@agimon-ai/browse-tool 0.8.4 → 0.8.6

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.
@@ -6,7 +6,7 @@ import{a as e,c as t,h as n,p as r,s as i,t as a,v as o,y as s}from"./playwright
6
6
  `).split(`
7
7
  `).map(e=>e.length>0?` ${e}`:e).join(`
8
8
  `)}function Vt(e){return[`export const name = ${JSON.stringify(e.name)};`,`export const description = ${JSON.stringify(e.description)};`,`export const run = async ({ page, context, browser }) => {`,Bt(e.code),`};`,``].join(`
9
- `)}async function Ht(e){let t=c(await j(e,`utf8`),{mode:`strip`});return await import(`data:text/javascript;base64,${Buffer.from(t,`utf8`).toString(`base64`)}`)}var Ut=class{constructor(e=process.env.BROWSE_TOOL_SNIPPETS_DIR){this.snippetsDir=e}getDirectory(){return this.snippetsDir?x.resolve(this.snippetsDir):void 0}async listSnippets(){let e=this.requireDirectory();await A(e,{recursive:!0});let t=await ce(e,{withFileTypes:!0}),n=[];for(let r of t){if(!r.isFile()||!r.name.endsWith(`.ts`))continue;let t=r.name,i=await Ht(x.join(e,r.name)),a=typeof i.name==`string`&&i.name.trim().length>0?i.name:r.name.replace(/\.ts$/,``),o=typeof i.description==`string`?i.description:``;n.push({name:a,description:o,snippetPath:t})}return n.sort((e,t)=>e.name.localeCompare(t.name)),n}async loadSnippet(e){let t=await this.resolveSnippetPath(e),n=await Ht(t.filePath);if(typeof n.run!=`function`)throw Error(`Snippet "${t.snippetPath}" must export a "run" function`);return{name:typeof n.name==`string`&&n.name.trim().length>0?n.name:t.snippetPath.replace(/\.ts$/,``),description:typeof n.description==`string`?n.description:``,snippetPath:t.snippetPath,run:n.run}}async saveSnippet(e){let t=this.requireDirectory();await A(t,{recursive:!0});let n=`${zt(e.name)}.ts`;return await M(x.join(t,n),Vt(e),`utf8`),{name:e.name,description:e.description,snippetPath:n}}requireDirectory(){let e=this.getDirectory();if(!e)throw Error(`Snippet storage is not configured. Start browse-tool with --snippets-dir.`);return e}async resolveSnippetPath(e){let t=this.requireDirectory(),n=e.endsWith(`.ts`)?e:`${e}.ts`,r=x.resolve(t,n);if(!r.startsWith(`${t}${x.sep}`)&&r!==x.join(t,n))throw Error(`Snippet path must stay within the configured snippets directory`);if(!(await de(r).catch(()=>null))?.isFile())throw Error(`Snippet "${e}" not found`);return{filePath:r,snippetPath:x.relative(t,r)}}};const W=I.object({uid:I.string().optional().describe(`Accessibility snapshot UID reference`),role:I.string().optional().describe(`ARIA role (e.g., "button", "textbox")`),name:I.string().optional().describe(`Accessible name used with the role selector`),label:I.string().optional().describe(`Associated label text`),placeholder:I.string().optional().describe(`Placeholder text`),testId:I.string().optional().describe(`data-testid value`),text:I.string().optional().describe(`Visible text content`),exact:I.boolean().optional().default(!1).describe(`Use exact matching for semantic selectors`),selector:I.string().optional().describe(`CSS selector`),xpath:I.string().optional().describe(`XPath expression`),frame:I.string().optional().describe(`Frame selector`)});let Wt=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??18e4,state:n.state??`visible`}),i.first()}async getFrameContext(e,t){return t?e.frameLocator(t):e}buildLocator(e,t){let n=t.exact??!1;if(t.uid)return e.locator(`[data-pw-proxy="${t.uid}"], [data-browse-tool-uid="${t.uid}"], [data-uid="${t.uid}"]`);if(t.role){let r=t.role;return t.name?e.getByRole(r,{name:t.name,exact:n}):e.getByRole(r)}if(t.label)return e.getByLabel(t.label,{exact:n});if(t.placeholder)return e.getByPlaceholder(t.placeholder,{exact:n});if(t.testId)return e.getByTestId(t.testId);if(t.text)return e.getByText(t.text,{exact:n});if(t.selector)return e.locator(t.selector);if(t.xpath)return e.locator(`xpath=${t.xpath}`);throw Error(`No selector provided. Specify one of: uid, role, label, placeholder, text, selector, or xpath.`)}describeSelector(e){let t=[];return e.uid&&t.push(`uid="${e.uid}"`),e.role&&t.push(`role="${e.role}"`),e.name&&t.push(`name="${e.name}"`),e.label&&t.push(`label="${e.label}"`),e.placeholder&&t.push(`placeholder="${e.placeholder}"`),e.testId&&t.push(`testId="${e.testId}"`),e.text&&t.push(`text="${e.text}"`),e.exact&&t.push(`exact=true`),e.selector&&t.push(`selector="${e.selector}"`),e.xpath&&t.push(`xpath="${e.xpath}"`),e.frame&&t.push(`frame="${e.frame}"`),t.length>0?t.join(`, `):`empty selector`}};Wt=V([v()],Wt);const Gt=process.env.BROWSE_TOOL_DEBUG_CUSTOM_TOOLS===`1`;function Kt(e){return JSON.stringify(e,(e,t)=>typeof t==`string`&&t.length>240?`${t.slice(0,240)}...<trimmed>`:t)}function G(e,t){if(Gt){if(t){console.error(`[ExtensionPageProxy] ${e}`,t);return}console.error(`[ExtensionPageProxy] ${e}`)}}function qt(e){return typeof e==`object`&&e&&`value`in e?e.value:e}let Jt=class{[o]=!0;currentUrl=`about:blank`;defaultTimeoutMs=H;_pageId;_browserId;constructor(e){this.taskQueue=e}setTarget(e,t){this._pageId=e,this._browserId=t,this.currentUrl=`about:blank`,this.currentUrlAsync().catch(()=>{})}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 qt(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 qt(e.result)??``}async textContent(e){return this.locator(e).textContent()}async innerText(e){return this.locator(e).innerText()}async inputValue(e){return this.locator(e).inputValue()}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 qt(r.result)}async getSnapshot(){let e=await this.executeTask(`browser_snapshot`,{});if(!e.success)throw Error(e.error??`Get snapshot failed`);let t=qt(e.result);return typeof t==`string`?t:t==null?``:JSON.stringify(t,null,2)}getByRole(e,t){return new s(this,[{type:`role`,role:e,options:t}])}getByText(e,t){return new s(this,[{type:`text`,text:e,options:t}])}getByLabel(e,t){return new s(this,[{type:`label`,text:e,options:t}])}getByPlaceholder(e,t){return new s(this,[{type:`placeholder`,text:e,options:t}])}getByTestId(e){return new s(this,[{type:`testId`,testId:e}])}locator(e){return new s(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};G(`Queueing extension task`,{tool:e,browserId:this._browserId,pageId:this._pageId,args:Kt(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 G(`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 G(`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 G(`Extension task completed with JSON text result`,{tool:e,browserId:this._browserId,pageId:this._pageId}),{success:!0,result:t}}catch{return G(`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 G(`Extension task completed with non-text result payload`,{tool:e,browserId:this._browserId,pageId:this._pageId,taskResult:r}),{success:!0,result:r.result}}};Jt=V([v(),B(0,_(R.ExtensionTaskQueue)),z(`design:paramtypes`,[Object])],Jt);let Yt=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}};Yt=V([v()],Yt);let Xt=class{constructor(e,t,n){this.bundler=e,this.pageProxy=t,this.sessionRegistry=n}async loadSpec(e){let n=await this.bundler.bundle(e),a=process,o=a.__pw_initiator__;try{return t(e),a.__pw_initiator__=void 0,await import(`${n.outputPath}?t=${Date.now()}`),i()}catch(t){throw r(),Error(`Failed to load spec "${e}": ${t instanceof Error?t.message:String(t)}`,{cause:t})}finally{a.__pw_initiator__=o,await n.cleanup()}}async executeSpec(e){let{specPath:t,sessionId:r,testFilter:i,specArgs:a,onHandoff:o}=e,s=Date.now(),c=[],l=0,u=0,d=!1,f=new Set,p=new Set;this.sessionRegistry.setActiveSpec(r,t);try{let e=await this.loadSpec(t),m=i?this.filterTests(e.allTests,i):e.allTests,h={page:this.pageProxy,requestHandoff:async e=>{if(!this.sessionRegistry.getSession(r))throw Error(`Session ${r} not found`);let t=await this.pageProxy.getSnapshot(),n=this.pageProxy.url();try{n=await this.pageProxy.currentUrlAsync()}catch{}this.sessionRegistry.requestHandoff({sessionId:r,reason:e,pageState:{url:n,snapshot:t}}),d=!0,o&&await o(r)},specArgs:a};for(let e of m){let{runtimeUse:t,unsupportedKeys:i,fixtureOverrides:a}=n(e.config.use);i.length>0&&f.add(`test.use() ignores unsupported fixture keys in extension mode: ${i.join(`, `)}`),Object.keys(t).length>0&&f.add(`test.use() runtime browser config is not applied in extension mode: ${Object.keys(t).join(`, `)}`);let o=e.serialScopeId,s=o!==void 0&&p.has(o);if(e.skip||s){c.push({title:e.title,fullTitle:e.fullTitle,passed:!0,error:null,duration:0}),l++;continue}let d=this.sessionRegistry.getSession(r);if(d?.handoffRequested)break;let m=Date.now();try{await e.fn({...h,...a}),c.push({title:e.title,fullTitle:e.fullTitle,passed:!0,error:null,duration:Date.now()-m,handoffTriggered:d?.handoffRequested}),l++}catch(t){let n=t instanceof Error?t.message:String(t);c.push({title:e.title,fullTitle:e.fullTitle,passed:!1,error:n,duration:Date.now()-m}),u++,o!==void 0&&p.add(o)}}return{specPath:t,totalTests:m.length,passed:l,failed:u,testResults:c,success:u===0,duration:Date.now()-s,handoffOccurred:d,sessionId:r,warnings:f.size>0?[...f]:void 0}}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,handoffOccurred:!1,sessionId:r,warnings:f.size>0?[...f]:void 0}}finally{this.sessionRegistry.setActiveSpec(r,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}};Xt=V([v(),B(0,_(R.SpecBundlerService)),B(1,_(R.ExtensionPageProxy)),B(2,_(R.ExtensionSessionRegistry)),z(`design:paramtypes`,[Object,Object,Object])],Xt);const Zt=`browse-tool-http`,Qt=[`pnpm-workspace.yaml`,`nx.json`,`.git`],$t=new Set([`127.0.0.1`,`localhost`,`::1`,`0.0.0.0`]);function en(e){return e===`1`||e===`true`}function tn(e){return Array.isArray(e)?JSON.stringify(e):typeof e==`string`||typeof e==`number`||typeof e==`boolean`?e:JSON.stringify(e)}function nn(e){if(!e)return;let t={};for(let[n,r]of Object.entries(e))r!=null&&(t[n]=tn(r));return Object.keys(t).length>0?t:void 0}function rn(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 an(e){if(!e)return;let t=Number(e);return Number.isFinite(t)&&t>0?t:void 0}function on(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 sn(e){return $t.has(e)}function cn(e=process.cwd()){let t=x.resolve(e);for(;;){for(let e of Qt)if(k(x.join(t,e)))return t;let e=x.dirname(t);if(e===t)return process.cwd();t=e}}function ln(e,t=process.cwd()){try{let n=re(d.resolveRegistryPath(e.PORT_REGISTRY_PATH??u),`utf8`),r=f.parse(JSON.parse(n)),i=p(cn(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 un(e,t){try{let n=new URL(e),r=new URL(t);return!sn(n.hostname)||sn(r.hostname)||(n.hostname=r.hostname),n.toString()}catch{return e}}function dn(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 on(r,t);let i=ln(e);return i?on(i,t):void 0}function fn(e,t,n){let r=t===`traces`?e.BROWSE_TOOL_OTEL_BROWSER_TRACES_ENDPOINT:e.BROWSE_TOOL_OTEL_BROWSER_LOGS_ENDPOINT;if(r)return un(r,n);let i=e.BROWSE_TOOL_OTEL_BROWSER_ENDPOINT;if(i)return un(on(i,t),n);let a=dn(e,t);return a?un(a,n):void 0}function pn(e,t){let n=e.BROWSE_TOOL_OTEL_BROWSER_SERVICE_NAME??`${e.OTEL_SERVICE_NAME??Zt}-extension`,r=fn(e,`traces`,t),i=fn(e,`logs`,t);return{enabled:!!(r||i),tracesEndpoint:r,logsEndpoint:i,serviceName:n}}function mn(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:dn(e,t),headers:rn(n??e.OTEL_EXPORTER_OTLP_HEADERS),timeoutMillis:an(r??e.OTEL_EXPORTER_OTLP_TIMEOUT)}}function hn(e){return e instanceof Error?e.message:String(e)}function gn(e){if(e instanceof Error)return nn({"exception.type":e.name,"exception.message":e.message,"exception.stacktrace":e.stack})}let _n=class{contextStore=new Ee;tracesEnabled;logsEnabled;tracerProvider;tracer;logSinkReady;constructor(e={}){let t=e.env??process.env,n=en(t.OTEL_SDK_DISABLED),r=en(t.BROWSE_TOOL_OTEL_ENABLED),i=mn(t,`traces`);this.tracesEnabled=!n&&(r||!!i.url),this.logsEnabled=!n;let a=e.serviceName??t.BROWSE_TOOL_OTEL_SERVICE_NAME??t.OTEL_SERVICE_NAME??Zt,o=e.serviceVersion??t.npm_package_version,s={"service.name":a};o&&(s[`service.version`]=o);let c=Ne(s);if(this.tracesEnabled){let t=e.traceExporter??new Me(i);this.tracerProvider=new Fe({resource:c,spanProcessors:[e.traceExporter?new Ie(t):new Pe(t)]})}this.tracer=this.tracerProvider?.getTracer(a,o)??je.getTracer(a,o),this.logSinkReady=this.logsEnabled?De({env:t,serviceName:a,serviceVersion:o,workspaceRoot:cn(),enableTraces:!1,enableLogs:!0}).catch(()=>null):Promise.resolve(null)}isEnabled(){return this.tracesEnabled||this.logsEnabled}getActiveTraceContext(){let e=this.contextStore.getStore();if(!e)return{};let t=je.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()??Ae.active(),i=this.tracer.startSpan(e,{kind:t.kind??Oe.INTERNAL,attributes:nn(t.attributes)},r),a=je.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(hn(e))),i.setStatus({code:ke.ERROR,message:hn(e)}),e}finally{i.end()}})}log(e,t,n={}){this.logsEnabled&&this.logSinkReady.then(r=>{if(!r)return;let i=n.context??this.contextStore.getStore()??Ae.active(),a=gn(n.exception);r.logger[e](t,{attributes:nn({...n.attributes,...a}),context:i,exception:n.exception})})}async forceFlush(){let e=await this.logSinkReady;await Promise.allSettled([this.tracerProvider?.forceFlush(),e?.flush()])}async shutdown(){let e=await this.logSinkReady;await Promise.allSettled([this.tracerProvider?.shutdown(),e?.shutdown()])}};_n=V([v(),z(`design:paramtypes`,[Object])],_n);let vn=class{pendingTasks=new Map;taskQueue=[];lastPollAt;lastResultAt;maxQueueSize=100;defaultTimeoutMs=H;constructor(e,t=new _n){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}}};vn=V([v(),B(0,_(R.WebSocketHub)),B(0,y()),B(1,_(R.TelemetryService)),B(1,y()),z(`design:paramtypes`,[Object,Object])],vn);const yn=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_inspect_element.browser_resolve_locator.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(`.`)),bn=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 xn=class{constructor(e){this.taskQueue=e}isToolSupported(e){return yn.has(e)}isToolNotApplicable(e){return bn.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(yn)}getNotApplicableTools(){return Array.from(bn)}};xn=V([v(),B(0,_(R.ExtensionTaskQueue)),z(`design:paramtypes`,[Object])],xn);const Sn=l.min,Cn=`PLAYWRIGHT_PORT`;function K(){return process.env.PLAYWRIGHT_HOST?.trim()||`localhost`}function wn(){let e=process.env[Cn];if(!e)return Sn;let t=Number.parseInt(e,10);if(Number.isNaN(t)||t<=0||t>65535)throw Error(`Invalid ${Cn} value: ${e}`);return t}function q(e=void 0,t){let n=typeof e==`string`?e:e?.host??K(),r=e&&typeof e!=`string`?e.port:t??wn();return`http://${n===`0.0.0.0`?`127.0.0.1`:n===`::`?`::1`:n}:${r}`}let Tn=class{baseUrl;defaultTimeout=H;constructor(){this.baseUrl=q()}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}}};Tn=V([v(),z(`design:paramtypes`,[])],Tn);let En=class{defaultTimeout=5e3;async check(e,t=this.defaultTimeout){try{let n=`${q(K(),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)}}}};En=V([v()],En);var Dn;const On=ye(import.meta.url),kn=b.dirname(On),An=[`pnpm-workspace.yaml`,`nx.json`,`.git`],J=`browse-tool-http`,jn=`tool`,Mn=`http-serve`,Nn=`ESRCH`,Pn=`node`,Fn=`cli.mjs`,In=`cli.ts`,Y=`[HttpServerManager]`;var Ln=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`}},Rn=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`}},zn=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 Bn(e){try{return await ae.access(e),!0}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return!1;throw e}}const Vn=Le(_e);async function Hn(e){try{let{stdout:t}=await Vn(`git`,[`rev-parse`,`--git-common-dir`],{cwd:e}),n=t.trim(),r=b.isAbsolute(n)?n:b.join(e,n),i=b.dirname(r);return i===e?null:i}catch{return null}}async function Un(e=process.cwd()){let t=b.resolve(e);for(;;){for(let e of An)if(await Bn(b.join(t,e)))return t;let e=b.dirname(t);if(e===t)return process.cwd();t=e}}let Wn=class{repositoryPath;environment;host;constructor(e,t,n=new m(process.env.PROCESS_REGISTRY_PATH)){this.healthCheck=e,this.portRegistry=t,this.processRegistry=n,this.environment=process.env.NODE_ENV||`development`,this.host=K()}async getRepositoryPath(){return this.repositoryPath||=await Un(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(){let e=await this.getRepositoryPath(),t={serviceName:J,serviceType:jn,environment:this.environment},n=await this.portRegistry.listAllocations({...t,repositoryPath:e});if(n.length>0)return n;let r=await Hn(e);if(r){let e=await this.portRegistry.listAllocations({...t,repositoryPath:r});if(e.length>0)return e}return this.portRegistry.listAllocations(t)}async releaseEntry(e){if(e.pid){let t=await this.processRegistry.releaseProcess({repositoryPath:e.repositoryPath,serviceName:J,serviceType:`service`,environment:e.environment,pid:e.pid,kill:!1,releasePort:!1});!t.success&&!t.error?.includes(`No matching process entry`)&&console.error(`${Y} Failed to release process entry for port ${e.port}: ${t.error}`)}let t=await this.portRegistry.releasePort({repositoryPath:e.repositoryPath,serviceName:J,serviceType:jn,environment:e.environment,pid:e.pid});!t.success&&!t.error?.includes(`No matching registry entry`)&&console.error(`${Y} 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===J)return{entry:t,browserCount:e.browserCount}}catch(e){console.error(`${Y} Health check threw for port ${t.port}: ${e instanceof Error?e.message:String(e)}`)}return null}async discoverHealthyServiceOnPort(e){let t=await this.findRegistrationByPort(e);if(!t)return null;try{let n=await this.healthCheck.check(e);if(n.healthy&&n.serviceName===J)return{entry:t,browserCount:n.browserCount}}catch(t){console.error(`${Y} Health check threw for requested port ${e}: ${t instanceof Error?t.message:String(t)}`)}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(`${Y} Health check threw for port ${n.port}, skipping cleanup: ${e instanceof Error?e.message:String(e)}`);continue}e.healthy&&e.serviceName===J||(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(`${Y} ${r}`),t.push(r)}t.length>0&&console.error(`${Y} ${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,t={}){let n=await this.getRepositoryPath(),r=await this.portRegistry.findAvailablePort({repositoryPath:n,serviceName:J,serviceType:jn,environment:this.environment,host:this.host,preferredPort:e,portRange:t.exactPort?{min:e,max:e}:void 0});if(!r.success||!r.port)throw new Ln(`No available port found from ${e}: ${r.error}`);return r.port}async ensureExactPortAvailable(e){let t=await this.findAvailablePort(e,{exactPort:!0});if(t!==e)throw new Ln(`Requested port ${e} is unavailable; next available port is ${t}`)}async resolveCliCommand(e){let t=b.resolve(kn,Fn),n=b.resolve(kn,`..`,In),r=[`--port`,e.toString(),`--host`,this.host];if(await Bn(t))return[Pn,[t,Mn,...r]];if(await Bn(n))return[`bun`,[`run`,n,Mn,...r]];let i=b.resolve(kn,`..`,`..`),a=b.join(i,`dist`,Fn),o=b.join(i,`src`,In);if(await Bn(a))return[Pn,[a,Mn,...r]];if(await Bn(o))return[`bun`,[`run`,o,Mn,...r]];throw new Rn(`Cannot find CLI at ${t}, ${n}, ${a}, or ${o}`)}async startHttpServer(e){let[t,n]=await this.resolveCliCommand(e),r=F(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 Rn(`Failed to spawn HTTP server process: ${i.message}`,{cause:i});r.unref();let a=r.pid;if(!a)throw new Rn(`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)===Nn){console.error(`${Y} 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)===Nn){console.error(`${Y} 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(`${Y} 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!==J)return await this.cleanupFailedSpawn(n,t),{success:!1,reason:`service_name_mismatch`,port:t,error:`Expected ${J}, got ${r.serviceName}`};let i=await this.findRegistrationByPort(t);return!i||i.pid!==n?(console.error(`${Y} 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(`${Y} Server self-registered on port ${t} (pid: ${i.pid})`),{success:!0,port:t,pid:n,browserCount:r.browserCount})}async ensureRunning(e=wn(),t={}){try{if(t.exactPort){let t=await this.discoverHealthyServiceOnPort(e);if(t)return{running:!0,port:t.entry.port,pid:t.entry.pid,browserCount:t.browserCount,spawned:!1};await this.cleanupStaleEntries(),await this.ensureExactPortAvailable(e);let n=await this.attemptSpawn(e);if(n.success)return{running:!0,port:n.port,pid:n.pid,browserCount:n.browserCount,spawned:!0};let r=new Rn(`Failed to start browse-tool HTTP server on requested port ${e}: ${n.reason}`);return this.buildErrorStatus(r)}let n=await this.discoverHealthyService();if(n)return{running:!0,port:n.entry.port,pid:n.entry.pid,browserCount:n.browserCount,spawned:!1};await this.cleanupStaleEntries();let r=e;for(let e=0;e<3;e+=1){let t=await this.attemptSpawn(r);if(t.success)return{running:!0,port:t.port,pid:t.pid,browserCount:t.browserCount,spawned:!0};console.error(`${Y} Spawn attempt ${e+1} failed: ${t.reason} on port ${t.port}`),r=t.port+1}let i=new Rn(`Failed to start browse-tool HTTP server after 3 attempts`);return this.buildErrorStatus(i)}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(`${Y} ${r.message}`),t.push(r)}if(t.length>0){let n=t.map(e=>e.message);throw new zn(`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)}}};Wn=V([v(),B(0,_(R.HttpServerHealthCheck)),B(1,_(R.PortRegistryService)),B(2,_(R.ProcessRegistryService)),z(`design:paramtypes`,[Object,Object,typeof(Dn=m!==void 0&&m)==`function`?Dn:Object])],Wn);const Gn=900*1e3,Kn=1800*1e3,qn=`PLAYWRIGHT_BROWSER_IDLE_TIMEOUT_MINUTES`;function Jn(){let e=process.env[qn];if(!e)return Kn;let t=Number.parseFloat(e);return!Number.isFinite(t)||t<=0?Kn:Math.round(t*60*1e3)}let Yn=class{intervalId=null;browserIdleTimeoutMs=Jn();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: ${Gn/6e4}min, browser timeout: ${this.browserIdleTimeoutMs/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<Gn)){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?Gn:this.browserIdleTimeoutMs,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)}}}}};Yn=V([v(),B(0,_(R.BrowserService)),B(1,_(R.PageRegistry)),z(`design:paramtypes`,[Object,Object])],Yn);let Xn=class{constructor(e){this.portRegistry=e}async findAvailablePort(e){let t=await this.portRegistry.findAvailablePort({repositoryPath:e.repositoryPath,serviceName:`browse-tool-http`,serviceType:`tool`,environment:e.environment,host:e.host,preferredPort:e.preferredPort,portRange:e.exactPort?{min:e.preferredPort,max:e.preferredPort}:void 0});if(!t.success||!t.port)throw Error(t.error||`Failed to acquire HTTP port from ${e.preferredPort}`);return t.port}async acquirePorts(e){let t,n=!1;try{if(e.reserveMcpPort){let n=e.preferredMcpPort??l.min,r=await this.portRegistry.reservePort({repositoryPath:e.repositoryPath,serviceName:e.mcpServiceName??`browse-tool-mcp-http`,serviceType:e.mcpServiceType??`tool`,environment:e.environment,preferredPort:n,pid:e.pid,host:e.host,force:!0,portRange:{min:n,max:n},metadata:e.mcpMetadata});if(!r.success||!r.record)throw Error(r.error||`Failed to reserve MCP port ${n}`);t=r.record}return{httpPort:await this.findAvailablePort({repositoryPath:e.repositoryPath,environment:e.environment,host:e.host,preferredPort:e.preferredHttpPort??l.min,exactPort:e.exactHttpPort}),mcpPort:t?.port,release:async()=>{n||!t||(n=!0,await this.portRegistry.releasePort({repositoryPath:t.repositoryPath,serviceName:t.serviceName,serviceType:t.serviceType,environment:t.environment,pid:t.pid}))}}}catch(e){throw t&&(n=!0,await this.portRegistry.releasePort({repositoryPath:t.repositoryPath,serviceName:t.serviceName,serviceType:t.serviceType,environment:t.environment,pid:t.pid})),e}}};Xn=V([v(),B(0,_(R.PortRegistryService)),z(`design:paramtypes`,[Object])],Xn);let Zn=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()}};Zn=V([v()],Zn);let Qn=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)}};Qn=V([v()],Qn);let $n=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}};$n=V([v(),B(0,_(R.WebSocketHub)),B(0,y()),z(`design:paramtypes`,[Object])],$n);let er=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)}};er=V([v()],er);let tr=class{profilesDir;constructor(){this.profilesDir=process.env.PLAYWRIGHT_PROFILES_DIR||T(he(),`.browse-tool`,`profiles`)}getProfilesDir(){return this.profilesDir}getProfileDir(e){return T(this.getProfilesDir(),e)}getProfilePath(e){return T(this.getProfileDir(e),`profile.json`)}getStorageStatePath(e){return T(this.getProfileDir(e),`storage-state.json`)}async ensureProfilesDir(){let e=this.getProfilesDir();k(e)||await A(e,{recursive:!0})}async list(){await this.ensureProfilesDir();let e=await ce(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(!k(t))return null;let n=await j(t,`utf-8`);return JSON.parse(n)}async create(e){if(await this.get(e.name))throw Error(`Profile "${e.name}" already exists`);await A(this.getProfileDir(e.name),{recursive:!0});let t=new Date().toISOString(),n={...e,createdAt:t,updatedAt:t};return await M(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 M(this.getProfilePath(e),JSON.stringify(r,null,2)),r}async delete(e){if(!await this.get(e))throw Error(`Profile "${e}" not found`);await ue(this.getProfileDir(e),{recursive:!0})}async saveStorageState(e,t){if(!await this.get(e))throw Error(`Profile "${e}" not found`);await M(this.getStorageStatePath(e),JSON.stringify(t,null,2))}async loadStorageState(e){let t=this.getStorageStatePath(e);if(!k(t))return null;let n=await j(t,`utf-8`);return JSON.parse(n)}};tr=V([v(),z(`design:paramtypes`,[])],tr);const nr=`BROWSE_TOOL_PROXY_CONFIG_DIR`,rr=`session`,ir=/\$\{([A-Z0-9_]+)\}/gi;function ar(e){return e.PLAYWRIGHT_PROFILES_DIR||x.join(he(),`.browse-tool`,`profiles`)}function or(e){let t=e.env??process.env,n=e.proxyConfigDir??t.BROWSE_TOOL_PROXY_CONFIG_DIR;if(n)return x.resolve(n);let r=e.profilesDir??ar(t);return x.join(x.dirname(x.resolve(r)),`proxy-config`)}function sr(e){if(!e||e.includes(`/`)||e.includes(`\\`)||e===`.`||e===`..`)throw Error(`Invalid proxy config name: ${e}`)}function cr(e,t){sr(t);let n=x.resolve(e),r=x.resolve(n,`${t}.yaml`),i=x.relative(n,r);if(i.startsWith(`..`)||x.isAbsolute(i))throw Error(`Proxy config path escapes configured directory: ${t}`);return r}function lr(e,t,n){return e.replace(ir,(e,r)=>{let i=t[r];if(i===void 0)throw Error(`Missing environment variable "${r}" referenced by proxy config ${n}`);return i})}function ur(e,t,n){let r=cr(e,t);if(!k(r))return;let i=Re(re(r,`utf8`));if(!i||typeof i!=`object`||Array.isArray(i))throw Error(`Proxy config ${r} must be a YAML object`);let a=i,o={server:dr(a,`server`,r,n)},s=fr(a,`username`,r,n),c=fr(a,`password`,r,n),l=fr(a,`bypass`,r,n);return s!==void 0&&(o.username=s),c!==void 0&&(o.password=c),l!==void 0&&(o.bypass=l),o}function dr(e,t,n,r){let i=fr(e,t,n,r);if(!i)throw Error(`Proxy config ${n} must define a non-empty "${t}" string`);return i}function fr(e,t,n,r){let i=e[t];if(i!=null){if(typeof i!=`string`)throw Error(`Proxy config ${n} field "${t}" must be a string`);return lr(i,r,n)}}function pr(e){return!!e&&e!==!0&&typeof e==`object`}let X=class{getProxyConfigDir(e={}){return or(e)}resolve(e){if(pr(e.proxy))return e.proxy;let t=e.env??process.env,n=or(e);if(e.profileName){let r=ur(n,e.profileName,t);if(r)return r}if(e.proxy===!0){let e=ur(n,rr,t);if(!e)throw Error(`Proxy requested but ${cr(n,rr)} was not found`);return e}return ur(n,`default`,t)}};X=V([v()],X);function mr(e){return new X().resolve(e)}let hr=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(q(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}};hr=V([v(),B(0,_(R.HttpBrowserClient)),z(`design:paramtypes`,[Object])],hr);let gr=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}};gr=V([v(),B(0,_(R.SpecBundlerService)),z(`design:paramtypes`,[Object])],gr);const Z=`[SpecBundler]`,_r=RegExp(`^@playwright\\/test$`),vr=`__PLAYWRIGHT_MCP_STUB_PATH__`,yr={OUTDIR_NAME:`browse-tool-bundles`,PLUGIN_NAME:`playwright-test-alias`,EXTERNALS:[`playwright`,`playwright/test`,`playwright-core`]},br={BUILD_FAILED:`SPEC_BUNDLER_BUILD_FAILED`,NO_OUTPUT:`SPEC_BUNDLER_NO_OUTPUT`,IO_FAILED:`SPEC_BUNDLER_IO_FAILED`},Q={UNEXPECTED_BUILD:`Unexpected build exception`,IO_MKDIR:`Failed to create output directory`,CLEANUP_FAILED:`Failed to clean up temporary file`};var xr=class extends Error{code=br.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 "${S(e)}": ${t}`,n),this.specPath=e,this.buildErrors=t,this.name=`SpecBundlerBuildError`}},Sr=class extends Error{code=br.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`}};let Cr=class{stubPath;nodeModulesPath;constructor(){let e=C(import.meta.url.replace(`file://`,``));this.stubPath=T(e,`stubs`,`playwright-test.mjs`),this.nodeModulesPath=this.findNodeModules(e)}findNodeModules(e){let t=e,n=D(`/`);for(;t!==n;){let e=T(t,`node_modules`);if(k(T(e,`playwright`)))return e;t=C(t)}for(t=e;t!==n;){let e=T(t,`node_modules`);if(k(e))return e;t=C(t)}return T(e,`node_modules`)}async bundle(e){let t=T(P(),yr.OUTDIR_NAME);try{await A(t,{recursive:!0})}catch(e){throw console.error(`${Z} ${Q.IO_MKDIR} "${t}":`,e),new Sr(Q.IO_MKDIR,t,{cause:e})}let n=T(t,`node_modules`);if(!k(n))try{await fe(this.nodeModulesPath,n,`junction`)}catch{}return this.bundleWithEsbuild(e,t)}async bundleWithEsbuild(e,t){let n=S(e).replace(/\.[^.]+$/,``),r=this.stubPath;try{let i=await ze({entryPoints:[e],outdir:t,bundle:!0,platform:`node`,format:`esm`,target:`node18`,banner:{js:`import { createRequire as __esbuildCreateRequire } from 'module'; const require = __esbuildCreateRequire(import.meta.url);`},external:[...yr.EXTERNALS],define:{[vr]:JSON.stringify(r)},plugins:[{name:yr.PLUGIN_NAME,setup(e){e.onResolve({filter:_r},()=>({path:r}))}}],write:!0,logLevel:`silent`});if(i.errors.length>0){let t=i.errors.map(e=>e.text).join(`
9
+ `)}async function Ht(e){let t=c(await j(e,`utf8`),{mode:`strip`});return await import(`data:text/javascript;base64,${Buffer.from(t,`utf8`).toString(`base64`)}`)}var Ut=class{constructor(e=process.env.BROWSE_TOOL_SNIPPETS_DIR){this.snippetsDir=e}getDirectory(){return this.snippetsDir?x.resolve(this.snippetsDir):void 0}async listSnippets(){let e=this.requireDirectory();await A(e,{recursive:!0});let t=await ce(e,{withFileTypes:!0}),n=[];for(let r of t){if(!r.isFile()||!r.name.endsWith(`.ts`))continue;let t=r.name,i=await Ht(x.join(e,r.name)),a=typeof i.name==`string`&&i.name.trim().length>0?i.name:r.name.replace(/\.ts$/,``),o=typeof i.description==`string`?i.description:``;n.push({name:a,description:o,snippetPath:t})}return n.sort((e,t)=>e.name.localeCompare(t.name)),n}async loadSnippet(e){let t=await this.resolveSnippetPath(e),n=await Ht(t.filePath);if(typeof n.run!=`function`)throw Error(`Snippet "${t.snippetPath}" must export a "run" function`);return{name:typeof n.name==`string`&&n.name.trim().length>0?n.name:t.snippetPath.replace(/\.ts$/,``),description:typeof n.description==`string`?n.description:``,snippetPath:t.snippetPath,run:n.run}}async saveSnippet(e){let t=this.requireDirectory();await A(t,{recursive:!0});let n=`${zt(e.name)}.ts`;return await M(x.join(t,n),Vt(e),`utf8`),{name:e.name,description:e.description,snippetPath:n}}requireDirectory(){let e=this.getDirectory();if(!e)throw Error(`Snippet storage is not configured. Start browse-tool with --snippets-dir.`);return e}async resolveSnippetPath(e){let t=this.requireDirectory(),n=e.endsWith(`.ts`)?e:`${e}.ts`,r=x.resolve(t,n);if(!r.startsWith(`${t}${x.sep}`)&&r!==x.join(t,n))throw Error(`Snippet path must stay within the configured snippets directory`);if(!(await de(r).catch(()=>null))?.isFile())throw Error(`Snippet "${e}" not found`);return{filePath:r,snippetPath:x.relative(t,r)}}};const W=I.object({uid:I.string().optional().describe(`Accessibility snapshot UID reference`),role:I.string().optional().describe(`ARIA role (e.g., "button", "textbox")`),name:I.string().optional().describe(`Accessible name used with the role selector`),label:I.string().optional().describe(`Associated label text`),placeholder:I.string().optional().describe(`Placeholder text`),testId:I.string().optional().describe(`data-testid value`),text:I.string().optional().describe(`Visible text content`),exact:I.boolean().optional().default(!1).describe(`Use exact matching for semantic selectors`),selector:I.string().optional().describe(`CSS selector`),xpath:I.string().optional().describe(`XPath expression`),frame:I.string().optional().describe(`Frame selector`)});let Wt=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??18e4,state:n.state??`visible`}),i.first()}async getFrameContext(e,t){return t?e.frameLocator(t):e}buildLocator(e,t){let n=t.exact??!1;if(t.uid)return e.locator(`[data-pw-proxy="${t.uid}"], [data-browse-tool-uid="${t.uid}"], [data-uid="${t.uid}"]`);if(t.role){let r=t.role;return t.name?e.getByRole(r,{name:t.name,exact:n}):e.getByRole(r)}if(t.label)return e.getByLabel(t.label,{exact:n});if(t.placeholder)return e.getByPlaceholder(t.placeholder,{exact:n});if(t.testId)return e.getByTestId(t.testId);if(t.text)return e.getByText(t.text,{exact:n});if(t.selector)return e.locator(t.selector);if(t.xpath)return e.locator(`xpath=${t.xpath}`);throw Error(`No selector provided. Specify one of: uid, role, label, placeholder, text, selector, or xpath.`)}describeSelector(e){let t=[];return e.uid&&t.push(`uid="${e.uid}"`),e.role&&t.push(`role="${e.role}"`),e.name&&t.push(`name="${e.name}"`),e.label&&t.push(`label="${e.label}"`),e.placeholder&&t.push(`placeholder="${e.placeholder}"`),e.testId&&t.push(`testId="${e.testId}"`),e.text&&t.push(`text="${e.text}"`),e.exact&&t.push(`exact=true`),e.selector&&t.push(`selector="${e.selector}"`),e.xpath&&t.push(`xpath="${e.xpath}"`),e.frame&&t.push(`frame="${e.frame}"`),t.length>0?t.join(`, `):`empty selector`}};Wt=V([v()],Wt);const Gt=process.env.BROWSE_TOOL_DEBUG_CUSTOM_TOOLS===`1`;function Kt(e){return JSON.stringify(e,(e,t)=>typeof t==`string`&&t.length>240?`${t.slice(0,240)}...<trimmed>`:t)}function G(e,t){if(Gt){if(t){console.error(`[ExtensionPageProxy] ${e}`,t);return}console.error(`[ExtensionPageProxy] ${e}`)}}function qt(e){return typeof e==`object`&&e&&`value`in e?e.value:e}let Jt=class{[o]=!0;currentUrl=`about:blank`;defaultTimeoutMs=H;_pageId;_browserId;constructor(e){this.taskQueue=e}setTarget(e,t){this._pageId=e,this._browserId=t,this.currentUrl=`about:blank`,this.currentUrlAsync().catch(()=>{})}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 qt(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 qt(e.result)??``}async textContent(e){return this.locator(e).textContent()}async innerText(e){return this.locator(e).innerText()}async inputValue(e){return this.locator(e).inputValue()}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 qt(r.result)}async getSnapshot(){let e=await this.executeTask(`browser_snapshot`,{});if(!e.success)throw Error(e.error??`Get snapshot failed`);let t=qt(e.result);return typeof t==`string`?t:t==null?``:JSON.stringify(t,null,2)}getByRole(e,t){return new s(this,[{type:`role`,role:e,options:t}])}getByText(e,t){return new s(this,[{type:`text`,text:e,options:t}])}getByLabel(e,t){return new s(this,[{type:`label`,text:e,options:t}])}getByPlaceholder(e,t){return new s(this,[{type:`placeholder`,text:e,options:t}])}getByTestId(e){return new s(this,[{type:`testId`,testId:e}])}locator(e){return new s(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};G(`Queueing extension task`,{tool:e,browserId:this._browserId,pageId:this._pageId,args:Kt(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 G(`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 G(`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 G(`Extension task completed with JSON text result`,{tool:e,browserId:this._browserId,pageId:this._pageId}),{success:!0,result:t}}catch{return G(`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 G(`Extension task completed with non-text result payload`,{tool:e,browserId:this._browserId,pageId:this._pageId,taskResult:r}),{success:!0,result:r.result}}};Jt=V([v(),B(0,_(R.ExtensionTaskQueue)),z(`design:paramtypes`,[Object])],Jt);let Yt=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}};Yt=V([v()],Yt);let Xt=class{constructor(e,t,n){this.bundler=e,this.pageProxy=t,this.sessionRegistry=n}async loadSpec(e){let n=await this.bundler.bundle(e),a=process,o=a.__pw_initiator__;try{return t(e),a.__pw_initiator__=void 0,await import(`${n.outputPath}?t=${Date.now()}`),i()}catch(t){throw r(),Error(`Failed to load spec "${e}": ${t instanceof Error?t.message:String(t)}`,{cause:t})}finally{a.__pw_initiator__=o,await n.cleanup()}}async executeSpec(e){let{specPath:t,sessionId:r,testFilter:i,specArgs:a,onHandoff:o}=e,s=Date.now(),c=[],l=0,u=0,d=!1,f=new Set,p=new Set;this.sessionRegistry.setActiveSpec(r,t);try{let e=await this.loadSpec(t),m=i?this.filterTests(e.allTests,i):e.allTests,h={page:this.pageProxy,requestHandoff:async e=>{if(!this.sessionRegistry.getSession(r))throw Error(`Session ${r} not found`);let t=await this.pageProxy.getSnapshot(),n=this.pageProxy.url();try{n=await this.pageProxy.currentUrlAsync()}catch{}this.sessionRegistry.requestHandoff({sessionId:r,reason:e,pageState:{url:n,snapshot:t}}),d=!0,o&&await o(r)},specArgs:a};for(let e of m){let{runtimeUse:t,unsupportedKeys:i,fixtureOverrides:a}=n(e.config.use);i.length>0&&f.add(`test.use() ignores unsupported fixture keys in extension mode: ${i.join(`, `)}`),Object.keys(t).length>0&&f.add(`test.use() runtime browser config is not applied in extension mode: ${Object.keys(t).join(`, `)}`);let o=e.serialScopeId,s=o!==void 0&&p.has(o);if(e.skip||s){c.push({title:e.title,fullTitle:e.fullTitle,passed:!0,error:null,duration:0}),l++;continue}let d=this.sessionRegistry.getSession(r);if(d?.handoffRequested)break;let m=Date.now();try{await e.fn({...h,...a}),c.push({title:e.title,fullTitle:e.fullTitle,passed:!0,error:null,duration:Date.now()-m,handoffTriggered:d?.handoffRequested}),l++}catch(t){let n=t instanceof Error?t.message:String(t);c.push({title:e.title,fullTitle:e.fullTitle,passed:!1,error:n,duration:Date.now()-m}),u++,o!==void 0&&p.add(o)}}return{specPath:t,totalTests:m.length,passed:l,failed:u,testResults:c,success:u===0,duration:Date.now()-s,handoffOccurred:d,sessionId:r,warnings:f.size>0?[...f]:void 0}}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,handoffOccurred:!1,sessionId:r,warnings:f.size>0?[...f]:void 0}}finally{this.sessionRegistry.setActiveSpec(r,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}};Xt=V([v(),B(0,_(R.SpecBundlerService)),B(1,_(R.ExtensionPageProxy)),B(2,_(R.ExtensionSessionRegistry)),z(`design:paramtypes`,[Object,Object,Object])],Xt);const Zt=`browse-tool-http`,Qt=[`pnpm-workspace.yaml`,`nx.json`,`.git`],$t=new Set([`127.0.0.1`,`localhost`,`::1`,`0.0.0.0`]);function en(e){return e===`1`||e===`true`}function tn(e){return Array.isArray(e)?JSON.stringify(e):typeof e==`string`||typeof e==`number`||typeof e==`boolean`?e:JSON.stringify(e)}function nn(e){if(!e)return;let t={};for(let[n,r]of Object.entries(e))r!=null&&(t[n]=tn(r));return Object.keys(t).length>0?t:void 0}function rn(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 an(e){if(!e)return;let t=Number(e);return Number.isFinite(t)&&t>0?t:void 0}function on(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 sn(e){return $t.has(e)}function cn(e=process.cwd()){let t=x.resolve(e);for(;;){for(let e of Qt)if(k(x.join(t,e)))return t;let e=x.dirname(t);if(e===t)return process.cwd();t=e}}function ln(e,t=process.cwd()){try{let n=re(d.resolveRegistryPath(e.PORT_REGISTRY_PATH??u),`utf8`),r=f.parse(JSON.parse(n)),i=p(cn(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 un(e,t){try{let n=new URL(e),r=new URL(t);return!sn(n.hostname)||sn(r.hostname)||(n.hostname=r.hostname),n.toString()}catch{return e}}function dn(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 on(r,t);let i=ln(e);return i?on(i,t):void 0}function fn(e,t,n){let r=t===`traces`?e.BROWSE_TOOL_OTEL_BROWSER_TRACES_ENDPOINT:e.BROWSE_TOOL_OTEL_BROWSER_LOGS_ENDPOINT;if(r)return un(r,n);let i=e.BROWSE_TOOL_OTEL_BROWSER_ENDPOINT;if(i)return un(on(i,t),n);let a=dn(e,t);return a?un(a,n):void 0}function pn(e,t){let n=e.BROWSE_TOOL_OTEL_BROWSER_SERVICE_NAME??`${e.OTEL_SERVICE_NAME??Zt}-extension`,r=fn(e,`traces`,t),i=fn(e,`logs`,t);return{enabled:!!(r||i),tracesEndpoint:r,logsEndpoint:i,serviceName:n}}function mn(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:dn(e,t),headers:rn(n??e.OTEL_EXPORTER_OTLP_HEADERS),timeoutMillis:an(r??e.OTEL_EXPORTER_OTLP_TIMEOUT)}}function hn(e){return e instanceof Error?e.message:String(e)}function gn(e){if(e instanceof Error)return nn({"exception.type":e.name,"exception.message":e.message,"exception.stacktrace":e.stack})}let _n=class{contextStore=new Ee;tracesEnabled;logsEnabled;tracerProvider;tracer;logSinkReady;constructor(e={}){let t=e.env??process.env,n=en(t.OTEL_SDK_DISABLED),r=en(t.BROWSE_TOOL_OTEL_ENABLED),i=mn(t,`traces`);this.tracesEnabled=!n&&(r||!!i.url),this.logsEnabled=!n;let a=e.serviceName??t.BROWSE_TOOL_OTEL_SERVICE_NAME??t.OTEL_SERVICE_NAME??Zt,o=e.serviceVersion??t.npm_package_version,s={"service.name":a};o&&(s[`service.version`]=o);let c=Ne(s);if(this.tracesEnabled){let t=e.traceExporter??new Me(i);this.tracerProvider=new Fe({resource:c,spanProcessors:[e.traceExporter?new Ie(t):new Pe(t)]})}this.tracer=this.tracerProvider?.getTracer(a,o)??je.getTracer(a,o),this.logSinkReady=this.logsEnabled?De({env:t,serviceName:a,serviceVersion:o,workspaceRoot:cn(),enableTraces:!1,enableLogs:!0}).catch(()=>null):Promise.resolve(null)}isEnabled(){return this.tracesEnabled||this.logsEnabled}getActiveTraceContext(){let e=this.contextStore.getStore();if(!e)return{};let t=je.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()??Ae.active(),i=this.tracer.startSpan(e,{kind:t.kind??Oe.INTERNAL,attributes:nn(t.attributes)},r),a=je.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(hn(e))),i.setStatus({code:ke.ERROR,message:hn(e)}),e}finally{i.end()}})}log(e,t,n={}){this.logsEnabled&&this.logSinkReady.then(r=>{if(!r)return;let i=n.context??this.contextStore.getStore()??Ae.active(),a=gn(n.exception);r.logger[e](t,{attributes:nn({...n.attributes,...a}),context:i,exception:n.exception})})}async forceFlush(){let e=await this.logSinkReady;await Promise.allSettled([this.tracerProvider?.forceFlush(),e?.flush()])}async shutdown(){let e=await this.logSinkReady;await Promise.allSettled([this.tracerProvider?.shutdown(),e?.shutdown()])}};_n=V([v(),z(`design:paramtypes`,[Object])],_n);let vn=class{pendingTasks=new Map;taskQueue=[];lastPollAt;lastResultAt;maxQueueSize=100;defaultTimeoutMs=H;constructor(e,t=new _n){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}}};vn=V([v(),B(0,_(R.WebSocketHub)),B(0,y()),B(1,_(R.TelemetryService)),B(1,y()),z(`design:paramtypes`,[Object,Object])],vn);const yn=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_inspect_element.browser_resolve_locator.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(`.`)),bn=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 xn=class{constructor(e){this.taskQueue=e}isToolSupported(e){return yn.has(e)}isToolNotApplicable(e){return bn.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(yn)}getNotApplicableTools(){return Array.from(bn)}};xn=V([v(),B(0,_(R.ExtensionTaskQueue)),z(`design:paramtypes`,[Object])],xn);const Sn=l.min,Cn=`PLAYWRIGHT_PORT`;function K(){return process.env.PLAYWRIGHT_HOST?.trim()||`localhost`}function wn(){let e=process.env[Cn];if(!e)return Sn;let t=Number.parseInt(e,10);if(Number.isNaN(t)||t<=0||t>65535)throw Error(`Invalid ${Cn} value: ${e}`);return t}function q(e=void 0,t){let n=typeof e==`string`?e:e?.host??K(),r=e&&typeof e!=`string`?e.port:t??wn();return`http://${n===`0.0.0.0`?`127.0.0.1`:n===`::`?`::1`:n}:${r}`}let Tn=class{baseUrl;defaultTimeout=H;constructor(){this.baseUrl=q()}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=await fetch(n,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({tool:e,arguments:t}),signal:r.signal});if(clearTimeout(i),!a.ok){let e=await a.text();return{content:[{type:`text`,text:`HTTP error ${a.status}: ${e}`}],isError:!0}}let o=await a.json();return o.success?o.result||{content:[{type:`text`,text:`No result returned`}]}:{content:[{type:`text`,text:o.error||o.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}}};Tn=V([v(),z(`design:paramtypes`,[])],Tn);let En=class{defaultTimeout=5e3;async check(e,t=this.defaultTimeout){try{let n=`${q(K(),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)}}}};En=V([v()],En);var Dn;const On=ye(import.meta.url),kn=b.dirname(On),An=[`pnpm-workspace.yaml`,`nx.json`,`.git`],J=`browse-tool-http`,jn=`tool`,Mn=`http-serve`,Nn=`ESRCH`,Pn=`node`,Fn=`cli.mjs`,In=`cli.ts`,Y=`[HttpServerManager]`;var Ln=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`}},Rn=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`}},zn=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 Bn(e){try{return await ae.access(e),!0}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return!1;throw e}}const Vn=Le(_e);async function Hn(e){try{let{stdout:t}=await Vn(`git`,[`rev-parse`,`--git-common-dir`],{cwd:e}),n=t.trim(),r=b.isAbsolute(n)?n:b.join(e,n),i=b.dirname(r);return i===e?null:i}catch{return null}}async function Un(e=process.cwd()){let t=b.resolve(e);for(;;){for(let e of An)if(await Bn(b.join(t,e)))return t;let e=b.dirname(t);if(e===t)return process.cwd();t=e}}let Wn=class{repositoryPath;environment;host;constructor(e,t,n=new m(process.env.PROCESS_REGISTRY_PATH)){this.healthCheck=e,this.portRegistry=t,this.processRegistry=n,this.environment=process.env.NODE_ENV||`development`,this.host=K()}async getRepositoryPath(){return this.repositoryPath||=await Un(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(){let e=await this.getRepositoryPath(),t={serviceName:J,serviceType:jn,environment:this.environment},n=await this.portRegistry.listAllocations({...t,repositoryPath:e});if(n.length>0)return n;let r=await Hn(e);if(r){let e=await this.portRegistry.listAllocations({...t,repositoryPath:r});if(e.length>0)return e}return this.portRegistry.listAllocations(t)}async releaseEntry(e){if(e.pid){let t=await this.processRegistry.releaseProcess({repositoryPath:e.repositoryPath,serviceName:J,serviceType:`service`,environment:e.environment,pid:e.pid,kill:!1,releasePort:!1});!t.success&&!t.error?.includes(`No matching process entry`)&&console.error(`${Y} Failed to release process entry for port ${e.port}: ${t.error}`)}let t=await this.portRegistry.releasePort({repositoryPath:e.repositoryPath,serviceName:J,serviceType:jn,environment:e.environment,pid:e.pid});!t.success&&!t.error?.includes(`No matching registry entry`)&&console.error(`${Y} 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===J)return{entry:t,browserCount:e.browserCount}}catch(e){console.error(`${Y} Health check threw for port ${t.port}: ${e instanceof Error?e.message:String(e)}`)}return null}async discoverHealthyServiceOnPort(e){let t=await this.findRegistrationByPort(e);if(!t)return null;try{let n=await this.healthCheck.check(e);if(n.healthy&&n.serviceName===J)return{entry:t,browserCount:n.browserCount}}catch(t){console.error(`${Y} Health check threw for requested port ${e}: ${t instanceof Error?t.message:String(t)}`)}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(`${Y} Health check threw for port ${n.port}, skipping cleanup: ${e instanceof Error?e.message:String(e)}`);continue}e.healthy&&e.serviceName===J||(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(`${Y} ${r}`),t.push(r)}t.length>0&&console.error(`${Y} ${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,t={}){let n=await this.getRepositoryPath(),r=await this.portRegistry.findAvailablePort({repositoryPath:n,serviceName:J,serviceType:jn,environment:this.environment,host:this.host,preferredPort:e,portRange:t.exactPort?{min:e,max:e}:void 0});if(!r.success||!r.port)throw new Ln(`No available port found from ${e}: ${r.error}`);return r.port}async ensureExactPortAvailable(e){let t=await this.findAvailablePort(e,{exactPort:!0});if(t!==e)throw new Ln(`Requested port ${e} is unavailable; next available port is ${t}`)}async resolveCliCommand(e){let t=b.resolve(kn,Fn),n=b.resolve(kn,`..`,In),r=[`--port`,e.toString(),`--host`,this.host];if(await Bn(t))return[Pn,[t,Mn,...r]];if(await Bn(n))return[`bun`,[`run`,n,Mn,...r]];let i=b.resolve(kn,`..`,`..`),a=b.join(i,`dist`,Fn),o=b.join(i,`src`,In);if(await Bn(a))return[Pn,[a,Mn,...r]];if(await Bn(o))return[`bun`,[`run`,o,Mn,...r]];throw new Rn(`Cannot find CLI at ${t}, ${n}, ${a}, or ${o}`)}async startHttpServer(e){let[t,n]=await this.resolveCliCommand(e),r=F(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 Rn(`Failed to spawn HTTP server process: ${i.message}`,{cause:i});r.unref();let a=r.pid;if(!a)throw new Rn(`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)===Nn){console.error(`${Y} 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)===Nn){console.error(`${Y} 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(`${Y} 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!==J)return await this.cleanupFailedSpawn(n,t),{success:!1,reason:`service_name_mismatch`,port:t,error:`Expected ${J}, got ${r.serviceName}`};let i=await this.findRegistrationByPort(t);return!i||i.pid!==n?(console.error(`${Y} 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(`${Y} Server self-registered on port ${t} (pid: ${i.pid})`),{success:!0,port:t,pid:n,browserCount:r.browserCount})}async ensureRunning(e=wn(),t={}){try{if(t.exactPort){let t=await this.discoverHealthyServiceOnPort(e);if(t)return{running:!0,port:t.entry.port,pid:t.entry.pid,browserCount:t.browserCount,spawned:!1};await this.cleanupStaleEntries(),await this.ensureExactPortAvailable(e);let n=await this.attemptSpawn(e);if(n.success)return{running:!0,port:n.port,pid:n.pid,browserCount:n.browserCount,spawned:!0};let r=new Rn(`Failed to start browse-tool HTTP server on requested port ${e}: ${n.reason}`);return this.buildErrorStatus(r)}let n=await this.discoverHealthyService();if(n)return{running:!0,port:n.entry.port,pid:n.entry.pid,browserCount:n.browserCount,spawned:!1};await this.cleanupStaleEntries();let r=e;for(let e=0;e<3;e+=1){let t=await this.attemptSpawn(r);if(t.success)return{running:!0,port:t.port,pid:t.pid,browserCount:t.browserCount,spawned:!0};console.error(`${Y} Spawn attempt ${e+1} failed: ${t.reason} on port ${t.port}`),r=t.port+1}let i=new Rn(`Failed to start browse-tool HTTP server after 3 attempts`);return this.buildErrorStatus(i)}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(`${Y} ${r.message}`),t.push(r)}if(t.length>0){let n=t.map(e=>e.message);throw new zn(`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)}}};Wn=V([v(),B(0,_(R.HttpServerHealthCheck)),B(1,_(R.PortRegistryService)),B(2,_(R.ProcessRegistryService)),z(`design:paramtypes`,[Object,Object,typeof(Dn=m!==void 0&&m)==`function`?Dn:Object])],Wn);const Gn=900*1e3,Kn=1800*1e3,qn=`PLAYWRIGHT_BROWSER_IDLE_TIMEOUT_MINUTES`;function Jn(){let e=process.env[qn];if(!e)return Kn;let t=Number.parseFloat(e);return!Number.isFinite(t)||t<=0?Kn:Math.round(t*60*1e3)}let Yn=class{intervalId=null;browserIdleTimeoutMs=Jn();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: ${Gn/6e4}min, browser timeout: ${this.browserIdleTimeoutMs/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<Gn)){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?Gn:this.browserIdleTimeoutMs,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)}}}}};Yn=V([v(),B(0,_(R.BrowserService)),B(1,_(R.PageRegistry)),z(`design:paramtypes`,[Object,Object])],Yn);let Xn=class{constructor(e){this.portRegistry=e}async findAvailablePort(e){let t=await this.portRegistry.findAvailablePort({repositoryPath:e.repositoryPath,serviceName:`browse-tool-http`,serviceType:`tool`,environment:e.environment,host:e.host,preferredPort:e.preferredPort,portRange:e.exactPort?{min:e.preferredPort,max:e.preferredPort}:void 0});if(!t.success||!t.port)throw Error(t.error||`Failed to acquire HTTP port from ${e.preferredPort}`);return t.port}async acquirePorts(e){let t,n=!1;try{if(e.reserveMcpPort){let n=e.preferredMcpPort??l.min,r=await this.portRegistry.reservePort({repositoryPath:e.repositoryPath,serviceName:e.mcpServiceName??`browse-tool-mcp-http`,serviceType:e.mcpServiceType??`tool`,environment:e.environment,preferredPort:n,pid:e.pid,host:e.host,force:!0,portRange:{min:n,max:n},metadata:e.mcpMetadata});if(!r.success||!r.record)throw Error(r.error||`Failed to reserve MCP port ${n}`);t=r.record}return{httpPort:await this.findAvailablePort({repositoryPath:e.repositoryPath,environment:e.environment,host:e.host,preferredPort:e.preferredHttpPort??l.min,exactPort:e.exactHttpPort}),mcpPort:t?.port,release:async()=>{n||!t||(n=!0,await this.portRegistry.releasePort({repositoryPath:t.repositoryPath,serviceName:t.serviceName,serviceType:t.serviceType,environment:t.environment,pid:t.pid}))}}}catch(e){throw t&&(n=!0,await this.portRegistry.releasePort({repositoryPath:t.repositoryPath,serviceName:t.serviceName,serviceType:t.serviceType,environment:t.environment,pid:t.pid})),e}}};Xn=V([v(),B(0,_(R.PortRegistryService)),z(`design:paramtypes`,[Object])],Xn);let Zn=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()}};Zn=V([v()],Zn);let Qn=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)}};Qn=V([v()],Qn);let $n=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}};$n=V([v(),B(0,_(R.WebSocketHub)),B(0,y()),z(`design:paramtypes`,[Object])],$n);let er=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)}};er=V([v()],er);let tr=class{profilesDir;constructor(){this.profilesDir=process.env.PLAYWRIGHT_PROFILES_DIR||T(he(),`.browse-tool`,`profiles`)}getProfilesDir(){return this.profilesDir}getProfileDir(e){return T(this.getProfilesDir(),e)}getProfilePath(e){return T(this.getProfileDir(e),`profile.json`)}getStorageStatePath(e){return T(this.getProfileDir(e),`storage-state.json`)}async ensureProfilesDir(){let e=this.getProfilesDir();k(e)||await A(e,{recursive:!0})}async list(){await this.ensureProfilesDir();let e=await ce(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(!k(t))return null;let n=await j(t,`utf-8`);return JSON.parse(n)}async create(e){if(await this.get(e.name))throw Error(`Profile "${e.name}" already exists`);await A(this.getProfileDir(e.name),{recursive:!0});let t=new Date().toISOString(),n={...e,createdAt:t,updatedAt:t};return await M(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 M(this.getProfilePath(e),JSON.stringify(r,null,2)),r}async delete(e){if(!await this.get(e))throw Error(`Profile "${e}" not found`);await ue(this.getProfileDir(e),{recursive:!0})}async saveStorageState(e,t){if(!await this.get(e))throw Error(`Profile "${e}" not found`);await M(this.getStorageStatePath(e),JSON.stringify(t,null,2))}async loadStorageState(e){let t=this.getStorageStatePath(e);if(!k(t))return null;let n=await j(t,`utf-8`);return JSON.parse(n)}};tr=V([v(),z(`design:paramtypes`,[])],tr);const nr=`BROWSE_TOOL_PROXY_CONFIG_DIR`,rr=`session`,ir=/\$\{([A-Z0-9_]+)\}/gi;function ar(e){return e.PLAYWRIGHT_PROFILES_DIR||x.join(he(),`.browse-tool`,`profiles`)}function or(e){let t=e.env??process.env,n=e.proxyConfigDir??t.BROWSE_TOOL_PROXY_CONFIG_DIR;if(n)return x.resolve(n);let r=e.profilesDir??ar(t);return x.join(x.dirname(x.resolve(r)),`proxy-config`)}function sr(e){if(!e||e.includes(`/`)||e.includes(`\\`)||e===`.`||e===`..`)throw Error(`Invalid proxy config name: ${e}`)}function cr(e,t){sr(t);let n=x.resolve(e),r=x.resolve(n,`${t}.yaml`),i=x.relative(n,r);if(i.startsWith(`..`)||x.isAbsolute(i))throw Error(`Proxy config path escapes configured directory: ${t}`);return r}function lr(e,t,n){return e.replace(ir,(e,r)=>{let i=t[r];if(i===void 0)throw Error(`Missing environment variable "${r}" referenced by proxy config ${n}`);return i})}function ur(e,t,n){let r=cr(e,t);if(!k(r))return;let i=Re(re(r,`utf8`));if(!i||typeof i!=`object`||Array.isArray(i))throw Error(`Proxy config ${r} must be a YAML object`);let a=i,o={server:dr(a,`server`,r,n)},s=fr(a,`username`,r,n),c=fr(a,`password`,r,n),l=fr(a,`bypass`,r,n);return s!==void 0&&(o.username=s),c!==void 0&&(o.password=c),l!==void 0&&(o.bypass=l),o}function dr(e,t,n,r){let i=fr(e,t,n,r);if(!i)throw Error(`Proxy config ${n} must define a non-empty "${t}" string`);return i}function fr(e,t,n,r){let i=e[t];if(i!=null){if(typeof i!=`string`)throw Error(`Proxy config ${n} field "${t}" must be a string`);return lr(i,r,n)}}function pr(e){return!!e&&e!==!0&&typeof e==`object`}let X=class{getProxyConfigDir(e={}){return or(e)}resolve(e){if(pr(e.proxy))return e.proxy;let t=e.env??process.env,n=or(e);if(e.profileName){let r=ur(n,e.profileName,t);if(r)return r}if(e.proxy===!0){let e=ur(n,rr,t);if(!e)throw Error(`Proxy requested but ${cr(n,rr)} was not found`);return e}return ur(n,`default`,t)}};X=V([v()],X);function mr(e){return new X().resolve(e)}let hr=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(q(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}};hr=V([v(),B(0,_(R.HttpBrowserClient)),z(`design:paramtypes`,[Object])],hr);let gr=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}};gr=V([v(),B(0,_(R.SpecBundlerService)),z(`design:paramtypes`,[Object])],gr);const Z=`[SpecBundler]`,_r=RegExp(`^@playwright\\/test$`),vr=`__PLAYWRIGHT_MCP_STUB_PATH__`,yr={OUTDIR_NAME:`browse-tool-bundles`,PLUGIN_NAME:`playwright-test-alias`,EXTERNALS:[`playwright`,`playwright/test`,`playwright-core`]},br={BUILD_FAILED:`SPEC_BUNDLER_BUILD_FAILED`,NO_OUTPUT:`SPEC_BUNDLER_NO_OUTPUT`,IO_FAILED:`SPEC_BUNDLER_IO_FAILED`},Q={UNEXPECTED_BUILD:`Unexpected build exception`,IO_MKDIR:`Failed to create output directory`,CLEANUP_FAILED:`Failed to clean up temporary file`};var xr=class extends Error{code=br.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 "${S(e)}": ${t}`,n),this.specPath=e,this.buildErrors=t,this.name=`SpecBundlerBuildError`}},Sr=class extends Error{code=br.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`}};let Cr=class{stubPath;nodeModulesPath;constructor(){let e=C(import.meta.url.replace(`file://`,``));this.stubPath=T(e,`stubs`,`playwright-test.mjs`),this.nodeModulesPath=this.findNodeModules(e)}findNodeModules(e){let t=e,n=D(`/`);for(;t!==n;){let e=T(t,`node_modules`);if(k(T(e,`playwright`)))return e;t=C(t)}for(t=e;t!==n;){let e=T(t,`node_modules`);if(k(e))return e;t=C(t)}return T(e,`node_modules`)}async bundle(e){let t=T(P(),yr.OUTDIR_NAME);try{await A(t,{recursive:!0})}catch(e){throw console.error(`${Z} ${Q.IO_MKDIR} "${t}":`,e),new Sr(Q.IO_MKDIR,t,{cause:e})}let n=T(t,`node_modules`);if(!k(n))try{await fe(this.nodeModulesPath,n,`junction`)}catch{}return this.bundleWithEsbuild(e,t)}async bundleWithEsbuild(e,t){let n=S(e).replace(/\.[^.]+$/,``),r=this.stubPath;try{let i=await ze({entryPoints:[e],outdir:t,bundle:!0,platform:`node`,format:`esm`,target:`node18`,banner:{js:`import { createRequire as __esbuildCreateRequire } from 'module'; const require = __esbuildCreateRequire(import.meta.url);`},external:[...yr.EXTERNALS],define:{[vr]:JSON.stringify(r)},plugins:[{name:yr.PLUGIN_NAME,setup(e){e.onResolve({filter:_r},()=>({path:r}))}}],write:!0,logLevel:`silent`});if(i.errors.length>0){let t=i.errors.map(e=>e.text).join(`
10
10
  `);throw console.error(`${Z} Build failed for "${e}": ${t}`),new xr(e,t,{cause:Error(t)})}let a=T(t,`${n}.js`);return{outputPath:a,cleanup:()=>this.safeUnlink(a)}}catch(t){if(t instanceof xr)throw t;let n=t instanceof Error?t.message:Q.UNEXPECTED_BUILD;throw console.error(`${Z} Build failed for "${e}":`,t),new xr(e,n,{cause:t})}}async bundleWithHooks(e){let t=T(P(),yr.OUTDIR_NAME);try{await A(t,{recursive:!0})}catch(e){throw console.error(`${Z} ${Q.IO_MKDIR} "${t}":`,e),new Sr(Q.IO_MKDIR,t,{cause:e})}let n=T(t,`node_modules`);if(!k(n))try{await fe(this.nodeModulesPath,n,`junction`)}catch{}return this.bundleSpecWithHooksEntry(e.specPath,e.hooksPath,t)}async bundleSpecWithHooksEntry(e,t,n){let r=C(D(t)),i=this.stubPath,a=[`process.env.__HOOKS_SOURCE_DIR__ = ${JSON.stringify(r)};`,`import { setup as __hooksSetup } from ${JSON.stringify(t)};`,`await __hooksSetup();`,`delete process.env.__HOOKS_SOURCE_DIR__;`,`export * from ${JSON.stringify(e)};`].join(`
11
11
  `);try{let t=await ze({stdin:{contents:a,resolveDir:C(e),loader:`ts`,sourcefile:`spec-with-hooks.ts`},outdir:n,bundle:!0,platform:`node`,format:`esm`,target:`node18`,banner:{js:`import { createRequire as __esbuildCreateRequire } from 'module'; const require = __esbuildCreateRequire(import.meta.url);`},external:[...yr.EXTERNALS],define:{[vr]:JSON.stringify(i)},plugins:[{name:yr.PLUGIN_NAME,setup(e){e.onResolve({filter:_r},()=>({path:i}))}}],write:!0,logLevel:`silent`});if(t.errors.length>0){let n=t.errors.map(e=>e.text).join(`
12
12
  `);throw console.error(`${Z} Build failed for "${e}" (with hooks): ${n}`),new xr(e,n,{cause:Error(n)})}let r=T(n,`stdin.js`);return{outputPath:r,cleanup:()=>this.safeUnlink(r)}}catch(t){if(t instanceof xr)throw t;let n=t instanceof Error?t.message:Q.UNEXPECTED_BUILD;throw console.error(`${Z} Build failed for "${e}" (with hooks):`,t),new xr(e,n,{cause:t})}}async safeUnlink(e){try{await pe(e)}catch(t){console.warn(`${Z} ${Q.CLEANUP_FAILED} "${e}":`,t)}}};Cr=V([v(),z(`design:paramtypes`,[])],Cr);let wr=class{async discoverProjects(e){let t=e||process.cwd(),n=[],r=await this.findPlaywrightConfigs(t);for(let e of r){let t=C(e),r={name:S(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=T(e,`playwright.config.ts`);if(!k(t))throw Error(`No playwright.config.ts found in ${e}`);let n=T(e,await this.getTestDirFromConfig(t));if(!k(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=D(e);if(!k(n))throw Error(`Spec file not found: ${e}`);let r=S(n);return{name:r,path:n,relativePath:t?E(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=S(e);return!(t===`node_modules`||t.startsWith(`.`))}return S(e)===`playwright.config.ts`&&t.push(e),!0}),t}async findSpecFiles(e){let t=[];return await this.walkDirectory(e,(e,n)=>n?S(e)!==`node_modules`:(e.endsWith(`.spec.ts`)&&t.push(e),!0)),t}async walkDirectory(e,t){if(!k(e))return;let n=await ce(e,{withFileTypes:!0});for(let r of n){let n=T(e,r.name);r.isDirectory()?t(n,!0)&&await this.walkDirectory(n,t):t(n,!1)}}async getTestDirFromConfig(e){try{let t=(await j(e,`utf-8`)).match(/testDir:\s*['"`]([^'"`]+)['"`]/);if(t)return t[1].replace(/^\.\//,``)}catch{}return`tests`}async checkHasArgsSchema(e){try{let t=await j(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`)}};wr=V([v()],wr);let Tr=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 j(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}};Tr=V([v(),B(0,_(R.SpecBundlerService)),z(`design:paramtypes`,[Object])],Tr);function Er(e,t){let{runtimeUse:r,unsupportedKeys:i}=n(t);return{options:{...e?{baseURL:e}:{},...r},warnings:i.length>0?[`test.use() ignores unsupported fixture keys: ${i.join(`, `)}`]:[]}}let Dr=class{constructor(e){this.bundler=e}async loadSpec(e,n){let a=n?await this.bundler.bundleWithHooks({specPath:e,hooksPath:n}):await this.bundler.bundle(e),o=process,s=o.__pw_initiator__;try{return t(e),o.__pw_initiator__=void 0,await import(`${a.outputPath}?t=${Date.now()}`),i()}catch(t){throw r(),Error(`Failed to load spec "${e}": ${t instanceof Error?t.message:String(t)}`,{cause:t})}finally{o.__pw_initiator__=s,await a.cleanup()}}async executeSpec(e){let{specPath:t,browserType:n=`chromium`,headless:r=!0,hooksPath:i,baseURL:o,keepBrowserOpen:s}=e,c=Date.now(),l=[],u=0,d=0,f=new Set,p=new Set,m=[],h=await be[n].launch({channel:`chrome`,headless:r});try{let e=await this.loadSpec(t,i);for(let t of e.allTests){let{options:e,warnings:n}=Er(o,t.config.use);for(let e of n)f.add(e);let r=t.serialScopeId,i=r!==void 0&&p.has(r);if(t.skip||i){l.push({title:t.title,fullTitle:t.fullTitle,passed:!0,error:null,duration:0}),u++;continue}let c=await h.newContext(e),g=await c.newPage(),_={page:g,context:c,browser:h,playwright:be},v=Date.now();try{await t.fn(_),l.push({title:t.title,fullTitle:t.fullTitle,passed:!0,error:null,duration:Date.now()-v}),u++}catch(e){if(e instanceof a||e instanceof Error&&`isSkip`in e)l.push({title:t.title,fullTitle:t.fullTitle,passed:!0,error:null,duration:Date.now()-v}),u++;else{let n=e instanceof Error?e.message:String(e);l.push({title:t.title,fullTitle:t.fullTitle,passed:!1,error:n,duration:Date.now()-v}),d++,r!==void 0&&p.add(r)}}finally{s?m.push({page:g,context:c}):await c.close().catch(()=>{})}}if(!s){for(let e of h.contexts())await e.close().catch(()=>{});await h.close()}return{specPath:t,totalTests:e.testCount,passed:u,failed:d,testResults:l,success:d===0,duration:Date.now()-c,warnings:f.size>0?[...f]:void 0,browser:s?h:void 0,keptPages:m.length>0?m:void 0}}catch(e){for(let e of h.contexts())await e.close().catch(()=>{});return await h.close().catch(()=>{}),{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()-c}],success:!1,duration:Date.now()-c,warnings:f.size>0?[...f]:void 0}}}async executeSpecEnhanced(e){let{specPath:t,browserType:n=`chromium`,headless:r=!0,testFilter:i,specArgs:o,hooksPath:s,baseURL:c,keepBrowserOpen:l}=e,u=Date.now(),d=[],f=0,p=0,m=new Set,h=new Set,g=[],_=await be[n].launch({channel:`chrome`,headless:r});try{let e=await this.loadSpec(t,s),n=i?this.filterTests(e.allTests,i):e.allTests;for(let e of n){let{options:t,warnings:n}=Er(c,e.config.use);for(let e of n)m.add(e);let r=e.serialScopeId,i=r!==void 0&&h.has(r);if(e.skip||i){d.push({title:e.title,fullTitle:e.fullTitle,passed:!0,error:null,duration:0}),f++;continue}let s=await _.newContext(t),u=await s.newPage(),v={page:u,context:s,browser:_,playwright:be,specArgs:o},y=Date.now();try{await e.fn(v),d.push({title:e.title,fullTitle:e.fullTitle,passed:!0,error:null,duration:Date.now()-y}),f++}catch(t){if(t instanceof a||t instanceof Error&&`isSkip`in t)d.push({title:e.title,fullTitle:e.fullTitle,passed:!0,error:null,duration:Date.now()-y}),f++;else{let n=t instanceof Error?t.message:String(t);d.push({title:e.title,fullTitle:e.fullTitle,passed:!1,error:n,duration:Date.now()-y}),p++,r!==void 0&&h.add(r)}}finally{l?g.push({page:u,context:s}):await s.close().catch(()=>{})}}if(!l){for(let e of _.contexts())await e.close().catch(()=>{});await _.close()}return{specPath:t,totalTests:n.length,passed:f,failed:p,testResults:d,success:p===0,duration:Date.now()-u,warnings:m.size>0?[...m]:void 0,browser:l?_:void 0,keptPages:g.length>0?g:void 0}}catch(e){for(let e of _.contexts())await e.close().catch(()=>{});return await _.close().catch(()=>{}),{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()-u}],success:!1,duration:Date.now()-u,warnings:m.size>0?[...m]: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}};Dr=V([v(),B(0,_(R.SpecBundlerService)),z(`design:paramtypes`,[Object])],Dr);let Or=class{browsers=new Map;browserIdCounter=0;constructor(e,t,n){this.profileService=e,this.pageRegistry=t,this.lockManager=n}findChromePath(){let e=N.platform(),t={darwin:[`/Applications/Google Chrome.app/Contents/MacOS/Google Chrome`,`/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary`,`${N.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(O.existsSync(e))return e;return null}resolveExtensionPath(e){if(e&&O.existsSync(x.join(e,`manifest.json`)))return e;let t=x.dirname(new URL(import.meta.url).pathname),n=[x.resolve(t,`../dist/extension`),x.resolve(t,`../../dist/extension`)];for(let e of n)if(O.existsSync(x.join(e,`manifest.json`)))return e;let r=x.resolve(process.cwd(),`dist/extension`);if(O.existsSync(x.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=x.join(this.profileService.getProfilesDir(),e,`stealth-user-data`);return O.mkdirSync(t,{recursive:!0}),t}let t=x.join(N.tmpdir(),`stealth-chrome-${Date.now()}`);return O.mkdirSync(t,{recursive:!0}),t}async launch(e={}){let t=this.findChromePath();if(!t)throw Error(`Chrome not found. Please install Google Chrome.
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../playwright-test-DI0w6gpt.cjs`);exports.SkipTestError=e.t,exports.chromium=e.n,exports.defineConfig=e.r,exports.devices=e.i,exports.expect=e.a,exports.firefox=e.o,exports.getCollectedSuite=e.s,exports.initCollector=e.c,exports.mergeExpects=e.l,exports.mergeTests=e.u,exports.peekCollectedSuite=e.d,exports.request=e.f,exports.resetCollector=e.p,exports.selectors=e.m,exports.splitUseConfig=e.h,exports.test=e.g,exports.webkit=e._;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../playwright-test-CZJRdMkJ.cjs`);exports.SkipTestError=e.t,exports.chromium=e.n,exports.defineConfig=e.r,exports.devices=e.i,exports.expect=e.a,exports.firefox=e.o,exports.getCollectedSuite=e.s,exports.initCollector=e.c,exports.mergeExpects=e.l,exports.mergeTests=e.u,exports.peekCollectedSuite=e.d,exports.request=e.f,exports.resetCollector=e.p,exports.selectors=e.m,exports.splitUseConfig=e.h,exports.test=e.g,exports.webkit=e._;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@agimon-ai/browse-tool",
3
3
  "description": "MCP server for browser automation using Playwright with profile management, page registry, and multi-browser support",
4
- "version": "0.8.4",
4
+ "version": "0.8.6",
5
5
  "license": "BUSL-1.1",
6
6
  "keywords": [
7
7
  "mcp",
@@ -21,44 +21,44 @@
21
21
  "README.md"
22
22
  ],
23
23
  "dependencies": {
24
- "@hono/node-server": "1.19.13",
24
+ "@hono/node-server": "2.0.1",
25
25
  "@hono/node-ws": "1.3.0",
26
26
  "@modelcontextprotocol/sdk": "1.29.0",
27
27
  "@opentelemetry/api": "1.9.1",
28
- "@opentelemetry/api-logs": "0.214.0",
29
- "@opentelemetry/exporter-logs-otlp-http": "0.214.0",
30
- "@opentelemetry/exporter-trace-otlp-http": "0.214.0",
31
- "@opentelemetry/resources": "2.6.1",
32
- "@opentelemetry/sdk-logs": "0.214.0",
33
- "@opentelemetry/sdk-trace-node": "2.6.1",
28
+ "@opentelemetry/api-logs": "0.216.0",
29
+ "@opentelemetry/exporter-logs-otlp-http": "0.216.0",
30
+ "@opentelemetry/exporter-trace-otlp-http": "0.216.0",
31
+ "@opentelemetry/resources": "2.7.1",
32
+ "@opentelemetry/sdk-logs": "0.216.0",
33
+ "@opentelemetry/sdk-trace-node": "2.7.1",
34
34
  "@opentelemetry/semantic-conventions": "1.40.0",
35
35
  "@playwright/test": "1.59.1",
36
36
  "chalk": "5.6.2",
37
37
  "commander": "14.0.3",
38
- "hono": "4.12.12",
38
+ "hono": "4.12.16",
39
39
  "inversify": "8.1.0",
40
- "liquidjs": "10.25.5",
40
+ "liquidjs": "10.25.7",
41
41
  "playwright": "1.59.1",
42
42
  "reflect-metadata": "0.2.2",
43
43
  "esbuild": "0.28.0",
44
44
  "ws": "8.20.0",
45
45
  "yaml": "2.8.3",
46
- "zod": "4.3.6",
47
- "@agimon-ai/foundation-port-registry": "0.8.3",
48
- "@agimon-ai/log-sink-mcp": "0.8.3",
49
- "@agimon-ai/foundation-process-registry": "0.8.3",
50
- "@agimon-ai/foundation-validator": "0.5.3"
46
+ "zod": "4.4.1",
47
+ "@agimon-ai/foundation-port-registry": "0.8.4",
48
+ "@agimon-ai/log-sink-mcp": "0.8.4",
49
+ "@agimon-ai/foundation-validator": "0.5.4",
50
+ "@agimon-ai/foundation-process-registry": "0.8.4"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@types/chrome": "0.1.40",
54
54
  "@types/node": "25.6.0",
55
55
  "@types/ws": "8.18.1",
56
- "tsdown": "0.21.7",
57
- "typescript": "6.0.2",
56
+ "tsdown": "0.21.10",
57
+ "typescript": "6.0.3",
58
58
  "unplugin-raw": "0.7.0",
59
- "vite": "8.0.8",
60
- "vite-plugin-static-copy": "4.0.1",
61
- "vitest": "4.1.4"
59
+ "vite": "8.0.10",
60
+ "vite-plugin-static-copy": "4.1.0",
61
+ "vitest": "4.1.5"
62
62
  },
63
63
  "type": "module",
64
64
  "publishConfig": {