@postqode/browser 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +156 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +7 -0
- package/dist/session-tools.d.ts +356 -0
- package/dist/session-tools.d.ts.map +1 -0
- package/dist/session-tools.js +11 -0
- package/dist/session-tools.js.map +7 -0
- package/dist/session.d.ts +121 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +2 -0
- package/dist/session.js.map +7 -0
- package/dist/tools.d.ts +49 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +4 -0
- package/dist/tools.js.map +7 -0
- package/package.json +52 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";var __createBinding=this&&this.__createBinding||(Object.create?(function(t,e,o,r){r===void 0&&(r=o);var a=Object.getOwnPropertyDescriptor(e,o);(!a||("get"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[o]}}),Object.defineProperty(t,r,a)}):(function(t,e,o,r){r===void 0&&(r=o),t[r]=e[o]})),__setModuleDefault=this&&this.__setModuleDefault||(Object.create?(function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}):function(t,e){t.default=e}),__importStar=this&&this.__importStar||(function(){var t=function(e){return t=Object.getOwnPropertyNames||function(o){var r=[];for(var a in o)Object.prototype.hasOwnProperty.call(o,a)&&(r[r.length]=a);return r},t(e)};return function(e){if(e&&e.__esModule)return e;var o={};if(e!=null)for(var r=t(e),a=0;a<r.length;a++)r[a]!=="default"&&__createBinding(o,e,r[a]);return __setModuleDefault(o,e),o}})();Object.defineProperty(exports,"__esModule",{value:!0}),exports.makeSessionStorageActionTool=exports.makeLocalStorageActionTool=void 0,exports.makeNavigateTool=makeNavigateTool,exports.makeReadTool=makeReadTool,exports.makeClickTool=makeClickTool,exports.makeTypeTool=makeTypeTool,exports.makeWaitTool=makeWaitTool,exports.makeScreenshotTool=makeScreenshotTool,exports.makeEvalTool=makeEvalTool,exports.makeSnapshotTool=makeSnapshotTool,exports.makeHoverTool=makeHoverTool,exports.makeSelectOptionTool=makeSelectOptionTool,exports.makeFileUploadTool=makeFileUploadTool,exports.makePressKeyTool=makePressKeyTool,exports.makeNavigateBackTool=makeNavigateBackTool,exports.makeResizeTool=makeResizeTool,exports.makeTabsTool=makeTabsTool,exports.makeConsoleMessagesTool=makeConsoleMessagesTool,exports.makeNetworkRequestsTool=makeNetworkRequestsTool,exports.makeHandleDialogTool=makeHandleDialogTool,exports.makeReloadTool=makeReloadTool,exports.makeDblClickTool=makeDblClickTool,exports.makeDragTool=makeDragTool,exports.makeCheckTool=makeCheckTool,exports.makeUncheckTool=makeUncheckTool,exports.makePdfTool=makePdfTool,exports.makeMouseMoveTool=makeMouseMoveTool,exports.makeMouseDownTool=makeMouseDownTool,exports.makeMouseUpTool=makeMouseUpTool,exports.makeMouseWheelTool=makeMouseWheelTool,exports.makeKeyDownTool=makeKeyDownTool,exports.makeKeyUpTool=makeKeyUpTool,exports.makeCookieListTool=makeCookieListTool,exports.makeCookieGetTool=makeCookieGetTool,exports.makeCookieSetTool=makeCookieSetTool,exports.makeCookieDeleteTool=makeCookieDeleteTool,exports.makeCookieClearTool=makeCookieClearTool,exports.makeLocalStorageListTool=makeLocalStorageListTool,exports.makeLocalStorageGetTool=makeLocalStorageGetTool,exports.makeLocalStorageSetTool=makeLocalStorageSetTool,exports.makeLocalStorageDeleteTool=makeLocalStorageDeleteTool,exports.makeLocalStorageClearTool=makeLocalStorageClearTool,exports.makeSessionStorageListTool=makeSessionStorageListTool,exports.makeSessionStorageGetTool=makeSessionStorageGetTool,exports.makeSessionStorageSetTool=makeSessionStorageSetTool,exports.makeSessionStorageDeleteTool=makeSessionStorageDeleteTool,exports.makeSessionStorageClearTool=makeSessionStorageClearTool,exports.makeStateSaveTool=makeStateSaveTool,exports.makeStateLoadTool=makeStateLoadTool,exports.makeDeleteDataTool=makeDeleteDataTool,exports.makeRouteTool=makeRouteTool,exports.makeRouteListTool=makeRouteListTool,exports.makeUnrouteTool=makeUnrouteTool,exports.makeNetworkStateSetTool=makeNetworkStateSetTool,exports.makeTracingStartTool=makeTracingStartTool,exports.makeTracingStopTool=makeTracingStopTool,exports.makeCookiesTool=makeCookiesTool,exports.makeStateTool=makeStateTool,exports.makeRouteActionTool=makeRouteActionTool,exports.makeTracingTool=makeTracingTool,exports.makeMouseTool=makeMouseTool,exports.makeKeyTool=makeKeyTool,exports.makeCheckActionTool=makeCheckActionTool,exports.makeCloseTool=makeCloseTool,exports.createSessionTools=createSessionTools;const DEFAULT_MAX_CHARS=8e3;function bindAbort(t,e){e.signal.aborted||e.signal.addEventListener("abort",()=>{t.close().catch(()=>{})},{once:!0})}function errorOutput(t,e){return{content:t,isError:!0,details:e}}function makeNavigateTool(t){return{name:"browser_navigate",description:"Navigate the shared page to a URL.",inputSchema:{type:"object",properties:{url:{type:"string",description:"URL to navigate to."},waitUntil:{type:"string",enum:["load","domcontentloaded","networkidle"],description:"Playwright load-state to wait for. Default 'domcontentloaded'."},timeoutMs:{type:"integer",minimum:1}},required:["url"]},async execute({url:e,waitUntil:o,timeoutMs:r},a){bindAbort(t,a);try{const n=await t.getPage(),i=await n.goto(e,{waitUntil:o??"domcontentloaded",timeout:r}),s=await n.title().catch(()=>"");return{content:`Navigated to ${e} (${i?.status()??"unknown"})${s?" \u2014 "+s:""}`,details:{url:e,status:i?.status(),title:s}}}catch(n){return errorOutput(`browser_navigate failed: ${n instanceof Error?n.message:String(n)}`,{url:e})}}}}function makeReadTool(t){return{name:"browser_read",description:"Visible text from the page (optionally CSS-scoped).",inputSchema:{type:"object",properties:{maxChars:{type:"integer",minimum:100},selector:{type:"string"}}},async execute({maxChars:e,selector:o},r){bindAbort(t,r);try{const a=await t.getPage(),n=e??DEFAULT_MAX_CHARS,i=o?await a.evaluate(l=>{const u=document.querySelector(l);return u?u.innerText:""},o):await a.evaluate(()=>document.body?.innerText??""),s=i.length>n,c=s?i.slice(0,n):i;return{content:s?`${c}
|
|
2
|
+
[truncated ${i.length-n} characters]`:c,details:{length:i.length,truncated:s,selector:o}}}catch(a){return errorOutput(`browser_read failed: ${a instanceof Error?a.message:String(a)}`,{selector:o})}}}}function makeClickTool(t){return{name:"browser_click",description:"Click an element.",inputSchema:{type:"object",properties:{selector:{type:"string"},index:{type:"integer",minimum:0,description:"nth matching element when the selector is not unique."},timeoutMs:{type:"integer",minimum:1}},required:["selector"]},async execute({selector:e,index:o,timeoutMs:r},a){bindAbort(t,a);try{return await(await t.getPage()).locator(e).nth(o??0).click({timeout:r}),{content:`Clicked ${e}${o?`[${o}]`:""}`,details:{selector:e,index:o}}}catch(n){return errorOutput(`browser_click failed: ${n instanceof Error?n.message:String(n)}`,{selector:e})}}}}function makeTypeTool(t){return{name:"browser_type",description:"Fill an input. Optional clear-first and Enter-press.",inputSchema:{type:"object",properties:{selector:{type:"string"},text:{type:"string"},clear:{type:"boolean"},pressEnter:{type:"boolean"},timeoutMs:{type:"integer",minimum:1}},required:["selector","text"]},async execute({selector:e,text:o,clear:r,pressEnter:a,timeoutMs:n},i){bindAbort(t,i);try{const c=(await t.getPage()).locator(e).first();return r!==!1&&await c.fill("",{timeout:n}),await c.fill(o,{timeout:n}),a&&await c.press("Enter",{timeout:n}),{content:`Typed ${o.length} chars into ${e}`,details:{selector:e,length:o.length,pressEnter:!!a}}}catch(s){return errorOutput(`browser_type failed: ${s instanceof Error?s.message:String(s)}`,{selector:e})}}}}function makeWaitTool(t){return{name:"browser_wait",description:"Wait for a selector to attach OR a load-state.",inputSchema:{type:"object",properties:{selector:{type:"string"},loadState:{type:"string",enum:["load","domcontentloaded","networkidle"]},timeoutMs:{type:"integer",minimum:1}}},async execute({selector:e,loadState:o,timeoutMs:r},a){if(bindAbort(t,a),!e&&!o)return errorOutput("browser_wait requires either `selector` or `loadState`.");try{const n=await t.getPage();return e&&await n.waitForSelector(e,{timeout:r}),o&&await n.waitForLoadState(o,{timeout:r}),{content:"OK",details:{selector:e,loadState:o}}}catch(n){return errorOutput(`browser_wait failed: ${n instanceof Error?n.message:String(n)}`,{selector:e,loadState:o})}}}}function makeScreenshotTool(t){return{name:"browser_screenshot",description:"PNG screenshot of page or selector. Saves to `path` or returns base64.",inputSchema:{type:"object",properties:{path:{type:"string"},fullPage:{type:"boolean"},selector:{type:"string"}}},async execute({path:e,fullPage:o,selector:r},a){bindAbort(t,a);try{const n=await t.getPage(),s=await(r?n.locator(r).first():n).screenshot({path:e,fullPage:o,type:"png"});return e?{content:`Saved screenshot to ${e} (${s.length} bytes)`,details:{path:e,bytes:s.length}}:{content:`Captured ${s.length}-byte PNG`,details:{base64:s.toString("base64"),bytes:s.length}}}catch(n){return errorOutput(`browser_screenshot failed: ${n instanceof Error?n.message:String(n)}`,{path:e,selector:r})}}}}function makeEvalTool(t){return{name:"browser_eval",description:"Run JS in the page context; returns JSON-serialized result.",inputSchema:{type:"object",properties:{script:{type:"string"}},required:["script"]},async execute({script:e},o){bindAbort(t,o);try{const a=await(await t.getPage()).evaluate(i=>{const c=new Function(`return (${i})`)();return typeof c=="function"?c():c},e);let n;try{n=JSON.stringify(a)??String(a)}catch{n=String(a)}return{content:n,details:{result:a}}}catch(r){return errorOutput(`browser_eval failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeSnapshotTool(t){return{name:"browser_snapshot",description:"ARIA accessibility snapshot (YAML). Prefer over browser_read for stable element refs.",inputSchema:{type:"object",properties:{selector:{type:"string"},maxChars:{type:"integer",minimum:100}}},async execute({selector:e,maxChars:o},r){bindAbort(t,r);try{const i=await(await t.getPage()).locator(e??"body").first().ariaSnapshot(),s=o??DEFAULT_MAX_CHARS,c=i.length>s,l=c?i.slice(0,s):i;return{content:c?`${l}
|
|
3
|
+
[truncated ${i.length-s} characters]`:l,details:{length:i.length,truncated:c,selector:e??"body"}}}catch(a){return errorOutput(`browser_snapshot failed: ${a instanceof Error?a.message:String(a)}`,{selector:e})}}}}function makeHoverTool(t){return{name:"browser_hover",description:"Move the mouse over an element by CSS selector.",inputSchema:{type:"object",properties:{selector:{type:"string"},index:{type:"integer",minimum:0},timeoutMs:{type:"integer",minimum:1}},required:["selector"]},async execute({selector:e,index:o,timeoutMs:r},a){bindAbort(t,a);try{return await(await t.getPage()).locator(e).nth(o??0).hover({timeout:r}),{content:`Hovered ${e}`,details:{selector:e,index:o}}}catch(n){return errorOutput(`browser_hover failed: ${n instanceof Error?n.message:String(n)}`,{selector:e})}}}}function makeSelectOptionTool(t){return{name:"browser_select_option",description:"Select <option>s by `values` (attr) or `labels` (visible text).",inputSchema:{type:"object",properties:{selector:{type:"string"},values:{type:"array",items:{type:"string"}},labels:{type:"array",items:{type:"string"}},timeoutMs:{type:"integer",minimum:1}},required:["selector"]},async execute({selector:e,values:o,labels:r,timeoutMs:a},n){if(bindAbort(t,n),!o&&!r)return errorOutput("browser_select_option requires either `values` or `labels`.");try{const s=(await t.getPage()).locator(e).first(),c=o?o.map(u=>({value:u})):r.map(u=>({label:u})),l=await s.selectOption(c,{timeout:a});return{content:`Selected ${l.length} option(s) in ${e}`,details:{selector:e,selected:l}}}catch(i){return errorOutput(`browser_select_option failed: ${i instanceof Error?i.message:String(i)}`,{selector:e})}}}}function makeFileUploadTool(t){return{name:"browser_file_upload",description:"Set files on <input type=file>. Absolute paths; empty array clears.",inputSchema:{type:"object",properties:{selector:{type:"string"},paths:{type:"array",items:{type:"string"}},timeoutMs:{type:"integer",minimum:1}},required:["selector","paths"]},async execute({selector:e,paths:o,timeoutMs:r},a){bindAbort(t,a);try{return await(await t.getPage()).locator(e).first().setInputFiles(o,{timeout:r}),{content:`Uploaded ${o.length} file(s) to ${e}`,details:{selector:e,paths:o}}}catch(n){return errorOutput(`browser_file_upload failed: ${n instanceof Error?n.message:String(n)}`,{selector:e})}}}}function makePressKeyTool(t){return{name:"browser_press_key",description:"Press a key (Enter, Escape, ArrowDown, Control+A \u2026). Optional selector to focus first.",inputSchema:{type:"object",properties:{key:{type:"string"},selector:{type:"string"},timeoutMs:{type:"integer",minimum:1}},required:["key"]},async execute({key:e,selector:o,timeoutMs:r},a){bindAbort(t,a);try{const n=await t.getPage();return o?await n.locator(o).first().press(e,{timeout:r}):await n.keyboard.press(e),{content:`Pressed ${e}`,details:{key:e,selector:o}}}catch(n){return errorOutput(`browser_press_key failed: ${n instanceof Error?n.message:String(n)}`,{key:e,selector:o})}}}}function makeNavigateBackTool(t){return{name:"browser_navigate_back",description:"Go back (or forward) in the page history.",inputSchema:{type:"object",properties:{direction:{type:"string",enum:["back","forward"]},timeoutMs:{type:"integer",minimum:1}}},async execute({direction:e,timeoutMs:o},r){bindAbort(t,r);try{const a=await t.getPage(),n=e==="forward"?await a.goForward({timeout:o}):await a.goBack({timeout:o});return n?{content:`Navigated ${e??"back"} to ${a.url()} (${n.status()})`,details:{direction:e??"back",url:a.url(),status:n.status()}}:{content:`No history entry to go ${e??"back"}.`,details:{direction:e??"back"}}}catch(a){return errorOutput(`browser_navigate_back failed: ${a instanceof Error?a.message:String(a)}`)}}}}function makeResizeTool(t){return{name:"browser_resize",description:"Resize the viewport of the active page.",inputSchema:{type:"object",properties:{width:{type:"integer",minimum:100},height:{type:"integer",minimum:100}},required:["width","height"]},async execute({width:e,height:o},r){bindAbort(t,r);try{return await(await t.getPage()).setViewportSize({width:e,height:o}),{content:`Resized viewport to ${e}x${o}`,details:{width:e,height:o}}}catch(a){return errorOutput(`browser_resize failed: ${a instanceof Error?a.message:String(a)}`)}}}}function makeTabsTool(t){return{name:"browser_tabs",description:"Manage tabs. Actions: list, new, select, close.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["list","new","select","close"]},index:{type:"integer",minimum:0}}},async execute({action:e,index:o},r){bindAbort(t,r);const a=e??"list";try{if(a==="new")await t.newTab();else if(a==="select"){if(o===void 0)return errorOutput("browser_tabs select requires `index`.");await t.switchTab(o)}else if(a==="close"){if(o===void 0)return errorOutput("browser_tabs close requires `index`.");await t.closeTab(o)}const n=t.listPages();return{content:n.map(s=>`${s.active?"*":" "} [${s.index}] ${s.url||"about:blank"}`).join(`
|
|
4
|
+
`)||"(no tabs)",details:{action:a,tabs:n}}}catch(n){return errorOutput(`browser_tabs failed: ${n instanceof Error?n.message:String(n)}`,{action:a,index:o})}}}}function makeConsoleMessagesTool(t){return{name:"browser_console_messages",description:"Buffered console + page-error messages. Optional type filter, optional clear.",inputSchema:{type:"object",properties:{clear:{type:"boolean"},types:{type:"array",items:{type:"string"}}}},async execute({clear:e,types:o},r){bindAbort(t,r);let a=t.getConsole();if(o&&o.length>0){const i=new Set(o);a=a.filter(s=>i.has(s.type))}return e&&t.clearConsole(),a.length===0?{content:"(no console messages)",details:{count:0}}:{content:a.map(i=>`[${i.type}] ${i.text}${i.location?` (${i.location.url}:${i.location.lineNumber})`:""}`).join(`
|
|
5
|
+
`),details:{count:a.length,messages:a}}}}}function makeNetworkRequestsTool(t){return{name:"browser_network_requests",description:"Buffered network requests. Filter by URL substring, resource type, or failed-only.",inputSchema:{type:"object",properties:{clear:{type:"boolean"},urlContains:{type:"string"},resourceTypes:{type:"array",items:{type:"string"}},failedOnly:{type:"boolean"}}},async execute({clear:e,urlContains:o,resourceTypes:r,failedOnly:a},n){bindAbort(t,n);let i=t.getNetwork();if(o&&(i=i.filter(c=>c.url.includes(o))),r&&r.length>0){const c=new Set(r);i=i.filter(l=>c.has(l.resourceType))}return a&&(i=i.filter(c=>c.failed||c.status!==void 0&&c.status>=400)),e&&t.clearNetwork(),i.length===0?{content:"(no network entries)",details:{count:0}}:{content:i.map(c=>{const l=c.failed?`FAIL ${c.failureText??""}`:c.status??"pending";return`[${c.resourceType}] ${c.method} ${c.url} \u2192 ${l}`}).join(`
|
|
6
|
+
`),details:{count:i.length,entries:i}}}}}function makeHandleDialogTool(t){return{name:"browser_handle_dialog",description:"Pre-register accept/dismiss for the next dialog (alert/confirm/prompt).",inputSchema:{type:"object",properties:{accept:{type:"boolean"},promptText:{type:"string"}},required:["accept"]},async execute({accept:e,promptText:o},r){return bindAbort(t,r),t.setDialogPolicy({accept:e,promptText:o}),{content:`Next dialog will be ${e?"accepted":"dismissed"}.`,details:{accept:e,promptText:o}}}}}function makeReloadTool(t){return{name:"browser_reload",description:"Reload the active page.",inputSchema:{type:"object",properties:{waitUntil:{type:"string",enum:["load","domcontentloaded","networkidle"]},timeoutMs:{type:"integer",minimum:1}}},async execute({waitUntil:e,timeoutMs:o},r){bindAbort(t,r);try{const a=await t.getPage(),n=await a.reload({waitUntil:e??"domcontentloaded",timeout:o});return{content:`Reloaded ${a.url()} (${n?.status()??"unknown"})`,details:{url:a.url(),status:n?.status()}}}catch(a){return errorOutput(`browser_reload failed: ${a instanceof Error?a.message:String(a)}`)}}}}function makeDblClickTool(t){return{name:"browser_dblclick",description:"Double-click an element by CSS selector.",inputSchema:{type:"object",properties:{selector:{type:"string"},index:{type:"integer",minimum:0},timeoutMs:{type:"integer",minimum:1}},required:["selector"]},async execute({selector:e,index:o,timeoutMs:r},a){bindAbort(t,a);try{return await(await t.getPage()).locator(e).nth(o??0).dblclick({timeout:r}),{content:`Double-clicked ${e}`,details:{selector:e,index:o}}}catch(n){return errorOutput(`browser_dblclick failed: ${n instanceof Error?n.message:String(n)}`,{selector:e})}}}}function makeDragTool(t){return{name:"browser_drag",description:"Drag one element onto another by CSS selector.",inputSchema:{type:"object",properties:{fromSelector:{type:"string"},toSelector:{type:"string"},timeoutMs:{type:"integer",minimum:1}},required:["fromSelector","toSelector"]},async execute({fromSelector:e,toSelector:o,timeoutMs:r},a){bindAbort(t,a);try{const n=await t.getPage();return await n.locator(e).first().dragTo(n.locator(o).first(),{timeout:r}),{content:`Dragged ${e} \u2192 ${o}`,details:{fromSelector:e,toSelector:o}}}catch(n){return errorOutput(`browser_drag failed: ${n instanceof Error?n.message:String(n)}`,{fromSelector:e,toSelector:o})}}}}function makeCheckTool(t){return{name:"browser_check",description:"Check (tick) a checkbox or radio input.",inputSchema:{type:"object",properties:{selector:{type:"string"},timeoutMs:{type:"integer",minimum:1}},required:["selector"]},async execute({selector:e,timeoutMs:o},r){bindAbort(t,r);try{return await(await t.getPage()).locator(e).first().check({timeout:o}),{content:`Checked ${e}`,details:{selector:e}}}catch(a){return errorOutput(`browser_check failed: ${a instanceof Error?a.message:String(a)}`,{selector:e})}}}}function makeUncheckTool(t){return{name:"browser_uncheck",description:"Uncheck a checkbox.",inputSchema:{type:"object",properties:{selector:{type:"string"},timeoutMs:{type:"integer",minimum:1}},required:["selector"]},async execute({selector:e,timeoutMs:o},r){bindAbort(t,r);try{return await(await t.getPage()).locator(e).first().uncheck({timeout:o}),{content:`Unchecked ${e}`,details:{selector:e}}}catch(a){return errorOutput(`browser_uncheck failed: ${a instanceof Error?a.message:String(a)}`,{selector:e})}}}}function makePdfTool(t){return{name:"browser_pdf",description:"Render the active page as PDF. Chromium-only. Save to `path` if given, otherwise returns base64.",inputSchema:{type:"object",properties:{path:{type:"string"},format:{type:"string",enum:["Letter","Legal","Tabloid","Ledger","A0","A1","A2","A3","A4","A5","A6"]},landscape:{type:"boolean"},printBackground:{type:"boolean"}}},async execute({path:e,format:o,landscape:r,printBackground:a},n){bindAbort(t,n);try{const s=await(await t.getPage()).pdf({path:e,format:o,landscape:r,printBackground:a});return e?{content:`Saved PDF to ${e} (${s.length} bytes)`,details:{path:e,bytes:s.length}}:{content:`Captured ${s.length}-byte PDF`,details:{base64:s.toString("base64"),bytes:s.length}}}catch(i){return errorOutput(`browser_pdf failed: ${i instanceof Error?i.message:String(i)}`,{path:e})}}}}function makeMouseMoveTool(t){return{name:"browser_mouse_move",description:"Move the mouse to absolute viewport coordinates.",inputSchema:{type:"object",properties:{x:{type:"number"},y:{type:"number"},steps:{type:"integer",minimum:1}},required:["x","y"]},async execute({x:e,y:o,steps:r},a){bindAbort(t,a);try{return await(await t.getPage()).mouse.move(e,o,r!==void 0?{steps:r}:void 0),{content:`Mouse moved to (${e}, ${o})`,details:{x:e,y:o,steps:r}}}catch(n){return errorOutput(`browser_mouse_move failed: ${n instanceof Error?n.message:String(n)}`)}}}}function makeMouseDownTool(t){return{name:"browser_mouse_down",description:"Press a mouse button at the current cursor position.",inputSchema:{type:"object",properties:{button:{type:"string",enum:["left","right","middle"]},clickCount:{type:"integer",minimum:1}}},async execute({button:e,clickCount:o},r){bindAbort(t,r);try{return await(await t.getPage()).mouse.down({button:e,clickCount:o}),{content:`Mouse ${e??"left"} down`,details:{button:e,clickCount:o}}}catch(a){return errorOutput(`browser_mouse_down failed: ${a instanceof Error?a.message:String(a)}`)}}}}function makeMouseUpTool(t){return{name:"browser_mouse_up",description:"Release a mouse button at the current cursor position.",inputSchema:{type:"object",properties:{button:{type:"string",enum:["left","right","middle"]},clickCount:{type:"integer",minimum:1}}},async execute({button:e,clickCount:o},r){bindAbort(t,r);try{return await(await t.getPage()).mouse.up({button:e,clickCount:o}),{content:`Mouse ${e??"left"} up`,details:{button:e,clickCount:o}}}catch(a){return errorOutput(`browser_mouse_up failed: ${a instanceof Error?a.message:String(a)}`)}}}}function makeMouseWheelTool(t){return{name:"browser_mouse_wheel",description:"Scroll the mouse wheel by (deltaX, deltaY) at the current cursor position.",inputSchema:{type:"object",properties:{deltaX:{type:"number"},deltaY:{type:"number"}},required:["deltaX","deltaY"]},async execute({deltaX:e,deltaY:o},r){bindAbort(t,r);try{return await(await t.getPage()).mouse.wheel(e,o),{content:`Wheel scrolled (${e}, ${o})`,details:{deltaX:e,deltaY:o}}}catch(a){return errorOutput(`browser_mouse_wheel failed: ${a instanceof Error?a.message:String(a)}`)}}}}function makeKeyDownTool(t){return{name:"browser_key_down",description:"Press (and hold) a key. Use `browser_key_up` to release.",inputSchema:{type:"object",properties:{key:{type:"string"}},required:["key"]},async execute({key:e},o){bindAbort(t,o);try{return await(await t.getPage()).keyboard.down(e),{content:`Key down: ${e}`,details:{key:e}}}catch(r){return errorOutput(`browser_key_down failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeKeyUpTool(t){return{name:"browser_key_up",description:"Release a previously-held key.",inputSchema:{type:"object",properties:{key:{type:"string"}},required:["key"]},async execute({key:e},o){bindAbort(t,o);try{return await(await t.getPage()).keyboard.up(e),{content:`Key up: ${e}`,details:{key:e}}}catch(r){return errorOutput(`browser_key_up failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeCookieListTool(t){return{name:"browser_cookie_list",description:"List cookies on the browser context. Optionally scoped to specific URLs.",inputSchema:{type:"object",properties:{urls:{type:"array",items:{type:"string"}}}},async execute({urls:e},o){bindAbort(t,o);try{const a=await(await t.getContext()).cookies(e);return{content:a.map(i=>`${i.name}=${i.value} (domain=${i.domain} path=${i.path})`).join(`
|
|
7
|
+
`)||"(no cookies)",details:{count:a.length,cookies:a}}}catch(r){return errorOutput(`browser_cookie_list failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeCookieGetTool(t){return{name:"browser_cookie_get",description:"Return a single cookie by name. If `url` is given, scopes to that URL.",inputSchema:{type:"object",properties:{name:{type:"string"},url:{type:"string"}},required:["name"]},async execute({name:e,url:o},r){bindAbort(t,r);try{const i=(await(await t.getContext()).cookies(o?[o]:void 0)).find(s=>s.name===e);return i?{content:`${i.name}=${i.value}`,details:{cookie:i}}:{content:`Cookie '${e}' not found.`,details:{name:e}}}catch(a){return errorOutput(`browser_cookie_get failed: ${a instanceof Error?a.message:String(a)}`)}}}}function makeCookieSetTool(t){return{name:"browser_cookie_set",description:"Set a cookie on the browser context. Provide `url` OR `domain + path`.",inputSchema:{type:"object",properties:{name:{type:"string"},value:{type:"string"},url:{type:"string"},domain:{type:"string"},path:{type:"string"},expires:{type:"number"},httpOnly:{type:"boolean"},secure:{type:"boolean"},sameSite:{type:"string",enum:["Strict","Lax","None"]}},required:["name","value"]},async execute(e,o){bindAbort(t,o);try{return await(await t.getContext()).addCookies([e]),{content:`Set cookie ${e.name}`,details:{name:e.name}}}catch(r){return errorOutput(`browser_cookie_set failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeCookieDeleteTool(t){return{name:"browser_cookie_delete",description:"Delete a single cookie by name. If `url` is given, scopes to that URL.",inputSchema:{type:"object",properties:{name:{type:"string"},url:{type:"string"}},required:["name"]},async execute({name:e,url:o},r){bindAbort(t,r);try{const a=await t.getContext(),i=(await a.cookies(o?[o]:void 0)).filter(s=>s.name!==e);return await a.clearCookies(),i.length>0&&await a.addCookies(i),{content:`Deleted cookie ${e}`,details:{name:e}}}catch(a){return errorOutput(`browser_cookie_delete failed: ${a instanceof Error?a.message:String(a)}`)}}}}function makeCookieClearTool(t){return{name:"browser_cookie_clear",description:"Clear ALL cookies on the browser context.",inputSchema:{type:"object",properties:{}},async execute(e,o){bindAbort(t,o);try{return await(await t.getContext()).clearCookies(),{content:"Cleared all cookies."}}catch(r){return errorOutput(`browser_cookie_clear failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeLocalStorageListTool(t){return{name:"browser_localstorage_list",description:"List all keys in localStorage for the active page's origin.",inputSchema:{type:"object",properties:{}},async execute(e,o){bindAbort(t,o);try{const a=await(await t.getPage()).evaluate(()=>{const i={};for(let s=0;s<window.localStorage.length;s++){const c=window.localStorage.key(s);c!==null&&(i[c]=window.localStorage.getItem(c))}return i}),n=Object.keys(a);return{content:n.join(`
|
|
8
|
+
`)||"(empty localStorage)",details:{count:n.length,entries:a}}}catch(r){return errorOutput(`browser_localstorage_list failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeLocalStorageGetTool(t){return{name:"browser_localstorage_get",description:"Return the value of a key in localStorage for the active page's origin.",inputSchema:{type:"object",properties:{key:{type:"string"}},required:["key"]},async execute({key:e},o){bindAbort(t,o);try{const a=await(await t.getPage()).evaluate(n=>window.localStorage.getItem(n),e);return a===null?{content:`(localStorage key '${e}' not set)`,details:{key:e}}:{content:a,details:{key:e,value:a}}}catch(r){return errorOutput(`browser_localstorage_get failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeLocalStorageSetTool(t){return{name:"browser_localstorage_set",description:"Set a key in localStorage for the active page's origin.",inputSchema:{type:"object",properties:{key:{type:"string"},value:{type:"string"}},required:["key","value"]},async execute({key:e,value:o},r){bindAbort(t,r);try{return await(await t.getPage()).evaluate(({k:n,v:i})=>window.localStorage.setItem(n,i),{k:e,v:o}),{content:`Set localStorage[${e}]`,details:{key:e,length:o.length}}}catch(a){return errorOutput(`browser_localstorage_set failed: ${a instanceof Error?a.message:String(a)}`)}}}}function makeLocalStorageDeleteTool(t){return{name:"browser_localstorage_delete",description:"Delete a key in localStorage for the active page's origin.",inputSchema:{type:"object",properties:{key:{type:"string"}},required:["key"]},async execute({key:e},o){bindAbort(t,o);try{return await(await t.getPage()).evaluate(a=>window.localStorage.removeItem(a),e),{content:`Deleted localStorage[${e}]`,details:{key:e}}}catch(r){return errorOutput(`browser_localstorage_delete failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeLocalStorageClearTool(t){return{name:"browser_localstorage_clear",description:"Clear ALL keys in localStorage for the active page's origin.",inputSchema:{type:"object",properties:{}},async execute(e,o){bindAbort(t,o);try{return await(await t.getPage()).evaluate(()=>window.localStorage.clear()),{content:"Cleared localStorage."}}catch(r){return errorOutput(`browser_localstorage_clear failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeSessionStorageListTool(t){return{name:"browser_sessionstorage_list",description:"List all keys in sessionStorage for the active page's origin.",inputSchema:{type:"object",properties:{}},async execute(e,o){bindAbort(t,o);try{const a=await(await t.getPage()).evaluate(()=>{const i={};for(let s=0;s<window.sessionStorage.length;s++){const c=window.sessionStorage.key(s);c!==null&&(i[c]=window.sessionStorage.getItem(c))}return i}),n=Object.keys(a);return{content:n.join(`
|
|
9
|
+
`)||"(empty sessionStorage)",details:{count:n.length,entries:a}}}catch(r){return errorOutput(`browser_sessionstorage_list failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeSessionStorageGetTool(t){return{name:"browser_sessionstorage_get",description:"Return the value of a key in sessionStorage for the active page's origin.",inputSchema:{type:"object",properties:{key:{type:"string"}},required:["key"]},async execute({key:e},o){bindAbort(t,o);try{const a=await(await t.getPage()).evaluate(n=>window.sessionStorage.getItem(n),e);return a===null?{content:`(sessionStorage key '${e}' not set)`,details:{key:e}}:{content:a,details:{key:e,value:a}}}catch(r){return errorOutput(`browser_sessionstorage_get failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeSessionStorageSetTool(t){return{name:"browser_sessionstorage_set",description:"Set a key in sessionStorage for the active page's origin.",inputSchema:{type:"object",properties:{key:{type:"string"},value:{type:"string"}},required:["key","value"]},async execute({key:e,value:o},r){bindAbort(t,r);try{return await(await t.getPage()).evaluate(({k:n,v:i})=>window.sessionStorage.setItem(n,i),{k:e,v:o}),{content:`Set sessionStorage[${e}]`,details:{key:e,length:o.length}}}catch(a){return errorOutput(`browser_sessionstorage_set failed: ${a instanceof Error?a.message:String(a)}`)}}}}function makeSessionStorageDeleteTool(t){return{name:"browser_sessionstorage_delete",description:"Delete a key in sessionStorage for the active page's origin.",inputSchema:{type:"object",properties:{key:{type:"string"}},required:["key"]},async execute({key:e},o){bindAbort(t,o);try{return await(await t.getPage()).evaluate(a=>window.sessionStorage.removeItem(a),e),{content:`Deleted sessionStorage[${e}]`,details:{key:e}}}catch(r){return errorOutput(`browser_sessionstorage_delete failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeSessionStorageClearTool(t){return{name:"browser_sessionstorage_clear",description:"Clear ALL keys in sessionStorage for the active page's origin.",inputSchema:{type:"object",properties:{}},async execute(e,o){bindAbort(t,o);try{return await(await t.getPage()).evaluate(()=>window.sessionStorage.clear()),{content:"Cleared sessionStorage."}}catch(r){return errorOutput(`browser_sessionstorage_clear failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeStateSaveTool(t){return{name:"browser_state_save",description:"Persist the browser context's storage state (cookies + localStorage) to a JSON file.",inputSchema:{type:"object",properties:{path:{type:"string"}},required:["path"]},async execute({path:e},o){bindAbort(t,o);try{return await(await t.getContext()).storageState({path:e}),{content:`Saved storage state to ${e}`,details:{path:e}}}catch(r){return errorOutput(`browser_state_save failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeStateLoadTool(t){return{name:"browser_state_load",description:"Load cookies + localStorage from a storage-state JSON file. Cookies are restored to the context; localStorage is best-effort restored for the active page's origin only.",inputSchema:{type:"object",properties:{path:{type:"string"}},required:["path"]},async execute({path:e},o){bindAbort(t,o);try{const a=await(await Promise.resolve().then(()=>__importStar(require("node:fs/promises")))).readFile(e,"utf-8"),n=JSON.parse(a),i=await t.getContext();n.cookies&&n.cookies.length>0&&await i.addCookies(n.cookies);const s=await t.getPage(),c=new URL(s.url()).origin,l=n.origins?.find(u=>u.origin===c);return l&&await s.evaluate(u=>{for(const p of u)window.localStorage.setItem(p.name,p.value)},l.localStorage),{content:`Loaded storage state from ${e}`,details:{cookies:n.cookies?.length??0,origin:c}}}catch(r){return errorOutput(`browser_state_load failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeDeleteDataTool(t){return{name:"browser_delete_data",description:"Clear all cookies, localStorage and sessionStorage for the active page's origin.",inputSchema:{type:"object",properties:{}},async execute(e,o){bindAbort(t,o);try{return await(await t.getContext()).clearCookies(),await(await t.getPage()).evaluate(()=>{window.localStorage.clear(),window.sessionStorage.clear()}),{content:"Cleared cookies + storage for the active origin."}}catch(r){return errorOutput(`browser_delete_data failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeRouteTool(t){return{name:"browser_route",description:"Register a network mock for URLs matching `pattern`. Use `unroute` to remove.",inputSchema:{type:"object",properties:{pattern:{type:"string"},action:{type:"string",enum:["abort","fulfill","continue"]},status:{type:"integer",minimum:100,maximum:599},body:{type:"string"},contentType:{type:"string"}},required:["pattern","action"]},async execute(e,o){bindAbort(t,o);try{const r={pattern:e.pattern,action:e.action,status:e.status,body:e.body,contentType:e.contentType,handler:async a=>{e.action==="abort"?await a.abort():e.action==="fulfill"?await a.fulfill({status:e.status??200,body:e.body??"",contentType:e.contentType??"text/plain"}):await a.continue()}};return await t.addRoute(r),{content:`Registered route ${e.pattern} \u2192 ${e.action}`,details:{pattern:e.pattern,action:e.action}}}catch(r){return errorOutput(`browser_route failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeRouteListTool(t){return{name:"browser_route_list",description:"List all registered network routes on the active context.",inputSchema:{type:"object",properties:{}},async execute(e,o){bindAbort(t,o);const r=t.getRoutes();return r.length===0?{content:"(no routes registered)",details:{count:0}}:{content:r.map(n=>`${n.pattern} \u2192 ${n.action}${n.status?` (${n.status})`:""}`).join(`
|
|
10
|
+
`),details:{count:r.length,routes:r.map(({handler:n,...i})=>i)}}}}}function makeUnrouteTool(t){return{name:"browser_unroute",description:"Remove a previously-registered network route by its pattern.",inputSchema:{type:"object",properties:{pattern:{type:"string"}},required:["pattern"]},async execute({pattern:e},o){bindAbort(t,o);try{return await t.removeRoute(e)?{content:`Removed route ${e}`,details:{pattern:e}}:{content:`No route registered for ${e}`,details:{pattern:e,found:!1}}}catch(r){return errorOutput(`browser_unroute failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeNetworkStateSetTool(t){return{name:"browser_network_state_set",description:"Toggle offline mode on the browser context.",inputSchema:{type:"object",properties:{offline:{type:"boolean"}},required:["offline"]},async execute({offline:e},o){bindAbort(t,o);try{return await t.setOffline(e),{content:e?"Network: offline":"Network: online",details:{offline:e}}}catch(r){return errorOutput(`browser_network_state_set failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeTracingStartTool(t){return{name:"browser_tracing_start",description:"Begin a Playwright trace recording on the active context. Stop with `browser_tracing_stop`.",inputSchema:{type:"object",properties:{screenshots:{type:"boolean"},snapshots:{type:"boolean"},sources:{type:"boolean"}}},async execute(e,o){bindAbort(t,o);try{return await t.startTracing(e),{content:"Tracing started.",details:{...e}}}catch(r){return errorOutput(`browser_tracing_start failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeTracingStopTool(t){return{name:"browser_tracing_stop",description:"Stop the active Playwright trace. Saves to `path` (a .zip file) when provided.",inputSchema:{type:"object",properties:{path:{type:"string"}}},async execute({path:e},o){bindAbort(t,o);try{return await t.stopTracing(e),{content:e?`Tracing stopped \u2014 trace saved to ${e}`:"Tracing stopped (discarded).",details:{path:e}}}catch(r){return errorOutput(`browser_tracing_stop failed: ${r instanceof Error?r.message:String(r)}`)}}}}function makeCookiesTool(t){return{name:"browser_cookies",description:"Manage cookies. Actions: list, get, set, delete, clear.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["list","get","set","delete","clear"]},name:{type:"string"},value:{type:"string"},url:{type:"string"},domain:{type:"string"},path:{type:"string"},expires:{type:"number"},httpOnly:{type:"boolean"},secure:{type:"boolean"},sameSite:{type:"string",enum:["Strict","Lax","None"]}},required:["action"]},async execute(e,o){const{action:r,name:a,value:n,url:i}=e;return r==="list"?makeCookieListTool(t).execute({urls:i?[i]:void 0},o):r==="get"?a?makeCookieGetTool(t).execute({name:a,url:i},o):errorOutput("browser_cookies get requires `name`."):r==="set"?!a||n===void 0?errorOutput("browser_cookies set requires `name` and `value`."):makeCookieSetTool(t).execute(e,o):r==="delete"?a?makeCookieDeleteTool(t).execute({name:a,url:i},o):errorOutput("browser_cookies delete requires `name`."):makeCookieClearTool(t).execute({},o)}}}function makeStorageActionTool(t,e){const o=e==="local"?"browser_localstorage":"browser_sessionstorage",r=e==="local"?makeLocalStorageListTool:makeSessionStorageListTool,a=e==="local"?makeLocalStorageGetTool:makeSessionStorageGetTool,n=e==="local"?makeLocalStorageSetTool:makeSessionStorageSetTool,i=e==="local"?makeLocalStorageDeleteTool:makeSessionStorageDeleteTool,s=e==="local"?makeLocalStorageClearTool:makeSessionStorageClearTool;return{name:o,description:`Manage ${e}Storage for the active page's origin. Actions: list, get, set, delete, clear.`,inputSchema:{type:"object",properties:{action:{type:"string",enum:["list","get","set","delete","clear"]},key:{type:"string"},value:{type:"string"}},required:["action"]},async execute({action:c,key:l,value:u},p){return c==="list"?r(t).execute({},p):c==="clear"?s(t).execute({},p):l?c==="get"?a(t).execute({key:l},p):c==="set"?u===void 0?errorOutput(`${o} set requires \`value\`.`):n(t).execute({key:l,value:u},p):i(t).execute({key:l},p):errorOutput(`${o} ${c} requires \`key\`.`)}}}const makeLocalStorageActionTool=t=>makeStorageActionTool(t,"local");exports.makeLocalStorageActionTool=makeLocalStorageActionTool;const makeSessionStorageActionTool=t=>makeStorageActionTool(t,"session");exports.makeSessionStorageActionTool=makeSessionStorageActionTool;function makeStateTool(t){return{name:"browser_state",description:"Persist or restore Playwright storage state (cookies + per-origin localStorage). Actions: save, load.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["save","load"]},path:{type:"string"}},required:["action","path"]},async execute({action:e,path:o},r){return e==="save"?makeStateSaveTool(t).execute({path:o},r):makeStateLoadTool(t).execute({path:o},r)}}}function makeRouteActionTool(t){return{name:"browser_route",description:"Manage network mocks. Actions: add (pattern + mode), list, remove (pattern).",inputSchema:{type:"object",properties:{action:{type:"string",enum:["add","list","remove"]},pattern:{type:"string"},mode:{type:"string",enum:["abort","fulfill","continue"]},status:{type:"integer",minimum:100,maximum:599},body:{type:"string"},contentType:{type:"string"}},required:["action"]},async execute({action:e,pattern:o,mode:r,status:a,body:n,contentType:i},s){return e==="list"?makeRouteListTool(t).execute({},s):e==="remove"?o?makeUnrouteTool(t).execute({pattern:o},s):errorOutput("browser_route remove requires `pattern`."):!o||!r?errorOutput("browser_route add requires `pattern` and `mode`."):makeRouteTool(t).execute({pattern:o,action:r,status:a,body:n,contentType:i},s)}}}function makeTracingTool(t){return{name:"browser_tracing",description:"Playwright trace recording. Actions: start, stop (path saves a .zip).",inputSchema:{type:"object",properties:{action:{type:"string",enum:["start","stop"]},path:{type:"string"},screenshots:{type:"boolean"},snapshots:{type:"boolean"},sources:{type:"boolean"}},required:["action"]},async execute({action:e,path:o,screenshots:r,snapshots:a,sources:n},i){return e==="start"?makeTracingStartTool(t).execute({screenshots:r,snapshots:a,sources:n},i):makeTracingStopTool(t).execute({path:o},i)}}}function makeMouseTool(t){return{name:"browser_mouse",description:"Low-level mouse primitives. Actions: move (x, y), down/up (button), wheel (deltaX, deltaY).",inputSchema:{type:"object",properties:{action:{type:"string",enum:["move","down","up","wheel"]},x:{type:"number"},y:{type:"number"},steps:{type:"integer",minimum:1},button:{type:"string",enum:["left","right","middle"]},clickCount:{type:"integer",minimum:1},deltaX:{type:"number"},deltaY:{type:"number"}},required:["action"]},async execute(e,o){const{action:r,x:a,y:n,steps:i,button:s,clickCount:c,deltaX:l,deltaY:u}=e;return r==="move"?a===void 0||n===void 0?errorOutput("browser_mouse move requires `x` and `y`."):makeMouseMoveTool(t).execute({x:a,y:n,steps:i},o):r==="down"?makeMouseDownTool(t).execute({button:s,clickCount:c},o):r==="up"?makeMouseUpTool(t).execute({button:s,clickCount:c},o):l===void 0||u===void 0?errorOutput("browser_mouse wheel requires `deltaX` and `deltaY`."):makeMouseWheelTool(t).execute({deltaX:l,deltaY:u},o)}}}function makeKeyTool(t){return{name:"browser_key",description:"Hold or release a key for chord input. Actions: down, up. For single key-presses use `browser_press_key`.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["down","up"]},key:{type:"string"}},required:["action","key"]},async execute({action:e,key:o},r){return e==="down"?makeKeyDownTool(t).execute({key:o},r):makeKeyUpTool(t).execute({key:o},r)}}}function makeCheckActionTool(t){return{name:"browser_check",description:"Set a checkbox or radio to a target state. Pass `checked: true` to tick, `false` to untick.",inputSchema:{type:"object",properties:{selector:{type:"string"},checked:{type:"boolean"},timeoutMs:{type:"integer",minimum:1}},required:["selector","checked"]},async execute({selector:e,checked:o,timeoutMs:r},a){return o?makeCheckTool(t).execute({selector:e,timeoutMs:r},a):makeUncheckTool(t).execute({selector:e,timeoutMs:r},a)}}}function makeCloseTool(t){return{name:"browser_close",description:"Close the shared browser session. Later browser_* calls will auto-reopen.",inputSchema:{type:"object",properties:{}},async execute(){return await t.close(),{content:"Browser session closed."}}}}function createSessionTools(t){return[makeNavigateTool(t),makeNavigateBackTool(t),makeReloadTool(t),makeReadTool(t),makeSnapshotTool(t),makeScreenshotTool(t),makePdfTool(t),makeClickTool(t),makeDblClickTool(t),makeHoverTool(t),makeTypeTool(t),makeSelectOptionTool(t),makeCheckActionTool(t),makeFileUploadTool(t),makeDragTool(t),makePressKeyTool(t),makeWaitTool(t),makeMouseTool(t),makeKeyTool(t),makeEvalTool(t),makeResizeTool(t),makeTabsTool(t),makeConsoleMessagesTool(t),makeNetworkRequestsTool(t),makeHandleDialogTool(t),makeCookiesTool(t),(0,exports.makeLocalStorageActionTool)(t),(0,exports.makeSessionStorageActionTool)(t),makeStateTool(t),makeDeleteDataTool(t),makeRouteActionTool(t),makeNetworkStateSetTool(t),makeTracingTool(t),makeCloseTool(t)]}
|
|
11
|
+
//# sourceMappingURL=session-tools.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/session-tools.ts"],
|
|
4
|
+
"sourcesContent": ["import type { Tool, ToolOutput } from \"@postqode/agent\"\n\nimport type { Route } from \"playwright-core\"\n\nimport type { BrowserSession, RouteEntry } from \"./session\"\n\n/** Common truncation cap for text-returning tools. */\nconst DEFAULT_MAX_CHARS = 8_000\n\ninterface SessionToolCtx {\n\tsignal: AbortSignal\n}\n\n/** Thin wrapper that forwards an abort signal to `session.close()`. */\nfunction bindAbort(session: BrowserSession, ctx: SessionToolCtx): void {\n\tif (ctx.signal.aborted) return\n\tctx.signal.addEventListener(\n\t\t\"abort\",\n\t\t() => {\n\t\t\tsession.close().catch(() => {})\n\t\t},\n\t\t{ once: true },\n\t)\n}\n\nfunction errorOutput(message: string, details?: Record<string, unknown>): ToolOutput {\n\treturn { content: message, isError: true, details }\n}\n\n// \u2500\u2500\u2500 navigate \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserNavigateInput {\n\turl: string\n\t/** Navigation wait condition. Default \"domcontentloaded\". */\n\twaitUntil?: \"load\" | \"domcontentloaded\" | \"networkidle\"\n\ttimeoutMs?: number\n}\n\nexport function makeNavigateTool(session: BrowserSession): Tool<BrowserNavigateInput> {\n\treturn {\n\t\tname: \"browser_navigate\",\n\t\tdescription: \"Navigate the shared page to a URL.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\turl: { type: \"string\", description: \"URL to navigate to.\" },\n\t\t\t\twaitUntil: {\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t\tenum: [\"load\", \"domcontentloaded\", \"networkidle\"],\n\t\t\t\t\tdescription: \"Playwright load-state to wait for. Default 'domcontentloaded'.\",\n\t\t\t\t},\n\t\t\t\ttimeoutMs: { type: \"integer\", minimum: 1 },\n\t\t\t},\n\t\t\trequired: [\"url\"],\n\t\t},\n\t\tasync execute({ url, waitUntil, timeoutMs }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tconst response = await page.goto(url, {\n\t\t\t\t\twaitUntil: waitUntil ?? \"domcontentloaded\",\n\t\t\t\t\ttimeout: timeoutMs,\n\t\t\t\t})\n\t\t\t\tconst title = await page.title().catch(() => \"\")\n\t\t\t\treturn {\n\t\t\t\t\tcontent: `Navigated to ${url} (${response?.status() ?? \"unknown\"})${title ? \" \u2014 \" + title : \"\"}`,\n\t\t\t\t\tdetails: { url, status: response?.status(), title },\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_navigate failed: ${err instanceof Error ? err.message : String(err)}`, { url })\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 read \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserReadInput {\n\t/** Max characters of visible text returned. Default 8000. */\n\tmaxChars?: number\n\t/** Optional CSS selector to scope the read. */\n\tselector?: string\n}\n\nexport function makeReadTool(session: BrowserSession): Tool<BrowserReadInput> {\n\treturn {\n\t\tname: \"browser_read\",\n\t\tdescription: \"Visible text from the page (optionally CSS-scoped).\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tmaxChars: { type: \"integer\", minimum: 100 },\n\t\t\t\tselector: { type: \"string\" },\n\t\t\t},\n\t\t},\n\t\tasync execute({ maxChars, selector }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tconst cap = maxChars ?? DEFAULT_MAX_CHARS\n\t\t\t\tconst text = selector\n\t\t\t\t\t? await page.evaluate((sel) => {\n\t\t\t\t\t\t\tconst el = document.querySelector(sel)\n\t\t\t\t\t\t\treturn el ? (el as HTMLElement).innerText : \"\"\n\t\t\t\t\t\t}, selector)\n\t\t\t\t\t: await page.evaluate(() => document.body?.innerText ?? \"\")\n\t\t\t\tconst truncated = text.length > cap\n\t\t\t\tconst body = truncated ? text.slice(0, cap) : text\n\t\t\t\treturn {\n\t\t\t\t\tcontent: truncated ? `${body}\\n[truncated ${text.length - cap} characters]` : body,\n\t\t\t\t\tdetails: { length: text.length, truncated, selector },\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_read failed: ${err instanceof Error ? err.message : String(err)}`, { selector })\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 click \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserClickInput {\n\tselector: string\n\t/** Optional nth match. Default 0. */\n\tindex?: number\n\ttimeoutMs?: number\n}\n\nexport function makeClickTool(session: BrowserSession): Tool<BrowserClickInput> {\n\treturn {\n\t\tname: \"browser_click\",\n\t\tdescription: \"Click an element.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tselector: { type: \"string\" },\n\t\t\t\tindex: { type: \"integer\", minimum: 0, description: \"nth matching element when the selector is not unique.\" },\n\t\t\t\ttimeoutMs: { type: \"integer\", minimum: 1 },\n\t\t\t},\n\t\t\trequired: [\"selector\"],\n\t\t},\n\t\tasync execute({ selector, index, timeoutMs }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tconst locator = page.locator(selector).nth(index ?? 0)\n\t\t\t\tawait locator.click({ timeout: timeoutMs })\n\t\t\t\treturn { content: `Clicked ${selector}${index ? `[${index}]` : \"\"}`, details: { selector, index } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_click failed: ${err instanceof Error ? err.message : String(err)}`, { selector })\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 type \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserTypeInput {\n\tselector: string\n\ttext: string\n\t/** Clear existing contents first (default true). */\n\tclear?: boolean\n\t/** Press Enter after typing (default false). */\n\tpressEnter?: boolean\n\ttimeoutMs?: number\n}\n\nexport function makeTypeTool(session: BrowserSession): Tool<BrowserTypeInput> {\n\treturn {\n\t\tname: \"browser_type\",\n\t\tdescription: \"Fill an input. Optional clear-first and Enter-press.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tselector: { type: \"string\" },\n\t\t\t\ttext: { type: \"string\" },\n\t\t\t\tclear: { type: \"boolean\" },\n\t\t\t\tpressEnter: { type: \"boolean\" },\n\t\t\t\ttimeoutMs: { type: \"integer\", minimum: 1 },\n\t\t\t},\n\t\t\trequired: [\"selector\", \"text\"],\n\t\t},\n\t\tasync execute({ selector, text, clear, pressEnter, timeoutMs }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tconst locator = page.locator(selector).first()\n\t\t\t\tif (clear !== false) await locator.fill(\"\", { timeout: timeoutMs })\n\t\t\t\tawait locator.fill(text, { timeout: timeoutMs })\n\t\t\t\tif (pressEnter) await locator.press(\"Enter\", { timeout: timeoutMs })\n\t\t\t\treturn { content: `Typed ${text.length} chars into ${selector}`, details: { selector, length: text.length, pressEnter: !!pressEnter } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_type failed: ${err instanceof Error ? err.message : String(err)}`, { selector })\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 wait \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserWaitInput {\n\t/** Either wait for a selector to appear or for a load-state. */\n\tselector?: string\n\tloadState?: \"load\" | \"domcontentloaded\" | \"networkidle\"\n\ttimeoutMs?: number\n}\n\nexport function makeWaitTool(session: BrowserSession): Tool<BrowserWaitInput> {\n\treturn {\n\t\tname: \"browser_wait\",\n\t\tdescription: \"Wait for a selector to attach OR a load-state.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tselector: { type: \"string\" },\n\t\t\t\tloadState: { type: \"string\", enum: [\"load\", \"domcontentloaded\", \"networkidle\"] },\n\t\t\t\ttimeoutMs: { type: \"integer\", minimum: 1 },\n\t\t\t},\n\t\t},\n\t\tasync execute({ selector, loadState, timeoutMs }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\tif (!selector && !loadState) {\n\t\t\t\treturn errorOutput(\"browser_wait requires either `selector` or `loadState`.\")\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tif (selector) {\n\t\t\t\t\tawait page.waitForSelector(selector, { timeout: timeoutMs })\n\t\t\t\t}\n\t\t\t\tif (loadState) {\n\t\t\t\t\tawait page.waitForLoadState(loadState, { timeout: timeoutMs })\n\t\t\t\t}\n\t\t\t\treturn { content: \"OK\", details: { selector, loadState } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_wait failed: ${err instanceof Error ? err.message : String(err)}`, { selector, loadState })\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 screenshot \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserScreenshotInput {\n\t/** Optional output file path. When unset, returns base64 PNG in details. */\n\tpath?: string\n\tfullPage?: boolean\n\t/** Optional CSS selector to screenshot just that element. */\n\tselector?: string\n}\n\nexport function makeScreenshotTool(session: BrowserSession): Tool<BrowserScreenshotInput> {\n\treturn {\n\t\tname: \"browser_screenshot\",\n\t\tdescription: \"PNG screenshot of page or selector. Saves to `path` or returns base64.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tpath: { type: \"string\" },\n\t\t\t\tfullPage: { type: \"boolean\" },\n\t\t\t\tselector: { type: \"string\" },\n\t\t\t},\n\t\t},\n\t\tasync execute({ path, fullPage, selector }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tconst target = selector ? page.locator(selector).first() : page\n\t\t\t\tconst buf = await target.screenshot({ path, fullPage, type: \"png\" })\n\t\t\t\treturn path\n\t\t\t\t\t? { content: `Saved screenshot to ${path} (${buf.length} bytes)`, details: { path, bytes: buf.length } }\n\t\t\t\t\t: { content: `Captured ${buf.length}-byte PNG`, details: { base64: buf.toString(\"base64\"), bytes: buf.length } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_screenshot failed: ${err instanceof Error ? err.message : String(err)}`, { path, selector })\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 eval \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserEvalInput {\n\t/** JavaScript expression or function body evaluated in the page context.\n\t * When starting with `() =>` or `function(`, it's executed as a function;\n\t * otherwise the result is the value of the expression. */\n\tscript: string\n}\n\nexport function makeEvalTool(session: BrowserSession): Tool<BrowserEvalInput> {\n\treturn {\n\t\tname: \"browser_eval\",\n\t\tdescription: \"Run JS in the page context; returns JSON-serialized result.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tscript: { type: \"string\" },\n\t\t\t},\n\t\t\trequired: [\"script\"],\n\t\t},\n\t\tasync execute({ script }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\t// Wrap in a function factory so arbitrary expressions work.\n\t\t\t\tconst result = await page.evaluate((s) => {\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-implied-eval, no-new-func\n\t\t\t\t\tconst fn = new Function(`return (${s})`)\n\t\t\t\t\tconst v = fn()\n\t\t\t\t\treturn typeof v === \"function\" ? v() : v\n\t\t\t\t}, script)\n\t\t\t\tlet serialized: string\n\t\t\t\ttry {\n\t\t\t\t\tserialized = JSON.stringify(result) ?? String(result)\n\t\t\t\t} catch {\n\t\t\t\t\tserialized = String(result)\n\t\t\t\t}\n\t\t\t\treturn { content: serialized, details: { result } as Record<string, unknown> }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_eval failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 snapshot \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserSnapshotInput {\n\t/** Optional CSS selector to scope the snapshot. Defaults to `body`. */\n\tselector?: string\n\t/** Max characters of the YAML snapshot returned. Default 8000. */\n\tmaxChars?: number\n}\n\nexport function makeSnapshotTool(session: BrowserSession): Tool<BrowserSnapshotInput> {\n\treturn {\n\t\tname: \"browser_snapshot\",\n\t\tdescription: \"ARIA accessibility snapshot (YAML). Prefer over browser_read for stable element refs.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tselector: { type: \"string\" },\n\t\t\t\tmaxChars: { type: \"integer\", minimum: 100 },\n\t\t\t},\n\t\t},\n\t\tasync execute({ selector, maxChars }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tconst target = page.locator(selector ?? \"body\").first()\n\t\t\t\tconst yaml = await target.ariaSnapshot()\n\t\t\t\tconst cap = maxChars ?? DEFAULT_MAX_CHARS\n\t\t\t\tconst truncated = yaml.length > cap\n\t\t\t\tconst body = truncated ? yaml.slice(0, cap) : yaml\n\t\t\t\treturn {\n\t\t\t\t\tcontent: truncated ? `${body}\\n[truncated ${yaml.length - cap} characters]` : body,\n\t\t\t\t\tdetails: { length: yaml.length, truncated, selector: selector ?? \"body\" },\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_snapshot failed: ${err instanceof Error ? err.message : String(err)}`, { selector })\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 hover \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserHoverInput {\n\tselector: string\n\tindex?: number\n\ttimeoutMs?: number\n}\n\nexport function makeHoverTool(session: BrowserSession): Tool<BrowserHoverInput> {\n\treturn {\n\t\tname: \"browser_hover\",\n\t\tdescription: \"Move the mouse over an element by CSS selector.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tselector: { type: \"string\" },\n\t\t\t\tindex: { type: \"integer\", minimum: 0 },\n\t\t\t\ttimeoutMs: { type: \"integer\", minimum: 1 },\n\t\t\t},\n\t\t\trequired: [\"selector\"],\n\t\t},\n\t\tasync execute({ selector, index, timeoutMs }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tawait page.locator(selector).nth(index ?? 0).hover({ timeout: timeoutMs })\n\t\t\t\treturn { content: `Hovered ${selector}`, details: { selector, index } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_hover failed: ${err instanceof Error ? err.message : String(err)}`, { selector })\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 select_option \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserSelectOptionInput {\n\tselector: string\n\t/** One or more option values to select. */\n\tvalues?: string[]\n\t/** One or more option visible labels to select. */\n\tlabels?: string[]\n\ttimeoutMs?: number\n}\n\nexport function makeSelectOptionTool(session: BrowserSession): Tool<BrowserSelectOptionInput> {\n\treturn {\n\t\tname: \"browser_select_option\",\n\t\tdescription: \"Select <option>s by `values` (attr) or `labels` (visible text).\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tselector: { type: \"string\" },\n\t\t\t\tvalues: { type: \"array\", items: { type: \"string\" } },\n\t\t\t\tlabels: { type: \"array\", items: { type: \"string\" } },\n\t\t\t\ttimeoutMs: { type: \"integer\", minimum: 1 },\n\t\t\t},\n\t\t\trequired: [\"selector\"],\n\t\t},\n\t\tasync execute({ selector, values, labels, timeoutMs }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\tif (!values && !labels) {\n\t\t\t\treturn errorOutput(\"browser_select_option requires either `values` or `labels`.\")\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tconst locator = page.locator(selector).first()\n\t\t\t\tconst arg = values ? values.map((value) => ({ value })) : labels!.map((label) => ({ label }))\n\t\t\t\tconst selected = await locator.selectOption(arg, { timeout: timeoutMs })\n\t\t\t\treturn { content: `Selected ${selected.length} option(s) in ${selector}`, details: { selector, selected } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_select_option failed: ${err instanceof Error ? err.message : String(err)}`, { selector })\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 file_upload \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserFileUploadInput {\n\tselector: string\n\t/** Absolute file paths to upload. Pass an empty array to clear the input. */\n\tpaths: string[]\n\ttimeoutMs?: number\n}\n\nexport function makeFileUploadTool(session: BrowserSession): Tool<BrowserFileUploadInput> {\n\treturn {\n\t\tname: \"browser_file_upload\",\n\t\tdescription: \"Set files on <input type=file>. Absolute paths; empty array clears.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tselector: { type: \"string\" },\n\t\t\t\tpaths: { type: \"array\", items: { type: \"string\" } },\n\t\t\t\ttimeoutMs: { type: \"integer\", minimum: 1 },\n\t\t\t},\n\t\t\trequired: [\"selector\", \"paths\"],\n\t\t},\n\t\tasync execute({ selector, paths, timeoutMs }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tawait page.locator(selector).first().setInputFiles(paths, { timeout: timeoutMs })\n\t\t\t\treturn { content: `Uploaded ${paths.length} file(s) to ${selector}`, details: { selector, paths } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_file_upload failed: ${err instanceof Error ? err.message : String(err)}`, { selector })\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 press_key \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserPressKeyInput {\n\t/** Key to press. Examples: \"Enter\", \"Escape\", \"ArrowDown\", \"Control+A\". */\n\tkey: string\n\t/** Optional selector to focus before the press. */\n\tselector?: string\n\ttimeoutMs?: number\n}\n\nexport function makePressKeyTool(session: BrowserSession): Tool<BrowserPressKeyInput> {\n\treturn {\n\t\tname: \"browser_press_key\",\n\t\tdescription: \"Press a key (Enter, Escape, ArrowDown, Control+A \u2026). Optional selector to focus first.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tkey: { type: \"string\" },\n\t\t\t\tselector: { type: \"string\" },\n\t\t\t\ttimeoutMs: { type: \"integer\", minimum: 1 },\n\t\t\t},\n\t\t\trequired: [\"key\"],\n\t\t},\n\t\tasync execute({ key, selector, timeoutMs }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tif (selector) {\n\t\t\t\t\tawait page.locator(selector).first().press(key, { timeout: timeoutMs })\n\t\t\t\t} else {\n\t\t\t\t\tawait page.keyboard.press(key)\n\t\t\t\t}\n\t\t\t\treturn { content: `Pressed ${key}`, details: { key, selector } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_press_key failed: ${err instanceof Error ? err.message : String(err)}`, { key, selector })\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 navigate_back / forward \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserNavigateBackInput {\n\t/** \"back\" (default) or \"forward\". */\n\tdirection?: \"back\" | \"forward\"\n\ttimeoutMs?: number\n}\n\nexport function makeNavigateBackTool(session: BrowserSession): Tool<BrowserNavigateBackInput> {\n\treturn {\n\t\tname: \"browser_navigate_back\",\n\t\tdescription: \"Go back (or forward) in the page history.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tdirection: { type: \"string\", enum: [\"back\", \"forward\"] },\n\t\t\t\ttimeoutMs: { type: \"integer\", minimum: 1 },\n\t\t\t},\n\t\t},\n\t\tasync execute({ direction, timeoutMs }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tconst response = direction === \"forward\" ? await page.goForward({ timeout: timeoutMs }) : await page.goBack({ timeout: timeoutMs })\n\t\t\t\tif (!response) return { content: `No history entry to go ${direction ?? \"back\"}.`, details: { direction: direction ?? \"back\" } }\n\t\t\t\treturn {\n\t\t\t\t\tcontent: `Navigated ${direction ?? \"back\"} to ${page.url()} (${response.status()})`,\n\t\t\t\t\tdetails: { direction: direction ?? \"back\", url: page.url(), status: response.status() },\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_navigate_back failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 resize \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserResizeInput {\n\twidth: number\n\theight: number\n}\n\nexport function makeResizeTool(session: BrowserSession): Tool<BrowserResizeInput> {\n\treturn {\n\t\tname: \"browser_resize\",\n\t\tdescription: \"Resize the viewport of the active page.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\twidth: { type: \"integer\", minimum: 100 },\n\t\t\t\theight: { type: \"integer\", minimum: 100 },\n\t\t\t},\n\t\t\trequired: [\"width\", \"height\"],\n\t\t},\n\t\tasync execute({ width, height }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tawait page.setViewportSize({ width, height })\n\t\t\t\treturn { content: `Resized viewport to ${width}x${height}`, details: { width, height } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_resize failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 tabs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserTabsInput {\n\t/** Action to perform. Default \"list\". */\n\taction?: \"list\" | \"new\" | \"select\" | \"close\"\n\t/** Tab index (required for \"select\" and \"close\"). */\n\tindex?: number\n}\n\nexport function makeTabsTool(session: BrowserSession): Tool<BrowserTabsInput> {\n\treturn {\n\t\tname: \"browser_tabs\",\n\t\tdescription: \"Manage tabs. Actions: list, new, select, close.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\taction: { type: \"string\", enum: [\"list\", \"new\", \"select\", \"close\"] },\n\t\t\t\tindex: { type: \"integer\", minimum: 0 },\n\t\t\t},\n\t\t},\n\t\tasync execute({ action, index }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\tconst op = action ?? \"list\"\n\t\t\ttry {\n\t\t\t\tif (op === \"new\") {\n\t\t\t\t\tawait session.newTab()\n\t\t\t\t} else if (op === \"select\") {\n\t\t\t\t\tif (index === undefined) return errorOutput(\"browser_tabs select requires `index`.\")\n\t\t\t\t\tawait session.switchTab(index)\n\t\t\t\t} else if (op === \"close\") {\n\t\t\t\t\tif (index === undefined) return errorOutput(\"browser_tabs close requires `index`.\")\n\t\t\t\t\tawait session.closeTab(index)\n\t\t\t\t}\n\t\t\t\tconst tabs = session.listPages()\n\t\t\t\tconst lines = tabs.map((t) => `${t.active ? \"*\" : \" \"} [${t.index}] ${t.url || \"about:blank\"}`)\n\t\t\t\treturn { content: lines.join(\"\\n\") || \"(no tabs)\", details: { action: op, tabs } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_tabs failed: ${err instanceof Error ? err.message : String(err)}`, { action: op, index })\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 console_messages \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserConsoleMessagesInput {\n\t/** Drop the buffer after reading. Default false. */\n\tclear?: boolean\n\t/** Only return messages of these types (e.g. [\"error\", \"warning\"]). */\n\ttypes?: string[]\n}\n\nexport function makeConsoleMessagesTool(session: BrowserSession): Tool<BrowserConsoleMessagesInput> {\n\treturn {\n\t\tname: \"browser_console_messages\",\n\t\tdescription: \"Buffered console + page-error messages. Optional type filter, optional clear.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tclear: { type: \"boolean\" },\n\t\t\t\ttypes: { type: \"array\", items: { type: \"string\" } },\n\t\t\t},\n\t\t},\n\t\tasync execute({ clear, types }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\tlet messages = session.getConsole()\n\t\t\tif (types && types.length > 0) {\n\t\t\t\tconst allow = new Set(types)\n\t\t\t\tmessages = messages.filter((m) => allow.has(m.type))\n\t\t\t}\n\t\t\tif (clear) session.clearConsole()\n\t\t\tif (messages.length === 0) return { content: \"(no console messages)\", details: { count: 0 } }\n\t\t\tconst lines = messages.map((m) => `[${m.type}] ${m.text}${m.location ? ` (${m.location.url}:${m.location.lineNumber})` : \"\"}`)\n\t\t\treturn { content: lines.join(\"\\n\"), details: { count: messages.length, messages } }\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 network_requests \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserNetworkRequestsInput {\n\t/** Drop the buffer after reading. Default false. */\n\tclear?: boolean\n\t/** Only return entries whose URL contains this substring. */\n\turlContains?: string\n\t/** Only return entries with these resource types (document, xhr, fetch, \u2026). */\n\tresourceTypes?: string[]\n\t/** Only return entries that have a status >= 400 or were failed. */\n\tfailedOnly?: boolean\n}\n\nexport function makeNetworkRequestsTool(session: BrowserSession): Tool<BrowserNetworkRequestsInput> {\n\treturn {\n\t\tname: \"browser_network_requests\",\n\t\tdescription: \"Buffered network requests. Filter by URL substring, resource type, or failed-only.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tclear: { type: \"boolean\" },\n\t\t\t\turlContains: { type: \"string\" },\n\t\t\t\tresourceTypes: { type: \"array\", items: { type: \"string\" } },\n\t\t\t\tfailedOnly: { type: \"boolean\" },\n\t\t\t},\n\t\t},\n\t\tasync execute({ clear, urlContains, resourceTypes, failedOnly }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\tlet entries = session.getNetwork()\n\t\t\tif (urlContains) entries = entries.filter((e) => e.url.includes(urlContains))\n\t\t\tif (resourceTypes && resourceTypes.length > 0) {\n\t\t\t\tconst allow = new Set(resourceTypes)\n\t\t\t\tentries = entries.filter((e) => allow.has(e.resourceType))\n\t\t\t}\n\t\t\tif (failedOnly) entries = entries.filter((e) => e.failed || (e.status !== undefined && e.status >= 400))\n\t\t\tif (clear) session.clearNetwork()\n\t\t\tif (entries.length === 0) return { content: \"(no network entries)\", details: { count: 0 } }\n\t\t\tconst lines = entries.map((e) => {\n\t\t\t\tconst status = e.failed ? `FAIL ${e.failureText ?? \"\"}` : e.status ?? \"pending\"\n\t\t\t\treturn `[${e.resourceType}] ${e.method} ${e.url} \u2192 ${status}`\n\t\t\t})\n\t\t\treturn { content: lines.join(\"\\n\"), details: { count: entries.length, entries } }\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 handle_dialog \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserHandleDialogInput {\n\t/** Accept the next dialog. Set false to dismiss. */\n\taccept: boolean\n\t/** Optional response text for window.prompt(). */\n\tpromptText?: string\n}\n\nexport function makeHandleDialogTool(session: BrowserSession): Tool<BrowserHandleDialogInput> {\n\treturn {\n\t\tname: \"browser_handle_dialog\",\n\t\tdescription: \"Pre-register accept/dismiss for the next dialog (alert/confirm/prompt).\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\taccept: { type: \"boolean\" },\n\t\t\t\tpromptText: { type: \"string\" },\n\t\t\t},\n\t\t\trequired: [\"accept\"],\n\t\t},\n\t\tasync execute({ accept, promptText }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\tsession.setDialogPolicy({ accept, promptText })\n\t\t\treturn { content: `Next dialog will be ${accept ? \"accepted\" : \"dismissed\"}.`, details: { accept, promptText } }\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 reload \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserReloadInput {\n\twaitUntil?: \"load\" | \"domcontentloaded\" | \"networkidle\"\n\ttimeoutMs?: number\n}\n\nexport function makeReloadTool(session: BrowserSession): Tool<BrowserReloadInput> {\n\treturn {\n\t\tname: \"browser_reload\",\n\t\tdescription: \"Reload the active page.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\twaitUntil: { type: \"string\", enum: [\"load\", \"domcontentloaded\", \"networkidle\"] },\n\t\t\t\ttimeoutMs: { type: \"integer\", minimum: 1 },\n\t\t\t},\n\t\t},\n\t\tasync execute({ waitUntil, timeoutMs }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tconst response = await page.reload({ waitUntil: waitUntil ?? \"domcontentloaded\", timeout: timeoutMs })\n\t\t\t\treturn {\n\t\t\t\t\tcontent: `Reloaded ${page.url()} (${response?.status() ?? \"unknown\"})`,\n\t\t\t\t\tdetails: { url: page.url(), status: response?.status() },\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_reload failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 dblclick \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserDblClickInput {\n\tselector: string\n\tindex?: number\n\ttimeoutMs?: number\n}\n\nexport function makeDblClickTool(session: BrowserSession): Tool<BrowserDblClickInput> {\n\treturn {\n\t\tname: \"browser_dblclick\",\n\t\tdescription: \"Double-click an element by CSS selector.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tselector: { type: \"string\" },\n\t\t\t\tindex: { type: \"integer\", minimum: 0 },\n\t\t\t\ttimeoutMs: { type: \"integer\", minimum: 1 },\n\t\t\t},\n\t\t\trequired: [\"selector\"],\n\t\t},\n\t\tasync execute({ selector, index, timeoutMs }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tawait page.locator(selector).nth(index ?? 0).dblclick({ timeout: timeoutMs })\n\t\t\t\treturn { content: `Double-clicked ${selector}`, details: { selector, index } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_dblclick failed: ${err instanceof Error ? err.message : String(err)}`, { selector })\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 drag \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserDragInput {\n\tfromSelector: string\n\ttoSelector: string\n\ttimeoutMs?: number\n}\n\nexport function makeDragTool(session: BrowserSession): Tool<BrowserDragInput> {\n\treturn {\n\t\tname: \"browser_drag\",\n\t\tdescription: \"Drag one element onto another by CSS selector.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tfromSelector: { type: \"string\" },\n\t\t\t\ttoSelector: { type: \"string\" },\n\t\t\t\ttimeoutMs: { type: \"integer\", minimum: 1 },\n\t\t\t},\n\t\t\trequired: [\"fromSelector\", \"toSelector\"],\n\t\t},\n\t\tasync execute({ fromSelector, toSelector, timeoutMs }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tawait page.locator(fromSelector).first().dragTo(page.locator(toSelector).first(), { timeout: timeoutMs })\n\t\t\t\treturn { content: `Dragged ${fromSelector} \u2192 ${toSelector}`, details: { fromSelector, toSelector } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_drag failed: ${err instanceof Error ? err.message : String(err)}`, { fromSelector, toSelector })\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 check / uncheck \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserCheckInput {\n\tselector: string\n\ttimeoutMs?: number\n}\n\nexport function makeCheckTool(session: BrowserSession): Tool<BrowserCheckInput> {\n\treturn {\n\t\tname: \"browser_check\",\n\t\tdescription: \"Check (tick) a checkbox or radio input.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tselector: { type: \"string\" },\n\t\t\t\ttimeoutMs: { type: \"integer\", minimum: 1 },\n\t\t\t},\n\t\t\trequired: [\"selector\"],\n\t\t},\n\t\tasync execute({ selector, timeoutMs }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tawait page.locator(selector).first().check({ timeout: timeoutMs })\n\t\t\t\treturn { content: `Checked ${selector}`, details: { selector } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_check failed: ${err instanceof Error ? err.message : String(err)}`, { selector })\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport function makeUncheckTool(session: BrowserSession): Tool<BrowserCheckInput> {\n\treturn {\n\t\tname: \"browser_uncheck\",\n\t\tdescription: \"Uncheck a checkbox.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tselector: { type: \"string\" },\n\t\t\t\ttimeoutMs: { type: \"integer\", minimum: 1 },\n\t\t\t},\n\t\t\trequired: [\"selector\"],\n\t\t},\n\t\tasync execute({ selector, timeoutMs }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tawait page.locator(selector).first().uncheck({ timeout: timeoutMs })\n\t\t\t\treturn { content: `Unchecked ${selector}`, details: { selector } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_uncheck failed: ${err instanceof Error ? err.message : String(err)}`, { selector })\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 pdf \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserPdfInput {\n\t/** Output file path. If omitted, base64 is returned. */\n\tpath?: string\n\tformat?: \"Letter\" | \"Legal\" | \"Tabloid\" | \"Ledger\" | \"A0\" | \"A1\" | \"A2\" | \"A3\" | \"A4\" | \"A5\" | \"A6\"\n\tlandscape?: boolean\n\tprintBackground?: boolean\n}\n\nexport function makePdfTool(session: BrowserSession): Tool<BrowserPdfInput> {\n\treturn {\n\t\tname: \"browser_pdf\",\n\t\tdescription: \"Render the active page as PDF. Chromium-only. Save to `path` if given, otherwise returns base64.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tpath: { type: \"string\" },\n\t\t\t\tformat: { type: \"string\", enum: [\"Letter\", \"Legal\", \"Tabloid\", \"Ledger\", \"A0\", \"A1\", \"A2\", \"A3\", \"A4\", \"A5\", \"A6\"] },\n\t\t\t\tlandscape: { type: \"boolean\" },\n\t\t\t\tprintBackground: { type: \"boolean\" },\n\t\t\t},\n\t\t},\n\t\tasync execute({ path, format, landscape, printBackground }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tconst buf = await page.pdf({ path, format, landscape, printBackground })\n\t\t\t\treturn path\n\t\t\t\t\t? { content: `Saved PDF to ${path} (${buf.length} bytes)`, details: { path, bytes: buf.length } }\n\t\t\t\t\t: { content: `Captured ${buf.length}-byte PDF`, details: { base64: buf.toString(\"base64\"), bytes: buf.length } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_pdf failed: ${err instanceof Error ? err.message : String(err)}`, { path })\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 low-level mouse \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserMouseMoveInput {\n\tx: number\n\ty: number\n\tsteps?: number\n}\n\nexport function makeMouseMoveTool(session: BrowserSession): Tool<BrowserMouseMoveInput> {\n\treturn {\n\t\tname: \"browser_mouse_move\",\n\t\tdescription: \"Move the mouse to absolute viewport coordinates.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tx: { type: \"number\" },\n\t\t\t\ty: { type: \"number\" },\n\t\t\t\tsteps: { type: \"integer\", minimum: 1 },\n\t\t\t},\n\t\t\trequired: [\"x\", \"y\"],\n\t\t},\n\t\tasync execute({ x, y, steps }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tawait page.mouse.move(x, y, steps !== undefined ? { steps } : undefined)\n\t\t\t\treturn { content: `Mouse moved to (${x}, ${y})`, details: { x, y, steps } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_mouse_move failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport interface BrowserMouseButtonInput {\n\tbutton?: \"left\" | \"right\" | \"middle\"\n\tclickCount?: number\n}\n\nexport function makeMouseDownTool(session: BrowserSession): Tool<BrowserMouseButtonInput> {\n\treturn {\n\t\tname: \"browser_mouse_down\",\n\t\tdescription: \"Press a mouse button at the current cursor position.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tbutton: { type: \"string\", enum: [\"left\", \"right\", \"middle\"] },\n\t\t\t\tclickCount: { type: \"integer\", minimum: 1 },\n\t\t\t},\n\t\t},\n\t\tasync execute({ button, clickCount }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tawait page.mouse.down({ button, clickCount })\n\t\t\t\treturn { content: `Mouse ${button ?? \"left\"} down`, details: { button, clickCount } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_mouse_down failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport function makeMouseUpTool(session: BrowserSession): Tool<BrowserMouseButtonInput> {\n\treturn {\n\t\tname: \"browser_mouse_up\",\n\t\tdescription: \"Release a mouse button at the current cursor position.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tbutton: { type: \"string\", enum: [\"left\", \"right\", \"middle\"] },\n\t\t\t\tclickCount: { type: \"integer\", minimum: 1 },\n\t\t\t},\n\t\t},\n\t\tasync execute({ button, clickCount }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tawait page.mouse.up({ button, clickCount })\n\t\t\t\treturn { content: `Mouse ${button ?? \"left\"} up`, details: { button, clickCount } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_mouse_up failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport interface BrowserMouseWheelInput {\n\tdeltaX: number\n\tdeltaY: number\n}\n\nexport function makeMouseWheelTool(session: BrowserSession): Tool<BrowserMouseWheelInput> {\n\treturn {\n\t\tname: \"browser_mouse_wheel\",\n\t\tdescription: \"Scroll the mouse wheel by (deltaX, deltaY) at the current cursor position.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tdeltaX: { type: \"number\" },\n\t\t\t\tdeltaY: { type: \"number\" },\n\t\t\t},\n\t\t\trequired: [\"deltaX\", \"deltaY\"],\n\t\t},\n\t\tasync execute({ deltaX, deltaY }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tawait page.mouse.wheel(deltaX, deltaY)\n\t\t\t\treturn { content: `Wheel scrolled (${deltaX}, ${deltaY})`, details: { deltaX, deltaY } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_mouse_wheel failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 low-level keyboard \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserKeyEventInput {\n\tkey: string\n}\n\nexport function makeKeyDownTool(session: BrowserSession): Tool<BrowserKeyEventInput> {\n\treturn {\n\t\tname: \"browser_key_down\",\n\t\tdescription: \"Press (and hold) a key. Use `browser_key_up` to release.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: { key: { type: \"string\" } },\n\t\t\trequired: [\"key\"],\n\t\t},\n\t\tasync execute({ key }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tawait page.keyboard.down(key)\n\t\t\t\treturn { content: `Key down: ${key}`, details: { key } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_key_down failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport function makeKeyUpTool(session: BrowserSession): Tool<BrowserKeyEventInput> {\n\treturn {\n\t\tname: \"browser_key_up\",\n\t\tdescription: \"Release a previously-held key.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: { key: { type: \"string\" } },\n\t\t\trequired: [\"key\"],\n\t\t},\n\t\tasync execute({ key }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tawait page.keyboard.up(key)\n\t\t\t\treturn { content: `Key up: ${key}`, details: { key } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_key_up failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 cookies \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function makeCookieListTool(session: BrowserSession): Tool<{ urls?: string[] }> {\n\treturn {\n\t\tname: \"browser_cookie_list\",\n\t\tdescription: \"List cookies on the browser context. Optionally scoped to specific URLs.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\turls: { type: \"array\", items: { type: \"string\" } },\n\t\t\t},\n\t\t},\n\t\tasync execute({ urls }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst context = await session.getContext()\n\t\t\t\tconst cookies = await context.cookies(urls)\n\t\t\t\tconst lines = cookies.map((c) => `${c.name}=${c.value} (domain=${c.domain} path=${c.path})`)\n\t\t\t\treturn { content: lines.join(\"\\n\") || \"(no cookies)\", details: { count: cookies.length, cookies } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_cookie_list failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport interface BrowserCookieGetInput {\n\tname: string\n\turl?: string\n}\n\nexport function makeCookieGetTool(session: BrowserSession): Tool<BrowserCookieGetInput> {\n\treturn {\n\t\tname: \"browser_cookie_get\",\n\t\tdescription: \"Return a single cookie by name. If `url` is given, scopes to that URL.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tname: { type: \"string\" },\n\t\t\t\turl: { type: \"string\" },\n\t\t\t},\n\t\t\trequired: [\"name\"],\n\t\t},\n\t\tasync execute({ name, url }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst context = await session.getContext()\n\t\t\t\tconst cookies = await context.cookies(url ? [url] : undefined)\n\t\t\t\tconst found = cookies.find((c) => c.name === name)\n\t\t\t\tif (!found) return { content: `Cookie '${name}' not found.`, details: { name } }\n\t\t\t\treturn { content: `${found.name}=${found.value}`, details: { cookie: found } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_cookie_get failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport interface BrowserCookieSetInput {\n\tname: string\n\tvalue: string\n\turl?: string\n\tdomain?: string\n\tpath?: string\n\texpires?: number\n\thttpOnly?: boolean\n\tsecure?: boolean\n\tsameSite?: \"Strict\" | \"Lax\" | \"None\"\n}\n\nexport function makeCookieSetTool(session: BrowserSession): Tool<BrowserCookieSetInput> {\n\treturn {\n\t\tname: \"browser_cookie_set\",\n\t\tdescription: \"Set a cookie on the browser context. Provide `url` OR `domain + path`.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tname: { type: \"string\" },\n\t\t\t\tvalue: { type: \"string\" },\n\t\t\t\turl: { type: \"string\" },\n\t\t\t\tdomain: { type: \"string\" },\n\t\t\t\tpath: { type: \"string\" },\n\t\t\t\texpires: { type: \"number\" },\n\t\t\t\thttpOnly: { type: \"boolean\" },\n\t\t\t\tsecure: { type: \"boolean\" },\n\t\t\t\tsameSite: { type: \"string\", enum: [\"Strict\", \"Lax\", \"None\"] },\n\t\t\t},\n\t\t\trequired: [\"name\", \"value\"],\n\t\t},\n\t\tasync execute(input, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst context = await session.getContext()\n\t\t\t\tawait context.addCookies([input as never])\n\t\t\t\treturn { content: `Set cookie ${input.name}`, details: { name: input.name } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_cookie_set failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport interface BrowserCookieDeleteInput {\n\tname: string\n\turl?: string\n}\n\nexport function makeCookieDeleteTool(session: BrowserSession): Tool<BrowserCookieDeleteInput> {\n\treturn {\n\t\tname: \"browser_cookie_delete\",\n\t\tdescription: \"Delete a single cookie by name. If `url` is given, scopes to that URL.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tname: { type: \"string\" },\n\t\t\t\turl: { type: \"string\" },\n\t\t\t},\n\t\t\trequired: [\"name\"],\n\t\t},\n\t\tasync execute({ name, url }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst context = await session.getContext()\n\t\t\t\tconst cookies = await context.cookies(url ? [url] : undefined)\n\t\t\t\tconst remaining = cookies.filter((c) => c.name !== name)\n\t\t\t\tawait context.clearCookies()\n\t\t\t\tif (remaining.length > 0) await context.addCookies(remaining)\n\t\t\t\treturn { content: `Deleted cookie ${name}`, details: { name } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_cookie_delete failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport function makeCookieClearTool(session: BrowserSession): Tool<Record<string, never>> {\n\treturn {\n\t\tname: \"browser_cookie_clear\",\n\t\tdescription: \"Clear ALL cookies on the browser context.\",\n\t\tinputSchema: { type: \"object\", properties: {} },\n\t\tasync execute(_, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst context = await session.getContext()\n\t\t\t\tawait context.clearCookies()\n\t\t\t\treturn { content: \"Cleared all cookies.\" }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_cookie_clear failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 localStorage / sessionStorage \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function makeLocalStorageListTool(session: BrowserSession): Tool<Record<string, never>> {\n\treturn {\n\t\tname: \"browser_localstorage_list\",\n\t\tdescription: \"List all keys in localStorage for the active page's origin.\",\n\t\tinputSchema: { type: \"object\", properties: {} },\n\t\tasync execute(_, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tconst entries = await page.evaluate(() => {\n\t\t\t\t\tconst out: Record<string, string | null> = {}\n\t\t\t\t\tfor (let i = 0; i < window.localStorage.length; i++) {\n\t\t\t\t\t\tconst k = window.localStorage.key(i)\n\t\t\t\t\t\tif (k !== null) out[k] = window.localStorage.getItem(k)\n\t\t\t\t\t}\n\t\t\t\t\treturn out\n\t\t\t\t})\n\t\t\t\tconst keys = Object.keys(entries)\n\t\t\t\treturn { content: keys.join(\"\\n\") || \"(empty localStorage)\", details: { count: keys.length, entries } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_localstorage_list failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport function makeLocalStorageGetTool(session: BrowserSession): Tool<{ key: string }> {\n\treturn {\n\t\tname: \"browser_localstorage_get\",\n\t\tdescription: \"Return the value of a key in localStorage for the active page's origin.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: { key: { type: \"string\" } },\n\t\t\trequired: [\"key\"],\n\t\t},\n\t\tasync execute({ key }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tconst value = await page.evaluate((k) => window.localStorage.getItem(k), key)\n\t\t\t\tif (value === null) return { content: `(localStorage key '${key}' not set)`, details: { key } }\n\t\t\t\treturn { content: value, details: { key, value } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_localstorage_get failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport function makeLocalStorageSetTool(session: BrowserSession): Tool<{ key: string; value: string }> {\n\treturn {\n\t\tname: \"browser_localstorage_set\",\n\t\tdescription: \"Set a key in localStorage for the active page's origin.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: { key: { type: \"string\" }, value: { type: \"string\" } },\n\t\t\trequired: [\"key\", \"value\"],\n\t\t},\n\t\tasync execute({ key, value }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tawait page.evaluate(({ k, v }) => window.localStorage.setItem(k, v), { k: key, v: value })\n\t\t\t\treturn { content: `Set localStorage[${key}]`, details: { key, length: value.length } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_localstorage_set failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport function makeLocalStorageDeleteTool(session: BrowserSession): Tool<{ key: string }> {\n\treturn {\n\t\tname: \"browser_localstorage_delete\",\n\t\tdescription: \"Delete a key in localStorage for the active page's origin.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: { key: { type: \"string\" } },\n\t\t\trequired: [\"key\"],\n\t\t},\n\t\tasync execute({ key }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tawait page.evaluate((k) => window.localStorage.removeItem(k), key)\n\t\t\t\treturn { content: `Deleted localStorage[${key}]`, details: { key } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_localstorage_delete failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport function makeLocalStorageClearTool(session: BrowserSession): Tool<Record<string, never>> {\n\treturn {\n\t\tname: \"browser_localstorage_clear\",\n\t\tdescription: \"Clear ALL keys in localStorage for the active page's origin.\",\n\t\tinputSchema: { type: \"object\", properties: {} },\n\t\tasync execute(_, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tawait page.evaluate(() => window.localStorage.clear())\n\t\t\t\treturn { content: \"Cleared localStorage.\" }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_localstorage_clear failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport function makeSessionStorageListTool(session: BrowserSession): Tool<Record<string, never>> {\n\treturn {\n\t\tname: \"browser_sessionstorage_list\",\n\t\tdescription: \"List all keys in sessionStorage for the active page's origin.\",\n\t\tinputSchema: { type: \"object\", properties: {} },\n\t\tasync execute(_, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tconst entries = await page.evaluate(() => {\n\t\t\t\t\tconst out: Record<string, string | null> = {}\n\t\t\t\t\tfor (let i = 0; i < window.sessionStorage.length; i++) {\n\t\t\t\t\t\tconst k = window.sessionStorage.key(i)\n\t\t\t\t\t\tif (k !== null) out[k] = window.sessionStorage.getItem(k)\n\t\t\t\t\t}\n\t\t\t\t\treturn out\n\t\t\t\t})\n\t\t\t\tconst keys = Object.keys(entries)\n\t\t\t\treturn { content: keys.join(\"\\n\") || \"(empty sessionStorage)\", details: { count: keys.length, entries } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_sessionstorage_list failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport function makeSessionStorageGetTool(session: BrowserSession): Tool<{ key: string }> {\n\treturn {\n\t\tname: \"browser_sessionstorage_get\",\n\t\tdescription: \"Return the value of a key in sessionStorage for the active page's origin.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: { key: { type: \"string\" } },\n\t\t\trequired: [\"key\"],\n\t\t},\n\t\tasync execute({ key }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tconst value = await page.evaluate((k) => window.sessionStorage.getItem(k), key)\n\t\t\t\tif (value === null) return { content: `(sessionStorage key '${key}' not set)`, details: { key } }\n\t\t\t\treturn { content: value, details: { key, value } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_sessionstorage_get failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport function makeSessionStorageSetTool(session: BrowserSession): Tool<{ key: string; value: string }> {\n\treturn {\n\t\tname: \"browser_sessionstorage_set\",\n\t\tdescription: \"Set a key in sessionStorage for the active page's origin.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: { key: { type: \"string\" }, value: { type: \"string\" } },\n\t\t\trequired: [\"key\", \"value\"],\n\t\t},\n\t\tasync execute({ key, value }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tawait page.evaluate(({ k, v }) => window.sessionStorage.setItem(k, v), { k: key, v: value })\n\t\t\t\treturn { content: `Set sessionStorage[${key}]`, details: { key, length: value.length } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_sessionstorage_set failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport function makeSessionStorageDeleteTool(session: BrowserSession): Tool<{ key: string }> {\n\treturn {\n\t\tname: \"browser_sessionstorage_delete\",\n\t\tdescription: \"Delete a key in sessionStorage for the active page's origin.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: { key: { type: \"string\" } },\n\t\t\trequired: [\"key\"],\n\t\t},\n\t\tasync execute({ key }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tawait page.evaluate((k) => window.sessionStorage.removeItem(k), key)\n\t\t\t\treturn { content: `Deleted sessionStorage[${key}]`, details: { key } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_sessionstorage_delete failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport function makeSessionStorageClearTool(session: BrowserSession): Tool<Record<string, never>> {\n\treturn {\n\t\tname: \"browser_sessionstorage_clear\",\n\t\tdescription: \"Clear ALL keys in sessionStorage for the active page's origin.\",\n\t\tinputSchema: { type: \"object\", properties: {} },\n\t\tasync execute(_, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tawait page.evaluate(() => window.sessionStorage.clear())\n\t\t\t\treturn { content: \"Cleared sessionStorage.\" }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_sessionstorage_clear failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 storage state load / save \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserStateSaveInput {\n\tpath: string\n}\n\nexport function makeStateSaveTool(session: BrowserSession): Tool<BrowserStateSaveInput> {\n\treturn {\n\t\tname: \"browser_state_save\",\n\t\tdescription: \"Persist the browser context's storage state (cookies + localStorage) to a JSON file.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: { path: { type: \"string\" } },\n\t\t\trequired: [\"path\"],\n\t\t},\n\t\tasync execute({ path }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst context = await session.getContext()\n\t\t\t\tawait context.storageState({ path })\n\t\t\t\treturn { content: `Saved storage state to ${path}`, details: { path } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_state_save failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport interface BrowserStateLoadInput {\n\tpath: string\n}\n\nexport function makeStateLoadTool(session: BrowserSession): Tool<BrowserStateLoadInput> {\n\treturn {\n\t\tname: \"browser_state_load\",\n\t\tdescription: \"Load cookies + localStorage from a storage-state JSON file. Cookies are restored to the context; localStorage is best-effort restored for the active page's origin only.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: { path: { type: \"string\" } },\n\t\t\trequired: [\"path\"],\n\t\t},\n\t\tasync execute({ path }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst fs = await import(\"node:fs/promises\")\n\t\t\t\tconst raw = await fs.readFile(path, \"utf-8\")\n\t\t\t\tconst state = JSON.parse(raw) as { cookies?: any[]; origins?: { origin: string; localStorage: { name: string; value: string }[] }[] }\n\t\t\t\tconst context = await session.getContext()\n\t\t\t\tif (state.cookies && state.cookies.length > 0) await context.addCookies(state.cookies)\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tconst currentOrigin = new URL(page.url()).origin\n\t\t\t\tconst match = state.origins?.find((o) => o.origin === currentOrigin)\n\t\t\t\tif (match) {\n\t\t\t\t\tawait page.evaluate((items) => {\n\t\t\t\t\t\tfor (const it of items) window.localStorage.setItem(it.name, it.value)\n\t\t\t\t\t}, match.localStorage)\n\t\t\t\t}\n\t\t\t\treturn { content: `Loaded storage state from ${path}`, details: { cookies: state.cookies?.length ?? 0, origin: currentOrigin } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_state_load failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 delete_data \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function makeDeleteDataTool(session: BrowserSession): Tool<Record<string, never>> {\n\treturn {\n\t\tname: \"browser_delete_data\",\n\t\tdescription: \"Clear all cookies, localStorage and sessionStorage for the active page's origin.\",\n\t\tinputSchema: { type: \"object\", properties: {} },\n\t\tasync execute(_, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst context = await session.getContext()\n\t\t\t\tawait context.clearCookies()\n\t\t\t\tconst page = await session.getPage()\n\t\t\t\tawait page.evaluate(() => {\n\t\t\t\t\twindow.localStorage.clear()\n\t\t\t\t\twindow.sessionStorage.clear()\n\t\t\t\t})\n\t\t\t\treturn { content: \"Cleared cookies + storage for the active origin.\" }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_delete_data failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 network mocking \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserRouteInput {\n\t/** URL pattern (glob or string). */\n\tpattern: string\n\t/** Action when the route matches. */\n\taction: \"abort\" | \"fulfill\" | \"continue\"\n\t/** Status code for `fulfill`. Default 200. */\n\tstatus?: number\n\t/** Response body for `fulfill`. */\n\tbody?: string\n\t/** Content type for `fulfill`. Default text/plain. */\n\tcontentType?: string\n}\n\nexport function makeRouteTool(session: BrowserSession): Tool<BrowserRouteInput> {\n\treturn {\n\t\tname: \"browser_route\",\n\t\tdescription: \"Register a network mock for URLs matching `pattern`. Use `unroute` to remove.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tpattern: { type: \"string\" },\n\t\t\t\taction: { type: \"string\", enum: [\"abort\", \"fulfill\", \"continue\"] },\n\t\t\t\tstatus: { type: \"integer\", minimum: 100, maximum: 599 },\n\t\t\t\tbody: { type: \"string\" },\n\t\t\t\tcontentType: { type: \"string\" },\n\t\t\t},\n\t\t\trequired: [\"pattern\", \"action\"],\n\t\t},\n\t\tasync execute(input, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst entry: RouteEntry = {\n\t\t\t\t\tpattern: input.pattern,\n\t\t\t\t\taction: input.action,\n\t\t\t\t\tstatus: input.status,\n\t\t\t\t\tbody: input.body,\n\t\t\t\t\tcontentType: input.contentType,\n\t\t\t\t\thandler: async (route: Route) => {\n\t\t\t\t\t\tif (input.action === \"abort\") await route.abort()\n\t\t\t\t\t\telse if (input.action === \"fulfill\")\n\t\t\t\t\t\t\tawait route.fulfill({\n\t\t\t\t\t\t\t\tstatus: input.status ?? 200,\n\t\t\t\t\t\t\t\tbody: input.body ?? \"\",\n\t\t\t\t\t\t\t\tcontentType: input.contentType ?? \"text/plain\",\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\telse await route.continue()\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tawait session.addRoute(entry)\n\t\t\t\treturn { content: `Registered route ${input.pattern} \u2192 ${input.action}`, details: { pattern: input.pattern, action: input.action } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_route failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport function makeRouteListTool(session: BrowserSession): Tool<Record<string, never>> {\n\treturn {\n\t\tname: \"browser_route_list\",\n\t\tdescription: \"List all registered network routes on the active context.\",\n\t\tinputSchema: { type: \"object\", properties: {} },\n\t\tasync execute(_, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\tconst routes = session.getRoutes()\n\t\t\tif (routes.length === 0) return { content: \"(no routes registered)\", details: { count: 0 } }\n\t\t\tconst lines = routes.map((r) => `${r.pattern} \u2192 ${r.action}${r.status ? ` (${r.status})` : \"\"}`)\n\t\t\treturn { content: lines.join(\"\\n\"), details: { count: routes.length, routes: routes.map(({ handler: _h, ...rest }) => rest) } }\n\t\t},\n\t}\n}\n\nexport function makeUnrouteTool(session: BrowserSession): Tool<{ pattern: string }> {\n\treturn {\n\t\tname: \"browser_unroute\",\n\t\tdescription: \"Remove a previously-registered network route by its pattern.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: { pattern: { type: \"string\" } },\n\t\t\trequired: [\"pattern\"],\n\t\t},\n\t\tasync execute({ pattern }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tconst removed = await session.removeRoute(pattern)\n\t\t\t\treturn removed\n\t\t\t\t\t? { content: `Removed route ${pattern}`, details: { pattern } }\n\t\t\t\t\t: { content: `No route registered for ${pattern}`, details: { pattern, found: false } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_unroute failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport interface BrowserNetworkStateSetInput {\n\toffline: boolean\n}\n\nexport function makeNetworkStateSetTool(session: BrowserSession): Tool<BrowserNetworkStateSetInput> {\n\treturn {\n\t\tname: \"browser_network_state_set\",\n\t\tdescription: \"Toggle offline mode on the browser context.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: { offline: { type: \"boolean\" } },\n\t\t\trequired: [\"offline\"],\n\t\t},\n\t\tasync execute({ offline }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tawait session.setOffline(offline)\n\t\t\t\treturn { content: offline ? \"Network: offline\" : \"Network: online\", details: { offline } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_network_state_set failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 tracing \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserTracingStartInput {\n\tscreenshots?: boolean\n\tsnapshots?: boolean\n\tsources?: boolean\n}\n\nexport function makeTracingStartTool(session: BrowserSession): Tool<BrowserTracingStartInput> {\n\treturn {\n\t\tname: \"browser_tracing_start\",\n\t\tdescription: \"Begin a Playwright trace recording on the active context. Stop with `browser_tracing_stop`.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tscreenshots: { type: \"boolean\" },\n\t\t\t\tsnapshots: { type: \"boolean\" },\n\t\t\t\tsources: { type: \"boolean\" },\n\t\t\t},\n\t\t},\n\t\tasync execute(input, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tawait session.startTracing(input)\n\t\t\t\treturn { content: \"Tracing started.\", details: { ...input } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_tracing_start failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport interface BrowserTracingStopInput {\n\t/** Output zip path. If omitted, the trace is discarded. */\n\tpath?: string\n}\n\nexport function makeTracingStopTool(session: BrowserSession): Tool<BrowserTracingStopInput> {\n\treturn {\n\t\tname: \"browser_tracing_stop\",\n\t\tdescription: \"Stop the active Playwright trace. Saves to `path` (a .zip file) when provided.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: { path: { type: \"string\" } },\n\t\t},\n\t\tasync execute({ path }, ctx) {\n\t\t\tbindAbort(session, ctx)\n\t\t\ttry {\n\t\t\t\tawait session.stopTracing(path)\n\t\t\t\treturn { content: path ? `Tracing stopped \u2014 trace saved to ${path}` : \"Tracing stopped (discarded).\", details: { path } }\n\t\t\t} catch (err) {\n\t\t\t\treturn errorOutput(`browser_tracing_stop failed: ${err instanceof Error ? err.message : String(err)}`)\n\t\t\t}\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Action-discriminator tools \u2014 collapse related primitives into a single tool\n// to cut LLM prompt overhead. Individual factories above remain exported for\n// consumers who need granular control.\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n// \u2500\u2500\u2500 browser_cookies \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserCookiesInput {\n\taction: \"list\" | \"get\" | \"set\" | \"delete\" | \"clear\"\n\t/** Cookie name (get/set/delete). */\n\tname?: string\n\t/** Cookie value (set). */\n\tvalue?: string\n\t/** URL scope (get/set/delete) or list filter (list). */\n\turl?: string\n\tdomain?: string\n\tpath?: string\n\texpires?: number\n\thttpOnly?: boolean\n\tsecure?: boolean\n\tsameSite?: \"Strict\" | \"Lax\" | \"None\"\n}\n\nexport function makeCookiesTool(session: BrowserSession): Tool<BrowserCookiesInput> {\n\treturn {\n\t\tname: \"browser_cookies\",\n\t\tdescription: \"Manage cookies. Actions: list, get, set, delete, clear.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\taction: { type: \"string\", enum: [\"list\", \"get\", \"set\", \"delete\", \"clear\"] },\n\t\t\t\tname: { type: \"string\" },\n\t\t\t\tvalue: { type: \"string\" },\n\t\t\t\turl: { type: \"string\" },\n\t\t\t\tdomain: { type: \"string\" },\n\t\t\t\tpath: { type: \"string\" },\n\t\t\t\texpires: { type: \"number\" },\n\t\t\t\thttpOnly: { type: \"boolean\" },\n\t\t\t\tsecure: { type: \"boolean\" },\n\t\t\t\tsameSite: { type: \"string\", enum: [\"Strict\", \"Lax\", \"None\"] },\n\t\t\t},\n\t\t\trequired: [\"action\"],\n\t\t},\n\t\tasync execute(input, ctx) {\n\t\t\tconst { action, name, value, url } = input\n\t\t\tif (action === \"list\") return makeCookieListTool(session).execute({ urls: url ? [url] : undefined }, ctx)\n\t\t\tif (action === \"get\") {\n\t\t\t\tif (!name) return errorOutput(\"browser_cookies get requires `name`.\")\n\t\t\t\treturn makeCookieGetTool(session).execute({ name, url }, ctx)\n\t\t\t}\n\t\t\tif (action === \"set\") {\n\t\t\t\tif (!name || value === undefined) return errorOutput(\"browser_cookies set requires `name` and `value`.\")\n\t\t\t\treturn makeCookieSetTool(session).execute(input as BrowserCookieSetInput, ctx)\n\t\t\t}\n\t\t\tif (action === \"delete\") {\n\t\t\t\tif (!name) return errorOutput(\"browser_cookies delete requires `name`.\")\n\t\t\t\treturn makeCookieDeleteTool(session).execute({ name, url }, ctx)\n\t\t\t}\n\t\t\treturn makeCookieClearTool(session).execute({}, ctx)\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 browser_localstorage / browser_sessionstorage \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserStorageInput {\n\taction: \"list\" | \"get\" | \"set\" | \"delete\" | \"clear\"\n\tkey?: string\n\tvalue?: string\n}\n\nfunction makeStorageActionTool(\n\tsession: BrowserSession,\n\tkind: \"local\" | \"session\",\n): Tool<BrowserStorageInput> {\n\tconst name = kind === \"local\" ? \"browser_localstorage\" : \"browser_sessionstorage\"\n\tconst list = kind === \"local\" ? makeLocalStorageListTool : makeSessionStorageListTool\n\tconst get = kind === \"local\" ? makeLocalStorageGetTool : makeSessionStorageGetTool\n\tconst set = kind === \"local\" ? makeLocalStorageSetTool : makeSessionStorageSetTool\n\tconst del = kind === \"local\" ? makeLocalStorageDeleteTool : makeSessionStorageDeleteTool\n\tconst clear = kind === \"local\" ? makeLocalStorageClearTool : makeSessionStorageClearTool\n\treturn {\n\t\tname,\n\t\tdescription: `Manage ${kind}Storage for the active page's origin. Actions: list, get, set, delete, clear.`,\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\taction: { type: \"string\", enum: [\"list\", \"get\", \"set\", \"delete\", \"clear\"] },\n\t\t\t\tkey: { type: \"string\" },\n\t\t\t\tvalue: { type: \"string\" },\n\t\t\t},\n\t\t\trequired: [\"action\"],\n\t\t},\n\t\tasync execute({ action, key, value }, ctx) {\n\t\t\tif (action === \"list\") return list(session).execute({}, ctx)\n\t\t\tif (action === \"clear\") return clear(session).execute({}, ctx)\n\t\t\tif (!key) return errorOutput(`${name} ${action} requires \\`key\\`.`)\n\t\t\tif (action === \"get\") return get(session).execute({ key }, ctx)\n\t\t\tif (action === \"set\") {\n\t\t\t\tif (value === undefined) return errorOutput(`${name} set requires \\`value\\`.`)\n\t\t\t\treturn set(session).execute({ key, value }, ctx)\n\t\t\t}\n\t\t\treturn del(session).execute({ key }, ctx)\n\t\t},\n\t}\n}\n\nexport const makeLocalStorageActionTool = (s: BrowserSession) => makeStorageActionTool(s, \"local\")\nexport const makeSessionStorageActionTool = (s: BrowserSession) => makeStorageActionTool(s, \"session\")\n\n// \u2500\u2500\u2500 browser_state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserStateInput {\n\taction: \"save\" | \"load\"\n\tpath: string\n}\n\nexport function makeStateTool(session: BrowserSession): Tool<BrowserStateInput> {\n\treturn {\n\t\tname: \"browser_state\",\n\t\tdescription: \"Persist or restore Playwright storage state (cookies + per-origin localStorage). Actions: save, load.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\taction: { type: \"string\", enum: [\"save\", \"load\"] },\n\t\t\t\tpath: { type: \"string\" },\n\t\t\t},\n\t\t\trequired: [\"action\", \"path\"],\n\t\t},\n\t\tasync execute({ action, path }, ctx) {\n\t\t\tif (action === \"save\") return makeStateSaveTool(session).execute({ path }, ctx)\n\t\t\treturn makeStateLoadTool(session).execute({ path }, ctx)\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 browser_route \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserRouteActionInput {\n\taction: \"add\" | \"list\" | \"remove\"\n\tpattern?: string\n\tmode?: \"abort\" | \"fulfill\" | \"continue\"\n\tstatus?: number\n\tbody?: string\n\tcontentType?: string\n}\n\nexport function makeRouteActionTool(session: BrowserSession): Tool<BrowserRouteActionInput> {\n\treturn {\n\t\tname: \"browser_route\",\n\t\tdescription: \"Manage network mocks. Actions: add (pattern + mode), list, remove (pattern).\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\taction: { type: \"string\", enum: [\"add\", \"list\", \"remove\"] },\n\t\t\t\tpattern: { type: \"string\" },\n\t\t\t\tmode: { type: \"string\", enum: [\"abort\", \"fulfill\", \"continue\"] },\n\t\t\t\tstatus: { type: \"integer\", minimum: 100, maximum: 599 },\n\t\t\t\tbody: { type: \"string\" },\n\t\t\t\tcontentType: { type: \"string\" },\n\t\t\t},\n\t\t\trequired: [\"action\"],\n\t\t},\n\t\tasync execute({ action, pattern, mode, status, body, contentType }, ctx) {\n\t\t\tif (action === \"list\") return makeRouteListTool(session).execute({}, ctx)\n\t\t\tif (action === \"remove\") {\n\t\t\t\tif (!pattern) return errorOutput(\"browser_route remove requires `pattern`.\")\n\t\t\t\treturn makeUnrouteTool(session).execute({ pattern }, ctx)\n\t\t\t}\n\t\t\tif (!pattern || !mode) return errorOutput(\"browser_route add requires `pattern` and `mode`.\")\n\t\t\treturn makeRouteTool(session).execute({ pattern, action: mode, status, body, contentType }, ctx)\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 browser_tracing \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserTracingInput {\n\taction: \"start\" | \"stop\"\n\tpath?: string\n\tscreenshots?: boolean\n\tsnapshots?: boolean\n\tsources?: boolean\n}\n\nexport function makeTracingTool(session: BrowserSession): Tool<BrowserTracingInput> {\n\treturn {\n\t\tname: \"browser_tracing\",\n\t\tdescription: \"Playwright trace recording. Actions: start, stop (path saves a .zip).\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\taction: { type: \"string\", enum: [\"start\", \"stop\"] },\n\t\t\t\tpath: { type: \"string\" },\n\t\t\t\tscreenshots: { type: \"boolean\" },\n\t\t\t\tsnapshots: { type: \"boolean\" },\n\t\t\t\tsources: { type: \"boolean\" },\n\t\t\t},\n\t\t\trequired: [\"action\"],\n\t\t},\n\t\tasync execute({ action, path, screenshots, snapshots, sources }, ctx) {\n\t\t\tif (action === \"start\") return makeTracingStartTool(session).execute({ screenshots, snapshots, sources }, ctx)\n\t\t\treturn makeTracingStopTool(session).execute({ path }, ctx)\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 browser_mouse \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserMouseInput {\n\taction: \"move\" | \"down\" | \"up\" | \"wheel\"\n\tx?: number\n\ty?: number\n\tsteps?: number\n\tbutton?: \"left\" | \"right\" | \"middle\"\n\tclickCount?: number\n\tdeltaX?: number\n\tdeltaY?: number\n}\n\nexport function makeMouseTool(session: BrowserSession): Tool<BrowserMouseInput> {\n\treturn {\n\t\tname: \"browser_mouse\",\n\t\tdescription: \"Low-level mouse primitives. Actions: move (x, y), down/up (button), wheel (deltaX, deltaY).\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\taction: { type: \"string\", enum: [\"move\", \"down\", \"up\", \"wheel\"] },\n\t\t\t\tx: { type: \"number\" },\n\t\t\t\ty: { type: \"number\" },\n\t\t\t\tsteps: { type: \"integer\", minimum: 1 },\n\t\t\t\tbutton: { type: \"string\", enum: [\"left\", \"right\", \"middle\"] },\n\t\t\t\tclickCount: { type: \"integer\", minimum: 1 },\n\t\t\t\tdeltaX: { type: \"number\" },\n\t\t\t\tdeltaY: { type: \"number\" },\n\t\t\t},\n\t\t\trequired: [\"action\"],\n\t\t},\n\t\tasync execute(input, ctx) {\n\t\t\tconst { action, x, y, steps, button, clickCount, deltaX, deltaY } = input\n\t\t\tif (action === \"move\") {\n\t\t\t\tif (x === undefined || y === undefined) return errorOutput(\"browser_mouse move requires `x` and `y`.\")\n\t\t\t\treturn makeMouseMoveTool(session).execute({ x, y, steps }, ctx)\n\t\t\t}\n\t\t\tif (action === \"down\") return makeMouseDownTool(session).execute({ button, clickCount }, ctx)\n\t\t\tif (action === \"up\") return makeMouseUpTool(session).execute({ button, clickCount }, ctx)\n\t\t\tif (deltaX === undefined || deltaY === undefined) return errorOutput(\"browser_mouse wheel requires `deltaX` and `deltaY`.\")\n\t\t\treturn makeMouseWheelTool(session).execute({ deltaX, deltaY }, ctx)\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 browser_key (down/up only \u2014 press is kept standalone as the common case) \u2500\n\nexport interface BrowserKeyInput {\n\taction: \"down\" | \"up\"\n\tkey: string\n}\n\nexport function makeKeyTool(session: BrowserSession): Tool<BrowserKeyInput> {\n\treturn {\n\t\tname: \"browser_key\",\n\t\tdescription: \"Hold or release a key for chord input. Actions: down, up. For single key-presses use `browser_press_key`.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\taction: { type: \"string\", enum: [\"down\", \"up\"] },\n\t\t\t\tkey: { type: \"string\" },\n\t\t\t},\n\t\t\trequired: [\"action\", \"key\"],\n\t\t},\n\t\tasync execute({ action, key }, ctx) {\n\t\t\tif (action === \"down\") return makeKeyDownTool(session).execute({ key }, ctx)\n\t\t\treturn makeKeyUpTool(session).execute({ key }, ctx)\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 browser_check (collapsed \u2014 `checked: boolean`) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface BrowserCheckActionInput {\n\tselector: string\n\tchecked: boolean\n\ttimeoutMs?: number\n}\n\nexport function makeCheckActionTool(session: BrowserSession): Tool<BrowserCheckActionInput> {\n\treturn {\n\t\tname: \"browser_check\",\n\t\tdescription: \"Set a checkbox or radio to a target state. Pass `checked: true` to tick, `false` to untick.\",\n\t\tinputSchema: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tselector: { type: \"string\" },\n\t\t\t\tchecked: { type: \"boolean\" },\n\t\t\t\ttimeoutMs: { type: \"integer\", minimum: 1 },\n\t\t\t},\n\t\t\trequired: [\"selector\", \"checked\"],\n\t\t},\n\t\tasync execute({ selector, checked, timeoutMs }, ctx) {\n\t\t\tif (checked) return makeCheckTool(session).execute({ selector, timeoutMs }, ctx)\n\t\t\treturn makeUncheckTool(session).execute({ selector, timeoutMs }, ctx)\n\t\t},\n\t}\n}\n\n// \u2500\u2500\u2500 close \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function makeCloseTool(session: BrowserSession): Tool<Record<string, never>> {\n\treturn {\n\t\tname: \"browser_close\",\n\t\tdescription: \"Close the shared browser session. Later browser_* calls will auto-reopen.\",\n\t\tinputSchema: { type: \"object\", properties: {} },\n\t\tasync execute() {\n\t\t\tawait session.close()\n\t\t\treturn { content: \"Browser session closed.\" }\n\t\t},\n\t}\n}\n\n/**\n * Default session-bound tool set \u2014 33 tools, action-discriminator collapsed\n * for ~3.5K token savings vs. fully expanded 54-tool surface.\n *\n * Granular factories (`makeCookieListTool`, `makeMouseMoveTool`, \u2026) are still\n * exported above for consumers who want minimal surfaces.\n */\nexport function createSessionTools(session: BrowserSession): Tool[] {\n\treturn [\n\t\t// Navigation\n\t\tmakeNavigateTool(session),\n\t\tmakeNavigateBackTool(session),\n\t\tmakeReloadTool(session),\n\t\t// Observation\n\t\tmakeReadTool(session),\n\t\tmakeSnapshotTool(session),\n\t\tmakeScreenshotTool(session),\n\t\tmakePdfTool(session),\n\t\t// Interaction\n\t\tmakeClickTool(session),\n\t\tmakeDblClickTool(session),\n\t\tmakeHoverTool(session),\n\t\tmakeTypeTool(session),\n\t\tmakeSelectOptionTool(session),\n\t\tmakeCheckActionTool(session),\n\t\tmakeFileUploadTool(session),\n\t\tmakeDragTool(session),\n\t\tmakePressKeyTool(session),\n\t\tmakeWaitTool(session),\n\t\t// Low-level input (collapsed)\n\t\tmakeMouseTool(session),\n\t\tmakeKeyTool(session),\n\t\t// JS execution\n\t\tmakeEvalTool(session),\n\t\t// Viewport + tabs\n\t\tmakeResizeTool(session),\n\t\tmakeTabsTool(session),\n\t\t// Inspection\n\t\tmakeConsoleMessagesTool(session),\n\t\tmakeNetworkRequestsTool(session),\n\t\t// Dialogs\n\t\tmakeHandleDialogTool(session),\n\t\t// Storage (collapsed)\n\t\tmakeCookiesTool(session),\n\t\tmakeLocalStorageActionTool(session),\n\t\tmakeSessionStorageActionTool(session),\n\t\tmakeStateTool(session),\n\t\tmakeDeleteDataTool(session),\n\t\t// Network (collapsed)\n\t\tmakeRouteActionTool(session),\n\t\tmakeNetworkStateSetTool(session),\n\t\t// Tracing (collapsed)\n\t\tmakeTracingTool(session),\n\t\t// Lifecycle\n\t\tmakeCloseTool(session),\n\t]\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["session", "ctx", "message", "details", "url", "waitUntil", "timeoutMs", "page", "response", "title", "err", "maxChars", "selector", "cap", "text", "sel", "el", "truncated", "body", "index", "clear", "pressEnter", "locator", "loadState", "path", "fullPage", "buf", "script", "result", "s", "v", "serialized", "yaml", "values", "labels", "arg", "value", "label", "selected", "paths", "key", "direction", "width", "height", "action", "op", "tabs", "t", "types", "messages", "allow", "m", "urlContains", "resourceTypes", "failedOnly", "entries", "e", "status", "accept", "promptText", "fromSelector", "toSelector", "format", "landscape", "printBackground", "x", "y", "steps", "button", "clickCount", "deltaX", "deltaY", "urls", "cookies", "c", "name", "found", "input", "context", "remaining", "_", "out", "i", "k", "keys", "raw", "state", "currentOrigin", "match", "o", "items", "it", "entry", "route", "routes", "r", "_h", "rest", "pattern", "offline", "kind", "list", "get", "set", "del", "mode", "contentType", "screenshots", "snapshots", "sources", "checked"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { BrowserContext, Page, Route } from "playwright-core";
|
|
2
|
+
/** Configuration for a browser session. */
|
|
3
|
+
export interface BrowserSessionConfig {
|
|
4
|
+
/** Launch headless (default true). */
|
|
5
|
+
headless?: boolean;
|
|
6
|
+
/** Default timeout for every operation, in ms. Default 30000. */
|
|
7
|
+
defaultTimeoutMs?: number;
|
|
8
|
+
/** Viewport size. Default { width: 1280, height: 800 }. */
|
|
9
|
+
viewport?: {
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
};
|
|
13
|
+
/** User-agent override. */
|
|
14
|
+
userAgent?: string;
|
|
15
|
+
/** Additional launch args (passed to chromium.launch). */
|
|
16
|
+
launchArgs?: string[];
|
|
17
|
+
/** Max console messages retained per page (FIFO). Default 200. */
|
|
18
|
+
consoleBufferSize?: number;
|
|
19
|
+
/** Max network entries retained per page (FIFO). Default 200. */
|
|
20
|
+
networkBufferSize?: number;
|
|
21
|
+
}
|
|
22
|
+
/** Captured console message in plain-data form. */
|
|
23
|
+
export interface ConsoleEntry {
|
|
24
|
+
type: string;
|
|
25
|
+
text: string;
|
|
26
|
+
location?: {
|
|
27
|
+
url: string;
|
|
28
|
+
lineNumber: number;
|
|
29
|
+
columnNumber: number;
|
|
30
|
+
};
|
|
31
|
+
timestamp: number;
|
|
32
|
+
}
|
|
33
|
+
/** Captured network request in plain-data form. */
|
|
34
|
+
export interface NetworkEntry {
|
|
35
|
+
url: string;
|
|
36
|
+
method: string;
|
|
37
|
+
resourceType: string;
|
|
38
|
+
status?: number;
|
|
39
|
+
statusText?: string;
|
|
40
|
+
failed?: boolean;
|
|
41
|
+
failureText?: string;
|
|
42
|
+
fromCache?: boolean;
|
|
43
|
+
timestamp: number;
|
|
44
|
+
}
|
|
45
|
+
/** Pre-registered dialog policy. The next dialog `page.on('dialog')` fires will be handled per this policy. */
|
|
46
|
+
export interface DialogPolicy {
|
|
47
|
+
/** Accept the dialog. If false, dismiss it. */
|
|
48
|
+
accept: boolean;
|
|
49
|
+
/** Optional response for window.prompt(). */
|
|
50
|
+
promptText?: string;
|
|
51
|
+
}
|
|
52
|
+
/** Registered network route. */
|
|
53
|
+
export interface RouteEntry {
|
|
54
|
+
pattern: string;
|
|
55
|
+
action: "abort" | "fulfill" | "continue";
|
|
56
|
+
status?: number;
|
|
57
|
+
body?: string;
|
|
58
|
+
contentType?: string;
|
|
59
|
+
handler: (route: Route) => Promise<void>;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Long-lived browser session shared across tool calls.
|
|
63
|
+
*
|
|
64
|
+
* Call `start()` once per conversation; tools created with
|
|
65
|
+
* {@link createBrowserTools} bound to this session reuse the same
|
|
66
|
+
* {@link Page}. Call `close()` to release the browser.
|
|
67
|
+
*
|
|
68
|
+
* Errors on a closed session throw — consumers should guard with
|
|
69
|
+
* `session.isOpen()` or call `start()` again to reopen.
|
|
70
|
+
*/
|
|
71
|
+
export declare class BrowserSession {
|
|
72
|
+
private browser;
|
|
73
|
+
private context;
|
|
74
|
+
private states;
|
|
75
|
+
private activeIndex;
|
|
76
|
+
private dialogPolicy;
|
|
77
|
+
private routes;
|
|
78
|
+
private tracingActive;
|
|
79
|
+
private offline;
|
|
80
|
+
private readonly config;
|
|
81
|
+
constructor(config?: BrowserSessionConfig);
|
|
82
|
+
start(): Promise<void>;
|
|
83
|
+
private attachPage;
|
|
84
|
+
getPage(): Promise<Page>;
|
|
85
|
+
getContext(): Promise<BrowserContext>;
|
|
86
|
+
listPages(): {
|
|
87
|
+
index: number;
|
|
88
|
+
url: string;
|
|
89
|
+
title?: string;
|
|
90
|
+
active: boolean;
|
|
91
|
+
}[];
|
|
92
|
+
listPagesWithTitles(): Promise<{
|
|
93
|
+
index: number;
|
|
94
|
+
url: string;
|
|
95
|
+
title: string;
|
|
96
|
+
active: boolean;
|
|
97
|
+
}[]>;
|
|
98
|
+
switchTab(index: number): Promise<Page>;
|
|
99
|
+
newTab(): Promise<Page>;
|
|
100
|
+
closeTab(index: number): Promise<void>;
|
|
101
|
+
getConsole(): ConsoleEntry[];
|
|
102
|
+
clearConsole(): void;
|
|
103
|
+
getNetwork(): NetworkEntry[];
|
|
104
|
+
clearNetwork(): void;
|
|
105
|
+
setDialogPolicy(policy: DialogPolicy): void;
|
|
106
|
+
getRoutes(): RouteEntry[];
|
|
107
|
+
addRoute(entry: RouteEntry): Promise<void>;
|
|
108
|
+
removeRoute(pattern: string): Promise<boolean>;
|
|
109
|
+
setOffline(value: boolean): Promise<void>;
|
|
110
|
+
isOffline(): boolean;
|
|
111
|
+
isTracing(): boolean;
|
|
112
|
+
startTracing(options?: {
|
|
113
|
+
screenshots?: boolean;
|
|
114
|
+
snapshots?: boolean;
|
|
115
|
+
sources?: boolean;
|
|
116
|
+
}): Promise<void>;
|
|
117
|
+
stopTracing(outputPath?: string): Promise<void>;
|
|
118
|
+
isOpen(): boolean;
|
|
119
|
+
close(): Promise<void>;
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
|
package/dist/session.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.BrowserSession=void 0;const playwright_core_1=require("playwright-core");class BrowserSession{browser;context;states=[];activeIndex=0;dialogPolicy={accept:!1};routes=new Map;tracingActive=!1;offline=!1;config;constructor(t={}){this.config={headless:t.headless??!0,defaultTimeoutMs:t.defaultTimeoutMs??3e4,viewport:t.viewport??{width:1280,height:800},userAgent:t.userAgent,launchArgs:t.launchArgs,consoleBufferSize:t.consoleBufferSize??200,networkBufferSize:t.networkBufferSize??200}}async start(){if(this.browser)return;this.browser=await playwright_core_1.chromium.launch({headless:this.config.headless,args:this.config.launchArgs}),this.context=await this.browser.newContext({viewport:this.config.viewport,userAgent:this.config.userAgent}),this.context.setDefaultTimeout(this.config.defaultTimeoutMs),this.context.on("page",e=>this.attachPage(e));const t=await this.context.newPage();this.states.find(e=>e.page===t)||this.attachPage(t),this.activeIndex=0}attachPage(t){const e={page:t,console:[],network:[]};this.states.push(e),t.on("console",s=>{const i=s.location();e.console.push({type:s.type(),text:s.text(),location:i?{url:i.url,lineNumber:i.lineNumber,columnNumber:i.columnNumber}:void 0,timestamp:Date.now()}),e.console.length>this.config.consoleBufferSize&&e.console.shift()}),t.on("pageerror",s=>{e.console.push({type:"error",text:s.message,timestamp:Date.now()}),e.console.length>this.config.consoleBufferSize&&e.console.shift()}),t.on("request",s=>{e.network.push({url:s.url(),method:s.method(),resourceType:s.resourceType(),timestamp:Date.now()}),e.network.length>this.config.networkBufferSize&&e.network.shift()}),t.on("response",s=>{const i=[...e.network].reverse().find(n=>n.url===s.url()&&n.status===void 0);i&&(i.status=s.status(),i.statusText=s.statusText(),i.fromCache=s.fromServiceWorker())}),t.on("requestfailed",s=>{const i=[...e.network].reverse().find(n=>n.url===s.url()&&n.status===void 0);i&&(i.failed=!0,i.failureText=s.failure()?.errorText)}),t.on("dialog",s=>{const i=this.dialogPolicy;(i.accept?s.accept(i.promptText):s.dismiss()).catch(()=>{})}),t.on("close",()=>{const s=this.states.findIndex(i=>i.page===t);s>=0&&(this.states.splice(s,1),this.activeIndex>=this.states.length&&(this.activeIndex=Math.max(0,this.states.length-1)))})}async getPage(){this.states.length===0&&await this.start();const t=this.states[this.activeIndex];if(!t)throw new Error("BrowserSession failed to initialize a page");return t.page}async getContext(){if(this.context||await this.start(),!this.context)throw new Error("BrowserSession failed to initialize a context");return this.context}listPages(){return this.states.map((t,e)=>({index:e,url:t.page.url(),active:e===this.activeIndex}))}async listPagesWithTitles(){return Promise.all(this.states.map(async(t,e)=>({index:e,url:t.page.url(),title:await t.page.title().catch(()=>""),active:e===this.activeIndex})))}async switchTab(t){if(t<0||t>=this.states.length)throw new Error(`tab index ${t} out of range (0..${this.states.length-1})`);this.activeIndex=t;const e=this.states[t].page;return await e.bringToFront().catch(()=>{}),e}async newTab(){const e=await(await this.getContext()).newPage();return this.activeIndex=this.states.findIndex(s=>s.page===e),this.activeIndex<0&&(this.attachPage(e),this.activeIndex=this.states.length-1),e}async closeTab(t){if(t<0||t>=this.states.length)throw new Error(`tab index ${t} out of range (0..${this.states.length-1})`);await this.states[t].page.close().catch(()=>{})}getConsole(){return this.states[this.activeIndex]?.console.slice()??[]}clearConsole(){const t=this.states[this.activeIndex];t&&(t.console.length=0)}getNetwork(){return this.states[this.activeIndex]?.network.slice()??[]}clearNetwork(){const t=this.states[this.activeIndex];t&&(t.network.length=0)}setDialogPolicy(t){this.dialogPolicy=t}getRoutes(){return Array.from(this.routes.values())}async addRoute(t){const e=await this.getContext();this.routes.set(t.pattern,t),await e.route(t.pattern,t.handler)}async removeRoute(t){const e=this.routes.get(t);return e?(await(await this.getContext()).unroute(t,e.handler).catch(()=>{}),this.routes.delete(t),!0):!1}async setOffline(t){await(await this.getContext()).setOffline(t),this.offline=t}isOffline(){return this.offline}isTracing(){return this.tracingActive}async startTracing(t){await(await this.getContext()).tracing.start({screenshots:t?.screenshots??!0,snapshots:t?.snapshots??!0,sources:t?.sources??!1}),this.tracingActive=!0}async stopTracing(t){await(await this.getContext()).tracing.stop(t?{path:t}:void 0),this.tracingActive=!1}isOpen(){return this.browser!==void 0&&this.states.length>0}async close(){const t=this.browser;this.states=[],this.activeIndex=0,this.context=void 0,this.browser=void 0,this.routes.clear(),this.tracingActive=!1,this.offline=!1,t&&await t.close().catch(()=>{})}}exports.BrowserSession=BrowserSession;
|
|
2
|
+
//# sourceMappingURL=session.js.map
|