@agentic-qe/v3 3.0.0-alpha.34 → 3.0.0-alpha.42

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 (73) hide show
  1. package/dist/cli/bundle.js +2880 -177
  2. package/dist/cli/index.js +14 -10
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/domains/test-execution/index.d.ts +1 -1
  5. package/dist/domains/test-execution/index.d.ts.map +1 -1
  6. package/dist/domains/test-execution/index.js +1 -1
  7. package/dist/domains/test-execution/index.js.map +1 -1
  8. package/dist/domains/test-execution/services/auth-state-manager.d.ts +175 -0
  9. package/dist/domains/test-execution/services/auth-state-manager.d.ts.map +1 -0
  10. package/dist/domains/test-execution/services/auth-state-manager.js +376 -0
  11. package/dist/domains/test-execution/services/auth-state-manager.js.map +1 -0
  12. package/dist/domains/test-execution/services/e2e-runner.d.ts +145 -7
  13. package/dist/domains/test-execution/services/e2e-runner.d.ts.map +1 -1
  14. package/dist/domains/test-execution/services/e2e-runner.js +687 -40
  15. package/dist/domains/test-execution/services/e2e-runner.js.map +1 -1
  16. package/dist/domains/test-execution/services/index.d.ts +2 -0
  17. package/dist/domains/test-execution/services/index.d.ts.map +1 -1
  18. package/dist/domains/test-execution/services/index.js +2 -0
  19. package/dist/domains/test-execution/services/index.js.map +1 -1
  20. package/dist/domains/test-execution/services/network-mocker.d.ts +187 -0
  21. package/dist/domains/test-execution/services/network-mocker.d.ts.map +1 -0
  22. package/dist/domains/test-execution/services/network-mocker.js +283 -0
  23. package/dist/domains/test-execution/services/network-mocker.js.map +1 -0
  24. package/dist/domains/test-execution/types/e2e-step.types.d.ts +16 -2
  25. package/dist/domains/test-execution/types/e2e-step.types.d.ts.map +1 -1
  26. package/dist/domains/test-execution/types/e2e-step.types.js +33 -5
  27. package/dist/domains/test-execution/types/e2e-step.types.js.map +1 -1
  28. package/dist/domains/visual-accessibility/services/accessibility-tester.d.ts +90 -11
  29. package/dist/domains/visual-accessibility/services/accessibility-tester.d.ts.map +1 -1
  30. package/dist/domains/visual-accessibility/services/accessibility-tester.js +336 -24
  31. package/dist/domains/visual-accessibility/services/accessibility-tester.js.map +1 -1
  32. package/dist/domains/visual-accessibility/services/viewport-capture.d.ts +51 -0
  33. package/dist/domains/visual-accessibility/services/viewport-capture.d.ts.map +1 -1
  34. package/dist/domains/visual-accessibility/services/viewport-capture.js +164 -0
  35. package/dist/domains/visual-accessibility/services/viewport-capture.js.map +1 -1
  36. package/dist/domains/visual-accessibility/services/visual-regression.d.ts +49 -6
  37. package/dist/domains/visual-accessibility/services/visual-regression.d.ts.map +1 -1
  38. package/dist/domains/visual-accessibility/services/visual-regression.js +158 -11
  39. package/dist/domains/visual-accessibility/services/visual-regression.js.map +1 -1
  40. package/dist/integrations/browser/agent-browser/client.d.ts +200 -0
  41. package/dist/integrations/browser/agent-browser/client.d.ts.map +1 -0
  42. package/dist/integrations/browser/agent-browser/client.js +837 -0
  43. package/dist/integrations/browser/agent-browser/client.js.map +1 -0
  44. package/dist/integrations/browser/agent-browser/command-executor.d.ts +149 -0
  45. package/dist/integrations/browser/agent-browser/command-executor.d.ts.map +1 -0
  46. package/dist/integrations/browser/agent-browser/command-executor.js +381 -0
  47. package/dist/integrations/browser/agent-browser/command-executor.js.map +1 -0
  48. package/dist/integrations/browser/agent-browser/index.d.ts +9 -0
  49. package/dist/integrations/browser/agent-browser/index.d.ts.map +1 -0
  50. package/dist/integrations/browser/agent-browser/index.js +9 -0
  51. package/dist/integrations/browser/agent-browser/index.js.map +1 -0
  52. package/dist/integrations/browser/agent-browser/session-manager.d.ts +105 -0
  53. package/dist/integrations/browser/agent-browser/session-manager.d.ts.map +1 -0
  54. package/dist/integrations/browser/agent-browser/session-manager.js +272 -0
  55. package/dist/integrations/browser/agent-browser/session-manager.js.map +1 -0
  56. package/dist/integrations/browser/agent-browser/snapshot-parser.d.ts +90 -0
  57. package/dist/integrations/browser/agent-browser/snapshot-parser.d.ts.map +1 -0
  58. package/dist/integrations/browser/agent-browser/snapshot-parser.js +302 -0
  59. package/dist/integrations/browser/agent-browser/snapshot-parser.js.map +1 -0
  60. package/dist/integrations/browser/client-factory.d.ts +144 -0
  61. package/dist/integrations/browser/client-factory.d.ts.map +1 -0
  62. package/dist/integrations/browser/client-factory.js +323 -0
  63. package/dist/integrations/browser/client-factory.js.map +1 -0
  64. package/dist/integrations/browser/index.d.ts +54 -0
  65. package/dist/integrations/browser/index.d.ts.map +1 -0
  66. package/dist/integrations/browser/index.js +64 -0
  67. package/dist/integrations/browser/index.js.map +1 -0
  68. package/dist/integrations/browser/types.d.ts +437 -0
  69. package/dist/integrations/browser/types.d.ts.map +1 -0
  70. package/dist/integrations/browser/types.js +68 -0
  71. package/dist/integrations/browser/types.js.map +1 -0
  72. package/dist/mcp/bundle.js +2849 -147
  73. package/package.json +1 -1
@@ -13698,12 +13698,12 @@ var TestGenerationCoordinator = class {
13698
13698
  await this.agentCoordinator.stop(agentResult.value);
13699
13699
  return result;
13700
13700
  } catch (error) {
13701
- const err2 = error instanceof Error ? error : new Error(String(error));
13702
- this.failWorkflow(workflowId, err2.message);
13701
+ const err3 = error instanceof Error ? error : new Error(String(error));
13702
+ this.failWorkflow(workflowId, err3.message);
13703
13703
  if (this.config.publishEvents) {
13704
- await this.publishGenerationFailed(err2, "generateTests");
13704
+ await this.publishGenerationFailed(err3, "generateTests");
13705
13705
  }
13706
- return { success: false, error: err2 };
13706
+ return { success: false, error: err3 };
13707
13707
  }
13708
13708
  }
13709
13709
  /**
@@ -14475,13 +14475,13 @@ var TestGenerationPlugin = class extends BaseDomainPlugin {
14475
14475
  }
14476
14476
  }
14477
14477
  handleError(error) {
14478
- const err2 = error instanceof Error ? error : new Error(String(error));
14478
+ const err3 = error instanceof Error ? error : new Error(String(error));
14479
14479
  const currentHealth = this.getHealth();
14480
14480
  this.updateHealth({
14481
- errors: [...currentHealth.errors.slice(-9), err2.message],
14481
+ errors: [...currentHealth.errors.slice(-9), err3.message],
14482
14482
  status: currentHealth.errors.length >= 5 ? "degraded" : currentHealth.status
14483
14483
  });
14484
- return { success: false, error: err2 };
14484
+ return { success: false, error: err3 };
14485
14485
  }
14486
14486
  trackSuccessfulGeneration(_tests) {
14487
14487
  const health = this.getHealth();
@@ -16367,10 +16367,10 @@ var RetryHandlerService = class {
16367
16367
  const result = this.parseTestResult(code, stdout, stderr);
16368
16368
  resolve7(result);
16369
16369
  });
16370
- proc.on("error", (err2) => {
16370
+ proc.on("error", (err3) => {
16371
16371
  clearTimeout(timeoutHandle);
16372
16372
  reject(new Error(
16373
- `Failed to spawn test process: ${err2.message}. Command: ${command} ${args.join(" ")}. Ensure the test runner is installed and accessible.`
16373
+ `Failed to spawn test process: ${err3.message}. Command: ${command} ${args.join(" ")}. Ensure the test runner is installed and accessible.`
16374
16374
  ));
16375
16375
  });
16376
16376
  });
@@ -16946,6 +16946,1906 @@ var TestPrioritizerService = class {
16946
16946
  }
16947
16947
  };
16948
16948
 
16949
+ // src/integrations/browser/types.ts
16950
+ var BrowserError = class _BrowserError extends Error {
16951
+ constructor(message, code, tool, cause) {
16952
+ super(message);
16953
+ this.code = code;
16954
+ this.tool = tool;
16955
+ this.cause = cause;
16956
+ this.name = "BrowserError";
16957
+ Object.setPrototypeOf(this, _BrowserError.prototype);
16958
+ }
16959
+ };
16960
+ var BrowserUnavailableError = class _BrowserUnavailableError extends BrowserError {
16961
+ constructor(tool, message, cause) {
16962
+ super(message || "Browser tool is unavailable", "BROWSER_UNAVAILABLE", tool, cause);
16963
+ this.name = "BrowserUnavailableError";
16964
+ Object.setPrototypeOf(this, _BrowserUnavailableError.prototype);
16965
+ }
16966
+ };
16967
+ var BrowserTimeoutError = class _BrowserTimeoutError extends BrowserError {
16968
+ constructor(tool, operation, cause) {
16969
+ super(`${operation} timed out`, "BROWSER_TIMEOUT", tool, cause);
16970
+ this.name = "BrowserTimeoutError";
16971
+ Object.setPrototypeOf(this, _BrowserTimeoutError.prototype);
16972
+ }
16973
+ };
16974
+ var BrowserElementNotFoundError = class _BrowserElementNotFoundError extends BrowserError {
16975
+ constructor(tool, target, cause) {
16976
+ const targetStr = typeof target === "string" ? target : JSON.stringify(target);
16977
+ super(`Element not found: ${targetStr}`, "ELEMENT_NOT_FOUND", tool, cause);
16978
+ this.name = "BrowserElementNotFoundError";
16979
+ Object.setPrototypeOf(this, _BrowserElementNotFoundError.prototype);
16980
+ }
16981
+ };
16982
+
16983
+ // src/integrations/browser/agent-browser/command-executor.ts
16984
+ import { execSync, spawn as spawn4 } from "child_process";
16985
+ var AgentBrowserCommandExecutor = class {
16986
+ config;
16987
+ browserLaunched = false;
16988
+ constructor(config = {}) {
16989
+ this.config = {
16990
+ sessionName: config.sessionName ?? "default",
16991
+ timeout: config.timeout ?? 3e4,
16992
+ headed: config.headed ?? false,
16993
+ debug: config.debug ?? false
16994
+ };
16995
+ }
16996
+ // ========================================================================
16997
+ // Core execution methods
16998
+ // ========================================================================
16999
+ /**
17000
+ * Execute a command synchronously and parse JSON result
17001
+ */
17002
+ execute(command, args = []) {
17003
+ const fullArgs = this.buildArgs(command, args);
17004
+ const cmdString = `npx agent-browser ${fullArgs.join(" ")}`;
17005
+ if (this.config.debug) {
17006
+ console.log(`[agent-browser] Executing: ${cmdString}`);
17007
+ }
17008
+ try {
17009
+ const output = execSync(cmdString, {
17010
+ encoding: "utf-8",
17011
+ timeout: this.config.timeout,
17012
+ maxBuffer: 10 * 1024 * 1024
17013
+ // 10MB for screenshots
17014
+ });
17015
+ try {
17016
+ const parsed = JSON.parse(output.trim());
17017
+ return { success: true, data: parsed };
17018
+ } catch {
17019
+ return { success: true, data: output.trim() };
17020
+ }
17021
+ } catch (error) {
17022
+ const message = error instanceof Error ? error.message : String(error);
17023
+ return { success: false, error: message };
17024
+ }
17025
+ }
17026
+ /**
17027
+ * Execute a command asynchronously (for long-running ops)
17028
+ */
17029
+ async executeAsync(command, args = []) {
17030
+ return new Promise((resolve7) => {
17031
+ const fullArgs = this.buildArgs(command, args);
17032
+ if (this.config.debug) {
17033
+ console.log(`[agent-browser] Executing async: npx agent-browser ${fullArgs.join(" ")}`);
17034
+ }
17035
+ const process2 = spawn4("npx", ["agent-browser", ...fullArgs], {
17036
+ timeout: this.config.timeout
17037
+ });
17038
+ let stdout = "";
17039
+ let stderr = "";
17040
+ process2.stdout?.on("data", (data) => {
17041
+ stdout += data.toString();
17042
+ });
17043
+ process2.stderr?.on("data", (data) => {
17044
+ stderr += data.toString();
17045
+ });
17046
+ process2.on("close", (code) => {
17047
+ if (code === 0) {
17048
+ try {
17049
+ const parsed = JSON.parse(stdout.trim());
17050
+ resolve7({ success: true, data: parsed });
17051
+ } catch {
17052
+ resolve7({ success: true, data: stdout.trim() });
17053
+ }
17054
+ } else {
17055
+ resolve7({ success: false, error: stderr || `Exit code: ${code}` });
17056
+ }
17057
+ });
17058
+ process2.on("error", (error) => {
17059
+ resolve7({ success: false, error: error.message });
17060
+ });
17061
+ });
17062
+ }
17063
+ // ========================================================================
17064
+ // Browser lifecycle commands
17065
+ // ========================================================================
17066
+ /**
17067
+ * Open URL in browser (auto-launches if needed)
17068
+ */
17069
+ open(url) {
17070
+ const args = [url];
17071
+ if (this.config.headed) {
17072
+ args.push("--headed");
17073
+ }
17074
+ const result = this.execute("open", args);
17075
+ if (result.success) {
17076
+ this.browserLaunched = true;
17077
+ }
17078
+ return result;
17079
+ }
17080
+ /**
17081
+ * Close browser
17082
+ */
17083
+ close() {
17084
+ const result = this.execute("close");
17085
+ if (result.success) {
17086
+ this.browserLaunched = false;
17087
+ }
17088
+ return result;
17089
+ }
17090
+ /**
17091
+ * Terminate the daemon process for this session
17092
+ * CRITICAL: Must be called to prevent memory leaks!
17093
+ * The daemon persists even after close() - this kills it entirely.
17094
+ */
17095
+ terminateDaemon() {
17096
+ try {
17097
+ this.close();
17098
+ const sessionName = this.config.sessionName;
17099
+ try {
17100
+ execSync(
17101
+ `pkill -f "agent-browser.*--session[= ]${sessionName}" 2>/dev/null || true`,
17102
+ { timeout: 5e3, stdio: "ignore" }
17103
+ );
17104
+ } catch {
17105
+ }
17106
+ this.browserLaunched = false;
17107
+ return { success: true };
17108
+ } catch (error) {
17109
+ return {
17110
+ success: false,
17111
+ error: error instanceof Error ? error.message : "Failed to terminate daemon"
17112
+ };
17113
+ }
17114
+ }
17115
+ // ========================================================================
17116
+ // Snapshot commands (key feature)
17117
+ // ========================================================================
17118
+ /**
17119
+ * Get accessibility snapshot with refs
17120
+ */
17121
+ snapshot(options) {
17122
+ const args = ["--json"];
17123
+ if (options?.interactive) args.push("-i");
17124
+ if (options?.compact) args.push("-c");
17125
+ if (options?.depth) args.push("-d", String(options.depth));
17126
+ return this.execute("snapshot", args);
17127
+ }
17128
+ // ========================================================================
17129
+ // Element interaction commands
17130
+ // ========================================================================
17131
+ /**
17132
+ * Click element by ref or selector
17133
+ */
17134
+ click(target) {
17135
+ return this.execute("click", [target]);
17136
+ }
17137
+ /**
17138
+ * Fill input by ref or selector
17139
+ */
17140
+ fill(target, text) {
17141
+ return this.execute("fill", [target, `"${text.replace(/"/g, '\\"')}"`]);
17142
+ }
17143
+ /**
17144
+ * Type text (without clearing)
17145
+ */
17146
+ type(target, text) {
17147
+ return this.execute("type", [target, `"${text.replace(/"/g, '\\"')}"`]);
17148
+ }
17149
+ /**
17150
+ * Get element text
17151
+ */
17152
+ getText(target) {
17153
+ return this.execute("get", ["text", target, "--json"]);
17154
+ }
17155
+ /**
17156
+ * Check if element is visible
17157
+ */
17158
+ isVisible(target) {
17159
+ const result = this.execute("is", ["visible", target, "--json"]);
17160
+ if (result.success && result.data) {
17161
+ return { success: true, data: result.data.success };
17162
+ }
17163
+ return { success: false, error: result.error };
17164
+ }
17165
+ // ========================================================================
17166
+ // Screenshot commands
17167
+ // ========================================================================
17168
+ /**
17169
+ * Take screenshot
17170
+ */
17171
+ screenshot(path13, fullPage) {
17172
+ const args = [];
17173
+ if (path13) args.push(path13);
17174
+ if (fullPage) args.push("--full");
17175
+ if (!path13) args.push("--json");
17176
+ return this.execute("screenshot", args);
17177
+ }
17178
+ // ========================================================================
17179
+ // Wait commands
17180
+ // ========================================================================
17181
+ /**
17182
+ * Wait for element
17183
+ */
17184
+ waitForElement(target, timeout) {
17185
+ const args = [target];
17186
+ if (timeout) {
17187
+ return this.execute("wait", args);
17188
+ }
17189
+ return this.execute("wait", args);
17190
+ }
17191
+ /**
17192
+ * Wait for text to appear
17193
+ */
17194
+ waitForText(text) {
17195
+ return this.execute("wait", ["--text", text]);
17196
+ }
17197
+ /**
17198
+ * Wait for URL pattern
17199
+ */
17200
+ waitForUrl(pattern) {
17201
+ const urlPattern = pattern.includes("*") ? pattern : `**${pattern}**`;
17202
+ return this.execute("wait", ["--url", urlPattern]);
17203
+ }
17204
+ /**
17205
+ * Wait for network idle
17206
+ */
17207
+ waitForNetworkIdle() {
17208
+ return this.execute("wait", ["--load", "networkidle"]);
17209
+ }
17210
+ // ========================================================================
17211
+ // Device/viewport commands
17212
+ // ========================================================================
17213
+ /**
17214
+ * Set device emulation
17215
+ */
17216
+ setDevice(deviceName) {
17217
+ return this.execute("set", ["device", `"${deviceName}"`]);
17218
+ }
17219
+ /**
17220
+ * Set viewport size
17221
+ */
17222
+ setViewport(width, height) {
17223
+ return this.execute("set", ["viewport", String(width), String(height)]);
17224
+ }
17225
+ // ========================================================================
17226
+ // Network commands
17227
+ // ========================================================================
17228
+ /**
17229
+ * Mock network route
17230
+ */
17231
+ mockRoute(urlPattern, body) {
17232
+ const bodyJson = JSON.stringify(body).replace(/"/g, '\\"');
17233
+ return this.execute("network", ["route", urlPattern, "--body", `"${bodyJson}"`]);
17234
+ }
17235
+ /**
17236
+ * Abort network route
17237
+ */
17238
+ abortRoute(urlPattern) {
17239
+ return this.execute("network", ["route", urlPattern, "--abort"]);
17240
+ }
17241
+ /**
17242
+ * Clear network routes
17243
+ */
17244
+ clearRoutes() {
17245
+ return this.execute("network", ["unroute"]);
17246
+ }
17247
+ // ========================================================================
17248
+ // State commands
17249
+ // ========================================================================
17250
+ /**
17251
+ * Save browser state (cookies, storage)
17252
+ */
17253
+ saveState(path13) {
17254
+ return this.execute("state", ["save", path13]);
17255
+ }
17256
+ /**
17257
+ * Load browser state
17258
+ */
17259
+ loadState(path13) {
17260
+ return this.execute("state", ["load", path13]);
17261
+ }
17262
+ // ========================================================================
17263
+ // Trace recording
17264
+ // ========================================================================
17265
+ /**
17266
+ * Start trace recording
17267
+ * Records browser activity for debugging and analysis
17268
+ */
17269
+ startTrace() {
17270
+ return this.execute("trace", ["start"]);
17271
+ }
17272
+ /**
17273
+ * Stop trace recording and save to file
17274
+ * @param outputPath - Path to save the trace file
17275
+ */
17276
+ stopTrace(outputPath) {
17277
+ const result = this.execute("trace", ["stop", outputPath]);
17278
+ if (result.success) {
17279
+ return { success: true, data: outputPath };
17280
+ }
17281
+ return { success: false, error: result.error };
17282
+ }
17283
+ // ========================================================================
17284
+ // JavaScript evaluation
17285
+ // ========================================================================
17286
+ /**
17287
+ * Evaluate JavaScript in page context
17288
+ */
17289
+ eval(script) {
17290
+ const escapedScript = script.replace(/"/g, '\\"').replace(/\n/g, " ");
17291
+ return this.execute("eval", [`"${escapedScript}"`, "--json"]);
17292
+ }
17293
+ // ========================================================================
17294
+ // Session info
17295
+ // ========================================================================
17296
+ /**
17297
+ * Get current session name
17298
+ */
17299
+ getSessionName() {
17300
+ return this.config.sessionName;
17301
+ }
17302
+ /**
17303
+ * Check if browser is launched
17304
+ */
17305
+ isBrowserLaunched() {
17306
+ return this.browserLaunched;
17307
+ }
17308
+ // ========================================================================
17309
+ // Private helpers
17310
+ // ========================================================================
17311
+ buildArgs(command, args) {
17312
+ const fullArgs = [];
17313
+ if (this.config.sessionName !== "default") {
17314
+ fullArgs.push("--session", this.config.sessionName);
17315
+ }
17316
+ fullArgs.push(command, ...args);
17317
+ return fullArgs;
17318
+ }
17319
+ };
17320
+ function isAgentBrowserAvailable() {
17321
+ try {
17322
+ const output = execSync("npx agent-browser 2>&1", { encoding: "utf-8", timeout: 1e4 });
17323
+ return output.includes("agent-browser") && output.includes("Usage:");
17324
+ } catch {
17325
+ return false;
17326
+ }
17327
+ }
17328
+
17329
+ // src/integrations/browser/agent-browser/snapshot-parser.ts
17330
+ var INTERACTIVE_ROLES = /* @__PURE__ */ new Set([
17331
+ "button",
17332
+ "link",
17333
+ "textbox",
17334
+ "checkbox",
17335
+ "radio",
17336
+ "combobox",
17337
+ "listbox",
17338
+ "menuitem",
17339
+ "menuitemcheckbox",
17340
+ "menuitemradio",
17341
+ "option",
17342
+ "searchbox",
17343
+ "slider",
17344
+ "spinbutton",
17345
+ "switch",
17346
+ "tab",
17347
+ "treeitem"
17348
+ ]);
17349
+ var SnapshotParser = class {
17350
+ /**
17351
+ * Parse raw snapshot text into structured format
17352
+ */
17353
+ parse(snapshotOutput) {
17354
+ const lines = snapshotOutput.split("\n");
17355
+ const elements = [];
17356
+ const refMap = /* @__PURE__ */ new Map();
17357
+ let maxDepth = 0;
17358
+ for (const line of lines) {
17359
+ const element = this.parseLine(line);
17360
+ if (element) {
17361
+ elements.push(element);
17362
+ refMap.set(element.ref, element);
17363
+ if (element.depth > maxDepth) {
17364
+ maxDepth = element.depth;
17365
+ }
17366
+ }
17367
+ }
17368
+ this.buildRelationships(elements);
17369
+ const interactiveElements = elements.filter(
17370
+ (el) => INTERACTIVE_ROLES.has(el.role.toLowerCase())
17371
+ );
17372
+ return {
17373
+ rawTree: snapshotOutput,
17374
+ elements,
17375
+ interactiveElements,
17376
+ refMap,
17377
+ stats: {
17378
+ totalElements: elements.length,
17379
+ interactiveCount: interactiveElements.length,
17380
+ maxDepth
17381
+ },
17382
+ parsedAt: /* @__PURE__ */ new Date()
17383
+ };
17384
+ }
17385
+ /**
17386
+ * Parse JSON output from `agent-browser snapshot --json`
17387
+ */
17388
+ parseJson(jsonOutput) {
17389
+ const data = typeof jsonOutput === "string" ? JSON.parse(jsonOutput) : jsonOutput;
17390
+ if (data.success && data.data) {
17391
+ const snapshot = data.data.snapshot || data.data;
17392
+ const refs = data.data.refs || {};
17393
+ return this.parseWithRefs(snapshot, refs);
17394
+ }
17395
+ if (typeof data === "string") {
17396
+ return this.parse(data);
17397
+ }
17398
+ throw new Error("Invalid snapshot JSON format");
17399
+ }
17400
+ /**
17401
+ * Parse snapshot with pre-extracted refs (from JSON)
17402
+ */
17403
+ parseWithRefs(tree, refs) {
17404
+ const elements = [];
17405
+ const refMap = /* @__PURE__ */ new Map();
17406
+ let maxDepth = 0;
17407
+ for (const [refId, refData] of Object.entries(refs)) {
17408
+ const element = {
17409
+ ref: refId,
17410
+ refWithAt: `@${refId}`,
17411
+ role: refData.role,
17412
+ name: refData.name,
17413
+ attributes: {},
17414
+ depth: 0,
17415
+ children: []
17416
+ };
17417
+ elements.push(element);
17418
+ refMap.set(refId, element);
17419
+ }
17420
+ const treeElements = this.parse(tree);
17421
+ for (const treeEl of treeElements.elements) {
17422
+ const existing = refMap.get(treeEl.ref);
17423
+ if (existing) {
17424
+ existing.text = treeEl.text;
17425
+ existing.depth = treeEl.depth;
17426
+ existing.level = treeEl.level;
17427
+ if (treeEl.depth > maxDepth) maxDepth = treeEl.depth;
17428
+ }
17429
+ }
17430
+ const interactiveElements = elements.filter(
17431
+ (el) => INTERACTIVE_ROLES.has(el.role.toLowerCase())
17432
+ );
17433
+ return {
17434
+ rawTree: tree,
17435
+ elements,
17436
+ interactiveElements,
17437
+ refMap,
17438
+ stats: {
17439
+ totalElements: elements.length,
17440
+ interactiveCount: interactiveElements.length,
17441
+ maxDepth
17442
+ },
17443
+ parsedAt: /* @__PURE__ */ new Date()
17444
+ };
17445
+ }
17446
+ /**
17447
+ * Parse a single line from snapshot output
17448
+ */
17449
+ parseLine(line) {
17450
+ if (!line.trim()) return null;
17451
+ const depth = this.getIndentLevel(line);
17452
+ const match = line.match(/^(\s*-\s*)(\w+)(?:\s+"([^"]*)")?(.*)$/);
17453
+ if (!match) return null;
17454
+ const [, , role, name, suffix] = match;
17455
+ const refMatch = suffix?.match(/\[ref=(\w+)\]/);
17456
+ if (!refMatch) return null;
17457
+ const ref = refMatch[1];
17458
+ const levelMatch = suffix?.match(/\[level=(\d+)\]/);
17459
+ const level = levelMatch ? parseInt(levelMatch[1], 10) : void 0;
17460
+ const nthMatch = suffix?.match(/\[nth=(\d+)\]/);
17461
+ const nth = nthMatch ? parseInt(nthMatch[1], 10) : void 0;
17462
+ const textMatch = line.match(/:\s*(.+)$/);
17463
+ const text = textMatch ? textMatch[1].trim() : void 0;
17464
+ const attributes = {};
17465
+ if (level) attributes["level"] = String(level);
17466
+ if (nth !== void 0) attributes["nth"] = String(nth);
17467
+ return {
17468
+ ref,
17469
+ refWithAt: `@${ref}`,
17470
+ role: role.toLowerCase(),
17471
+ name,
17472
+ text,
17473
+ level,
17474
+ attributes,
17475
+ depth,
17476
+ children: []
17477
+ };
17478
+ }
17479
+ /**
17480
+ * Get indentation level (2 spaces per level)
17481
+ */
17482
+ getIndentLevel(line) {
17483
+ const match = line.match(/^(\s*)/);
17484
+ return match ? Math.floor(match[1].length / 2) : 0;
17485
+ }
17486
+ /**
17487
+ * Build parent-child relationships between elements
17488
+ */
17489
+ buildRelationships(elements) {
17490
+ const stack = [];
17491
+ for (const element of elements) {
17492
+ while (stack.length > 0 && stack[stack.length - 1].depth >= element.depth) {
17493
+ stack.pop();
17494
+ }
17495
+ if (stack.length > 0) {
17496
+ const parent = stack[stack.length - 1];
17497
+ element.parent = parent.ref;
17498
+ parent.children.push(element.ref);
17499
+ }
17500
+ stack.push(element);
17501
+ }
17502
+ }
17503
+ // ========================================================================
17504
+ // Query methods
17505
+ // ========================================================================
17506
+ /**
17507
+ * Find element by ref
17508
+ */
17509
+ findByRef(snapshot, ref) {
17510
+ const normalizedRef = ref.startsWith("@") ? ref.slice(1) : ref;
17511
+ return snapshot.refMap.get(normalizedRef) || null;
17512
+ }
17513
+ /**
17514
+ * Find elements by role
17515
+ */
17516
+ findByRole(snapshot, role) {
17517
+ return snapshot.elements.filter(
17518
+ (el) => el.role.toLowerCase() === role.toLowerCase()
17519
+ );
17520
+ }
17521
+ /**
17522
+ * Find elements by name (accessible name)
17523
+ */
17524
+ findByName(snapshot, name, exact = false) {
17525
+ return snapshot.elements.filter((el) => {
17526
+ if (!el.name) return false;
17527
+ if (exact) return el.name === name;
17528
+ return el.name.toLowerCase().includes(name.toLowerCase());
17529
+ });
17530
+ }
17531
+ /**
17532
+ * Find elements by text content
17533
+ */
17534
+ findByText(snapshot, text, exact = false) {
17535
+ return snapshot.elements.filter((el) => {
17536
+ const content = el.text || el.name || "";
17537
+ if (exact) return content === text;
17538
+ return content.toLowerCase().includes(text.toLowerCase());
17539
+ });
17540
+ }
17541
+ /**
17542
+ * Find first interactive element matching criteria
17543
+ */
17544
+ findInteractive(snapshot, criteria) {
17545
+ for (const el of snapshot.interactiveElements) {
17546
+ if (criteria.role && el.role.toLowerCase() !== criteria.role.toLowerCase()) {
17547
+ continue;
17548
+ }
17549
+ if (criteria.name && el.name !== criteria.name) {
17550
+ continue;
17551
+ }
17552
+ if (criteria.text) {
17553
+ const content = el.text || el.name || "";
17554
+ if (!content.toLowerCase().includes(criteria.text.toLowerCase())) {
17555
+ continue;
17556
+ }
17557
+ }
17558
+ return el;
17559
+ }
17560
+ return null;
17561
+ }
17562
+ /**
17563
+ * Convert ref to CSS selector (for Vibium fallback)
17564
+ * Uses role + name as best guess
17565
+ */
17566
+ refToCssSelector(snapshot, ref) {
17567
+ const element = this.findByRef(snapshot, ref);
17568
+ if (!element) return null;
17569
+ const role = element.role;
17570
+ const name = element.name;
17571
+ const selectorMap = {
17572
+ button: name ? `button:has-text("${name}")` : "button",
17573
+ link: name ? `a:has-text("${name}")` : "a",
17574
+ textbox: name ? `input[placeholder="${name}"], input[aria-label="${name}"]` : 'input[type="text"]',
17575
+ heading: name ? `h1:has-text("${name}"), h2:has-text("${name}"), h3:has-text("${name}")` : "h1, h2, h3",
17576
+ checkbox: name ? `input[type="checkbox"][aria-label="${name}"]` : 'input[type="checkbox"]'
17577
+ };
17578
+ return selectorMap[role] || `[role="${role}"]`;
17579
+ }
17580
+ };
17581
+ var parserInstance = null;
17582
+ function getSnapshotParser() {
17583
+ if (!parserInstance) {
17584
+ parserInstance = new SnapshotParser();
17585
+ }
17586
+ return parserInstance;
17587
+ }
17588
+
17589
+ // src/integrations/browser/agent-browser/session-manager.ts
17590
+ import { execSync as execSync2 } from "child_process";
17591
+ var AgentBrowserSessionManager = class {
17592
+ constructor(defaultConfig) {
17593
+ this.defaultConfig = defaultConfig;
17594
+ }
17595
+ sessions = /* @__PURE__ */ new Map();
17596
+ activeSession = null;
17597
+ sessionCounter = 0;
17598
+ // ========================================================================
17599
+ // Session lifecycle
17600
+ // ========================================================================
17601
+ /**
17602
+ * Create a new isolated session
17603
+ */
17604
+ async createSession(options) {
17605
+ const name = options?.name ?? this.generateSessionName();
17606
+ if (this.sessions.has(name)) {
17607
+ throw new Error(`Session "${name}" already exists`);
17608
+ }
17609
+ const executor = new AgentBrowserCommandExecutor({
17610
+ sessionName: name,
17611
+ headed: options?.headed ?? this.defaultConfig?.headed ?? false,
17612
+ timeout: options?.timeout ?? this.defaultConfig?.timeout ?? 3e4
17613
+ });
17614
+ const session = {
17615
+ name,
17616
+ createdAt: /* @__PURE__ */ new Date(),
17617
+ lastActivity: /* @__PURE__ */ new Date(),
17618
+ status: "idle",
17619
+ executor
17620
+ };
17621
+ this.sessions.set(name, session);
17622
+ if (options?.initialUrl) {
17623
+ const result = executor.open(options.initialUrl);
17624
+ if (result.success) {
17625
+ session.currentUrl = options.initialUrl;
17626
+ session.status = "active";
17627
+ }
17628
+ }
17629
+ if (!this.activeSession) {
17630
+ this.activeSession = name;
17631
+ }
17632
+ return session;
17633
+ }
17634
+ /**
17635
+ * Get or create a session by name
17636
+ */
17637
+ async getOrCreateSession(name, options) {
17638
+ const existing = this.sessions.get(name);
17639
+ if (existing) {
17640
+ return existing;
17641
+ }
17642
+ return this.createSession({ ...options, name });
17643
+ }
17644
+ /**
17645
+ * Get session by name
17646
+ */
17647
+ getSession(name) {
17648
+ return this.sessions.get(name);
17649
+ }
17650
+ /**
17651
+ * Get currently active session
17652
+ */
17653
+ getActiveSession() {
17654
+ if (!this.activeSession) return void 0;
17655
+ return this.sessions.get(this.activeSession);
17656
+ }
17657
+ /**
17658
+ * Switch to a different session
17659
+ */
17660
+ switchSession(name) {
17661
+ if (!this.sessions.has(name)) {
17662
+ throw new Error(`Session "${name}" not found`);
17663
+ }
17664
+ this.activeSession = name;
17665
+ }
17666
+ /**
17667
+ * List all sessions
17668
+ */
17669
+ listSessions() {
17670
+ return Array.from(this.sessions.values());
17671
+ }
17672
+ /**
17673
+ * List active session names from CLI
17674
+ */
17675
+ listCliSessions() {
17676
+ try {
17677
+ const output = execSync2("npx agent-browser session list", {
17678
+ encoding: "utf-8",
17679
+ timeout: 5e3
17680
+ });
17681
+ const lines = output.split("\n");
17682
+ const sessions = [];
17683
+ for (const line of lines) {
17684
+ const match = line.match(/^\s*(?:->)?\s*(\w+)\s*$/);
17685
+ if (match) {
17686
+ sessions.push(match[1]);
17687
+ }
17688
+ }
17689
+ return sessions;
17690
+ } catch {
17691
+ return [];
17692
+ }
17693
+ }
17694
+ // ========================================================================
17695
+ // Session control
17696
+ // ========================================================================
17697
+ /**
17698
+ * Close a specific session
17699
+ */
17700
+ async closeSession(name) {
17701
+ const session = this.sessions.get(name);
17702
+ if (!session) {
17703
+ return { success: false, error: `Session "${name}" not found` };
17704
+ }
17705
+ const result = session.executor.terminateDaemon();
17706
+ if (result.success) {
17707
+ session.status = "closed";
17708
+ this.sessions.delete(name);
17709
+ if (this.activeSession === name) {
17710
+ const remaining = Array.from(this.sessions.keys());
17711
+ this.activeSession = remaining.length > 0 ? remaining[0] : null;
17712
+ }
17713
+ }
17714
+ return result;
17715
+ }
17716
+ /**
17717
+ * Close all sessions
17718
+ */
17719
+ async closeAllSessions() {
17720
+ const names = Array.from(this.sessions.keys());
17721
+ for (const name of names) {
17722
+ await this.closeSession(name);
17723
+ }
17724
+ this.sessions.clear();
17725
+ this.activeSession = null;
17726
+ }
17727
+ /**
17728
+ * Clean up idle sessions older than maxAge
17729
+ */
17730
+ async cleanupIdleSessions(maxAgeMs = 5 * 60 * 1e3) {
17731
+ const now = Date.now();
17732
+ let closedCount = 0;
17733
+ for (const [name, session] of this.sessions) {
17734
+ if (session.status === "idle") {
17735
+ const age = now - session.lastActivity.getTime();
17736
+ if (age > maxAgeMs) {
17737
+ await this.closeSession(name);
17738
+ closedCount++;
17739
+ }
17740
+ }
17741
+ }
17742
+ return closedCount;
17743
+ }
17744
+ // ========================================================================
17745
+ // Session operations via active session
17746
+ // ========================================================================
17747
+ /**
17748
+ * Get executor for active session
17749
+ */
17750
+ getExecutor() {
17751
+ const session = this.getActiveSession();
17752
+ if (!session) {
17753
+ throw new Error("No active session. Create one first.");
17754
+ }
17755
+ return session.executor;
17756
+ }
17757
+ /**
17758
+ * Get executor for specific session
17759
+ */
17760
+ getSessionExecutor(name) {
17761
+ const session = this.sessions.get(name);
17762
+ if (!session) {
17763
+ throw new Error(`Session "${name}" not found`);
17764
+ }
17765
+ return session.executor;
17766
+ }
17767
+ /**
17768
+ * Update session activity timestamp
17769
+ */
17770
+ touchSession(name) {
17771
+ const session = this.sessions.get(name);
17772
+ if (session) {
17773
+ session.lastActivity = /* @__PURE__ */ new Date();
17774
+ }
17775
+ }
17776
+ /**
17777
+ * Update session URL
17778
+ */
17779
+ updateSessionUrl(name, url) {
17780
+ const session = this.sessions.get(name);
17781
+ if (session) {
17782
+ session.currentUrl = url;
17783
+ session.lastActivity = /* @__PURE__ */ new Date();
17784
+ session.status = "active";
17785
+ }
17786
+ }
17787
+ // ========================================================================
17788
+ // Private helpers
17789
+ // ========================================================================
17790
+ generateSessionName() {
17791
+ return `session-${++this.sessionCounter}-${Date.now().toString(36)}`;
17792
+ }
17793
+ // ========================================================================
17794
+ // Stats
17795
+ // ========================================================================
17796
+ /**
17797
+ * Get session statistics
17798
+ */
17799
+ getStats() {
17800
+ let active = 0;
17801
+ let idle = 0;
17802
+ let closed = 0;
17803
+ for (const session of this.sessions.values()) {
17804
+ switch (session.status) {
17805
+ case "active":
17806
+ active++;
17807
+ break;
17808
+ case "idle":
17809
+ idle++;
17810
+ break;
17811
+ case "closed":
17812
+ closed++;
17813
+ break;
17814
+ }
17815
+ }
17816
+ return {
17817
+ totalSessions: this.sessions.size,
17818
+ activeSessions: active,
17819
+ idleSessions: idle,
17820
+ closedSessions: closed,
17821
+ activeSessionName: this.activeSession
17822
+ };
17823
+ }
17824
+ };
17825
+
17826
+ // src/integrations/browser/agent-browser/client.ts
17827
+ function resolveTarget(target) {
17828
+ if (typeof target === "string") {
17829
+ if (/^@?e\d+$/.test(target)) {
17830
+ return target.startsWith("@") ? target : `@${target}`;
17831
+ }
17832
+ return target;
17833
+ }
17834
+ switch (target.type) {
17835
+ case "ref":
17836
+ return target.value.startsWith("@") ? target.value : `@${target.value}`;
17837
+ case "css":
17838
+ return target.value;
17839
+ case "xpath":
17840
+ return `xpath=${target.value}`;
17841
+ case "text":
17842
+ return `text=${target.value}`;
17843
+ default:
17844
+ return target.value;
17845
+ }
17846
+ }
17847
+ function ok2(value) {
17848
+ return { success: true, value };
17849
+ }
17850
+ function err2(error) {
17851
+ return { success: false, error };
17852
+ }
17853
+ function toSessionInfo(info) {
17854
+ return {
17855
+ id: info.name,
17856
+ tool: "agent-browser",
17857
+ status: info.status,
17858
+ currentUrl: info.currentUrl,
17859
+ createdAt: info.createdAt
17860
+ };
17861
+ }
17862
+ function toTypedSnapshot(parsed) {
17863
+ const elements = parsed.elements.map((el) => ({
17864
+ ref: el.refWithAt,
17865
+ role: el.role,
17866
+ name: el.name,
17867
+ text: el.text,
17868
+ depth: el.depth
17869
+ }));
17870
+ const interactiveElements = parsed.interactiveElements.map((el) => ({
17871
+ ref: el.refWithAt,
17872
+ role: el.role,
17873
+ name: el.name,
17874
+ text: el.text,
17875
+ depth: el.depth
17876
+ }));
17877
+ const refMap = /* @__PURE__ */ new Map();
17878
+ for (const el of elements) {
17879
+ refMap.set(el.ref, el);
17880
+ }
17881
+ return {
17882
+ url: parsed.url ?? "",
17883
+ title: parsed.title ?? "",
17884
+ elements,
17885
+ interactiveElements,
17886
+ refMap,
17887
+ timestamp: parsed.parsedAt
17888
+ };
17889
+ }
17890
+ var AgentBrowserClient = class {
17891
+ tool = "agent-browser";
17892
+ executor;
17893
+ sessionManager;
17894
+ snapshotParser;
17895
+ config;
17896
+ isLaunched = false;
17897
+ currentSessionId = null;
17898
+ constructor(config = {}) {
17899
+ this.config = {
17900
+ headed: config.headed ?? false,
17901
+ timeout: config.timeout ?? 3e4,
17902
+ debug: config.debug ?? false,
17903
+ sessionName: config.sessionName ?? "default"
17904
+ };
17905
+ const executorConfig = {
17906
+ sessionName: this.config.sessionName,
17907
+ timeout: this.config.timeout,
17908
+ headed: this.config.headed,
17909
+ debug: this.config.debug
17910
+ };
17911
+ this.executor = new AgentBrowserCommandExecutor(executorConfig);
17912
+ this.sessionManager = new AgentBrowserSessionManager({
17913
+ headed: this.config.headed,
17914
+ timeout: this.config.timeout
17915
+ });
17916
+ this.snapshotParser = getSnapshotParser();
17917
+ }
17918
+ // ==========================================================================
17919
+ // Lifecycle
17920
+ // ==========================================================================
17921
+ /**
17922
+ * Launch a browser instance
17923
+ */
17924
+ async launch(options) {
17925
+ try {
17926
+ if (this.isLaunched && this.currentSessionId) {
17927
+ const existingSession = this.sessionManager.getSession(this.currentSessionId);
17928
+ if (existingSession) {
17929
+ if (options?.viewport) {
17930
+ await this.setViewport(options.viewport.width, options.viewport.height);
17931
+ }
17932
+ return ok2(toSessionInfo(existingSession));
17933
+ }
17934
+ }
17935
+ const available = await this.isAvailable();
17936
+ if (!available) {
17937
+ return err2(new BrowserUnavailableError("agent-browser", "agent-browser CLI is not available"));
17938
+ }
17939
+ const sessionName = options?.sessionName ?? this.config.sessionName;
17940
+ const session = await this.sessionManager.createSession({
17941
+ name: sessionName,
17942
+ headed: options?.headless === false || this.config.headed,
17943
+ timeout: this.config.timeout
17944
+ });
17945
+ this.currentSessionId = session.name;
17946
+ this.isLaunched = true;
17947
+ this.executor = new AgentBrowserCommandExecutor({
17948
+ sessionName: session.name,
17949
+ timeout: this.config.timeout,
17950
+ headed: options?.headless === false || this.config.headed,
17951
+ debug: this.config.debug
17952
+ });
17953
+ if (options?.viewport) {
17954
+ await this.setViewport(options.viewport.width, options.viewport.height);
17955
+ }
17956
+ if (options?.deviceName) {
17957
+ await this.setDevice(options.deviceName);
17958
+ }
17959
+ return ok2(toSessionInfo(session));
17960
+ } catch (error) {
17961
+ const browserError = new BrowserError(
17962
+ error instanceof Error ? error.message : String(error),
17963
+ "LAUNCH_FAILED",
17964
+ "agent-browser",
17965
+ error instanceof Error ? error : void 0
17966
+ );
17967
+ return err2(browserError);
17968
+ }
17969
+ }
17970
+ /**
17971
+ * Close the browser and terminate the daemon process
17972
+ * CRITICAL: This must fully terminate all processes to prevent memory leaks!
17973
+ */
17974
+ async quit() {
17975
+ try {
17976
+ if (this.currentSessionId) {
17977
+ const result = await this.sessionManager.closeSession(this.currentSessionId);
17978
+ if (!result.success) {
17979
+ if (this.config.debug) {
17980
+ console.warn(`[agent-browser] Session close warning: ${result.error}`);
17981
+ }
17982
+ }
17983
+ }
17984
+ if (this.executor) {
17985
+ try {
17986
+ this.executor.terminateDaemon();
17987
+ } catch {
17988
+ }
17989
+ }
17990
+ this.isLaunched = false;
17991
+ this.currentSessionId = null;
17992
+ return ok2(void 0);
17993
+ } catch (error) {
17994
+ this.isLaunched = false;
17995
+ this.currentSessionId = null;
17996
+ return err2(
17997
+ new BrowserError(
17998
+ error instanceof Error ? error.message : String(error),
17999
+ "QUIT_FAILED",
18000
+ "agent-browser",
18001
+ error instanceof Error ? error : void 0
18002
+ )
18003
+ );
18004
+ }
18005
+ }
18006
+ /**
18007
+ * Check if agent-browser CLI is available
18008
+ */
18009
+ async isAvailable() {
18010
+ return isAgentBrowserAvailable();
18011
+ }
18012
+ /**
18013
+ * Dispose all resources
18014
+ */
18015
+ async dispose() {
18016
+ await this.sessionManager.closeAllSessions();
18017
+ this.isLaunched = false;
18018
+ this.currentSessionId = null;
18019
+ }
18020
+ // ==========================================================================
18021
+ // Navigation
18022
+ // ==========================================================================
18023
+ /**
18024
+ * Navigate to a URL
18025
+ */
18026
+ async navigate(url) {
18027
+ const startTime = Date.now();
18028
+ try {
18029
+ const result = this.executor.open(url);
18030
+ if (!result.success) {
18031
+ return err2(new BrowserError(result.error ?? "Navigation failed", "NAVIGATION_FAILED", "agent-browser"));
18032
+ }
18033
+ if (this.currentSessionId) {
18034
+ this.sessionManager.updateSessionUrl(this.currentSessionId, url);
18035
+ }
18036
+ const evalResult = this.executor.eval(
18037
+ "JSON.stringify({ title: document.title, url: window.location.href })"
18038
+ );
18039
+ const pageInfo = evalResult.success && evalResult.data ? typeof evalResult.data === "string" ? JSON.parse(evalResult.data) : evalResult.data : { title: "", url };
18040
+ return ok2({
18041
+ url: pageInfo.url || url,
18042
+ title: pageInfo.title || "",
18043
+ success: true,
18044
+ durationMs: Date.now() - startTime
18045
+ });
18046
+ } catch (error) {
18047
+ return err2(
18048
+ new BrowserError(
18049
+ error instanceof Error ? error.message : String(error),
18050
+ "NAVIGATION_FAILED",
18051
+ "agent-browser",
18052
+ error instanceof Error ? error : void 0
18053
+ )
18054
+ );
18055
+ }
18056
+ }
18057
+ /**
18058
+ * Reload the current page
18059
+ */
18060
+ async reload() {
18061
+ try {
18062
+ const result = this.executor.eval("window.location.reload()");
18063
+ if (!result.success) {
18064
+ return err2(new BrowserError(result.error ?? "Reload failed", "RELOAD_FAILED", "agent-browser"));
18065
+ }
18066
+ return ok2(void 0);
18067
+ } catch (error) {
18068
+ return err2(
18069
+ new BrowserError(
18070
+ error instanceof Error ? error.message : String(error),
18071
+ "RELOAD_FAILED",
18072
+ "agent-browser",
18073
+ error instanceof Error ? error : void 0
18074
+ )
18075
+ );
18076
+ }
18077
+ }
18078
+ /**
18079
+ * Go back in browser history
18080
+ */
18081
+ async goBack() {
18082
+ try {
18083
+ const result = this.executor.eval("window.history.back()");
18084
+ if (!result.success) {
18085
+ return err2(new BrowserError(result.error ?? "Go back failed", "HISTORY_FAILED", "agent-browser"));
18086
+ }
18087
+ return ok2(void 0);
18088
+ } catch (error) {
18089
+ return err2(
18090
+ new BrowserError(
18091
+ error instanceof Error ? error.message : String(error),
18092
+ "HISTORY_FAILED",
18093
+ "agent-browser",
18094
+ error instanceof Error ? error : void 0
18095
+ )
18096
+ );
18097
+ }
18098
+ }
18099
+ /**
18100
+ * Go forward in browser history
18101
+ */
18102
+ async goForward() {
18103
+ try {
18104
+ const result = this.executor.eval("window.history.forward()");
18105
+ if (!result.success) {
18106
+ return err2(new BrowserError(result.error ?? "Go forward failed", "HISTORY_FAILED", "agent-browser"));
18107
+ }
18108
+ return ok2(void 0);
18109
+ } catch (error) {
18110
+ return err2(
18111
+ new BrowserError(
18112
+ error instanceof Error ? error.message : String(error),
18113
+ "HISTORY_FAILED",
18114
+ "agent-browser",
18115
+ error instanceof Error ? error : void 0
18116
+ )
18117
+ );
18118
+ }
18119
+ }
18120
+ // ==========================================================================
18121
+ // Element Interaction
18122
+ // ==========================================================================
18123
+ /**
18124
+ * Click an element
18125
+ */
18126
+ async click(target) {
18127
+ try {
18128
+ const resolvedTarget = resolveTarget(target);
18129
+ const result = this.executor.click(resolvedTarget);
18130
+ if (!result.success) {
18131
+ return err2(new BrowserElementNotFoundError("agent-browser", target, new Error(result.error)));
18132
+ }
18133
+ return ok2(void 0);
18134
+ } catch (error) {
18135
+ return err2(
18136
+ new BrowserError(
18137
+ error instanceof Error ? error.message : String(error),
18138
+ "CLICK_FAILED",
18139
+ "agent-browser",
18140
+ error instanceof Error ? error : void 0
18141
+ )
18142
+ );
18143
+ }
18144
+ }
18145
+ /**
18146
+ * Fill input field with text
18147
+ */
18148
+ async fill(target, text) {
18149
+ try {
18150
+ const resolvedTarget = resolveTarget(target);
18151
+ const result = this.executor.fill(resolvedTarget, text);
18152
+ if (!result.success) {
18153
+ return err2(new BrowserElementNotFoundError("agent-browser", target, new Error(result.error)));
18154
+ }
18155
+ return ok2(void 0);
18156
+ } catch (error) {
18157
+ return err2(
18158
+ new BrowserError(
18159
+ error instanceof Error ? error.message : String(error),
18160
+ "FILL_FAILED",
18161
+ "agent-browser",
18162
+ error instanceof Error ? error : void 0
18163
+ )
18164
+ );
18165
+ }
18166
+ }
18167
+ /**
18168
+ * Get text content of an element
18169
+ */
18170
+ async getText(target) {
18171
+ try {
18172
+ const resolvedTarget = resolveTarget(target);
18173
+ const result = this.executor.getText(resolvedTarget);
18174
+ if (!result.success) {
18175
+ return err2(new BrowserElementNotFoundError("agent-browser", target, new Error(result.error)));
18176
+ }
18177
+ let text = result.data;
18178
+ if (text && typeof text === "object") {
18179
+ const obj = text;
18180
+ if ("text" in obj) {
18181
+ text = obj.text;
18182
+ } else if ("data" in obj && typeof obj.data === "object") {
18183
+ const dataObj = obj.data;
18184
+ if ("text" in dataObj) {
18185
+ text = dataObj.text;
18186
+ } else if ("result" in dataObj) {
18187
+ text = dataObj.result;
18188
+ }
18189
+ } else if ("result" in obj) {
18190
+ text = obj.result;
18191
+ }
18192
+ }
18193
+ return ok2(String(text ?? ""));
18194
+ } catch (error) {
18195
+ return err2(
18196
+ new BrowserError(
18197
+ error instanceof Error ? error.message : String(error),
18198
+ "GET_TEXT_FAILED",
18199
+ "agent-browser",
18200
+ error instanceof Error ? error : void 0
18201
+ )
18202
+ );
18203
+ }
18204
+ }
18205
+ /**
18206
+ * Check if element is visible
18207
+ */
18208
+ async isVisible(target) {
18209
+ try {
18210
+ const resolvedTarget = resolveTarget(target);
18211
+ const result = this.executor.isVisible(resolvedTarget);
18212
+ if (!result.success) {
18213
+ return ok2(false);
18214
+ }
18215
+ return ok2(Boolean(result.data));
18216
+ } catch (error) {
18217
+ return err2(
18218
+ new BrowserError(
18219
+ error instanceof Error ? error.message : String(error),
18220
+ "VISIBILITY_CHECK_FAILED",
18221
+ "agent-browser",
18222
+ error instanceof Error ? error : void 0
18223
+ )
18224
+ );
18225
+ }
18226
+ }
18227
+ // ==========================================================================
18228
+ // Screenshots
18229
+ // ==========================================================================
18230
+ /**
18231
+ * Capture a screenshot
18232
+ */
18233
+ async screenshot(options) {
18234
+ try {
18235
+ const result = this.executor.screenshot(options?.path, options?.fullPage);
18236
+ if (!result.success) {
18237
+ return err2(new BrowserError(result.error ?? "Screenshot failed", "SCREENSHOT_FAILED", "agent-browser"));
18238
+ }
18239
+ const dimensionsResult = this.executor.eval(
18240
+ "JSON.stringify({ width: window.innerWidth, height: window.innerHeight })"
18241
+ );
18242
+ let dimensions = { width: 1280, height: 720 };
18243
+ if (dimensionsResult.success && dimensionsResult.data) {
18244
+ const parsed = typeof dimensionsResult.data === "string" ? JSON.parse(dimensionsResult.data) : dimensionsResult.data;
18245
+ dimensions = { width: parsed.width || 1280, height: parsed.height || 720 };
18246
+ }
18247
+ return ok2({
18248
+ base64: options?.path ? void 0 : String(result.data ?? ""),
18249
+ path: options?.path,
18250
+ format: "png",
18251
+ dimensions
18252
+ });
18253
+ } catch (error) {
18254
+ return err2(
18255
+ new BrowserError(
18256
+ error instanceof Error ? error.message : String(error),
18257
+ "SCREENSHOT_FAILED",
18258
+ "agent-browser",
18259
+ error instanceof Error ? error : void 0
18260
+ )
18261
+ );
18262
+ }
18263
+ }
18264
+ // ==========================================================================
18265
+ // Script Evaluation
18266
+ // ==========================================================================
18267
+ /**
18268
+ * Evaluate JavaScript in the browser context
18269
+ */
18270
+ async evaluate(script) {
18271
+ try {
18272
+ const result = this.executor.eval(script);
18273
+ if (!result.success) {
18274
+ return err2(new BrowserError(result.error ?? "Evaluation failed", "EVAL_FAILED", "agent-browser"));
18275
+ }
18276
+ let value = result.data;
18277
+ if (value && typeof value === "object") {
18278
+ const obj = value;
18279
+ if ("data" in obj && obj.data && typeof obj.data === "object") {
18280
+ const dataObj = obj.data;
18281
+ if ("result" in dataObj) {
18282
+ value = dataObj.result;
18283
+ }
18284
+ } else if ("result" in obj) {
18285
+ value = obj.result;
18286
+ }
18287
+ }
18288
+ return ok2(value);
18289
+ } catch (error) {
18290
+ return err2(
18291
+ new BrowserError(
18292
+ error instanceof Error ? error.message : String(error),
18293
+ "EVAL_FAILED",
18294
+ "agent-browser",
18295
+ error instanceof Error ? error : void 0
18296
+ )
18297
+ );
18298
+ }
18299
+ }
18300
+ // ==========================================================================
18301
+ // Snapshots (agent-browser specific)
18302
+ // ==========================================================================
18303
+ /**
18304
+ * Get accessibility snapshot with element refs
18305
+ */
18306
+ async getSnapshot(options) {
18307
+ try {
18308
+ const result = this.executor.snapshot({
18309
+ interactive: options?.interactive,
18310
+ depth: options?.depth
18311
+ });
18312
+ if (!result.success) {
18313
+ return err2(new BrowserError(result.error ?? "Snapshot failed", "SNAPSHOT_FAILED", "agent-browser"));
18314
+ }
18315
+ let parsed;
18316
+ try {
18317
+ parsed = this.snapshotParser.parseJson(result.data);
18318
+ } catch {
18319
+ parsed = this.snapshotParser.parse(String(result.data));
18320
+ }
18321
+ const urlResult = this.executor.eval("window.location.href");
18322
+ const titleResult = this.executor.eval("document.title");
18323
+ if (urlResult.success) {
18324
+ parsed.url = String(urlResult.data);
18325
+ }
18326
+ if (titleResult.success) {
18327
+ parsed.title = String(titleResult.data);
18328
+ }
18329
+ return ok2(toTypedSnapshot(parsed));
18330
+ } catch (error) {
18331
+ return err2(
18332
+ new BrowserError(
18333
+ error instanceof Error ? error.message : String(error),
18334
+ "SNAPSHOT_FAILED",
18335
+ "agent-browser",
18336
+ error instanceof Error ? error : void 0
18337
+ )
18338
+ );
18339
+ }
18340
+ }
18341
+ // ==========================================================================
18342
+ // Session Management (agent-browser specific)
18343
+ // ==========================================================================
18344
+ /**
18345
+ * Create a new isolated session
18346
+ */
18347
+ async createSession(name) {
18348
+ try {
18349
+ const session = await this.sessionManager.createSession({ name });
18350
+ return ok2(toSessionInfo(session));
18351
+ } catch (error) {
18352
+ return err2(
18353
+ new BrowserError(
18354
+ error instanceof Error ? error.message : String(error),
18355
+ "SESSION_CREATE_FAILED",
18356
+ "agent-browser",
18357
+ error instanceof Error ? error : void 0
18358
+ )
18359
+ );
18360
+ }
18361
+ }
18362
+ /**
18363
+ * Switch to an existing session
18364
+ */
18365
+ async switchSession(name) {
18366
+ try {
18367
+ this.sessionManager.switchSession(name);
18368
+ this.currentSessionId = name;
18369
+ this.executor = new AgentBrowserCommandExecutor({
18370
+ sessionName: name,
18371
+ timeout: this.config.timeout,
18372
+ headed: this.config.headed,
18373
+ debug: this.config.debug
18374
+ });
18375
+ return ok2(void 0);
18376
+ } catch (error) {
18377
+ return err2(
18378
+ new BrowserError(
18379
+ error instanceof Error ? error.message : String(error),
18380
+ "SESSION_SWITCH_FAILED",
18381
+ "agent-browser",
18382
+ error instanceof Error ? error : void 0
18383
+ )
18384
+ );
18385
+ }
18386
+ }
18387
+ /**
18388
+ * List all available sessions
18389
+ */
18390
+ async listSessions() {
18391
+ try {
18392
+ const sessions = this.sessionManager.listSessions();
18393
+ return ok2(sessions.map(toSessionInfo));
18394
+ } catch (error) {
18395
+ return err2(
18396
+ new BrowserError(
18397
+ error instanceof Error ? error.message : String(error),
18398
+ "SESSION_LIST_FAILED",
18399
+ "agent-browser",
18400
+ error instanceof Error ? error : void 0
18401
+ )
18402
+ );
18403
+ }
18404
+ }
18405
+ // ==========================================================================
18406
+ // Network Interception (agent-browser specific)
18407
+ // ==========================================================================
18408
+ /**
18409
+ * Mock network route
18410
+ */
18411
+ async mockRoute(urlPattern, response) {
18412
+ try {
18413
+ const mockBody = {
18414
+ status: response.status ?? 200,
18415
+ body: response.body,
18416
+ headers: response.headers
18417
+ };
18418
+ const result = this.executor.mockRoute(urlPattern, mockBody);
18419
+ if (!result.success) {
18420
+ return err2(new BrowserError(result.error ?? "Mock route failed", "MOCK_ROUTE_FAILED", "agent-browser"));
18421
+ }
18422
+ return ok2(void 0);
18423
+ } catch (error) {
18424
+ return err2(
18425
+ new BrowserError(
18426
+ error instanceof Error ? error.message : String(error),
18427
+ "MOCK_ROUTE_FAILED",
18428
+ "agent-browser",
18429
+ error instanceof Error ? error : void 0
18430
+ )
18431
+ );
18432
+ }
18433
+ }
18434
+ /**
18435
+ * Abort requests matching a pattern
18436
+ */
18437
+ async abortRoute(urlPattern) {
18438
+ try {
18439
+ const result = this.executor.abortRoute(urlPattern);
18440
+ if (!result.success) {
18441
+ return err2(new BrowserError(result.error ?? "Abort route failed", "ABORT_ROUTE_FAILED", "agent-browser"));
18442
+ }
18443
+ return ok2(void 0);
18444
+ } catch (error) {
18445
+ return err2(
18446
+ new BrowserError(
18447
+ error instanceof Error ? error.message : String(error),
18448
+ "ABORT_ROUTE_FAILED",
18449
+ "agent-browser",
18450
+ error instanceof Error ? error : void 0
18451
+ )
18452
+ );
18453
+ }
18454
+ }
18455
+ /**
18456
+ * Clear all mocked routes
18457
+ */
18458
+ async clearRoutes() {
18459
+ try {
18460
+ const result = this.executor.clearRoutes();
18461
+ if (!result.success) {
18462
+ return err2(new BrowserError(result.error ?? "Clear routes failed", "CLEAR_ROUTES_FAILED", "agent-browser"));
18463
+ }
18464
+ return ok2(void 0);
18465
+ } catch (error) {
18466
+ return err2(
18467
+ new BrowserError(
18468
+ error instanceof Error ? error.message : String(error),
18469
+ "CLEAR_ROUTES_FAILED",
18470
+ "agent-browser",
18471
+ error instanceof Error ? error : void 0
18472
+ )
18473
+ );
18474
+ }
18475
+ }
18476
+ // ==========================================================================
18477
+ // Device Emulation (agent-browser specific)
18478
+ // ==========================================================================
18479
+ /**
18480
+ * Emulate a specific device
18481
+ */
18482
+ async setDevice(deviceName) {
18483
+ try {
18484
+ const result = this.executor.setDevice(deviceName);
18485
+ if (!result.success) {
18486
+ return err2(new BrowserError(result.error ?? "Set device failed", "SET_DEVICE_FAILED", "agent-browser"));
18487
+ }
18488
+ return ok2(void 0);
18489
+ } catch (error) {
18490
+ return err2(
18491
+ new BrowserError(
18492
+ error instanceof Error ? error.message : String(error),
18493
+ "SET_DEVICE_FAILED",
18494
+ "agent-browser",
18495
+ error instanceof Error ? error : void 0
18496
+ )
18497
+ );
18498
+ }
18499
+ }
18500
+ /**
18501
+ * Set custom viewport dimensions
18502
+ */
18503
+ async setViewport(width, height) {
18504
+ try {
18505
+ const result = this.executor.setViewport(width, height);
18506
+ if (!result.success) {
18507
+ return err2(new BrowserError(result.error ?? "Set viewport failed", "SET_VIEWPORT_FAILED", "agent-browser"));
18508
+ }
18509
+ return ok2(void 0);
18510
+ } catch (error) {
18511
+ return err2(
18512
+ new BrowserError(
18513
+ error instanceof Error ? error.message : String(error),
18514
+ "SET_VIEWPORT_FAILED",
18515
+ "agent-browser",
18516
+ error instanceof Error ? error : void 0
18517
+ )
18518
+ );
18519
+ }
18520
+ }
18521
+ // ==========================================================================
18522
+ // Authentication State Persistence (agent-browser specific)
18523
+ // ==========================================================================
18524
+ /**
18525
+ * Save browser state (cookies, storage, etc.)
18526
+ */
18527
+ async saveState(path13) {
18528
+ try {
18529
+ const result = this.executor.saveState(path13);
18530
+ if (!result.success) {
18531
+ return err2(new BrowserError(result.error ?? "Save state failed", "SAVE_STATE_FAILED", "agent-browser"));
18532
+ }
18533
+ return ok2(void 0);
18534
+ } catch (error) {
18535
+ return err2(
18536
+ new BrowserError(
18537
+ error instanceof Error ? error.message : String(error),
18538
+ "SAVE_STATE_FAILED",
18539
+ "agent-browser",
18540
+ error instanceof Error ? error : void 0
18541
+ )
18542
+ );
18543
+ }
18544
+ }
18545
+ /**
18546
+ * Load previously saved browser state
18547
+ */
18548
+ async loadState(path13) {
18549
+ try {
18550
+ const result = this.executor.loadState(path13);
18551
+ if (!result.success) {
18552
+ return err2(new BrowserError(result.error ?? "Load state failed", "LOAD_STATE_FAILED", "agent-browser"));
18553
+ }
18554
+ return ok2(void 0);
18555
+ } catch (error) {
18556
+ return err2(
18557
+ new BrowserError(
18558
+ error instanceof Error ? error.message : String(error),
18559
+ "LOAD_STATE_FAILED",
18560
+ "agent-browser",
18561
+ error instanceof Error ? error : void 0
18562
+ )
18563
+ );
18564
+ }
18565
+ }
18566
+ // ==========================================================================
18567
+ // Advanced Wait Strategies (agent-browser specific)
18568
+ // ==========================================================================
18569
+ /**
18570
+ * Wait for an element to be present
18571
+ */
18572
+ async waitForElement(target, timeout) {
18573
+ try {
18574
+ const resolvedTarget = resolveTarget(target);
18575
+ const result = this.executor.waitForElement(resolvedTarget, timeout);
18576
+ if (!result.success) {
18577
+ return err2(
18578
+ new BrowserTimeoutError("agent-browser", `waitForElement(${resolvedTarget})`, new Error(result.error))
18579
+ );
18580
+ }
18581
+ return ok2(void 0);
18582
+ } catch (error) {
18583
+ return err2(
18584
+ new BrowserError(
18585
+ error instanceof Error ? error.message : String(error),
18586
+ "WAIT_FAILED",
18587
+ "agent-browser",
18588
+ error instanceof Error ? error : void 0
18589
+ )
18590
+ );
18591
+ }
18592
+ }
18593
+ /**
18594
+ * Wait for text to appear on page
18595
+ */
18596
+ async waitForText(text, timeout) {
18597
+ try {
18598
+ void timeout;
18599
+ const result = this.executor.waitForText(text);
18600
+ if (!result.success) {
18601
+ return err2(new BrowserTimeoutError("agent-browser", `waitForText("${text}")`, new Error(result.error)));
18602
+ }
18603
+ return ok2(void 0);
18604
+ } catch (error) {
18605
+ return err2(
18606
+ new BrowserError(
18607
+ error instanceof Error ? error.message : String(error),
18608
+ "WAIT_FAILED",
18609
+ "agent-browser",
18610
+ error instanceof Error ? error : void 0
18611
+ )
18612
+ );
18613
+ }
18614
+ }
18615
+ /**
18616
+ * Wait for URL to match pattern
18617
+ */
18618
+ async waitForUrl(pattern, timeout) {
18619
+ try {
18620
+ void timeout;
18621
+ const result = this.executor.waitForUrl(pattern);
18622
+ if (!result.success) {
18623
+ return err2(new BrowserTimeoutError("agent-browser", `waitForUrl("${pattern}")`, new Error(result.error)));
18624
+ }
18625
+ return ok2(void 0);
18626
+ } catch (error) {
18627
+ return err2(
18628
+ new BrowserError(
18629
+ error instanceof Error ? error.message : String(error),
18630
+ "WAIT_FAILED",
18631
+ "agent-browser",
18632
+ error instanceof Error ? error : void 0
18633
+ )
18634
+ );
18635
+ }
18636
+ }
18637
+ /**
18638
+ * Wait for network to idle
18639
+ */
18640
+ async waitForNetworkIdle(timeout) {
18641
+ try {
18642
+ void timeout;
18643
+ const result = this.executor.waitForNetworkIdle();
18644
+ if (!result.success) {
18645
+ return err2(new BrowserTimeoutError("agent-browser", "waitForNetworkIdle", new Error(result.error)));
18646
+ }
18647
+ return ok2(void 0);
18648
+ } catch (error) {
18649
+ return err2(
18650
+ new BrowserError(
18651
+ error instanceof Error ? error.message : String(error),
18652
+ "WAIT_FAILED",
18653
+ "agent-browser",
18654
+ error instanceof Error ? error : void 0
18655
+ )
18656
+ );
18657
+ }
18658
+ }
18659
+ // ==========================================================================
18660
+ // Trace Recording (agent-browser specific)
18661
+ // ==========================================================================
18662
+ /**
18663
+ * Start trace recording
18664
+ *
18665
+ * Records browser activity including network requests, console logs,
18666
+ * and user interactions. Useful for debugging test failures.
18667
+ */
18668
+ async startTrace() {
18669
+ try {
18670
+ const result = this.executor.startTrace();
18671
+ if (!result.success) {
18672
+ return err2(new BrowserError(result.error ?? "Start trace failed", "START_TRACE_FAILED", "agent-browser"));
18673
+ }
18674
+ return ok2(void 0);
18675
+ } catch (error) {
18676
+ return err2(
18677
+ new BrowserError(
18678
+ error instanceof Error ? error.message : String(error),
18679
+ "START_TRACE_FAILED",
18680
+ "agent-browser",
18681
+ error instanceof Error ? error : void 0
18682
+ )
18683
+ );
18684
+ }
18685
+ }
18686
+ /**
18687
+ * Stop trace recording and save to file
18688
+ *
18689
+ * @param outputPath - Path to save the trace file (.zip recommended)
18690
+ * @returns Path where trace was saved
18691
+ */
18692
+ async stopTrace(outputPath) {
18693
+ try {
18694
+ const result = this.executor.stopTrace(outputPath);
18695
+ if (!result.success) {
18696
+ return err2(new BrowserError(result.error ?? "Stop trace failed", "STOP_TRACE_FAILED", "agent-browser"));
18697
+ }
18698
+ return ok2(result.data ?? outputPath);
18699
+ } catch (error) {
18700
+ return err2(
18701
+ new BrowserError(
18702
+ error instanceof Error ? error.message : String(error),
18703
+ "STOP_TRACE_FAILED",
18704
+ "agent-browser",
18705
+ error instanceof Error ? error : void 0
18706
+ )
18707
+ );
18708
+ }
18709
+ }
18710
+ };
18711
+
18712
+ // src/integrations/browser/client-factory.ts
18713
+ async function isVibiumAvailable() {
18714
+ return false;
18715
+ }
18716
+ async function isAgentBrowserAvailable2() {
18717
+ try {
18718
+ const client = new AgentBrowserClient();
18719
+ return await client.isAvailable();
18720
+ } catch {
18721
+ return false;
18722
+ }
18723
+ }
18724
+ var AGENT_BROWSER_REQUIRED_USE_CASES = [
18725
+ "e2e-testing",
18726
+ // Requires refs and sessions
18727
+ "api-mocking",
18728
+ // Only agent-browser supports network interception
18729
+ "responsive-testing",
18730
+ // Requires device emulation
18731
+ "auth-testing"
18732
+ // Requires state persistence
18733
+ ];
18734
+ function requiresAgentBrowser(useCase) {
18735
+ return AGENT_BROWSER_REQUIRED_USE_CASES.includes(useCase);
18736
+ }
18737
+ var VibiumClientStub = class {
18738
+ tool = "vibium";
18739
+ async isAvailable() {
18740
+ return false;
18741
+ }
18742
+ async launch() {
18743
+ return {
18744
+ success: false,
18745
+ error: new BrowserUnavailableError("vibium", "Vibium client not yet implemented")
18746
+ };
18747
+ }
18748
+ async quit() {
18749
+ return {
18750
+ success: false,
18751
+ error: new BrowserUnavailableError("vibium", "Vibium client not yet implemented")
18752
+ };
18753
+ }
18754
+ async navigate() {
18755
+ return {
18756
+ success: false,
18757
+ error: new BrowserUnavailableError("vibium", "Vibium client not yet implemented")
18758
+ };
18759
+ }
18760
+ async reload() {
18761
+ return {
18762
+ success: false,
18763
+ error: new BrowserUnavailableError("vibium", "Vibium client not yet implemented")
18764
+ };
18765
+ }
18766
+ async goBack() {
18767
+ return {
18768
+ success: false,
18769
+ error: new BrowserUnavailableError("vibium", "Vibium client not yet implemented")
18770
+ };
18771
+ }
18772
+ async goForward() {
18773
+ return {
18774
+ success: false,
18775
+ error: new BrowserUnavailableError("vibium", "Vibium client not yet implemented")
18776
+ };
18777
+ }
18778
+ async click() {
18779
+ return {
18780
+ success: false,
18781
+ error: new BrowserUnavailableError("vibium", "Vibium client not yet implemented")
18782
+ };
18783
+ }
18784
+ async fill() {
18785
+ return {
18786
+ success: false,
18787
+ error: new BrowserUnavailableError("vibium", "Vibium client not yet implemented")
18788
+ };
18789
+ }
18790
+ async getText() {
18791
+ return {
18792
+ success: false,
18793
+ error: new BrowserUnavailableError("vibium", "Vibium client not yet implemented")
18794
+ };
18795
+ }
18796
+ async isVisible() {
18797
+ return {
18798
+ success: false,
18799
+ error: new BrowserUnavailableError("vibium", "Vibium client not yet implemented")
18800
+ };
18801
+ }
18802
+ async screenshot() {
18803
+ return {
18804
+ success: false,
18805
+ error: new BrowserUnavailableError("vibium", "Vibium client not yet implemented")
18806
+ };
18807
+ }
18808
+ async evaluate() {
18809
+ return {
18810
+ success: false,
18811
+ error: new BrowserUnavailableError("vibium", "Vibium client not yet implemented")
18812
+ };
18813
+ }
18814
+ async dispose() {
18815
+ }
18816
+ };
18817
+ async function createBrowserClient(options = {}) {
18818
+ const { preference = "auto", useCase } = options;
18819
+ if (useCase && requiresAgentBrowser(useCase)) {
18820
+ return createAgentBrowserClient();
18821
+ }
18822
+ if (preference === "agent-browser") {
18823
+ return createAgentBrowserClient();
18824
+ }
18825
+ if (preference === "vibium") {
18826
+ const available = await isVibiumAvailable();
18827
+ if (available) {
18828
+ return new VibiumClientStub();
18829
+ }
18830
+ throw new BrowserUnavailableError("vibium", "Vibium is not available");
18831
+ }
18832
+ const vibiumAvailable = await isVibiumAvailable();
18833
+ if (vibiumAvailable) {
18834
+ return new VibiumClientStub();
18835
+ }
18836
+ const agentBrowserAvailable = await isAgentBrowserAvailable2();
18837
+ if (agentBrowserAvailable) {
18838
+ return createAgentBrowserClient();
18839
+ }
18840
+ return createAgentBrowserClient();
18841
+ }
18842
+ async function createAgentBrowserClient() {
18843
+ return new AgentBrowserClient();
18844
+ }
18845
+ async function getBrowserClientForUseCase(useCase) {
18846
+ return createBrowserClient({ useCase });
18847
+ }
18848
+
16949
18849
  // src/domains/test-execution/types/e2e-step.types.ts
16950
18850
  var E2EStepType = {
16951
18851
  /** Navigate to a URL */
@@ -16994,7 +18894,9 @@ var DEFAULT_E2E_RUNNER_CONFIG = {
16994
18894
  stopOnFirstFailure: false,
16995
18895
  pollingInterval: 100,
16996
18896
  maxParallelWorkers: 4,
16997
- verbose: false
18897
+ verbose: false,
18898
+ preferAgentBrowser: true,
18899
+ browserClientType: "auto"
16998
18900
  };
16999
18901
  var E2ERunnerError = class extends Error {
17000
18902
  constructor(message, code, stepId, cause) {
@@ -17019,17 +18921,102 @@ var AssertionError = class extends E2ERunnerError {
17019
18921
  this.name = "AssertionError";
17020
18922
  }
17021
18923
  };
18924
+ function isAgentBrowserClient(client) {
18925
+ return "tool" in client && client.tool === "agent-browser";
18926
+ }
18927
+ function isVibiumClient(client) {
18928
+ return !("tool" in client) || !client.tool;
18929
+ }
18930
+ function toElementTarget(selector) {
18931
+ if (/^@?e\d+$/.test(selector)) {
18932
+ const value = selector.startsWith("@") ? selector : `@${selector}`;
18933
+ return { type: "ref", value };
18934
+ }
18935
+ if (selector.startsWith("//") || selector.startsWith("xpath=")) {
18936
+ const value = selector.replace(/^xpath=/, "");
18937
+ return { type: "xpath", value };
18938
+ }
18939
+ if (selector.startsWith("text=")) {
18940
+ const value = selector.replace(/^text=/, "");
18941
+ return { type: "text", value };
18942
+ }
18943
+ return { type: "css", value: selector };
18944
+ }
18945
+ function toVibiumScreenshotResult(result) {
18946
+ return {
18947
+ base64: result.base64,
18948
+ path: result.path,
18949
+ format: result.format,
18950
+ dimensions: result.dimensions,
18951
+ sizeBytes: result.base64 ? Math.ceil(result.base64.length * 0.75) : 0,
18952
+ // Estimate size from base64
18953
+ capturedAt: /* @__PURE__ */ new Date()
18954
+ };
18955
+ }
18956
+ function toVibiumAccessibilityResult(axeResults) {
18957
+ const violationsBySeverity = {
18958
+ critical: 0,
18959
+ high: 0,
18960
+ medium: 0,
18961
+ low: 0,
18962
+ info: 0
18963
+ };
18964
+ const violations = axeResults.violations.map((v) => {
18965
+ const impact = v.impact;
18966
+ if (impact in violationsBySeverity) {
18967
+ violationsBySeverity[impact]++;
18968
+ }
18969
+ return {
18970
+ id: v.id,
18971
+ impact: v.impact,
18972
+ description: v.description,
18973
+ nodes: v.nodes.length
18974
+ };
18975
+ });
18976
+ return {
18977
+ passes: violations.length === 0,
18978
+ violations,
18979
+ violationsBySeverity,
18980
+ passedRules: axeResults.passes.map((p) => p.id),
18981
+ incompleteRules: axeResults.incomplete.map((i) => i.id),
18982
+ checkedAt: /* @__PURE__ */ new Date()
18983
+ };
18984
+ }
17022
18985
  var E2ETestRunnerService = class {
17023
18986
  /**
17024
18987
  * Create E2E Test Runner Service
17025
- * @param client - Vibium browser automation client (dependency injection)
18988
+ *
18989
+ * @param client - Browser automation client (VibiumClient or IBrowserClient)
17026
18990
  * @param config - Runner configuration
18991
+ *
18992
+ * @example
18993
+ * ```typescript
18994
+ * // Using VibiumClient (legacy)
18995
+ * const vibiumClient = await createVibiumClient({ enabled: true });
18996
+ * const runner = new E2ETestRunnerService(vibiumClient);
18997
+ *
18998
+ * // Using agent-browser (recommended for E2E)
18999
+ * const agentClient = await createAgentBrowserClient();
19000
+ * const runner = new E2ETestRunnerService(agentClient, {
19001
+ * preferAgentBrowser: true
19002
+ * });
19003
+ *
19004
+ * // Using auto-selection
19005
+ * const runner = createE2ETestRunnerServiceWithBrowserClient(undefined, {
19006
+ * browserClientType: 'auto'
19007
+ * });
19008
+ * ```
17027
19009
  */
17028
19010
  constructor(client, config = {}) {
17029
19011
  this.client = client;
17030
19012
  this.config = { ...DEFAULT_E2E_RUNNER_CONFIG, ...config };
19013
+ this.unifiedClient = config.browserClient ?? client;
19014
+ this.useAgentBrowser = isAgentBrowserClient(this.unifiedClient);
19015
+ this.log(`E2E Runner initialized with ${this.useAgentBrowser ? "agent-browser" : "vibium"} client`);
17031
19016
  }
17032
19017
  config;
19018
+ unifiedClient;
19019
+ useAgentBrowser;
17033
19020
  // ==========================================================================
17034
19021
  // Public Methods
17035
19022
  // ==========================================================================
@@ -17055,27 +19042,20 @@ var E2ETestRunnerService = class {
17055
19042
  }
17056
19043
  }
17057
19044
  try {
17058
- const session = await this.client.getSession();
17059
- if (!session) {
17060
- const launchResult = await this.client.launch({
17061
- headless: true,
17062
- viewport: testCase.viewport,
17063
- ...this.getBrowserContextOptions(testCase)
17064
- });
17065
- if (!launchResult.success) {
17066
- return this.createErrorResult(
17067
- testCase,
17068
- startedAt,
17069
- `Failed to launch browser: ${launchResult.error.message}`
17070
- );
17071
- }
19045
+ const launchError = await this.ensureBrowserLaunched(testCase);
19046
+ if (launchError) {
19047
+ return this.createErrorResult(testCase, startedAt, launchError);
17072
19048
  }
17073
19049
  const context2 = {
17074
19050
  testCase,
17075
19051
  baseUrl: testCase.baseUrl,
17076
19052
  variables: testCase.testData ?? {},
17077
- previousResults: stepResults
19053
+ previousResults: stepResults,
19054
+ useAgentBrowser: this.useAgentBrowser
17078
19055
  };
19056
+ if (this.useAgentBrowser) {
19057
+ context2.currentSnapshot = await this.refreshSnapshot();
19058
+ }
17079
19059
  if (testCase.hooks?.beforeAll) {
17080
19060
  const hookResults = await this.executeHooks(
17081
19061
  testCase.hooks.beforeAll,
@@ -17189,14 +19169,95 @@ var E2ETestRunnerService = class {
17189
19169
  };
17190
19170
  }
17191
19171
  // ==========================================================================
19172
+ // Browser Launch Helper
19173
+ // ==========================================================================
19174
+ /**
19175
+ * Ensure browser is launched for the test case
19176
+ * Handles both agent-browser and Vibium clients
19177
+ */
19178
+ async ensureBrowserLaunched(testCase) {
19179
+ try {
19180
+ if (this.useAgentBrowser && isAgentBrowserClient(this.unifiedClient)) {
19181
+ const launchResult = await this.unifiedClient.launch({
19182
+ headless: true,
19183
+ viewport: testCase.viewport
19184
+ // Use client's default session name, not test-specific
19185
+ });
19186
+ if (!launchResult.success) {
19187
+ return `Failed to launch browser: ${launchResult.error.message}`;
19188
+ }
19189
+ return null;
19190
+ } else if (isVibiumClient(this.client)) {
19191
+ const session = await this.client.getSession();
19192
+ if (!session) {
19193
+ const launchResult = await this.client.launch({
19194
+ headless: true,
19195
+ viewport: testCase.viewport,
19196
+ ...this.getBrowserContextOptions(testCase)
19197
+ });
19198
+ if (!launchResult.success) {
19199
+ return `Failed to launch browser: ${launchResult.error.message}`;
19200
+ }
19201
+ }
19202
+ return null;
19203
+ } else {
19204
+ const launchResult = await this.unifiedClient.launch({
19205
+ headless: true,
19206
+ viewport: testCase.viewport
19207
+ });
19208
+ if (!launchResult.success) {
19209
+ return `Failed to launch browser: ${launchResult.error.message}`;
19210
+ }
19211
+ return null;
19212
+ }
19213
+ } catch (error) {
19214
+ return error instanceof Error ? error.message : String(error);
19215
+ }
19216
+ }
19217
+ /**
19218
+ * Refresh the page snapshot (agent-browser only)
19219
+ */
19220
+ async refreshSnapshot() {
19221
+ if (!this.useAgentBrowser || !isAgentBrowserClient(this.unifiedClient)) {
19222
+ return void 0;
19223
+ }
19224
+ try {
19225
+ const snapshotResult = await this.unifiedClient.getSnapshot({ interactive: true });
19226
+ if (snapshotResult.success) {
19227
+ return snapshotResult.value;
19228
+ }
19229
+ } catch {
19230
+ this.log("Failed to refresh snapshot");
19231
+ }
19232
+ return void 0;
19233
+ }
19234
+ // ==========================================================================
17192
19235
  // Step Executors
17193
19236
  // ==========================================================================
17194
19237
  /**
17195
19238
  * Execute a navigate step
19239
+ * Supports both agent-browser and Vibium clients
17196
19240
  */
17197
19241
  async executeNavigateStep(step, client, context2) {
17198
19242
  const url = this.resolveUrl(step.target, context2.baseUrl);
17199
- const result = await client.navigate({
19243
+ if (!isVibiumClient(client)) {
19244
+ const browserClient = client;
19245
+ const result2 = await browserClient.navigate(url);
19246
+ if (!result2.success) {
19247
+ throw result2.error;
19248
+ }
19249
+ if (context2.useAgentBrowser) {
19250
+ context2.currentSnapshot = await this.refreshSnapshot();
19251
+ }
19252
+ return {
19253
+ data: {
19254
+ url: result2.value.url,
19255
+ title: result2.value.title
19256
+ }
19257
+ };
19258
+ }
19259
+ const vibiumClient = client;
19260
+ const result = await vibiumClient.navigate({
17200
19261
  url,
17201
19262
  waitUntil: step.options?.waitUntil ?? "load",
17202
19263
  timeout: step.timeout ?? this.config.defaultStepTimeout
@@ -17213,18 +19274,43 @@ var E2ETestRunnerService = class {
17213
19274
  }
17214
19275
  /**
17215
19276
  * Execute a click step
19277
+ * Supports both agent-browser and Vibium clients
17216
19278
  */
17217
- async executeClickStep(step, client, _context) {
19279
+ async executeClickStep(step, client, context2) {
19280
+ if (!isVibiumClient(client)) {
19281
+ const browserClient = client;
19282
+ const target = toElementTarget(step.target);
19283
+ if (context2.useAgentBrowser && isAgentBrowserClient(browserClient)) {
19284
+ const waitResult = await browserClient.waitForElement(target, step.timeout);
19285
+ if (!waitResult.success) {
19286
+ throw waitResult.error;
19287
+ }
19288
+ }
19289
+ const result2 = await browserClient.click(target);
19290
+ if (!result2.success) {
19291
+ throw result2.error;
19292
+ }
19293
+ if (context2.useAgentBrowser) {
19294
+ context2.currentSnapshot = await this.refreshSnapshot();
19295
+ }
19296
+ if (step.options?.waitForNavigation && isAgentBrowserClient(browserClient)) {
19297
+ await browserClient.waitForNetworkIdle(step.timeout);
19298
+ }
19299
+ return {
19300
+ data: {}
19301
+ };
19302
+ }
19303
+ const vibiumClient = client;
17218
19304
  if (step.options?.scrollIntoView) {
17219
- await this.scrollIntoView(client, step.target);
19305
+ await this.scrollIntoView(vibiumClient, step.target);
17220
19306
  }
17221
19307
  if (step.options?.hoverFirst) {
17222
- const findResult = await client.findElement({ selector: step.target });
19308
+ const findResult = await vibiumClient.findElement({ selector: step.target });
17223
19309
  if (!findResult.success) {
17224
19310
  throw findResult.error;
17225
19311
  }
17226
19312
  }
17227
- const result = await client.click({
19313
+ const result = await vibiumClient.click({
17228
19314
  selector: step.target,
17229
19315
  button: step.options?.button,
17230
19316
  clickCount: step.options?.clickCount,
@@ -17239,7 +19325,7 @@ var E2ETestRunnerService = class {
17239
19325
  }
17240
19326
  if (step.options?.waitForNavigation) {
17241
19327
  await this.delay(500);
17242
- const pageInfo = await client.getPageInfo();
19328
+ const pageInfo = await vibiumClient.getPageInfo();
17243
19329
  if (pageInfo.success) {
17244
19330
  return {
17245
19331
  data: {
@@ -17256,9 +19342,33 @@ var E2ETestRunnerService = class {
17256
19342
  }
17257
19343
  /**
17258
19344
  * Execute a type step
19345
+ * Supports both agent-browser and Vibium clients
17259
19346
  */
17260
- async executeTypeStep(step, client, _context) {
17261
- const result = await client.type({
19347
+ async executeTypeStep(step, client, context2) {
19348
+ if (!isVibiumClient(client)) {
19349
+ const browserClient = client;
19350
+ const target = toElementTarget(step.target);
19351
+ if (context2.useAgentBrowser && isAgentBrowserClient(browserClient)) {
19352
+ const waitResult = await browserClient.waitForElement(target, step.timeout);
19353
+ if (!waitResult.success) {
19354
+ throw waitResult.error;
19355
+ }
19356
+ }
19357
+ const result2 = await browserClient.fill(target, step.value);
19358
+ if (!result2.success) {
19359
+ throw result2.error;
19360
+ }
19361
+ if (context2.useAgentBrowser) {
19362
+ context2.currentSnapshot = await this.refreshSnapshot();
19363
+ }
19364
+ return {
19365
+ data: {
19366
+ elementText: step.options?.sensitive ? "[MASKED]" : step.value
19367
+ }
19368
+ };
19369
+ }
19370
+ const vibiumClient = client;
19371
+ const result = await vibiumClient.type({
17262
19372
  selector: step.target,
17263
19373
  text: step.value,
17264
19374
  delay: step.options?.delay,
@@ -17277,11 +19387,51 @@ var E2ETestRunnerService = class {
17277
19387
  }
17278
19388
  /**
17279
19389
  * Execute a wait step
19390
+ * Supports both agent-browser and Vibium clients
17280
19391
  */
17281
- async executeWaitStep(step, client, _context) {
19392
+ async executeWaitStep(step, client, context2) {
17282
19393
  const timeout = step.timeout ?? this.config.defaultStepTimeout;
17283
19394
  const pollingInterval = step.options.pollingInterval ?? this.config.pollingInterval;
17284
- const waitResult = await this.waitForCondition(
19395
+ if (!isVibiumClient(client) && isAgentBrowserClient(client)) {
19396
+ const browserClient = client;
19397
+ let waitResult;
19398
+ switch (step.options.condition) {
19399
+ case "element-visible":
19400
+ case "element-hidden":
19401
+ if (step.target) {
19402
+ waitResult = await browserClient.waitForElement(toElementTarget(step.target), timeout);
19403
+ }
19404
+ break;
19405
+ case "element-text":
19406
+ if (step.options.expectedText) {
19407
+ waitResult = await browserClient.waitForText(step.options.expectedText, timeout);
19408
+ }
19409
+ break;
19410
+ case "url-match":
19411
+ if (step.options.urlPattern) {
19412
+ const pattern = typeof step.options.urlPattern === "string" ? step.options.urlPattern : step.options.urlPattern.source;
19413
+ waitResult = await browserClient.waitForUrl(pattern, timeout);
19414
+ }
19415
+ break;
19416
+ case "network-idle":
19417
+ case "page-loaded":
19418
+ case "dom-loaded":
19419
+ waitResult = await browserClient.waitForNetworkIdle(timeout);
19420
+ break;
19421
+ default:
19422
+ break;
19423
+ }
19424
+ if (waitResult && !waitResult.success) {
19425
+ throw waitResult.error;
19426
+ }
19427
+ context2.currentSnapshot = await this.refreshSnapshot();
19428
+ return { data: {} };
19429
+ }
19430
+ if (!isVibiumClient(client)) {
19431
+ await this.delay(pollingInterval);
19432
+ return { data: {} };
19433
+ }
19434
+ const waitData = await this.waitForCondition(
17285
19435
  step.options.condition,
17286
19436
  client,
17287
19437
  step,
@@ -17289,16 +19439,33 @@ var E2ETestRunnerService = class {
17289
19439
  pollingInterval
17290
19440
  );
17291
19441
  return {
17292
- data: waitResult
19442
+ data: waitData
17293
19443
  };
17294
19444
  }
17295
19445
  /**
17296
19446
  * Execute an assert step
17297
- */
17298
- async executeAssertStep(step, client, _context) {
19447
+ * Supports both agent-browser and Vibium clients
19448
+ */
19449
+ async executeAssertStep(step, client, context2) {
19450
+ if (!isVibiumClient(client)) {
19451
+ const browserClient = client;
19452
+ const assertResult2 = await this.performUnifiedAssertion(
19453
+ step.options.assertion,
19454
+ browserClient,
19455
+ step,
19456
+ context2
19457
+ );
19458
+ return {
19459
+ data: {
19460
+ actualValue: assertResult2.actual,
19461
+ expectedValue: assertResult2.expected
19462
+ }
19463
+ };
19464
+ }
19465
+ const vibiumClient = client;
17299
19466
  const assertResult = await this.performAssertion(
17300
19467
  step.options.assertion,
17301
- client,
19468
+ vibiumClient,
17302
19469
  step
17303
19470
  );
17304
19471
  return {
@@ -17310,9 +19477,28 @@ var E2ETestRunnerService = class {
17310
19477
  }
17311
19478
  /**
17312
19479
  * Execute a screenshot step
19480
+ * Supports both agent-browser and Vibium clients
17313
19481
  */
17314
19482
  async executeScreenshotStep(step, client, _context) {
17315
- const result = await client.screenshot({
19483
+ if (!isVibiumClient(client)) {
19484
+ const browserClient = client;
19485
+ const result2 = await browserClient.screenshot({
19486
+ path: step.target,
19487
+ fullPage: step.options?.fullPage
19488
+ });
19489
+ if (!result2.success) {
19490
+ throw result2.error;
19491
+ }
19492
+ const screenshotResult = toVibiumScreenshotResult(result2.value);
19493
+ return {
19494
+ screenshot: screenshotResult,
19495
+ data: {
19496
+ url: result2.value.path
19497
+ }
19498
+ };
19499
+ }
19500
+ const vibiumClient = client;
19501
+ const result = await vibiumClient.screenshot({
17316
19502
  selector: step.target,
17317
19503
  fullPage: step.options?.fullPage,
17318
19504
  format: step.options?.format,
@@ -17331,9 +19517,56 @@ var E2ETestRunnerService = class {
17331
19517
  }
17332
19518
  /**
17333
19519
  * Execute an accessibility check step
19520
+ * Supports both agent-browser and Vibium clients
17334
19521
  */
17335
19522
  async executeA11yCheckStep(step, client, _context) {
17336
- const result = await client.checkAccessibility({
19523
+ if (!isVibiumClient(client)) {
19524
+ const browserClient = client;
19525
+ const axeScript = `
19526
+ (async () => {
19527
+ if (!window.axe) {
19528
+ const script = document.createElement('script');
19529
+ script.src = 'https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.7.2/axe.min.js';
19530
+ document.head.appendChild(script);
19531
+ await new Promise(resolve => script.onload = resolve);
19532
+ }
19533
+ const results = await axe.run(${step.target ? `'${step.target}'` : "document"}, {
19534
+ runOnly: ${JSON.stringify(step.options?.tags ?? ["wcag2a", "wcag2aa"])},
19535
+ });
19536
+ return JSON.stringify(results);
19537
+ })()
19538
+ `;
19539
+ const evalResult = await browserClient.evaluate(axeScript);
19540
+ if (!evalResult.success) {
19541
+ throw evalResult.error;
19542
+ }
19543
+ const axeResults = JSON.parse(evalResult.value);
19544
+ const a11yResult2 = toVibiumAccessibilityResult(axeResults);
19545
+ if (step.options?.failOnSeverity) {
19546
+ const severityOrder = {
19547
+ critical: 0,
19548
+ high: 1,
19549
+ medium: 2,
19550
+ low: 3,
19551
+ info: 4
19552
+ };
19553
+ const threshold = severityOrder[step.options.failOnSeverity];
19554
+ const violationsOverThreshold = axeResults.violations.filter(
19555
+ (v) => severityOrder[v.impact] <= threshold
19556
+ );
19557
+ if (violationsOverThreshold.length > 0) {
19558
+ throw new AssertionError(
19559
+ `Accessibility violations found: ${violationsOverThreshold.length} at or above ${step.options.failOnSeverity}`,
19560
+ step.id,
19561
+ 0,
19562
+ violationsOverThreshold.length
19563
+ );
19564
+ }
19565
+ }
19566
+ return { accessibilityResult: a11yResult2 };
19567
+ }
19568
+ const vibiumClient = client;
19569
+ const result = await vibiumClient.checkAccessibility({
17337
19570
  selector: step.target,
17338
19571
  wcagLevel: step.options?.wcagLevel ?? "AA",
17339
19572
  rules: step.options?.rules ? {
@@ -17472,7 +19705,188 @@ var E2ETestRunnerService = class {
17472
19705
  // Assertion Handlers
17473
19706
  // ==========================================================================
17474
19707
  /**
17475
- * Perform an assertion
19708
+ * Perform an assertion using the unified browser client (IBrowserClient)
19709
+ * Supports agent-browser and generic browser clients
19710
+ */
19711
+ async performUnifiedAssertion(assertion, client, step, _context) {
19712
+ let actual;
19713
+ const expected = step.options.expected ?? step.value;
19714
+ switch (assertion) {
19715
+ case "element-exists":
19716
+ case "element-visible":
19717
+ case "visible": {
19718
+ if (step.target) {
19719
+ const result = await client.isVisible(toElementTarget(step.target));
19720
+ actual = result.success ? result.value : false;
19721
+ } else {
19722
+ actual = false;
19723
+ }
19724
+ this.assertCondition(actual === true, step, true, actual);
19725
+ break;
19726
+ }
19727
+ case "element-not-exists":
19728
+ case "element-hidden":
19729
+ case "hidden": {
19730
+ if (step.target) {
19731
+ const result = await client.isVisible(toElementTarget(step.target));
19732
+ actual = result.success ? !result.value : true;
19733
+ } else {
19734
+ actual = true;
19735
+ }
19736
+ this.assertCondition(actual === true, step, true, actual);
19737
+ break;
19738
+ }
19739
+ case "element-text":
19740
+ case "text": {
19741
+ if (step.target) {
19742
+ const result = await client.getText(toElementTarget(step.target));
19743
+ if (!result.success) {
19744
+ throw result.error;
19745
+ }
19746
+ actual = result.value;
19747
+ this.assertTextMatch(actual, expected, step.options.operator, step);
19748
+ }
19749
+ break;
19750
+ }
19751
+ case "url-equals":
19752
+ case "url-contains":
19753
+ case "url-matches": {
19754
+ const urlResult = await client.evaluate("window.location.href");
19755
+ if (!urlResult.success) {
19756
+ throw urlResult.error;
19757
+ }
19758
+ actual = urlResult.value;
19759
+ if (assertion === "url-equals") {
19760
+ this.assertCondition(actual === expected, step, expected, actual);
19761
+ } else if (assertion === "url-contains") {
19762
+ this.assertCondition(
19763
+ actual.includes(expected),
19764
+ step,
19765
+ expected,
19766
+ actual
19767
+ );
19768
+ } else {
19769
+ const regex = new RegExp(expected);
19770
+ this.assertCondition(regex.test(actual), step, expected, actual);
19771
+ }
19772
+ break;
19773
+ }
19774
+ case "title-equals":
19775
+ case "title-contains": {
19776
+ const titleResult = await client.evaluate("document.title");
19777
+ if (!titleResult.success) {
19778
+ throw titleResult.error;
19779
+ }
19780
+ actual = titleResult.value;
19781
+ if (assertion === "title-equals") {
19782
+ this.assertCondition(actual === expected, step, expected, actual);
19783
+ } else {
19784
+ this.assertCondition(
19785
+ actual.includes(expected),
19786
+ step,
19787
+ expected,
19788
+ actual
19789
+ );
19790
+ }
19791
+ break;
19792
+ }
19793
+ case "page-has-text": {
19794
+ const textResult = await client.evaluate(
19795
+ `document.body.innerText.includes('${expected}')`
19796
+ );
19797
+ actual = textResult.success ? textResult.value : false;
19798
+ this.assertCondition(actual === true, step, true, actual);
19799
+ break;
19800
+ }
19801
+ case "element-attribute": {
19802
+ if (step.target && step.options.attributeName) {
19803
+ const attrResult = await client.evaluate(
19804
+ `document.querySelector('${step.target}')?.getAttribute('${step.options.attributeName}')`
19805
+ );
19806
+ if (attrResult.success) {
19807
+ actual = attrResult.value;
19808
+ this.assertCondition(actual === expected, step, expected, actual);
19809
+ } else {
19810
+ throw attrResult.error;
19811
+ }
19812
+ }
19813
+ break;
19814
+ }
19815
+ case "element-value": {
19816
+ if (step.target) {
19817
+ const valueResult = await client.evaluate(
19818
+ `document.querySelector('${step.target}')?.value`
19819
+ );
19820
+ if (valueResult.success) {
19821
+ actual = valueResult.value;
19822
+ this.assertCondition(actual === expected, step, expected, actual);
19823
+ } else {
19824
+ throw valueResult.error;
19825
+ }
19826
+ }
19827
+ break;
19828
+ }
19829
+ case "element-count": {
19830
+ if (step.target) {
19831
+ const countResult = await client.evaluate(
19832
+ `document.querySelectorAll('${step.target}').length`
19833
+ );
19834
+ if (countResult.success) {
19835
+ actual = countResult.value;
19836
+ const expectedCount = step.options.count ?? expected;
19837
+ this.assertNumericCondition(
19838
+ actual,
19839
+ expectedCount,
19840
+ step.options.operator ?? "eq",
19841
+ step
19842
+ );
19843
+ } else {
19844
+ throw countResult.error;
19845
+ }
19846
+ }
19847
+ break;
19848
+ }
19849
+ case "element-class": {
19850
+ if (step.target && step.options.className) {
19851
+ const classResult = await client.evaluate(
19852
+ `document.querySelector('${step.target}')?.classList.contains('${step.options.className}')`
19853
+ );
19854
+ actual = classResult.success ? classResult.value : false;
19855
+ this.assertCondition(actual === true, step, true, actual);
19856
+ }
19857
+ break;
19858
+ }
19859
+ case "element-enabled":
19860
+ case "element-disabled": {
19861
+ if (step.target) {
19862
+ const enabledResult = await client.evaluate(
19863
+ `!document.querySelector('${step.target}')?.disabled`
19864
+ );
19865
+ actual = enabledResult.success ? enabledResult.value : false;
19866
+ if (assertion === "element-disabled") {
19867
+ actual = !actual;
19868
+ }
19869
+ this.assertCondition(actual === true, step, true, actual);
19870
+ }
19871
+ break;
19872
+ }
19873
+ case "console-no-errors":
19874
+ actual = true;
19875
+ break;
19876
+ case "custom":
19877
+ actual = true;
19878
+ break;
19879
+ default:
19880
+ throw new E2ERunnerError(
19881
+ `Unsupported assertion type: ${assertion}`,
19882
+ "UNSUPPORTED_ASSERTION",
19883
+ step.id
19884
+ );
19885
+ }
19886
+ return { actual, expected };
19887
+ }
19888
+ /**
19889
+ * Perform an assertion (Legacy Vibium path)
17476
19890
  */
17477
19891
  async performAssertion(assertion, client, step) {
17478
19892
  let actual;
@@ -17701,20 +20115,21 @@ var E2ETestRunnerService = class {
17701
20115
  return { data: {} };
17702
20116
  }
17703
20117
  }
20118
+ const client = this.unifiedClient;
17704
20119
  if (isNavigateStep(step)) {
17705
- return this.executeNavigateStep(step, this.client, context2);
20120
+ return this.executeNavigateStep(step, client, context2);
17706
20121
  } else if (isClickStep(step)) {
17707
- return this.executeClickStep(step, this.client, context2);
20122
+ return this.executeClickStep(step, client, context2);
17708
20123
  } else if (isTypeStep(step)) {
17709
- return this.executeTypeStep(step, this.client, context2);
20124
+ return this.executeTypeStep(step, client, context2);
17710
20125
  } else if (isWaitStep(step)) {
17711
- return this.executeWaitStep(step, this.client, context2);
20126
+ return this.executeWaitStep(step, client, context2);
17712
20127
  } else if (isAssertStep(step)) {
17713
- return this.executeAssertStep(step, this.client, context2);
20128
+ return this.executeAssertStep(step, client, context2);
17714
20129
  } else if (isScreenshotStep(step)) {
17715
- return this.executeScreenshotStep(step, this.client, context2);
20130
+ return this.executeScreenshotStep(step, client, context2);
17716
20131
  } else if (isA11yCheckStep(step)) {
17717
- return this.executeA11yCheckStep(step, this.client, context2);
20132
+ return this.executeA11yCheckStep(step, client, context2);
17718
20133
  }
17719
20134
  const unknownStep = step;
17720
20135
  throw new E2ERunnerError(
@@ -17930,9 +20345,18 @@ var E2ETestRunnerService = class {
17930
20345
  }
17931
20346
  /**
17932
20347
  * Capture screenshot on failure
20348
+ * Supports both agent-browser and Vibium clients
17933
20349
  */
17934
20350
  async captureFailureScreenshot(stepId) {
17935
20351
  try {
20352
+ if (!isVibiumClient(this.unifiedClient)) {
20353
+ const browserClient = this.unifiedClient;
20354
+ const result2 = await browserClient.screenshot({ fullPage: true });
20355
+ if (result2.success) {
20356
+ return toVibiumScreenshotResult(result2.value);
20357
+ }
20358
+ return null;
20359
+ }
17936
20360
  const result = await this.client.screenshot({
17937
20361
  fullPage: true,
17938
20362
  format: "png"
@@ -25737,13 +28161,13 @@ var QualityAssessmentPlugin = class extends BaseDomainPlugin {
25737
28161
  }
25738
28162
  }
25739
28163
  handleError(error) {
25740
- const err2 = error instanceof Error ? error : new Error(String(error));
28164
+ const err3 = error instanceof Error ? error : new Error(String(error));
25741
28165
  const currentHealth = this.getHealth();
25742
28166
  this.updateHealth({
25743
- errors: [...currentHealth.errors.slice(-9), err2.message],
28167
+ errors: [...currentHealth.errors.slice(-9), err3.message],
25744
28168
  status: currentHealth.errors.length >= 5 ? "degraded" : currentHealth.status
25745
28169
  });
25746
- return { success: false, error: err2 };
28170
+ return { success: false, error: err3 };
25747
28171
  }
25748
28172
  trackSuccessfulOperation(type) {
25749
28173
  const health = this.getHealth();
@@ -28053,9 +30477,9 @@ var DefectIntelligenceCoordinator = class {
28053
30477
  await this.agentCoordinator.stop(agentResult.value);
28054
30478
  return result;
28055
30479
  } catch (error) {
28056
- const err2 = error instanceof Error ? error : new Error(String(error));
28057
- this.failWorkflow(workflowId, err2.message);
28058
- return { success: false, error: err2 };
30480
+ const err3 = error instanceof Error ? error : new Error(String(error));
30481
+ this.failWorkflow(workflowId, err3.message);
30482
+ return { success: false, error: err3 };
28059
30483
  }
28060
30484
  }
28061
30485
  /**
@@ -28635,13 +31059,13 @@ var DefectIntelligencePlugin = class extends BaseDomainPlugin {
28635
31059
  }
28636
31060
  }
28637
31061
  handleError(error) {
28638
- const err2 = error instanceof Error ? error : new Error(String(error));
31062
+ const err3 = error instanceof Error ? error : new Error(String(error));
28639
31063
  const currentHealth = this.getHealth();
28640
31064
  this.updateHealth({
28641
- errors: [...currentHealth.errors.slice(-9), err2.message],
31065
+ errors: [...currentHealth.errors.slice(-9), err3.message],
28642
31066
  status: currentHealth.errors.length >= 5 ? "degraded" : currentHealth.status
28643
31067
  });
28644
- return { success: false, error: err2 };
31068
+ return { success: false, error: err3 };
28645
31069
  }
28646
31070
  trackSuccessfulOperation(_type) {
28647
31071
  const health = this.getHealth();
@@ -30451,12 +32875,12 @@ var RequirementsValidationCoordinator = class {
30451
32875
  }
30452
32876
  return ok(analysis);
30453
32877
  } catch (error) {
30454
- const err2 = error instanceof Error ? error : new Error(String(error));
30455
- this.failWorkflow(workflowId, err2.message);
32878
+ const err3 = error instanceof Error ? error : new Error(String(error));
32879
+ this.failWorkflow(workflowId, err3.message);
30456
32880
  if (this.config.publishEvents) {
30457
- await this.publishValidationFailed(err2, "analyzeRequirement");
32881
+ await this.publishValidationFailed(err3, "analyzeRequirement");
30458
32882
  }
30459
- return { success: false, error: err2 };
32883
+ return { success: false, error: err3 };
30460
32884
  }
30461
32885
  }
30462
32886
  /**
@@ -30526,9 +32950,9 @@ var RequirementsValidationCoordinator = class {
30526
32950
  }
30527
32951
  return ok(artifacts);
30528
32952
  } catch (error) {
30529
- const err2 = error instanceof Error ? error : new Error(String(error));
30530
- this.failWorkflow(workflowId, err2.message);
30531
- return { success: false, error: err2 };
32953
+ const err3 = error instanceof Error ? error : new Error(String(error));
32954
+ this.failWorkflow(workflowId, err3.message);
32955
+ return { success: false, error: err3 };
30532
32956
  }
30533
32957
  }
30534
32958
  /**
@@ -30611,9 +33035,9 @@ var RequirementsValidationCoordinator = class {
30611
33035
  }
30612
33036
  return ok(validation);
30613
33037
  } catch (error) {
30614
- const err2 = error instanceof Error ? error : new Error(String(error));
30615
- this.failWorkflow(workflowId, err2.message);
30616
- return { success: false, error: err2 };
33038
+ const err3 = error instanceof Error ? error : new Error(String(error));
33039
+ this.failWorkflow(workflowId, err3.message);
33040
+ return { success: false, error: err3 };
30617
33041
  }
30618
33042
  }
30619
33043
  // ============================================================================
@@ -31371,13 +33795,13 @@ var RequirementsValidationPlugin = class extends BaseDomainPlugin {
31371
33795
  }
31372
33796
  }
31373
33797
  handleError(error) {
31374
- const err2 = error instanceof Error ? error : new Error(String(error));
33798
+ const err3 = error instanceof Error ? error : new Error(String(error));
31375
33799
  const currentHealth = this.getHealth();
31376
33800
  this.updateHealth({
31377
- errors: [...currentHealth.errors.slice(-9), err2.message],
33801
+ errors: [...currentHealth.errors.slice(-9), err3.message],
31378
33802
  status: currentHealth.errors.length >= 5 ? "degraded" : currentHealth.status
31379
33803
  });
31380
- return { success: false, error: err2 };
33804
+ return { success: false, error: err3 };
31381
33805
  }
31382
33806
  trackSuccessfulOperation(_type) {
31383
33807
  const health = this.getHealth();
@@ -33080,7 +35504,7 @@ var DEFAULT_METRIC_CONFIG = {
33080
35504
  };
33081
35505
 
33082
35506
  // src/domains/code-intelligence/services/metric-collector/loc-counter.ts
33083
- import { execSync, spawnSync } from "child_process";
35507
+ import { execSync as execSync3, spawnSync } from "child_process";
33084
35508
  import { existsSync as existsSync5, readdirSync, readFileSync as readFileSync4 } from "fs";
33085
35509
  import { join as join5, extname } from "path";
33086
35510
  async function countLOC(projectPath, config = {}) {
@@ -33125,7 +35549,7 @@ async function tryClocCount(projectPath, config) {
33125
35549
  try {
33126
35550
  const excludeDirs = config.excludeDirs.join(",");
33127
35551
  const command = `cloc --json --exclude-dir=${excludeDirs} "${projectPath}"`;
33128
- const output = execSync(command, {
35552
+ const output = execSync3(command, {
33129
35553
  encoding: "utf-8",
33130
35554
  timeout: config.timeout,
33131
35555
  maxBuffer: 10 * 1024 * 1024
@@ -33159,7 +35583,7 @@ async function tryTokeiCount(projectPath, config) {
33159
35583
  try {
33160
35584
  const excludeArgs = config.excludeDirs.map((dir) => `-e "${dir}"`).join(" ");
33161
35585
  const command = `tokei --output json ${excludeArgs} "${projectPath}"`;
33162
- const output = execSync(command, {
35586
+ const output = execSync3(command, {
33163
35587
  encoding: "utf-8",
33164
35588
  timeout: config.timeout,
33165
35589
  maxBuffer: 10 * 1024 * 1024
@@ -33428,7 +35852,7 @@ function getBlockCommentEnd(ext) {
33428
35852
  }
33429
35853
 
33430
35854
  // src/domains/code-intelligence/services/metric-collector/test-counter.ts
33431
- import { execSync as execSync2, spawnSync as spawnSync2 } from "child_process";
35855
+ import { execSync as execSync4, spawnSync as spawnSync2 } from "child_process";
33432
35856
  import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync as readdirSync2 } from "fs";
33433
35857
  import { join as join6, extname as extname2 } from "path";
33434
35858
  async function countTests(projectPath, config = {}) {
@@ -33541,7 +35965,7 @@ function checkTestRunners(projectPath) {
33541
35965
  }
33542
35966
  function countVitestTests(projectPath, config) {
33543
35967
  try {
33544
- const output = execSync2(
35968
+ const output = execSync4(
33545
35969
  "npx vitest list --reporter=json 2>/dev/null",
33546
35970
  {
33547
35971
  cwd: projectPath,
@@ -33601,7 +36025,7 @@ function countTestsRecursive(tests) {
33601
36025
  }
33602
36026
  function countJestTests(projectPath, config) {
33603
36027
  try {
33604
- const output = execSync2(
36028
+ const output = execSync4(
33605
36029
  "npx jest --listTests 2>/dev/null",
33606
36030
  {
33607
36031
  cwd: projectPath,
@@ -33627,7 +36051,7 @@ function countJestTests(projectPath, config) {
33627
36051
  }
33628
36052
  function countCargoTests(projectPath, config) {
33629
36053
  try {
33630
- const output = execSync2(
36054
+ const output = execSync4(
33631
36055
  'cargo test --list 2>/dev/null || echo ""',
33632
36056
  {
33633
36057
  cwd: projectPath,
@@ -33661,7 +36085,7 @@ function countCargoTests(projectPath, config) {
33661
36085
  }
33662
36086
  function countPytestTests(projectPath, config) {
33663
36087
  try {
33664
- const output = execSync2(
36088
+ const output = execSync4(
33665
36089
  'pytest --collect-only -q 2>/dev/null || echo ""',
33666
36090
  {
33667
36091
  cwd: projectPath,
@@ -33702,7 +36126,7 @@ function countPytestTests(projectPath, config) {
33702
36126
  }
33703
36127
  function countGoTests(projectPath, config) {
33704
36128
  try {
33705
- const output = execSync2(
36129
+ const output = execSync4(
33706
36130
  'go test -list ".*" ./... 2>/dev/null || echo ""',
33707
36131
  {
33708
36132
  cwd: projectPath,
@@ -35301,13 +37725,13 @@ var CodeIntelligencePlugin = class extends BaseDomainPlugin {
35301
37725
  }
35302
37726
  }
35303
37727
  handleError(error) {
35304
- const err2 = error instanceof Error ? error : new Error(String(error));
37728
+ const err3 = error instanceof Error ? error : new Error(String(error));
35305
37729
  const currentHealth = this.getHealth();
35306
37730
  this.updateHealth({
35307
- errors: [...currentHealth.errors.slice(-9), err2.message],
37731
+ errors: [...currentHealth.errors.slice(-9), err3.message],
35308
37732
  status: currentHealth.errors.length >= 5 ? "degraded" : currentHealth.status
35309
37733
  });
35310
- return { success: false, error: err2 };
37734
+ return { success: false, error: err3 };
35311
37735
  }
35312
37736
  trackSuccessfulOperation(_operation, _result) {
35313
37737
  const health = this.getHealth();
@@ -42067,9 +44491,9 @@ var SecurityComplianceCoordinator = class {
42067
44491
  await this.agentCoordinator.stop(agentResult.value);
42068
44492
  return result;
42069
44493
  } catch (error) {
42070
- const err2 = error instanceof Error ? error : new Error(String(error));
42071
- this.failWorkflow(workflowId, err2.message);
42072
- return { success: false, error: err2 };
44494
+ const err3 = error instanceof Error ? error : new Error(String(error));
44495
+ this.failWorkflow(workflowId, err3.message);
44496
+ return { success: false, error: err3 };
42073
44497
  }
42074
44498
  }
42075
44499
  /**
@@ -42094,9 +44518,9 @@ var SecurityComplianceCoordinator = class {
42094
44518
  }
42095
44519
  return result;
42096
44520
  } catch (error) {
42097
- const err2 = error instanceof Error ? error : new Error(String(error));
42098
- this.failWorkflow(workflowId, err2.message);
42099
- return { success: false, error: err2 };
44521
+ const err3 = error instanceof Error ? error : new Error(String(error));
44522
+ this.failWorkflow(workflowId, err3.message);
44523
+ return { success: false, error: err3 };
42100
44524
  }
42101
44525
  }
42102
44526
  /**
@@ -42122,9 +44546,9 @@ var SecurityComplianceCoordinator = class {
42122
44546
  }
42123
44547
  return result;
42124
44548
  } catch (error) {
42125
- const err2 = error instanceof Error ? error : new Error(String(error));
42126
- this.failWorkflow(workflowId, err2.message);
42127
- return { success: false, error: err2 };
44549
+ const err3 = error instanceof Error ? error : new Error(String(error));
44550
+ this.failWorkflow(workflowId, err3.message);
44551
+ return { success: false, error: err3 };
42128
44552
  }
42129
44553
  }
42130
44554
  /**
@@ -42150,9 +44574,9 @@ var SecurityComplianceCoordinator = class {
42150
44574
  return result;
42151
44575
  }
42152
44576
  } catch (error) {
42153
- const err2 = error instanceof Error ? error : new Error(String(error));
42154
- this.failWorkflow(workflowId, err2.message);
42155
- return { success: false, error: err2 };
44577
+ const err3 = error instanceof Error ? error : new Error(String(error));
44578
+ this.failWorkflow(workflowId, err3.message);
44579
+ return { success: false, error: err3 };
42156
44580
  }
42157
44581
  }
42158
44582
  /**
@@ -42822,13 +45246,13 @@ var SecurityCompliancePlugin = class extends BaseDomainPlugin {
42822
45246
  }
42823
45247
  }
42824
45248
  handleError(error) {
42825
- const err2 = error instanceof Error ? error : new Error(String(error));
45249
+ const err3 = error instanceof Error ? error : new Error(String(error));
42826
45250
  const currentHealth = this.getHealth();
42827
45251
  this.updateHealth({
42828
- errors: [...currentHealth.errors.slice(-9), err2.message],
45252
+ errors: [...currentHealth.errors.slice(-9), err3.message],
42829
45253
  status: currentHealth.errors.length >= 5 ? "degraded" : currentHealth.status
42830
45254
  });
42831
- return { success: false, error: err2 };
45255
+ return { success: false, error: err3 };
42832
45256
  }
42833
45257
  trackSuccessfulOperation(operation) {
42834
45258
  const health = this.getHealth();
@@ -47134,13 +49558,13 @@ var ContractTestingPlugin = class extends BaseDomainPlugin {
47134
49558
  }
47135
49559
  }
47136
49560
  handleError(error) {
47137
- const err2 = error instanceof Error ? error : new Error(String(error));
49561
+ const err3 = error instanceof Error ? error : new Error(String(error));
47138
49562
  const currentHealth = this.getHealth();
47139
49563
  this.updateHealth({
47140
- errors: [...currentHealth.errors.slice(-9), err2.message],
49564
+ errors: [...currentHealth.errors.slice(-9), err3.message],
47141
49565
  status: currentHealth.errors.length >= 5 ? "degraded" : currentHealth.status
47142
49566
  });
47143
- return { success: false, error: err2 };
49567
+ return { success: false, error: err3 };
47144
49568
  }
47145
49569
  trackSuccessfulOperation(_operation) {
47146
49570
  const health = this.getHealth();
@@ -47667,7 +50091,9 @@ var DEFAULT_CONFIG36 = {
47667
50091
  browserConfig: {
47668
50092
  headless: true,
47669
50093
  timeout: 3e4
47670
- }
50094
+ },
50095
+ browserClient: void 0,
50096
+ preferAgentBrowser: true
47671
50097
  };
47672
50098
  var WCAG_CRITERIA = {
47673
50099
  "1.1.1": { id: "1.1.1", level: "A", title: "Non-text Content" },
@@ -47691,35 +50117,49 @@ var AccessibilityTesterService = class {
47691
50117
  *
47692
50118
  * @param memory - Memory backend for storing audit results
47693
50119
  * @param config - Service configuration options
47694
- * @param vibiumClient - Optional Vibium client for browser-based testing
50120
+ * @param vibiumClient - Optional Vibium client for browser-based testing (legacy)
47695
50121
  */
47696
50122
  constructor(memory, config = {}, vibiumClient) {
47697
50123
  this.memory = memory;
47698
50124
  this.config = { ...DEFAULT_CONFIG36, ...config };
47699
50125
  this.rules = this.initializeRules();
47700
50126
  this.vibiumClient = vibiumClient ?? null;
50127
+ this.browserClient = config.browserClient ?? null;
47701
50128
  }
47702
50129
  config;
47703
50130
  rules;
47704
50131
  vibiumClient;
50132
+ browserClient;
50133
+ managedBrowserClient = null;
47705
50134
  /**
47706
50135
  * Check if browser mode is available and enabled
47707
50136
  *
47708
50137
  * Browser mode requires:
47709
- * 1. useBrowserMode feature flag enabled
47710
- * 2. VibiumClient instance provided
47711
- * 3. axe-core feature flag enabled (for accessibility checks)
50138
+ * 1. useBrowserMode config setting enabled
50139
+ * 2. Browser client (IBrowserClient) or VibiumClient instance provided
50140
+ * 3. Feature flags enabled (if using Vibium)
50141
+ *
50142
+ * Priority order:
50143
+ * 1. Provided browserClient (from config)
50144
+ * 2. agent-browser (if preferAgentBrowser is true)
50145
+ * 3. Vibium (if available and feature flags enabled)
47712
50146
  *
47713
50147
  * @returns true if browser mode should be used
47714
50148
  */
47715
50149
  shouldUseBrowserMode() {
47716
- if (!isBrowserModeEnabled()) {
50150
+ if (!this.config.useBrowserMode) {
47717
50151
  return false;
47718
50152
  }
47719
- if (!isAxeCoreEnabled()) {
50153
+ if (this.browserClient) {
50154
+ return true;
50155
+ }
50156
+ if (this.config.preferAgentBrowser) {
50157
+ return true;
50158
+ }
50159
+ if (!isBrowserModeEnabled()) {
47720
50160
  return false;
47721
50161
  }
47722
- if (!this.config.useBrowserMode) {
50162
+ if (!isAxeCoreEnabled()) {
47723
50163
  return false;
47724
50164
  }
47725
50165
  if (!this.vibiumClient) {
@@ -47727,11 +50167,45 @@ var AccessibilityTesterService = class {
47727
50167
  }
47728
50168
  return true;
47729
50169
  }
50170
+ /**
50171
+ * Get or create a browser client for accessibility testing
50172
+ * Prefers agent-browser, falls back to Vibium
50173
+ *
50174
+ * @returns Browser client or null if unavailable
50175
+ */
50176
+ async getBrowserClient() {
50177
+ if (this.browserClient) {
50178
+ return this.browserClient;
50179
+ }
50180
+ if (this.managedBrowserClient) {
50181
+ return this.managedBrowserClient;
50182
+ }
50183
+ if (this.config.preferAgentBrowser) {
50184
+ try {
50185
+ const client = await getBrowserClientForUseCase("accessibility");
50186
+ const available = await client.isAvailable();
50187
+ if (available) {
50188
+ this.managedBrowserClient = client;
50189
+ return client;
50190
+ }
50191
+ } catch {
50192
+ }
50193
+ }
50194
+ return null;
50195
+ }
50196
+ /**
50197
+ * Check if client is an IAgentBrowserClient (has getSnapshot method)
50198
+ */
50199
+ isAgentBrowserClient(client) {
50200
+ return client.tool === "agent-browser" && "getSnapshot" in client;
50201
+ }
47730
50202
  /**
47731
50203
  * Run full accessibility audit
47732
50204
  *
47733
- * Uses browser mode via Vibium if available and enabled, otherwise
47734
- * falls back to heuristic-based URL pattern analysis.
50205
+ * Priority order for browser-based testing:
50206
+ * 1. agent-browser (if preferAgentBrowser is true and available)
50207
+ * 2. Vibium (if available and enabled via feature flags)
50208
+ * 3. Heuristic mode (URL pattern analysis)
47735
50209
  *
47736
50210
  * @param url - URL to audit
47737
50211
  * @param options - Audit configuration options
@@ -47741,13 +50215,30 @@ var AccessibilityTesterService = class {
47741
50215
  try {
47742
50216
  const wcagLevel = options?.wcagLevel || this.config.defaultWCAGLevel;
47743
50217
  if (this.shouldUseBrowserMode()) {
47744
- const browserResult = await this.auditWithBrowser(url, wcagLevel, options);
47745
- if (browserResult.success) {
47746
- await this.storeReport(browserResult.value);
47747
- return browserResult;
50218
+ const browserClient = await this.getBrowserClient();
50219
+ if (browserClient) {
50220
+ const browserResult = await this.auditWithBrowserClient(
50221
+ browserClient,
50222
+ url,
50223
+ wcagLevel,
50224
+ options
50225
+ );
50226
+ if (browserResult.success) {
50227
+ await this.storeReport(browserResult.value);
50228
+ return browserResult;
50229
+ }
50230
+ const errorMsg = this.getErrorMessage(browserResult);
50231
+ console.warn(`Browser client audit failed: ${errorMsg}`);
50232
+ }
50233
+ if (this.vibiumClient && isBrowserModeEnabled() && isAxeCoreEnabled()) {
50234
+ const vibiumResult = await this.auditWithBrowser(url, wcagLevel, options);
50235
+ if (vibiumResult.success) {
50236
+ await this.storeReport(vibiumResult.value);
50237
+ return vibiumResult;
50238
+ }
50239
+ const errorMsg = this.getErrorMessage(vibiumResult);
50240
+ console.warn(`Vibium audit failed, falling back to heuristic mode: ${errorMsg}`);
47748
50241
  }
47749
- const errorMsg = this.getErrorMessage(browserResult);
47750
- console.warn(`Browser mode audit failed, falling back to heuristic mode: ${errorMsg}`);
47751
50242
  }
47752
50243
  return this.auditWithHeuristics(url, wcagLevel, options);
47753
50244
  } catch (error) {
@@ -47755,7 +50246,208 @@ var AccessibilityTesterService = class {
47755
50246
  }
47756
50247
  }
47757
50248
  /**
47758
- * Run accessibility audit using browser via Vibium
50249
+ * Run accessibility audit using unified browser client (agent-browser or other)
50250
+ *
50251
+ * This method uses the IBrowserClient interface for browser automation.
50252
+ * For agent-browser, it uses getSnapshot() for element discovery and
50253
+ * evaluate() to inject and run axe-core for accessibility testing.
50254
+ *
50255
+ * @param client - Browser client instance
50256
+ * @param url - URL to audit
50257
+ * @param wcagLevel - WCAG conformance level
50258
+ * @param options - Audit options
50259
+ * @returns AccessibilityReport from browser-based axe-core audit
50260
+ */
50261
+ async auditWithBrowserClient(client, url, wcagLevel, options) {
50262
+ try {
50263
+ const launchResult = await client.launch({
50264
+ headless: this.config.browserConfig.headless
50265
+ });
50266
+ if (!launchResult.success) {
50267
+ return err(new Error(`Failed to launch browser: ${launchResult.error?.message ?? "Unknown error"}`));
50268
+ }
50269
+ try {
50270
+ const navResult = await client.navigate(url);
50271
+ if (!navResult.success) {
50272
+ return err(new Error(`Failed to navigate to ${url}: ${navResult.error?.message ?? "Unknown error"}`));
50273
+ }
50274
+ if (this.isAgentBrowserClient(client)) {
50275
+ const snapshotResult = await client.getSnapshot({ interactive: true });
50276
+ if (snapshotResult.success) {
50277
+ const elementCount = snapshotResult.value.interactiveElements.length;
50278
+ console.debug(`[AccessibilityTester] Found ${elementCount} interactive elements`);
50279
+ }
50280
+ }
50281
+ const axeResult = await this.runAxeCore(client, wcagLevel, options);
50282
+ if (!axeResult.success) {
50283
+ return err(axeResult.error);
50284
+ }
50285
+ const report = this.mapAxeResultToReport(url, axeResult.value, wcagLevel);
50286
+ return ok(report);
50287
+ } finally {
50288
+ await client.quit();
50289
+ }
50290
+ } catch (error) {
50291
+ return err(error instanceof Error ? error : new Error(String(error)));
50292
+ }
50293
+ }
50294
+ /**
50295
+ * Inject and run axe-core in the browser context
50296
+ *
50297
+ * @param client - Browser client
50298
+ * @param wcagLevel - WCAG conformance level
50299
+ * @param options - Audit options
50300
+ * @returns Axe-core results
50301
+ */
50302
+ async runAxeCore(client, wcagLevel, options) {
50303
+ const tags = this.getAxeTagsForWcagLevel(wcagLevel);
50304
+ const excludeSelectors = options?.excludeSelectors ?? [];
50305
+ const axeScript = `
50306
+ (async function() {
50307
+ // Check if axe is already loaded
50308
+ if (typeof axe === 'undefined') {
50309
+ // Inject axe-core from CDN
50310
+ const script = document.createElement('script');
50311
+ script.src = 'https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.8.4/axe.min.js';
50312
+ script.crossOrigin = 'anonymous';
50313
+ document.head.appendChild(script);
50314
+
50315
+ // Wait for script to load
50316
+ await new Promise((resolve, reject) => {
50317
+ script.onload = resolve;
50318
+ script.onerror = () => reject(new Error('Failed to load axe-core'));
50319
+ setTimeout(() => reject(new Error('Timeout loading axe-core')), 10000);
50320
+ });
50321
+ }
50322
+
50323
+ // Configure and run axe
50324
+ const config = {
50325
+ runOnly: {
50326
+ type: 'tag',
50327
+ values: ${JSON.stringify(tags)}
50328
+ },
50329
+ exclude: ${JSON.stringify(excludeSelectors.map((s) => [s]))}
50330
+ };
50331
+
50332
+ const results = await axe.run(document, config);
50333
+
50334
+ return JSON.stringify({
50335
+ violations: results.violations.map(v => ({
50336
+ id: v.id,
50337
+ impact: v.impact,
50338
+ description: v.description,
50339
+ help: v.help,
50340
+ helpUrl: v.helpUrl,
50341
+ tags: v.tags,
50342
+ nodes: v.nodes.map(n => ({
50343
+ selector: n.target.join(' > '),
50344
+ html: n.html,
50345
+ target: n.target,
50346
+ failureSummary: n.failureSummary
50347
+ }))
50348
+ })),
50349
+ passes: results.passes.map(p => p.id),
50350
+ incomplete: results.incomplete.map(i => i.id),
50351
+ inapplicable: results.inapplicable.map(i => i.id)
50352
+ });
50353
+ })();
50354
+ `;
50355
+ const evalResult = await client.evaluate(axeScript);
50356
+ if (!evalResult.success) {
50357
+ return err(new Error(`Failed to run axe-core: ${evalResult.error?.message ?? "Unknown error"}`));
50358
+ }
50359
+ try {
50360
+ const parsed = JSON.parse(evalResult.value);
50361
+ return ok(parsed);
50362
+ } catch (parseError) {
50363
+ return err(new Error(`Failed to parse axe-core results: ${parseError}`));
50364
+ }
50365
+ }
50366
+ /**
50367
+ * Get axe-core tags for a WCAG conformance level
50368
+ */
50369
+ getAxeTagsForWcagLevel(level) {
50370
+ const baseTags = ["wcag2a", "wcag21a", "wcag22a", "best-practice"];
50371
+ if (level === "A") {
50372
+ return baseTags;
50373
+ }
50374
+ const aaTags = [...baseTags, "wcag2aa", "wcag21aa", "wcag22aa"];
50375
+ if (level === "AA") {
50376
+ return aaTags;
50377
+ }
50378
+ return [...aaTags, "wcag2aaa", "wcag21aaa", "wcag22aaa"];
50379
+ }
50380
+ /**
50381
+ * Map axe-core result to AccessibilityReport
50382
+ */
50383
+ mapAxeResultToReport(url, axeResult, wcagLevel) {
50384
+ const violations = axeResult.violations.map((v) => ({
50385
+ id: v.id,
50386
+ impact: this.mapImpactSeverity(v.impact ?? "moderate"),
50387
+ wcagCriteria: this.extractWcagCriteria(v.tags ?? [], wcagLevel),
50388
+ description: v.description,
50389
+ help: v.help,
50390
+ helpUrl: v.helpUrl ?? `https://dequeuniversity.com/rules/axe/4.8/${v.id}`,
50391
+ nodes: v.nodes.map((n) => ({
50392
+ selector: n.selector,
50393
+ html: n.html,
50394
+ target: n.target,
50395
+ failureSummary: n.failureSummary ?? ""
50396
+ }))
50397
+ }));
50398
+ const passes = axeResult.passes.map((ruleId) => ({
50399
+ id: ruleId,
50400
+ description: `Rule ${ruleId} passed`,
50401
+ nodes: 0
50402
+ }));
50403
+ const incomplete = axeResult.incomplete.map((ruleId) => ({
50404
+ id: ruleId,
50405
+ description: `Rule ${ruleId} requires manual review`,
50406
+ reason: "Could not automatically determine compliance",
50407
+ nodes: []
50408
+ }));
50409
+ const totalRules = violations.length + passes.length + incomplete.length;
50410
+ const failedWeight = violations.reduce((sum, v) => {
50411
+ const weights = { critical: 4, serious: 3, moderate: 2, minor: 1 };
50412
+ return sum + weights[v.impact];
50413
+ }, 0);
50414
+ const maxWeight = totalRules * 4;
50415
+ const score = totalRules > 0 ? Math.round((maxWeight - failedWeight) / maxWeight * 100) : 100;
50416
+ return {
50417
+ url,
50418
+ timestamp: /* @__PURE__ */ new Date(),
50419
+ violations,
50420
+ passes,
50421
+ incomplete,
50422
+ score: Math.max(0, Math.min(100, score)),
50423
+ wcagLevel
50424
+ };
50425
+ }
50426
+ /**
50427
+ * Extract WCAG criteria from axe-core tags
50428
+ */
50429
+ extractWcagCriteria(tags, defaultLevel) {
50430
+ const criteria = [];
50431
+ for (const tag of tags) {
50432
+ const match = tag.match(/^wcag(\d)(\d)(\d)(\d)?$/);
50433
+ if (match) {
50434
+ const id = match[4] ? `${match[1]}.${match[2]}.${match[3]}${match[4]}` : `${match[1]}.${match[2]}.${match[3]}`;
50435
+ const existing = WCAG_CRITERIA[id];
50436
+ if (existing) {
50437
+ criteria.push(existing);
50438
+ } else {
50439
+ criteria.push({
50440
+ id,
50441
+ level: defaultLevel,
50442
+ title: `WCAG ${id}`
50443
+ });
50444
+ }
50445
+ }
50446
+ }
50447
+ return criteria;
50448
+ }
50449
+ /**
50450
+ * Run accessibility audit using browser via Vibium (legacy method)
47759
50451
  *
47760
50452
  * @param url - URL to audit
47761
50453
  * @param wcagLevel - WCAG conformance level
@@ -48867,6 +51559,16 @@ var AccessibilityTesterService = class {
48867
51559
  }
48868
51560
  return Math.abs(hash).toString(36);
48869
51561
  }
51562
+ /**
51563
+ * Dispose service resources
51564
+ * Cleans up any managed browser clients
51565
+ */
51566
+ async dispose() {
51567
+ if (this.managedBrowserClient) {
51568
+ await this.managedBrowserClient.dispose();
51569
+ this.managedBrowserClient = null;
51570
+ }
51571
+ }
48870
51572
  };
48871
51573
 
48872
51574
  // src/domains/visual-accessibility/services/responsive-tester.ts
@@ -49922,9 +52624,9 @@ var VisualAccessibilityCoordinator = class {
49922
52624
  await this.agentCoordinator.stop(agentResult.value);
49923
52625
  return ok(report);
49924
52626
  } catch (error) {
49925
- const err2 = error instanceof Error ? error : new Error(String(error));
49926
- this.failWorkflow(workflowId, err2.message);
49927
- return { success: false, error: err2 };
52627
+ const err3 = error instanceof Error ? error : new Error(String(error));
52628
+ this.failWorkflow(workflowId, err3.message);
52629
+ return { success: false, error: err3 };
49928
52630
  }
49929
52631
  }
49930
52632
  /**
@@ -49978,9 +52680,9 @@ var VisualAccessibilityCoordinator = class {
49978
52680
  await this.agentCoordinator.stop(agentResult.value);
49979
52681
  return ok(auditReport);
49980
52682
  } catch (error) {
49981
- const err2 = error instanceof Error ? error : new Error(String(error));
49982
- this.failWorkflow(workflowId, err2.message);
49983
- return { success: false, error: err2 };
52683
+ const err3 = error instanceof Error ? error : new Error(String(error));
52684
+ this.failWorkflow(workflowId, err3.message);
52685
+ return { success: false, error: err3 };
49984
52686
  }
49985
52687
  }
49986
52688
  /**
@@ -50906,13 +53608,13 @@ var VisualAccessibilityPlugin = class extends BaseDomainPlugin {
50906
53608
  }
50907
53609
  }
50908
53610
  handleError(error) {
50909
- const err2 = error instanceof Error ? error : new Error(String(error));
53611
+ const err3 = error instanceof Error ? error : new Error(String(error));
50910
53612
  const currentHealth = this.getHealth();
50911
53613
  this.updateHealth({
50912
- errors: [...currentHealth.errors.slice(-9), err2.message],
53614
+ errors: [...currentHealth.errors.slice(-9), err3.message],
50913
53615
  status: currentHealth.errors.length >= 5 ? "degraded" : currentHealth.status
50914
53616
  });
50915
- return { success: false, error: err2 };
53617
+ return { success: false, error: err3 };
50916
53618
  }
50917
53619
  trackSuccessfulTest(_type, _count) {
50918
53620
  const health = this.getHealth();
@@ -51327,10 +54029,10 @@ var ChaosEngineerService = class _ChaosEngineerService {
51327
54029
  socket.destroy();
51328
54030
  resolve7(true);
51329
54031
  });
51330
- socket.on("error", (err2) => {
54032
+ socket.on("error", (err3) => {
51331
54033
  clearTimeout(timer);
51332
54034
  socket.destroy();
51333
- console.log(`TCP probe error: ${probe.name} -> ${err2.message}`);
54035
+ console.log(`TCP probe error: ${probe.name} -> ${err3.message}`);
51334
54036
  resolve7(false);
51335
54037
  });
51336
54038
  } catch (error) {
@@ -54689,13 +57391,13 @@ var ChaosResiliencePlugin = class extends BaseDomainPlugin {
54689
57391
  }
54690
57392
  }
54691
57393
  handleError(error) {
54692
- const err2 = error instanceof Error ? error : new Error(String(error));
57394
+ const err3 = error instanceof Error ? error : new Error(String(error));
54693
57395
  const currentHealth = this.getHealth();
54694
57396
  this.updateHealth({
54695
- errors: [...currentHealth.errors.slice(-9), err2.message],
57397
+ errors: [...currentHealth.errors.slice(-9), err3.message],
54696
57398
  status: currentHealth.errors.length >= 5 ? "degraded" : currentHealth.status
54697
57399
  });
54698
- return { success: false, error: err2 };
57400
+ return { success: false, error: err3 };
54699
57401
  }
54700
57402
  trackSuccessfulOperation(_type) {
54701
57403
  const health = this.getHealth();
@@ -61751,8 +64453,8 @@ var MinCutHealthMonitor = class {
61751
64453
  ...payload
61752
64454
  }
61753
64455
  };
61754
- this.eventBus.publish(event).catch((err2) => {
61755
- console.error("Failed to publish MinCut event:", err2);
64456
+ this.eventBus.publish(event).catch((err3) => {
64457
+ console.error("Failed to publish MinCut event:", err3);
61756
64458
  });
61757
64459
  }
61758
64460
  };
@@ -67518,13 +70220,13 @@ var InitOrchestrator = class {
67518
70220
  db.close();
67519
70221
  console.log(` \u2713 Version ${version} written to memory.db`);
67520
70222
  return true;
67521
- } catch (err2) {
70223
+ } catch (err3) {
67522
70224
  db.close();
67523
- console.warn(` \u26A0 Could not write version: ${err2 instanceof Error ? err2.message : String(err2)}`);
70225
+ console.warn(` \u26A0 Could not write version: ${err3 instanceof Error ? err3.message : String(err3)}`);
67524
70226
  return false;
67525
70227
  }
67526
- } catch (err2) {
67527
- console.warn(` \u26A0 Could not open memory.db: ${err2 instanceof Error ? err2.message : String(err2)}`);
70228
+ } catch (err3) {
70229
+ console.warn(` \u26A0 Could not open memory.db: ${err3 instanceof Error ? err3.message : String(err3)}`);
67528
70230
  return false;
67529
70231
  }
67530
70232
  }
@@ -72530,8 +75232,8 @@ var TokenMetricsCollectorImpl = class {
72530
75232
  if (this.persistenceConfig.autoSaveIntervalMs > 0) {
72531
75233
  this.autoSaveTimer = setInterval(() => {
72532
75234
  if (this.isDirty) {
72533
- this.save().catch((err2) => {
72534
- console.warn("[TokenMetricsCollector] Auto-save failed:", err2);
75235
+ this.save().catch((err3) => {
75236
+ console.warn("[TokenMetricsCollector] Auto-save failed:", err3);
72535
75237
  });
72536
75238
  }
72537
75239
  }, this.persistenceConfig.autoSaveIntervalMs);
@@ -73304,10 +76006,10 @@ function parsePipelineFile(filePath) {
73304
76006
  let content;
73305
76007
  try {
73306
76008
  content = fs10.readFileSync(filePath, "utf-8");
73307
- } catch (err2) {
76009
+ } catch (err3) {
73308
76010
  return {
73309
76011
  success: false,
73310
- errors: [`Failed to read file: ${err2}`]
76012
+ errors: [`Failed to read file: ${err3}`]
73311
76013
  };
73312
76014
  }
73313
76015
  return parsePipelineContent(content, filePath);
@@ -73317,10 +76019,10 @@ function parsePipelineContent(content, sourcePath) {
73317
76019
  let parsed;
73318
76020
  try {
73319
76021
  parsed = parseYAMLContent(content);
73320
- } catch (err2) {
76022
+ } catch (err3) {
73321
76023
  return {
73322
76024
  success: false,
73323
- errors: [`Invalid YAML syntax: ${err2}`]
76025
+ errors: [`Invalid YAML syntax: ${err3}`]
73324
76026
  };
73325
76027
  }
73326
76028
  if (!parsed.name || typeof parsed.name !== "string") {
@@ -78159,13 +80861,13 @@ async function ensureInitialized() {
78159
80861
  ]);
78160
80862
  console.log(chalk8.green("\u2713 System ready\n"));
78161
80863
  return true;
78162
- } catch (err2) {
78163
- const error = err2;
80864
+ } catch (err3) {
80865
+ const error = err3;
78164
80866
  if (error.message.includes("timeout")) {
78165
80867
  console.error(chalk8.red("Initialization timed out after 30 seconds."));
78166
80868
  console.log(chalk8.yellow("Try running `aqe init` manually."));
78167
80869
  } else {
78168
- console.error(chalk8.red("Failed to auto-initialize:"), err2);
80870
+ console.error(chalk8.red("Failed to auto-initialize:"), err3);
78169
80871
  console.log(chalk8.yellow("Try running `aqe init` manually."));
78170
80872
  }
78171
80873
  return false;
@@ -78186,6 +80888,7 @@ async function cleanupAndExit(code = 0) {
78186
80888
  if (context.kernel) {
78187
80889
  await context.kernel.dispose();
78188
80890
  }
80891
+ UnifiedMemoryManager.resetInstance();
78189
80892
  } catch {
78190
80893
  }
78191
80894
  process.exit(code);
@@ -78382,7 +81085,7 @@ program.command("health").description("Check system health").option("-d, --domai
78382
81085
  if (health.errors.length > 0) {
78383
81086
  console.log(chalk8.red(`
78384
81087
  Errors:`));
78385
- health.errors.forEach((err2) => console.log(chalk8.red(` \u2022 ${err2}`)));
81088
+ health.errors.forEach((err3) => console.log(chalk8.red(` \u2022 ${err3}`)));
78386
81089
  }
78387
81090
  } else {
78388
81091
  const health = context.queen.getHealth();
@@ -78684,7 +81387,7 @@ domainCmd.command("health <domain>").description("Get domain health").action(asy
78684
81387
  }
78685
81388
  if (health.errors.length > 0) {
78686
81389
  console.log(chalk8.red("\n Errors:"));
78687
- health.errors.forEach((err2) => console.log(chalk8.red(` \u2022 ${err2}`)));
81390
+ health.errors.forEach((err3) => console.log(chalk8.red(` \u2022 ${err3}`)));
78688
81391
  }
78689
81392
  console.log("");
78690
81393
  } catch (error) {
@@ -79132,7 +81835,7 @@ program.command("test").description("Test generation shortcut").argument("<actio
79132
81835
  console.log(chalk8.blue(`
79133
81836
  \u{1F9EA} Generating tests for ${target || "current directory"}...
79134
81837
  `));
79135
- const testGenAPI = context.kernel.getDomainAPI("test-generation");
81838
+ const testGenAPI = await context.kernel.getDomainAPIAsync("test-generation");
79136
81839
  if (!testGenAPI) {
79137
81840
  console.log(chalk8.red("\u274C Test generation domain not available"));
79138
81841
  return;
@@ -79201,7 +81904,7 @@ program.command("test").description("Test generation shortcut").argument("<actio
79201
81904
  console.log(chalk8.blue(`
79202
81905
  \u{1F9EA} Executing tests in ${target || "current directory"}...
79203
81906
  `));
79204
- const testExecAPI = context.kernel.getDomainAPI("test-execution");
81907
+ const testExecAPI = await context.kernel.getDomainAPIAsync("test-execution");
79205
81908
  if (!testExecAPI) {
79206
81909
  console.log(chalk8.red("\u274C Test execution domain not available"));
79207
81910
  return;
@@ -79293,8 +81996,8 @@ program.command("coverage").description("Coverage analysis shortcut").argument("
79293
81996
  detectGaps = true;
79294
81997
  threshold = wizardResult.threshold;
79295
81998
  console.log(chalk8.green("\n Starting coverage analysis...\n"));
79296
- } catch (err2) {
79297
- console.error(chalk8.red("\n Wizard error:"), err2);
81999
+ } catch (err3) {
82000
+ console.error(chalk8.red("\n Wizard error:"), err3);
79298
82001
  await cleanupAndExit(1);
79299
82002
  }
79300
82003
  }
@@ -79303,7 +82006,7 @@ program.command("coverage").description("Coverage analysis shortcut").argument("
79303
82006
  console.log(chalk8.blue(`
79304
82007
  Analyzing coverage for ${analyzeTarget}...
79305
82008
  `));
79306
- const coverageAPI = context.kernel.getDomainAPI("coverage-analysis");
82009
+ const coverageAPI = await context.kernel.getDomainAPIAsync("coverage-analysis");
79307
82010
  if (!coverageAPI) {
79308
82011
  console.log(chalk8.red("\u274C Coverage analysis domain not available"));
79309
82012
  return;
@@ -79482,7 +82185,7 @@ program.command("security").description("Security scanning shortcut").option("--
79482
82185
  console.log(chalk8.blue(`
79483
82186
  \u{1F512} Running security scan on ${options.target}...
79484
82187
  `));
79485
- const securityAPI = context.kernel.getDomainAPI("security-compliance");
82188
+ const securityAPI = await context.kernel.getDomainAPIAsync("security-compliance");
79486
82189
  if (!securityAPI) {
79487
82190
  console.log(chalk8.red("\u274C Security domain not available"));
79488
82191
  return;
@@ -79568,15 +82271,15 @@ program.command("security").description("Security scanning shortcut").option("--
79568
82271
  }
79569
82272
  console.log(chalk8.green("\u2705 Security scan complete\n"));
79570
82273
  await cleanupAndExit(0);
79571
- } catch (err2) {
79572
- console.error(chalk8.red("\n\u274C Failed:"), err2);
82274
+ } catch (err3) {
82275
+ console.error(chalk8.red("\n\u274C Failed:"), err3);
79573
82276
  await cleanupAndExit(1);
79574
82277
  }
79575
82278
  });
79576
82279
  program.command("code").description("Code intelligence analysis").argument("<action>", "Action (index|search|impact|deps)").argument("[target]", "Target path or query").option("--depth <depth>", "Analysis depth", "3").option("--include-tests", "Include test files").action(async (action, target, options) => {
79577
82280
  if (!await ensureInitialized()) return;
79578
82281
  try {
79579
- const codeAPI = context.kernel.getDomainAPI("code-intelligence");
82282
+ const codeAPI = await context.kernel.getDomainAPIAsync("code-intelligence");
79580
82283
  if (!codeAPI) {
79581
82284
  console.log(chalk8.red("\u274C Code intelligence domain not available"));
79582
82285
  return;
@@ -79631,8 +82334,8 @@ program.command("code").description("Code intelligence analysis").argument("<act
79631
82334
  if (idx.errors.length > 0) {
79632
82335
  console.log(chalk8.red(`
79633
82336
  Errors (${idx.errors.length}):`));
79634
- for (const err2 of idx.errors.slice(0, 5)) {
79635
- console.log(chalk8.red(` ${err2.file}: ${err2.error}`));
82337
+ for (const err3 of idx.errors.slice(0, 5)) {
82338
+ console.log(chalk8.red(` ${err3.file}: ${err3.error}`));
79636
82339
  }
79637
82340
  }
79638
82341
  } else {
@@ -79900,8 +82603,8 @@ migrateCmd.command("run").description("Run full migration from v2 to v3").option
79900
82603
  if (hasClaudeAgents) copyDir(claudeAgentDir, path13.join(backupDir, ".claude", "agents"));
79901
82604
  console.log(chalk8.green(` \u2713 Backup created at .aqe-backup/
79902
82605
  `));
79903
- } catch (err2) {
79904
- console.log(chalk8.red(` \u2717 Backup failed: ${err2}`));
82606
+ } catch (err3) {
82607
+ console.log(chalk8.red(` \u2717 Backup failed: ${err3}`));
79905
82608
  await cleanupAndExit(1);
79906
82609
  }
79907
82610
  } else {
@@ -79916,8 +82619,8 @@ migrateCmd.command("run").description("Run full migration from v2 to v3").option
79916
82619
  fs13.mkdirSync(path13.join(v3Dir, "cache"), { recursive: true });
79917
82620
  fs13.mkdirSync(path13.join(v3Dir, "logs"), { recursive: true });
79918
82621
  console.log(chalk8.green(" \u2713 Directory structure created\n"));
79919
- } catch (err2) {
79920
- console.log(chalk8.red(` \u2717 Failed: ${err2}
82622
+ } catch (err3) {
82623
+ console.log(chalk8.red(` \u2717 Failed: ${err3}
79921
82624
  `));
79922
82625
  await cleanupAndExit(1);
79923
82626
  }
@@ -79938,8 +82641,8 @@ migrateCmd.command("run").description("Run full migration from v2 to v3").option
79938
82641
  const stats = fs13.statSync(v2Files.memoryDb);
79939
82642
  console.log(chalk8.green(` \u2713 Memory database migrated (${(stats.size / 1024).toFixed(1)} KB)
79940
82643
  `));
79941
- } catch (err2) {
79942
- console.log(chalk8.red(` \u2717 Migration failed: ${err2}
82644
+ } catch (err3) {
82645
+ console.log(chalk8.red(` \u2717 Migration failed: ${err3}
79943
82646
  `));
79944
82647
  }
79945
82648
  } else if (options.target && options.target !== "memory") {
@@ -79991,8 +82694,8 @@ migrateCmd.command("run").description("Run full migration from v2 to v3").option
79991
82694
  const destConfig = path13.join(v3Dir, "config.json");
79992
82695
  fs13.writeFileSync(destConfig, JSON.stringify(v3Config, null, 2));
79993
82696
  console.log(chalk8.green(" \u2713 Configuration migrated\n"));
79994
- } catch (err2) {
79995
- console.log(chalk8.red(` \u2717 Config migration failed: ${err2}
82697
+ } catch (err3) {
82698
+ console.log(chalk8.red(` \u2717 Config migration failed: ${err3}
79996
82699
  `));
79997
82700
  }
79998
82701
  } else if (options.target && options.target !== "config") {
@@ -80025,8 +82728,8 @@ migrateCmd.command("run").description("Run full migration from v2 to v3").option
80025
82728
  }, null, 2));
80026
82729
  console.log(chalk8.green(` \u2713 ${migratedCount} patterns migrated
80027
82730
  `));
80028
- } catch (err2) {
80029
- console.log(chalk8.red(` \u2717 Pattern migration failed: ${err2}
82731
+ } catch (err3) {
82732
+ console.log(chalk8.red(` \u2717 Pattern migration failed: ${err3}
80030
82733
  `));
80031
82734
  }
80032
82735
  } else if (options.skipPatterns) {
@@ -80079,8 +82782,8 @@ ${newFrontmatter}
80079
82782
  fs13.renameSync(v2FilePath, deprecatedPath);
80080
82783
  console.log(chalk8.gray(` ${v2Name} \u2192 ${v3Name}`));
80081
82784
  migratedAgents++;
80082
- } catch (err2) {
80083
- console.log(chalk8.red(` \u2717 ${v2Name}: ${err2}`));
82785
+ } catch (err3) {
82786
+ console.log(chalk8.red(` \u2717 ${v2Name}: ${err3}`));
80084
82787
  }
80085
82788
  }
80086
82789
  if (migratedAgents > 0) {
@@ -80278,8 +82981,8 @@ ${newFrontmatter}
80278
82981
  console.log(chalk8.green(` \u2713 Migrated ${v2Name} \u2192 ${v3Name}`));
80279
82982
  fixedCount++;
80280
82983
  }
80281
- } catch (err2) {
80282
- console.log(chalk8.red(` \u2717 Failed to migrate ${v2Name}: ${err2}`));
82984
+ } catch (err3) {
82985
+ console.log(chalk8.red(` \u2717 Failed to migrate ${v2Name}: ${err3}`));
80283
82986
  }
80284
82987
  }
80285
82988
  }
@@ -80404,8 +83107,8 @@ Installing completions for ${shellInfo.name}...
80404
83107
  fs13.writeFileSync(completionFile, script);
80405
83108
  console.log(chalk8.green(`Completions installed to: ${completionFile}`));
80406
83109
  console.log(chalk8.gray("\nRestart your shell or run: source ~/.config/fish/completions/aqe.fish\n"));
80407
- } catch (err2) {
80408
- console.log(chalk8.red(`Failed to install: ${err2}`));
83110
+ } catch (err3) {
83111
+ console.log(chalk8.red(`Failed to install: ${err3}`));
80409
83112
  console.log(chalk8.yellow("\nManual installation:"));
80410
83113
  console.log(getInstallInstructions("fish"));
80411
83114
  }