@tontoko/fast-playwright-mcp 0.0.4
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 +202 -0
- package/README.md +1047 -0
- package/cli.js +18 -0
- package/config.d.ts +124 -0
- package/index.d.ts +25 -0
- package/index.js +18 -0
- package/lib/actions.d.js +0 -0
- package/lib/batch/batch-executor.js +137 -0
- package/lib/browser-context-factory.js +252 -0
- package/lib/browser-server-backend.js +139 -0
- package/lib/config/constants.js +80 -0
- package/lib/config.js +405 -0
- package/lib/context.js +274 -0
- package/lib/diagnostics/common/diagnostic-base.js +63 -0
- package/lib/diagnostics/common/error-enrichment-utils.js +212 -0
- package/lib/diagnostics/common/index.js +56 -0
- package/lib/diagnostics/common/initialization-manager.js +210 -0
- package/lib/diagnostics/common/performance-tracker.js +132 -0
- package/lib/diagnostics/diagnostic-error.js +140 -0
- package/lib/diagnostics/diagnostic-level.js +123 -0
- package/lib/diagnostics/diagnostic-thresholds.js +347 -0
- package/lib/diagnostics/element-discovery.js +441 -0
- package/lib/diagnostics/enhanced-error-handler.js +376 -0
- package/lib/diagnostics/error-enrichment.js +157 -0
- package/lib/diagnostics/frame-reference-manager.js +179 -0
- package/lib/diagnostics/page-analyzer.js +639 -0
- package/lib/diagnostics/parallel-page-analyzer.js +129 -0
- package/lib/diagnostics/resource-manager.js +134 -0
- package/lib/diagnostics/smart-config.js +482 -0
- package/lib/diagnostics/smart-handle.js +118 -0
- package/lib/diagnostics/unified-system.js +717 -0
- package/lib/extension/cdp-relay.js +486 -0
- package/lib/extension/extension-context-factory.js +74 -0
- package/lib/extension/main.js +41 -0
- package/lib/file-utils.js +42 -0
- package/lib/generate-keys.js +75 -0
- package/lib/http-server.js +50 -0
- package/lib/in-process-client.js +64 -0
- package/lib/index.js +48 -0
- package/lib/javascript.js +90 -0
- package/lib/log.js +33 -0
- package/lib/loop/loop-claude.js +247 -0
- package/lib/loop/loop-open-ai.js +222 -0
- package/lib/loop/loop.js +174 -0
- package/lib/loop/main.js +46 -0
- package/lib/loopTools/context.js +76 -0
- package/lib/loopTools/main.js +65 -0
- package/lib/loopTools/perform.js +40 -0
- package/lib/loopTools/snapshot.js +37 -0
- package/lib/loopTools/tool.js +26 -0
- package/lib/manual-promise.js +125 -0
- package/lib/mcp/in-process-transport.js +91 -0
- package/lib/mcp/proxy-backend.js +127 -0
- package/lib/mcp/server.js +123 -0
- package/lib/mcp/transport.js +159 -0
- package/lib/package.js +28 -0
- package/lib/program.js +82 -0
- package/lib/response.js +493 -0
- package/lib/schemas/expectation.js +152 -0
- package/lib/session-log.js +210 -0
- package/lib/tab.js +417 -0
- package/lib/tools/base-tool-handler.js +141 -0
- package/lib/tools/batch-execute.js +150 -0
- package/lib/tools/common.js +65 -0
- package/lib/tools/console.js +60 -0
- package/lib/tools/diagnose/diagnose-analysis-runner.js +101 -0
- package/lib/tools/diagnose/diagnose-config-handler.js +130 -0
- package/lib/tools/diagnose/diagnose-report-builder.js +394 -0
- package/lib/tools/diagnose.js +147 -0
- package/lib/tools/dialogs.js +57 -0
- package/lib/tools/evaluate.js +67 -0
- package/lib/tools/files.js +53 -0
- package/lib/tools/find-elements.js +307 -0
- package/lib/tools/install.js +60 -0
- package/lib/tools/keyboard.js +93 -0
- package/lib/tools/mouse.js +110 -0
- package/lib/tools/navigate.js +82 -0
- package/lib/tools/network.js +50 -0
- package/lib/tools/pdf.js +46 -0
- package/lib/tools/screenshot.js +113 -0
- package/lib/tools/snapshot.js +158 -0
- package/lib/tools/tabs.js +97 -0
- package/lib/tools/tool.js +47 -0
- package/lib/tools/utils.js +131 -0
- package/lib/tools/wait.js +64 -0
- package/lib/tools.js +65 -0
- package/lib/types/batch.js +47 -0
- package/lib/types/diff.js +0 -0
- package/lib/types/performance.js +0 -0
- package/lib/types/threshold-base.js +0 -0
- package/lib/utils/array-utils.js +44 -0
- package/lib/utils/code-deduplication-utils.js +141 -0
- package/lib/utils/common-formatters.js +252 -0
- package/lib/utils/console-filter.js +64 -0
- package/lib/utils/diagnostic-report-utils.js +178 -0
- package/lib/utils/diff-formatter.js +126 -0
- package/lib/utils/disposable-manager.js +135 -0
- package/lib/utils/error-handler-middleware.js +77 -0
- package/lib/utils/image-processor.js +137 -0
- package/lib/utils/index.js +92 -0
- package/lib/utils/report-builder.js +189 -0
- package/lib/utils/request-logger.js +82 -0
- package/lib/utils/response-diff-detector.js +150 -0
- package/lib/utils/section-builder.js +62 -0
- package/lib/utils/tool-patterns.js +153 -0
- package/lib/utils.js +46 -0
- package/package.json +77 -0
|
@@ -0,0 +1,717 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
|
+
|
|
20
|
+
// src/diagnostics/unified-system.ts
|
|
21
|
+
import { getErrorMessage } from "../utils/common-formatters.js";
|
|
22
|
+
import {
|
|
23
|
+
createAdvancedStage,
|
|
24
|
+
createCoreStage,
|
|
25
|
+
createDependentStage,
|
|
26
|
+
InitializationManager
|
|
27
|
+
} from "./common/initialization-manager.js";
|
|
28
|
+
import { PerformanceTracker } from "./common/performance-tracker.js";
|
|
29
|
+
import { DiagnosticError } from "./diagnostic-error.js";
|
|
30
|
+
import { ElementDiscovery } from "./element-discovery.js";
|
|
31
|
+
import { EnhancedErrorHandler } from "./enhanced-error-handler.js";
|
|
32
|
+
import { PageAnalyzer } from "./page-analyzer.js";
|
|
33
|
+
import { ParallelPageAnalyzer } from "./parallel-page-analyzer.js";
|
|
34
|
+
import { ResourceManager } from "./resource-manager.js";
|
|
35
|
+
import { SmartConfigManager } from "./smart-config.js";
|
|
36
|
+
|
|
37
|
+
class UnifiedDiagnosticSystem {
|
|
38
|
+
static instances = new Map;
|
|
39
|
+
page;
|
|
40
|
+
configManager;
|
|
41
|
+
initializationManager;
|
|
42
|
+
performanceTracker;
|
|
43
|
+
disposed = false;
|
|
44
|
+
pageAnalyzer;
|
|
45
|
+
parallelAnalyzer;
|
|
46
|
+
elementDiscovery;
|
|
47
|
+
resourceManager;
|
|
48
|
+
errorHandler;
|
|
49
|
+
get isInitialized() {
|
|
50
|
+
return this.initializationManager?.getIsInitialized() ?? false;
|
|
51
|
+
}
|
|
52
|
+
get initializationPromise() {
|
|
53
|
+
return this.initializationManager?.initializationPromise ?? null;
|
|
54
|
+
}
|
|
55
|
+
stats;
|
|
56
|
+
operationHistory = [];
|
|
57
|
+
constructor(page, config) {
|
|
58
|
+
this.page = page;
|
|
59
|
+
this.configManager = SmartConfigManager.getInstance(config);
|
|
60
|
+
if (!this.configManager) {
|
|
61
|
+
throw new DiagnosticError("Failed to initialize SmartConfigManager", {
|
|
62
|
+
timestamp: Date.now(),
|
|
63
|
+
component: "UnifiedSystem",
|
|
64
|
+
operation: "constructor",
|
|
65
|
+
suggestions: [
|
|
66
|
+
"Ensure SmartConfigManager singleton is not reset during initialization",
|
|
67
|
+
"Check if config parameter is valid",
|
|
68
|
+
"Verify no concurrent initialization issues"
|
|
69
|
+
]
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
this.performanceTracker = new PerformanceTracker;
|
|
73
|
+
this.initializationManager = new InitializationManager({
|
|
74
|
+
componentName: "UnifiedSystem",
|
|
75
|
+
config,
|
|
76
|
+
performanceTracker: this.performanceTracker
|
|
77
|
+
});
|
|
78
|
+
this.stats = this.initializeStats();
|
|
79
|
+
this.setupConfigurationListener();
|
|
80
|
+
}
|
|
81
|
+
async initializeComponents() {
|
|
82
|
+
if (this.disposed) {
|
|
83
|
+
throw new DiagnosticError("System has been disposed and cannot be reinitialized", {
|
|
84
|
+
timestamp: Date.now(),
|
|
85
|
+
component: "UnifiedSystem",
|
|
86
|
+
operation: "initializeComponents",
|
|
87
|
+
suggestions: [
|
|
88
|
+
"Create a new system instance instead of reusing disposed instance",
|
|
89
|
+
"Check component dependencies",
|
|
90
|
+
"Ensure proper disposal handling"
|
|
91
|
+
]
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
if (!this.initializationManager) {
|
|
95
|
+
throw new DiagnosticError("InitializationManager is not available", {
|
|
96
|
+
timestamp: Date.now(),
|
|
97
|
+
component: "UnifiedSystem",
|
|
98
|
+
operation: "initializeComponents",
|
|
99
|
+
suggestions: [
|
|
100
|
+
"Verify system was properly constructed",
|
|
101
|
+
"Check if instance was disposed",
|
|
102
|
+
"Ensure getInstance was called with valid page"
|
|
103
|
+
]
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
const stages = [
|
|
108
|
+
createCoreStage("core-infrastructure", [
|
|
109
|
+
() => {
|
|
110
|
+
this.resourceManager = new ResourceManager;
|
|
111
|
+
this.initializationManager.trackPartialInitialization(this.resourceManager);
|
|
112
|
+
return Promise.resolve();
|
|
113
|
+
}
|
|
114
|
+
]),
|
|
115
|
+
createDependentStage("page-dependent", ["core-infrastructure"], [
|
|
116
|
+
() => {
|
|
117
|
+
if (!this.configManager) {
|
|
118
|
+
throw new DiagnosticError("SmartConfigManager is not available during component initialization", {
|
|
119
|
+
timestamp: Date.now(),
|
|
120
|
+
component: "UnifiedSystem",
|
|
121
|
+
operation: "initializeComponents",
|
|
122
|
+
suggestions: [
|
|
123
|
+
"Check if SmartConfigManager instance was reset during initialization",
|
|
124
|
+
"Ensure singleton lifecycle is properly managed",
|
|
125
|
+
"Verify no concurrent disposal operations"
|
|
126
|
+
]
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
const componentConfig = this.configManager.getComponentConfig("pageAnalyzer");
|
|
130
|
+
this.pageAnalyzer = new PageAnalyzer(this.page);
|
|
131
|
+
this.elementDiscovery = new ElementDiscovery(this.page);
|
|
132
|
+
this.errorHandler = new EnhancedErrorHandler(this.page, componentConfig.diagnostic);
|
|
133
|
+
this.initializationManager.trackPartialInitialization(this.pageAnalyzer);
|
|
134
|
+
this.initializationManager.trackPartialInitialization(this.elementDiscovery);
|
|
135
|
+
return Promise.resolve();
|
|
136
|
+
}
|
|
137
|
+
]),
|
|
138
|
+
createAdvancedStage("advanced-features", [
|
|
139
|
+
() => {
|
|
140
|
+
this.parallelAnalyzer = new ParallelPageAnalyzer(this.page);
|
|
141
|
+
this.initializationManager.trackPartialInitialization(this.parallelAnalyzer);
|
|
142
|
+
return Promise.resolve();
|
|
143
|
+
}
|
|
144
|
+
])
|
|
145
|
+
];
|
|
146
|
+
await this.initializationManager.initialize(stages);
|
|
147
|
+
} catch (error) {
|
|
148
|
+
if (error instanceof DiagnosticError) {
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
const baseError = error instanceof Error ? error : new Error(String(error));
|
|
152
|
+
throw new DiagnosticError(`Component initialization failed: ${baseError.message}`, {
|
|
153
|
+
timestamp: Date.now(),
|
|
154
|
+
component: "UnifiedSystem",
|
|
155
|
+
operation: "initializeComponents",
|
|
156
|
+
suggestions: [
|
|
157
|
+
"Review component dependencies",
|
|
158
|
+
"Check page and configuration validity",
|
|
159
|
+
"Verify all required components are available"
|
|
160
|
+
],
|
|
161
|
+
context: {
|
|
162
|
+
stage: "initialization",
|
|
163
|
+
failedComponents: this ? this.getFailedComponents?.() ?? [] : []
|
|
164
|
+
}
|
|
165
|
+
}, baseError);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
getFailedComponents() {
|
|
169
|
+
const failedComponents = [];
|
|
170
|
+
if (!this.resourceManager) {
|
|
171
|
+
failedComponents.push("ResourceManager");
|
|
172
|
+
}
|
|
173
|
+
if (!this.pageAnalyzer) {
|
|
174
|
+
failedComponents.push("PageAnalyzer");
|
|
175
|
+
}
|
|
176
|
+
if (!this.elementDiscovery) {
|
|
177
|
+
failedComponents.push("ElementDiscovery");
|
|
178
|
+
}
|
|
179
|
+
if (!this.errorHandler) {
|
|
180
|
+
failedComponents.push("ErrorHandler");
|
|
181
|
+
}
|
|
182
|
+
if (!this.parallelAnalyzer) {
|
|
183
|
+
failedComponents.push("ParallelAnalyzer");
|
|
184
|
+
}
|
|
185
|
+
return failedComponents;
|
|
186
|
+
}
|
|
187
|
+
async cleanupPartialInitialization(components) {
|
|
188
|
+
await Promise.allSettled(components.map(async (component) => {
|
|
189
|
+
try {
|
|
190
|
+
await component.dispose();
|
|
191
|
+
} catch {}
|
|
192
|
+
}));
|
|
193
|
+
}
|
|
194
|
+
async ensureInitialized() {
|
|
195
|
+
if (!this.initializationManager.getIsInitialized()) {
|
|
196
|
+
await this.initializeComponents();
|
|
197
|
+
}
|
|
198
|
+
if (!this.initializationManager.getIsInitialized()) {
|
|
199
|
+
const error = this.initializationManager.getInitializationError();
|
|
200
|
+
throw error || new DiagnosticError("UnifiedSystem components are not initialized", {
|
|
201
|
+
timestamp: Date.now(),
|
|
202
|
+
component: "UnifiedSystem",
|
|
203
|
+
operation: "ensureInitialized",
|
|
204
|
+
suggestions: [
|
|
205
|
+
"Call initializeComponents() before using the system",
|
|
206
|
+
"Check for initialization errors",
|
|
207
|
+
"Verify page and configuration are valid"
|
|
208
|
+
]
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
static getInstance(page, config) {
|
|
213
|
+
if (!UnifiedDiagnosticSystem.instances.has(page)) {
|
|
214
|
+
const instance = new UnifiedDiagnosticSystem(page, config);
|
|
215
|
+
UnifiedDiagnosticSystem.instances.set(page, instance);
|
|
216
|
+
}
|
|
217
|
+
const system = UnifiedDiagnosticSystem.instances.get(page);
|
|
218
|
+
if (!system) {
|
|
219
|
+
throw new Error("UnifiedDiagnosticSystem instance not found");
|
|
220
|
+
}
|
|
221
|
+
return system;
|
|
222
|
+
}
|
|
223
|
+
static disposeInstance(page) {
|
|
224
|
+
const instance = UnifiedDiagnosticSystem.instances.get(page);
|
|
225
|
+
if (instance) {
|
|
226
|
+
instance.dispose();
|
|
227
|
+
UnifiedDiagnosticSystem.instances.delete(page);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
initializeStats() {
|
|
231
|
+
return {
|
|
232
|
+
operationCount: {},
|
|
233
|
+
errorCount: {
|
|
234
|
+
PageAnalyzer: 0,
|
|
235
|
+
ElementDiscovery: 0,
|
|
236
|
+
ResourceManager: 0,
|
|
237
|
+
ErrorHandler: 0,
|
|
238
|
+
ConfigManager: 0,
|
|
239
|
+
UnifiedSystem: 0,
|
|
240
|
+
InitializationManager: 0
|
|
241
|
+
},
|
|
242
|
+
performanceMetrics: {
|
|
243
|
+
averageExecutionTime: {},
|
|
244
|
+
peakMemoryUsage: 0,
|
|
245
|
+
totalOperations: 0,
|
|
246
|
+
successRate: 1
|
|
247
|
+
},
|
|
248
|
+
resourceUsage: {
|
|
249
|
+
currentHandles: 0,
|
|
250
|
+
peakHandles: 0,
|
|
251
|
+
memoryLeaks: 0,
|
|
252
|
+
autoDisposeCount: 0
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
setupConfigurationListener() {
|
|
257
|
+
if (!this.configManager) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
this.configManager.onConfigChange((_config) => {});
|
|
261
|
+
}
|
|
262
|
+
async executeOperation(operation, component, fn, options) {
|
|
263
|
+
const startTime = Date.now();
|
|
264
|
+
if (!this.configManager) {
|
|
265
|
+
throw new DiagnosticError("SmartConfigManager is not available for operation execution", {
|
|
266
|
+
timestamp: startTime,
|
|
267
|
+
component: "UnifiedSystem",
|
|
268
|
+
operation: "executeOperation",
|
|
269
|
+
suggestions: [
|
|
270
|
+
"Ensure UnifiedSystem is properly initialized",
|
|
271
|
+
"Check if SmartConfigManager instance was disposed",
|
|
272
|
+
"Verify system lifecycle management"
|
|
273
|
+
],
|
|
274
|
+
context: {
|
|
275
|
+
operation,
|
|
276
|
+
targetComponent: component
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
const config = this.configManager.getConfig();
|
|
281
|
+
let componentConfigType;
|
|
282
|
+
switch (component) {
|
|
283
|
+
case "ElementDiscovery":
|
|
284
|
+
componentConfigType = "elementDiscovery";
|
|
285
|
+
break;
|
|
286
|
+
case "ResourceManager":
|
|
287
|
+
componentConfigType = "resourceManager";
|
|
288
|
+
break;
|
|
289
|
+
default:
|
|
290
|
+
componentConfigType = "pageAnalyzer";
|
|
291
|
+
}
|
|
292
|
+
const componentConfig = this.configManager.getComponentConfig(componentConfigType);
|
|
293
|
+
try {
|
|
294
|
+
const timeout = Number(options?.timeout ?? componentConfig.executionTimeout ?? 1e4);
|
|
295
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
296
|
+
setTimeout(() => reject(new Error(`Operation timeout after ${timeout}ms`)), timeout);
|
|
297
|
+
});
|
|
298
|
+
const result = await Promise.race([fn(), timeoutPromise]);
|
|
299
|
+
const executionTime = Date.now() - startTime;
|
|
300
|
+
this.recordOperation(operation, component, executionTime, true);
|
|
301
|
+
return {
|
|
302
|
+
success: true,
|
|
303
|
+
data: result,
|
|
304
|
+
executionTime
|
|
305
|
+
};
|
|
306
|
+
} catch (error) {
|
|
307
|
+
const executionTime = Date.now() - startTime;
|
|
308
|
+
this.recordOperation(operation, component, executionTime, false);
|
|
309
|
+
this.stats.errorCount[component]++;
|
|
310
|
+
let enhancedDiagnosticError;
|
|
311
|
+
if (error instanceof DiagnosticError) {
|
|
312
|
+
enhancedDiagnosticError = error;
|
|
313
|
+
} else {
|
|
314
|
+
const baseError = error instanceof Error ? error : new Error(getErrorMessage(error));
|
|
315
|
+
enhancedDiagnosticError = DiagnosticError.from(baseError, component, operation, {
|
|
316
|
+
executionTime,
|
|
317
|
+
timestamp: startTime
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
let enrichedError = enhancedDiagnosticError;
|
|
321
|
+
if (config.errorHandling.enableErrorEnrichment) {
|
|
322
|
+
try {
|
|
323
|
+
enrichedError = await this.enrichError(enhancedDiagnosticError, operation);
|
|
324
|
+
} catch {}
|
|
325
|
+
}
|
|
326
|
+
return {
|
|
327
|
+
success: false,
|
|
328
|
+
error: enrichedError,
|
|
329
|
+
executionTime
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
recordOperation(operation, component, executionTime, success) {
|
|
334
|
+
this.updateOperationStats(operation, executionTime, success);
|
|
335
|
+
this.updateOperationHistory(operation, component, executionTime, success);
|
|
336
|
+
this.performAdaptiveThresholdAdjustment(operation, component);
|
|
337
|
+
}
|
|
338
|
+
updateOperationStats(operation, executionTime, success) {
|
|
339
|
+
this.stats.operationCount[operation] = (this.stats.operationCount[operation] ?? 0) + 1;
|
|
340
|
+
const currentAvg = this.stats.performanceMetrics.averageExecutionTime[operation] ?? 0;
|
|
341
|
+
const currentCount = this.stats.operationCount[operation];
|
|
342
|
+
this.stats.performanceMetrics.averageExecutionTime[operation] = (currentAvg * (currentCount - 1) + executionTime) / currentCount;
|
|
343
|
+
this.stats.performanceMetrics.totalOperations++;
|
|
344
|
+
const successfulOps = this.operationHistory.filter((op) => op.success).length + (success ? 1 : 0);
|
|
345
|
+
const totalOps = this.operationHistory.length + 1;
|
|
346
|
+
this.stats.performanceMetrics.successRate = successfulOps / totalOps;
|
|
347
|
+
}
|
|
348
|
+
updateOperationHistory(operation, component, executionTime, success) {
|
|
349
|
+
this.operationHistory.push({
|
|
350
|
+
operation,
|
|
351
|
+
component,
|
|
352
|
+
timestamp: Date.now(),
|
|
353
|
+
executionTime,
|
|
354
|
+
success
|
|
355
|
+
});
|
|
356
|
+
const maxHistory = this.configManager ? this.configManager.getConfig().errorHandling.maxErrorHistory : 100;
|
|
357
|
+
if (this.operationHistory.length > maxHistory) {
|
|
358
|
+
this.operationHistory = this.operationHistory.slice(-maxHistory);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
performAdaptiveThresholdAdjustment(operation, component) {
|
|
362
|
+
if (!this.configManager?.isAdaptiveThresholdsEnabled()) {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
const recentOps = this.operationHistory.filter((op) => op.operation === operation && Date.now() - op.timestamp < 300000);
|
|
366
|
+
if (recentOps.length >= 10) {
|
|
367
|
+
const avgTime = recentOps.reduce((sum, op) => sum + op.executionTime, 0) / recentOps.length;
|
|
368
|
+
const successRate = recentOps.filter((op) => op.success).length / recentOps.length;
|
|
369
|
+
this.adjustComponentThresholds(component, avgTime, successRate);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
adjustComponentThresholds(component, avgTime, successRate) {
|
|
373
|
+
if (!this.configManager) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
if (component === "PageAnalyzer") {
|
|
377
|
+
this.configManager.adjustThresholds("pageAnalysis", avgTime, successRate);
|
|
378
|
+
} else if (component === "ElementDiscovery") {
|
|
379
|
+
this.configManager.adjustThresholds("elementDiscovery", avgTime, successRate);
|
|
380
|
+
} else if (component === "ResourceManager") {
|
|
381
|
+
this.configManager.adjustThresholds("resourceMonitoring", avgTime, successRate);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
async enrichError(error, operation) {
|
|
385
|
+
try {
|
|
386
|
+
if (!this.errorHandler) {
|
|
387
|
+
return error;
|
|
388
|
+
}
|
|
389
|
+
const enrichedPlaywrightError = await this.errorHandler.enhanceToolError({
|
|
390
|
+
toolName: operation,
|
|
391
|
+
error: new Error(error.message),
|
|
392
|
+
toolArgs: { component: error.component, operation: error.operation }
|
|
393
|
+
});
|
|
394
|
+
const enrichedDiagnosticError = new DiagnosticError(enrichedPlaywrightError.message, {
|
|
395
|
+
timestamp: error.timestamp,
|
|
396
|
+
component: error.component,
|
|
397
|
+
operation: error.operation,
|
|
398
|
+
executionTime: error.executionTime,
|
|
399
|
+
performanceImpact: error.performanceImpact,
|
|
400
|
+
suggestions: [
|
|
401
|
+
...error.suggestions,
|
|
402
|
+
...enrichedPlaywrightError.suggestions ?? []
|
|
403
|
+
]
|
|
404
|
+
}, error.originalError);
|
|
405
|
+
return enrichedDiagnosticError;
|
|
406
|
+
} catch {
|
|
407
|
+
return error;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
async analyzePageStructure(forceParallel) {
|
|
411
|
+
await this.ensureInitialized();
|
|
412
|
+
if (!this.configManager) {
|
|
413
|
+
throw new DiagnosticError("Cannot analyze page structure: SmartConfigManager is not available", {
|
|
414
|
+
timestamp: Date.now(),
|
|
415
|
+
component: "UnifiedSystem",
|
|
416
|
+
operation: "analyzePageStructure",
|
|
417
|
+
suggestions: [
|
|
418
|
+
"Ensure UnifiedSystem is properly initialized",
|
|
419
|
+
"Check if SmartConfigManager instance was disposed",
|
|
420
|
+
"Verify system lifecycle management"
|
|
421
|
+
]
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
const config = this.configManager.getConfig();
|
|
425
|
+
const shouldUseParallel = forceParallel ?? config.features.enableParallelAnalysis;
|
|
426
|
+
if (shouldUseParallel) {
|
|
427
|
+
return this.executeOperation("analyzePageStructure", "PageAnalyzer", async () => {
|
|
428
|
+
const recommendation = await this.pageAnalyzer?.shouldUseParallelAnalysis();
|
|
429
|
+
if (recommendation?.recommended ?? forceParallel) {
|
|
430
|
+
return await this.parallelAnalyzer?.runParallelAnalysis();
|
|
431
|
+
}
|
|
432
|
+
return await this.pageAnalyzer?.analyzePageStructure();
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
return this.executeOperation("analyzePageStructure", "PageAnalyzer", async () => this.pageAnalyzer?.analyzePageStructure());
|
|
436
|
+
}
|
|
437
|
+
async findAlternativeElements(searchCriteria) {
|
|
438
|
+
await this.ensureInitialized();
|
|
439
|
+
return this.executeOperation("findAlternativeElements", "ElementDiscovery", async () => this.elementDiscovery?.findAlternativeElements({
|
|
440
|
+
originalSelector: "",
|
|
441
|
+
searchCriteria,
|
|
442
|
+
maxResults: 10
|
|
443
|
+
}));
|
|
444
|
+
}
|
|
445
|
+
async analyzePerformanceMetrics() {
|
|
446
|
+
await this.ensureInitialized();
|
|
447
|
+
return this.executeOperation("analyzePerformanceMetrics", "PageAnalyzer", async () => this.pageAnalyzer?.analyzePerformanceMetrics());
|
|
448
|
+
}
|
|
449
|
+
async createSmartHandle(creator, _disposer, _options) {
|
|
450
|
+
await this.ensureInitialized();
|
|
451
|
+
const handle = await creator();
|
|
452
|
+
const smartHandle = this.resourceManager?.createSmartHandle(handle, "dispose");
|
|
453
|
+
return smartHandle?.handle ?? handle;
|
|
454
|
+
}
|
|
455
|
+
updateConfiguration(updates) {
|
|
456
|
+
if (!this.configManager) {
|
|
457
|
+
throw new DiagnosticError("Cannot update configuration: SmartConfigManager is not available", {
|
|
458
|
+
timestamp: Date.now(),
|
|
459
|
+
component: "UnifiedSystem",
|
|
460
|
+
operation: "updateConfiguration",
|
|
461
|
+
suggestions: [
|
|
462
|
+
"Ensure UnifiedSystem is properly initialized",
|
|
463
|
+
"Check if SmartConfigManager instance was disposed",
|
|
464
|
+
"Verify system lifecycle management"
|
|
465
|
+
]
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
this.configManager.updateConfig(updates);
|
|
469
|
+
}
|
|
470
|
+
getConfiguration() {
|
|
471
|
+
if (!this.configManager) {
|
|
472
|
+
throw new DiagnosticError("Cannot get configuration: SmartConfigManager is not available", {
|
|
473
|
+
timestamp: Date.now(),
|
|
474
|
+
component: "UnifiedSystem",
|
|
475
|
+
operation: "getConfiguration",
|
|
476
|
+
suggestions: [
|
|
477
|
+
"Ensure UnifiedSystem is properly initialized",
|
|
478
|
+
"Check if SmartConfigManager instance was disposed",
|
|
479
|
+
"Verify system lifecycle management"
|
|
480
|
+
]
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
return this.configManager.getConfig();
|
|
484
|
+
}
|
|
485
|
+
getSystemStats() {
|
|
486
|
+
if (!(this.initializationManager.getIsInitialized() && this.resourceManager)) {
|
|
487
|
+
return this.stats;
|
|
488
|
+
}
|
|
489
|
+
const currentResourceUsage = this.resourceManager.getResourceStats();
|
|
490
|
+
return {
|
|
491
|
+
...this.stats,
|
|
492
|
+
resourceUsage: {
|
|
493
|
+
...this.stats.resourceUsage,
|
|
494
|
+
currentHandles: currentResourceUsage.activeCount,
|
|
495
|
+
peakHandles: Math.max(this.stats.resourceUsage.peakHandles ?? 0, currentResourceUsage.activeCount)
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
getRecentOperations(limit = 50) {
|
|
500
|
+
return this.operationHistory.slice(-limit);
|
|
501
|
+
}
|
|
502
|
+
getConfigurationReport() {
|
|
503
|
+
const configData = this.getConfigData();
|
|
504
|
+
const configurationStatus = this.determineConfigurationStatus(configData.configSummary);
|
|
505
|
+
const appliedOverrides = this.buildAppliedOverrides(configData.impactReport);
|
|
506
|
+
const performanceBaseline = this.calculatePerformanceBaseline(configData.config);
|
|
507
|
+
const recommendations = this.generateAllRecommendations(configData.impactReport, performanceBaseline.deviations);
|
|
508
|
+
return {
|
|
509
|
+
configurationStatus,
|
|
510
|
+
appliedOverrides,
|
|
511
|
+
performanceBaseline,
|
|
512
|
+
recommendations: this.sortRecommendations(recommendations)
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
getConfigData() {
|
|
516
|
+
if (!this.configManager) {
|
|
517
|
+
throw new DiagnosticError("Cannot get configuration data: SmartConfigManager is not available", {
|
|
518
|
+
timestamp: Date.now(),
|
|
519
|
+
component: "UnifiedSystem",
|
|
520
|
+
operation: "getConfigData",
|
|
521
|
+
suggestions: [
|
|
522
|
+
"Ensure UnifiedSystem is properly initialized",
|
|
523
|
+
"Check if SmartConfigManager instance was disposed",
|
|
524
|
+
"Verify system lifecycle management"
|
|
525
|
+
]
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
const config = this.configManager.getConfig();
|
|
529
|
+
const impactReport = this.configManager.getConfigurationImpactReport();
|
|
530
|
+
const configSummary = this.configManager.getConfigurationSummary();
|
|
531
|
+
return { config, impactReport, configSummary };
|
|
532
|
+
}
|
|
533
|
+
determineConfigurationStatus(configSummary) {
|
|
534
|
+
if (configSummary.totalOverrides === 0) {
|
|
535
|
+
return "default";
|
|
536
|
+
}
|
|
537
|
+
return configSummary.totalOverrides > 5 ? "heavily-customized" : "customized";
|
|
538
|
+
}
|
|
539
|
+
buildAppliedOverrides(impactReport) {
|
|
540
|
+
return [
|
|
541
|
+
{
|
|
542
|
+
category: "Performance Thresholds",
|
|
543
|
+
changes: Object.entries(impactReport.performanceImpact.executionTimeChanges).map(([component, change]) => `${component}: ${change.from}ms → ${change.to}ms (${change.percentChange > 0 ? "+" : ""}${change.percentChange}%)`),
|
|
544
|
+
impact: Object.keys(impactReport.performanceImpact.executionTimeChanges).length > 2 ? "high" : "medium"
|
|
545
|
+
},
|
|
546
|
+
{
|
|
547
|
+
category: "Feature Flags",
|
|
548
|
+
changes: [
|
|
549
|
+
...impactReport.featureChanges.enabled.map((feature) => `${feature}: Enabled`),
|
|
550
|
+
...impactReport.featureChanges.disabled.map((feature) => `${feature}: Disabled`),
|
|
551
|
+
...impactReport.featureChanges.modified
|
|
552
|
+
],
|
|
553
|
+
impact: impactReport.featureChanges.enabled.length + impactReport.featureChanges.disabled.length > 2 ? "medium" : "low"
|
|
554
|
+
}
|
|
555
|
+
].filter((override) => override.changes.length > 0);
|
|
556
|
+
}
|
|
557
|
+
calculatePerformanceBaseline(config) {
|
|
558
|
+
const expectedExecutionTimes = {
|
|
559
|
+
pageAnalysis: config.performance.thresholds.executionTime.pageAnalysis,
|
|
560
|
+
elementDiscovery: config.performance.thresholds.executionTime.elementDiscovery,
|
|
561
|
+
resourceMonitoring: config.performance.thresholds.executionTime.resourceMonitoring
|
|
562
|
+
};
|
|
563
|
+
const actualAverages = {
|
|
564
|
+
pageAnalysis: this.stats.performanceMetrics.averageExecutionTime.analyzePageStructure ?? 0,
|
|
565
|
+
elementDiscovery: this.stats.performanceMetrics.averageExecutionTime.findAlternativeElements ?? 0,
|
|
566
|
+
resourceMonitoring: this.stats.performanceMetrics.averageExecutionTime.resourceMonitoring ?? 0
|
|
567
|
+
};
|
|
568
|
+
const deviations = this.calculateDeviations(expectedExecutionTimes, actualAverages);
|
|
569
|
+
return { expectedExecutionTimes, actualAverages, deviations };
|
|
570
|
+
}
|
|
571
|
+
calculateDeviations(expected, actual) {
|
|
572
|
+
const deviations = {};
|
|
573
|
+
for (const key of Object.keys(expected)) {
|
|
574
|
+
const expectedTime = expected[key];
|
|
575
|
+
const actualTime = actual[key];
|
|
576
|
+
if (actualTime > 0 && expectedTime > 0) {
|
|
577
|
+
const percent = (actualTime - expectedTime) / expectedTime * 100;
|
|
578
|
+
let significance = "normal";
|
|
579
|
+
if (Math.abs(percent) > 50) {
|
|
580
|
+
significance = "significant";
|
|
581
|
+
} else if (Math.abs(percent) > 25) {
|
|
582
|
+
significance = "notable";
|
|
583
|
+
}
|
|
584
|
+
deviations[key] = { percent: Math.round(percent), significance };
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
return deviations;
|
|
588
|
+
}
|
|
589
|
+
generateAllRecommendations(impactReport, deviations) {
|
|
590
|
+
const recommendations = [];
|
|
591
|
+
this.addPerformanceRecommendations(recommendations, deviations);
|
|
592
|
+
this.addConfigurationRecommendations(recommendations, impactReport);
|
|
593
|
+
this.addErrorRateRecommendations(recommendations);
|
|
594
|
+
return recommendations;
|
|
595
|
+
}
|
|
596
|
+
addPerformanceRecommendations(recommendations, deviations) {
|
|
597
|
+
for (const [component, deviation] of Object.entries(deviations)) {
|
|
598
|
+
if (deviation.significance === "significant") {
|
|
599
|
+
if (deviation.percent > 50) {
|
|
600
|
+
recommendations.push({
|
|
601
|
+
type: "warning",
|
|
602
|
+
message: `${component} is taking ${Math.abs(deviation.percent)}% longer than expected - consider optimization`,
|
|
603
|
+
priority: "high"
|
|
604
|
+
});
|
|
605
|
+
} else if (deviation.percent < -50) {
|
|
606
|
+
recommendations.push({
|
|
607
|
+
type: "info",
|
|
608
|
+
message: `${component} is performing ${Math.abs(deviation.percent)}% faster than expected - thresholds may be too conservative`,
|
|
609
|
+
priority: "low"
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
addConfigurationRecommendations(recommendations, impactReport) {
|
|
616
|
+
if (impactReport.performanceImpact.recommendedOptimizations.length > 0) {
|
|
617
|
+
for (const optimization of impactReport.performanceImpact.recommendedOptimizations) {
|
|
618
|
+
recommendations.push({
|
|
619
|
+
type: "optimization",
|
|
620
|
+
message: optimization,
|
|
621
|
+
priority: "medium"
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
for (const warning of impactReport.validationStatus.warnings) {
|
|
626
|
+
recommendations.push({
|
|
627
|
+
type: "warning",
|
|
628
|
+
message: warning,
|
|
629
|
+
priority: "medium"
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
addErrorRateRecommendations(recommendations) {
|
|
634
|
+
const totalErrors = Object.values(this.stats.errorCount).reduce((sum, count) => sum + count, 0);
|
|
635
|
+
const errorRate = totalErrors / Math.max(this.stats.performanceMetrics.totalOperations, 1);
|
|
636
|
+
if (errorRate > 0.05) {
|
|
637
|
+
recommendations.push({
|
|
638
|
+
type: "warning",
|
|
639
|
+
message: `Error rate is ${(errorRate * 100).toFixed(1)}% - consider reviewing recent failures`,
|
|
640
|
+
priority: "high"
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
sortRecommendations(recommendations) {
|
|
645
|
+
return recommendations.sort((a, b) => {
|
|
646
|
+
const priorityOrder = { high: 3, medium: 2, low: 1 };
|
|
647
|
+
return priorityOrder[b.priority] - priorityOrder[a.priority];
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
performHealthCheck() {
|
|
651
|
+
const issues = [];
|
|
652
|
+
const recommendations = [];
|
|
653
|
+
if (!this.configManager) {
|
|
654
|
+
issues.push("SmartConfigManager is not available");
|
|
655
|
+
recommendations.push("Reinitialize UnifiedSystem with proper configuration");
|
|
656
|
+
return { status: "critical", issues, recommendations };
|
|
657
|
+
}
|
|
658
|
+
const config = this.configManager.getConfig();
|
|
659
|
+
if (!this.initializationManager.getIsInitialized()) {
|
|
660
|
+
issues.push("System not initialized");
|
|
661
|
+
recommendations.push("Call initializeComponents() to initialize the system");
|
|
662
|
+
return { status: "critical", issues, recommendations };
|
|
663
|
+
}
|
|
664
|
+
const resourceStats = this.resourceManager?.getResourceStats();
|
|
665
|
+
if (!resourceStats) {
|
|
666
|
+
issues.push("Resource manager not initialized");
|
|
667
|
+
recommendations.push("Initialize the system components");
|
|
668
|
+
return { status: "critical", issues, recommendations };
|
|
669
|
+
}
|
|
670
|
+
if (resourceStats.activeCount > config.maxConcurrentHandles * 0.9) {
|
|
671
|
+
issues.push(`High handle usage: ${resourceStats.activeCount}/${config.maxConcurrentHandles}`);
|
|
672
|
+
recommendations.push("Consider reducing concurrent operations or increasing maxConcurrentHandles");
|
|
673
|
+
}
|
|
674
|
+
const totalErrors = Object.values(this.stats.errorCount).reduce((sum, count) => sum + count, 0);
|
|
675
|
+
const errorRate = totalErrors / Math.max(this.stats.performanceMetrics.totalOperations, 1);
|
|
676
|
+
if (errorRate > 0.1) {
|
|
677
|
+
issues.push(`High error rate: ${(errorRate * 100).toFixed(1)}%`);
|
|
678
|
+
recommendations.push("Review recent errors and consider adjusting timeout thresholds");
|
|
679
|
+
}
|
|
680
|
+
const avgExecutionTimes = Object.values(this.stats.performanceMetrics.averageExecutionTime);
|
|
681
|
+
const avgOverall = avgExecutionTimes.reduce((sum, time) => sum + time, 0) / Math.max(avgExecutionTimes.length, 1);
|
|
682
|
+
if (avgOverall > 2000) {
|
|
683
|
+
issues.push(`Slow performance: average ${avgOverall.toFixed(0)}ms`);
|
|
684
|
+
recommendations.push("Consider enabling parallel analysis or optimizing operations");
|
|
685
|
+
}
|
|
686
|
+
let status = "healthy";
|
|
687
|
+
if (issues.length > 2) {
|
|
688
|
+
status = "critical";
|
|
689
|
+
} else if (issues.length > 0) {
|
|
690
|
+
status = "warning";
|
|
691
|
+
}
|
|
692
|
+
return { status, issues, recommendations };
|
|
693
|
+
}
|
|
694
|
+
async dispose() {
|
|
695
|
+
if (this.disposed) {
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
this.disposed = true;
|
|
699
|
+
try {
|
|
700
|
+
const disposePromises = [];
|
|
701
|
+
if (this.pageAnalyzer) {
|
|
702
|
+
disposePromises.push(this.pageAnalyzer.dispose());
|
|
703
|
+
}
|
|
704
|
+
if (this.parallelAnalyzer) {
|
|
705
|
+
disposePromises.push(this.parallelAnalyzer.dispose());
|
|
706
|
+
}
|
|
707
|
+
if (this.resourceManager) {
|
|
708
|
+
disposePromises.push(this.resourceManager.dispose());
|
|
709
|
+
}
|
|
710
|
+
await Promise.all(disposePromises);
|
|
711
|
+
await this.initializationManager.dispose();
|
|
712
|
+
} catch {}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
export {
|
|
716
|
+
UnifiedDiagnosticSystem
|
|
717
|
+
};
|