@agimon-ai/browse-tool 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +8 -8
- package/dist/cli.mjs +3 -3
- package/dist/extension/background.js +104 -28
- package/dist/extension/background.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{playwright-test-DTw_9rvK.cjs → playwright-test-CWwqqICj.cjs} +1 -1
- package/dist/stdio-BwMaaSWk.cjs +10 -0
- package/dist/stdio-CT2oPr3E.mjs +9 -0
- package/dist/stubs/playwright-test.cjs +1 -1
- package/package.json +3 -2
- package/dist/stdio-DKou0TqY.cjs +0 -10
- package/dist/stdio-ELROpCD_.mjs +0 -9
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=require(`./stdio-
|
|
1
|
+
const e=require(`./stdio-BwMaaSWk.cjs`);require(`./playwright-test-CWwqqICj.cjs`);let t=require(`@modelcontextprotocol/sdk/server/index.js`),n=require(`@modelcontextprotocol/sdk/types.js`),r=require(`liquidjs`);function i(){let e=()=>void 0;return{debug:e,info:e,warn:e,error:e}}var a=class extends Error{code=`UNKNOWN_TOOL`;recovery=`Use ListTools to see available tools.`;availableTools;constructor(e,t,n){super(`Unknown tool: ${e}. Available tools: ${t.slice(0,5).join(`, `)}${t.length>5?`, ... (${t.length} total)`:``}. Use ListTools to see all available tools.`,n),this.name=`UnknownToolError`,this.availableTools=t}},o=class extends Error{code=`TOOL_EXECUTION_ERROR`;recovery;toolName;constructor(e,t,n){super(`Tool execution failed for '${e}': ${t}`,n),this.name=`ToolExecutionError`,this.toolName=e,this.recovery=n?.recovery??`Check tool inputs and try again.`}};function s(e,t){let n=e instanceof Error?e.message:`Unknown error occurred`,r={error:{code:e instanceof Error&&`code`in e?e.code:`TOOL_EXECUTION_ERROR`,message:n,toolName:t,recovery:e instanceof Error&&`recovery`in e?e.recovery:`Check tool inputs and try again.`}};return{content:[{type:`text`,text:JSON.stringify(r,null,2)}],isError:!0}}function c(r){let c=r?.container??e.n,l=r?.logger??i(),u=new t.Server({name:`browse-tool`,version:`0.1.0`},{capabilities:{tools:{}}}),d=c.getAll(e.g.Tool),f=new Map;for(let e of d){let t=e.getDefinition();f.set(t.name,e)}return l.info(`MCP server initialized`,{toolCount:d.length}),u.setRequestHandler(n.ListToolsRequestSchema,async()=>(l.debug(`ListTools request received`),{tools:d.map(e=>e.getDefinition())})),u.setRequestHandler(n.CallToolRequestSchema,async e=>{let{name:t,arguments:n}=e.params;l.debug(`Tool call received`,{toolName:t,timestamp:new Date().toISOString()});let r=f.get(t);if(!r){let e=Array.from(f.keys());throw l.warn(`Unknown tool requested`,{toolName:t,availableTools:e,timestamp:new Date().toISOString()}),new a(t,e)}try{return await r.execute(n)}catch(e){let n=e instanceof o?e:new o(t,e instanceof Error?e.message:String(e),{cause:e});return l.error(`Tool execution failed`,{toolName:t,error:n.message,code:n.code,timestamp:new Date().toISOString()}),s(n,t)}}),u}var l='Create a browse-tool custom tool folder for use with `browse-tool mcp-serve --custom-tools <dir>`.\n\nGoal: {{ toolGoal }}\nPreferred tool name: {{ preferredToolName }}\nPage context: {{ pageContext }}\n\nRequirements:\n- Produce a `tools.yaml` file with a top-level `tools` array.\n- Each tool entry must include `name`, `description`, `script`, `capabilities`, and `inputSchema`.\n- Each tool entry may optionally include `suggestionActions` as a short text string describing the recommended next step after the tool succeeds.\n- `inputSchema` must be JSON Schema with `type: object`.\n- `inputSchema` must define `pageId` as `type: string` and include `pageId` in `required`.\n- The script file must be `.ts` and export a default function with the shape `({ page, input, logger }) => { ... }`.\n- The default export runs in Node.js, not inside the page.\n- Use the provided `page` object for browser interaction. It will be a Playwright page in playwright mode or an extension page proxy in extension mode.\n- Use the provided `logger` object for instrumentation. It exposes `trace`, `debug`, `info`, `warn`, `error`, and `fatal`, and logs automatically attach to the active custom-tool telemetry context.\n- The logger also exposes `getTraceContext()` so a tool can return the active `traceId` and `spanId` when needed for downstream log inspection.\n- If you need DOM access, call `page.evaluate(...)` from the default export instead of assuming browser globals are available at module scope.\n- Keep the script self-contained and avoid relative imports.\n- Return either a plain object, a string, or an MCP-style `CallToolResult`.\n- Prefer read-only behavior unless the goal explicitly requires mutation.\n\nOutput format:\n- Show the full `tools.yaml` content.\n- Show the full `{{ preferredToolName }}.ts` content.\n- If the tool needs additional inputs beyond `pageId`, define them in `inputSchema` and read them from `input`.\n- Filesystem access is allowed because the script runs in Node.js.\n\nExample `tools.yaml` shape:\n```yaml\ntools:\n - name: get_post\n description: Get the current post from the open feed page\n script: get_post.ts\n suggestionActions: Open the author profile and review whether the post is worth engaging with\n capabilities:\n readOnlyHint: true\n openWorldHint: false\n inputSchema:\n type: object\n properties:\n pageId:\n type: string\n selector:\n type: string\n required:\n - pageId\n```\n\nExample script shape:\n```ts\nexport default async function getPost({ page, input, logger }) {\n const traceContext = logger.getTraceContext();\n logger.info("reading post", { attributes: { selector: input.selector ?? "body" } });\n const selector = input.selector ?? "body";\n const text = await page.evaluate((currentSelector) => {\n return document.querySelector(currentSelector)?.textContent ?? "";\n }, selector);\n return {\n pageUrl: page.url(),\n traceContext,\n text,\n };\n}\n```\n';const u={name:`custom_script_authoring`,description:`Generate a browse-tool custom tool folder with tools.yaml and TypeScript scripts.`,arguments:[{name:`toolGoal`,description:`What the custom tool should do on the page`,required:!0},{name:`toolName`,description:`Preferred snake_case tool name`,required:!1},{name:`pageContext`,description:`Optional context about the target page or workflow`,required:!1}]},d=new r.Liquid;function f(e){let t=e.toolName?.trim()||`custom_page_tool`,n=e.pageContext?.trim()||`No extra page context provided.`;return[{role:`user`,content:{type:`text`,text:d.parseAndRenderSync(l,{toolGoal:e.toolGoal,preferredToolName:t,pageContext:n})}}]}exports.PLAYWRIGHT_TYPES=e.g,exports.StdioTransportHandler=e.t,exports.ToolExecutionError=o,exports.UnknownToolError=a,exports.container=e.n,exports.createContainer=e.r,exports.createServer=c,exports.customScriptAuthoringPrompt=u,exports.generateCustomScriptAuthoringPrompt=f;
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{g as e,n as t,r as n,t as r}from"./stdio-
|
|
1
|
+
import{g as e,n as t,r as n,t as r}from"./stdio-CT2oPr3E.mjs";import"./playwright-test-BwI7HgW7.mjs";import{Server as i}from"@modelcontextprotocol/sdk/server/index.js";import{CallToolRequestSchema as a,ListToolsRequestSchema as o}from"@modelcontextprotocol/sdk/types.js";import{Liquid as s}from"liquidjs";function c(){let e=()=>void 0;return{debug:e,info:e,warn:e,error:e}}var l=class extends Error{code=`UNKNOWN_TOOL`;recovery=`Use ListTools to see available tools.`;availableTools;constructor(e,t,n){super(`Unknown tool: ${e}. Available tools: ${t.slice(0,5).join(`, `)}${t.length>5?`, ... (${t.length} total)`:``}. Use ListTools to see all available tools.`,n),this.name=`UnknownToolError`,this.availableTools=t}},u=class extends Error{code=`TOOL_EXECUTION_ERROR`;recovery;toolName;constructor(e,t,n){super(`Tool execution failed for '${e}': ${t}`,n),this.name=`ToolExecutionError`,this.toolName=e,this.recovery=n?.recovery??`Check tool inputs and try again.`}};function d(e,t){let n=e instanceof Error?e.message:`Unknown error occurred`,r={error:{code:e instanceof Error&&`code`in e?e.code:`TOOL_EXECUTION_ERROR`,message:n,toolName:t,recovery:e instanceof Error&&`recovery`in e?e.recovery:`Check tool inputs and try again.`}};return{content:[{type:`text`,text:JSON.stringify(r,null,2)}],isError:!0}}function f(n){let r=n?.container??t,s=n?.logger??c(),f=new i({name:`browse-tool`,version:`0.1.0`},{capabilities:{tools:{}}}),p=r.getAll(e.Tool),m=new Map;for(let e of p){let t=e.getDefinition();m.set(t.name,e)}return s.info(`MCP server initialized`,{toolCount:p.length}),f.setRequestHandler(o,async()=>(s.debug(`ListTools request received`),{tools:p.map(e=>e.getDefinition())})),f.setRequestHandler(a,async e=>{let{name:t,arguments:n}=e.params;s.debug(`Tool call received`,{toolName:t,timestamp:new Date().toISOString()});let r=m.get(t);if(!r){let e=Array.from(m.keys());throw s.warn(`Unknown tool requested`,{toolName:t,availableTools:e,timestamp:new Date().toISOString()}),new l(t,e)}try{return await r.execute(n)}catch(e){let n=e instanceof u?e:new u(t,e instanceof Error?e.message:String(e),{cause:e});return s.error(`Tool execution failed`,{toolName:t,error:n.message,code:n.code,timestamp:new Date().toISOString()}),d(n,t)}}),f}var p='Create a browse-tool custom tool folder for use with `browse-tool mcp-serve --custom-tools <dir>`.\n\nGoal: {{ toolGoal }}\nPreferred tool name: {{ preferredToolName }}\nPage context: {{ pageContext }}\n\nRequirements:\n- Produce a `tools.yaml` file with a top-level `tools` array.\n- Each tool entry must include `name`, `description`, `script`, `capabilities`, and `inputSchema`.\n- Each tool entry may optionally include `suggestionActions` as a short text string describing the recommended next step after the tool succeeds.\n- `inputSchema` must be JSON Schema with `type: object`.\n- `inputSchema` must define `pageId` as `type: string` and include `pageId` in `required`.\n- The script file must be `.ts` and export a default function with the shape `({ page, input, logger }) => { ... }`.\n- The default export runs in Node.js, not inside the page.\n- Use the provided `page` object for browser interaction. It will be a Playwright page in playwright mode or an extension page proxy in extension mode.\n- Use the provided `logger` object for instrumentation. It exposes `trace`, `debug`, `info`, `warn`, `error`, and `fatal`, and logs automatically attach to the active custom-tool telemetry context.\n- The logger also exposes `getTraceContext()` so a tool can return the active `traceId` and `spanId` when needed for downstream log inspection.\n- If you need DOM access, call `page.evaluate(...)` from the default export instead of assuming browser globals are available at module scope.\n- Keep the script self-contained and avoid relative imports.\n- Return either a plain object, a string, or an MCP-style `CallToolResult`.\n- Prefer read-only behavior unless the goal explicitly requires mutation.\n\nOutput format:\n- Show the full `tools.yaml` content.\n- Show the full `{{ preferredToolName }}.ts` content.\n- If the tool needs additional inputs beyond `pageId`, define them in `inputSchema` and read them from `input`.\n- Filesystem access is allowed because the script runs in Node.js.\n\nExample `tools.yaml` shape:\n```yaml\ntools:\n - name: get_post\n description: Get the current post from the open feed page\n script: get_post.ts\n suggestionActions: Open the author profile and review whether the post is worth engaging with\n capabilities:\n readOnlyHint: true\n openWorldHint: false\n inputSchema:\n type: object\n properties:\n pageId:\n type: string\n selector:\n type: string\n required:\n - pageId\n```\n\nExample script shape:\n```ts\nexport default async function getPost({ page, input, logger }) {\n const traceContext = logger.getTraceContext();\n logger.info("reading post", { attributes: { selector: input.selector ?? "body" } });\n const selector = input.selector ?? "body";\n const text = await page.evaluate((currentSelector) => {\n return document.querySelector(currentSelector)?.textContent ?? "";\n }, selector);\n return {\n pageUrl: page.url(),\n traceContext,\n text,\n };\n}\n```\n';const m={name:`custom_script_authoring`,description:`Generate a browse-tool custom tool folder with tools.yaml and TypeScript scripts.`,arguments:[{name:`toolGoal`,description:`What the custom tool should do on the page`,required:!0},{name:`toolName`,description:`Preferred snake_case tool name`,required:!1},{name:`pageContext`,description:`Optional context about the target page or workflow`,required:!1}]},h=new s;function g(e){let t=e.toolName?.trim()||`custom_page_tool`,n=e.pageContext?.trim()||`No extra page context provided.`;return[{role:`user`,content:{type:`text`,text:h.parseAndRenderSync(p,{toolGoal:e.toolGoal,preferredToolName:t,pageContext:n})}}]}export{e as PLAYWRIGHT_TYPES,r as StdioTransportHandler,u as ToolExecutionError,l as UnknownToolError,t as container,n as createContainer,f as createServer,m as customScriptAuthoringPrompt,g as generateCustomScriptAuthoringPrompt};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const e=require(`./stdio-
|
|
1
|
+
const e=require(`./stdio-BwMaaSWk.cjs`);let t=require(`node:module`);const n=Symbol.for(`__locatorProxyBrand__`);var r=class e{[n]=!0;constructor(e,t){this.page=e,this.steps=t}getByRole(t,n){return new e(this.page,[...this.steps,{type:`role`,role:t,options:n}])}getByText(t,n){return new e(this.page,[...this.steps,{type:`text`,text:t,options:n}])}getByLabel(t,n){return new e(this.page,[...this.steps,{type:`label`,text:t,options:n}])}getByPlaceholder(t,n){return new e(this.page,[...this.steps,{type:`placeholder`,text:t,options:n}])}getByTestId(t){return new e(this.page,[...this.steps,{type:`testId`,testId:t}])}locator(t){return new e(this.page,[...this.steps,{type:`css`,selector:t}])}filter(t){return new e(this.page,[...this.steps,{type:`filter`,options:t}])}first(){return new e(this.page,[...this.steps,{type:`first`}])}last(){return this.nth(-1)}nth(t){return new e(this.page,[...this.steps,{type:`nth`,index:t}])}async click(e){let t=await this.resolveAndMark(e?.timeout);await this.page.click(t)}async fill(e,t){let n=await this.resolveAndMark(t?.timeout);await this.page.fill(n,e)}async type(e,t){let n=await this.resolveAndMark(t?.timeout);await this.page.type(n,e,{delay:t?.delay})}async press(e){let t=await this.resolveAndMark();await this.page.click(t),await this.page.press(e)}async hover(e){let t=await this.resolveAndMark(e?.timeout);await this.page.hover(t)}async selectOption(e){let t=await this.resolveAndMark();await this.page.selectOption(t,e)}async check(){let e=await this.resolveAndMark();await this.page.click(e)}async uncheck(){let e=await this.resolveAndMark();await this.page.click(e)}async isVisible(){let e=this.buildResolveScript(`isVisible`);return await this.page.evaluate(e)??!1}async isHidden(){return!await this.isVisible()}async isEnabled(){return!await this.evaluateProperty(`disabled`)}async isDisabled(){return!!await this.evaluateProperty(`disabled`)}async isChecked(){return!!await this.evaluateProperty(`checked`)}async evaluateProperty(e){let t=this.buildResolveScript(`getProperty`,e);return this.page.evaluate(t)}async textContent(){let e=this.buildResolveScript(`textContent`);return this.page.evaluate(e)}async innerText(){let e=this.buildResolveScript(`innerText`);return await this.page.evaluate(e)??``}async inputValue(){let e=this.buildResolveScript(`inputValue`);return await this.page.evaluate(e)??``}async count(){let e=this.buildResolveScript(`count`);return await this.page.evaluate(e)??0}async waitFor(e){let t=e?.timeout??5e3,n=e?.state??`visible`,r=Date.now();for(;Date.now()-r<t;){if(n===`visible`&&await this.isVisible()||n===`hidden`&&!await this.isVisible()||n===`attached`&&await this.count()>0||n===`detached`&&await this.count()===0)return;await new Promise(e=>setTimeout(e,100))}throw Error(`Locator waitFor("${n}") timed out after ${t}ms`)}async resolveAndMark(e){let t=e??5e3,n=Date.now(),r=`pw-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;for(;Date.now()-n<t;){let e=this.buildResolveScript(`mark`,r);if(await this.page.evaluate(e))return`[data-pw-proxy="${r}"]`;await new Promise(e=>setTimeout(e,100))}throw Error(`Locator could not resolve element within ${t}ms. Steps: ${this.describeSteps()}`)}describeSteps(){return this.steps.map(e=>{switch(e.type){case`role`:return`getByRole("${e.role}"${e.options?.name?`, { name: "${String(e.options.name)}" }`:``})`;case`text`:return`getByText("${String(e.text)}")`;case`label`:return`getByLabel("${String(e.text)}")`;case`placeholder`:return`getByPlaceholder("${String(e.text)}")`;case`testId`:return`getByTestId("${e.testId}")`;case`css`:return`locator("${e.selector}")`;case`filter`:return`filter(...)`;case`first`:return`first()`;case`nth`:return`nth(${e.index})`}}).join(`.`)}serializeSteps(){return this.steps.map(e=>{if(e.type===`text`||e.type===`label`||e.type===`placeholder`)return{...e,text:e.text instanceof RegExp?{__regex__:e.text.source,flags:e.text.flags}:e.text};if(e.type===`role`&&e.options?.name instanceof RegExp)return{...e,options:{...e.options,name:{__regex__:e.options.name.source,flags:e.options.name.flags}}};if(e.type===`filter`){let t={};return e.options.hasText&&(t.hasText=e.options.hasText instanceof RegExp?{__regex__:e.options.hasText.source,flags:e.options.hasText.flags}:e.options.hasText),e.options.has&&(t.hasSteps=e.options.has.serializeSteps()),{type:`filter`,options:t}}return e})}buildResolveScript(e,t){return`(function() {
|
|
2
2
|
var steps = ${JSON.stringify(this.serializeSteps())};
|
|
3
3
|
var action = "${e}";
|
|
4
4
|
var extra = ${t===void 0?`null`:JSON.stringify(t)};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));const c=require(`./playwright-test-CWwqqICj.cjs`);require(`reflect-metadata/lite`);let l=require(`@modelcontextprotocol/sdk/server/stdio.js`),u=require(`inversify`),d=require(`node:async_hooks`),f=require(`node:fs`);f=s(f);let p=require(`node:path`);p=s(p);let m=require(`@opentelemetry/api`),h=require(`@opentelemetry/api-logs`),g=require(`@opentelemetry/exporter-logs-otlp-http`),_=require(`@opentelemetry/exporter-trace-otlp-http`),v=require(`@opentelemetry/resources`),y=require(`@opentelemetry/sdk-logs`),b=require(`@opentelemetry/sdk-trace-node`),x=require(`@agimon-ai/foundation-port-registry`),S=require(`node:os`);S=s(S);let C=require(`zod`),w=require(`node:fs/promises`);w=s(w);let T=require(`node:child_process`),ee=require(`node:url`),te=require(`playwright`),ne=require(`node:stream`),re=require(`node:stream/promises`),E=require(`node:crypto`),ie=require(`node:util`),D=require(`zod/v4`);const ae=`ProfileService`,oe=`PageRegistry`,se=`BrowserService`,ce=`ElementLocatorService`,le=`PageMonitorService`,ue=`PauseController`,de=`AutomationRunner`,fe=`SpecRunner`,pe=`SpecBundlerService`,me=`SpecDiscoveryService`,he=`SpecMetadataService`,ge=`SetupRunner`,_e=`WebServerManager`,ve=`Logger`,ye=`TelemetryService`,be=`HttpServerHealthCheck`,xe=`HttpServerManager`,Se=`HttpBrowserClient`,Ce=`RemoteToolExecutor`,we=`ExtensionTaskQueue`,Te=`ExtensionToolDelegator`,Ee=`ToolExecutor`,De=`ExtensionSessionRegistry`,Oe=`ExtensionPageProxy`,ke=`ExtensionSpecRunner`,Ae=`StealthLauncher`,je=`BrowserLockManager`,Me=`McpSessionTracker`,Ne=`ChromeForTestingService`,Pe=`WebSocketHub`,Fe=`IdleCleanupService`,Ie=`PortRegistryService`,Le=`Tool`,O={ProfileService:Symbol.for(`ProfileService`),PageRegistry:Symbol.for(`PageRegistry`),BrowserService:Symbol.for(`BrowserService`),ElementLocatorService:Symbol.for(`ElementLocatorService`),PageMonitorService:Symbol.for(`PageMonitorService`),PauseController:Symbol.for(`PauseController`),AutomationRunner:Symbol.for(`AutomationRunner`),SpecRunner:Symbol.for(`SpecRunner`),SpecBundlerService:Symbol.for(`SpecBundlerService`),SpecDiscoveryService:Symbol.for(`SpecDiscoveryService`),SpecMetadataService:Symbol.for(`SpecMetadataService`),SetupRunner:Symbol.for(`SetupRunner`),WebServerManager:Symbol.for(`WebServerManager`),Logger:Symbol.for(`Logger`),TelemetryService:Symbol.for(`TelemetryService`),HttpServerHealthCheck:Symbol.for(`HttpServerHealthCheck`),HttpServerManager:Symbol.for(`HttpServerManager`),HttpBrowserClient:Symbol.for(`HttpBrowserClient`),RemoteToolExecutor:Symbol.for(`RemoteToolExecutor`),ExtensionTaskQueue:Symbol.for(`ExtensionTaskQueue`),ExtensionToolDelegator:Symbol.for(`ExtensionToolDelegator`),ToolExecutor:Symbol.for(`ToolExecutor`),StealthLauncher:Symbol.for(`StealthLauncher`),BrowserLockManager:Symbol.for(`BrowserLockManager`),ExtensionSessionRegistry:Symbol.for(`ExtensionSessionRegistry`),ExtensionPageProxy:Symbol.for(`ExtensionPageProxy`),ExtensionSpecRunner:Symbol.for(`ExtensionSpecRunner`),McpSessionTracker:Symbol.for(`McpSessionTracker`),ChromeForTestingService:Symbol.for(`ChromeForTestingService`),WebSocketHub:Symbol.for(`WebSocketHub`),IdleCleanupService:Symbol.for(`IdleCleanupService`),PortRegistryService:Symbol.for(`PortRegistryService`),Tool:Symbol.for(`Tool`)};function k(e,t){if(typeof Reflect==`object`&&typeof Reflect.metadata==`function`)return Reflect.metadata(e,t)}function A(e,t,n,r){var i=arguments.length,a=i<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r,o;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)a=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(a=(i<3?o(a):i>3?o(t,n,a):o(t,n))||a);return i>3&&a&&Object.defineProperty(t,n,a),a}const Re=`browse-tool-http`,ze=`log-sink-mcp-http`,Be=[`pnpm-workspace.yaml`,`nx.json`,`.git`],Ve=new Set([`127.0.0.1`,`localhost`,`::1`,`0.0.0.0`]);function He(e){return e===`1`||e===`true`}function Ue(e){return Array.isArray(e)?JSON.stringify(e):typeof e==`string`||typeof e==`number`||typeof e==`boolean`?e:JSON.stringify(e)}function We(e){if(!e)return;let t={};for(let[n,r]of Object.entries(e))r!=null&&(t[n]=Ue(r));return Object.keys(t).length>0?t:void 0}function Ge(e){if(!e)return;let t={};for(let n of e.split(`,`)){let[e,...r]=n.split(`=`),i=e?.trim(),a=r.join(`=`).trim();!i||!a||(t[i]=a)}return Object.keys(t).length>0?t:void 0}function Ke(e){if(!e)return;let t=Number(e);return Number.isFinite(t)&&t>0?t:void 0}function qe(e,t){let n=e.endsWith(`/`)?e:`${e}/`;return n.endsWith(`/v1/${t}/`)||n.endsWith(`/v1/${t}`)?e:new URL(`v1/${t}`,n).toString()}function Je(e){return Ve.has(e)}function Ye(e=process.cwd()){let t=p.default.resolve(e);for(;;){for(let e of Be)if((0,f.existsSync)(p.default.join(t,e)))return t;let e=p.default.dirname(t);if(e===t)return process.cwd();t=e}}function Xe(e,t=process.cwd()){try{let n=(0,f.readFileSync)(x.PortRegistryService.resolveRegistryPath(e.PORT_REGISTRY_PATH??x.DEFAULT_REGISTRY_PATH),`utf8`),r=x.PortRegistryStateSchema.parse(JSON.parse(n)),i=(0,x.normalizeRepositoryPath)(Ye(t)),a=e.NODE_ENV||`development`,o=e.BROWSE_TOOL_OTEL_LOG_SINK_SERVICE_NAME??`log-sink-mcp-http`,s=r.entries.find(e=>e.repositoryPath===i&&e.serviceName===o&&e.serviceType===`tool`&&(e.environment??`development`)===a);if(!s)return;let c=typeof s.metadata?.healthCheckUrl==`string`&&s.metadata.healthCheckUrl.length>0?s.metadata.healthCheckUrl:void 0;return c?new URL(c).origin:`http://${s.host===`0.0.0.0`?`127.0.0.1`:s.host}:${s.port}`}catch{return}}function Ze(e,t){try{let n=new URL(e),r=new URL(t);return!Je(n.hostname)||Je(r.hostname)||(n.hostname=r.hostname),n.toString()}catch{return e}}function Qe(e,t){let n=t===`traces`?e.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT:e.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT;if(n)return n;let r=e.OTEL_EXPORTER_OTLP_ENDPOINT;if(r)return qe(r,t);let i=Xe(e);return i?qe(i,t):void 0}function $e(e,t,n){let r=t===`traces`?e.BROWSE_TOOL_OTEL_BROWSER_TRACES_ENDPOINT:e.BROWSE_TOOL_OTEL_BROWSER_LOGS_ENDPOINT;if(r)return Ze(r,n);let i=e.BROWSE_TOOL_OTEL_BROWSER_ENDPOINT;if(i)return Ze(qe(i,t),n);let a=Qe(e,t);return a?Ze(a,n):void 0}function et(e,t){let n=e.BROWSE_TOOL_OTEL_BROWSER_SERVICE_NAME??`${e.OTEL_SERVICE_NAME??Re}-extension`,r=$e(e,`traces`,t),i=$e(e,`logs`,t);return{enabled:!!(r||i),tracesEndpoint:r,logsEndpoint:i,serviceName:n}}function tt(e,t){let n=t===`traces`?e.OTEL_EXPORTER_OTLP_TRACES_HEADERS:e.OTEL_EXPORTER_OTLP_LOGS_HEADERS,r=t===`traces`?e.OTEL_EXPORTER_OTLP_TRACES_TIMEOUT:e.OTEL_EXPORTER_OTLP_LOGS_TIMEOUT;return{url:Qe(e,t),headers:Ge(n??e.OTEL_EXPORTER_OTLP_HEADERS),timeoutMillis:Ke(r??e.OTEL_EXPORTER_OTLP_TIMEOUT)}}function nt(e){switch(e){case`trace`:return h.SeverityNumber.TRACE;case`debug`:return h.SeverityNumber.DEBUG;case`info`:return h.SeverityNumber.INFO;case`warn`:return h.SeverityNumber.WARN;case`error`:return h.SeverityNumber.ERROR;case`fatal`:return h.SeverityNumber.FATAL}}function rt(e){return e instanceof Error?e.message:String(e)}function it(e){if(e instanceof Error)return We({"exception.type":e.name,"exception.message":e.message,"exception.stacktrace":e.stack})}let j=class{contextStore=new d.AsyncLocalStorage;tracesEnabled;logsEnabled;tracerProvider;loggerProvider;tracer;logger;constructor(e={}){let t=e.env??process.env,n=He(t.OTEL_SDK_DISABLED),r=He(t.BROWSE_TOOL_OTEL_ENABLED),i=tt(t,`traces`),a=tt(t,`logs`);this.tracesEnabled=!n&&(r||!!i.url),this.logsEnabled=!n&&(r||!!a.url);let o=e.serviceName??t.BROWSE_TOOL_OTEL_SERVICE_NAME??t.OTEL_SERVICE_NAME??Re,s=e.serviceVersion??t.npm_package_version,c={"service.name":o};s&&(c[`service.version`]=s);let l=(0,v.resourceFromAttributes)(c);if(this.tracesEnabled){let t=e.traceExporter??new _.OTLPTraceExporter(i);this.tracerProvider=new b.NodeTracerProvider({resource:l,spanProcessors:[e.traceExporter?new b.SimpleSpanProcessor(t):new b.BatchSpanProcessor(t)]})}if(this.logsEnabled){let t=e.logExporter??new g.OTLPLogExporter(a);this.loggerProvider=new y.LoggerProvider({resource:l,processors:[e.logExporter?new y.SimpleLogRecordProcessor(t):new y.BatchLogRecordProcessor(t)]})}this.tracer=this.tracerProvider?.getTracer(o,s)??m.trace.getTracer(o,s),this.logger=this.loggerProvider?.getLogger(o,s)}isEnabled(){return this.tracesEnabled||this.logsEnabled}getActiveTraceContext(){let e=this.contextStore.getStore();if(!e)return{};let t=m.trace.getSpan(e);if(!t)return{};let n=t.spanContext();return{traceId:n.traceId,spanId:n.spanId}}async runInSpan(e,t,n){if(!this.tracesEnabled)return await n(void 0);let r=this.contextStore.getStore()??m.context.active(),i=this.tracer.startSpan(e,{kind:t.kind??m.SpanKind.INTERNAL,attributes:We(t.attributes)},r),a=m.trace.setSpan(r,i);return await this.contextStore.run(a,async()=>{try{return await n(i)}catch(e){throw i.recordException(e instanceof Error?e:Error(rt(e))),i.setStatus({code:m.SpanStatusCode.ERROR,message:rt(e)}),e}finally{i.end()}})}log(e,t,n={}){if(this.logsEnabled)try{let r=n.context??this.contextStore.getStore()??m.context.active(),i=it(n.exception);this.logger?.emit({severityNumber:nt(e),severityText:e.toUpperCase(),body:t,attributes:We({...n.attributes,...i}),context:r,exception:n.exception})}catch{}}async forceFlush(){await Promise.allSettled([this.tracerProvider?.forceFlush(),this.loggerProvider?.forceFlush()])}async shutdown(){await Promise.allSettled([this.tracerProvider?.shutdown(),this.loggerProvider?.shutdown()])}};j=A([(0,u.injectable)(),k(`design:paramtypes`,[Object])],j);const M=18e4;function N(e,t){return function(n,r){t(n,r,e)}}let P=class{pendingTasks=new Map;taskQueue=[];lastPollAt;lastResultAt;maxQueueSize=100;defaultTimeoutMs=M;constructor(e,t=new j){this.webSocketHub=e,this.telemetry=t}async queueTask(e,t,n=this.defaultTimeoutMs,r){if(this.pendingTasks.size>=this.maxQueueSize)throw Error(`Task queue full (max ${this.maxQueueSize} tasks)`);let i=r??t.browserId,a={id:crypto.randomUUID(),tool:e,arguments:t,createdAt:new Date,timeoutMs:n,browserId:i,pageId:typeof t.pageId==`string`?t.pageId:void 0,telemetry:this.getTaskTelemetryContext()};return new Promise((e,t)=>{let r=setTimeout(()=>{this.pendingTasks.delete(a.id);let e=this.taskQueue.findIndex(e=>e.id===a.id);e!==-1&&this.taskQueue.splice(e,1),t(Error(`Task ${a.id} timed out after ${n}ms`))},n);if(this.pendingTasks.set(a.id,{task:a,resolve:e,reject:t,timeoutId:r}),this.webSocketHub){let e=i?this.pushTaskViaWebSocket(a,i):!1;if(e||=this.pushTaskToAnyConnection(a),e)return}this.taskQueue.push(a)})}pushTaskToAnyConnection(e){if(!this.webSocketHub)return!1;let t=this.webSocketHub.getStats();if(t.totalConnections===0)return!1;let n=t.connections[0];return n?this.pushTaskViaWebSocket(e,n.browserId):!1}pushTaskViaWebSocket(e,t){if(!this.webSocketHub)return!1;let n={type:`task:push`,id:crypto.randomUUID(),payload:{taskId:e.id,tool:e.tool,arguments:e.arguments,telemetry:e.telemetry}};return this.webSocketHub.pushTask(t,n)}getNextTask(){return this.lastPollAt=new Date,this.taskQueue.shift()}submitResult(e){this.lastResultAt=new Date;let t=this.pendingTasks.get(e.taskId);if(t)return clearTimeout(t.timeoutId),this.pendingTasks.delete(e.taskId),t.resolve(e),t.task}getConnectionStatus(){let e=new Date,t=this.lastPollAt?e.getTime()-this.lastPollAt.getTime()<5e3:!1,n=this.webSocketHub?this.webSocketHub.getStats().totalConnections>0:!1;return{connected:t||n,lastPollAt:this.lastPollAt,lastResultAt:this.lastResultAt,pendingTasks:this.pendingTasks.size}}clearAllTasks(e){for(let[t,n]of this.pendingTasks)clearTimeout(n.timeoutId),n.reject(Error(e)),this.pendingTasks.delete(t);this.taskQueue.length=0}get queueSize(){return this.taskQueue.length}get pendingCount(){return this.pendingTasks.size}getTaskTelemetryContext(){let e=this.telemetry.getActiveTraceContext();if(!(!e.traceId&&!e.spanId))return{traceId:e.traceId,parentSpanId:e.spanId}}};P=A([(0,u.injectable)(),N(0,(0,u.inject)(O.WebSocketHub)),N(0,(0,u.optional)()),N(1,(0,u.inject)(O.TelemetryService)),N(1,(0,u.optional)()),k(`design:paramtypes`,[Object,Object])],P);const at=new Set(`browser_navigate.browser_go_back.browser_go_forward.browser_reload.browser_click.browser_fill.browser_type.browser_upload_file.browser_select.browser_hover.browser_drag.browser_press_key.browser_pdf.browser_screenshot.browser_snapshot.browser_list_pages.browser_new_page.browser_select_page.browser_close_page.browser_wait_for.browser_evaluate_script.browser_resize_page.browser_handle_dialog.browser_emulate.browser_list_network_requests.browser_get_network_request.browser_list_console_messages.browser_expect`.split(`.`)),ot=new Set([`browser_launch`,`browser_list_profiles`,`browser_create_profile`,`browser_delete_profile`,`browser_save_profile_state`,`browser_start_trace`,`browser_stop_trace`,`run_spec`,`discover_specs`]);let F=class{constructor(e){this.taskQueue=e}isToolSupported(e){return at.has(e)}isToolNotApplicable(e){return ot.has(e)}async executeTool(e,t){if(this.isToolNotApplicable(e))return{content:[{type:`text`,text:`Tool "${e}" is not available in Chrome extension mode. This tool requires Playwright and cannot be run through the extension.`}],isError:!0};if(!this.isToolSupported(e))return{content:[{type:`text`,text:`Tool "${e}" is not yet implemented in Chrome extension mode.`}],isError:!0};if(!this.taskQueue.getConnectionStatus().connected)return{content:[{type:`text`,text:`Chrome extension is not connected. Please ensure the extension is running and connected to the server.`}],isError:!0};try{let n=await this.taskQueue.queueTask(e,t);return n.success?n.result?n.result:{content:[{type:`text`,text:`Tool executed successfully`}]}:{content:[{type:`text`,text:n.error||n.result?.content?.[0]?.text||`Unknown error from Chrome extension`}],isError:!0}}catch(e){return{content:[{type:`text`,text:e instanceof Error?e.message:String(e)}],isError:!0}}}getSupportedTools(){return Array.from(at)}getNotApplicableTools(){return Array.from(ot)}};F=A([(0,u.injectable)(),N(0,(0,u.inject)(O.ExtensionTaskQueue)),k(`design:paramtypes`,[Object])],F);const st={width:1920,height:1080};let ct=class{sessions=new Map;sessionIdCounter=0;constructor(e,t,n,r,i,a){this.browserService=e,this.specRunner=t,this.specMetadataService=n,this.setupRunner=r,this.webServerManager=i,this.pageRegistry=a}async runSpec(e){let{specPath:t,automationId:n,keepBrowserOpen:r=!1,browserOptions:i={},recordVideo:a,browserId:o,pageId:s,windowBounds:c}=e,l=n??`spec-${++this.sessionIdCounter}`,u={id:l,scriptPath:t,status:`pending`,pageIds:[],browserId:null,error:null,createdAt:new Date,updatedAt:new Date};this.sessions.set(l,u);try{let e,n,d,f=!1;if(o&&s){let t=this.pageRegistry.get(s);if(!t)throw Error(`Page with ID ${s} not found`);if(!t.page||!t.context||!t.browser)throw Error(`Page entry is missing required Playwright instances`);e=t.page,n=t.context,d=t.browser,u.browserId=o,u.pageIds.push(s),f=!0}else{let t=await this.browserService.launch({...i,recordVideo:a,onPageClose:e=>{let t=u.pageIds.indexOf(e);t>=0&&u.pageIds.splice(t,1)}});u.browserId=t.browserInstance.id,u.pageIds.push(t.pageId),t.browserInstance.specOrigin=!0;let{context:r,browser:o}=t.browserInstance;if(!r||!o)throw Error(`Browser context or browser is not available`);e=t.page,n=r,d=o}u.status=`running`,u.updatedAt=new Date,c&&await this.applyWindowBounds(d,c);let p=await this.specRunner.executeSpec({specPath:t,sessionId:l,page:e,context:n,browser:d});return u.status=`completed`,u.updatedAt=new Date,!r&&!f&&u.browserId&&u.browserId&&await this.browserService.closeBrowser(u.browserId),{automationId:l,status:`completed`,pageIds:r||f?[...u.pageIds]:[],browserId:r||f?u.browserId:null,specResult:p}}catch(e){u.status=`failed`,u.error=e instanceof Error?e.message:String(e),u.updatedAt=new Date;let t=!!(o&&s);return!r&&!t&&u.browserId&&await this.browserService.closeBrowser(u.browserId),{automationId:l,status:`failed`,pageIds:r||t?[...u.pageIds]:[],browserId:r||t?u.browserId:null}}}async runSpecEnhanced(e){let{specPath:t,automationId:n,keepBrowserOpen:r=!1,browserOptions:i={},recordVideo:a,testFilter:o,specArgs:s,configPath:c,runSetup:l=!1,startServer:u=!1,stopServerAfter:d=!0,browserId:f,pageId:m,windowBounds:h}=e,g=n??`spec-${++this.sessionIdCounter}`,_={id:g,scriptPath:t,status:`pending`,pageIds:[],browserId:null,error:null,createdAt:new Date,updatedAt:new Date};this.sessions.set(g,_);let v,y;try{let e=c?await this.specMetadataService.loadPlaywrightConfig(c):null,n=c?(0,p.dirname)(c):process.cwd();u&&e?.webServer&&(v=await this.webServerManager.startServer(e.webServer,n));let b,x,S,C=!1;if(f&&m){let e=this.pageRegistry.get(m);if(!e)throw Error(`Page with ID ${m} not found`);if(!e.page||!e.context||!e.browser)throw Error(`Page entry is missing required Playwright instances`);b=e.page,x=e.context,S=e.browser,_.browserId=f,_.pageIds.push(m),C=!0}else{let e=await this.browserService.launch({...i,recordVideo:a,onPageClose:e=>{let t=_.pageIds.indexOf(e);t>=0&&_.pageIds.splice(t,1)}});_.browserId=e.browserInstance.id,_.pageIds.push(e.pageId),e.browserInstance.specOrigin=!0;let{context:t,browser:n}=e.browserInstance;if(!t)throw Error(`Browser context is not available`);if(!n)throw Error(`Browser instance is not available`);b=e.page,x=t,S=n}if(_.status=`running`,_.updatedAt=new Date,h&&await this.applyWindowBounds(S,h),l&&e?.setupFile){let t=e.setupFile.startsWith(`/`)?e.setupFile:`${n}/${e.setupFile}`,r=e.setupExport??`default`;if(y=await this.setupRunner.runSetup(t,r,{browser:S,context:x,page:b}),!y.success)throw Error(y.error??`Setup failed`)}let w=await this.specRunner.executeSpecEnhanced({specPath:t,sessionId:g,page:b,context:x,browser:S,testFilter:o,specArgs:{...s,...y?.state}});return _.status=`completed`,_.updatedAt=new Date,d&&v?.started&&await this.webServerManager.stopServer(),!r&&!C&&_.browserId&&await this.browserService.closeBrowser(_.browserId),{automationId:g,status:`completed`,pageIds:r||C?[..._.pageIds]:[],browserId:r||C?_.browserId:null,specResult:w,serverResult:v,setupResult:y}}catch(e){_.status=`failed`,_.error=e instanceof Error?e.message:String(e),_.updatedAt=new Date,d&&v?.started&&await this.webServerManager.stopServer();let t=!!(f&&m);return!r&&!t&&_.browserId&&await this.browserService.closeBrowser(_.browserId),{automationId:g,status:`failed`,pageIds:r||t?[..._.pageIds]:[],browserId:r||t?_.browserId:null,serverResult:v,setupResult:y}}}getSession(e){return this.sessions.get(e)}listSessions(){return Array.from(this.sessions.values())}async stop(e){let t=this.sessions.get(e);return t?(t.browserId&&await this.browserService.closeBrowser(t.browserId),t.status=`completed`,t.updatedAt=new Date,!0):!1}async applyWindowBounds(e,t){let n=this.resolveWindowBounds(t),r=e.contexts();if(r.length===0)return;let i=r[0].pages();if(i.length===0)return;let a;try{a=await i[0].context().newCDPSession(i[0]);let{windowId:e}=await a.send(`Browser.getWindowForTarget`);await a.send(`Browser.setWindowBounds`,{windowId:e,bounds:{left:n.x,top:n.y,width:n.width,height:n.height}})}finally{a&&await a.detach()}}resolveWindowBounds(e){let t=e.screenDimensions??st;if(e.preset){let n=this.calculatePresetBounds(e.preset,t);return{x:e.x??n.x,y:e.y??n.y,width:e.width??n.width,height:e.height??n.height}}return{x:e.x??0,y:e.y??0,width:e.width??t.width,height:e.height??t.height}}calculatePresetBounds(e,t){let n=Math.floor(t.width/2),r=Math.floor(t.height/2);switch(e){case`right-half`:return{x:n,y:0,width:n,height:t.height};case`left-half`:return{x:0,y:0,width:n,height:t.height};case`top-half`:return{x:0,y:0,width:t.width,height:r};case`bottom-half`:return{x:0,y:r,width:t.width,height:r};case`center`:{let e=Math.floor(t.width*.75),n=Math.floor(t.height*.75);return{x:Math.floor((t.width-e)/2),y:Math.floor((t.height-n)/2),width:e,height:n}}case`fullscreen`:return{x:0,y:0,width:t.width,height:t.height};default:return{x:0,y:0,width:t.width,height:t.height}}}};ct=A([(0,u.injectable)(),N(0,(0,u.inject)(O.BrowserService)),N(1,(0,u.inject)(O.SpecRunner)),N(2,(0,u.inject)(O.SpecMetadataService)),N(3,(0,u.inject)(O.SetupRunner)),N(4,(0,u.inject)(O.WebServerManager)),N(5,(0,u.inject)(O.PageRegistry)),k(`design:paramtypes`,[Object,Object,Object,Object,Object,Object])],ct);var lt=class extends Error{constructor(e,t,n){super(e),this.pid=t,this.userDataDir=n,this.name=`BrowserSessionConflictError`}};let ut=class{platform=S.default.platform();async checkLock(e){let t={isLocked:!1};return this.platform===`win32`?this.checkWindowsLock(e,t):this.checkUnixLock(e,t)}async cleanupOrphanedLocks(e){let t=await this.checkLock(e);if(!t.isLocked)return!0;if(t.isProcessAlive)return!1;let n=[p.default.join(e,`SingletonLock`),p.default.join(e,`SingletonCookie`),p.default.join(e,`SingletonSocket`),p.default.join(e,`lockfile`)];for(let e of n)try{f.default.existsSync(e)&&await(0,w.unlink)(e)}catch{}let r=p.default.join(e,`Default`,`LOCK`);try{f.default.existsSync(r)&&await(0,w.unlink)(r)}catch{}return!0}async ensureAvailable(e){if(!f.default.existsSync(e))return;let t=await this.checkLock(e);if(t.isLocked){if(t.isProcessAlive)throw new lt(`Browser session conflict: Another Chrome process (PID: ${t.pid}) is using this profile.\nUser data directory: ${e}\n\nTo resolve:\n1. Close the existing browser session manually\n2. Or use a different profile name\n3. Or kill the process: kill ${t.pid}`,t.pid,e);if(!await this.cleanupOrphanedLocks(e))throw Error(`Failed to clean up orphaned browser lock in ${e}`)}}async checkUnixLock(e,t){let n=p.default.join(e,`SingletonLock`),r=p.default.join(e,`SingletonSocket`);if(t.lockFilePath=n,t.socketPath=r,this.symlinkExists(n))try{let e=f.default.readlinkSync(n).match(/-(\d+)$/);e&&(t.isLocked=!0,t.pid=Number.parseInt(e[1],10),t.isProcessAlive=this.isProcessRunning(t.pid))}catch{t.isLocked=!0,t.isProcessAlive=f.default.existsSync(r)}return!t.isLocked&&f.default.existsSync(r)&&(t.isLocked=!0,t.isProcessAlive=!0),t}symlinkExists(e){try{return f.default.lstatSync(e).isSymbolicLink()}catch{return!1}}async checkWindowsLock(e,t){let n=p.default.join(e,`lockfile`);if(t.lockFilePath=n,f.default.existsSync(n))try{let e=await(0,w.readFile)(n,`utf-8`),r=Number.parseInt(e.trim(),10);Number.isNaN(r)||(t.isLocked=!0,t.pid=r,t.isProcessAlive=this.isProcessRunning(r))}catch{t.isLocked=!0,t.isProcessAlive=!0}return t}isProcessRunning(e){try{return process.kill(e,0),!0}catch(e){return e.code===`EPERM`}}};ut=A([(0,u.injectable)()],ut);var dt=`145.0.7632.117`,ft=`browse-tool/chrome-for-testing:145.0.7632.117`,pt=`/opt/chrome-for-testing/chrome-linux64/chrome`,mt=`linux/amd64`;function ht(){let e=new Map,t=(0,T.execSync)(`ps -axo pid=,ppid=`,{encoding:`utf-8`,stdio:[`ignore`,`pipe`,`ignore`],timeout:3e3});for(let n of t.split(`
|
|
2
|
+
`)){let[t,r]=n.trim().split(/\s+/,2);if(!t||!r)continue;let i=Number(t),a=Number(r);if(Number.isNaN(i)||Number.isNaN(a))continue;let o=e.get(a);o?o.push(i):e.set(a,[i])}return e}function gt(e){let t=[];try{let n;try{n=(0,T.execSync)(`pgrep -P ${e}`,{encoding:`utf-8`,stdio:[`ignore`,`pipe`,`ignore`],timeout:3e3}).trim().split(`
|
|
3
|
+
`).filter(Boolean).map(Number).filter(e=>!Number.isNaN(e))}catch{n=ht().get(e)??[]}for(let e of n)t.push(...gt(e)),t.push(e)}catch{}return t}function _t(e){try{return process.kill(e,0),!0}catch{return!1}}async function vt(e,t=3e3){if(!_t(e))return;let n=[...gt(e),e];for(let e of n)try{process.kill(e,`SIGTERM`)}catch{}let r=Date.now()+t;for(;Date.now()<r;){if(!n.some(_t))return;await new Promise(e=>setTimeout(e,100))}for(let e of n)try{_t(e)&&process.kill(e,`SIGKILL`)}catch{}}function yt(e,t){let n=p.default.join(S.default.tmpdir(),`proxy-auth-ext-${Date.now()}-${Math.random().toString(36).slice(2,8)}`);f.default.mkdirSync(n,{recursive:!0});let r={manifest_version:3,name:`Proxy Auth Helper`,version:`1.0.0`,permissions:[`webRequest`,`webRequestAuthProvider`],host_permissions:[`<all_urls>`],background:{service_worker:`background.js`}},i=[`chrome.webRequest.onAuthRequired.addListener(`,` (details) => ({ authCredentials: { username: ${JSON.stringify(e)}, password: ${JSON.stringify(t)} } }),`,` { urls: ["<all_urls>"] },`,` ["blocking"]`,`);`,``].join(`
|
|
4
|
+
`);return f.default.writeFileSync(p.default.join(n,`manifest.json`),JSON.stringify(r,null,2)),f.default.writeFileSync(p.default.join(n,`background.js`),i),n}function bt(e){let t=[`--proxy-server=${e.server}`];return e.bypass&&t.push(`--proxy-bypass-list=${e.bypass}`),t}var I;const xt=new Set([`docker`,`docker-vm`,`docker-chromium`,`docker-chrome-testing`]),St=ft,Ct=pt,wt=`/vm/extensions/playwright`,Tt=`/vm/user-data`,Et=`2g`,Dt=`1920,1080`,Ot=`1920x1080x24`,kt=5e3,At=5e3,jt=12e3,Mt=8e3,Nt=1500,Pt=100,Ft=32*1024,It=3,Lt=250,Rt=250;let zt=class{static{I=this}static MAX_ACTIVE_BROWSERS=15;static MAX_PAGES_PER_BROWSER=15;static chromeForTestingLaunchQueue=Promise.resolve();browsers=new Map;profileToBrowserId=new Map;browserIdCounter=0;constructor(e,t,n,r,i,a){this.profileService=e,this.pageRegistry=t,this.lockManager=n,this.chromeForTesting=r,this.webSocketHub=i,this.extensionSessionRegistry=a}getBrowserByProfile(e){let t=this.profileToBrowserId.get(e);if(t){let n=this.browsers.get(t);if(n){if(this.isBrowserAlive(n))return n;this.cleanupStaleBrowser(t,e)}else this.profileToBrowserId.delete(e)}}async launch(e={}){let{profileName:t,browserType:n=`chromium`,headless:r=!0,onPageClose:i,baseURL:a,recordVideo:o,proxy:s,browserId:c}=e;if(t){let e=this.getBrowserByProfile(t);if(e){let{pageId:t,page:n}=await this.newPage(e.id,i);return{browserInstance:e,pageId:t,page:n}}}await this.enforceMaxBrowserLimit();let l=c||(t?`browser-${t}`:`browser-${++this.browserIdCounter}`);if(c&&this.browsers.has(c))throw Error(`Browser ID "${c}" is already in use`);let u=this.getBrowserType(n),d=t?await this.profileService.get(t):null;t&&!d&&(d=await this.profileService.create({name:t,browserType:n}));let f=await u.launch({headless:r,...s?{proxy:{server:s.server,username:s.username,password:s.password,bypass:s.bypass}}:{}}),p=this.buildContextOptions(d,a,o);if(d&&t){let e=await this.profileService.loadStorageState(t);e&&(p.storageState=e)}let m=await f.newContext(p),h=await m.newPage(),g=new Date,_={id:l,mode:`playwright`,browser:f,context:m,profileName:t,pageIds:new Set,currentPageId:null,createdAt:g,lastAccessedAt:g};this.browsers.set(l,_),f.on(`disconnected`,()=>{this.cleanupStaleBrowser(l,t)}),t&&this.profileToBrowserId.set(t,l);let v=await this.pageRegistry.register({page:h,browser:f,context:m,browserId:l,profileName:t,onClose:e=>{if(_.pageIds.delete(e),_.currentPageId===e){let e=Array.from(_.pageIds);_.currentPageId=e.length>0?e[0]:null}i?.(e),_.pageIds.size===0&&this.closeBrowser(l).catch(()=>{})}});return _.pageIds.add(v),_.currentPageId=v,{browserInstance:_,pageId:v,page:h}}async launchWithExtension(e={}){let{profileName:t,command:n,commandArgs:r=[],browserId:i,mode:a=`extension`}=e;if(t){let e=this.getBrowserByProfile(t);if(e)if(!this.canReuseExtensionBrowser(e))await this.closeBrowser(e.id).catch(()=>{this.cleanupStaleBrowser(e.id,t)});else{let t=this.getTrackedExtensionPageId(e);return this.recordBrowserActivity(e.id,t),{browserInstance:e,pageId:t,process:{pid:e.pid}}}}await this.enforceMaxBrowserLimit();let o=this.resolveExtensionPath(e.extensionPath),s=p.default.join(o,`manifest.json`);if(!f.default.existsSync(s))throw Error(`Extension manifest not found at ${s}. Please build the extension first: pnpm build:extension`);let c=i||(t?`browser-${t}`:`browser-${++this.browserIdCounter}`);if(i&&this.browsers.has(i))throw Error(`Browser ID "${i}" is already in use`);t&&(await this.profileService.get(t)||await this.profileService.create({name:t,browserType:`chromium`}));let l=this.createUserDataDir(t);l&&await this.lockManager.ensureAvailable(l);let u=await this.resolveVmRuntime({command:n,launchMode:a,useChromeForTesting:e.useChromeForTesting??a===`vm`,extensionHostPath:o,requestedRuntimeExtensionPath:e.extensionPath,userDataDir:l});if(u.kind===`docker`)try{this.ensureDockerWritableUserDataDir(l)}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`Failed to prepare Docker user-data directory "${l}": ${t}`,{cause:e})}let d=[u.extensionPath],m=[];if(u.kind===`docker`&&m.push(...this.createDockerVolumeArgs(o,u.extensionPath,!0)),e.proxy?.username&&e.proxy?.password){let t=yt(e.proxy.username,e.proxy.password);if(u.kind===`docker`){let e=`${u.docker.extensionPathInContainer}-proxy-auth-${Date.now()}`;d.push(e),m.push(...this.createDockerVolumeArgs(t,e,!0))}else d.push(t)}let h=d.join(`,`),g=[`--user-data-dir=${u.userDataDir}`,`--load-extension=${h}`,`--disable-extensions-except=${h}`,`--enable-extensions`,`--disable-blink-features=AutomationControlled`,`--disable-infobars`,`--no-first-run`,`--no-default-browser-check`,`--disable-background-timer-throttling`,`--disable-backgrounding-occluded-windows`,`--disable-renderer-backgrounding`,`--disable-component-update`,`--disable-features=TranslateUI`,`--disable-ipc-flooding-protection`,`--password-store=basic`,`--use-mock-keychain`,`--disable-dev-shm-usage`,...u.kind===`docker`?[`--no-sandbox`]:[],`--window-size=1920,1080`,...e.proxy?bt(e.proxy):[],e.url??`about:blank`],_=e=>{try{let t=new URL(e);return t.protocol===`http:`||t.protocol===`https:`||t.protocol===`file:`}catch{return!1}},v=e=>{if(!_(e))return e;try{let t=new URL(e),n=t.pathname.endsWith(`/`)&&t.pathname!==`/`?t.pathname.slice(0,-1):t.pathname;return`${t.protocol}//${t.host}${n}${t.search}`}catch{return e}},y=v(e.url??`about:blank`),b=a===`vm`&&r.length>0?[...g,...r.filter(e=>_(e)?v(e)!==y:!0)]:r.length>0?r:g,x=u.kind===`docker`?[...this.buildDockerSpawnArgs(u.docker,l,m,e.dockerRunArgs,e.dockerEnv,e.dockerEnableVnc),...b]:b,S,C=0,w;for(let n=1;n<=3;n+=1)try{let n=()=>this.startExtensionBrowser({browserId:c,launchMode:a,profileName:t,vmRuntime:u,spawnArgs:x,startupDelayMs:e.startupDelayMs,launchUrl:e.url});return this.shouldSerializeChromeForTestingLaunch(u)?await this.runSerializedChromeForTestingLaunch(n):await n()}catch(e){if(S=e instanceof Error?e:Error(String(e)),!this.isRetryableExtensionLaunchError(S)||n===3){if(u.kind===`docker`&&(C>0||w)){let e=[C>0?`Docker retry cleanup attempts: ${C}.`:``,w?`Last Docker retry cleanup: ${w}.`:``].filter(Boolean).join(` `);S.message=`${S.message} ${e}`.trim()}throw S}u.kind===`docker`&&(C+=1,w=await this.prepareDockerRetryUserDataDir(l)),await this.delay(250*n)}throw S??Error(`Extension browser launch failed`)}async resolveVmRuntime(e){let{command:t,launchMode:n,useChromeForTesting:r,extensionHostPath:i,requestedRuntimeExtensionPath:a,userDataDir:o}=e;if(n===`vm`&&this.isDockerVmAlias(t)){let e=this.resolveDockerRuntimeExtensionPath(a),t=process.env.PLAYWRIGHT_VM_DOCKER_USER_DATA_DIR||`/vm/user-data`;return{kind:`docker`,command:`docker`,extensionPath:e,userDataDir:t,docker:{image:process.env.PLAYWRIGHT_VM_DOCKER_IMAGE||St,browserBinary:process.env.PLAYWRIGHT_VM_DOCKER_BROWSER_BINARY||Ct,platform:process.env.PLAYWRIGHT_VM_DOCKER_PLATFORM||mt,extensionPathInContainer:e,userDataDirInContainer:t}}}return{kind:`host`,command:await this.resolveLaunchCommand({command:t,launchMode:n,useChromeForTesting:r}),extensionPath:i,userDataDir:o}}resolveDockerRuntimeExtensionPath(e){return e&&!f.default.existsSync(p.default.join(e,`manifest.json`))?e:process.env.PLAYWRIGHT_VM_DOCKER_EXTENSION_PATH||`/vm/extensions/playwright`}createDockerVolumeArgs(e,t,n){return[`-v`,`${p.default.resolve(e)}:${t}${n?`:ro`:``}`]}ensureDockerWritableUserDataDir(e){f.default.mkdirSync(e,{recursive:!0,mode:511});let t=[e];for(;t.length>0;){let e=t.pop();if(!e)continue;f.default.chmodSync(e,511);let n=f.default.readdirSync(e,{withFileTypes:!0});for(let r of n){let n=p.default.join(e,r.name);f.default.chmodSync(n,r.isDirectory()?511:438),r.isDirectory()&&t.push(n)}}}buildDockerSpawnArgs(e,t,n,r,i,a){let o=[`run`,`--rm`,`--init`,`--shm-size`,process.env.PLAYWRIGHT_VM_DOCKER_SHM_SIZE||`2g`];return e.platform&&o.push(`--platform`,e.platform),process.env.PLAYWRIGHT_VM_DOCKER_NETWORK&&o.push(`--network`,process.env.PLAYWRIGHT_VM_DOCKER_NETWORK),process.platform===`linux`&&o.push(`--add-host`,`host.docker.internal:host-gateway`),o.push(...n),o.push(...this.createDockerVolumeArgs(t,e.userDataDirInContainer,!1)),o.push(...this.createDockerEnvArgs(i)),o.push(...this.parseDockerRunArgs(process.env.PLAYWRIGHT_VM_DOCKER_RUN_ARGS)),o.push(...r??[]),a?(o.push(`--entrypoint`,`/bin/bash`,e.image,`-lc`,this.buildDockerVncLaunchScript(e.browserBinary),`_`),o):(o.push(`--entrypoint`,`xvfb-run`,e.image,`-a`,e.browserBinary),o)}buildDockerVncLaunchScript(e){return[`set -euo pipefail`,`Xvfb :99 -screen 0 1920x1080x24 -nolisten tcp >/tmp/xvfb.log 2>&1 &`,`for i in $(seq 1 30); do xdpyinfo -display :99 >/dev/null 2>&1 && break; sleep 0.2; done`,`export DISPLAY=:99`,'if [ -n "${SE_VNC_PASSWORD:-}" ]; then',' x11vnc -storepasswd "${SE_VNC_PASSWORD}" /tmp/vnc-passwd >/dev/null 2>&1',` X11VNC_AUTH="-rfbauth /tmp/vnc-passwd"`,`else`,` X11VNC_AUTH=""`,`fi`,'x11vnc -forever -shared -rfbport "${SE_VNC_PORT:-5900}" -display :99 $X11VNC_AUTH >/tmp/x11vnc.log 2>&1 &',`if command -v websockify >/dev/null 2>&1; then`,' websockify --web /opt/bin/noVNC "${SE_NO_VNC_PORT:-7900}" "localhost:${SE_VNC_PORT:-5900}" >/tmp/novnc.log 2>&1 &',`fi`,`BROWSER_BIN=${JSON.stringify(e)}`,`exec "$BROWSER_BIN" "$@"`].join(`
|
|
5
|
+
`)}createDockerEnvArgs(e){if(!e)return[];let t=[];for(let[n,r]of Object.entries(e))n&&t.push(`-e`,`${n}=${r}`);return t}parseDockerRunArgs(e){return e?e.split(/\s+/).map(e=>e.trim()).filter(e=>e.length>0):[]}isDockerVmAlias(e){if(!e)return!1;let t=e.trim().toLowerCase();return xt.has(t)}async resolveLaunchCommand(e){let{command:t,launchMode:n,useChromeForTesting:r}=e;if(n===`vm`&&r){if(!t)return this.findChromeExecutable();if(this.isChromeTestingAlias(t)||this.isGenericChromeAlias(t))return this.chromeForTesting.getExecutablePath()}return t||this.findChromeExecutable()}isChromeTestingAlias(e){let t=e.trim().toLowerCase();return t===`chrome-testing`||t===`chrome-for-testing`||t===`google-chrome-for-testing`||t.endsWith(`google chrome for testing`)||t.endsWith(`google-chrome-for-testing`)||t.endsWith(`chrome-for-testing.exe`)}isGenericChromeAlias(e){let t=e.trim().toLowerCase(),n=p.default.basename(t);return n===`chrome`||n===`google-chrome`||n===`googlechrome`}resolveExtensionPath(e){if(e&&f.default.existsSync(p.default.join(e,`manifest.json`)))return e;let t=p.default.dirname((0,ee.fileURLToPath)(require(`url`).pathToFileURL(__filename).href)),n=this.findPackageRoot(t),r=[n?p.default.resolve(n,`dist/extension`):``,p.default.resolve(t,`../dist/extension`),p.default.resolve(t,`../../dist/extension`)].filter(Boolean);for(let e of r)if(f.default.existsSync(p.default.join(e,`manifest.json`)))return e;let i=p.default.resolve(process.cwd(),`dist/extension`);if(f.default.existsSync(p.default.join(i,`manifest.json`)))return i;throw Error(`Chrome extension not found. Build the extension first: pnpm build:extension`)}findPackageRoot(e,t=`browse-tool`){let n=e;for(let e=0;e<8;e++){let e=p.default.join(n,`package.json`);if(f.default.existsSync(e))try{if(JSON.parse(f.default.readFileSync(e,`utf8`))?.name===t)return n}catch{}let r=p.default.dirname(n);if(r===n)break;n=r}return null}getExtensionUserDataDir(e){return p.default.join(this.profileService.getProfilesDir(),e,`extension-user-data`)}createUserDataDir(e){if(e){let t=this.getExtensionUserDataDir(e);return f.default.mkdirSync(t,{recursive:!0}),t}let t=p.default.join(S.default.tmpdir(),`extension-chrome-${Date.now()}`);return f.default.mkdirSync(t,{recursive:!0}),t}async findChromeExecutable(){try{return await this.chromeForTesting.getExecutablePath()}catch{}let e=process.platform,t={darwin:[`/Applications/Google Chrome.app/Contents/MacOS/Google Chrome`,`/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary`,`${S.default.homedir()}/Applications/Google Chrome.app/Contents/MacOS/Google Chrome`],linux:[`/usr/bin/google-chrome`,`/usr/bin/google-chrome-stable`,`/usr/bin/chromium`,`/usr/bin/chromium-browser`,`/snap/bin/chromium`],win32:[`${process.env.LOCALAPPDATA}\\Google\\Chrome\\Application\\chrome.exe`,`${process.env.PROGRAMFILES}\\Google\\Chrome\\Application\\chrome.exe`,`${process.env[`PROGRAMFILES(X86)`]}\\Google\\Chrome\\Application\\chrome.exe`]};for(let n of t[e]??[])if(f.default.existsSync(n))return n;throw Error(`Chrome not found. Install Google Chrome or run with Chrome for Testing.`)}async newPage(e,t){let n=this.browsers.get(e);if(!n)throw Error(`Browser "${e}" not found`);if(n.mode===`extension`||n.mode===`vm`)throw Error(`Cannot create new page in extension mode browser. Use extension APIs directly.`);if(!n.context||!n.browser)throw Error(`Browser "${e}" has no Playwright context`);await this.enforceMaxPageLimit(n);let r=await n.context.newPage(),i=await this.pageRegistry.register({page:r,browser:n.browser,context:n.context,browserId:e,profileName:n.profileName,onClose:r=>{if(n.pageIds.delete(r),n.currentPageId===r){let e=Array.from(n.pageIds);n.currentPageId=e.length>0?e[0]:null}t?.(r),n.pageIds.size===0&&this.closeBrowser(e).catch(()=>{})}});return n.pageIds.add(i),{pageId:i,page:r}}getBrowser(e){return this.browsers.get(e)}getDefaultBrowser(){let e=this.listBrowsers();for(let t of e){if(this.isBrowserAlive(t))return t;this.cleanupStaleBrowser(t.id,t.profileName)}}async getOrCreateDefaultBrowser(e){return this.getDefaultBrowser()||(await this.launch(e)).browserInstance}setCurrentPage(e,t){let n=this.browsers.get(e);if(!n)throw Error(`Browser "${e}" not found`);if(!n.pageIds.has(t))throw Error(`Page "${t}" does not belong to browser "${e}"`);n.currentPageId=t}async closeBrowser(e){let t=this.browsers.get(e);if(t){if(t.browser)await t.browser.close();else if(t.context)if(t.pid)try{await vt(t.pid)}catch{try{let e=t.context.pages();await Promise.all(e.map(e=>e.close().catch(e=>{}))),await t.context.close()}catch{}}else{let e=t.context.pages();await Promise.all(e.map(e=>e.close().catch(e=>{}))),await t.context.close()}else if(t.pid)try{await vt(t.pid)}catch{}t.profileName&&this.profileToBrowserId.delete(t.profileName),this.browsers.delete(e)}}async closeAll(){let e=Array.from(this.browsers.keys());await Promise.all(e.map(e=>this.closeBrowser(e).catch(()=>{}))),this.browsers.clear(),this.profileToBrowserId.clear(),this.pageRegistry.clear()}listBrowsers(){return Array.from(this.browsers.values())}touchBrowser(e){let t=this.browsers.get(e);t&&(t.lastAccessedAt=new Date)}recordBrowserActivity(e,t){let n=this.browsers.get(e);return n?(n.lastAccessedAt=new Date,t&&this.pageRegistry.touchPage(t),!0):!1}registerExtensionBrowser(){let e=`browser-${++this.browserIdCounter}`,t=new Date,n={id:e,mode:`extension`,browser:void 0,context:void 0,pageIds:new Set,currentPageId:null,createdAt:t,lastAccessedAt:t};return this.browsers.set(e,n),e}registerExtensionBrowserWithId(e){if(this.browsers.has(e))return;let t=new Date,n={id:e,mode:`extension`,browser:void 0,context:void 0,pageIds:new Set,currentPageId:null,createdAt:t,lastAccessedAt:t};this.browsers.set(e,n)}async enforceMaxPageLimit(e){if(e.pageIds.size<I.MAX_PAGES_PER_BROWSER)return;let t=this.pageRegistry.findByBrowser(e.id);t.sort((e,t)=>e.createdAt.getTime()-t.createdAt.getTime());let n=t[0];n&&(n.page?await n.page.close():(this.pageRegistry.remove(n.id),e.pageIds.delete(n.id)))}async enforceMaxBrowserLimit(){if(this.browsers.size>=I.MAX_ACTIVE_BROWSERS){let e=Array.from(this.browsers.values());e.sort((e,t)=>e.createdAt.getTime()-t.createdAt.getTime());let t=e[0];t&&await this.closeBrowser(t.id)}}isBrowserAlive(e){try{if(e.mode===`playwright`)return e.browser?.isConnected()??!1;if(e.mode===`extension`||e.mode===`vm`){if(!e.pid||!this.isProcessRunning(e.pid))return!1;if(!e.context)return!0;try{return e.context.pages(),!0}catch{return!1}}return!1}catch{return!1}}isProcessRunning(e){try{return process.kill(e,0),!0}catch(e){return e.code===`EPERM`}}captureProcessOutput(){let e=[],t=0,n=(n,r)=>{if(typeof r!=`string`&&!Buffer.isBuffer(r))return;let i=typeof r==`string`?r:r.toString(`utf8`);if(!i)return;let a=32768-t;if(a<=0)return;let o=Buffer.from(i,`utf8`).subarray(0,a).toString(`utf8`);t+=Buffer.byteLength(o,`utf8`),e.push(`[${n}] ${o}`)};return{attach:e=>{e.stdout?.on(`data`,e=>n(`stdout`,e)),e.stderr?.on(`data`,e=>n(`stderr`,e))},snapshot:()=>e.join(``)}}async startExtensionBrowser(e){let{browserId:t,launchMode:n,profileName:r,vmRuntime:i,spawnArgs:a,startupDelayMs:o,launchUrl:s}=e,c=this.captureProcessOutput(),l=(0,T.spawn)(i.command,a,{detached:!1,stdio:[`ignore`,`pipe`,`pipe`],env:i.kind===`docker`?process.env:{...process.env,DISPLAY:process.env.DISPLAY}});if(!l.pid)throw Error(`Failed to start Chrome process`);c.attach(l);let u=new Date,d={id:t,mode:n,browser:void 0,context:void 0,profileName:r,pageIds:new Set,currentPageId:null,pid:l.pid,createdAt:u,lastAccessedAt:u};l.on(`exit`,()=>this.cleanupStaleBrowser(t,r)),l.on(`error`,()=>this.cleanupStaleBrowser(t,r)),this.browsers.set(t,d),r&&this.profileToBrowserId.set(r,t);let f=this.pageRegistry.registerExtensionPage(t);d.pageIds.add(f),d.currentPageId=f;try{await this.waitForExtensionReady(t,l,c,{vmRuntimeKind:i.kind,launchUrl:s})}catch(e){throw await this.closeBrowser(t).catch(()=>{}),e}return o&&o>0&&await this.delay(o),{browserInstance:d,pageId:f,process:l}}async waitForExtensionReady(e,t,n,r){if(!this.webSocketHub&&!this.extensionSessionRegistry)return;let i=null,a=null,o;t.once(`exit`,(e,t)=>{i=e,a=t}),t.once(`error`,e=>{o=e});let s=null,c=!1,l=0,u=0,d=null,f=!1,p=Date.now(),m=this.getExtensionStartupTimeoutMs(r.vmRuntimeKind),h=this.getExtensionStartupGraceTimeoutMs(r.vmRuntimeKind),g=this.getExtensionReadyStabilityMs(),_=this.getExtensionStartupPollIntervalMs(),v=p+m;for(;;){let t=Date.now();if(t>=v){if(!f&&o===void 0&&i===null&&a===null){f=!0,v=t+h;continue}break}if(this.hasExtensionConnection(e)){if(c=!0,s??=t,d??=t,u=Math.max(u,t-s),t-s>=g)return}else s!==null&&(l+=1,u=Math.max(u,t-s)),s=null;if(o||i!==null||a!==null)break;await new Promise(e=>setTimeout(e,_))}if(this.hasExtensionConnection(e)&&s!==null&&Date.now()-s>=g)return;let y=n.snapshot(),b=this.writeLaunchFailureLog(e,y),x=[`Chrome extension browser "${e}" failed to become ready within ${m+(f?h:0)}ms.`,`Ready state requires a stable session for ${g}ms.`,`Observed connection: ${c?`yes`:`no`}.`,c&&d!==null?`First connection observed after ${Math.max(0,d-p)}ms.`:void 0,`Longest stable connection: ${u}ms.`,l>0?`Connection flaps: ${l}.`:void 0,f?`Startup grace applied: ${h}ms.`:void 0,r.launchUrl?`Launch URL: ${r.launchUrl}.`:void 0,o?`Error: ${o.message}`:void 0,i===null?void 0:`Exit code: ${i}`,a?`Signal: ${a}`:void 0,b?`Launch log: ${b}`:void 0].filter(Boolean).join(` `);throw Error(x)}getExtensionStartupTimeoutMs(e){return e===`docker`?12e3:5e3}getExtensionStartupGraceTimeoutMs(e){return e===`docker`?8e3:5e3}getExtensionReadyStabilityMs(){return 1500}getExtensionStartupPollIntervalMs(){return 100}isRetryableExtensionLaunchError(e){return/failed to become ready/i.test(e.message)||/Failed to start Chrome process/i.test(e.message)}shouldSerializeChromeForTestingLaunch(e){return process.platform===`darwin`&&e.kind===`host`&&this.isChromeTestingAlias(e.command)}async runSerializedChromeForTestingLaunch(e){let t,n=I.chromeForTestingLaunchQueue;I.chromeForTestingLaunchQueue=new Promise(e=>{t=e}),await n;try{return await e()}finally{t?.()}}async delay(e){await new Promise(t=>setTimeout(t,e))}hasExtensionConnection(e){return this.extensionSessionRegistry?!!this.extensionSessionRegistry.getSessionByBrowserId(e):!!this.webSocketHub?.hasConnection(e)}canReuseExtensionBrowser(e){return e.mode!==`extension`&&e.mode!==`vm`||!e.pid?!1:this.isProcessRunning(e.pid)&&this.hasExtensionConnection(e.id)}getTrackedExtensionPageId(e){let t=e.currentPageId&&this.pageRegistry.get(e.currentPageId)?e.currentPageId:Array.from(e.pageIds).find(e=>this.pageRegistry.get(e));if(t)return e.currentPageId=t,t;let n=this.pageRegistry.registerExtensionPage(e.id);return e.pageIds.add(n),e.currentPageId=n,n}writeLaunchFailureLog(e,t){if(t.trim())try{let n=p.default.join(S.default.tmpdir(),`${e}-launch.log`);return f.default.writeFileSync(n,t,`utf8`),n}catch{return}}async prepareDockerRetryUserDataDir(e){await this.delay(250);try{let t=await this.lockManager.cleanupOrphanedLocks(e);return this.cleanupExtensionSingletonArtifacts(e),`${t?`cleaned`:`checked`} ${e}`}catch(t){let n=t instanceof Error?t.message:String(t);return this.cleanupExtensionSingletonArtifacts(e),`lock-manager cleanup failed (${n}); singleton artifacts removed directly from ${e}`}}cleanupExtensionSingletonArtifacts(e){let t=[p.default.join(e,`SingletonLock`),p.default.join(e,`SingletonCookie`),p.default.join(e,`SingletonSocket`),p.default.join(e,`lockfile`),p.default.join(e,`Default`,`LOCK`)];for(let e of t)try{f.default.rmSync(e,{force:!0})}catch{}}cleanupStaleBrowser(e,t){if(t){let e=this.getExtensionUserDataDir(t);this.cleanupExtensionSingletonArtifacts(e),this.lockManager.cleanupOrphanedLocks(e).catch(()=>{})}this.browsers.delete(e),t&&this.profileToBrowserId.delete(t)}getBrowserType(e){switch(e){case`chromium`:return te.chromium;case`firefox`:return te.firefox;case`webkit`:return te.webkit}}buildContextOptions(e,t,n){let r={};return t&&(r.baseURL=t),n&&(r.recordVideo=n),e?(e.viewport&&(r.viewport=e.viewport),e.userAgent&&(r.userAgent=e.userAgent),e.locale&&(r.locale=e.locale),e.timezone&&(r.timezoneId=e.timezone),e.geolocation&&(r.geolocation=e.geolocation),e.permissions&&(r.permissions=e.permissions),e.colorScheme&&(r.colorScheme=e.colorScheme),r):r}};zt=I=A([(0,u.injectable)(),N(0,(0,u.inject)(O.ProfileService)),N(1,(0,u.inject)(O.PageRegistry)),N(2,(0,u.inject)(O.BrowserLockManager)),N(3,(0,u.inject)(O.ChromeForTestingService)),N(4,(0,u.inject)(O.WebSocketHub)),N(4,(0,u.optional)()),N(5,(0,u.inject)(O.ExtensionSessionRegistry)),N(5,(0,u.optional)()),k(`design:paramtypes`,[Object,Object,Object,Object,Object,Object])],zt);var Bt;const Vt=dt;let Ht=class{static{Bt=this}static API_URL=`https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json`;cacheDir;constructor(){this.cacheDir=(0,p.join)((0,S.homedir)(),`.cache`,`chrome-for-testing`)}async getExecutablePath(){let e=this.getExpectedExecutablePath(),t=await this.getInstalledVersion();try{let n=await this.fetchVersionInfo();return(0,f.existsSync)(e)&&t===n.version?e:this.download(n)}catch(t){if((0,f.existsSync)(e))return e;throw t}}async isInstalled(){return(0,f.existsSync)(this.getExpectedExecutablePath())}async getInstalledVersion(){let e=(0,p.join)(this.cacheDir,`version.txt`);if(!(0,f.existsSync)(e))return null;try{return(await(0,w.readFile)(e,`utf-8`)).trim()}catch{return null}}async update(){let e=(0,p.join)(this.cacheDir,`chrome`);return(0,f.existsSync)(e)&&await(0,w.rm)(e,{recursive:!0,force:!0}),this.download(await this.fetchVersionInfo())}async download(e){(0,f.mkdirSync)(this.cacheDir,{recursive:!0});let t=this.getDownloadUrl(e);if(!t)throw Error(`No Chrome for Testing download available for ${this.getPlatformKey()}`);let n=(0,p.join)(this.cacheDir,`chrome.zip`),r=(0,p.join)(this.cacheDir,`chrome`);await this.downloadFile(t,n),await this.extractZip(n,r),await(0,w.rm)(n,{force:!0}),await(0,w.writeFile)((0,p.join)(this.cacheDir,`version.txt`),e.version,`utf-8`);let i=this.getExpectedExecutablePath();if(!(0,f.existsSync)(i))throw Error(`Chrome for Testing executable not found at expected path: ${i}`);return(0,S.platform)()!==`win32`&&await(0,w.chmod)(i,493),i}async fetchVersionInfo(){let e=await fetch(Bt.API_URL);if(!e.ok)throw Error(`Failed to fetch Chrome for Testing info: ${e.statusText}`);let t=(await e.json()).versions.find(e=>e.version===Vt);if(!t)throw Error(`Pinned Chrome for Testing version ${Vt} not found in feed`);return t}getDownloadUrl(e){let t=this.getPlatformKey();return e.downloads.chrome.find(e=>e.platform===t)?.url}getPlatformKey(){let e=(0,S.platform)(),t=(0,S.arch)();if(e===`darwin`)return t===`arm64`?`mac-arm64`:`mac-x64`;if(e===`linux`)return`linux64`;if(e===`win32`)return t===`x64`?`win64`:`win32`;throw Error(`Unsupported platform: ${e}`)}getExpectedExecutablePath(){let e=(0,S.platform)(),t=(0,p.join)(this.cacheDir,`chrome`);if(e===`darwin`)return(0,p.join)(t,`chrome-mac-${(0,S.arch)()===`arm64`?`arm64`:`x64`}`,`Google Chrome for Testing.app`,`Contents`,`MacOS`,`Google Chrome for Testing`);if(e===`linux`)return(0,p.join)(t,`chrome-linux64`,`chrome`);if(e===`win32`)return(0,p.join)(t,`chrome-win${(0,S.arch)()===`x64`?`64`:`32`}`,`chrome.exe`);throw Error(`Unsupported platform: ${e}`)}async downloadFile(e,t){let n=await fetch(e);if(!n.ok||!n.body)throw Error(`Failed to download: ${n.statusText}`);let r=`${t}.tmp`,i=(0,f.createWriteStream)(r),a=n.body.getReader();await(0,re.pipeline)(new ne.Readable({async read(){let{done:e,value:t}=await a.read();e?this.push(null):this.push(Buffer.from(t))}}),i),await(0,w.rename)(r,t)}async extractZip(e,t){let n=(0,S.platform)();return new Promise((r,i)=>{let a;n===`win32`?a=(0,T.spawn)(`powershell`,[`-NoProfile`,`-Command`,`Expand-Archive -Path "${e}" -DestinationPath "${t}" -Force`]):((0,f.mkdirSync)(t,{recursive:!0}),a=(0,T.spawn)(`unzip`,[`-o`,`-q`,e,`-d`,t])),a.on(`close`,e=>{e===0?r():i(Error(`Failed to extract zip (exit code: ${e})`))}),a.on(`error`,e=>{i(Error(`Failed to spawn extraction process: ${e.message}`))})})}};Ht=Bt=A([(0,u.injectable)(),k(`design:paramtypes`,[])],Ht);let Ut=class{async locate(e,t){let n=await this.getFrameContext(e,t.frame),r=this.buildLocator(n,t);if(await r.count()===0)throw Error(`Element not found: ${this.describeSelector(t)}`);return r.first()}async locateAll(e,t){let n=await this.getFrameContext(e,t.frame);return this.buildLocator(n,t)}async waitForElement(e,t,n={}){let r=await this.getFrameContext(e,t.frame),i=this.buildLocator(r,t);return await i.waitFor({timeout:n.timeout??M,state:n.state??`visible`}),i.first()}async getFrameContext(e,t){return t?e.frameLocator(t):e}buildLocator(e,t){if(t.uid)return e.locator(`[data-uid="${t.uid}"]`);if(t.xpath)return e.locator(`xpath=${t.xpath}`);if(t.text)return e.locator(`text=${t.text}`);if(t.selector)return e.locator(t.selector);throw Error(`No selector provided. Specify one of: selector, xpath, text, or uid.`)}describeSelector(e){let t=[];return e.uid&&t.push(`uid="${e.uid}"`),e.selector&&t.push(`selector="${e.selector}"`),e.xpath&&t.push(`xpath="${e.xpath}"`),e.text&&t.push(`text="${e.text}"`),e.frame&&t.push(`frame="${e.frame}"`),t.length>0?t.join(`, `):`empty selector`}};Ut=A([(0,u.injectable)()],Ut);const Wt=process.env.BROWSE_TOOL_DEBUG_CUSTOM_TOOLS===`1`;function Gt(e){return JSON.stringify(e,(e,t)=>typeof t==`string`&&t.length>240?`${t.slice(0,240)}...<trimmed>`:t)}function L(e,t){if(Wt){if(t){console.error(`[ExtensionPageProxy] ${e}`,t);return}console.error(`[ExtensionPageProxy] ${e}`)}}function R(e){return typeof e==`object`&&e&&`value`in e?e.value:e}let z=class{[c.s]=!0;currentUrl=`about:blank`;defaultTimeoutMs=M;_pageId;_browserId;constructor(e){this.taskQueue=e}setTarget(e,t){this._pageId=e,this._browserId=t}get pageId(){return this._pageId}get browserId(){return this._browserId}async goto(e,t){let n=await this.executeTask(`browser_navigate`,{url:e,waitUntil:t?.waitUntil,timeout:t?.timeout});if(!n.success)throw Error(n.error??`Navigation failed`);this.currentUrl=e}async click(e,t){let n=await this.executeTask(`browser_click`,{selector:e,clickCount:t?.clickCount,delay:t?.delay,button:t?.button,modifiers:t?.modifiers});if(!n.success)throw Error(n.error??`Click failed on ${e}`)}async fill(e,t,n){let r=await this.executeTask(`browser_fill`,{selector:e,text:t,force:n?.force});if(!r.success)throw Error(r.error??`Fill failed on ${e}`)}async type(e,t,n){let r=await this.executeTask(`browser_type`,{selector:e,text:t,delay:n?.delay});if(!r.success)throw Error(r.error??`Type failed on ${e}`)}async press(e){let t=await this.executeTask(`browser_press_key`,{key:e});if(!t.success)throw Error(t.error??`Press key failed: ${e}`)}async hover(e){let t=await this.executeTask(`browser_hover`,{selector:e});if(!t.success)throw Error(t.error??`Hover failed on ${e}`)}async selectOption(e,t){let n=await this.executeTask(`browser_select`,{selector:e,values:Array.isArray(t)?t:[t]});if(!n.success)throw Error(n.error??`Select option failed on ${e}`)}async waitForSelector(e,t){let n=await this.executeTask(`browser_wait_for`,{selector:e,state:t?.state??`visible`,timeout:t?.timeout});if(!n.success)throw Error(n.error??`Wait for selector failed: ${e}`)}async waitForTimeout(e){let t=await this.executeTask(`browser_wait_for`,{timeout:e});if(!t.success)throw Error(t.error??`Wait for timeout failed`)}async screenshot(e){let t=await this.executeTask(`browser_screenshot`,{path:e?.path,fullPage:e?.fullPage,type:e?.type});if(!t.success)throw Error(t.error??`Screenshot failed`);return t.result?.path??``}async content(){let e=await this.executeTask(`browser_evaluate_script`,{script:`document.documentElement.outerHTML`});if(!e.success)throw Error(e.error??`Get content failed`);return R(e.result)??``}async title(){let e=await this.executeTask(`browser_evaluate_script`,{script:`document.title`});if(!e.success)throw Error(e.error??`Get title failed`);return R(e.result)??``}url(){return this.currentUrl}async evaluate(e,...t){let n=typeof e==`function`?`(${e.toString()})(${t.map(e=>JSON.stringify(e)).join(`,`)})`:e,r=await this.executeTask(`browser_evaluate_script`,{script:n});if(!r.success)throw Error(r.error??`Evaluate failed`);return R(r.result)}async getSnapshot(){let e=await this.executeTask(`browser_snapshot`,{});if(!e.success)throw Error(e.error??`Get snapshot failed`);let t=R(e.result);return typeof t==`string`?t:t==null?``:JSON.stringify(t,null,2)}getByRole(e,t){return new c.c(this,[{type:`role`,role:e,options:t}])}getByText(e,t){return new c.c(this,[{type:`text`,text:e,options:t}])}getByLabel(e,t){return new c.c(this,[{type:`label`,text:e,options:t}])}getByPlaceholder(e,t){return new c.c(this,[{type:`placeholder`,text:e,options:t}])}getByTestId(e){return new c.c(this,[{type:`testId`,testId:e}])}locator(e){return new c.c(this,[{type:`css`,selector:e}])}context(){return{clearCookies:async()=>{await this.clearStorageState()}}}async reload(e){let t=await this.executeTask(`browser_reload`,{waitUntil:e?.waitUntil,timeout:e?.timeout});if(!t.success)throw Error(t.error??`Reload failed`)}async currentUrlAsync(){let e=await this.evaluate(`window.location.href`);return e&&(this.currentUrl=e),this.currentUrl}async waitForResponse(e,t){let n=typeof e==`string`?{url:e}:e instanceof RegExp?{urlPattern:{source:e.source,flags:e.flags}}:null;if(!n)throw Error(`Extension mode only supports waitForResponse with a string or RegExp target`);let r=await this.executeTask(`browser_wait_for_response`,{...n,timeout:t?.timeout??this.defaultTimeoutMs});if(!r.success)throw Error(r.error??`Wait for response failed`)}async getStorageState(){let e=await this.executeTask(`browser_get_storage_state`,{});if(!e.success)throw Error(e.error??`Get storage state failed`);return e.result??{}}async clearStorageState(){let e=await this.executeTask(`browser_clear_storage_state`,{});if(!e.success)throw Error(e.error??`Clear storage state failed`)}async startRecording(){let e=await this.executeTask(`browser_start_recording`,{});if(!e.success)throw Error(e.error??`Start recording failed`)}async stopRecording(){let e=await this.executeTask(`browser_stop_recording`,{});if(!e.success)throw Error(e.error??`Stop recording failed`);return e.result?.videoBase64??``}async executeTask(e,t){if(!this._pageId||!this._browserId)return{success:!1,error:`Extension page proxy target is not initialized`};let n={...t,pageId:this._pageId};L(`Queueing extension task`,{tool:e,browserId:this._browserId,pageId:this._pageId,args:Gt(n)});let r;try{r=await this.taskQueue.queueTask(e,n,this.defaultTimeoutMs,this._browserId)}catch(t){let n=t instanceof Error?t.message:String(t);return L(`Extension task threw before result`,{tool:e,browserId:this._browserId,pageId:this._pageId,error:n}),{success:!1,error:`Extension task "${e}" threw for page "${this._pageId}" in browser "${this._browserId}": ${n}`}}if(!r.success)return L(`Extension task returned unsuccessful result`,{tool:e,browserId:this._browserId,pageId:this._pageId,taskError:r.error??`Task failed`,taskResult:r}),{success:!1,error:r.error??`Extension task "${e}" failed for page "${this._pageId}" in browser "${this._browserId}"`};let i=r.result?.content?.[0];if(i?.type===`text`&&i.text)try{let t=JSON.parse(i.text);return L(`Extension task completed with JSON text result`,{tool:e,browserId:this._browserId,pageId:this._pageId}),{success:!0,result:t}}catch{return L(`Extension task completed with plain text result`,{tool:e,browserId:this._browserId,pageId:this._pageId,textPreview:i.text.slice(0,240)}),{success:!0,result:{value:i.text}}}return L(`Extension task completed with non-text result payload`,{tool:e,browserId:this._browserId,pageId:this._pageId,taskResult:r}),{success:!0,result:r.result}}};z=A([(0,u.injectable)(),N(0,(0,u.inject)(O.ExtensionTaskQueue)),k(`design:paramtypes`,[Object])],z);let Kt=class{sessions=new Map;browserIdToSessionId=new Map;sessionIdCounter=0;defaultStaleThresholdMs=6e4;register(e){let t=this.browserIdToSessionId.get(e.browserId);t&&(this.sessions.delete(t),this.browserIdToSessionId.delete(e.browserId));let n=`session-${++this.sessionIdCounter}-${Date.now()}`,r=new Date,i={id:n,browserId:e.browserId,tabId:e.tabId,currentUrl:e.url,createdAt:r,lastHeartbeatAt:r,controlMode:`manual`,handoffRequested:!1,metadata:e.metadata};return this.sessions.set(n,i),this.browserIdToSessionId.set(e.browserId,n),i}heartbeat(e){let t=this.sessions.get(e.sessionId);if(t)return t.lastHeartbeatAt=new Date,e.tabId!==void 0&&(t.tabId=e.tabId),e.url!==void 0&&(t.currentUrl=e.url),e.state&&(t.metadata={...t.metadata,...e.state}),t}requestHandoff(e){let t=this.sessions.get(e.sessionId);if(t)return t.handoffRequested=!0,e.pageState&&(t.currentUrl=e.pageState.url,t.metadata={...t.metadata,handoffReason:e.reason,handoffPageState:e.pageState}),t}acknowledgeHandoff(e){let t=this.sessions.get(e);if(!(!t||!t.handoffRequested))return t.handoffRequested=!1,t.controlMode=`ai`,t.activeSpecPath=void 0,t}getSession(e){return this.sessions.get(e)}getSessionByBrowserId(e){let t=this.browserIdToSessionId.get(e);if(t)return this.sessions.get(t)}listSessions(){return Array.from(this.sessions.values())}removeSession(e){let t=this.sessions.get(e);return t?(this.browserIdToSessionId.delete(t.browserId),this.sessions.delete(e),!0):!1}setControlMode(e,t){let n=this.sessions.get(e);if(n)return n.controlMode=t,n}setActiveSpec(e,t){let n=this.sessions.get(e);if(n)return n.activeSpecPath=t,t&&(n.controlMode=`spec`),n}cleanupStaleSessions(e=this.defaultStaleThresholdMs){let t=Date.now(),n=0;for(let[r,i]of this.sessions)t-i.lastHeartbeatAt.getTime()>e&&(this.browserIdToSessionId.delete(i.browserId),this.sessions.delete(r),n++);return n}};Kt=A([(0,u.injectable)()],Kt);let qt=class{constructor(e,t,n){this.bundler=e,this.pageProxy=t,this.sessionRegistry=n}async loadSpec(e){let t=await this.bundler.bundle(e);try{c.r(e);let n=process,r=n.__pw_initiator__;return n.__pw_initiator__=void 0,await import(`${t.outputPath}?t=${Date.now()}`),n.__pw_initiator__=r,c.n()}catch(t){throw c.a(),Error(`Failed to load spec "${e}": ${t instanceof Error?t.message:String(t)}`,{cause:t})}finally{await t.cleanup()}}async executeSpec(e){let{specPath:t,sessionId:n,testFilter:r,specArgs:i,onHandoff:a}=e,o=Date.now(),s=[],c=0,l=0,u=!1;this.sessionRegistry.setActiveSpec(n,t);try{let e=await this.loadSpec(t),d=r?this.filterTests(e.allTests,r):e.allTests,f={page:this.pageProxy,requestHandoff:async e=>{if(!this.sessionRegistry.getSession(n))throw Error(`Session ${n} not found`);let t=await this.pageProxy.getSnapshot(),r=this.pageProxy.url();this.sessionRegistry.requestHandoff({sessionId:n,reason:e,pageState:{url:r,snapshot:t}}),u=!0,a&&await a(n)},specArgs:i};for(let e of d){if(e.skip){s.push({title:e.title,fullTitle:e.fullTitle,passed:!0,error:null,duration:0}),c++;continue}let t=this.sessionRegistry.getSession(n);if(t?.handoffRequested)break;let r=Date.now();try{await e.fn(f),s.push({title:e.title,fullTitle:e.fullTitle,passed:!0,error:null,duration:Date.now()-r,handoffTriggered:t?.handoffRequested}),c++}catch(t){let n=t instanceof Error?t.message:String(t);s.push({title:e.title,fullTitle:e.fullTitle,passed:!1,error:n,duration:Date.now()-r}),l++}}return{specPath:t,totalTests:d.length,passed:c,failed:l,testResults:s,success:l===0,duration:Date.now()-o,handoffOccurred:u,sessionId:n}}catch(e){return{specPath:t,totalTests:0,passed:0,failed:1,testResults:[{title:`Spec Loading`,fullTitle:`Failed to load: ${t}`,passed:!1,error:e instanceof Error?e.message:String(e),duration:Date.now()-o}],success:!1,duration:Date.now()-o,handoffOccurred:!1,sessionId:n}}finally{this.sessionRegistry.setActiveSpec(n,void 0)}}filterTests(e,t){let n=[...e];if(t.onlyMarked){let e=n.filter(e=>e.only);e.length>0&&(n=e)}if(t.testName&&(n=n.filter(e=>e.title===t.testName)),t.testPattern){let e=new RegExp(t.testPattern,`i`);n=n.filter(t=>e.test(t.fullTitle))}if(t.describeFilter){let e=new RegExp(t.describeFilter,`i`);n=n.filter(t=>e.test(t.fullTitle))}return n}};qt=A([(0,u.injectable)(),N(0,(0,u.inject)(O.SpecBundlerService)),N(1,(0,u.inject)(O.ExtensionPageProxy)),N(2,(0,u.inject)(O.ExtensionSessionRegistry)),k(`design:paramtypes`,[Object,Object,Object])],qt);const Jt=`localhost`,Yt=3200,Xt=`PLAYWRIGHT_HOST`,Zt=`PLAYWRIGHT_PORT`;function B(){return process.env.PLAYWRIGHT_HOST?.trim()||`localhost`}function Qt(){let e=process.env[Zt];if(!e)return Yt;let t=Number.parseInt(e,10);if(Number.isNaN(t)||t<=0||t>65535)throw Error(`Invalid ${Zt} value: ${e}`);return t}function V(e=void 0,t){return`http://${typeof e==`string`?e:e?.host??B()}:${e&&typeof e!=`string`?e.port:t??Qt()}`}let $t=class{baseUrl;defaultTimeout=M;constructor(){this.baseUrl=V()}setBaseUrl(e){this.baseUrl=e}getBaseUrl(){return this.baseUrl}async execute(e,t={}){let n=`${this.baseUrl}/execute`,r=new AbortController,i=setTimeout(()=>r.abort(),this.defaultTimeout);try{let a={tool:e,arguments:t},o=await fetch(n,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(a),signal:r.signal});if(clearTimeout(i),!o.ok){let e=await o.text();return{content:[{type:`text`,text:`HTTP error ${o.status}: ${e}`}],isError:!0}}let s=await o.json();return s.success?s.result||{content:[{type:`text`,text:`No result returned`}]}:{content:[{type:`text`,text:s.error||s.result?.content?.[0]?.text||`Unknown error`}],isError:!0}}catch(e){return clearTimeout(i),e instanceof Error&&e.name===`AbortError`?{content:[{type:`text`,text:`Request timed out after ${this.defaultTimeout}ms`}],isError:!0}:{content:[{type:`text`,text:e instanceof Error?e.message:String(e)}],isError:!0}}}async isHealthy(){try{let e=await fetch(`${this.baseUrl}/health`,{headers:{"Content-Type":`application/json`}});return e.ok?(await e.json()).status===`healthy`:!1}catch{return!1}}};$t=A([(0,u.injectable)(),k(`design:paramtypes`,[])],$t);let H=class{defaultTimeout=5e3;async check(e,t=this.defaultTimeout){try{let n=`${V(B(),e)}/health`,r=new AbortController,i=setTimeout(()=>r.abort(),t);try{let t=await fetch(n,{signal:r.signal,headers:{"Content-Type":`application/json`}});if(clearTimeout(i),!t.ok)return{healthy:!1,error:`HTTP error ${t.status}: ${t.statusText}`};let a=await t.json();return a.status===`healthy`?{healthy:!0,port:e,serviceName:a.service,browserCount:a.browsers?.count}:{healthy:!1,error:`Unexpected health status: ${a.status||`unknown`}`}}catch(e){return clearTimeout(i),e instanceof Error?e.name===`AbortError`?{healthy:!1,error:`Health check timed out after ${t}ms`}:`code`in e&&e.code===`ECONNREFUSED`?{healthy:!1,error:`Connection refused - server not running`}:{healthy:!1,error:`Network error: ${e.message}`}:{healthy:!1,error:`Unknown error: ${String(e)}`}}}catch(e){return{healthy:!1,error:e instanceof Error?e.message:String(e)}}}};H=A([(0,u.injectable)()],H);const en=(0,ee.fileURLToPath)(require(`url`).pathToFileURL(__filename).href),tn=p.dirname(en),nn=`PLAYWRIGHT_SKIP_DYNAMIC_TOOL_COMMANDS`,rn=`1`,an=[`pnpm-workspace.yaml`,`nx.json`,`.git`],U=`browse-tool-http`,on=`tool`,sn=`http-serve`,cn=3,ln=1e4,un=100,dn=1e3,fn=`ESRCH`,pn=`SIGTERM`,mn=`SIGKILL`,hn=`--port`,gn=`--host`,_n=`development`,vn=`node`,yn=`bun`,bn=`run`,xn=`cli.mjs`,Sn=`cli.ts`,Cn=`dist`,wn=`src`,Tn=`HTTP_SERVER_STALE_ENTRY`,En=`HTTP_SERVER_NOT_REGISTERED`,Dn=`Server registered but not healthy`,On=`No HTTP server registered`,kn=`Run ensureRunning() to start a fresh server or clean up stale entries.`,An=`Call ensureRunning() to discover or spawn a server.`,jn=`No matching registry entry`,W=`[HttpServerManager]`;var Mn=class extends Error{code=`HTTP_SERVER_PORT_ERROR`;recovery=`Check if other services are occupying ports in the configured range.`;constructor(e,t){super(e,t),this.name=`HttpServerPortError`}},G=class extends Error{code=`HTTP_SERVER_STARTUP_ERROR`;recovery=`Check server logs, ensure CLI binary exists, and verify port availability.`;constructor(e,t){super(e,t),this.name=`HttpServerStartupError`}},Nn=class extends Error{code=`HTTP_SERVER_STOP_ERROR`;recovery=`Manually kill the process and clean up the port registry.`;causes;constructor(e,t=[],n){super(e,n),this.name=`HttpServerStopError`,this.causes=t}};async function K(e){try{return await w.access(e),!0}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return!1;throw e}}async function Pn(e=process.cwd()){let t=p.resolve(e);for(;;){for(let e of an)if(await K(p.join(t,e)))return t;let e=p.dirname(t);if(e===t)return process.cwd();t=e}}let Fn=class{repositoryPath;environment;host;constructor(e,t){this.healthCheck=e,this.portRegistry=t,this.environment=process.env.NODE_ENV||`development`,this.host=B()}async getRepositoryPath(){return this.repositoryPath||=await Pn(process.cwd()),this.repositoryPath}buildErrorStatus(e){return{running:!1,error:e instanceof Error?e.message:String(e),errorCode:e instanceof Error&&`code`in e?e.code:void 0,errorRecovery:e instanceof Error&&`recovery`in e?e.recovery:void 0,errorCause:e instanceof Error&&e.cause instanceof Error?e.cause.message:void 0}}async listServiceEntries(){return this.portRegistry.listAllocations({serviceName:U,serviceType:on,environment:this.environment})}async releaseEntry(e){let t=await this.portRegistry.releasePort({repositoryPath:e.repositoryPath,serviceName:U,serviceType:on,environment:e.environment,pid:e.pid});!t.success&&!t.error?.includes(`No matching registry entry`)&&console.error(`${W} Failed to release entry for port ${e.port}: ${t.error}`)}async discoverHealthyService(){let e=await this.listServiceEntries();for(let t of e)try{let e=await this.healthCheck.check(t.port);if(e.healthy&&e.serviceName===U)return{entry:t,browserCount:e.browserCount}}catch(e){console.error(`${W} Health check threw for port ${t.port}: ${e instanceof Error?e.message:String(e)}`)}return null}async cleanupStaleEntries(){let e=await this.listServiceEntries(),t=[];for(let n of e)try{let e;try{e=await this.healthCheck.check(n.port)}catch(e){console.error(`${W} Health check threw for port ${n.port}, skipping cleanup: ${e instanceof Error?e.message:String(e)}`);continue}e.healthy&&e.serviceName===U||(n.pid&&await this.killProcess(n.pid),await this.releaseEntry(n))}catch(e){let r=`Failed to clean up entry on port ${n.port}: ${e instanceof Error?e.message:String(e)}`;console.error(`${W} ${r}`),t.push(r)}t.length>0&&console.error(`${W} ${t.length} entry cleanup failure(s) during stale entry removal`)}async findRegistrationByPort(e){return(await this.listServiceEntries()).find(t=>t.port===e)??null}async findAvailablePort(e){let t=await this.getRepositoryPath(),n=await this.portRegistry.findAvailablePort({repositoryPath:t,serviceName:U,serviceType:on,environment:this.environment,host:this.host,preferredPort:e});if(!n.success||!n.port)throw new Mn(`No available port found from ${e}: ${n.error}`);return n.port}async resolveCliCommand(e){let t=p.resolve(tn,xn),n=p.resolve(tn,`..`,Sn),r=[`--port`,e.toString(),`--host`,this.host];if(await K(t))return[vn,[t,sn,...r]];if(await K(n))return[`bun`,[`run`,n,sn,...r]];let i=p.resolve(tn,`..`,`..`),a=p.join(i,`dist`,xn),o=p.join(i,`src`,Sn);if(await K(a))return[vn,[a,sn,...r]];if(await K(o))return[`bun`,[`run`,o,sn,...r]];throw new G(`Cannot find CLI at ${t}, ${n}, ${a}, or ${o}`)}async startHttpServer(e){let[t,n]=await this.resolveCliCommand(e),r=(0,T.spawn)(t,n,{detached:!0,stdio:`ignore`,env:{...process.env,NODE_ENV:this.environment,PLAYWRIGHT_SKIP_DYNAMIC_TOOL_COMMANDS:`1`}}),i=await new Promise(e=>{let t=setTimeout(()=>{r.removeAllListeners(`error`),e(null)},100);r.once(`error`,n=>{clearTimeout(t),e(n)})});if(i)throw new G(`Failed to spawn HTTP server process: ${i.message}`,{cause:i});r.unref();let a=r.pid;if(!a)throw new G(`Failed to spawn HTTP server - no PID returned`);return a}async killProcess(e){try{process.kill(e,0),process.kill(e,`SIGTERM`)}catch(t){if((t instanceof Error&&`code`in t?t.code:void 0)===fn){console.error(`${W} Process ${e} does not exist — skipping kill`);return}throw t}await new Promise(e=>setTimeout(e,1e3));try{process.kill(e,0),process.kill(e,`SIGKILL`)}catch(t){if((t instanceof Error&&`code`in t?t.code:void 0)===fn){console.error(`${W} Process ${e} exited after SIGTERM`);return}throw t}}async cleanupFailedSpawn(e,t){await this.killProcess(e);let n=await this.findRegistrationByPort(t);n&&n.pid===e&&await this.releaseEntry(n)}async attemptSpawn(e){let t=await this.findAvailablePort(e),n=await this.startHttpServer(t);await new Promise(e=>setTimeout(e,1e4));let r;try{r=await this.healthCheck.check(t)}catch(e){let r=e instanceof Error?e.message:String(e);return console.error(`${W} Health check threw on port ${t}: ${r}`),await this.cleanupFailedSpawn(n,t),{success:!1,reason:`health_check_error`,port:t,error:r}}if(!r.healthy)return await this.cleanupFailedSpawn(n,t),{success:!1,reason:`health_check_failed`,port:t,error:r.error};if(r.serviceName!==U)return await this.cleanupFailedSpawn(n,t),{success:!1,reason:`service_name_mismatch`,port:t,error:`Expected ${U}, got ${r.serviceName}`};let i=await this.findRegistrationByPort(t);return!i||i.pid!==n?(console.error(`${W} Ownership mismatch on port ${t}: expected pid ${n}, found ${i?.pid}`),await this.cleanupFailedSpawn(n,t),{success:!1,reason:`ownership_mismatch`,port:t}):(console.error(`${W} Server self-registered on port ${t} (pid: ${i.pid})`),{success:!0,port:t,pid:n,browserCount:r.browserCount})}async ensureRunning(e=Qt()){try{let t=await this.discoverHealthyService();if(t)return{running:!0,port:t.entry.port,pid:t.entry.pid,browserCount:t.browserCount,spawned:!1};await this.cleanupStaleEntries();let n=e;for(let e=0;e<3;e+=1){let t=await this.attemptSpawn(n);if(t.success)return{running:!0,port:t.port,pid:t.pid,browserCount:t.browserCount,spawned:!0};console.error(`${W} Spawn attempt ${e+1} failed: ${t.reason} on port ${t.port}`),n=t.port+1}let r=new G(`Failed to start browse-tool HTTP server after 3 attempts`);return this.buildErrorStatus(r)}catch(e){return this.buildErrorStatus(e)}}async stop(){let e=await this.listServiceEntries();if(e.length===0)return!1;let t=[];for(let n of e)try{n.pid&&await this.killProcess(n.pid),await this.releaseEntry(n)}catch(e){let r=e instanceof Error?e:Error(`Failed to stop entry on port ${n.port}: ${String(e)}`);console.error(`${W} ${r.message}`),t.push(r)}if(t.length>0){let n=t.map(e=>e.message);throw new Nn(`Failed to stop ${t.length} of ${e.length} server(s): ${n.join(`; `)}`,t,{cause:t[0]})}return!0}async getStatus(){try{let e=await this.discoverHealthyService();if(e)return{running:!0,port:e.entry.port,pid:e.entry.pid,browserCount:e.browserCount};let t=await this.listServiceEntries();if(t.length>0){let e=t[0];return{running:!1,port:e.port,pid:e.pid,error:`Server registered but not healthy`,errorCode:`HTTP_SERVER_STALE_ENTRY`,errorRecovery:`Run ensureRunning() to start a fresh server or clean up stale entries.`}}return{running:!1,error:`No HTTP server registered`,errorCode:`HTTP_SERVER_NOT_REGISTERED`,errorRecovery:`Call ensureRunning() to discover or spawn a server.`}}catch(e){return this.buildErrorStatus(e)}}};Fn=A([(0,u.injectable)(),N(0,(0,u.inject)(O.HttpServerHealthCheck)),N(1,(0,u.inject)(O.PortRegistryService)),k(`design:paramtypes`,[Object,Object])],Fn);const In=900*1e3,Ln=1800*1e3,Rn=60*1e3;let zn=class{intervalId=null;constructor(e,t){this.browserService=e,this.pageRegistry=t}start(){this.intervalId||(this.intervalId=setInterval(()=>{this.cleanup().catch(e=>{console.warn(`[IdleCleanup] Error during cleanup:`,e)})},6e4),this.intervalId&&typeof this.intervalId==`object`&&`unref`in this.intervalId&&this.intervalId.unref(),console.warn(`[IdleCleanup] Started (page timeout: ${In/6e4}min, browser timeout: ${Ln/6e4}min)`))}stop(){this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null,console.warn(`[IdleCleanup] Stopped`))}async cleanup(){let e=Date.now();await this.cleanupIdlePages(e),await this.cleanupIdleBrowsers(e)}async cleanupIdlePages(e){let t=this.pageRegistry.list();for(let n of t){let t=e-n.lastAccessedAt.getTime();if(!(t<In)){console.warn(`[IdleCleanup] Closing idle page "${n.id}" (idle ${Math.round(t/6e4)}min)`);try{if(n.page)await n.page.close();else{let e=this.browserService.getBrowser(n.browserId);if(e&&(e.pageIds.delete(n.id),e.currentPageId===n.id)){let t=Array.from(e.pageIds);e.currentPageId=t.length>0?t[0]:null}this.pageRegistry.remove(n.id)}}catch(e){console.warn(`[IdleCleanup] Failed to close page "${n.id}":`,e)}}}}async cleanupIdleBrowsers(e){let t=this.browserService.listBrowsers();for(let n of t){let t=n.specOrigin?In:Ln,r=e-n.lastAccessedAt.getTime();if(!(r<t)){console.warn(`[IdleCleanup] Closing idle browser "${n.id}" (idle ${Math.round(r/6e4)}min)`);try{await this.browserService.closeBrowser(n.id)}catch(e){console.warn(`[IdleCleanup] Failed to close browser "${n.id}":`,e)}}}}};zn=A([(0,u.injectable)(),N(0,(0,u.inject)(O.BrowserService)),N(1,(0,u.inject)(O.PageRegistry)),k(`design:paramtypes`,[Object,Object])],zn);let q=class{browsers=new Map;pages=new Map;trackBrowser(e,t){this.browsers.has(e)||this.browsers.set(e,{browserId:e,mode:t,createdAt:new Date,pageIds:new Set})}trackPage(e,t,n){if(this.pages.has(e))return;this.pages.set(e,{pageId:e,browserId:t,url:n,createdAt:new Date});let r=this.browsers.get(t);r&&r.pageIds.add(e)}untrackBrowser(e){let t=this.browsers.get(e);if(t){for(let e of t.pageIds)this.pages.delete(e);this.browsers.delete(e)}}untrackPage(e){let t=this.pages.get(e);if(t){let n=this.browsers.get(t.browserId);n&&n.pageIds.delete(e),this.pages.delete(e)}}getBrowserIds(){return Array.from(this.browsers.keys())}getPageIds(){return Array.from(this.pages.keys())}getPageIdsForBrowser(e){let t=this.browsers.get(e);return t?Array.from(t.pageIds):[]}getSessionState(){return{browsers:Array.from(this.browsers.values()).map(e=>({browserId:e.browserId,mode:e.mode,createdAt:e.createdAt.toISOString(),pageIds:Array.from(e.pageIds)})),pages:Array.from(this.pages.values()).map(e=>({pageId:e.pageId,browserId:e.browserId,url:e.url,createdAt:e.createdAt.toISOString()})),totalBrowsers:this.browsers.size,totalPages:this.pages.size}}clear(){this.browsers.clear(),this.pages.clear()}};q=A([(0,u.injectable)()],q);let Bn=class{pageStates=new Map;pageInstances=new Map;startMonitoring(e,t){this.stopMonitoring(e);let n={networkRequests:new Map,consoleMessages:[],requestCounter:0,messageCounter:0,listeners:{}};n.listeners.request=e=>{let t=`req-${++n.requestCounter}`,r={id:t,url:e.url(),method:e.method(),resourceType:e.resourceType(),headers:e.headers(),postData:e.postData()??void 0,timestamp:new Date};n.networkRequests.set(t,r)},n.listeners.response=e=>{let t=e.request();for(let[,r]of n.networkRequests)if(r.url===t.url()&&!r.response){r.response={status:e.status(),statusText:e.statusText(),headers:e.headers(),timing:e.request().timing().responseEnd};break}},n.listeners.console=e=>{let t=`msg-${++n.messageCounter}`,r=e.location(),i={id:t,type:e.type(),text:e.text(),location:r.url?{url:r.url,lineNumber:r.lineNumber,columnNumber:r.columnNumber}:void 0,timestamp:new Date};n.consoleMessages.push(i)},t.on(`request`,n.listeners.request),t.on(`response`,n.listeners.response),t.on(`console`,n.listeners.console),this.pageStates.set(e,n),this.pageInstances.set(e,t),t.once(`close`,()=>{this.stopMonitoring(e)})}stopMonitoring(e){let t=this.pageStates.get(e),n=this.pageInstances.get(e);t&&n&&(t.listeners.request&&n.off(`request`,t.listeners.request),t.listeners.response&&n.off(`response`,t.listeners.response),t.listeners.console&&n.off(`console`,t.listeners.console)),this.pageStates.delete(e),this.pageInstances.delete(e)}getNetworkRequests(e){let t=this.pageStates.get(e);return t?Array.from(t.networkRequests.values()):[]}getNetworkRequest(e,t){let n=this.pageStates.get(e);if(n)return n.networkRequests.get(t)}getConsoleMessages(e,t){let n=this.pageStates.get(e);return n?t?n.consoleMessages.filter(e=>e.type===t):[...n.consoleMessages]:[]}clearData(e){let t=this.pageStates.get(e);t&&(t.networkRequests.clear(),t.consoleMessages=[],t.requestCounter=0,t.messageCounter=0)}};Bn=A([(0,u.injectable)()],Bn);let Vn=class{pages=new Map;pageIdCounter=0;constructor(e){this.webSocketHub=e}async register(e){let{page:t,browser:n,context:r,browserId:i,profileName:a,mode:o,onClose:s}=e,c=`page-${++this.pageIdCounter}`,l={id:c,mode:o??`playwright`,page:t,browser:n,context:r,browserId:i,url:t.url(),title:await t.title(),profileName:a,createdAt:new Date,lastAccessedAt:new Date,onClose:s};return this.pages.set(c,l),t.once(`close`,()=>{try{s?.(c)}catch{}this.remove(c)}),c}registerExtensionPage(e,t,n,r=!0){let i=`page-${++this.pageIdCounter}`,a={id:i,mode:`extension`,page:void 0,browser:void 0,context:void 0,browserId:e,url:n??`about:blank`,title:`Extension Tab`,extensionTabId:t,createdAt:new Date,lastAccessedAt:new Date};return this.pages.set(i,a),r&&this.webSocketHub?.broadcastPageCreated(e,i,n),i}get(e){return this.pages.get(e)}remove(e){let t=this.pages.get(e);t&&(this.pages.delete(e),t.mode===`extension`&&this.webSocketHub?.broadcastPageRemoved(t.browserId,e))}list(){return Array.from(this.pages.values())}findByBrowser(e){return this.list().filter(t=>t.browserId===e)}findByProfile(e){return this.list().filter(t=>t.profileName===e)}touchPage(e){let t=this.pages.get(e);t&&(t.lastAccessedAt=new Date)}async updateMetadata(e){let t=this.get(e);t&&t.page&&(t.url=t.page.url(),t.title=await t.page.title())}clear(){this.pages.clear(),this.pageIdCounter=0}};Vn=A([(0,u.injectable)(),N(0,(0,u.inject)(O.WebSocketHub)),N(0,(0,u.optional)()),k(`design:paramtypes`,[Object])],Vn);let Hn=class{pauseStates=new Map;getOrCreateState(e){let t=this.pauseStates.get(e);return t||(t={isPaused:!1,stepName:null,reason:null,pausedAt:null,resolver:null},this.pauseStates.set(e,t)),t}pause(e,t,n){let r=this.getOrCreateState(e);if(r.isPaused)throw Error(`Session "${e}" is already paused at step "${r.stepName}"`);return r.isPaused=!0,r.stepName=t,r.reason=n??null,r.pausedAt=new Date,new Promise(e=>{r.resolver=e})}resume(e){let t=this.pauseStates.get(e);if(!t||!t.isPaused)return!1;let n=t.resolver;return t.isPaused=!1,t.stepName=null,t.reason=null,t.pausedAt=null,t.resolver=null,n&&n(),!0}waitForResume(e){let t=this.pauseStates.get(e);return!t||!t.isPaused||!t.resolver?Promise.resolve():new Promise(e=>{let n=t.resolver;t.resolver=()=>{n&&n(),e()}})}getStatus(e){let t=this.pauseStates.get(e);return{sessionId:e,isPaused:t?.isPaused??!1,stepName:t?.stepName??null,reason:t?.reason??null,pausedAt:t?.pausedAt??null}}isPaused(e){return this.pauseStates.get(e)?.isPaused??!1}clear(e){let t=this.pauseStates.get(e);t?.resolver&&t.resolver(),this.pauseStates.delete(e)}};Hn=A([(0,u.injectable)()],Hn);let Un=class{profilesDir;constructor(){this.profilesDir=process.env.PLAYWRIGHT_PROFILES_DIR||(0,p.join)((0,S.homedir)(),`.browse-tool`,`profiles`)}getProfilesDir(){return this.profilesDir}getProfileDir(e){return(0,p.join)(this.getProfilesDir(),e)}getProfilePath(e){return(0,p.join)(this.getProfileDir(e),`profile.json`)}getStorageStatePath(e){return(0,p.join)(this.getProfileDir(e),`storage-state.json`)}async ensureProfilesDir(){let e=this.getProfilesDir();(0,f.existsSync)(e)||await(0,w.mkdir)(e,{recursive:!0})}async list(){await this.ensureProfilesDir();let e=await(0,w.readdir)(this.getProfilesDir(),{withFileTypes:!0}),t=[];for(let n of e)if(n.isDirectory()){let e=await this.get(n.name);e&&t.push(e)}return t}async get(e){let t=this.getProfilePath(e);if(!(0,f.existsSync)(t))return null;let n=await(0,w.readFile)(t,`utf-8`);return JSON.parse(n)}async create(e){if(await this.get(e.name))throw Error(`Profile "${e.name}" already exists`);await(0,w.mkdir)(this.getProfileDir(e.name),{recursive:!0});let t=new Date().toISOString(),n={...e,createdAt:t,updatedAt:t};return await(0,w.writeFile)(this.getProfilePath(e.name),JSON.stringify(n,null,2)),n}async update(e,t){let n=await this.get(e);if(!n)throw Error(`Profile "${e}" not found`);let r={...n,...t,name:n.name,createdAt:n.createdAt,updatedAt:new Date().toISOString()};return await(0,w.writeFile)(this.getProfilePath(e),JSON.stringify(r,null,2)),r}async delete(e){if(!await this.get(e))throw Error(`Profile "${e}" not found`);await(0,w.rm)(this.getProfileDir(e),{recursive:!0})}async saveStorageState(e,t){if(!await this.get(e))throw Error(`Profile "${e}" not found`);await(0,w.writeFile)(this.getStorageStatePath(e),JSON.stringify(t,null,2))}async loadStorageState(e){let t=this.getStorageStatePath(e);if(!(0,f.existsSync)(t))return null;let n=await(0,w.readFile)(t,`utf-8`);return JSON.parse(n)}};Un=A([(0,u.injectable)(),k(`design:paramtypes`,[])],Un);let Wn=class{constructor(e){this.httpClient=e}async execute(e,t={}){return this.httpClient.execute(e,t)}async isServerAvailable(){return this.httpClient.isHealthy()}setServerPort(e){this.httpClient.setBaseUrl(V(void 0,e))}async listTools(){let e=this.httpClient.getBaseUrl(),t=await fetch(`${e}/tools`);if(!t.ok)throw Error(`Failed to list tools: ${t.statusText}`);let n=await t.json();if(n.error)throw Error(n.error);return n.tools}};Wn=A([(0,u.injectable)(),N(0,(0,u.inject)(O.HttpBrowserClient)),k(`design:paramtypes`,[Object])],Wn);let Gn=class{constructor(e){this.bundler=e}async runSetup(e,t,n){let r=null;try{r=await this.bundler.bundle(e);let i=await import(`${r.outputPath}?t=${Date.now()}`),a=await this.getSetupFunction(i,t,e)(n);return{state:this.validateSetupResult(a,e),success:!0}}catch(t){return{state:{},success:!1,error:`Setup failed for "${e}": ${t instanceof Error?t.message:String(t)}`}}finally{r&&await r.cleanup()}}getSetupFunction(e,t,n){if(t in e&&typeof e[t]==`function`)return e[t];if(t===`default`&&`default`in e){let t=e.default;if(typeof t==`function`)return t;throw Error(`Default export in "${n}" is not a function`)}let r=Object.keys(e).filter(t=>typeof e[t]==`function`);throw r.length===0?Error(`No function exports found in "${n}"`):Error(`Export "${t}" not found in "${n}". Available functions: ${r.join(`, `)}`)}validateSetupResult(e,t){if(e==null)return{};if(typeof e!=`object`||Array.isArray(e))throw Error(`Setup function in "${t}" must return an object or undefined, got ${typeof e}`);return e}};Gn=A([(0,u.injectable)(),N(0,(0,u.inject)(O.SpecBundlerService)),k(`design:paramtypes`,[Object])],Gn);const Kn=(0,ie.promisify)(T.execFile),J=`[SpecBundler]`,qn=`file://`,Jn=`^@playwright\\/test$`,Yn=new RegExp(Jn),Xn=`
|
|
6
|
+
`,Zn=0,Qn=`""`,$n=`stubs`,er=`playwright-test.mjs`,tr=`build`,nr=`__PLAYWRIGHT_MCP_STUB_PATH__`,Y={OUTDIR_NAME:`browse-tool-bundles`,SCRIPT_PREFIX:`bun-build-`,SCRIPT_EXTENSION:`.mjs`,TARGET_BUN:`bun`,TARGET_NODE:`node`,FORMAT:`esm`,PLUGIN_NAME:`playwright-test-alias`,BUN_COMMAND:`bun`,EXTERNALS:[`playwright`,`playwright/test`,`playwright-core`],SCRIPT_NEWLINE:`\\n`},rr={BUILD_FAILURE:1},ir={BUILD_FAILED:`SPEC_BUNDLER_BUILD_FAILED`,NO_OUTPUT:`SPEC_BUNDLER_NO_OUTPUT`,CLI_FAILED:`SPEC_BUNDLER_CLI_FAILED`,IO_FAILED:`SPEC_BUNDLER_IO_FAILED`},X={UNEXPECTED_BUILD:`Unexpected build exception`,EMPTY_OUTPUTS:`Bun build returned empty outputs array`,EMPTY_STDOUT:`Empty stdout`,BUILD_SCRIPT_EXIT:`Build script exited with code ${rr.BUILD_FAILURE}`,IO_MKDIR:`Failed to create output directory`,IO_WRITE_SCRIPT:`Failed to write build script`,CLI_EXECUTION:`bun CLI execution failed`,CLEANUP_FAILED:`Failed to clean up temporary file`};var ar=class extends Error{code=ir.BUILD_FAILED;recovery=`Check the spec file for syntax errors and ensure all imports are resolvable.`;constructor(e,t,n){super(`Failed to bundle spec "${(0,p.basename)(e)}": ${t}`,n),this.specPath=e,this.buildErrors=t,this.name=`SpecBundlerBuildError`}},or=class extends Error{code=ir.NO_OUTPUT;recovery=`Verify the spec file exists and contains valid TypeScript/JavaScript.`;constructor(e,t,n){let r=t?`: ${t}`:``;super(`Bundling produced no output for "${(0,p.basename)(e)}"${r}`,n),this.specPath=e,this.stderr=t,this.name=`SpecBundlerNoOutputError`}},sr=class extends Error{code=ir.CLI_FAILED;recovery=`Ensure bun is installed and accessible in PATH. Run "bun --version" to verify.`;constructor(e,t,n,r){let i=[t==null?void 0:`exit=${t}`,n?`stderr="${n}"`:void 0].filter(Boolean).join(`, `),a=i?` (${i})`:``;super(`Failed to bundle "${(0,p.basename)(e)}" via bun CLI${a}`,r),this.specPath=e,this.exitCode=t,this.stderr=n,this.name=`SpecBundlerCliError`}},cr=class extends Error{code=ir.IO_FAILED;recovery=`Check filesystem permissions and available disk space.`;constructor(e,t,n){super(`${e} at "${t}"`,n),this.operation=e,this.targetPath=t,this.name=`SpecBundlerIoError`}};const lr=D.z.object({success:D.z.boolean(),logs:D.z.array(D.z.object({message:D.z.string()})),outputs:D.z.array(D.z.object({path:D.z.string()}))});function ur(){let e=globalThis.Bun;if(typeof e==`object`&&e&&tr in e&&typeof e[tr]==`function`)return e}function dr(e){if(!(e instanceof Error)||!(`stderr`in e))return!1;let t=e;return typeof t.stderr==`string`?typeof t.code==`number`||typeof t.code==`string`:!1}let fr=class{stubPath;constructor(){this.stubPath=(0,p.join)((0,p.dirname)(require(`url`).pathToFileURL(__filename).href.replace(`file://`,``)),`stubs`,`playwright-test.mjs`)}async bundle(e){let t=(0,p.join)((0,S.tmpdir)(),Y.OUTDIR_NAME);try{await(0,w.mkdir)(t,{recursive:!0})}catch(e){throw console.error(`${J} ${X.IO_MKDIR} "${t}":`,e),new cr(X.IO_MKDIR,t,{cause:e})}let n=ur();return n?this.bundleWithBunApi(n,e,t):this.bundleWithBunCli(e,t)}async bundleWithBunApi(e,t,n){let r;try{let i=await e.build({entrypoints:[t],outdir:n,target:Y.TARGET_BUN,format:Y.FORMAT,external:[...Y.EXTERNALS],define:{[nr]:JSON.stringify(this.stubPath)},plugins:[{name:Y.PLUGIN_NAME,setup:e=>{e.onResolve({filter:Yn},()=>({path:this.stubPath}))}}]});r=lr.parse(i)}catch(e){throw e instanceof D.z.ZodError?(console.error(`${J} Unexpected build result shape for "${t}":`,e),new ar(t,X.UNEXPECTED_BUILD,{cause:e})):(console.error(`${J} Unexpected build error for "${t}":`,e),new ar(t,X.UNEXPECTED_BUILD,{cause:e}))}if(!r.success){let e=r.logs.map(e=>e.message).join(`
|
|
7
|
+
`);throw console.error(`${J} Build failed for "${t}": ${e}`),new ar(t,e,{cause:Error(e)})}let i=r.outputs[0]?.path;if(!i)throw console.error(`${J} No output produced for "${t}"`),new or(t,void 0,{cause:Error(X.EMPTY_OUTPUTS)});return{outputPath:i,cleanup:()=>this.safeUnlink(i)}}async bundleWithBunCli(e,t){let n=(0,p.join)((0,S.tmpdir)(),`${Y.SCRIPT_PREFIX}${(0,E.randomUUID)()}${Y.SCRIPT_EXTENSION}`),r=this.generateBuildScript(e,t);try{await(0,w.writeFile)(n,r)}catch(e){throw console.error(`${J} ${X.IO_WRITE_SCRIPT} "${n}":`,e),new cr(X.IO_WRITE_SCRIPT,n,{cause:e})}try{return await this.executeBuildScript(n,e)}finally{await this.safeUnlink(n)}}generateBuildScript(e,t){return[`const result = await Bun.build({`,` entrypoints: [${JSON.stringify(e)}],`,` outdir: ${JSON.stringify(t)},`,` target: ${JSON.stringify(Y.TARGET_NODE)},`,` format: ${JSON.stringify(Y.FORMAT)},`,` external: ${JSON.stringify(Y.EXTERNALS)},`,` define: { ${JSON.stringify(nr)}: ${JSON.stringify(JSON.stringify(this.stubPath))} },`,` plugins: [{`,` name: ${JSON.stringify(Y.PLUGIN_NAME)},`,` setup: (build) => {`,` build.onResolve({ filter: new RegExp(${JSON.stringify(Jn)}) }, () => ({`,` path: ${JSON.stringify(this.stubPath)},`,` }));`,` },`,` }],`,`});`,`if (!result.success) {`,` const errors = result.logs.map(l => l.message).join('${Y.SCRIPT_NEWLINE}');`,` process.stderr.write(errors);`,` process.exit(${rr.BUILD_FAILURE});`,`}`,`process.stdout.write(result.outputs[0]?.path ?? "");`].join(`
|
|
8
|
+
`)}async executeBuildScript(e,t){try{let{stdout:n,stderr:r}=await Kn(Y.BUN_COMMAND,[e]),i=n.trim();if(!i)throw console.error(`${J} CLI produced no output for "${t}": ${r}`),new or(t,r,{cause:Error(r||X.EMPTY_STDOUT)});return{outputPath:i,cleanup:()=>this.safeUnlink(i)}}catch(e){if(e instanceof or||e instanceof cr)throw e;if((dr(e)?typeof e.code==`string`?Number(e.code):e.code:void 0)===rr.BUILD_FAILURE&&dr(e))throw console.error(`${J} CLI build failed for "${t}": ${e.stderr}`),new ar(t,e.stderr||X.BUILD_SCRIPT_EXIT,{cause:e});let n=dr(e)?e.code:void 0,r=dr(e)?e.stderr:void 0;throw console.error(`${J} ${X.CLI_EXECUTION} for "${t}":`,e),new sr(t,n,r,{cause:e})}}async safeUnlink(e){try{await(0,w.unlink)(e)}catch(t){console.warn(`${J} ${X.CLEANUP_FAILED} "${e}":`,t)}}};fr=A([(0,u.injectable)(),k(`design:paramtypes`,[])],fr);let pr=class{async discoverProjects(e){let t=e||process.cwd(),n=[],r=await this.findPlaywrightConfigs(t);for(let e of r){let t=(0,p.dirname)(e),r={name:(0,p.basename)(t),path:t,configPath:e,testDir:await this.getTestDirFromConfig(e),specs:[]};r.specs=await this.getProjectSpecs(t),n.push(r)}return n}async getProjectSpecs(e){let t=(0,p.join)(e,`playwright.config.ts`);if(!(0,f.existsSync)(t))throw Error(`No playwright.config.ts found in ${e}`);let n=(0,p.join)(e,await this.getTestDirFromConfig(t));if(!(0,f.existsSync)(n))return[];let r=[],i=await this.findSpecFiles(n);for(let t of i){let n=await this.getSpecInfo(t,e);r.push(n)}return r}async getSpecInfo(e,t){let n=(0,p.resolve)(e);if(!(0,f.existsSync)(n))throw Error(`Spec file not found: ${e}`);let r=(0,p.basename)(n);return{name:r,path:n,relativePath:t?(0,p.relative)(t,n):r,hasArgsSchema:await this.checkHasArgsSchema(n)}}async filterSpecs(e,t){let n=await this.discoverProjects(e),r=[];for(let e of n){if(t?.projectName&&e.name!==t.projectName)continue;let n=e.specs;if(t?.specPattern){let e=this.globToRegex(t.specPattern);n=n.filter(t=>e.test(t.name)||e.test(t.relativePath))}r=r.concat(n)}return r}async findPlaywrightConfigs(e){let t=[];return await this.walkDirectory(e,(e,n)=>{if(n){let t=(0,p.basename)(e);return!(t===`node_modules`||t.startsWith(`.`))}return(0,p.basename)(e)===`playwright.config.ts`&&t.push(e),!0}),t}async findSpecFiles(e){let t=[];return await this.walkDirectory(e,(e,n)=>n?(0,p.basename)(e)!==`node_modules`:(e.endsWith(`.spec.ts`)&&t.push(e),!0)),t}async walkDirectory(e,t){if(!(0,f.existsSync)(e))return;let n=await(0,w.readdir)(e,{withFileTypes:!0});for(let r of n){let n=(0,p.join)(e,r.name);r.isDirectory()?t(n,!0)&&await this.walkDirectory(n,t):t(n,!1)}}async getTestDirFromConfig(e){try{let t=(await(0,w.readFile)(e,`utf-8`)).match(/testDir:\s*['"`]([^'"`]+)['"`]/);if(t)return t[1].replace(/^\.\//,``)}catch{}return`tests`}async checkHasArgsSchema(e){try{let t=await(0,w.readFile)(e,`utf-8`);return/export\s+(const\s+)?argsSchema\b/.test(t)}catch{return!1}}globToRegex(e){let t=e.replace(/[.+^${}()|[\]\\]/g,`\\$&`).replace(/\*/g,`.*`).replace(/\?/g,`.`);return RegExp(`^${t}$`,`i`)}};pr=A([(0,u.injectable)()],pr);let mr=class{constructor(e){this.bundler=e}async extractSpecMetadata(e){let t=await this.bundler.bundle(e);try{let e=await import(`${t.outputPath}?t=${Date.now()}`),n=e.argsSchema??null;return{argsSchema:n,envPrefix:e.envPrefix??null,hasDynamicArgs:n!==null}}catch{return{argsSchema:null,envPrefix:null,hasDynamicArgs:!1}}finally{await t.cleanup()}}async loadPlaywrightConfig(e){try{let t=await(0,w.readFile)(e,`utf-8`),n={},r=t.match(/baseURL:\s*['"`]([^'"`]+)['"`]/);r&&(n.baseURL=r[1]);let i=t.match(/export\s+const\s+mcpConfig\s*=\s*\{([^}]+)\}/s);if(i){let e=i[1],t=e.match(/setupFile:\s*['"`]([^'"`]+)['"`]/);t&&(n.setupFile=t[1]);let r=e.match(/setupExport:\s*['"`]([^'"`]+)['"`]/);r&&(n.setupExport=r[1])}let a=t.match(/webServer:\s*\{([^}]+(?:\{[^}]*\}[^}]*)*)\}/s);if(a){let e=a[1],t=e.match(/command:\s*['"`]([^'"`]+)['"`]/),r=e.match(/url:\s*['"`]([^'"`]+)['"`]/),i=e.match(/reuseExistingServer:\s*(true|false)/),o=e.match(/timeout:\s*(\d+)/),s=e.match(/cwd:\s*['"`]([^'"`]+)['"`]/);t&&r&&(n.webServer={command:t[1],url:r[1],reuseExistingServer:i?i[1]===`true`:void 0,timeout:o?Number.parseInt(o[1],10):void 0,cwd:s?s[1]:void 0})}return n}catch{return{}}}parseArgsFromEnv(e,t){let n={},r=t.toUpperCase();for(let[e,t]of Object.entries(process.env))if(e.startsWith(r)&&t!==void 0){let i=this.envKeyToFieldName(e.slice(r.length));n[i]=this.parseEnvValue(t)}try{return e.parse(n)}catch{return n}}envKeyToFieldName(e){return e.toLowerCase().split(`_`).map((e,t)=>t===0?e:e.charAt(0).toUpperCase()+e.slice(1)).join(``)}parseEnvValue(e){if(e.toLowerCase()===`true`)return!0;if(e.toLowerCase()===`false`)return!1;let t=Number(e);if(!Number.isNaN(t)&&e.trim()!==``)return t;if(e.startsWith(`{`)&&e.endsWith(`}`)||e.startsWith(`[`)&&e.endsWith(`]`))try{return JSON.parse(e)}catch{}return e}};mr=A([(0,u.injectable)(),N(0,(0,u.inject)(O.SpecBundlerService)),k(`design:paramtypes`,[Object])],mr);let hr=class{constructor(e){this.bundler=e}async loadSpec(e){let t=await this.bundler.bundle(e);try{c.r(e);let n=process,r=n.__pw_initiator__;return n.__pw_initiator__=void 0,await import(`${t.outputPath}?t=${Date.now()}`),n.__pw_initiator__=r,c.n()}catch(t){throw c.a(),Error(`Failed to load spec "${e}": ${t instanceof Error?t.message:String(t)}`,{cause:t})}finally{await t.cleanup()}}async executeSpec(e){let{specPath:t,page:n,context:r,browser:i}=e,a=Date.now(),o=[],s=0,c=0;try{let e=await this.loadSpec(t),l={page:n,context:r,browser:i};for(let t of e.allTests){let e=Date.now();try{await t.fn(l),o.push({title:t.title,fullTitle:t.fullTitle,passed:!0,error:null,duration:Date.now()-e}),s++}catch(n){let r=n instanceof Error?n.message:String(n);o.push({title:t.title,fullTitle:t.fullTitle,passed:!1,error:r,duration:Date.now()-e}),c++}}return{specPath:t,totalTests:e.testCount,passed:s,failed:c,testResults:o,success:c===0,duration:Date.now()-a}}catch(e){return{specPath:t,totalTests:0,passed:0,failed:1,testResults:[{title:`Spec Loading`,fullTitle:`Failed to load: ${t}`,passed:!1,error:e instanceof Error?e.message:String(e),duration:Date.now()-a}],success:!1,duration:Date.now()-a}}}async executeSpecEnhanced(e){let{specPath:t,page:n,context:r,browser:i,testFilter:a,specArgs:o}=e,s=Date.now(),c=[],l=0,u=0;try{let e=await this.loadSpec(t),d=a?this.filterTests(e.allTests,a):e.allTests,f={page:n,context:r,browser:i,specArgs:o};for(let e of d){if(e.skip){c.push({title:e.title,fullTitle:e.fullTitle,passed:!0,error:null,duration:0}),l++;continue}let t=Date.now();try{await e.fn(f),c.push({title:e.title,fullTitle:e.fullTitle,passed:!0,error:null,duration:Date.now()-t}),l++}catch(n){let r=n instanceof Error?n.message:String(n);c.push({title:e.title,fullTitle:e.fullTitle,passed:!1,error:r,duration:Date.now()-t}),u++}}return{specPath:t,totalTests:d.length,passed:l,failed:u,testResults:c,success:u===0,duration:Date.now()-s}}catch(e){return{specPath:t,totalTests:0,passed:0,failed:1,testResults:[{title:`Spec Loading`,fullTitle:`Failed to load: ${t}`,passed:!1,error:e instanceof Error?e.message:String(e),duration:Date.now()-s}],success:!1,duration:Date.now()-s}}}filterTests(e,t){let n=[...e];if(t.onlyMarked){let e=n.filter(e=>e.only);e.length>0&&(n=e)}if(t.testName&&(n=n.filter(e=>e.title===t.testName)),t.testPattern){let e=new RegExp(t.testPattern,`i`);n=n.filter(t=>e.test(t.fullTitle))}if(t.describeFilter){let e=new RegExp(t.describeFilter,`i`);n=n.filter(t=>e.test(t.fullTitle))}return n}};hr=A([(0,u.injectable)(),N(0,(0,u.inject)(O.SpecBundlerService)),k(`design:paramtypes`,[Object])],hr);let gr=class{browsers=new Map;browserIdCounter=0;constructor(e,t,n){this.profileService=e,this.pageRegistry=t,this.lockManager=n}findChromePath(){let e=S.default.platform(),t={darwin:[`/Applications/Google Chrome.app/Contents/MacOS/Google Chrome`,`/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary`,`${S.default.homedir()}/Applications/Google Chrome.app/Contents/MacOS/Google Chrome`],win32:[`C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe`,`C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe`,`${process.env.LOCALAPPDATA}\\Google\\Chrome\\Application\\chrome.exe`],linux:[`/usr/bin/google-chrome`,`/usr/bin/google-chrome-stable`,`/usr/bin/chromium`,`/usr/bin/chromium-browser`,`/snap/bin/chromium`]},n=t[e]??t.linux;for(let e of n)if(f.default.existsSync(e))return e;return null}resolveExtensionPath(e){if(e&&f.default.existsSync(p.default.join(e,`manifest.json`)))return e;let t=p.default.dirname(new URL(require(`url`).pathToFileURL(__filename).href).pathname),n=[p.default.resolve(t,`../dist/extension`),p.default.resolve(t,`../../dist/extension`)];for(let e of n)if(f.default.existsSync(p.default.join(e,`manifest.json`)))return e;let r=p.default.resolve(process.cwd(),`dist/extension`);if(f.default.existsSync(p.default.join(r,`manifest.json`)))return r;throw Error(`Chrome extension not found. Build the extension first: pnpm build:extension`)}createUserDataDir(e){if(e){let t=p.default.join(this.profileService.getProfilesDir(),e,`stealth-user-data`);return f.default.mkdirSync(t,{recursive:!0}),t}let t=p.default.join(S.default.tmpdir(),`stealth-chrome-${Date.now()}`);return f.default.mkdirSync(t,{recursive:!0}),t}async launch(e={}){let t=this.findChromePath();if(!t)throw Error(`Chrome not found. Please install Google Chrome.
|
|
9
|
+
macOS: brew install --cask google-chrome
|
|
10
|
+
Linux: sudo apt install google-chrome-stable`);let n=this.resolveExtensionPath(e.extensionPath),r=this.createUserDataDir(e.profileName);await this.lockManager.ensureAvailable(r);let i=`stealth-browser-${++this.browserIdCounter}`,a=[n];e.proxy?.username&&e.proxy?.password&&a.push(yt(e.proxy.username,e.proxy.password));let o=a.join(`,`),s=(0,T.spawn)(t,[`--user-data-dir=${r}`,`--load-extension=${o}`,`--disable-extensions-except=${o}`,`--disable-blink-features=AutomationControlled`,`--disable-infobars`,`--no-first-run`,`--no-default-browser-check`,`--disable-background-timer-throttling`,`--disable-backgrounding-occluded-windows`,`--disable-renderer-backgrounding`,`--disable-component-update`,`--disable-features=TranslateUI`,`--disable-ipc-flooding-protection`,`--password-store=basic`,`--use-mock-keychain`,`--disable-dev-shm-usage`,`--disable-gpu-sandbox`,...e.windowSize?[`--window-size=${e.windowSize.width},${e.windowSize.height}`]:[`--window-size=1280,720`],...e.proxy?bt(e.proxy):[],e.url??`about:blank`,...e.extraArgs??[]],{detached:!1,stdio:[`ignore`,`ignore`,`ignore`],env:{...process.env,DISPLAY:process.env.DISPLAY}});if(!s.pid)throw Error(`Failed to start Chrome process`);let c={id:i,process:s,pid:s.pid,userDataDir:r,extensionPath:n,profileName:e.profileName,createdAt:new Date,isRunning:!0};return s.on(`exit`,()=>{c.isRunning=!1}),s.on(`error`,e=>{console.error(`Chrome process ${i} error:`,e),c.isRunning=!1}),this.browsers.set(i,c),this.pageRegistry.registerExtensionPage(i),c}async close(e){let t=this.browsers.get(e);if(t&&(t.isRunning&&t.pid&&await vt(t.pid),t.isRunning=!1,this.browsers.delete(e),!t.profileName&&t.userDataDir.includes(`stealth-chrome-`)))try{f.default.rmSync(t.userDataDir,{recursive:!0,force:!0})}catch{}}async closeAll(){let e=Array.from(this.browsers.keys()).map(e=>this.close(e));await Promise.all(e)}getBrowser(e){return this.browsers.get(e)}listBrowsers(){return Array.from(this.browsers.values()).filter(e=>e.isRunning)}};gr=A([(0,u.injectable)(),N(0,(0,u.inject)(O.ProfileService)),N(1,(0,u.inject)(O.PageRegistry)),N(2,(0,u.inject)(O.BrowserLockManager)),k(`design:paramtypes`,[Object,Object,Object])],gr);function _r(e){if(!e.isError)return;let t=e.content[0];return t?.type===`text`&&typeof t.text==`string`?t.text:`Unknown tool execution error`}let vr=class{constructor(e,t,n,r=new j){this.pageRegistry=e,this.browserService=t,this.delegator=n,this.telemetry=r}async execute(e,t,n,r){return this.telemetry.runInSpan(`browse_tool.tool_executor.page`,{attributes:{"browse_tool.tool.name":e,"browse_tool.page.id":t}},async i=>{let a=this.pageRegistry.get(t);if(!a)return i?.setStatus({code:m.SpanStatusCode.ERROR,message:`Page "${t}" not found`}),{content:[{type:`text`,text:`Page "${t}" not found`}],isError:!0};i?.setAttributes({"browse_tool.browser.id":a.browserId,"browse_tool.execution.mode":a.mode});let o=a.mode===`extension`?await this.delegator.executeTool(e,{pageId:t,browserId:a.browserId,...n}):await r(),s=_r(o);return s&&i?.setStatus({code:m.SpanStatusCode.ERROR,message:s}),o})}isExtensionMode(e){return this.pageRegistry.get(e)?.mode===`extension`}async executeForBrowser(e,t,n,r){return this.telemetry.runInSpan(`browse_tool.tool_executor.browser`,{attributes:{"browse_tool.tool.name":e,"browse_tool.browser.id":t}},async i=>{let a=this.browserService.getBrowser(t);if(!a)return i?.setStatus({code:m.SpanStatusCode.ERROR,message:`Browser "${t}" not found`}),{content:[{type:`text`,text:`Browser "${t}" not found`}],isError:!0};i?.setAttributes({"browse_tool.execution.mode":a.mode});let o=a.mode===`extension`||a.mode===`vm`?await this.delegator.executeTool(e,{browserId:t,...n}):await r(),s=_r(o);return s&&i?.setStatus({code:m.SpanStatusCode.ERROR,message:s}),o})}isBrowserExtensionMode(e){let t=this.browserService.getBrowser(e);return t?.mode===`extension`||t?.mode===`vm`}};vr=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ExtensionToolDelegator)),N(3,(0,u.inject)(O.TelemetryService)),k(`design:paramtypes`,[Object,Object,Object,Object])],vr);let yr=class{serverProcess=null;currentUrl=null;cleanupRegistered=!1;constructor(){this.registerCleanup()}registerCleanup(){if(this.cleanupRegistered)return;this.cleanupRegistered=!0;let e=()=>this.cleanupSync();process.on(`exit`,e),process.on(`SIGINT`,e),process.on(`SIGTERM`,e)}async startServer(e,t){let{command:n,url:r,reuseExistingServer:i=!1,timeout:a=3e4,cwd:o}=e;if(i&&await this.isServerRunning(r))return this.currentUrl=r,{started:!1,url:r,reused:!0};await this.stopServer();let s=o?(0,p.resolve)(t,o):t,[c,...l]=this.parseCommand(n);if(this.serverProcess=(0,T.spawn)(c,l,{cwd:s,shell:!0,stdio:[`ignore`,`pipe`,`pipe`],detached:!1}),this.currentUrl=r,this.serverProcess.on(`error`,e=>{console.error(`Server process error: ${e.message}`)}),!await this.waitForServer(r,a))throw await this.stopServer(),Error(`Server failed to start within ${a}ms. URL: ${r}, Command: ${n}`);return{started:!0,url:r,reused:!1}}async waitForServer(e,t){let n=Date.now(),r=100;for(;Date.now()-n<t;){if(await this.isServerRunning(e))return!0;await this.sleep(r),r=Math.min(r*1.5,2e3)}return!1}async stopServer(){if(this.serverProcess)return new Promise(e=>{if(!this.serverProcess){e();return}let t=this.serverProcess;this.serverProcess=null,this.currentUrl=null;let n=setTimeout(()=>{try{t.kill(`SIGKILL`)}catch{}e()},5e3);t.on(`exit`,()=>{clearTimeout(n),e()});try{t.kill(`SIGTERM`)}catch{clearTimeout(n),e()}})}async isServerRunning(e){try{let t=new AbortController,n=setTimeout(()=>t.abort(),3e3),r=await fetch(e,{method:`HEAD`,signal:t.signal});return clearTimeout(n),r.status>=200&&r.status<400}catch{return!1}}parseCommand(e){let t=[],n=``,r=!1,i=``;for(let a of e)(a===`"`||a===`'`)&&!r?(r=!0,i=a):a===i&&r?(r=!1,i=``):a===` `&&!r?n&&=(t.push(n),``):n+=a;return n&&t.push(n),t}sleep(e){return new Promise(t=>setTimeout(t,e))}getCurrentUrl(){return this.currentUrl}cleanupSync(){if(this.serverProcess){try{this.serverProcess.kill(`SIGKILL`)}catch{}this.serverProcess=null,this.currentUrl=null}}};yr=A([(0,u.injectable)(),k(`design:paramtypes`,[])],yr);const br=C.z.object({type:C.z.string(),text:C.z.string().optional(),data:C.z.string().optional(),mimeType:C.z.string().optional()}),xr=C.z.object({traceId:C.z.string().regex(/^[0-9a-f]{32}$/i).optional(),parentSpanId:C.z.string().regex(/^[0-9a-f]{16}$/i).optional()}),Sr=C.z.object({content:C.z.array(br),isError:C.z.boolean().optional()}),Cr=C.z.object({type:C.z.literal(`task:push`),id:C.z.string(),payload:C.z.object({taskId:C.z.string(),tool:C.z.string(),arguments:C.z.record(C.z.string(),C.z.unknown()),pageId:C.z.string().optional(),telemetry:xr.optional()})}),wr=C.z.object({type:C.z.literal(`page:created`),payload:C.z.object({pageId:C.z.string(),browserId:C.z.string(),url:C.z.string().optional()})}),Tr=C.z.object({type:C.z.literal(`page:removed`),payload:C.z.object({pageId:C.z.string()})}),Er=C.z.object({type:C.z.literal(`session:ack`),id:C.z.string(),payload:C.z.object({sessionId:C.z.string(),controlMode:C.z.string()})}),Dr=C.z.object({type:C.z.literal(`pong`)}),Or=C.z.object({type:C.z.literal(`error`),payload:C.z.object({message:C.z.string(),code:C.z.string().optional()})}),kr=C.z.discriminatedUnion(`type`,[Cr,wr,Tr,Er,Dr,Or]),Ar=C.z.object({type:C.z.literal(`session:register`),id:C.z.string(),payload:C.z.object({browserId:C.z.string(),tabId:C.z.number().optional(),url:C.z.string().optional()})}),jr=C.z.object({type:C.z.literal(`task:result`),payload:C.z.object({taskId:C.z.string(),success:C.z.boolean(),result:Sr.optional(),error:C.z.string().optional()})}),Mr=C.z.object({type:C.z.literal(`tab:mapped`),payload:C.z.object({pageId:C.z.string(),tabId:C.z.number()})}),Nr=C.z.object({type:C.z.literal(`ping`)}),Pr=C.z.object({type:C.z.literal(`heartbeat`),payload:C.z.object({sessionId:C.z.string(),tabId:C.z.number().optional(),url:C.z.string().optional()})}),Fr=C.z.discriminatedUnion(`type`,[Ar,jr,Mr,Nr,Pr]);function Ir(e){let t=Fr.safeParse(e);return t.success?t.data:null}let Lr=class{connections=new Map;browserConnections=new Map;eventHandlers={};maxConnections=100;setEventHandlers(e){this.eventHandlers=e}addConnection(e,t){if(this.connections.size>=this.maxConnections)throw Error(`Maximum connections (${this.maxConnections}) reached`);let n=crypto.randomUUID(),r={id:n,ws:e,browserId:t,connectedAt:new Date,lastMessageAt:new Date};return this.connections.set(n,r),this.browserConnections.has(t)||this.browserConnections.set(t,new Set),this.browserConnections.get(t).add(n),console.log(`[WebSocketHub] Connection added: ${n} for browser ${t}`),n}removeConnection(e){let t=this.connections.get(e);if(!t)return;this.eventHandlers.onDisconnect?.(t);let n=this.browserConnections.get(t.browserId);n&&(n.delete(e),n.size===0&&this.browserConnections.delete(t.browserId)),this.connections.delete(e),console.log(`[WebSocketHub] Connection removed: ${e}`)}getConnection(e){return this.connections.get(e)}getConnectionsByBrowser(e){let t=this.browserConnections.get(e);return t?Array.from(t).map(e=>this.connections.get(e)).filter(e=>e!==void 0):[]}hasConnection(e){return this.browserConnections.has(e)&&(this.browserConnections.get(e)?.size??0)>0}reassignConnection(e,t){let n=this.connections.get(e);if(!n)return!1;let r=n.browserId;if(r===t)return!0;let i=this.browserConnections.get(r);return i&&(i.delete(e),i.size===0&&this.browserConnections.delete(r)),this.browserConnections.has(t)||this.browserConnections.set(t,new Set),this.browserConnections.get(t).add(e),n.browserId=t,!0}handleMessage(e,t){let n=this.connections.get(e);if(!n){console.warn(`[WebSocketHub] Message from unknown connection: ${e}`);return}n.lastMessageAt=new Date;try{let r=typeof t==`string`?t:new TextDecoder().decode(t),i=JSON.parse(r),a=Ir(i);if(!a){console.warn(`[WebSocketHub] Invalid message format from ${e}:`,i),this.sendError(n,`Invalid message format`);return}this.routeMessage(n,a)}catch(t){console.error(`[WebSocketHub] Error parsing message from ${e}:`,t),this.sendError(n,`Failed to parse message`)}}routeMessage(e,t){switch(t.type){case`session:register`:this.eventHandlers.onSessionRegister?.(e,t);break;case`task:result`:this.eventHandlers.onTaskResult?.(e,t);break;case`tab:mapped`:this.eventHandlers.onTabMapped?.(e,t);break;case`heartbeat`:this.eventHandlers.onHeartbeat?.(e,t);break;case`ping`:this.sendToConnection(e,{type:`pong`});break}}sendToConnection(e,t){try{return e.ws.send(JSON.stringify(t)),!0}catch(t){return console.error(`[WebSocketHub] Failed to send to ${e.id}:`,t),!1}}sendError(e,t,n){this.sendToConnection(e,{type:`error`,payload:{message:t,code:n}})}pushTask(e,t){let n=this.getConnectionsByBrowser(e);if(n.length===0)return console.warn(`[WebSocketHub] No connections for browser ${e}`),!1;let r=n[0];return this.sendToConnection(r,t)}broadcastPageCreated(e,t,n){let r={type:`page:created`,payload:{pageId:t,browserId:e,url:n}},i=this.getConnectionsByBrowser(e);for(let e of i)this.sendToConnection(e,r)}broadcastPageRemoved(e,t){let n={type:`page:removed`,payload:{pageId:t}},r=this.getConnectionsByBrowser(e);for(let e of r)this.sendToConnection(e,n)}sendSessionAck(e,t,n,r){e.sessionId=n;let i={type:`session:ack`,id:t,payload:{sessionId:n,controlMode:r}};this.sendToConnection(e,i)}getStats(){return{totalConnections:this.connections.size,browserCount:this.browserConnections.size,connections:Array.from(this.connections.values()).map(e=>({id:e.id,browserId:e.browserId,connectedAt:e.connectedAt}))}}closeAll(){for(let[e,t]of this.connections){try{t.ws.close()}catch{}this.removeConnection(e)}}};Lr=A([(0,u.injectable)()],Lr);let Z=class{constructor(e,t,n){this.pageRegistry=e,this.browserService=t,this.toolExecutor=n}getPage(e){return this.pageRegistry.get(e)}resolvePage(e){let t=this.pageRegistry.get(e);if(!t)throw Error(`Page "${e}" not found`);if(!t.page)throw Error(`Page "${e}" is in extension mode and has no Playwright page`);return t.page}resolvePageEntry(e){let t=this.pageRegistry.get(e);if(!t)throw Error(`Page "${e}" not found`);return t}success(e){return{content:[{type:`text`,text:e}]}}successJson(e){return{content:[{type:`text`,text:JSON.stringify(e,null,2)}]}}successImage(e,t=`image/png`){return{content:[{type:`image`,data:e,mimeType:t}]}}error(e){return{content:[{type:`text`,text:e}],isError:!0}}async safeExecute(e){try{return await e()}catch(e){let t=e instanceof Error?e.message:String(e);return this.error(t)}}async executeWithMode(e,t,n,r){return this.toolExecutor.execute(e,t,n,r)}};Z=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),k(`design:paramtypes`,[Object,Object,Object])],Z);var Rr;let zr=class extends Z{static{Rr=this}static TOOL_NAME=`browser_click`;constructor(e,t,n,r){super(e,t,n),this.elementLocator=r}getDefinition(){return{name:Rr.TOOL_NAME,description:`Clicks on an element on the page. Supports CSS selector, XPath, text content, or accessibility snapshot UID for element identification.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Optional page ID to override browser current page`},selector:{type:`string`,description:`CSS selector (e.g., "button.submit", "#login-btn")`},xpath:{type:`string`,description:`XPath expression (e.g., "//button[@type='submit']")`},text:{type:`string`,description:`Text content to match`},uid:{type:`string`,description:`Accessibility snapshot UID reference`},frame:{type:`string`,description:`Frame selector for iframe content`},clickCount:{type:`number`,description:`Number of clicks (default: 1, use 2 for double-click)`,default:1},button:{type:`string`,enum:[`left`,`middle`,`right`],description:`Mouse button to use`,default:`left`},modifiers:{type:`array`,items:{type:`string`,enum:[`Alt`,`Control`,`Meta`,`Shift`]},description:`Modifier keys to hold during click`},delay:{type:`number`,description:`Time to wait between mousedown and mouseup in ms`},position:{type:`object`,properties:{x:{type:`number`},y:{type:`number`}},description:`Position offset within the element`},timeout:{type:`number`,description:`Timeout in milliseconds (default: ${M})`,default:M}},required:[`pageId`],additionalProperties:!1}}}async execute(e){return this.executeWithMode(Rr.TOOL_NAME,e.pageId,e,async()=>{let t=this.resolvePage(e.pageId);return await(await this.elementLocator.locate(t,{selector:e.selector,xpath:e.xpath,text:e.text,uid:e.uid,frame:e.frame})).click({clickCount:e.clickCount,button:e.button,modifiers:e.modifiers,delay:e.delay,position:e.position,timeout:e.timeout}),this.success(`Clicked element successfully`)})}};zr=Rr=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),N(3,(0,u.inject)(O.ElementLocatorService)),k(`design:paramtypes`,[Object,Object,Object,Object])],zr);var Br;let Vr=class extends Z{static{Br=this}static TOOL_NAME=`browser_close`;constructor(e,t,n){super(e,t,n)}getDefinition(){return{name:Br.TOOL_NAME,description:`Closes a browser instance by its ID. Terminates the browser process, cleans up all associated pages, and releases resources. Works for all modes: playwright, extension, vm (Docker), and stealth.`,inputSchema:{type:`object`,properties:{browserId:{type:`string`,description:`The browser ID to close (returned by browser_launch)`}},required:[`browserId`],additionalProperties:!1}}}async execute(e){return this.safeExecute(async()=>{let t=this.browserService.getBrowser(e.browserId);if(!t)return this.error(`Browser "${e.browserId}" not found`);let n=t.pageIds.size,r=t.mode??`playwright`;return await this.browserService.closeBrowser(e.browserId),this.successJson({closedBrowserId:e.browserId,mode:r,pagesRemoved:n,message:`Browser "${e.browserId}" closed successfully`})})}};Vr=Br=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),k(`design:paramtypes`,[Object,Object,Object])],Vr);var Hr;let Ur=class extends Z{static{Hr=this}static TOOL_NAME=`browser_close_page`;constructor(e,t,n,r){super(e,t,n),this.profileService=r}getDefinition(){return{name:Hr.TOOL_NAME,description:`Closes a page (tab) by its ID. Removes the page from the session and registry. If closed page was current, another page becomes current.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Page ID to close`}},required:[`pageId`],additionalProperties:!1}}}async execute(e){return this.safeExecute(async()=>{let t=this.pageRegistry.get(e.pageId);if(!t)return this.error(`Page "${e.pageId}" not found`);let{browserId:n,profileName:r,mode:i}=t,a=this.browserService.getBrowser(n);if(!a)return this.error(`Browser "${n}" not found`);let o=a.currentPageId===e.pageId,s=a.pageIds.size===1;if(i===`extension`||i===`vm`){let t=await this.executeWithMode(Hr.TOOL_NAME,e.pageId,e,async()=>this.error(`Page "${e.pageId}" is not in extension mode`));if(t.isError)return t;if(this.pageRegistry.remove(e.pageId),a.pageIds.delete(e.pageId),a.currentPageId===e.pageId&&(a.currentPageId=Array.from(a.pageIds)[0]??null),s)try{await this.browserService.closeBrowser(n)}catch(e){console.error(`Failed to close extension browser "${n}" after last tab shutdown:`,e)}return this.successJson({closedPageId:e.pageId,browserId:n,wasCurrentPage:o,newCurrentPageId:a.currentPageId,browserKeptOpen:!s,message:s?`Page "${e.pageId}" closed. Browser "${n}" was also closed because no tabs remained.`:`Page "${e.pageId}" closed successfully`})}if(!t.page)return this.error(`Page "${e.pageId}" is in extension mode and cannot be closed via Playwright`);await t.page.close();let c=this.browserService.getBrowser(n)?.currentPageId??null;if(s){if(r&&a.context)try{let e=await a.context.storageState();await this.profileService.saveStorageState(r,e)}catch(e){console.error(`Failed to auto-save profile "${r}":`,e)}if(!r)try{await this.browserService.closeBrowser(n)}catch(e){console.error(`Failed to auto-close browser "${n}":`,e)}}return this.successJson({closedPageId:e.pageId,browserId:n,wasCurrentPage:o,newCurrentPageId:c,browserKeptOpen:s&&!!r,message:s&&r?`Page "${e.pageId}" closed. Browser kept open for profile "${r}" reuse.`:`Page "${e.pageId}" closed successfully`})})}};Ur=Hr=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),N(3,(0,u.inject)(O.ProfileService)),k(`design:paramtypes`,[Object,Object,Object,Object])],Ur);var Wr;let Gr=class{static{Wr=this}static TOOL_NAME=`browser_create_profile`;constructor(e){this.profileService=e}getDefinition(){return{name:Wr.TOOL_NAME,description:`Creates a browser profile for persistent browser settings and session reuse.`,inputSchema:{type:`object`,properties:{name:{type:`string`,description:`Unique profile name`},browserType:{type:`string`,enum:[`chromium`,`firefox`,`webkit`],description:`Preferred browser type for the profile`,default:`chromium`},viewport:{type:`object`,properties:{width:{type:`number`},height:{type:`number`}},required:[`width`,`height`],additionalProperties:!1},userAgent:{type:`string`},locale:{type:`string`},timezone:{type:`string`},colorScheme:{type:`string`,enum:[`light`,`dark`,`no-preference`]}},required:[`name`],additionalProperties:!1}}}async execute(e){try{let t=await this.profileService.create({name:e.name,browserType:e.browserType??`chromium`,viewport:e.viewport,userAgent:e.userAgent,locale:e.locale,timezone:e.timezone,colorScheme:e.colorScheme});return{content:[{type:`text`,text:JSON.stringify(t,null,2)}]}}catch(e){return{content:[{type:`text`,text:e instanceof Error?e.message:String(e)}],isError:!0}}}};Gr=Wr=A([(0,u.injectable)(),N(0,(0,u.inject)(O.ProfileService)),k(`design:paramtypes`,[Object])],Gr);var Kr;let qr=class{static{Kr=this}static TOOL_NAME=`browser_delete_profile`;constructor(e){this.profileService=e}getDefinition(){return{name:Kr.TOOL_NAME,description:`Deletes a browser profile and all its associated storage state data.`,inputSchema:{type:`object`,properties:{name:{type:`string`,description:`Name of the profile to delete`}},required:[`name`],additionalProperties:!1}}}async execute(e){try{return await this.profileService.delete(e.name),{content:[{type:`text`,text:JSON.stringify({success:!0,message:`Profile "${e.name}" deleted successfully`},null,2)}]}}catch(e){return{content:[{type:`text`,text:`Error: ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}}};qr=Kr=A([(0,u.injectable)(),N(0,(0,u.inject)(O.ProfileService)),k(`design:paramtypes`,[Object])],qr);var Jr;let Yr=class{static{Jr=this}static TOOL_NAME=`discover_specs`;constructor(e){this.specDiscoveryService=e}getDefinition(){return{name:Jr.TOOL_NAME,description:`Discovers e2e projects (directories with playwright.config.ts) and their spec files. Use to find available specs before running them.`,inputSchema:{type:`object`,properties:{basePath:{type:`string`,description:`Base path to search for e2e projects (default: current working directory)`},projectName:{type:`string`,description:`Filter by project name (e.g., 'boomlink-e2e')`},specPattern:{type:`string`,description:`Filter specs by name pattern (supports * and ? wildcards, e.g., "auth*", "*.spec.ts")`},includeMetadata:{type:`boolean`,description:`Include metadata like hasArgsSchema detection (default: true)`,default:!0}},additionalProperties:!1}}}async execute(e){try{let t=e.basePath||process.cwd(),n=e.includeMetadata!==!1;if(e.projectName||e.specPattern){let r=await this.specDiscoveryService.filterSpecs(t,{projectName:e.projectName,specPattern:e.specPattern}),i={filter:{basePath:t,projectName:e.projectName,specPattern:e.specPattern},totalSpecs:r.length,specs:r.map(e=>({name:e.name,path:e.path,relativePath:e.relativePath,...n&&{hasArgsSchema:e.hasArgsSchema}}))};return{content:[{type:`text`,text:JSON.stringify(i,null,2)}]}}let r=await this.specDiscoveryService.discoverProjects(t),i={basePath:t,totalProjects:r.length,totalSpecs:r.reduce((e,t)=>e+t.specs.length,0),projects:r.map(e=>({name:e.name,path:e.path,configPath:e.configPath,testDir:e.testDir,specCount:e.specs.length,specs:e.specs.map(e=>({name:e.name,path:e.path,relativePath:e.relativePath,...n&&{hasArgsSchema:e.hasArgsSchema}}))}))};return{content:[{type:`text`,text:JSON.stringify(i,null,2)}]}}catch(e){return{content:[{type:`text`,text:`Error discovering specs: ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}}};Yr=Jr=A([(0,u.injectable)(),N(0,(0,u.inject)(O.SpecDiscoveryService)),k(`design:paramtypes`,[Object])],Yr);var Xr;let Zr=class extends Z{static{Xr=this}static TOOL_NAME=`browser_drag`;constructor(e,t,n,r){super(e,t,n),this.elementLocator=r}getDefinition(){return{name:Xr.TOOL_NAME,description:`Drags an element to a target location or element.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Page ID to operate on`},source:{type:`object`,description:`Source element selector`,properties:{selector:{type:`string`,description:`CSS selector`},xpath:{type:`string`,description:`XPath expression`},text:{type:`string`,description:`Text content to match`},uid:{type:`string`,description:`Accessibility snapshot UID`},frame:{type:`string`,description:`Frame selector`}}},target:{type:`object`,description:`Target element selector or coordinates`,properties:{selector:{type:`string`,description:`CSS selector`},xpath:{type:`string`,description:`XPath expression`},text:{type:`string`,description:`Text content to match`},uid:{type:`string`,description:`Accessibility snapshot UID`},frame:{type:`string`,description:`Frame selector`},x:{type:`number`,description:`X coordinate`},y:{type:`number`,description:`Y coordinate`}}},force:{type:`boolean`,description:`Bypass actionability checks`,default:!1},timeout:{type:`number`,description:`Timeout in milliseconds`,default:M}},required:[`pageId`,`source`,`target`],additionalProperties:!1}}}async execute(e){return this.executeWithMode(Xr.TOOL_NAME,e.pageId,e,async()=>{let t=this.resolvePage(e.pageId),n=await this.elementLocator.locate(t,e.source);if(`x`in e.target&&`y`in e.target)await n.dragTo(t.locator(`body`),{targetPosition:{x:e.target.x,y:e.target.y},force:e.force,timeout:e.timeout});else{let r=await this.elementLocator.locate(t,e.target);await n.dragTo(r,{force:e.force,timeout:e.timeout})}return this.success(`Dragged element successfully`)})}};Zr=Xr=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),N(3,(0,u.inject)(O.ElementLocatorService)),k(`design:paramtypes`,[Object,Object,Object,Object])],Zr);var Qr;let $r=class extends Z{static{Qr=this}static TOOL_NAME=`browser_emulate`;getDefinition(){return{name:Qr.TOOL_NAME,description:`Emulates device characteristics like geolocation, timezone, locale, color scheme, and network conditions.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Optional page ID to override browser current page`},geolocation:{type:`object`,description:`Geolocation coordinates to emulate`,properties:{latitude:{type:`number`,minimum:-90,maximum:90},longitude:{type:`number`,minimum:-180,maximum:180},accuracy:{type:`number`,minimum:0}},required:[`latitude`,`longitude`]},locale:{type:`string`,description:`Locale to emulate (e.g., "en-US", "de-DE")`},timezone:{type:`string`,description:`Timezone to emulate (e.g., "America/New_York", "Europe/London")`},userAgent:{type:`string`,description:`User agent string to use`},offline:{type:`boolean`,description:`Whether to emulate offline mode`},colorScheme:{type:`string`,enum:[`light`,`dark`,`no-preference`],description:`Color scheme preference`},reducedMotion:{type:`string`,enum:[`reduce`,`no-preference`],description:`Reduced motion preference`}},required:[`pageId`],additionalProperties:!1}}}async execute(e){return this.safeExecute(async()=>{let t=this.resolvePageEntry(e.pageId),n=t.context,r=t.page;if(!n||!r)return this.error(`Page "${e.pageId}" is in extension mode and cannot be emulated via Playwright`);let i={};return e.geolocation&&(await n.setGeolocation(e.geolocation),i.geolocation=e.geolocation),e.offline!==void 0&&(await n.setOffline(e.offline),i.offline=e.offline),e.colorScheme&&(await r.emulateMedia({colorScheme:e.colorScheme}),i.colorScheme=e.colorScheme),e.reducedMotion&&(await r.emulateMedia({reducedMotion:e.reducedMotion}),i.reducedMotion=e.reducedMotion),e.locale&&(i.locale=e.locale,i.localeNote=`Locale changes may require a new browser context to take full effect`),e.timezone&&(i.timezone=e.timezone,i.timezoneNote=`Timezone changes may require a new browser context to take full effect`),e.userAgent&&(i.userAgent=e.userAgent,i.userAgentNote=`User agent changes may require a new browser context to take full effect`),this.successJson({success:!0,pageId:t.id,appliedSettings:i})})}};$r=Qr=A([(0,u.injectable)()],$r);var ei;let ti=class extends Z{static{ei=this}static TOOL_NAME=`browser_evaluate_script`;constructor(e,t,n){super(e,t,n)}getDefinition(){return{name:ei.TOOL_NAME,description:`Executes JavaScript code in the page context and returns the result. The script can be a function body or an expression.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Optional page ID to override browser current page`},script:{type:`string`,description:`JavaScript code to execute. Can be a function body or expression (e.g., "document.title" or "() => window.location.href")`},arg:{description:`Optional argument to pass to the script if it is a function`}},required:[`pageId`,`script`],additionalProperties:!1}}}async execute(e){return this.executeWithMode(ei.TOOL_NAME,e.pageId,{script:e.script,arg:e.arg},async()=>{let t=await this.resolvePage(e.pageId).evaluate(e.script,e.arg),n;try{n=JSON.stringify(t,null,2)}catch{n=String(t)}let r=`evaluate-${(0,E.randomUUID)()}.json`,i=(0,p.join)((0,S.tmpdir)(),r);return await(0,w.writeFile)(i,n,`utf-8`),this.success(`Result saved to: ${i}`)})}};ti=ei=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),k(`design:paramtypes`,[Object,Object,Object])],ti);var ni;let ri=class extends Z{static{ni=this}static TOOL_NAME=`browser_expect`;getDefinition(){return{name:ni.TOOL_NAME,description:`Performs Playwright expect() assertions on page elements. Supports various assertion types like toBeVisible, toHaveText, toHaveValue, toBeEnabled, etc.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Optional page ID to override browser current page`},selector:{type:`string`,description:`CSS selector for the element to assert on (not required for page-level assertions like toHaveTitle, toHaveURL)`},assertion:{type:`string`,enum:[`toBeVisible`,`toBeHidden`,`toBeEnabled`,`toBeDisabled`,`toBeChecked`,`toBeEditable`,`toBeFocused`,`toBeEmpty`,`toHaveText`,`toContainText`,`toHaveValue`,`toHaveAttribute`,`toHaveClass`,`toHaveCount`,`toHaveCSS`,`toHaveId`,`toHaveTitle`,`toHaveURL`],description:`Type of assertion to perform`},expected:{oneOf:[{type:`string`},{type:`number`}],description:`Expected value for assertions that require one (e.g., toHaveText, toHaveValue)`},attributeName:{type:`string`,description:`Attribute name for toHaveAttribute or toHaveCSS assertion`},not:{type:`boolean`,description:`Whether to negate the assertion (not.toBeVisible, etc.)`},timeout:{type:`number`,description:`Timeout in milliseconds for the assertion (default: 5000)`}},required:[`pageId`,`assertion`],additionalProperties:!1}}}async execute(e){return this.safeExecute(async()=>{let t=this.resolvePage(e.pageId),{selector:n,assertion:r,expected:i,attributeName:a,not:o,timeout:s=5e3}=e,l=[`toHaveTitle`,`toHaveURL`];if(!l.includes(r)&&!n)return this.error(`Selector is required for assertion type: ${r}`);try{if(l.includes(r)){let e=o?c.t(t).not:c.t(t);r===`toHaveTitle`?await e.toHaveTitle(i,{timeout:s}):r===`toHaveURL`&&await e.toHaveURL(i,{timeout:s})}else{let e=t.locator(n),l=o?c.t(e).not:c.t(e);switch(r){case`toBeVisible`:await l.toBeVisible({timeout:s});break;case`toBeHidden`:await l.toBeHidden({timeout:s});break;case`toBeEnabled`:await l.toBeEnabled({timeout:s});break;case`toBeDisabled`:await l.toBeDisabled({timeout:s});break;case`toBeChecked`:await l.toBeChecked({timeout:s});break;case`toBeEditable`:await l.toBeEditable({timeout:s});break;case`toBeFocused`:await l.toBeFocused({timeout:s});break;case`toBeEmpty`:await l.toBeEmpty({timeout:s});break;case`toHaveText`:await l.toHaveText(i,{timeout:s});break;case`toContainText`:await l.toContainText(i,{timeout:s});break;case`toHaveValue`:await l.toHaveValue(i,{timeout:s});break;case`toHaveAttribute`:if(!a)return this.error(`attributeName is required for toHaveAttribute assertion`);await l.toHaveAttribute(a,i,{timeout:s});break;case`toHaveClass`:await l.toHaveClass(i,{timeout:s});break;case`toHaveCount`:await l.toHaveCount(i,{timeout:s});break;case`toHaveCSS`:if(!a)return this.error(`attributeName (CSS property name) is required for toHaveCSS assertion`);await l.toHaveCSS(a,i,{timeout:s});break;case`toHaveId`:await l.toHaveId(i,{timeout:s});break;default:return this.error(`Unsupported assertion type: ${r}`)}}return this.successJson({success:!0,assertion:o?`not.${r}`:r,selector:n??null,passed:!0})}catch(e){let t=e instanceof Error?e.message:`Assertion failed`;return this.successJson({success:!0,assertion:o?`not.${r}`:r,selector:n??null,passed:!1,failureMessage:t})}})}};ri=ni=A([(0,u.injectable)()],ri);var ii;let ai=class extends Z{static{ii=this}static TOOL_NAME=`browser_fill`;constructor(e,t,n,r){super(e,t,n),this.elementLocator=r}getDefinition(){return{name:ii.TOOL_NAME,description:`Fills an input field with text, clearing any existing content first. Use for form inputs, textareas, and contenteditable elements.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Page ID to operate on`},selector:{type:`string`,description:`CSS selector`},xpath:{type:`string`,description:`XPath expression`},text:{type:`string`,description:`Text content to match`},uid:{type:`string`,description:`Accessibility snapshot UID`},frame:{type:`string`,description:`Frame selector`},value:{type:`string`,description:`The text value to fill into the input`},force:{type:`boolean`,description:`Bypass actionability checks`,default:!1},timeout:{type:`number`,description:`Timeout in milliseconds`,default:M}},required:[`pageId`,`value`],additionalProperties:!1}}}async execute(e){return this.executeWithMode(ii.TOOL_NAME,e.pageId,e,async()=>{let t=this.resolvePage(e.pageId);return await(await this.elementLocator.locate(t,e)).fill(e.value,{force:e.force,timeout:e.timeout}),this.success(`Filled element with: "${e.value}"`)})}};ai=ii=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),N(3,(0,u.inject)(O.ElementLocatorService)),k(`design:paramtypes`,[Object,Object,Object,Object])],ai);var oi;let si=class extends Z{static{oi=this}static TOOL_NAME=`browser_get_network_request`;constructor(e,t,n,r){super(e,t,n),this.pageMonitor=r}getDefinition(){return{name:oi.TOOL_NAME,description:`Retrieves detailed information about a specific network request by ID, including headers, body, and response data.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Optional page ID to override browser current page`},requestId:{type:`string`,description:`The ID of the network request to retrieve (e.g., "req-1")`}},required:[`pageId`,`requestId`],additionalProperties:!1}}}async execute(e){return this.safeExecute(async()=>{let t=this.resolvePageEntry(e.pageId),n=this.pageMonitor.getNetworkRequest(t.id,e.requestId);return n?this.successJson({id:n.id,url:n.url,method:n.method,resourceType:n.resourceType,headers:n.headers,postData:n.postData,timestamp:n.timestamp.toISOString(),response:n.response?{status:n.response.status,statusText:n.response.statusText,headers:n.response.headers,timing:n.response.timing}:null}):this.error(`Network request "${e.requestId}" not found for page "${t.id}"`)})}};si=oi=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),N(3,(0,u.inject)(O.PageMonitorService)),k(`design:paramtypes`,[Object,Object,Object,Object])],si);var ci;let li=class extends Z{static{ci=this}static TOOL_NAME=`browser_go_back`;constructor(e,t,n){super(e,t,n)}getDefinition(){return{name:ci.TOOL_NAME,description:`Navigates the browser back in history.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Page ID to operate on`},waitUntil:{type:`string`,enum:[`load`,`domcontentloaded`,`networkidle`,`commit`],description:`Wait until condition`,default:`load`},timeout:{type:`number`,description:`Timeout in milliseconds`,default:M}},required:[`pageId`],additionalProperties:!1}}}async execute(e){return this.executeWithMode(ci.TOOL_NAME,e.pageId,e,async()=>{let t=await this.resolvePage(e.pageId).goBack({waitUntil:e.waitUntil,timeout:e.timeout});if(t===null)return this.success(`No previous page in history`);let n=t.status();return this.success(`Navigated back (status: ${n})`)})}};li=ci=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),k(`design:paramtypes`,[Object,Object,Object])],li);var ui;let di=class extends Z{static{ui=this}static TOOL_NAME=`browser_go_forward`;constructor(e,t,n){super(e,t,n)}getDefinition(){return{name:ui.TOOL_NAME,description:`Navigates the browser forward in history.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Page ID to operate on`},waitUntil:{type:`string`,enum:[`load`,`domcontentloaded`,`networkidle`,`commit`],description:`Wait until condition`,default:`load`},timeout:{type:`number`,description:`Timeout in milliseconds`,default:M}},required:[`pageId`],additionalProperties:!1}}}async execute(e){return this.executeWithMode(ui.TOOL_NAME,e.pageId,e,async()=>{let t=await this.resolvePage(e.pageId).goForward({waitUntil:e.waitUntil,timeout:e.timeout});if(t===null)return this.success(`No next page in history`);let n=t.status();return this.success(`Navigated forward (status: ${n})`)})}};di=ui=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),k(`design:paramtypes`,[Object,Object,Object])],di);var fi;let pi=class extends Z{static{fi=this}static TOOL_NAME=`browser_handle_dialog`;constructor(e,t,n){super(e,t,n)}getDefinition(){return{name:fi.TOOL_NAME,description:`Handles JavaScript dialogs (alert, confirm, prompt) by accepting or dismissing them. Set up a listener before triggering the action that opens the dialog.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Optional page ID to override browser current page`},accept:{type:`boolean`,description:`Whether to accept (true) or dismiss (false) the dialog`},promptText:{type:`string`,description:`Text to enter for prompt dialogs (only used when accept is true)`},timeout:{type:`number`,description:`Timeout in milliseconds to wait for dialog (default: ${M})`,default:M}},required:[`pageId`,`accept`],additionalProperties:!1}}}async execute(e){return this.safeExecute(()=>this.executeWithMode(fi.TOOL_NAME,e.pageId,{accept:e.accept,promptText:e.promptText,timeout:e.timeout},async()=>{let t=this.resolvePage(e.pageId),n=e.timeout??M,r=await new Promise((e,r)=>{let i=setTimeout(()=>{t.off(`dialog`,a),r(Error(`Timeout waiting for dialog after ${n}ms`))},n),a=t=>{clearTimeout(i),e(t)};t.once(`dialog`,a)}),i={type:r.type(),message:r.message(),defaultValue:r.defaultValue()};return e.accept?await r.accept(e.promptText):await r.dismiss(),this.successJson({handled:!0,action:e.accept?`accepted`:`dismissed`,dialogType:i.type,dialogMessage:i.message,defaultValue:i.defaultValue,promptText:e.promptText})}))}};pi=fi=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),k(`design:paramtypes`,[Object,Object,Object])],pi);var mi;let hi=class extends Z{static{mi=this}static TOOL_NAME=`browser_hover`;constructor(e,t,n,r){super(e,t,n),this.elementLocator=r}getDefinition(){return{name:mi.TOOL_NAME,description:`Hovers over an element to trigger hover states, tooltips, or dropdown menus.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Page ID to operate on`},selector:{type:`string`,description:`CSS selector`},xpath:{type:`string`,description:`XPath expression`},text:{type:`string`,description:`Text content to match`},uid:{type:`string`,description:`Accessibility snapshot UID`},frame:{type:`string`,description:`Frame selector`},position:{type:`object`,properties:{x:{type:`number`},y:{type:`number`}},description:`Position offset within element`},modifiers:{type:`array`,items:{type:`string`,enum:[`Alt`,`Control`,`Meta`,`Shift`]},description:`Modifier keys to hold`},force:{type:`boolean`,description:`Bypass actionability checks`,default:!1},timeout:{type:`number`,description:`Timeout in milliseconds`,default:M}},required:[`pageId`],additionalProperties:!1}}}async execute(e){return this.executeWithMode(mi.TOOL_NAME,e.pageId,e,async()=>{let t=this.resolvePage(e.pageId);return await(await this.elementLocator.locate(t,e)).hover({position:e.position,modifiers:e.modifiers,force:e.force,timeout:e.timeout}),this.success(`Hovered over element successfully`)})}};hi=mi=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),N(3,(0,u.inject)(O.ElementLocatorService)),k(`design:paramtypes`,[Object,Object,Object,Object])],hi);var gi;const _i=[`pnpm-workspace.yaml`,`nx.json`,`.git`],vi=`about:blank`,yi=`browser-extension-`,bi=`browse-tool-http`,xi=`tool`,Si=`development`,Ci=`host.docker.internal`,wi=`[LaunchBrowserTool]`,Ti=new Set([`docker`,`docker-vm`,`docker-chromium`,`docker-chrome-testing`]);function Ei(e=process.cwd()){let t=p.default.resolve(e);for(;;){for(let e of _i)if((0,f.existsSync)(p.default.join(t,e)))return t;let e=p.default.dirname(t);if(e===t)return process.cwd();t=e}}let Di=class{static{gi=this}static TOOL_NAME=`browser_launch`;constructor(e,t){this.browserService=e,this.stealthLauncher=t}getDefinition(){return{name:gi.TOOL_NAME,description:`Launches a new browser instance. Returns browserId and pageId for subsequent browser operations. Use mode "extension" for bot-detection-free automation via Chrome extension, or mode "vm" for isolated runtime launch.`,inputSchema:{type:`object`,properties:{mode:{type:`string`,enum:[`playwright`,`extension`,`vm`,`stealth`],description:`Execution mode. "playwright" uses Playwright APIs. "extension" uses Playwright with Chrome extension. "vm" launches in an isolated runtime (for example via Docker). "stealth" spawns Chrome directly without automation flags.`,default:`playwright`},browserType:{type:`string`,enum:[`chromium`,`firefox`,`webkit`],description:`Browser type to use (only applies to playwright mode)`,default:`chromium`},headless:{type:`boolean`,description:`Run browser in headless mode (only applies to playwright mode)`,default:!0},url:{type:`string`,description:`Optional URL to navigate to after launch`},profileName:{type:`string`,description:`Optional profile name to use for browser settings and persistent storage`},vmCommand:{type:`string`,description:`Executable/alias for vm mode launch (e.g., "docker" for isolated container runtime)`},vmCommandArgs:{type:`array`,description:`Browser arguments for vm command runtime`,items:{type:`string`}},vmUseChromeForTesting:{type:`boolean`,description:`When true, vm mode prefers Chrome for Testing. If command is omitted, "chrome-testing" alias, or generic "chrome", this resolves to Chrome for Testing.`,default:!0},vmBrowserId:{type:`string`,description:`Optional browserId override for vm mode`},startupDelayMs:{type:`number`,description:`Optional startup delay in milliseconds before returning in vm mode`},vmServerUrl:{type:`string`,description:`Explicit MCP server URL reachable from inside VM (e.g., "http://host.docker.internal:3200"). Overrides registry discovery.`},vmExtensionPath:{type:`string`,description:`Explicit extension path that exists inside VM filesystem. Useful when VM does not share host workspace paths.`},vmEnableVnc:{type:`boolean`,description:`Expose VNC/noVNC ports when using Docker VM runtime`,default:!1},vmVncPort:{type:`number`,description:`Host port for VNC (container port 5900) when vmEnableVnc is true`,minimum:1,maximum:65535},vmNoVncPort:{type:`number`,description:`Host port for noVNC web UI (container port 7900) when vmEnableVnc is true`,minimum:1,maximum:65535},vmVncPassword:{type:`string`,description:`Optional VNC password for Docker VM runtime`},baseURL:{type:`string`,description:`Base URL for relative navigation (e.g., page.goto("/") will use this as the base)`},videoDir:{type:`string`,description:`Directory to save video recordings. If provided, video will be recorded for all pages. Videos are saved when the page or context is closed.`},proxy:{type:`object`,description:`Proxy configuration for routing browser traffic through a proxy server. Supports authenticated residential proxies.`,properties:{server:{type:`string`,description:`Proxy server URL (e.g., "http://proxy.example.com:8080")`},username:{type:`string`,description:`Proxy username for authentication`},password:{type:`string`,description:`Proxy password for authentication`},bypass:{type:`string`,description:`Comma-separated list of hosts to bypass the proxy (e.g., "localhost,127.0.0.1")`}},required:[`server`],additionalProperties:!1}},required:[],additionalProperties:!1}}}async execute(e){let t=e.mode??`playwright`;try{return t===`stealth`?await this.launchStealthMode(e):t===`vm`?await this.launchVmMode(e):t===`extension`?await this.launchExtensionMode(e):await this.launchPlaywrightMode(e)}catch(e){return{content:[{type:`text`,text:e instanceof Error?e.message:String(e)}],isError:!0}}}async launchPlaywrightMode(e){let t=await this.browserService.launch({browserType:e.browserType,headless:e.headless,profileName:e.profileName,baseURL:e.baseURL,recordVideo:e.videoDir?{dir:e.videoDir}:void 0,proxy:e.proxy});return e.url&&await t.page.goto(e.url),{content:[{type:`text`,text:JSON.stringify({browserId:t.browserInstance.id,pageId:t.pageId,mode:`playwright`,url:e.url??t.page.url()},null,2)}]}}async launchStealthMode(e){let t=await this.stealthLauncher.launch({url:e.url,profileName:e.profileName,proxy:e.proxy});return{content:[{type:`text`,text:JSON.stringify({browserId:t.id,pageId:`page-${t.id}`,mode:`stealth`,url:e.url??`about:blank`,pid:t.pid},null,2)}]}}async launchExtensionMode(e){let t=e.profileName?`browser-${e.profileName}`:`browser-extension-${(0,E.randomUUID)()}`,n=e.url??vi,r=await this.resolveExtensionBootstrapServerUrl(),i=this.buildVmBootstrapUrl(r,t,n),a=await this.browserService.launchWithExtension({url:i,baseURL:e.baseURL,profileName:e.profileName,recordVideo:e.videoDir?{dir:e.videoDir}:void 0,proxy:e.proxy,mode:`extension`,browserId:t});return{content:[{type:`text`,text:JSON.stringify({browserId:a.browserInstance.id,pageId:a.pageId,mode:`extension`,url:n,pid:a.process.pid},null,2)}]}}async launchVmMode(e){let t=e.vmBrowserId??`browser-vm-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,n=e.url??vi,r=e.vmCommand??`docker`,i=await this.resolveVmBootstrapServerUrl(e.vmServerUrl,r),a=this.buildVmBootstrapUrl(i,t,n),o=this.buildVmDockerRuntimeOptions(e),s=await this.browserService.launchWithExtension({url:a,baseURL:e.baseURL,profileName:e.profileName,recordVideo:e.videoDir?{dir:e.videoDir}:void 0,proxy:e.proxy,extensionPath:e.vmExtensionPath??process.env.PLAYWRIGHT_VM_EXTENSION_PATH,mode:`vm`,useChromeForTesting:e.vmUseChromeForTesting??!0,command:r,commandArgs:e.vmCommandArgs,dockerRunArgs:o.runArgs,dockerEnv:o.env,dockerEnableVnc:o.enableVnc,browserId:t,startupDelayMs:e.startupDelayMs}),c=o.vnc?{vncUrl:o.vnc.vncUrl,noVncUrl:o.vnc.noVncUrl}:void 0;return{content:[{type:`text`,text:JSON.stringify({browserId:s.browserInstance.id,pageId:s.pageId,mode:`vm`,url:n,pid:s.process.pid,...c?{vm:c}:{}},null,2)}]}}buildVmBootstrapUrl(e,t,n){let r=new URL(e);return r.searchParams.set(`playwright_mcp_connect`,`1`),r.searchParams.set(`playwright_mcp_server`,e),r.searchParams.set(`playwright_mcp_browser_id`,t),r.searchParams.set(`playwright_mcp_navigate`,n),r.toString()}async resolveVmBootstrapServerUrl(e,t){let n=e??process.env.PLAYWRIGHT_VM_SERVER_URL;if(n)return this.normalizeVmServerUrl(n);let r=B(),i=await this.getRegisteredPort(r);return this.isDockerVmCommand(t??`docker`)?V(`host.docker.internal`,i.port):V(i.host,i.port)}async resolveExtensionBootstrapServerUrl(){let e=B(),t=await this.getRegisteredPort(e);return V(t.host,t.port)}normalizeVmServerUrl(e){let t;try{t=new URL(e)}catch{throw Error(`Invalid vmServerUrl: "${e}"`)}if(t.protocol!==`http:`&&t.protocol!==`https:`)throw Error(`vmServerUrl must use http or https: "${e}"`);return t.origin}isDockerVmCommand(e){return Ti.has(e.trim().toLowerCase())}buildVmDockerRuntimeOptions(e){let t=e.vmEnableVnc||e.vmVncPort!==void 0||e.vmNoVncPort!==void 0,n=[],r={},i;if(t){let t=e.vmVncPort??5901,r=e.vmNoVncPort??7901;n.push(`-p`,`${t}:5900`,`-p`,`${r}:7900`),i={vncUrl:`vnc://localhost:${t}`,noVncUrl:`http://localhost:${r}/`}}return e.vmVncPassword&&e.vmVncPassword.trim().length>0&&(r.SE_VNC_PASSWORD=e.vmVncPassword.trim()),{runArgs:n.length>0?n:void 0,env:Object.keys(r).length>0?r:void 0,enableVnc:t,vnc:i}}getFallbackPort(){try{return Qt()}catch{return 3200}}isValidPort(e){return typeof e==`number`&&Number.isInteger(e)&&e>0&&e<=65535}getLatestRegistryEntry(e){return e.length===0?null:[...e].sort((e,t)=>{let n=Number.isNaN(Date.parse(e.updatedAt))?0:Date.parse(e.updatedAt);return(Number.isNaN(Date.parse(t.updatedAt))?0:Date.parse(t.updatedAt))-n})[0]??null}async getRegisteredPort(e){let t={host:e,port:this.getFallbackPort()},n=Ei(process.cwd()),r=process.env.NODE_ENV||`development`,i=new x.PortRegistryService(process.env.PORT_REGISTRY_PATH);try{let t=await i.getPort({repositoryPath:n,serviceName:bi,serviceType:xi,environment:r});if(t.success&&t.record&&this.isValidPort(t.record.port))return{host:t.record.host||e,port:t.record.port}}catch(e){let t=e instanceof Error?e.message:String(e);console.warn(`${wi} Scoped registry lookup failed for ${bi} in ${r}: ${t}`)}try{let n=await i.listAllocations({serviceName:bi,serviceType:xi,environment:r}),a=this.getLatestRegistryEntry(n);return!a||!this.isValidPort(a.port)?t:{host:a.host||e,port:a.port}}catch(e){let n=e instanceof Error?e.message:String(e);return console.warn(`${wi} Global registry lookup failed for ${bi} in ${r}: ${n}`),t}}};Di=gi=A([(0,u.injectable)(),N(0,(0,u.inject)(O.BrowserService)),N(1,(0,u.inject)(O.StealthLauncher)),k(`design:paramtypes`,[Object,Object])],Di);var Oi;let ki=class extends Z{static{Oi=this}static TOOL_NAME=`browser_list_console_messages`;constructor(e,t,n,r){super(e,t,n),this.pageMonitor=r}getDefinition(){return{name:Oi.TOOL_NAME,description:`Lists all console messages captured during page automation. Requires monitoring to be started first.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Optional page ID to override browser current page`},type:{type:`string`,description:`Filter by message type (log, info, warning, error, debug, trace, etc.)`,enum:[`log`,`info`,`warning`,`error`,`debug`,`trace`,`dir`,`dirxml`,`table`,`count`,`assert`]},limit:{type:`number`,description:`Maximum number of messages to return`,minimum:1}},required:[`pageId`],additionalProperties:!1}}}async execute(e){return this.safeExecute(async()=>{let t=this.resolvePageEntry(e.pageId),n=this.pageMonitor.getConsoleMessages(t.id,e.type);return e.limit&&(n=n.slice(0,e.limit)),this.successJson({pageId:t.id,messageCount:n.length,messages:n.map(e=>({id:e.id,type:e.type,text:e.text,location:e.location,timestamp:e.timestamp.toISOString()}))})})}};ki=Oi=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),N(3,(0,u.inject)(O.PageMonitorService)),k(`design:paramtypes`,[Object,Object,Object,Object])],ki);var Ai;let ji=class extends Z{static{Ai=this}static TOOL_NAME=`browser_list_network_requests`;constructor(e,t,n,r){super(e,t,n),this.pageMonitor=r}getDefinition(){return{name:Ai.TOOL_NAME,description:`Lists all network requests captured during page automation. Requires monitoring to be started first.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Optional page ID to override browser current page`},resourceType:{type:`string`,description:`Filter by resource type (document, xhr, fetch, script, stylesheet, image, etc.)`},urlPattern:{type:`string`,description:`Filter by URL pattern (substring match)`},method:{type:`string`,description:`Filter by HTTP method (GET, POST, etc.)`},limit:{type:`number`,description:`Maximum number of requests to return`,minimum:1}},required:[`pageId`],additionalProperties:!1}}}async execute(e){return this.safeExecute(async()=>{let t=this.resolvePageEntry(e.pageId),n=this.pageMonitor.getNetworkRequests(t.id);return e.resourceType&&(n=n.filter(t=>t.resourceType===e.resourceType)),e.urlPattern&&(n=n.filter(t=>t.url.includes(e.urlPattern))),e.method&&(n=n.filter(t=>t.method===e.method)),e.limit&&(n=n.slice(0,e.limit)),this.successJson({pageId:t.id,requestCount:n.length,requests:n.map(e=>({id:e.id,url:e.url,method:e.method,resourceType:e.resourceType,status:e.response?.status,statusText:e.response?.statusText,timing:e.response?.timing,timestamp:e.timestamp.toISOString()}))})})}};ji=Ai=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),N(3,(0,u.inject)(O.PageMonitorService)),k(`design:paramtypes`,[Object,Object,Object,Object])],ji);var Mi;let Ni=class extends Z{static{Mi=this}static TOOL_NAME=`browser_list_pages`;constructor(e,t,n){super(e,t,n)}getDefinition(){return{name:Mi.TOOL_NAME,description:`Lists all pages (tabs) in a browser. Returns page IDs, URLs, titles, and indicates which page is currently active.`,inputSchema:{type:`object`,properties:{browserId:{type:`string`,description:`Browser ID to list pages for`}},required:[`browserId`],additionalProperties:!1}}}async execute(e){return this.toolExecutor.executeForBrowser(Mi.TOOL_NAME,e.browserId,e,async()=>{let t=this.browserService.getBrowser(e.browserId);if(!t)return this.error(`Browser "${e.browserId}" not found`);let n=this.pageRegistry.findByBrowser(e.browserId),r=await Promise.all(n.map(async e=>{await this.pageRegistry.updateMetadata(e.id);let n=this.pageRegistry.get(e.id);return{pageId:e.id,url:n?.url??e.url,title:n?.title??e.title,isActive:e.id===t.currentPageId,browserId:e.browserId,profileName:e.profileName,createdAt:e.createdAt.toISOString()}}));return this.successJson({browserId:e.browserId,currentPageId:t.currentPageId,pageCount:r.length,pages:r})})}};Ni=Mi=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),k(`design:paramtypes`,[Object,Object,Object])],Ni);var Pi;let Fi=class{static{Pi=this}static TOOL_NAME=`browser_list_profiles`;constructor(e){this.profileService=e}getDefinition(){return{name:Pi.TOOL_NAME,description:`Lists all available browser profiles with their settings, browser type, viewport, and timestamps.`,inputSchema:{type:`object`,properties:{},required:[],additionalProperties:!1}}}async execute(){try{let e=await this.profileService.list();return{content:[{type:`text`,text:JSON.stringify({profileCount:e.length,profiles:e.map(e=>({name:e.name,browserType:e.browserType,viewport:e.viewport??null,userAgent:e.userAgent??null,locale:e.locale??null,timezone:e.timezone??null,colorScheme:e.colorScheme??null,createdAt:e.createdAt,updatedAt:e.updatedAt}))},null,2)}]}}catch(e){return{content:[{type:`text`,text:`Error: ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}}};Fi=Pi=A([(0,u.injectable)(),N(0,(0,u.inject)(O.ProfileService)),k(`design:paramtypes`,[Object])],Fi);var Ii;let Li=class extends Z{static{Ii=this}static TOOL_NAME=`browser_navigate`;constructor(e,t,n){super(e,t,n)}getDefinition(){return{name:Ii.TOOL_NAME,description:`Navigates the browser to a specified URL.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Page ID to operate on`},url:{type:`string`,description:`URL to navigate to`},waitUntil:{type:`string`,enum:[`load`,`domcontentloaded`,`networkidle`,`commit`],description:`Wait until condition`,default:`load`},timeout:{type:`number`,description:`Timeout in milliseconds`,default:M},referer:{type:`string`,description:`Referer header value`}},required:[`pageId`,`url`],additionalProperties:!1}}}async execute(e){return this.executeWithMode(Ii.TOOL_NAME,e.pageId,e,async()=>{let t=(await this.resolvePage(e.pageId).goto(e.url,{waitUntil:e.waitUntil,timeout:e.timeout,referer:e.referer}))?.status()??`unknown`;return this.success(`Navigated to ${e.url} (status: ${t})`)})}};Li=Ii=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),k(`design:paramtypes`,[Object,Object,Object])],Li);var Ri;let zi=class extends Z{static{Ri=this}static TOOL_NAME=`browser_new_page`;constructor(e,t,n){super(e,t,n)}getDefinition(){return{name:Ri.TOOL_NAME,description:`Creates a new page (tab) in a browser instance. Uses the default browser if browserId is not specified, launching one if needed.`,inputSchema:{type:`object`,properties:{browserId:{type:`string`,description:`Browser ID to create the page in (optional - uses default browser if not specified)`},url:{type:`string`,description:`Optional URL to navigate to after creation`},setAsCurrent:{type:`boolean`,description:`Whether to set as current page for the browser (default: true)`,default:!0}},required:[],additionalProperties:!1}}}async execute(e){return this.safeExecute(async()=>{let t=e.browserId?this.browserService.getBrowser(e.browserId):await this.browserService.getOrCreateDefaultBrowser();if(!t)return this.error(`Browser "${e.browserId}" not found`);let n=t.id,r=e.setAsCurrent!==!1;if(t.mode===`extension`||t.mode===`vm`){let i=this.pageRegistry.registerExtensionPage(n,void 0,e.url,!1),a=await this.toolExecutor.executeForBrowser(Ri.TOOL_NAME,n,{...e,pageId:i},async()=>this.error(`Browser "${n}" is not in extension mode`));if(a.isError)return this.pageRegistry.remove(i),a;t.pageIds.add(i),(r||!t.currentPageId)&&(t.currentPageId=i);let o=a.content[0]?.type===`text`?a.content[0].text:void 0,s={};if(typeof o==`string`)try{s=JSON.parse(o)}catch{s={}}let c=this.pageRegistry.get(i);return c&&(c.url=s.url??c.url,c.title=s.title??c.title,c.extensionTabId=s.tabId??c.extensionTabId),this.browserService.recordBrowserActivity(n,i),this.successJson({pageId:i,url:c?.url??e.url??`about:blank`,title:c?.title??``,browserId:n,isActive:t.currentPageId===i})}let{pageId:i,page:a}=await this.browserService.newPage(n);if(e.url)try{await a.goto(e.url),await this.pageRegistry.updateMetadata(i)}catch(e){throw await a.close(),e}r&&this.browserService.setCurrentPage(n,i);let o=this.pageRegistry.get(i);return this.successJson({pageId:i,url:o?.url??a.url(),title:o?.title??``,browserId:n,isActive:r})})}};zi=Ri=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),k(`design:paramtypes`,[Object,Object,Object])],zi);var Q;let Bi=class extends Z{static{Q=this}static TOOL_NAME=`browser_pdf`;constructor(e,t,n,r){super(e,t,n),this.extensionTaskQueue=r}getDefinition(){return{name:Q.TOOL_NAME,description:`Generates a PDF of the page with configurable format options. Saves to temp directory and returns the file path.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Page ID to operate on`},format:{type:`string`,enum:[`Letter`,`Legal`,`Tabloid`,`Ledger`,`A0`,`A1`,`A2`,`A3`,`A4`,`A5`,`A6`],description:`Paper format`,default:`Letter`},printBackground:{type:`boolean`,description:`Print background graphics`,default:!1},landscape:{type:`boolean`,description:`Landscape orientation`,default:!1},scale:{type:`number`,description:`Page scale (0.1 to 2)`,minimum:.1,maximum:2,default:1},marginTop:{type:`string`,description:`Top margin (e.g., "1cm", "0.5in")`},marginBottom:{type:`string`,description:`Bottom margin`},marginLeft:{type:`string`,description:`Left margin`},marginRight:{type:`string`,description:`Right margin`},filename:{type:`string`,description:`Custom filename without extension`}},required:[`pageId`],additionalProperties:!1}}}async execute(e){let t=this.getPage(e.pageId);return t?t.mode===`extension`?this.safeExecute(async()=>{let n=e.filename??`page-${(0,E.randomUUID)()}`,r=(0,p.join)((0,S.tmpdir)(),`${n}.pdf`),i=await this.extensionTaskQueue.queueTask(Q.TOOL_NAME,{pageId:e.pageId,format:e.format,printBackground:e.printBackground,landscape:e.landscape,scale:e.scale,marginTop:e.marginTop,marginBottom:e.marginBottom,marginLeft:e.marginLeft,marginRight:e.marginRight,filename:n},void 0,t.browserId),a=JSON.parse(i.result?.content?.[0]?.text??`{}`);if(!a.pdfBase64)throw Error(`Extension mode PDF generation returned no data`);return await(0,w.writeFile)(r,Buffer.from(a.pdfBase64,`base64`)),this.success(`PDF saved to: ${r}`)}):this.executeWithMode(Q.TOOL_NAME,e.pageId,e,async()=>{let t=this.resolvePage(e.pageId),n=e.filename??`page-${(0,E.randomUUID)()}`,r=(0,p.join)((0,S.tmpdir)(),`${n}.pdf`);return await t.pdf({path:r,format:e.format??`Letter`,printBackground:e.printBackground??!1,landscape:e.landscape??!1,scale:e.scale??1,margin:{top:e.marginTop,bottom:e.marginBottom,left:e.marginLeft,right:e.marginRight}}),this.success(`PDF saved to: ${r}`)}):this.error(`Page "${e.pageId}" not found`)}};Bi=Q=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),N(3,(0,u.inject)(O.ExtensionTaskQueue)),k(`design:paramtypes`,[Object,Object,Object,Object])],Bi);var Vi;let Hi=class extends Z{static{Vi=this}static TOOL_NAME=`browser_press_key`;constructor(e,t,n,r){super(e,t,n),this.elementLocator=r}getDefinition(){return{name:Vi.TOOL_NAME,description:`Presses a keyboard key or key combination. Supports modifier keys like Control, Shift, Alt, Meta.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Page ID to operate on`},key:{type:`string`,description:`Key or key combination (e.g., "Enter", "Tab", "Control+a", "Meta+Shift+t", "ArrowDown")`},element:{type:`object`,description:`Optional element to focus before pressing key`,properties:{selector:{type:`string`,description:`CSS selector`},xpath:{type:`string`,description:`XPath expression`},text:{type:`string`,description:`Text content to match`},uid:{type:`string`,description:`Accessibility snapshot UID`},frame:{type:`string`,description:`Frame selector`}}},delay:{type:`number`,description:`Delay between keydown and keyup in ms`},timeout:{type:`number`,description:`Timeout in milliseconds`,default:M}},required:[`pageId`,`key`],additionalProperties:!1}}}async execute(e){return this.executeWithMode(Vi.TOOL_NAME,e.pageId,e,async()=>{let t=this.resolvePage(e.pageId);return e.element?await(await this.elementLocator.locate(t,e.element)).press(e.key,{delay:e.delay,timeout:e.timeout}):await t.keyboard.press(e.key,{delay:e.delay}),this.success(`Pressed key: "${e.key}"`)})}};Hi=Vi=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),N(3,(0,u.inject)(O.ElementLocatorService)),k(`design:paramtypes`,[Object,Object,Object,Object])],Hi);var $;let Ui=class extends Z{static{$=this}static TOOL_NAME=`browser_reload`;constructor(e,t,n){super(e,t,n)}getDefinition(){return{name:$.TOOL_NAME,description:`Reloads the current page.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Page ID to operate on`},waitUntil:{type:`string`,enum:[`load`,`domcontentloaded`,`networkidle`,`commit`],description:`Wait until condition`,default:`load`},timeout:{type:`number`,description:`Timeout in milliseconds`,default:M}},required:[`pageId`],additionalProperties:!1}}}async execute(e){return this.executeWithMode($.TOOL_NAME,e.pageId,e,async()=>{let t=(await this.resolvePage(e.pageId).reload({waitUntil:e.waitUntil,timeout:e.timeout}))?.status()??`unknown`;return this.success(`Page reloaded (status: ${t})`)})}};Ui=$=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),k(`design:paramtypes`,[Object,Object,Object])],Ui);var Wi;let Gi=class extends Z{static{Wi=this}static TOOL_NAME=`browser_resize_page`;constructor(e,t,n){super(e,t,n)}getDefinition(){return{name:Wi.TOOL_NAME,description:`Resizes the viewport of a page to specified width and height dimensions.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Optional page ID to override browser current page`},width:{type:`number`,description:`Viewport width in pixels`,minimum:1},height:{type:`number`,description:`Viewport height in pixels`,minimum:1},deviceScaleFactor:{type:`number`,description:`Device scale factor (default: 1)`,minimum:1,maximum:3},isMobile:{type:`boolean`,description:`Whether the meta viewport tag is taken into account`},hasTouch:{type:`boolean`,description:`Whether the viewport supports touch events`}},required:[`pageId`,`width`,`height`],additionalProperties:!1}}}async execute(e){return this.executeWithMode(Wi.TOOL_NAME,e.pageId,{width:e.width,height:e.height},async()=>{let t=this.resolvePage(e.pageId);await t.setViewportSize({width:e.width,height:e.height});let n=t.viewportSize();return this.successJson({success:!0,viewport:{width:n?.width??e.width,height:n?.height??e.height}})})}};Gi=Wi=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),k(`design:paramtypes`,[Object,Object,Object])],Gi);var Ki;let qi=class extends Z{static{Ki=this}static TOOL_NAME=`browser_run_code`;constructor(e,t,n,r){super(e,t,n),this.extensionPageProxy=r}getDefinition(){return{name:Ki.TOOL_NAME,description:`Runs a Playwright code snippet. The code should be an async function body that receives { page, context, browser } and can perform any Playwright operation. Return a value to include it in the response.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Optional page ID to override browser current page`},code:{type:`string`,description:`JavaScript code to execute. Receives { page, context, browser } as arguments. Example: "await page.goto('https://example.com'); return await page.title();"`}},required:[`pageId`,`code`],additionalProperties:!1}}}async execute(e){return this.safeExecute(async()=>{let t=this.resolvePageEntry(e.pageId),{page:n,context:r,browser:i}=t,a=t.mode===`extension`?(()=>(this.extensionPageProxy.setTarget(t.id,t.browserId),this.extensionPageProxy))():n,o=t.mode===`extension`?this.extensionPageProxy.context():r,s=t.mode===`extension`?{id:t.browserId,mode:this.browserService.getBrowser(t.browserId)?.mode??`extension`,pageId:t.id}:i,c=await Function(`page`,`context`,`browser`,`return (async () => { ${e.code} })();`)(a,o,s);return c===void 0?this.success(`Code executed successfully`):this.successJson({result:c})})}};qi=Ki=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),N(3,(0,u.inject)(O.ExtensionPageProxy)),k(`design:paramtypes`,[Object,Object,Object,Object])],qi);var Ji;const Yi=`run-spec-hooks.ts`,Xi=4,Zi={width:1920,height:1080};let Qi=class{static{Ji=this}static TOOL_NAME=`run_spec`;constructor(e,t,n,r,i){this.automationRunner=e,this.specMetadataService=t,this.extensionSpecRunner=n,this.extensionPageProxy=r,this.specBundlerService=i}getDefinition(){return{name:Ji.TOOL_NAME,description:`Runs a Playwright spec file with optional test filtering and dynamic arguments. Supports filtering by test name, pattern, or test.only markers.`,inputSchema:{type:`object`,properties:{specPath:{type:`string`,description:`Path to the Playwright spec file to execute`},automationId:{type:`string`,description:`Optional automation session ID (auto-generated if not provided)`},mode:{type:`string`,enum:[`playwright`,`extension`],description:`Execution mode: playwright (standard) or extension (Chrome extension)`,default:`playwright`},browserId:{type:`string`,description:`Browser ID to use (required for extension mode)`},pageId:{type:`string`,description:`Page ID to use (required for extension mode)`},browserType:{type:`string`,enum:[`chromium`,`firefox`,`webkit`],description:`Browser type to use (only applies to playwright mode)`,default:`chromium`},headless:{type:`boolean`,description:`Run browser in headless mode (only applies to playwright mode)`,default:!0},baseURL:{type:`string`,description:`Base URL for relative navigation (e.g., page.goto("/") will use this as the base)`},keepBrowserOpen:{type:`boolean`,description:`Keep browser open after spec execution completes for further interaction`,default:!1},hooksPath:{type:`string`,description:`Explicit path to run-spec-hooks.ts file. Skips auto-discovery when provided. The source directory is injected as process.env.__HOOKS_SOURCE_DIR__ so hooks can resolve paths relative to their original location.`},env:{type:`object`,description:`Environment variables to set before running the spec. Applied before hooks execution. Useful for passing config like API endpoints without relying on hooks file path resolution.`,additionalProperties:{type:`string`}},testName:{type:`string`,description:`Filter by exact test name`},testPattern:{type:`string`,description:`Filter by regex pattern on full test title (e.g., "login.*success")`},onlyMarked:{type:`boolean`,description:`Run only tests marked with test.only()`,default:!1},describeFilter:{type:`string`,description:`Filter by describe block name pattern`},specArgs:{type:`object`,description:`Arguments to pass to the spec (available as fixtures.specArgs)`,additionalProperties:!0},loadArgsFromEnv:{type:`boolean`,description:`Load specArgs from environment variables using spec's envPrefix export`,default:!1},videoDir:{type:`string`,description:`Directory to save video recordings. Supported in both playwright and extension modes.`}},required:[`specPath`],additionalProperties:!1}}}async execute(e){try{if(e.env)for(let[t,n]of Object.entries(e.env))process.env[t]=n;let t=await this.discoverAndRunHooks(e.specPath,e.hooksPath);return t?.baseURL&&!e.baseURL&&(e.baseURL=t.baseURL),(e.mode??`playwright`)===`extension`?await this.executeExtensionMode(e):e.testName||e.testPattern||e.onlyMarked||e.describeFilter||e.loadArgsFromEnv?await this.executeEnhanced(e):await this.executeBasic(e)}catch(e){return{content:[{type:`text`,text:`Error: ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}}findHooksFile(e){let t=(0,p.dirname)((0,p.resolve)(e));for(let e=0;e<4;e++){let e=(0,p.join)(t,`run-spec-hooks.ts`);if((0,f.existsSync)(e))return e;let n=(0,p.dirname)(t);if(n===t)break;t=n}return null}async runHooks(e){let t=(0,p.dirname)((0,p.resolve)(e)),n=await this.specBundlerService.bundle(e);try{process.env.__HOOKS_SOURCE_DIR__=t;let e=await import(`${n.outputPath}?t=${Date.now()}`);return typeof e.setup==`function`?await e.setup():void 0}finally{process.env.__HOOKS_SOURCE_DIR__=void 0,await n.cleanup()}}async discoverAndRunHooks(e,t){let n=t?(0,p.resolve)(t):this.findHooksFile(e);return n?await this.runHooks(n)??null:null}async executeExtensionMode(e){if(!e.pageId||!e.browserId)return{content:[{type:`text`,text:`Error: pageId and browserId are required for extension mode`}],isError:!0};this.extensionPageProxy.setTarget(e.pageId,e.browserId);let t=e.specArgs??{};if(e.loadArgsFromEnv){let n=await this.specMetadataService.extractSpecMetadata(e.specPath);n.argsSchema&&n.envPrefix&&(t={...this.specMetadataService.parseArgsFromEnv(n.argsSchema,n.envPrefix),...t})}let n={};e.testName&&(n.testName=e.testName),e.testPattern&&(n.testPattern=e.testPattern),e.onlyMarked&&(n.onlyMarked=e.onlyMarked),e.describeFilter&&(n.describeFilter=e.describeFilter);let r=e.automationId??`ext-spec-${Date.now()}`,i=!!e.videoDir;i&&await this.extensionPageProxy.startRecording();let a;try{a=await this.extensionSpecRunner.executeSpec({specPath:e.specPath,sessionId:r,testFilter:Object.keys(n).length>0?n:void 0,specArgs:Object.keys(t).length>0?t:void 0})}finally{if(i&&e.videoDir)try{let t=await this.extensionPageProxy.stopRecording();if(t){(0,f.mkdirSync)(e.videoDir,{recursive:!0});let n=(0,p.join)(e.videoDir,`recording-${r}.webm`);(0,f.writeFileSync)(n,Buffer.from(t,`base64`)),a.videoPath=n}}catch{}}return this.formatExtensionResult(a)}async executeBasic(e){let t=await this.automationRunner.runSpec({specPath:e.specPath,automationId:e.automationId,browserId:e.browserId,pageId:e.pageId,keepBrowserOpen:e.keepBrowserOpen??!1,recordVideo:e.videoDir?{dir:e.videoDir,size:Zi}:void 0,browserOptions:{browserType:e.browserType,headless:e.headless,baseURL:e.baseURL}});return this.formatResult(t,e.keepBrowserOpen??!1)}async executeEnhanced(e){let t=e.specArgs??{};if(e.loadArgsFromEnv){let n=await this.specMetadataService.extractSpecMetadata(e.specPath);n.argsSchema&&n.envPrefix&&(t={...this.specMetadataService.parseArgsFromEnv(n.argsSchema,n.envPrefix),...t})}let n={};e.testName&&(n.testName=e.testName),e.testPattern&&(n.testPattern=e.testPattern),e.onlyMarked&&(n.onlyMarked=e.onlyMarked),e.describeFilter&&(n.describeFilter=e.describeFilter);let r=await this.automationRunner.runSpecEnhanced({specPath:e.specPath,automationId:e.automationId,browserId:e.browserId,pageId:e.pageId,keepBrowserOpen:e.keepBrowserOpen??!1,recordVideo:e.videoDir?{dir:e.videoDir,size:Zi}:void 0,browserOptions:{browserType:e.browserType,headless:e.headless,baseURL:e.baseURL},testFilter:Object.keys(n).length>0?n:void 0,specArgs:Object.keys(t).length>0?t:void 0});return this.formatResult(r,e.keepBrowserOpen??!1)}formatResult(e,t){let n=t?`Spec completed. Browser kept open for further interaction.`:`Spec completed.`;return{content:[{type:`text`,text:JSON.stringify({automationId:e.automationId,status:e.status,pageIds:e.pageIds,browserId:e.browserId,specResult:e.specResult,message:n},null,2)}]}}formatExtensionResult(e){let t=e.success?`Spec completed: ${e.passed}/${e.totalTests} tests passed`:`Spec failed: ${e.failed}/${e.totalTests} tests failed`;return{content:[{type:`text`,text:JSON.stringify({sessionId:e.sessionId,status:e.success?`completed`:`failed`,totalTests:e.totalTests,passed:e.passed,failed:e.failed,duration:e.duration,handoffOccurred:e.handoffOccurred,testResults:e.testResults,videoPath:e.videoPath,message:t},null,2)}],isError:!e.success}}};Qi=Ji=A([(0,u.injectable)(),N(0,(0,u.inject)(O.AutomationRunner)),N(1,(0,u.inject)(O.SpecMetadataService)),N(2,(0,u.inject)(O.ExtensionSpecRunner)),N(3,(0,u.inject)(O.ExtensionPageProxy)),N(4,(0,u.inject)(O.SpecBundlerService)),k(`design:paramtypes`,[Object,Object,Object,Object,Object])],Qi);var $i;let ea=class{static{$i=this}static TOOL_NAME=`browser_save_profile_state`;constructor(e,t,n){this.profileService=e,this.browserService=t,this.extensionPageProxy=n}getDefinition(){return{name:$i.TOOL_NAME,description:`Saves the current browser state to the named profile for reuse across future launches.`,inputSchema:{type:`object`,properties:{profileName:{type:`string`,description:`Profile to save state into`},browserId:{type:`string`,description:`Browser to read state from`}},required:[`profileName`],additionalProperties:!1}}}async execute(e){try{let t=e.browserId?this.browserService.getBrowser(e.browserId):this.browserService.getBrowserByProfile(e.profileName);if(!t)throw Error(`Browser for profile "${e.profileName}" not found`);if(t.context){let n=await t.context.storageState();await this.profileService.saveStorageState(e.profileName,n)}else{let n=t.currentPageId??[...t.pageIds][0];if(!n)throw Error(`Browser "${t.id}" has no active page`);this.extensionPageProxy.setTarget(n,t.id);let r=await this.extensionPageProxy.getStorageState();await this.profileService.saveStorageState(e.profileName,r)}return{content:[{type:`text`,text:JSON.stringify({profileName:e.profileName,browserId:t.id,saved:!0},null,2)}]}}catch(e){return{content:[{type:`text`,text:e instanceof Error?e.message:String(e)}],isError:!0}}}};ea=$i=A([(0,u.injectable)(),N(0,(0,u.inject)(O.ProfileService)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ExtensionPageProxy)),k(`design:paramtypes`,[Object,Object,Object])],ea);var ta;let na=class extends Z{static{ta=this}static TOOL_NAME=`browser_screenshot`;constructor(e,t,n){super(e,t,n)}getDefinition(){return{name:ta.TOOL_NAME,description:`Captures a screenshot of the page or specific element. Saves to temp directory and returns the file path.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Page ID to operate on`},fullPage:{type:`boolean`,description:`Capture full page scrollable area`,default:!1},selector:{type:`string`,description:`CSS selector for element to screenshot`},clip:{type:`object`,description:`Clip region to capture by coordinates (cannot be used with selector)`,properties:{x:{type:`number`,description:`X coordinate of top-left corner`,minimum:0},y:{type:`number`,description:`Y coordinate of top-left corner`,minimum:0},width:{type:`number`,description:`Width of clipping region`,minimum:1},height:{type:`number`,description:`Height of clipping region`,minimum:1}},required:[`x`,`y`,`width`,`height`],additionalProperties:!1},type:{type:`string`,enum:[`png`,`jpeg`],description:`Image format`,default:`png`},quality:{type:`number`,description:`Quality for jpeg format (0-100)`,minimum:0,maximum:100},omitBackground:{type:`boolean`,description:`Omit background for transparent PNG`,default:!1},filename:{type:`string`,description:`Custom filename without extension`}},required:[`pageId`],additionalProperties:!1}}}async execute(e){return this.executeWithMode(ta.TOOL_NAME,e.pageId,e,async()=>{let t=this.resolvePage(e.pageId);if(e.clip&&e.selector)throw Error(`Cannot use both clip and selector options together`);let n=e.type??`png`,r=e.filename??`screenshot-${(0,E.randomUUID)()}`,i=(0,p.join)((0,S.tmpdir)(),`${r}.${n}`);if(e.selector){let r=await t.$(e.selector);if(!r)throw Error(`Element not found: ${e.selector}`);await r.screenshot({path:i,type:n,omitBackground:e.omitBackground??!1,quality:n===`jpeg`?e.quality:void 0})}else await t.screenshot({path:i,type:n,fullPage:e.fullPage??!1,omitBackground:e.omitBackground??!1,quality:n===`jpeg`?e.quality:void 0,clip:e.clip});return this.success(`Screenshot saved to: ${i}`)})}};na=ta=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),k(`design:paramtypes`,[Object,Object,Object])],na);var ra;let ia=class extends Z{static{ra=this}static TOOL_NAME=`browser_select_page`;constructor(e,t,n){super(e,t,n)}getDefinition(){return{name:ra.TOOL_NAME,description:`Switches the active page for a browser. Updates the current page ID so subsequent operations use this page by default.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Page ID to set as current`}},required:[`pageId`],additionalProperties:!1}}}async execute(e){return this.safeExecute(async()=>{let t=this.pageRegistry.get(e.pageId);if(!t)return this.error(`Page "${e.pageId}" not found`);let{browserId:n}=t;if(t.mode===`extension`||t.mode===`vm`){let t=await this.executeWithMode(ra.TOOL_NAME,e.pageId,e,async()=>this.error(`Page "${e.pageId}" is not in extension mode`));if(t.isError)return t}this.browserService.setCurrentPage(n,e.pageId),this.browserService.recordBrowserActivity(n,e.pageId),await this.pageRegistry.updateMetadata(e.pageId);let r=this.pageRegistry.get(e.pageId);return this.successJson({browserId:n,pageId:e.pageId,url:r?.url??t.url,title:r?.title??t.title,message:`Page "${e.pageId}" is now the active page for browser "${n}"`})})}};ia=ra=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),k(`design:paramtypes`,[Object,Object,Object])],ia);var aa;let oa=class extends Z{static{aa=this}static TOOL_NAME=`browser_select`;constructor(e,t,n,r){super(e,t,n),this.elementLocator=r}getDefinition(){return{name:aa.TOOL_NAME,description:`Selects option(s) from a dropdown/select element. Can select by value, label, or index.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Page ID to operate on`},selector:{type:`string`,description:`CSS selector`},xpath:{type:`string`,description:`XPath expression`},text:{type:`string`,description:`Text content to match`},uid:{type:`string`,description:`Accessibility snapshot UID`},frame:{type:`string`,description:`Frame selector`},values:{type:`array`,items:{type:`string`},description:`Option value(s) to select`},labels:{type:`array`,items:{type:`string`},description:`Option label(s) to select`},indexes:{type:`array`,items:{type:`number`},description:`Option index(es) to select`},timeout:{type:`number`,description:`Timeout in milliseconds`,default:M}},required:[`pageId`],additionalProperties:!1}}}async execute(e){return this.executeWithMode(aa.TOOL_NAME,e.pageId,e,async()=>{let t=this.resolvePage(e.pageId),n=await this.elementLocator.locate(t,e),r=[];e.values?r=e.values.map(e=>({value:e})):e.labels?r=e.labels.map(e=>({label:e})):e.indexes&&(r=e.indexes.map(e=>({index:e})));let i=await n.selectOption(r,{timeout:e.timeout});return this.success(`Selected ${i.length} option(s): ${i.join(`, `)}`)})}};oa=aa=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),N(3,(0,u.inject)(O.ElementLocatorService)),k(`design:paramtypes`,[Object,Object,Object,Object])],oa);var sa;const ca=1e4;let la=class extends Z{static{sa=this}static TOOL_NAME=`browser_snapshot`;constructor(e,t,n){super(e,t,n)}getDefinition(){return{name:sa.TOOL_NAME,description:`Returns the accessibility tree snapshot of the page. Preferred for LLM processing as it provides structured, semantic information about page content.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Page ID to operate on`},root:{type:`string`,description:`CSS selector for root element to snapshot (defaults to body)`},sizeThreshold:{type:`number`,description:`Size threshold in bytes; snapshots larger than this are saved to file (default: 10000)`,default:1e4}},required:[`pageId`],additionalProperties:!1}}}async execute(e){return this.executeWithMode(sa.TOOL_NAME,e.pageId,e,async()=>{let t=this.resolvePage(e.pageId),n=e.root??`body`,r=t.locator(n);if(await r.count()===0)throw Error(`Root element not found: ${n}`);let i=await r.ariaSnapshot();if(!i)return this.success(`No accessibility tree available for this page`);let a=e.sizeThreshold??1e4;if(Buffer.byteLength(i,`utf-8`)<=a)return this.success(i);let o=`snapshot-${(0,E.randomUUID)()}.yaml`,s=(0,p.join)((0,S.tmpdir)(),o);return await(0,w.writeFile)(s,i,`utf-8`),this.success(`Snapshot saved to: ${s}`)})}};la=sa=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),k(`design:paramtypes`,[Object,Object,Object])],la);var ua;let da=class extends Z{static{ua=this}static TOOL_NAME=`browser_start_trace`;getDefinition(){return{name:ua.TOOL_NAME,description:`Starts Playwright performance tracing with configurable options for screenshots, snapshots, and sources. Use browser_stop_trace to stop and save the trace.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Optional page ID to override browser current page`},name:{type:`string`,description:`Name for the trace (used in trace filename)`},screenshots:{type:`boolean`,description:`Whether to capture screenshots during tracing (default: true)`},snapshots:{type:`boolean`,description:`Whether to capture snapshots during tracing (default: true)`},sources:{type:`boolean`,description:`Whether to include source files in the trace (default: false)`}},required:[`pageId`],additionalProperties:!1}}}async execute(e){return this.safeExecute(async()=>{let t=this.resolvePageEntry(e.pageId),n=t.context;if(!n)return this.error(`Page "${e.pageId}" is in extension mode and cannot start tracing`);let{name:r,screenshots:i=!0,snapshots:a=!0,sources:o=!1}=e;return await n.tracing.start({name:r,screenshots:i,snapshots:a,sources:o}),this.successJson({success:!0,message:`Tracing started`,pageId:t.id,options:{name:r??null,screenshots:i,snapshots:a,sources:o}})})}};da=ua=A([(0,u.injectable)()],da);var fa;let pa=class extends Z{static{fa=this}static TOOL_NAME=`browser_stop_trace`;getDefinition(){return{name:fa.TOOL_NAME,description:`Stops Playwright performance tracing and saves the trace file to a specified path. The trace can be viewed using Playwright Trace Viewer.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Optional page ID to override browser current page`},path:{type:`string`,description:`Path where the trace file should be saved (e.g., "./traces/trace.zip"). Must end with .zip extension.`}},required:[`pageId`,`path`],additionalProperties:!1}}}async execute(e){return this.safeExecute(async()=>{let t=this.resolvePageEntry(e.pageId),n=t.context;if(!n)return this.error(`Page "${e.pageId}" is in extension mode and cannot stop tracing`);let r=e.path;if(!r.endsWith(`.zip`))return this.error(`Trace path must end with .zip extension`);await n.tracing.stop({path:r});let i=p.default.resolve(r);return this.successJson({success:!0,message:`Tracing stopped and saved`,pageId:t.id,tracePath:i,viewCommand:`npx playwright show-trace ${i}`})})}};pa=fa=A([(0,u.injectable)()],pa);var ma;let ha=class extends Z{static{ma=this}static TOOL_NAME=`browser_type`;constructor(e,t,n,r){super(e,t,n),this.elementLocator=r}getDefinition(){return{name:ma.TOOL_NAME,description:`Types text into an element character by character, simulating real keyboard input. Does not clear existing content. Use browser_fill for replacing content.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Page ID to operate on`},selector:{type:`string`,description:`CSS selector`},xpath:{type:`string`,description:`XPath expression`},uid:{type:`string`,description:`Accessibility snapshot UID`},frame:{type:`string`,description:`Frame selector`},text:{type:`string`,description:`The text to type character by character`},delay:{type:`number`,description:`Delay between key presses in ms`,default:0},timeout:{type:`number`,description:`Timeout in milliseconds`,default:M}},required:[`pageId`,`text`],additionalProperties:!1}}}async execute(e){return this.executeWithMode(ma.TOOL_NAME,e.pageId,e,async()=>{let t=this.resolvePage(e.pageId);return await(await this.elementLocator.locate(t,{selector:e.selector,xpath:e.xpath,uid:e.uid,frame:e.frame})).pressSequentially(e.text,{delay:e.delay,timeout:e.timeout}),this.success(`Typed: "${e.text}"`)})}};ha=ma=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),N(3,(0,u.inject)(O.ElementLocatorService)),k(`design:paramtypes`,[Object,Object,Object,Object])],ha);var ga;let _a=class extends Z{static{ga=this}static TOOL_NAME=`browser_upload_file`;constructor(e,t,n,r){super(e,t,n),this.elementLocator=r}getDefinition(){return{name:ga.TOOL_NAME,description:`Uploads file(s) to a file input element.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Page ID to operate on`},selector:{type:`string`,description:`CSS selector`},xpath:{type:`string`,description:`XPath expression`},text:{type:`string`,description:`Text content to match`},uid:{type:`string`,description:`Accessibility snapshot UID`},frame:{type:`string`,description:`Frame selector`},files:{oneOf:[{type:`string`,description:`Single file path to upload`},{type:`array`,items:{type:`string`},description:`Multiple file paths to upload`}],description:`File path(s) to upload`},timeout:{type:`number`,description:`Timeout in milliseconds`,default:M}},required:[`pageId`,`files`],additionalProperties:!1}}}async execute(e){return this.executeWithMode(ga.TOOL_NAME,e.pageId,e,async()=>{let t=this.resolvePage(e.pageId);await(await this.elementLocator.locate(t,e)).setInputFiles(e.files,{timeout:e.timeout});let n=Array.isArray(e.files)?e.files.length:1;return this.success(`Uploaded ${n} file(s) successfully`)})}};_a=ga=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),N(3,(0,u.inject)(O.ElementLocatorService)),k(`design:paramtypes`,[Object,Object,Object,Object])],_a);var va;let ya=class extends Z{static{va=this}static TOOL_NAME=`browser_wait_for`;constructor(e,t,n){super(e,t,n)}getDefinition(){return{name:va.TOOL_NAME,description:`Waits for a condition to be met: element visibility, text appearance, timeout duration, or page load state.`,inputSchema:{type:`object`,properties:{pageId:{type:`string`,description:`Page ID to operate on`},type:{type:`string`,enum:[`element`,`text`,`timeout`,`loadState`],description:`Type of wait condition`},selector:{type:`string`,description:`CSS selector for element wait`},text:{type:`string`,description:`Text to wait for (supports regex patterns)`},duration:{type:`number`,description:`Duration in milliseconds for timeout wait`},state:{type:`string`,enum:[`load`,`domcontentloaded`,`networkidle`],description:`Load state to wait for`},elementState:{type:`string`,enum:[`attached`,`detached`,`visible`,`hidden`],description:`Element state to wait for`,default:`visible`},timeout:{type:`number`,description:`Timeout in milliseconds`,default:M}},required:[`pageId`,`type`],additionalProperties:!1}}}async execute(e){if(e.type===`timeout`){let t=e.duration??1e3;return await new Promise(e=>setTimeout(e,t)),this.success(`Waited for ${t}ms`)}return this.executeWithMode(va.TOOL_NAME,e.pageId,e,async()=>{let t=this.resolvePage(e.pageId);switch(e.type){case`element`:if(!e.selector)throw Error(`selector is required for element wait`);return await t.locator(e.selector).waitFor({state:e.elementState??`visible`,timeout:e.timeout}),this.success(`Element "${e.selector}" is ${e.elementState??`visible`}`);case`text`:if(!e.text)throw Error(`text is required for text wait`);return await t.getByText(e.text).waitFor({state:`visible`,timeout:e.timeout}),this.success(`Text "${e.text}" appeared on page`);case`loadState`:{let n=e.state??`load`;return await t.waitForLoadState(n,{timeout:e.timeout}),this.success(`Page reached "${n}" state`)}default:throw Error(`Unknown wait type: ${e.type}`)}})}};ya=va=A([(0,u.injectable)(),N(0,(0,u.inject)(O.PageRegistry)),N(1,(0,u.inject)(O.BrowserService)),N(2,(0,u.inject)(O.ToolExecutor)),k(`design:paramtypes`,[Object,Object,Object])],ya);const ba=new u.ContainerModule(e=>{e.bind(O.PortRegistryService).toDynamicValue(()=>new x.PortRegistryService(process.env.PORT_REGISTRY_PATH)).inSingletonScope(),e.bind(O.HttpServerHealthCheck).to(H).inSingletonScope(),e.bind(O.HttpServerManager).to(Fn).inSingletonScope(),e.bind(O.McpSessionTracker).to(q).inSingletonScope()}),xa=new u.ContainerModule(e=>{e.bind(O.ProfileService).to(Un).inSingletonScope(),e.bind(O.PageRegistry).to(Vn).inSingletonScope(),e.bind(O.BrowserService).to(zt).inSingletonScope(),e.bind(O.BrowserLockManager).to(ut).inSingletonScope(),e.bind(O.ChromeForTestingService).to(Ht).inSingletonScope(),e.bind(O.ElementLocatorService).to(Ut).inSingletonScope(),e.bind(O.PageMonitorService).to(Bn).inSingletonScope(),e.bind(O.PauseController).to(Hn).inSingletonScope(),e.bind(O.SpecBundlerService).to(fr).inSingletonScope(),e.bind(O.SpecDiscoveryService).to(pr).inSingletonScope(),e.bind(O.SpecMetadataService).to(mr).inSingletonScope(),e.bind(O.SetupRunner).to(Gn).inSingletonScope(),e.bind(O.WebServerManager).to(yr).inSingletonScope(),e.bind(O.SpecRunner).to(hr).inSingletonScope(),e.bind(O.AutomationRunner).to(ct).inSingletonScope(),e.bind(O.TelemetryService).to(j).inSingletonScope(),e.bind(O.ExtensionTaskQueue).to(P).inSingletonScope(),e.bind(O.ExtensionToolDelegator).to(F).inSingletonScope(),e.bind(O.ToolExecutor).to(vr).inSingletonScope(),e.bind(O.ExtensionSessionRegistry).to(Kt).inSingletonScope(),e.bind(O.ExtensionPageProxy).to(z).inSingletonScope(),e.bind(O.ExtensionSpecRunner).to(qt).inSingletonScope(),e.bind(O.StealthLauncher).to(gr).inSingletonScope(),e.bind(O.HttpServerHealthCheck).to(H).inSingletonScope(),e.bind(O.HttpBrowserClient).to($t).inSingletonScope(),e.bind(O.RemoteToolExecutor).to(Wn).inSingletonScope(),e.bind(O.WebSocketHub).to(Lr).inSingletonScope(),e.bind(O.IdleCleanupService).to(zn).inSingletonScope()}),Sa=new u.ContainerModule(e=>{e.bind(O.Tool).to(zr).inSingletonScope(),e.bind(O.Tool).to(ai).inSingletonScope(),e.bind(O.Tool).to(ha).inSingletonScope(),e.bind(O.Tool).to(oa).inSingletonScope(),e.bind(O.Tool).to(hi).inSingletonScope(),e.bind(O.Tool).to(Zr).inSingletonScope(),e.bind(O.Tool).to(Hi).inSingletonScope(),e.bind(O.Tool).to(_a).inSingletonScope(),e.bind(O.Tool).to(Li).inSingletonScope(),e.bind(O.Tool).to(li).inSingletonScope(),e.bind(O.Tool).to(di).inSingletonScope(),e.bind(O.Tool).to(Ui).inSingletonScope(),e.bind(O.Tool).to(ya).inSingletonScope(),e.bind(O.Tool).to(la).inSingletonScope(),e.bind(O.Tool).to(na).inSingletonScope(),e.bind(O.Tool).to(Bi).inSingletonScope(),e.bind(O.Tool).to(Ni).inSingletonScope(),e.bind(O.Tool).to(zi).inSingletonScope(),e.bind(O.Tool).to(ia).inSingletonScope(),e.bind(O.Tool).to(Ur).inSingletonScope(),e.bind(O.Tool).to(pi).inSingletonScope(),e.bind(O.Tool).to(ji).inSingletonScope(),e.bind(O.Tool).to(si).inSingletonScope(),e.bind(O.Tool).to(ki).inSingletonScope(),e.bind(O.Tool).to(ti).inSingletonScope(),e.bind(O.Tool).to($r).inSingletonScope(),e.bind(O.Tool).to(Gi).inSingletonScope(),e.bind(O.Tool).to(ri).inSingletonScope(),e.bind(O.Tool).to(da).inSingletonScope(),e.bind(O.Tool).to(pa).inSingletonScope(),e.bind(O.Tool).to(Fi).inSingletonScope(),e.bind(O.Tool).to(Gr).inSingletonScope(),e.bind(O.Tool).to(qr).inSingletonScope(),e.bind(O.Tool).to(ea).inSingletonScope(),e.bind(O.Tool).to(Qi).inSingletonScope(),e.bind(O.Tool).to(Yr).inSingletonScope(),e.bind(O.Tool).to(Di).inSingletonScope(),e.bind(O.Tool).to(Vr).inSingletonScope(),e.bind(O.Tool).to(qi).inSingletonScope()});function Ca(){let e=new u.Container({defaultScope:`Singleton`});return e.load(ba),e}function wa(){let e=new u.Container({defaultScope:`Singleton`});return e.load(xa,Sa),e}const Ta=new u.ContainerModule(e=>{e.bind(O.PortRegistryService).toDynamicValue(()=>new x.PortRegistryService(process.env.PORT_REGISTRY_PATH)).inSingletonScope(),e.bind(O.ProfileService).to(Un).inSingletonScope(),e.bind(O.PageRegistry).to(Vn).inSingletonScope(),e.bind(O.BrowserService).to(zt).inSingletonScope(),e.bind(O.ElementLocatorService).to(Ut).inSingletonScope(),e.bind(O.PageMonitorService).to(Bn).inSingletonScope(),e.bind(O.PauseController).to(Hn).inSingletonScope(),e.bind(O.SpecBundlerService).to(fr).inSingletonScope(),e.bind(O.SpecDiscoveryService).to(pr).inSingletonScope(),e.bind(O.SpecMetadataService).to(mr).inSingletonScope(),e.bind(O.SetupRunner).to(Gn).inSingletonScope(),e.bind(O.WebServerManager).to(yr).inSingletonScope(),e.bind(O.SpecRunner).to(hr).inSingletonScope(),e.bind(O.AutomationRunner).to(ct).inSingletonScope(),e.bind(O.HttpServerHealthCheck).to(H).inSingletonScope(),e.bind(O.HttpServerManager).to(Fn).inSingletonScope(),e.bind(O.HttpBrowserClient).to($t).inSingletonScope(),e.bind(O.RemoteToolExecutor).to(Wn).inSingletonScope(),e.bind(O.ExtensionTaskQueue).to(P).inSingletonScope(),e.bind(O.ExtensionToolDelegator).to(F).inSingletonScope(),e.bind(O.ToolExecutor).to(vr).inSingletonScope(),e.bind(O.StealthLauncher).to(gr).inSingletonScope(),e.bind(O.BrowserLockManager).to(ut).inSingletonScope(),e.bind(O.ExtensionSessionRegistry).to(Kt).inSingletonScope(),e.bind(O.ExtensionPageProxy).to(z).inSingletonScope(),e.bind(O.ExtensionSpecRunner).to(qt).inSingletonScope(),e.bind(O.McpSessionTracker).to(q).inSingletonScope(),e.bind(O.ChromeForTestingService).to(Ht).inSingletonScope(),e.bind(O.IdleCleanupService).to(zn).inSingletonScope()}),Ea=new u.Container({defaultScope:`Singleton`});Ea.load(Ta,Sa);function Da(){let e=new u.Container({defaultScope:`Singleton`});return e.load(Ta,Sa),e}var Oa=class extends Error{code=`TRANSPORT_CONNECTION_ERROR`;recovery=`Check that stdio streams are available and try again.`;constructor(e,t){super(e,t),this.name=`TransportConnectionError`}},ka=class{server;transport=null;constructor(e){this.server=e}async start(){let e=new l.StdioServerTransport;try{await this.server.connect(e),this.transport=e,console.error(`browse-tool MCP server started on stdio`)}catch(t){try{await e.close()}catch{}let n=new Oa(`Failed to establish stdio transport connection`,{cause:t});throw console.error(`[${n.code}] ${n.message}. Recovery: ${n.recovery}`),n}}async stop(){this.transport&&=(await this.transport.close(),null)}};Object.defineProperty(exports,`_`,{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return Ca}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return V}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return z}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return F}}),Object.defineProperty(exports,`g`,{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,`h`,{enumerable:!0,get:function(){return et}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return wa}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return B}}),Object.defineProperty(exports,`m`,{enumerable:!0,get:function(){return j}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return Ea}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return q}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return P}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return Da}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return Yt}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return ka}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return Qt}});
|