reflex-browser
Advanced tools
+10
-9
@@ -1,4 +0,4 @@ | ||
| "use strict";var D=(e,t)=>()=>{try{return t||e((t={exports:{}}).exports,t),t.exports}catch(r){throw t=0,r}};var Ke=D((sr,X)=>{"use strict";var de=require("fs"),Ot=require("path"),{execFileSync:B}=require("child_process");function Ue(e){if(!e||e<1)return!1;try{return process.kill(e,0),!0}catch(t){return t.code==="EPERM"}}function jt(e){if(process.platform==="win32")return!1;let t="";try{t=B("ps",["-e","-o","pgid=,command="],{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:4e3})}catch{return!1}let r=String(e);for(let n of t.split(` | ||
| `)){let o=n.match(/^\s*(\d+)\s+(.*)$/);if(o&&o[1]===r&&/chrome|chromium|ms-playwright|playwright[\/\\]/i.test(o[2]))return!0}return!1}function At(e){if(process.platform==="win32")return null;let t="";try{t=B("ps",["-Ao","pid=,ppid=,pgid=,command="],{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:4e3})}catch{return null}for(let r of t.split(` | ||
| `)){let n=r.match(/^\s*(\d+)\s+(\d+)\s+(\d+)\s+(.*)$/);if(!n)continue;let[,o,s,c,u]=n;if(s===String(e)&&/chrome|chromium|ms-playwright/i.test(u)&&!/crashpad/i.test(u))return{pid:parseInt(o,10),pgid:parseInt(c,10)}}return null}function Ft(e,t){let r;try{r=de.readdirSync(e)}catch{return}for(let n of r){if(!/^daemon(-.+)?\.json$/.test(n))continue;let o=Ot.join(e,n),s;try{s=JSON.parse(de.readFileSync(o,"utf8"))}catch{continue}if(!(!s||s.pid===t)&&!Ue(s.pid)){try{let c=s.pgid||s.pid;!c||c<1||(process.platform==="win32"?s.browserPid&&B("taskkill",["/PID",String(s.browserPid),"/T","/F"],{stdio:"ignore",timeout:8e3}):X.exports.groupLooksLikeReflex(c)&&process.kill(-c,"SIGKILL"))}catch{}try{de.unlinkSync(o)}catch{}}}}function Pt(e){if(!e||e<2||process.platform==="win32")return!1;let t="";try{t=B("ps",["-p",String(e),"-o","command="],{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:4e3})}catch{return!1}return/reflex[\/\\]|reflex-browser|daemon\.js/i.test(t)}function Nt(e){if(e)try{if(process.platform==="win32"){if(e.browserPid)try{B("taskkill",["/PID",String(e.browserPid),"/T","/F"],{stdio:"ignore",timeout:8e3})}catch{}return}if(e.pid&&e.pid>1&&e.pid!==process.pid&&X.exports.daemonPidLooksLikeReflex(e.pid))try{process.kill(e.pid,"SIGKILL")}catch{}let t=e.pgid;if(t&&t>1&&t!==process.pid&&X.exports.groupLooksLikeReflex(t))try{process.kill(-t,"SIGKILL")}catch{}}catch{}}X.exports={isAlive:Ue,groupLooksLikeReflex:jt,daemonPidLooksLikeReflex:Pt,reapOrphans:Ft,reapState:Nt,findBrowserGroup:At}});var ze=D((ir,We)=>{"use strict";var Dt=require("http"),E=require("fs"),he=require("path"),Mt=require("os"),{spawn:qt}=require("child_process"),me=process.env.REFLEX_HOME||he.join(Mt.homedir(),".reflex"),z=e=>String(e||"default").replace(/[^a-zA-Z0-9_-]/g,"_").slice(0,40)||"default",Z=z(process.env.REFLEX_SESSION),U=e=>he.join(me,e==="default"?"daemon.json":`daemon-${e}.json`),Ct=U(Z),Ye=he.join(__dirname,"daemon.js");function ye(e){try{return JSON.parse(E.readFileSync(U(e?z(e):Z),"utf8"))}catch{return null}}function Je(e,t,r,n){return new Promise((o,s)=>{let c=JSON.stringify({cmd:t,args:r}),u={"x-reflex-token":e.token||""};n&&(u["x-reflex-caller"]=n);let l=Dt.request({host:"127.0.0.1",port:e.port,method:"POST",path:"/",timeout:12e4,headers:u},f=>{let p="";f.on("data",g=>p+=g),f.on("end",()=>{try{o(JSON.parse(p))}catch{s(new Error("bad daemon response"))}})});l.on("error",s),l.on("timeout",()=>{l.destroy(),s(new Error("daemon timeout"))}),l.end(c)})}var He=e=>new Promise(t=>setTimeout(t,e));async function W(e){let t=ye(e);if(t)try{return await Je(t,"ping",{}),t}catch{}return null}function Ge(e){try{let t=E.openSync(e,"wx");return E.writeSync(t,String(process.pid)),E.closeSync(t),!0}catch(t){if(t.code!=="EEXIST")return!1;try{if(Date.now()-E.statSync(e).mtimeMs>15e3)return E.unlinkSync(e),Ge(e)}catch{}return!1}}function $t(e){try{return E.statSync(e),!0}catch{return!1}}async function Xt(e,t){let r=e?z(e):Z,n=await W(r);if(n)return n;try{E.mkdirSync(me,{recursive:!0,mode:448})}catch{}let o=U(r).replace(/\.json$/,".lock");for(let s=0;s<2;s++){if(Ge(o))try{if(n=await W(r),n)return n;let c=ye(r);if(c)try{Ke().reapState(c)}catch{}try{E.unlinkSync(U(r))}catch{}let u=Object.assign({},process.env,t||{},{REFLEX_SESSION:r});qt(process.execPath,[Ye],{detached:!0,stdio:"ignore",windowsHide:!0,env:u}).unref();for(let f=0;f<100;f++)if(await He(100),n=await W(r),n)return n;throw new Error("daemon failed to start (check ~/.reflex/daemon.log)")}finally{try{E.unlinkSync(o)}catch{}}for(let c=0;c<100;c++){if(await He(100),n=await W(r),n)return n;if(!$t(o))break}}throw new Error("daemon failed to start (check ~/.reflex/daemon.log)")}function pe(e,t){if(typeof e=="string")return e.replace(/\{\{env:(\w+)\}\}/g,(r,n)=>process.env[n]===void 0?r:(t&&(t[n]=process.env[n]),process.env[n]));if(Array.isArray(e))return e.map(r=>pe(r,t));if(e&&typeof e=="object"){let r={};for(let n in e)r[n]=pe(e[n],t);return r}return e}We.exports={readState:ye,rpc:Je,ensureDaemon:Xt,subEnv:pe,sanitizeSession:z,stateFileFor:U,HOME:me,SESSION:Z,STATE_FILE:Ct,DAEMON:Ye}});var ge=D((ar,rt)=>{"use strict";var M=require("fs"),Bt=require("os"),Ze=require("path"),Ut=require("http"),Kt=require("crypto"),{spawn:Ht}=require("child_process"),{URL:Yt}=require("url"),Ve=process.env.REFLEX_SITE_BASE||"https://reflexmcp.com",Qe=process.env.REFLEX_API_BASE||"https://reflex.openlabs.workers.dev",Jt=18e4;function et(){return process.env.REFLEX_HOME||Ze.join(Bt.homedir(),".reflex")}function q(){return Ze.join(et(),"auth.json")}function Gt(){try{let e=M.readFileSync(q(),"utf8"),t=JSON.parse(e);return t&&typeof t.api_key=="string"?t.api_key:null}catch{return null}}function tt({api_key:e,key_id:t}){let r=et();M.mkdirSync(r,{recursive:!0});let n=q()+".tmp",o=JSON.stringify({v:1,api_key:e,key_id:t||null,saved_at:new Date().toISOString()});M.writeFileSync(n,o,{mode:384}),M.renameSync(n,q());try{M.chmodSync(q(),384)}catch{}}function Wt(){try{return M.unlinkSync(q()),!0}catch(e){if(e&&e.code==="ENOENT")return!1;throw e}}function nt(e){let t,r;process.platform==="darwin"?(t="open",r=[e]):process.platform==="win32"?(t="cmd",r=["/c","start","",e]):(t="xdg-open",r=[e]);try{let n=Ht(t,r,{detached:!0,stdio:"ignore"});return n.on("error",()=>{}),n.unref(),!0}catch{return!1}}function zt(e){e=e||{};let t=(e.siteBase||Ve).replace(/\/+$/,""),r=(e.apiBase||Qe).replace(/\/+$/,""),n=e.timeoutMs||Jt,o=Kt.randomBytes(24).toString("base64url");return new Promise((s,c)=>{let u=!1,l=null,f=(g,h)=>{if(!u){u=!0,l&&clearTimeout(l);try{p.close()}catch{}g(h)}},p=Ut.createServer((g,h)=>{let $;try{$=new Yt(g.url,"http://127.0.0.1")}catch{h.writeHead(400),h.end();return}if($.pathname!=="/callback"){h.writeHead(404),h.end("not found");return}let Xe=$.searchParams.get("state"),Be=$.searchParams.get("code"),ue=$.searchParams.get("error");if(ue){h.writeHead(200,{"content-type":"text/html"}),h.end(V("Login failed",String(ue).slice(0,200))),f(c,new Error("login failed: "+ue));return}if(!Xe||Xe!==o){h.writeHead(400,{"content-type":"text/html"}),h.end(V("Login error","Security check failed (state mismatch). Run reflex_auth login again.")),f(c,new Error("state mismatch"));return}if(!Be){h.writeHead(400,{"content-type":"text/html"}),h.end(V("Login error","No login code received. Run reflex_auth login again.")),f(c,new Error("no code"));return}h.writeHead(200,{"content-type":"text/html"}),h.end(V("You are signed in to Reflex","You can close this tab and return to your agent.")),Zt(r,Be).then(fe=>f(s,fe),fe=>f(c,fe))});p.on("error",g=>f(c,g)),p.listen(0,"127.0.0.1",()=>{let g=p.address().port,h=`${t}/cli-auth?port=${g}&state=${encodeURIComponent(o)}`;if(typeof e.onUrl=="function")try{e.onUrl(h)}catch{}e.open!==!1&&nt(h),l=setTimeout(()=>f(c,new Error("timed out waiting for browser login (3 min)")),n),l.unref&&l.unref()})})}async function Zt(e,t){let r;try{r=await fetch(e+"/v1/auth/cli-exchange",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({code:t})})}catch(o){throw new Error("could not reach the Reflex login server: "+(o&&o.message?o.message:o))}let n=null;try{n=await r.json()}catch{}if(!r.ok){let o=n&&n.error&&n.error.message?n.error.message:`login exchange failed (HTTP ${r.status})`;throw new Error(o)}if(!n||typeof n.api_key!="string")throw new Error("login exchange returned no key");return tt({api_key:n.api_key,key_id:n.key_id}),n}function V(e,t){return`<!doctype html><html><head><meta charset="utf-8"><title>${e}</title> | ||
| "use strict";var D=(e,t)=>()=>{try{return t||e((t={exports:{}}).exports,t),t.exports}catch(r){throw t=0,r}};var Je=D((ar,X)=>{"use strict";var de=require("fs"),Ot=require("path"),{execFileSync:B}=require("child_process");function Ye(e){if(!e||e<1)return!1;try{return process.kill(e,0),!0}catch(t){return t.code==="EPERM"}}function jt(e){if(process.platform==="win32")return!1;let t="";try{t=B("ps",["-e","-o","pgid=,command="],{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:4e3})}catch{return!1}let r=String(e);for(let n of t.split(` | ||
| `)){let o=n.match(/^\s*(\d+)\s+(.*)$/);if(o&&o[1]===r&&/chrome|chromium|ms-playwright|playwright[\/\\]/i.test(o[2]))return!0}return!1}function Ft(e){if(process.platform==="win32")return null;let t="";try{t=B("ps",["-Ao","pid=,ppid=,pgid=,command="],{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:4e3})}catch{return null}for(let r of t.split(` | ||
| `)){let n=r.match(/^\s*(\d+)\s+(\d+)\s+(\d+)\s+(.*)$/);if(!n)continue;let[,o,s,c,u]=n;if(s===String(e)&&/chrome|chromium|ms-playwright/i.test(u)&&!/crashpad/i.test(u))return{pid:parseInt(o,10),pgid:parseInt(c,10)}}return null}function Nt(e,t){let r;try{r=de.readdirSync(e)}catch{return}for(let n of r){if(!/^daemon(-.+)?\.json$/.test(n))continue;let o=Ot.join(e,n),s;try{s=JSON.parse(de.readFileSync(o,"utf8"))}catch{continue}if(!(!s||s.pid===t)&&!Ye(s.pid)){try{let c=s.pgid||s.pid;!c||c<1||(process.platform==="win32"?s.browserPid&&B("taskkill",["/PID",String(s.browserPid),"/T","/F"],{stdio:"ignore",timeout:8e3}):X.exports.groupLooksLikeReflex(c)&&process.kill(-c,"SIGKILL"))}catch{}try{de.unlinkSync(o)}catch{}}}}function Pt(e){if(!e||e<2||process.platform==="win32")return!1;let t="";try{t=B("ps",["-p",String(e),"-o","command="],{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:4e3})}catch{return!1}return/reflex[\/\\]|reflex-browser|daemon\.js/i.test(t)}function Dt(e){if(e)try{if(process.platform==="win32"){if(e.browserPid)try{B("taskkill",["/PID",String(e.browserPid),"/T","/F"],{stdio:"ignore",timeout:8e3})}catch{}return}if(e.pid&&e.pid>1&&e.pid!==process.pid&&X.exports.daemonPidLooksLikeReflex(e.pid))try{process.kill(e.pid,"SIGKILL")}catch{}let t=e.pgid;if(t&&t>1&&t!==process.pid&&X.exports.groupLooksLikeReflex(t))try{process.kill(-t,"SIGKILL")}catch{}}catch{}}X.exports={isAlive:Ye,groupLooksLikeReflex:jt,daemonPidLooksLikeReflex:Pt,reapOrphans:Nt,reapState:Dt,findBrowserGroup:Ft}});var Qe=D((cr,Ve)=>{"use strict";var Mt=require("http"),E=require("fs"),he=require("path"),qt=require("os"),{spawn:$t}=require("child_process"),me=process.env.REFLEX_HOME||he.join(qt.homedir(),".reflex"),z=e=>String(e||"default").replace(/[^a-zA-Z0-9_-]/g,"_").slice(0,40)||"default",Z=z(process.env.REFLEX_SESSION),U=e=>he.join(me,e==="default"?"daemon.json":`daemon-${e}.json`),Ct=U(Z),We=he.join(__dirname,"daemon.js");function ye(e){try{return JSON.parse(E.readFileSync(U(e?z(e):Z),"utf8"))}catch{return null}}function ze(e,t,r,n){return new Promise((o,s)=>{let c=JSON.stringify({cmd:t,args:r}),u={"x-reflex-token":e.token||""};n&&(u["x-reflex-caller"]=n);let f=Mt.request({host:"127.0.0.1",port:e.port,method:"POST",path:"/",timeout:12e4,headers:u},l=>{let p="";l.on("data",g=>p+=g),l.on("end",()=>{try{o(JSON.parse(p))}catch{s(new Error("bad daemon response"))}})});f.on("error",s),f.on("timeout",()=>{f.destroy(),s(new Error("daemon timeout"))}),f.end(c)})}var Ge=e=>new Promise(t=>setTimeout(t,e));async function W(e){let t=ye(e);if(t)try{return await ze(t,"ping",{}),t}catch{}return null}function Ze(e){try{let t=E.openSync(e,"wx");return E.writeSync(t,String(process.pid)),E.closeSync(t),!0}catch(t){if(t.code!=="EEXIST")return!1;try{if(Date.now()-E.statSync(e).mtimeMs>15e3)return E.unlinkSync(e),Ze(e)}catch{}return!1}}function Xt(e){try{return E.statSync(e),!0}catch{return!1}}async function Bt(e,t){let r=e?z(e):Z,n=await W(r);if(n)return n;try{E.mkdirSync(me,{recursive:!0,mode:448})}catch{}let o=U(r).replace(/\.json$/,".lock");for(let s=0;s<2;s++){if(Ze(o))try{if(n=await W(r),n)return n;let c=ye(r);if(c)try{Je().reapState(c)}catch{}try{E.unlinkSync(U(r))}catch{}let u=Object.assign({},process.env,t||{},{REFLEX_SESSION:r});$t(process.execPath,[We],{detached:!0,stdio:"ignore",windowsHide:!0,env:u}).unref();for(let l=0;l<100;l++)if(await Ge(100),n=await W(r),n)return n;throw new Error("daemon failed to start (check ~/.reflex/daemon.log)")}finally{try{E.unlinkSync(o)}catch{}}for(let c=0;c<100;c++){if(await Ge(100),n=await W(r),n)return n;if(!Xt(o))break}}throw new Error("daemon failed to start (check ~/.reflex/daemon.log)")}function pe(e,t){if(typeof e=="string")return e.replace(/\{\{env:(\w+)\}\}/g,(r,n)=>process.env[n]===void 0?r:(t&&(t[n]=process.env[n]),process.env[n]));if(Array.isArray(e))return e.map(r=>pe(r,t));if(e&&typeof e=="object"){let r={};for(let n in e)r[n]=pe(e[n],t);return r}return e}Ve.exports={readState:ye,rpc:ze,ensureDaemon:Bt,subEnv:pe,sanitizeSession:z,stateFileFor:U,HOME:me,SESSION:Z,STATE_FILE:Ct,DAEMON:We}});var ge=D((lr,it)=>{"use strict";var M=require("fs"),Ut=require("os"),et=require("path"),Kt=require("http"),Ht=require("crypto"),{spawn:Yt}=require("child_process"),{URL:Jt}=require("url"),tt=process.env.REFLEX_SITE_BASE||"https://reflexmcp.com",nt=process.env.REFLEX_API_BASE||"https://reflex.openlabs.workers.dev",Gt=18e4;function rt(){return process.env.REFLEX_HOME||et.join(Ut.homedir(),".reflex")}function q(){return et.join(rt(),"auth.json")}function Wt(){try{let e=M.readFileSync(q(),"utf8"),t=JSON.parse(e);return t&&typeof t.api_key=="string"?t.api_key:null}catch{return null}}function ot({api_key:e,key_id:t}){let r=rt();M.mkdirSync(r,{recursive:!0});let n=q()+".tmp",o=JSON.stringify({v:1,api_key:e,key_id:t||null,saved_at:new Date().toISOString()});M.writeFileSync(n,o,{mode:384}),M.renameSync(n,q());try{M.chmodSync(q(),384)}catch{}}function zt(){try{return M.unlinkSync(q()),!0}catch(e){if(e&&e.code==="ENOENT")return!1;throw e}}function st(e){let t,r;process.platform==="darwin"?(t="open",r=[e]):process.platform==="win32"?(t="cmd",r=["/c","start","",e]):(t="xdg-open",r=[e]);try{let n=Yt(t,r,{detached:!0,stdio:"ignore"});return n.on("error",()=>{}),n.unref(),!0}catch{return!1}}function Zt(e){e=e||{};let t=(e.siteBase||tt).replace(/\/+$/,""),r=(e.apiBase||nt).replace(/\/+$/,""),n=e.timeoutMs||Gt,o=Ht.randomBytes(24).toString("base64url");return new Promise((s,c)=>{let u=!1,f=null,l=(g,h)=>{if(!u){u=!0,f&&clearTimeout(f);try{p.close()}catch{}g(h)}},p=Kt.createServer((g,h)=>{let C;try{C=new Jt(g.url,"http://127.0.0.1")}catch{h.writeHead(400),h.end();return}if(C.pathname!=="/callback"){h.writeHead(404),h.end("not found");return}let Ke=C.searchParams.get("state"),He=C.searchParams.get("code"),ue=C.searchParams.get("error");if(ue){h.writeHead(200,{"content-type":"text/html"}),h.end(V("Login failed",String(ue).slice(0,200))),l(c,new Error("login failed: "+ue));return}if(!Ke||Ke!==o){h.writeHead(400,{"content-type":"text/html"}),h.end(V("Login error","Security check failed (state mismatch). Run reflex_auth login again.")),l(c,new Error("state mismatch"));return}if(!He){h.writeHead(400,{"content-type":"text/html"}),h.end(V("Login error","No login code received. Run reflex_auth login again.")),l(c,new Error("no code"));return}h.writeHead(200,{"content-type":"text/html"}),h.end(V("You are signed in to Reflex","You can close this tab and return to your agent.")),Vt(r,He).then(fe=>l(s,fe),fe=>l(c,fe))});p.on("error",g=>l(c,g)),p.listen(0,"127.0.0.1",()=>{let g=p.address().port,h=`${t}/cli-auth?port=${g}&state=${encodeURIComponent(o)}`;if(typeof e.onUrl=="function")try{e.onUrl(h)}catch{}e.open!==!1&&st(h),f=setTimeout(()=>l(c,new Error("timed out waiting for browser login (3 min)")),n),f.unref&&f.unref()})})}async function Vt(e,t){let r;try{r=await fetch(e+"/v1/auth/cli-exchange",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({code:t})})}catch(o){throw new Error("could not reach the Reflex login server: "+(o&&o.message?o.message:o))}let n=null;try{n=await r.json()}catch{}if(!r.ok){let o=n&&n.error&&n.error.message?n.error.message:`login exchange failed (HTTP ${r.status})`;throw new Error(o)}if(!n||typeof n.api_key!="string")throw new Error("login exchange returned no key");return ot({api_key:n.api_key,key_id:n.key_id}),n}function V(e,t){return`<!doctype html><html><head><meta charset="utf-8"><title>${e}</title> | ||
| <style>html{color-scheme:dark}body{margin:0;display:grid;place-items:center;min-height:100vh; | ||
@@ -8,3 +8,3 @@ background:#0a1410;color:#e6f2ec;font:16px/1.5 system-ui,sans-serif} | ||
| .s{margin-top:.5rem;color:#9fb3a8}</style></head> | ||
| <body><div class="c"><div class="t">${e}</div><div class="s">${t}</div></div></body></html>`}rt.exports={login:zt,logout:Wt,loadKey:Gt,saveKey:tt,openBrowser:nt,SITE_BASE:Ve,API_BASE:Qe,_authFile:q}});var _e=D((cr,Vt)=>{Vt.exports={name:"reflex-browser",version:"0.10.0",mcpName:"com.reflexmcp/reflex",description:"Token-efficient browser automation for AI agents. Local MCP server + CLI: compressed page snapshots, batched actions, forensic failures.",license:"SEE LICENSE IN LICENSE",bin:{reflex:"./dist/reflex.js","reflex-browser":"./dist/reflex-browser.js"},files:["dist","README.md","LICENSE"],scripts:{bench:"node bench/run.js","bench:h2h":"node bench/h2h-run.js",smoke:"node test/smoke.js","test:engine":"node test/engine.js","test:tenx":"node test/tenx.js","test:mcp":"node test/mcp.js","test:profile":"node test/profile.js","test:memory":"node test/memory.js",test:"node test/profile.js && node test/smoke.js && node test/engine.js && node test/tenx.js && node test/mcp.js && node test/credits.js && node test/memory.js && node test/teardown.js && node test/hygiene.js && node test/parallel.js && node test/concurrency.js","test:parallel":"node test/parallel.js","test:concurrency":"node test/concurrency.js",check:"npm run check:all","check:all":"mkdir -p checks-outputs && npm run check:root && npm run check:server && npm run check:web","check:root":"bash -c 'set -o pipefail; node bin/reflex.js stop 2>/dev/null || true; npm test 2>&1 | tee checks-outputs/root-test.txt'","check:server":"bash -c 'set -o pipefail; cd server && npm test 2>&1 | tee ../checks-outputs/server-test.txt && npm run typecheck 2>&1 | tee ../checks-outputs/server-type.txt'","check:web":"bash -c 'set -o pipefail; cd web && npm run typecheck 2>&1 | tee ../checks-outputs/web-type.txt && rm -rf .next && npm run build 2>&1 | tee ../checks-outputs/web-build.txt'",build:"node scripts/build-dist.mjs",prepack:"npm run build","test:dist":"npm run build && REFLEX_TEST_CLI=dist/reflex.js REFLEX_TEST_BIN=dist/reflex-browser.js npm test"},dependencies:{"@modelcontextprotocol/sdk":"^1.29.0","playwright-core":"^1.50.0"},homepage:"https://reflexmcp.com",repository:{type:"git",url:"git+https://github.com/nitaiaharoni1/reflex-browser.git"},keywords:["mcp","browser-automation","playwright","claude-desktop","cursor","ai-agent","model-context-protocol"],devDependencies:{esbuild:"^0.28.1"}}});var wt=D((lr,_t)=>{"use strict";var d=require("fs"),Qt=require("os"),A=require("path"),H=require("crypto"),en=ge(),ke=process.env.REFLEX_API_BASE||"https://reflex.openlabs.workers.dev";function T(){return process.env.REFLEX_HOME||A.join(Qt.homedir(),".reflex")}function te(){return A.join(T(),"credits.json")}function ne(e){return A.join(T(),`usage-${e||process.pid}.json`)}function at(){return A.join(T(),"credits.lock")}function we(){return A.join(T(),"device.json")}var be=/^rfx_(live|test)_[A-Za-z0-9]{32}$/,Se=25,tn="rfx_trial_loc";function nn(){return process.env.REFLEX_TRIAL!=="off"&&process.env.REFLEX_TRIAL!=="0"}var rn={k1:process.env.REFLEX_PUBKEY_K1||"cU8LzUpIjro9cQo/A4o7BaOJ6QcDKloN6hffQISY28o="},on=3,sn=3e4,an=250,Ee=6e4,cn=1e3,ln=100,un=10,fn=6e5,ct=3e5,Re=3e3,dn=5e3,pn=2e3,hn=3e5,mn=250,yn=5e3,Le=(()=>{try{return _e().version}catch{return"0.0.0"}})(),w={noKey:'Reflex is not signed in, so this call was not run and was not charged. Please tell the user to sign in: run the reflex_auth tool with {"action":"login"} and it will open their browser to sign in (free, 30 starter credits at https://reflexmcp.com). Then retry this call. (CI/headless: set REFLEX_API_KEY in the MCP client config instead.)',badKey:"This Reflex API key is invalid or has been revoked. Check your key at https://reflexmcp.com/dashboard or generate a new one, then update REFLEX_API_KEY and restart.",outOfCredits:`Reflex is out of credits, so this call was not run and was not charged. Your | ||
| <body><div class="c"><div class="t">${e}</div><div class="s">${t}</div></div></body></html>`}it.exports={login:Zt,logout:zt,loadKey:Wt,saveKey:ot,openBrowser:st,SITE_BASE:tt,API_BASE:nt,_authFile:q}});var _e=D((ur,Qt)=>{Qt.exports={name:"reflex-browser",version:"0.11.0",mcpName:"com.reflexmcp/reflex",description:"Token-efficient browser automation for AI agents. Local MCP server + CLI: compressed page snapshots, batched actions, forensic failures.",license:"SEE LICENSE IN LICENSE",bin:{reflex:"./dist/reflex.js","reflex-browser":"./dist/reflex-browser.js"},files:["dist","README.md","LICENSE"],scripts:{bench:"node bench/run.js","bench:h2h":"node bench/h2h-run.js",smoke:"node test/smoke.js","test:engine":"node test/engine.js","test:tenx":"node test/tenx.js","test:mcp":"node test/mcp.js","test:profile":"node test/profile.js","test:memory":"node test/memory.js",test:"node test/profile.js && node test/smoke.js && node test/engine.js && node test/tenx.js && node test/mcp.js && node test/credits.js && node test/trial.js && node test/memory.js && node test/teardown.js && node test/hygiene.js && node test/parallel.js && node test/concurrency.js","test:parallel":"node test/parallel.js","test:concurrency":"node test/concurrency.js",check:"npm run check:all","check:all":"mkdir -p checks-outputs && npm run check:root && npm run check:server && npm run check:web","check:root":"bash -c 'set -o pipefail; node bin/reflex.js stop 2>/dev/null || true; npm test 2>&1 | tee checks-outputs/root-test.txt'","check:server":"bash -c 'set -o pipefail; cd server && npm test 2>&1 | tee ../checks-outputs/server-test.txt && npm run typecheck 2>&1 | tee ../checks-outputs/server-type.txt'","check:web":"bash -c 'set -o pipefail; cd web && npm run typecheck 2>&1 | tee ../checks-outputs/web-type.txt && rm -rf .next && npm run build 2>&1 | tee ../checks-outputs/web-build.txt'",build:"node scripts/build-dist.mjs",prepack:"npm run build","test:dist":"npm run build && REFLEX_TEST_CLI=dist/reflex.js REFLEX_TEST_BIN=dist/reflex-browser.js npm test"},dependencies:{"@modelcontextprotocol/sdk":"^1.29.0","playwright-core":"^1.50.0"},homepage:"https://reflexmcp.com",repository:{type:"git",url:"git+https://github.com/nitaiaharoni1/reflex-browser.git"},keywords:["mcp","browser-automation","playwright","claude-desktop","cursor","ai-agent","model-context-protocol"],devDependencies:{esbuild:"^0.28.1"}}});var vt=D((fr,xt)=>{"use strict";var d=require("fs"),en=require("os"),j=require("path"),H=require("crypto"),tn=ge(),ke=process.env.REFLEX_API_BASE||"https://reflex.openlabs.workers.dev";function T(){return process.env.REFLEX_HOME||j.join(en.homedir(),".reflex")}function te(){return j.join(T(),"credits.json")}function ne(e){return j.join(T(),`usage-${e||process.pid}.json`)}function ut(){return j.join(T(),"credits.lock")}function we(){return j.join(T(),"device.json")}var be=/^rfx_(live|test)_[A-Za-z0-9]{32}$/,Se=25,nn="rfx_trial_loc";function rn(){return process.env.REFLEX_TRIAL!=="off"&&process.env.REFLEX_TRIAL!=="0"}var on={k1:process.env.REFLEX_PUBKEY_K1||"cU8LzUpIjro9cQo/A4o7BaOJ6QcDKloN6hffQISY28o="},sn=3,an=3e4,cn=250,Ee=6e4,ln=1e3,un=100,fn=10,dn=6e5,ft=3e5,Re=3e3,pn=5e3,hn=2e3,mn=3e5,yn=250,gn=5e3,Le=(()=>{try{return _e().version}catch{return"0.0.0"}})(),w={noKey:'Reflex is not signed in, so this call was not run and was not charged. Please tell the user to sign in: run the reflex_auth tool with {"action":"login"} and it will open their browser to sign in (free, 30 starter credits at https://reflexmcp.com). Then retry this call. (CI/headless: set REFLEX_API_KEY in the MCP client config instead.)',badKey:"This Reflex API key is invalid or has been revoked. Check your key at https://reflexmcp.com/dashboard or generate a new one, then update REFLEX_API_KEY and restart.",outOfCredits:`Reflex is out of credits, so this call was not run and was not charged. Your | ||
| browser, open tabs, and login sessions are untouched. Please tell the user: | ||
@@ -20,6 +20,7 @@ top up at https://reflexmcp.com/pricing (150 credits for $9, 500 for $19), and | ||
| and adds 30 more credits), or buy a pack from https://reflexmcp.com/pricing | ||
| (150 credits for $9). Then simply retry this call.`};function gn(e){return`[reflex: ${e} credits left. Top up: https://reflexmcp.com/pricing]`}var m=null,_=null,a=null,i=null,re=!1,y=null,R=null,Q=!1,K=!1,j=0,Y=0,xe=0,ve=0,I=!1,F=!1,v=!1,x=null,ee=!1;function ot(e){return Buffer.from(e.replace(/-/g,"+").replace(/_/g,"/"),"base64")}function _n(e,t){return{v:2,key_id:e||null,key_prefix:t||null,token:null,balance:0,free_expires_at:null,last_sync_at:null,max_token_iat:0,last_wall_clock:new Date().toISOString()}}function wn(e){return{v:1,pid:process.pid,key_prefix:e||null,buffer:[],overflow:{calls:0,from:null,to:null},pending_batch:null}}function lt(e){return e?e.slice(0,13):null}function ut(){try{let e=JSON.parse(d.readFileSync(te(),"utf8"));if(e&&(e.v===1||e.v===2))return e}catch{}return null}function bn(){try{let e=JSON.parse(d.readFileSync(ne(),"utf8"));if(e&&e.v===1&&Array.isArray(e.buffer))return e}catch{}return null}function Ie(){d.existsSync(T())||d.mkdirSync(T(),{recursive:!0})}function ft(){try{let e=JSON.parse(d.readFileSync(we(),"utf8"));if(e&&e.v===1&&typeof e.device_id=="string")return e}catch{}return null}function dt(e){try{Ie();let t=we()+".tmp";return d.writeFileSync(t,JSON.stringify(e),{mode:384}),d.renameSync(t,we()),!0}catch{return!1}}function xn(){let e=ft();if(e)return e;let t={v:1,device_id:H.randomUUID(),trial_key:null,claimed_at:null};return dt(t)?t:null}async function vn(){if(ee||!x||!v)return!1;ee=!0;try{let e=new AbortController,t=setTimeout(()=>e.abort(),Re),r;try{r=await fetch(ke+"/v1/trial/claim",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({device_id:x.device_id,client_version:Le}),signal:e.signal})}finally{clearTimeout(t)}if(r.status===429)return _={reason:"no_key",message:w.noKey},v=!1,!1;let n=await r.json().catch(()=>null);if(!r.ok||!n||!be.test(n.api_key||""))return!1;m=n.api_key;let o=lt(m);return a.key_prefix=o,i.key_prefix=o,typeof n.balance=="number"&&(a.balance=Math.max(0,n.balance-i.buffer.length)),v=!1,x.trial_key=m,x.claimed_at=new Date().toISOString(),dt(x),P(),await J(),!0}catch{return!1}finally{ee=!1}}async function kn(e){let t=ft();if(!(!t||!e))try{let r=new AbortController,n=setTimeout(()=>r.abort(),Re);try{await fetch(ke+"/v1/trial/convert",{method:"POST",headers:{authorization:`Bearer ${e}`,"content-type":"application/json"},body:JSON.stringify({device_id:t.device_id}),signal:r.signal})}finally{clearTimeout(n)}}catch{}}function st(e,t){let r=e?Date.parse(e):NaN,n=t?Date.parse(t):NaN;return Number.isNaN(r)?!1:Number.isNaN(n)?!0:r>n}function Sn(){let e=at(),t=Date.now()+mn;for(;;)try{return d.mkdirSync(e),!0}catch{try{let n=d.statSync(e);if(Date.now()-n.mtimeMs>yn){d.rmdirSync(e);continue}}catch{}if(Date.now()>=t)return!1;let r=Math.min(Date.now()+10,t);for(;Date.now()<r;);}}function En(){try{d.rmdirSync(at())}catch{}}function Te(){if(!a)return;let e=ut();if(!(!e||e.v!==2||e.key_prefix!==a.key_prefix)){if((e.max_token_iat||0)>(a.max_token_iat||0)&&e.token&&(a.token=e.token,a.max_token_iat=e.max_token_iat,a.free_expires_at=e.free_expires_at||a.free_expires_at),st(e.last_sync_at,a.last_sync_at)){let t=i?i.buffer.length:0;a.balance=(e.balance||0)-t,a.last_sync_at=e.last_sync_at}st(e.last_wall_clock,a.last_wall_clock)&&(a.last_wall_clock=e.last_wall_clock),a.key_id=a.key_id||e.key_id}}function Rn(){if(a)try{Ie();let e=Sn();try{Te();let t=te()+".tmp."+process.pid;d.writeFileSync(t,JSON.stringify(a),{mode:384}),d.renameSync(t,te())}finally{e&&En()}}catch{}}function Oe(){if(!i)return!1;try{Ie();let e=ne()+".tmp";return d.writeFileSync(e,JSON.stringify(i),{mode:384}),d.renameSync(e,ne()),!0}catch{return!1}}function P(){Oe(),Rn(),re=!1}function N(){re=!0,!y&&(y=setTimeout(()=>{y=null,re&&P()},an),y.unref&&y.unref())}function se(e){if(typeof e!="string")return null;let t=e.split(".");if(t.length!==3||t[0]!=="RFX1")return null;let[,r,n]=t,o;try{o=JSON.parse(ot(r).toString("utf8"))}catch{return null}let s=rn[o.kid];if(!s||s.startsWith("REPLACE_"))return null;let c;try{c=H.createPublicKey({key:Buffer.concat([Buffer.from("302a300506032b6570032100","hex"),Buffer.from(s,"base64")]),format:"der",type:"spki"})}catch{return null}let u=Buffer.from("RFX1."+r,"ascii"),l=!1;try{l=H.verify(null,u,c,ot(n))}catch{return null}return l?o:null}function pt(e,t,r,n){a.token=e,a.max_token_iat=Math.max(a.max_token_iat||0,t.iat||0),a.balance=r-(n||0),a.free_expires_at=t.fxp?new Date(t.fxp*1e3).toISOString():null,a.last_sync_at=new Date().toISOString(),N()}function C(){if(!a||!a.token)return!1;let e=se(a.token);if(!e||(e.iat||0)<(a.max_token_iat||0))return!1;let t=Math.floor(Date.now()/1e3);return!(e.exp<=t-ct/1e3)}async function ht(e,t,r,n){let o=new AbortController,s=setTimeout(()=>o.abort(),n);try{let c=await fetch(ke+t,{method:e,headers:{authorization:`Bearer ${m}`,"content-type":"application/json"},body:r?JSON.stringify(r):void 0,signal:o.signal}),u=null;try{u=await c.json()}catch{}return{status:c.status,json:u}}finally{clearTimeout(s)}}async function J(){let{status:e,json:t}=await ht("POST","/v1/validate",{client_version:Le},Re);if(e===401||e===403){_={reason:e===403?"key_revoked":"bad_key",message:w.badKey};try{d.unlinkSync(te())}catch{}return!1}if(e===200&&t&&t.ok&&t.token){let r=se(t.token);if(r&&(r.iat||0)>=(a.max_token_iat||0))return _=null,a.key_id=t.key_id||a.key_id,pt(t.token,r,t.balance,i.buffer.length),!0}return!1}function Ln(){if(i.pending_batch)return i.pending_batch;if(i.buffer.length===0&&i.overflow.calls===0)return null;let e=i.buffer.slice(),t={},r=null,n=null,o=0,s=0,c=0,u={};for(let p of e){if(t[p.tool]=(t[p.tool]||0)+1,p.ok===!0)o++;else if(p.ok===!1){let g=p.cat||"other";s++,u[g]=(u[g]||0)+1}Number.isFinite(p.resp_chars)&&(c+=p.resp_chars),(!r||p.ts<r)&&(r=p.ts),(!n||p.ts>n)&&(n=p.ts)}let l=new Date().toISOString(),f={batch_id:H.randomUUID(),calls:e.length,tools:t,ok:o,fail:s,overflow_calls:i.overflow.calls,period_start:r||i.overflow.from||l,period_end:n||i.overflow.to||l,client_balance:a.balance,hit_zero:!!i._hitZeroPending,client_version:Le,_event_ids:e.map(p=>p.id)};return Object.keys(u).length&&(f.fail_cats=u),c>0&&(f.resp_chars=c),f.calls===0&&f.overflow_calls===0?null:f}async function je(){if(K||!a||!i||!C()&&!i.pending_batch)return;let e=Ln();if(!e)return;K=!0,i.pending_batch=e,Oe();let{_event_ids:t,...r}=e,n=null;try{n=await ht("POST","/v1/usage",r,dn)}catch{n=null}if(n&&n.status===200&&n.json&&n.json.ok&&n.json.token){let o=se(n.json.token);if(o&&(o.iat||0)>=(a.max_token_iat||0)){let s=new Set(t),c=i.buffer.filter(l=>!s.has(l.id)),u=c.length;i.buffer=c,i.overflow={calls:0,from:null,to:null},i._hitZeroPending=!1,i.pending_batch=null,pt(n.json.token,o,n.json.balance,u),j=0,Y=0,K=!1;return}}n&&(n.status===401||n.status===403)&&(_={reason:n.status===403?"key_revoked":"bad_key",message:w.badKey},i.pending_batch=null),j=j?Math.min(j*2,hn):Ee,Y=Date.now()+j,K=!1,N()}function In(e){try{return process.kill(e,0),!0}catch(t){return t&&t.code!=="ESRCH"}}function mt(){if(!i)return;let e;try{e=d.readdirSync(T())}catch{return}for(let t of e){let r=/^usage-(\d+)\.json$/.exec(t);if(!r)continue;let n=Number(r[1]);if(n===process.pid||In(n))continue;let o=A.join(T(),t),s=null;try{s=JSON.parse(d.readFileSync(o,"utf8"))}catch{continue}if(!s||s.v!==1||!Array.isArray(s.buffer)||s.key_prefix&&i.key_prefix&&s.key_prefix!==i.key_prefix)continue;let c=A.join(T(),`usage-${n}.claimed-${process.pid}.json`);try{d.renameSync(o,c)}catch{continue}try{let u=JSON.parse(d.readFileSync(c,"utf8"));if(u&&Array.isArray(u.buffer)){if(i.buffer=i.buffer.concat(u.buffer),u.overflow&&u.overflow.calls){i.overflow.calls+=u.overflow.calls;let{from:l,to:f}=u.overflow;l&&(!i.overflow.from||l<i.overflow.from)&&(i.overflow.from=l),f&&(!i.overflow.to||f>i.overflow.to)&&(i.overflow.to=f)}u.pending_batch&&(i.pending_batch||(i.pending_batch=u.pending_batch)),u._hitZeroPending&&(i._hitZeroPending=!0)}Oe()&&d.unlinkSync(c)}catch{}}}async function oe(){if(!Q&&!(Date.now()<Y)&&!(!I||!a||!i)){Q=!0;try{if(v&&!await vn()||(C()?a.balance<=0&&Date.now()-xe>=Ee&&(xe=Date.now(),await J()):await J(),_))return;mt(),await je(),Te()}catch{}finally{Q=!1}}}function Tn(){if(!I)return;let e=i.buffer.length,t=e>=on;if(!t&&e>0){let r=new Date(i.buffer[0].ts).getTime();Date.now()-r>=sn&&(t=!0)}t&&setImmediate(oe)}function yt(){m=null,_=null,a=null,i=null,I=!1,re=!1,y&&clearTimeout(y),R&&clearInterval(R),y=null,R=null,Q=!1,K=!1,j=0,Y=0,xe=0,ve=0,F=!1,v=!1,x=null,ee=!1}async function gt(e){if(I)return;if(e=e||{},m=e.apiKey||process.env.REFLEX_API_KEY||en.loadKey()||null,!m&&nn()&&(x=xn(),x&&be.test(x.trial_key||"")?(m=x.trial_key,F=!0):x&&(F=!0,v=!0)),!m&&!v){_={reason:"no_key",message:w.noKey},I=!0;return}if(m&&!be.test(m)){_={reason:"no_key",message:w.noKey},I=!0;return}let t=v?tn:lt(m),r=bn();i=r&&r.key_prefix===t?r:wn(t);let n=ut(),o=!1;n&&n.key_prefix&&n.key_prefix===t?n.v===1&&Array.isArray(n.buffer)?(i.buffer=i.buffer.concat(n.buffer),n.overflow&&n.overflow.calls&&(i.overflow.calls+=n.overflow.calls,n.overflow.from&&(i.overflow.from=i.overflow.from||n.overflow.from),n.overflow.to&&(i.overflow.to=n.overflow.to)),n.pending_batch&&!i.pending_batch&&(i.pending_batch=n.pending_batch),n._hitZeroPending&&(i._hitZeroPending=!0),a={v:2,key_id:n.key_id||null,key_prefix:n.key_prefix,token:n.token||null,balance:n.balance||0,free_expires_at:n.free_expires_at||null,last_sync_at:n.last_sync_at||null,max_token_iat:n.max_token_iat||0,last_wall_clock:n.last_wall_clock||new Date().toISOString()},o=!0):a=n:(a=_n(null,t),v&&(a.balance=Se,P())),I=!0,o&&P(),R||(R=setInterval(oe,Ee),R.unref&&R.unref()),setImmediate(()=>{oe()})}function On(){let e=Date.now(),t=a&&a.last_wall_clock?new Date(a.last_wall_clock).getTime():0;return!(t&&e<t-ct)}function jn(e){if(_)return{ok:!1,reason:_.reason,message:_.message};if(!a||!i)return{ok:!1,reason:"no_key",message:w.noKey};if(!v&&!On()&&!C())return{ok:!1,reason:"offline_grace_expired",message:it()};if(!v&&!C())return{ok:!1,reason:"offline_grace_expired",message:a.token?it():w.graceExpiredFirstRun};if(a.balance<=0)return i._hitZeroPending=!0,N(),setImmediate(oe),F?{ok:!1,reason:"trial_exhausted",message:w.trialExhausted}:{ok:!1,reason:"out_of_credits",message:a.free_expires_at&&new Date(a.free_expires_at).getTime()<=Date.now()?w.outOfCreditsExpired:w.outOfCredits};a.balance-=1;let t={id:H.randomUUID(),tool:e,ts:new Date().toISOString()};if(i.buffer.push(t),a.last_wall_clock=t.ts,i.buffer.length>cn){let n=i.buffer.splice(0,ln);i.overflow.calls+=n.length;let o=n[0].ts,s=n[n.length-1].ts;(!i.overflow.from||o<i.overflow.from)&&(i.overflow.from=o),(!i.overflow.to||s>i.overflow.to)&&(i.overflow.to=s)}N();let r;if(a.balance<=un){let n=Date.now();n-ve>=fn&&(ve=n,r=gn(a.balance))}return Tn(),{ok:!0,warn:r,id:t.id}}function An(e,t,r,n){if(!i||!e)return;let o=i.buffer.find(s=>s.id===e);o&&(o.ok=!!t,!t&&r&&(o.cat=String(r).slice(0,24)),Number.isFinite(n)&&n>=0&&(o.resp_chars=Math.floor(n)),N())}function Fn(e){if(!a||!i||!e)return;let t=i.buffer.findIndex(r=>r.id===e);if(t>=0&&!(i.pending_batch&&Array.isArray(i.pending_batch._event_ids)&&i.pending_batch._event_ids.includes(e))){i.buffer.splice(t,1),a.balance+=1,N();return}a.balance+=1,N()}function Pn(){return{balance:a?a.balance:0,keyTail:m?m.slice(-4):null,trial:F,trialGrant:Se}}function it(){return w.graceExpired}async function Nn(){if(y&&(clearTimeout(y),y=null),P(),R&&(clearInterval(R),R=null),!(!I||_||!a||!i)){if(i.buffer.length===0&&!i.pending_batch&&i.overflow.calls===0){try{d.unlinkSync(ne())}catch{}return}await Promise.race([(async()=>{try{C()||await J(),await je()}catch{}})(),new Promise(e=>{let t=setTimeout(e,pn);t.unref&&t.unref()})]),P()}}async function Dn(e){let t=F;yt(),await gt(e),t&&!F&&m&&kn(m).catch(()=>{})}_t.exports={init:gt,reinit:Dn,spend:jn,refund:Fn,recordOutcome:An,status:Pn,shutdown:Nn,_MSG:w,_TRIAL_GRANT:Se,_verifyToken:se,_persistNow(){y&&(clearTimeout(y),y=null),P()},async _syncOnce(){j=0,Y=0;try{if(!I||!a||!i||(C()||await J(),_))return;mt(),await je(),Te()}catch{}},_reset:yt}});var xt=D((ur,bt)=>{"use strict";function Mn(e){let t=String(e||"").split(/\n(?:url:|changes before failure:|screenshot:)/)[0];return/needs a target|provide (?:ms|a)|must be a|bad step|non-empty|file not found on disk|invalid (?:css|xpath) selector/i.test(t)?"baduse":/expect failed/i.test(t)?"assertion":/ambiguous|candidates:|near miss|no (?:exact )?match|no element|not found|could not (?:find|resolve)|couldn'?t resolve|(?:target|ref) not (?:resolved|found)/i.test(t)?"resolution":/disconnected|browser (?:restarted|disconnected)|page state was lost|net::|ERR_|navigation/i.test(t)?"navigation":/intercepts pointer events|not clickable|is hidden|resolved but not visible|outside of the viewport|element is not|not actionable|not stable/i.test(t)?"interaction":/expect|expected|assertion|still (?:visible|present)|not visible/i.test(t)?"assertion":/timed out|timeout|time limit|exceeded.*s/i.test(t)?"timeout":"other"}bt.exports={classifyFailure:Mn}});var Me=require("fs"),{Server:qn}=require("@modelcontextprotocol/sdk/server/index.js"),{StdioServerTransport:Cn}=require("@modelcontextprotocol/sdk/server/stdio.js"),{ListToolsRequestSchema:$n,CallToolRequestSchema:Xn}=require("@modelcontextprotocol/sdk/types.js"),{readState:G,rpc:O,ensureDaemon:Pe,subEnv:Bn,sanitizeSession:St,SESSION:S,HOME:Un}=ze(),vt=ge(),Ne=_e(),L=`mcp-${process.pid}`,Ae=e=>new Promise(t=>setTimeout(t,e)),b;try{b=wt()}catch{b={init:async()=>{},spend:()=>({ok:!0}),refund:()=>{},recordOutcome:()=>{},status:()=>({}),shutdown:async()=>{},_MSG:{}}}process.env.REFLEX_RAISE===void 0&&(process.env.REFLEX_RAISE="0");var qe=[{name:"reflex_open",description:"Open a URL in the local Chrome and return a distilled snapshot with element refs like [a3f2]. new_tab opens in a new tab, keeping the current one open.",inputSchema:{type:"object",properties:{url:{type:"string"},new_tab:{type:"boolean",description:"open in a new tab, keeping existing tabs open"},state:{type:"string",description:"saved auth state to load (via reflex_flow state_save)"},headed:{type:"boolean",description:"show the browser window (default true; false = headless)"},session:{type:"string",description:"isolated parallel browser; same name on every call that uses it"}},required:["url"]}},{name:"reflex_act",description:'Run a batch of browser steps in one call; stops at the first failure with a forensic report (reason, near-miss candidates, console/network errors, pre-failure page changes). Success returns only what changed, not the full page. A batch may start cold with {"goto":url}, which opens the browser too, so a flow whose targets you can already name needs no reflex_open.',inputSchema:{type:"object",properties:{steps:{type:"array",items:{type:"object"},description:'Each step is one object: {"goto":url} {"click":t} {"dblclick":t} {"hover":t} {"focus":t} {"fill":[t,value]} {"type":[t,text]} {"press":key} {"select":[t,option]} {"upload":[t,path]} {"check":t} {"uncheck":t} {"scroll":{"by":px}} {"scroll":{"to":t}} {"wait":ms} {"wait":{"text":s}} {"wait":{"url_contains":s}} {"expect":{"visible":t | "hidden":t | "text":s | "url_contains":s | "value":v,"target":t | "download":"*.pdf"}} {"shot":label} {"eval":js}. Target t: ref (a3f2), accessible name, or css=/xpath=. Secrets: {{env:VAR}}. Use expect guards between actions. Downloads auto-save (path in response). Compounds: {"if":{"visible":t,"then":[],"else":[]}} {"try":[steps]} {"repeat":{"do":[],"until":cond,"max":N}} {"extract":t} {"fetch":url}.'},quiet:{type:"boolean",description:"self-guarded batch returns only the result, not a page snapshot"},session:{type:"string"}},required:["steps"]}},{name:"reflex_read",description:"Re-read the current page. Returns only the delta since the last look, '(page unchanged)', or a full snapshot.",inputSchema:{type:"object",properties:{query:{type:"string",description:"only return lines matching this"},full:{type:"boolean",description:"force a full snapshot"},session:{type:"string"}}}},{name:"reflex_extract",description:"Extract data a snapshot folds (table/list/region), a captured JSON feed by its net<id> handle, or a collection. mode:'crawl' = same-domain link manifest; mode:'media' = verified page-media manifest (optional save:true). >6KB spills to a file.",inputSchema:{type:"object",properties:{target:{type:"string",description:"ref, name, or css=/xpath=; omit for main content"},mode:{type:"string",enum:["crawl","media"],description:"crawl: link manifest (maxDepth/maxWidth/maxPages); media: page-media manifest (save:true downloads)"},session:{type:"string"}}}},{name:"reflex_check",description:"Audit the page: visual defects (overlaps, low contrast, clipped text, broken images) plus recent console errors and failed network requests.",inputSchema:{type:"object",properties:{session:{type:"string"}}}},{name:"reflex_shot",description:"Screenshot the page or one element. Returns the image and its path.",inputSchema:{type:"object",properties:{region:{type:"string",description:"ref or name to crop to"},full:{type:"boolean",description:"full page height"},path_only:{type:"boolean",description:"return only the file path, no image tokens"},session:{type:"string"}}}},{name:"reflex_tab",description:"List, switch to, or close browser tabs. Popups and target=_blank are followed automatically.",inputSchema:{type:"object",properties:{n:{type:"integer",description:"tab number to switch to; omit to list"},close:{type:"boolean",description:"close tab n instead of switching"},session:{type:"string"}}}},{name:"reflex_flow",description:"Reusable automation: save this session's recorded steps as a flow, run a saved flow (deterministic replay, no page reading needed), list flows, or save auth state (cookies + localStorage) for reflex_open.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["save","run","list","state_save"]},name:{type:"string",description:"flow or state name"},params:{type:"array",items:{type:"string"},description:"save: values to parameterize as {{name}}"},values:{type:"object",description:"run: parameter values"},last:{type:"integer",description:"save: keep only the last N steps"},session:{type:"string"}},required:["action"]}},{name:"reflex_session",description:"List or stop parallel browser sessions. Free (no credit). Sessions spawn on demand on first use; each is an isolated browser, safe for concurrent agents.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["list","stop"]},session:{type:"string",description:"stop: which session"}},required:["action"]}},{name:"reflex_auth",description:"Sign in to Reflex (required before billed calls). Free. login opens a browser to sign in and stores the key; logout clears it; status shows account + credits. Tell the user to finish sign-in in the browser tab.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["login","logout","status"]}},required:["action"]}}];function Ce(){let e=process.env.REFLEX_MCP_EVAL;return e!=="0"&&e!=="false"&&e!=="off"}Ce()&&qe.push({name:"reflex_eval",description:"Run page JavaScript and return the result. Prefer act {eval} for side effects.",inputSchema:{type:"object",properties:{js:{type:"string"}},required:["js"]}});var Et='Reflex drives a local Chrome. If you know the targets, do the whole flow in ONE reflex_act starting {"goto":url}; no reflex_open needed. Else reflex_open once, then one big reflex_act. Guard with expect; read the returned delta, do not re-read. On failure the report names a [ref]: fix it and resend that same turn. Targets: [refs] or visible labels. 1 credit per call.';function Kn(e){switch(e.action){case"save":return{cmd:"flow_save",args:{name:e.name,params:e.params,last:e.last}};case"run":return{cmd:"flow_run",args:{name:e.name,params:e.values||{}}};case"list":return{cmd:"flow_list",args:{}};case"state_save":return{cmd:"state_save",args:{name:e.name}};default:throw new Error("action must be save|run|list|state_save")}}function ce(e,t){if(t=t||new Set,!Array.isArray(e))return t;for(let r of e){if(!r||typeof r!="object")continue;let n=Object.keys(r)[0];t.add(n);let o=r[n];if(Array.isArray(o))ce(o,t);else if(o&&typeof o=="object"){for(let s of["then","else","do","steps"])Array.isArray(o[s])&&ce(o[s],t);n==="optional"&&ce([o],t)}}return t}var Hn={reflex_open:{map:e=>{if(!e.url)throw new Error("url required");return{cmd:"open",args:{url:e.url,state:e.state,headed:e.headed,new_tab:e.new_tab}}}},reflex_act:{map:e=>{if(!Array.isArray(e.steps))throw new Error("steps must be an array");if(!Ce()&&ce(e.steps).has("eval"))throw new Error("eval steps are disabled (REFLEX_MCP_EVAL=0; unset to enable)");return{cmd:"act",args:{steps:e.steps,quiet:e.quiet}}}},reflex_read:{map:e=>({cmd:"read",args:{query:e.query,full:e.full}})},reflex_extract:{map:e=>({cmd:"extract",args:{target:e.target,mode:e.mode,maxDepth:e.maxDepth,maxWidth:e.maxWidth,maxPages:e.maxPages,save:e.save,includeAuth:e.includeAuth}})},reflex_check:{map:()=>({cmd:"check",args:{visual:!0}})},reflex_shot:{map:e=>({cmd:"shot",args:{region:e.region,full:e.full}}),shape:Zn},reflex_tab:{map:e=>e.n===void 0?{cmd:"tabs",args:{}}:{cmd:"tab",args:{n:e.n,close:e.close}}},reflex_flow:{map:Kn},reflex_eval:{map:e=>({cmd:"eval",args:{js:e.js}})}},Yn=new Set(["read","check","tabs","extract","shot","flow_list","open"]);function Jn(e){let t=process.env.REFLEX_METER;return b.spend(e)}function Fe(e){let t=process.env.REFLEX_METER;if(!(!e||!e.id))try{b.refund(e.id)}catch{}}var{classifyFailure:Rt}=xt();function Gn(e,t,r,n){let o=process.env.REFLEX_METER;if(!(!e||!e.id||typeof b.recordOutcome!="function"))try{b.recordOutcome(e.id,t,t?null:Rt(r),n)}catch{}}function Wn(e){return!e||!Array.isArray(e.content)?0:e.content.reduce((t,r)=>t+(r&&r.type==="text"?String(r.text||"").length:0),0)}var k=e=>({isError:!0,content:[{type:"text",text:e}]});function zn(e){return/Executable doesn'?t exist|is not found at|playwright install|please run the following/i.test(e)}function Lt(e,t){if(e.ok){let n=t&&t.warn?` | ||
| `+t.warn:"";return{content:[{type:"text",text:e.text+n}]}}if(zn(e.text))return k("Reflex needs Google Chrome installed (it drives your real browser). Install Chrome and retry.");let r=e.text;if(process.env.REFLEX_FAIL_SHOT==="inline"&&e.artifact){let n=[{type:"text",text:r}];try{let o=Me.readFileSync(e.artifact);n.push({type:"image",data:o.toString("base64"),mimeType:"image/png"})}catch{}return{isError:!0,content:n}}return r=r.replace(/^screenshot: .*$/m,"screenshot saved (call reflex_shot to view the page)"),{isError:!0,content:[{type:"text",text:r}]}}function Zn(e,t,r){if(!e.ok)return Lt(e,r);let n=r&&r.warn?` | ||
| `+r.warn:"",o=e.text+n;if(t.path_only)return{content:[{type:"text",text:o}]};let s=null;try{s=Me.readFileSync(e.artifact)}catch{}let c=/(\d+)x(\d+)/.exec(e.text||""),u=c?+c[2]:0;return s&&s.length<=2*1024*1024&&u<=2e3?{content:[{type:"text",text:o},{type:"image",data:s.toString("base64"),mimeType:"image/png"}]}:{content:[{type:"text",text:o+` | ||
| image too large to inline; retry with region or path_only`}]}}function ie(e){let t=new Error(e);return t.transport=!0,t.kind=e,t}function De(e){let t={};return process.env.REFLEX_IDLE_EXIT_MIN||(t.REFLEX_IDLE_EXIT_MIN=!e||e===S?"20":"15"),process.env.REFLEX_RAISE===void 0&&(t.REFLEX_RAISE="0"),Object.keys(t).length?t:void 0}var It=new Set,ae=null;function Vn(){return ae||(ae=(async()=>{if(process.env.REFLEX_AUTO_ISOLATE==="0"||process.env.REFLEX_SESSION&&S!=="default")return S;try{let e=await Pe(S,De(S)),t=await O(e,"claim",{caller:L},L),r=t&&t.owned?S:`a${process.pid}`;return r!==S&&console.error(`reflex: default session in use by another agent; auto-isolated to session=${r}`),r}catch{return S}})(),ae)}async function Qn(e,t,r){r&&r!==S&&It.add(r);let n;try{n=await Pe(r,De(r))}catch{throw ie("spawn")}try{return await O(n,e,t,L)}catch(o){if(/timeout/i.test(String(o.message||o)))throw ie("timeout");if(Yn.has(e))try{let s=await Pe(r,De(r));return await O(s,e,t,L)}catch{throw ie("lost")}throw ie("lost")}}function er(e){return e==="timeout"?"browser call timed out after 120s; the page may still be loading. Use reflex_read to see the current state.":"browser restarted; page state was lost. Use reflex_open to reopen the page, then retry."}async function tr(e){if(e.action==="stop"){if(!e.session)throw new Error("session required for stop");let n=St(e.session),o=G(n);if(!o)return{content:[{type:"text",text:`session ${n}: not running`}]};try{await O(o,"stop",{},L)}catch{}return{content:[{type:"text",text:`session ${n}: stopped`}]}}if(e.action!=="list")throw new Error("action must be list|stop");let t=Me.readdirSync(Un).map(n=>{let o=/^daemon(?:-([A-Za-z0-9_-]+))?\.json$/.exec(n);return o?o[1]||"default":null}).filter(Boolean),r=[];for(let n of t){let o=G(n);if(o)try{let c=(((await O(o,"status",{},L)).text||"").match(/^page: (.*)$/m)||[])[1];r.push(`${n}${n===S?" (default)":""}: ${c||"no page open"}`)}catch{}}return{content:[{type:"text",text:r.length?r.join(` | ||
| `):"(no active sessions)"}]}}async function nr(e){let t=e&&e.action;if(t==="logout"){let n=vt.logout();return await b.reinit({}).catch(()=>{}),{content:[{type:"text",text:n?"Signed out of Reflex. Run reflex_auth login to sign back in.":"Not signed in."}]}}if(t==="status"){let n=!!process.env.REFLEX_API_KEY,o=(()=>{try{return b.status()}catch{return{}}})();return o.trial?{content:[{type:"text",text:`Running on the free install trial, no account needed: ${o.balance} of ${o.trialGrant} calls left. Run reflex_auth login to create a free account and keep going.`}]}:o.keyTail?{content:[{type:"text",text:`Signed in (${n?"env REFLEX_API_KEY":"browser login"}); key \u2026${o.keyTail}, ${o.balance} credits.`}]}:{content:[{type:"text",text:"Not signed in. Run reflex_auth login to sign in (opens your browser)."}]}}if(t!=="login")throw new Error("action must be login|logout|status");if(process.env.REFLEX_API_KEY)return{content:[{type:"text",text:"Already authenticated via the REFLEX_API_KEY environment variable; no browser login needed."}]};let r=null;try{let n=await vt.login({onUrl:s=>{r=s,console.error("reflex login url: "+s)}});return await b.reinit({}).catch(()=>{}),{content:[{type:"text",text:`Signed in to Reflex${typeof n.balance=="number"?`, ${n.balance} credits`:""}. You can retry the call you wanted to make.`}]}}catch(n){let o=r?` If your browser did not open, sign in here: ${r}`:"";return k(`Reflex sign-in did not complete: ${String(n.message||n)}.${o}`)}}async function Tt(e,t){if(e==="reflex_session")try{return await tr(t||{})}catch(l){return k("bad arguments: "+String(l.message||l))}if(e==="reflex_auth")try{return await nr(t||{})}catch(l){return k("bad arguments: "+String(l.message||l))}let r=Hn[e];if(!r)return k(`unknown tool: ${e}`);if(e==="reflex_eval"&&!Ce())return k("reflex_eval is disabled (REFLEX_MCP_EVAL=0; unset to enable)");let n;t&&t.session!==void 0&&(n=St(t.session),t=Object.assign({},t),delete t.session);let o=Jn(e);if(!o.ok)return k(o.message);let s;try{s=r.map(t||{});let l={};s.args=Bn(s.args,l),s.cmd==="act"&&Object.keys(l).length&&(s.args.__env=l)}catch(l){return Fe(o),k("bad arguments: "+String(l.message||l))}n===void 0&&(n=await Vn());let c;try{c=await Qn(s.cmd,s.args,n)}catch(l){return l.transport?(Fe(o),k(er(l.kind))):(Fe(o),k("error: "+String(l.message||l)))}let u=r.shape?r.shape(c,t||{},o):Lt(c,o);return Gn(o,c.ok,c.text,Wn(u)),u}var $e=new qn({name:"reflex",version:Ne.version},{capabilities:{tools:{}},instructions:Et});$e.setRequestHandler($n,async()=>({tools:qe}));$e.setRequestHandler(Xn,async e=>{let{name:t,arguments:r}=e.params||{};try{return await Tt(t,r)}catch(n){return k("error: "+String(n.message||n))}});var kt=!1;async function le(){if(kt)return;kt=!0;try{await Promise.race([b.shutdown(),Ae(2100)])}catch{}let e=process.env.REFLEX_STOP_ON_EXIT==="1"?"stop":"detach";try{let t=G();t&&await Promise.race([O(t,e,{caller:L},L),Ae(2e3)])}catch{}for(let t of It)try{let r=G(t);r&&await Promise.race([O(r,e,{caller:L},L),Ae(1e3)])}catch{}process.exit(0)}async function rr(){try{let s=G();if(s){let c=await O(s,"ping",{});c&&c.v&&c.v!==Ne.version&&await O(s,"stop",{}).catch(()=>{})}}catch{}b.init({apiKey:process.env.REFLEX_API_KEY}).catch(()=>{});let e=process.env.REFLEX_API_KEY?"set":"none";try{let s=b.status();s&&s.keyTail&&(e=s.keyTail)}catch{}console.error(`reflex mcp v${Ne.version} session=${S} key=${e}`);let t=new Cn;await $e.connect(t);let r=t.onclose;t.onclose=()=>{if(r)try{r()}catch{}le()};let n=process.ppid,o=setInterval(()=>{n!==1&&process.ppid===1&&le()},5e3);o.unref&&o.unref()}process.on("SIGINT",le);process.on("SIGTERM",le);module.exports={TOOLS:qe,INSTRUCTIONS:Et,callTool:Tt,classifyFailure:Rt,start:rr}; | ||
| (150 credits for $9). Then simply retry this call.`};function _n(e){return`[reflex: ${e} credits left. Top up: https://reflexmcp.com/pricing]`}var m=null,_=null,a=null,i=null,re=!1,y=null,R=null,Q=!1,K=!1,O=0,Y=0,xe=0,ve=0,I=!1,F=!1,v=!1,x=null,ee=!1;function at(e){return Buffer.from(e.replace(/-/g,"+").replace(/_/g,"/"),"base64")}function wn(e,t){return{v:2,key_id:e||null,key_prefix:t||null,token:null,balance:0,free_expires_at:null,last_sync_at:null,max_token_iat:0,last_wall_clock:new Date().toISOString()}}function bn(e){return{v:1,pid:process.pid,key_prefix:e||null,buffer:[],overflow:{calls:0,from:null,to:null},pending_batch:null}}function dt(e){return e?e.slice(0,13):null}function pt(){try{let e=JSON.parse(d.readFileSync(te(),"utf8"));if(e&&(e.v===1||e.v===2))return e}catch{}return null}function xn(){try{let e=JSON.parse(d.readFileSync(ne(),"utf8"));if(e&&e.v===1&&Array.isArray(e.buffer))return e}catch{}return null}function Ie(){d.existsSync(T())||d.mkdirSync(T(),{recursive:!0})}function ht(){try{let e=JSON.parse(d.readFileSync(we(),"utf8"));if(e&&e.v===1&&typeof e.device_id=="string")return e}catch{}return null}function mt(e){try{Ie();let t=we()+".tmp";return d.writeFileSync(t,JSON.stringify(e),{mode:384}),d.renameSync(t,we()),!0}catch{return!1}}function vn(){let e=ht();if(e)return e;let t={v:1,device_id:H.randomUUID(),trial_key:null,claimed_at:null};return mt(t)?t:null}async function kn(){if(ee||!x||!v)return!1;ee=!0;try{let e=new AbortController,t=setTimeout(()=>e.abort(),Re),r;try{r=await fetch(ke+"/v1/trial/claim",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({device_id:x.device_id,client_version:Le}),signal:e.signal})}finally{clearTimeout(t)}if(r.status===429)return _={reason:"no_key",message:w.noKey},v=!1,!1;let n=await r.json().catch(()=>null);if(!r.ok||!n||!be.test(n.api_key||""))return!1;m=n.api_key;let o=dt(m);return a.key_prefix=o,i.key_prefix=o,typeof n.balance=="number"&&(a.balance=Math.max(0,n.balance-i.buffer.length)),v=!1,x.trial_key=m,x.claimed_at=new Date().toISOString(),mt(x),N(),await J(),!0}catch{return!1}finally{ee=!1}}async function Sn(e){let t=ht();if(!(!t||!e))try{let r=new AbortController,n=setTimeout(()=>r.abort(),Re);try{await fetch(ke+"/v1/trial/convert",{method:"POST",headers:{authorization:`Bearer ${e}`,"content-type":"application/json"},body:JSON.stringify({device_id:t.device_id}),signal:r.signal})}finally{clearTimeout(n)}}catch{}}function ct(e,t){let r=e?Date.parse(e):NaN,n=t?Date.parse(t):NaN;return Number.isNaN(r)?!1:Number.isNaN(n)?!0:r>n}function En(){let e=ut(),t=Date.now()+yn;for(;;)try{return d.mkdirSync(e),!0}catch{try{let n=d.statSync(e);if(Date.now()-n.mtimeMs>gn){d.rmdirSync(e);continue}}catch{}if(Date.now()>=t)return!1;let r=Math.min(Date.now()+10,t);for(;Date.now()<r;);}}function Rn(){try{d.rmdirSync(ut())}catch{}}function Te(){if(!a)return;let e=pt();if(!(!e||e.v!==2||e.key_prefix!==a.key_prefix)){if((e.max_token_iat||0)>(a.max_token_iat||0)&&e.token&&(a.token=e.token,a.max_token_iat=e.max_token_iat,a.free_expires_at=e.free_expires_at||a.free_expires_at),ct(e.last_sync_at,a.last_sync_at)){let t=i?i.buffer.length:0;a.balance=(e.balance||0)-t,a.last_sync_at=e.last_sync_at}ct(e.last_wall_clock,a.last_wall_clock)&&(a.last_wall_clock=e.last_wall_clock),a.key_id=a.key_id||e.key_id}}function Ln(){if(a)try{Ie();let e=En();try{Te();let t=te()+".tmp."+process.pid;d.writeFileSync(t,JSON.stringify(a),{mode:384}),d.renameSync(t,te())}finally{e&&Rn()}}catch{}}function Ae(){if(!i)return!1;try{Ie();let e=ne()+".tmp";return d.writeFileSync(e,JSON.stringify(i),{mode:384}),d.renameSync(e,ne()),!0}catch{return!1}}function N(){Ae(),Ln(),re=!1}function P(){re=!0,!y&&(y=setTimeout(()=>{y=null,re&&N()},cn),y.unref&&y.unref())}function se(e){if(typeof e!="string")return null;let t=e.split(".");if(t.length!==3||t[0]!=="RFX1")return null;let[,r,n]=t,o;try{o=JSON.parse(at(r).toString("utf8"))}catch{return null}let s=on[o.kid];if(!s||s.startsWith("REPLACE_"))return null;let c;try{c=H.createPublicKey({key:Buffer.concat([Buffer.from("302a300506032b6570032100","hex"),Buffer.from(s,"base64")]),format:"der",type:"spki"})}catch{return null}let u=Buffer.from("RFX1."+r,"ascii"),f=!1;try{f=H.verify(null,u,c,at(n))}catch{return null}return f?o:null}function yt(e,t,r,n){a.token=e,a.max_token_iat=Math.max(a.max_token_iat||0,t.iat||0),a.balance=r-(n||0),a.free_expires_at=t.fxp?new Date(t.fxp*1e3).toISOString():null,a.last_sync_at=new Date().toISOString(),P()}function $(){if(!a||!a.token)return!1;let e=se(a.token);if(!e||(e.iat||0)<(a.max_token_iat||0))return!1;let t=Math.floor(Date.now()/1e3);return!(e.exp<=t-ft/1e3)}async function gt(e,t,r,n){let o=new AbortController,s=setTimeout(()=>o.abort(),n);try{let c=await fetch(ke+t,{method:e,headers:{authorization:`Bearer ${m}`,"content-type":"application/json"},body:r?JSON.stringify(r):void 0,signal:o.signal}),u=null;try{u=await c.json()}catch{}return{status:c.status,json:u}}finally{clearTimeout(s)}}async function J(){let{status:e,json:t}=await gt("POST","/v1/validate",{client_version:Le},Re);if(e===401||e===403){_={reason:e===403?"key_revoked":"bad_key",message:w.badKey};try{d.unlinkSync(te())}catch{}return!1}if(e===200&&t&&t.ok&&t.token){let r=se(t.token);if(r&&(r.iat||0)>=(a.max_token_iat||0))return _=null,a.key_id=t.key_id||a.key_id,yt(t.token,r,t.balance,i.buffer.length),!0}return!1}function In(){if(i.pending_batch)return i.pending_batch;if(i.buffer.length===0&&i.overflow.calls===0)return null;let e=i.buffer.slice(),t={},r=null,n=null,o=0,s=0,c=0,u={};for(let p of e){if(t[p.tool]=(t[p.tool]||0)+1,p.ok===!0)o++;else if(p.ok===!1){let g=p.cat||"other";s++,u[g]=(u[g]||0)+1}Number.isFinite(p.resp_chars)&&(c+=p.resp_chars),(!r||p.ts<r)&&(r=p.ts),(!n||p.ts>n)&&(n=p.ts)}let f=new Date().toISOString(),l={batch_id:H.randomUUID(),calls:e.length,tools:t,ok:o,fail:s,overflow_calls:i.overflow.calls,period_start:r||i.overflow.from||f,period_end:n||i.overflow.to||f,client_balance:a.balance,hit_zero:!!i._hitZeroPending,client_version:Le,_event_ids:e.map(p=>p.id)};return Object.keys(u).length&&(l.fail_cats=u),c>0&&(l.resp_chars=c),l.calls===0&&l.overflow_calls===0?null:l}async function Oe(){if(K||!a||!i||!$()&&!i.pending_batch)return;let e=In();if(!e)return;K=!0,i.pending_batch=e,Ae();let{_event_ids:t,...r}=e,n=null;try{n=await gt("POST","/v1/usage",r,pn)}catch{n=null}if(n&&n.status===200&&n.json&&n.json.ok&&n.json.token){let o=se(n.json.token);if(o&&(o.iat||0)>=(a.max_token_iat||0)){let s=new Set(t),c=i.buffer.filter(f=>!s.has(f.id)),u=c.length;i.buffer=c,i.overflow={calls:0,from:null,to:null},i._hitZeroPending=!1,i.pending_batch=null,yt(n.json.token,o,n.json.balance,u),O=0,Y=0,K=!1;return}}n&&(n.status===401||n.status===403)&&(_={reason:n.status===403?"key_revoked":"bad_key",message:w.badKey},i.pending_batch=null),O=O?Math.min(O*2,mn):Ee,Y=Date.now()+O,K=!1,P()}function Tn(e){try{return process.kill(e,0),!0}catch(t){return t&&t.code!=="ESRCH"}}function _t(){if(!i)return;let e;try{e=d.readdirSync(T())}catch{return}for(let t of e){let r=/^usage-(\d+)\.json$/.exec(t);if(!r)continue;let n=Number(r[1]);if(n===process.pid||Tn(n))continue;let o=j.join(T(),t),s=null;try{s=JSON.parse(d.readFileSync(o,"utf8"))}catch{continue}if(!s||s.v!==1||!Array.isArray(s.buffer)||s.key_prefix&&i.key_prefix&&s.key_prefix!==i.key_prefix)continue;let c=j.join(T(),`usage-${n}.claimed-${process.pid}.json`);try{d.renameSync(o,c)}catch{continue}try{let u=JSON.parse(d.readFileSync(c,"utf8"));if(u&&Array.isArray(u.buffer)){if(i.buffer=i.buffer.concat(u.buffer),u.overflow&&u.overflow.calls){i.overflow.calls+=u.overflow.calls;let{from:f,to:l}=u.overflow;f&&(!i.overflow.from||f<i.overflow.from)&&(i.overflow.from=f),l&&(!i.overflow.to||l>i.overflow.to)&&(i.overflow.to=l)}u.pending_batch&&(i.pending_batch||(i.pending_batch=u.pending_batch)),u._hitZeroPending&&(i._hitZeroPending=!0)}Ae()&&d.unlinkSync(c)}catch{}}}async function oe(){if(!Q&&!(Date.now()<Y)&&!(!I||!a||!i)){Q=!0;try{if(v&&!await kn()||($()?a.balance<=0&&Date.now()-xe>=Ee&&(xe=Date.now(),await J()):await J(),_))return;_t(),await Oe(),Te()}catch{}finally{Q=!1}}}function An(){if(!I)return;let e=i.buffer.length,t=e>=sn;if(!t&&e>0){let r=new Date(i.buffer[0].ts).getTime();Date.now()-r>=an&&(t=!0)}t&&setImmediate(oe)}function wt(){m=null,_=null,a=null,i=null,I=!1,re=!1,y&&clearTimeout(y),R&&clearInterval(R),y=null,R=null,Q=!1,K=!1,O=0,Y=0,xe=0,ve=0,F=!1,v=!1,x=null,ee=!1}async function bt(e){if(I)return;if(e=e||{},m=e.apiKey||process.env.REFLEX_API_KEY||tn.loadKey()||null,!m&&rn()&&(x=vn(),x&&be.test(x.trial_key||"")?(m=x.trial_key,F=!0):x&&(F=!0,v=!0)),!m&&!v){_={reason:"no_key",message:w.noKey},I=!0;return}if(m&&!be.test(m)){_={reason:"no_key",message:w.noKey},I=!0;return}let t=v?nn:dt(m),r=xn();i=r&&r.key_prefix===t?r:bn(t);let n=pt(),o=!1;n&&n.key_prefix&&n.key_prefix===t?n.v===1&&Array.isArray(n.buffer)?(i.buffer=i.buffer.concat(n.buffer),n.overflow&&n.overflow.calls&&(i.overflow.calls+=n.overflow.calls,n.overflow.from&&(i.overflow.from=i.overflow.from||n.overflow.from),n.overflow.to&&(i.overflow.to=n.overflow.to)),n.pending_batch&&!i.pending_batch&&(i.pending_batch=n.pending_batch),n._hitZeroPending&&(i._hitZeroPending=!0),a={v:2,key_id:n.key_id||null,key_prefix:n.key_prefix,token:n.token||null,balance:n.balance||0,free_expires_at:n.free_expires_at||null,last_sync_at:n.last_sync_at||null,max_token_iat:n.max_token_iat||0,last_wall_clock:n.last_wall_clock||new Date().toISOString()},o=!0):a=n:(a=wn(null,t),v&&(a.balance=Se,N())),I=!0,o&&N(),R||(R=setInterval(oe,Ee),R.unref&&R.unref()),setImmediate(()=>{oe()})}function On(){let e=Date.now(),t=a&&a.last_wall_clock?new Date(a.last_wall_clock).getTime():0;return!(t&&e<t-ft)}function jn(e){if(_)return{ok:!1,reason:_.reason,message:_.message};if(!a||!i)return{ok:!1,reason:"no_key",message:w.noKey};if(!v&&!On()&&!$())return{ok:!1,reason:"offline_grace_expired",message:lt()};if(!v&&!$())return{ok:!1,reason:"offline_grace_expired",message:a.token?lt():w.graceExpiredFirstRun};if(a.balance<=0)return i._hitZeroPending=!0,P(),setImmediate(oe),F?{ok:!1,reason:"trial_exhausted",message:w.trialExhausted}:{ok:!1,reason:"out_of_credits",message:a.free_expires_at&&new Date(a.free_expires_at).getTime()<=Date.now()?w.outOfCreditsExpired:w.outOfCredits};a.balance-=1;let t={id:H.randomUUID(),tool:e,ts:new Date().toISOString()};if(i.buffer.push(t),a.last_wall_clock=t.ts,i.buffer.length>ln){let n=i.buffer.splice(0,un);i.overflow.calls+=n.length;let o=n[0].ts,s=n[n.length-1].ts;(!i.overflow.from||o<i.overflow.from)&&(i.overflow.from=o),(!i.overflow.to||s>i.overflow.to)&&(i.overflow.to=s)}P();let r;if(a.balance<=fn){let n=Date.now();n-ve>=dn&&(ve=n,r=_n(a.balance))}return An(),{ok:!0,warn:r,id:t.id}}function Fn(e,t,r,n){if(!i||!e)return;let o=i.buffer.find(s=>s.id===e);o&&(o.ok=!!t,!t&&r&&(o.cat=String(r).slice(0,24)),Number.isFinite(n)&&n>=0&&(o.resp_chars=Math.floor(n)),P())}function Nn(e){if(!a||!i||!e)return;let t=i.buffer.findIndex(r=>r.id===e);if(t>=0&&!(i.pending_batch&&Array.isArray(i.pending_batch._event_ids)&&i.pending_batch._event_ids.includes(e))){i.buffer.splice(t,1),a.balance+=1,P();return}a.balance+=1,P()}function Pn(){return{balance:a?a.balance:0,keyTail:m?m.slice(-4):null,trial:F,trialGrant:Se}}function lt(){return w.graceExpired}async function Dn(){if(y&&(clearTimeout(y),y=null),N(),R&&(clearInterval(R),R=null),!(!I||_||!a||!i)){if(i.buffer.length===0&&!i.pending_batch&&i.overflow.calls===0){try{d.unlinkSync(ne())}catch{}return}await Promise.race([(async()=>{try{$()||await J(),await Oe()}catch{}})(),new Promise(e=>{let t=setTimeout(e,hn);t.unref&&t.unref()})]),N()}}async function Mn(e){let t=F;wt(),await bt(e),t&&!F&&m&&Sn(m).catch(()=>{})}xt.exports={init:bt,reinit:Mn,spend:jn,refund:Nn,recordOutcome:Fn,status:Pn,shutdown:Dn,_MSG:w,_TRIAL_GRANT:Se,_verifyToken:se,_persistNow(){y&&(clearTimeout(y),y=null),N()},async _syncOnce(){O=0,Y=0;try{if(!I||!a||!i||($()||await J(),_))return;_t(),await Oe(),Te()}catch{}},_reset:wt}});var St=D((dr,kt)=>{"use strict";function qn(e){let t=String(e||"").split(/\n(?:url:|changes before failure:|screenshot:)/)[0];return/needs a target|provide (?:ms|a)|must be a|bad step|non-empty|file not found on disk|invalid (?:css|xpath) selector/i.test(t)?"baduse":/expect failed/i.test(t)?"assertion":/ambiguous|candidates:|near miss|no (?:exact )?match|no element|not found|could not (?:find|resolve)|couldn'?t resolve|(?:target|ref) not (?:resolved|found)/i.test(t)?"resolution":/disconnected|browser (?:restarted|disconnected)|page state was lost|net::|ERR_|navigation/i.test(t)?"navigation":/intercepts pointer events|not clickable|is hidden|resolved but not visible|outside of the viewport|element is not|not actionable|not stable/i.test(t)?"interaction":/expect|expected|assertion|still (?:visible|present)|not visible/i.test(t)?"assertion":/timed out|timeout|time limit|exceeded.*s/i.test(t)?"timeout":"other"}kt.exports={classifyFailure:qn}});var $e=require("fs"),{Server:$n}=require("@modelcontextprotocol/sdk/server/index.js"),{StdioServerTransport:Cn}=require("@modelcontextprotocol/sdk/server/stdio.js"),{ListToolsRequestSchema:Xn,CallToolRequestSchema:Bn}=require("@modelcontextprotocol/sdk/types.js"),{readState:G,rpc:A,ensureDaemon:Ne,subEnv:Un,sanitizeSession:Pe,SESSION:S,HOME:Kn}=Qe(),Et=ge(),De=_e(),L=`mcp-${process.pid}`,je=e=>new Promise(t=>setTimeout(t,e)),b;try{b=vt()}catch{b={init:async()=>{},spend:()=>({ok:!0}),refund:()=>{},recordOutcome:()=>{},status:()=>({}),shutdown:async()=>{},_MSG:{}}}process.env.REFLEX_RAISE===void 0&&(process.env.REFLEX_RAISE="0");var Ce=[{name:"reflex_open",description:"Open a URL in the local Chrome and return a distilled snapshot with element refs like [a3f2]. new_tab opens in a new tab, keeping the current one open.",inputSchema:{type:"object",properties:{url:{type:"string"},new_tab:{type:"boolean",description:"open in a new tab, keeping existing tabs open"},state:{type:"string",description:"saved auth state to load (via reflex_flow state_save)"},headed:{type:"boolean",description:"show the browser window (default true; false = headless)"},session:{type:"string",description:"isolated parallel browser; same name on every call that uses it"}},required:["url"]}},{name:"reflex_act",description:'Run a batch of browser steps in one call; stops at the first failure with a forensic report (reason, near-miss candidates, console/network errors, pre-failure page changes). Success returns only what changed, not the full page. A batch may start cold with {"goto":url}, which opens the browser too, so a flow whose targets you can already name needs no reflex_open.',inputSchema:{type:"object",properties:{steps:{type:"array",items:{type:"object"},description:'Each step is one object: {"goto":url} {"click":t} {"dblclick":t} {"hover":t} {"focus":t} {"fill":[t,value]} {"type":[t,text]} {"press":key} {"select":[t,option]} {"upload":[t,path]} {"check":t} {"uncheck":t} {"scroll":{"by":px}} {"scroll":{"to":t}} {"wait":ms} {"wait":{"text":s}} {"wait":{"url_contains":s}} {"expect":{"visible":t | "hidden":t | "text":s | "url_contains":s | "value":v,"target":t | "download":"*.pdf"}} {"shot":label} {"eval":js}. Target t: ref (a3f2), accessible name, or css=/xpath=. Secrets: {{env:VAR}}. Use expect guards between actions. Downloads auto-save (path in response). Compounds: {"if":{"visible":t,"then":[],"else":[]}} {"try":[steps]} {"repeat":{"do":[],"until":cond,"max":N}} {"extract":t} {"fetch":url}.'},quiet:{type:"boolean",description:"self-guarded batch returns only the result, not a page snapshot"},session:{type:"string"}},required:["steps"]}},{name:"reflex_read",description:"Re-read the current page. Returns only the delta since the last look, '(page unchanged)', or a full snapshot.",inputSchema:{type:"object",properties:{query:{type:"string",description:"only return lines matching this"},full:{type:"boolean",description:"force a full snapshot"},session:{type:"string"}}}},{name:"reflex_extract",description:"Extract data a snapshot folds (table/list/region), a captured JSON feed by its net<id> handle, or a collection. mode:'crawl' = same-domain link manifest; mode:'media' = verified page-media manifest (optional save:true). >6KB spills to a file.",inputSchema:{type:"object",properties:{target:{type:"string",description:"ref, name, or css=/xpath=; omit for main content"},mode:{type:"string",enum:["crawl","media"],description:"crawl: link manifest (maxDepth/maxWidth/maxPages); media: page-media manifest (save:true downloads)"},session:{type:"string"}}}},{name:"reflex_check",description:"Audit the page: visual defects (overlaps, low contrast, clipped text, broken images) plus recent console errors and failed network requests.",inputSchema:{type:"object",properties:{session:{type:"string"}}}},{name:"reflex_shot",description:"Screenshot the page or one element. Returns the image and its path.",inputSchema:{type:"object",properties:{region:{type:"string",description:"ref or name to crop to"},full:{type:"boolean",description:"full page height"},path_only:{type:"boolean",description:"return only the file path, no image tokens"},session:{type:"string"}}}},{name:"reflex_tab",description:"List, switch to, or close browser tabs. Popups and target=_blank are followed automatically.",inputSchema:{type:"object",properties:{n:{type:"integer",description:"tab number to switch to; omit to list"},close:{type:"boolean",description:"close tab n instead of switching"},session:{type:"string"}}}},{name:"reflex_flow",description:"Reusable automation: save this session's recorded steps as a flow, run a saved flow (deterministic replay, no page reading needed), list flows, or save auth state (cookies + localStorage) for reflex_open.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["save","run","list","state_save"]},name:{type:"string",description:"flow or state name"},params:{type:"array",items:{type:"string"},description:"save: values to parameterize as {{name}}"},values:{type:"object",description:"run: parameter values"},last:{type:"integer",description:"save: keep only the last N steps"},session:{type:"string"}},required:["action"]}},{name:"reflex_session",description:"List or stop parallel browser sessions. Free (no credit). Sessions spawn on demand on first use; each is an isolated browser, safe for concurrent agents.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["list","stop"]},session:{type:"string",description:"stop: which session"}},required:["action"]}},{name:"reflex_auth",description:"Sign in to Reflex (required before billed calls). Free. login opens a browser to sign in and stores the key; logout clears it; status shows account + credits. Tell the user to finish sign-in in the browser tab.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["login","logout","status"]}},required:["action"]}}];function Xe(){let e=process.env.REFLEX_MCP_EVAL;return e!=="0"&&e!=="false"&&e!=="off"}Xe()&&Ce.push({name:"reflex_eval",description:"Run page JavaScript and return the result. Prefer act {eval} for side effects.",inputSchema:{type:"object",properties:{js:{type:"string"}},required:["js"]}});var Lt='Reflex drives a local Chrome. Do the whole task in ONE reflex_act that starts {"goto":url}, with expect guards. Only call reflex_open first if you truly cannot guess the target labels. A wrong guess is cheap: the failure report names the right [ref], so fix it and resend that same turn. Read the returned delta, do not re-read. 1 credit per call.';function Hn(e){switch(e.action){case"save":return{cmd:"flow_save",args:{name:e.name,params:e.params,last:e.last}};case"run":return{cmd:"flow_run",args:{name:e.name,params:e.values||{}}};case"list":return{cmd:"flow_list",args:{}};case"state_save":return{cmd:"state_save",args:{name:e.name}};default:throw new Error("action must be save|run|list|state_save")}}function ce(e,t){if(t=t||new Set,!Array.isArray(e))return t;for(let r of e){if(!r||typeof r!="object")continue;let n=Object.keys(r)[0];t.add(n);let o=r[n];if(Array.isArray(o))ce(o,t);else if(o&&typeof o=="object"){for(let s of["then","else","do","steps"])Array.isArray(o[s])&&ce(o[s],t);n==="optional"&&ce([o],t)}}return t}var Yn={reflex_open:{map:e=>{if(!e.url)throw new Error("url required");return{cmd:"open",args:{url:e.url,state:e.state,headed:e.headed,new_tab:e.new_tab}}}},reflex_act:{map:e=>{if(!Array.isArray(e.steps))throw new Error("steps must be an array");if(!Xe()&&ce(e.steps).has("eval"))throw new Error("eval steps are disabled (REFLEX_MCP_EVAL=0; unset to enable)");return{cmd:"act",args:{steps:e.steps,quiet:e.quiet}}}},reflex_read:{map:e=>({cmd:"read",args:{query:e.query,full:e.full}})},reflex_extract:{map:e=>({cmd:"extract",args:{target:e.target,mode:e.mode,maxDepth:e.maxDepth,maxWidth:e.maxWidth,maxPages:e.maxPages,save:e.save,includeAuth:e.includeAuth}})},reflex_check:{map:()=>({cmd:"check",args:{visual:!0}})},reflex_shot:{map:e=>({cmd:"shot",args:{region:e.region,full:e.full}}),shape:Vn},reflex_tab:{map:e=>e.n===void 0?{cmd:"tabs",args:{}}:{cmd:"tab",args:{n:e.n,close:e.close}}},reflex_flow:{map:Hn},reflex_eval:{map:e=>({cmd:"eval",args:{js:e.js}})}},Jn=new Set(["read","check","tabs","extract","shot","flow_list","open"]);function Gn(e){let t=process.env.REFLEX_METER;return b.spend(e)}function Fe(e){let t=process.env.REFLEX_METER;if(!(!e||!e.id))try{b.refund(e.id)}catch{}}var{classifyFailure:It}=St();function Wn(e,t,r,n){let o=process.env.REFLEX_METER;if(!(!e||!e.id||typeof b.recordOutcome!="function"))try{b.recordOutcome(e.id,t,t?null:It(r),n)}catch{}}function zn(e){return!e||!Array.isArray(e.content)?0:e.content.reduce((t,r)=>t+(r&&r.type==="text"?String(r.text||"").length:0),0)}var k=e=>({isError:!0,content:[{type:"text",text:e}]});function Zn(e){return/Executable doesn'?t exist|is not found at|playwright install|please run the following/i.test(e)}function Tt(e,t){if(e.ok){let n=t&&t.warn?` | ||
| `+t.warn:"";return{content:[{type:"text",text:e.text+n}]}}if(Zn(e.text))return k("Reflex needs Google Chrome installed (it drives your real browser). Install Chrome and retry.");let r=e.text;if(process.env.REFLEX_FAIL_SHOT==="inline"&&e.artifact){let n=[{type:"text",text:r}];try{let o=$e.readFileSync(e.artifact);n.push({type:"image",data:o.toString("base64"),mimeType:"image/png"})}catch{}return{isError:!0,content:n}}return r=r.replace(/^screenshot: .*$/m,"screenshot saved (call reflex_shot to view the page)"),{isError:!0,content:[{type:"text",text:r}]}}function Vn(e,t,r){if(!e.ok)return Tt(e,r);let n=r&&r.warn?` | ||
| `+r.warn:"",o=e.text+n;if(t.path_only)return{content:[{type:"text",text:o}]};let s=null;try{s=$e.readFileSync(e.artifact)}catch{}let c=/(\d+)x(\d+)/.exec(e.text||""),u=c?+c[2]:0;return s&&s.length<=2*1024*1024&&u<=2e3?{content:[{type:"text",text:o},{type:"image",data:s.toString("base64"),mimeType:"image/png"}]}:{content:[{type:"text",text:o+` | ||
| image too large to inline; retry with region or path_only`}]}}function ie(e){let t=new Error(e);return t.transport=!0,t.kind=e,t}function Me(e){let t={};return process.env.REFLEX_IDLE_EXIT_MIN||(t.REFLEX_IDLE_EXIT_MIN=!e||e===S?"20":"15"),process.env.REFLEX_RAISE===void 0&&(t.REFLEX_RAISE="0"),Object.keys(t).length?t:void 0}var Be=new Set,ae=null;function Qn(){return ae||(ae=(async()=>{if(process.env.REFLEX_AUTO_ISOLATE==="0"||process.env.REFLEX_SESSION&&S!=="default")return S;try{let e=await Ne(S,Me(S)),t=await A(e,"claim",{caller:L},L),r=t&&t.owned?S:`a${process.pid}`;return r!==S&&console.error(`reflex: default session in use by another agent; auto-isolated to session=${r}`),r}catch{return S}})(),ae)}async function er(e,t,r){r&&r!==S&&Be.add(r);let n;try{n=await Ne(r,Me(r))}catch{throw ie("spawn")}try{return await A(n,e,t,L)}catch(o){if(/timeout/i.test(String(o.message||o)))throw ie("timeout");if(Jn.has(e))try{let s=await Ne(r,Me(r));return await A(s,e,t,L)}catch{throw ie("lost")}throw ie("lost")}}function tr(e){return e==="timeout"?"browser call timed out after 120s; the page may still be loading. Use reflex_read to see the current state.":"browser restarted; page state was lost. Use reflex_open to reopen the page, then retry."}async function nr(e){if(e.action==="stop"){if(!e.session)throw new Error("session required for stop");let n=Pe(e.session),o=G(n);if(!o)return{content:[{type:"text",text:`session ${n}: not running`}]};try{await A(o,"stop",{},L)}catch{}return{content:[{type:"text",text:`session ${n}: stopped`}]}}if(e.action!=="list")throw new Error("action must be list|stop");let t=$e.readdirSync(Kn).map(n=>{let o=/^daemon(?:-([A-Za-z0-9_-]+))?\.json$/.exec(n);return o?o[1]||"default":null}).filter(Boolean),r=[];for(let n of t){let o=G(n);if(o)try{let c=(((await A(o,"status",{},L)).text||"").match(/^page: (.*)$/m)||[])[1];r.push(`${n}${n===S?" (default)":""}: ${c||"no page open"}`)}catch{}}return{content:[{type:"text",text:r.length?r.join(` | ||
| `):"(no active sessions)"}]}}async function rr(e){let t=e&&e.action;if(t==="logout"){let n=Et.logout();return await b.reinit({}).catch(()=>{}),{content:[{type:"text",text:n?"Signed out of Reflex. Run reflex_auth login to sign back in.":"Not signed in."}]}}if(t==="status"){let n=!!process.env.REFLEX_API_KEY,o=(()=>{try{return b.status()}catch{return{}}})();return o.trial?{content:[{type:"text",text:`Running on the free install trial, no account needed: ${o.balance} of ${o.trialGrant} calls left. Run reflex_auth login to create a free account and keep going.`}]}:o.keyTail?{content:[{type:"text",text:`Signed in (${n?"env REFLEX_API_KEY":"browser login"}); key \u2026${o.keyTail}, ${o.balance} credits.`}]}:{content:[{type:"text",text:"Not signed in. Run reflex_auth login to sign in (opens your browser)."}]}}if(t!=="login")throw new Error("action must be login|logout|status");if(process.env.REFLEX_API_KEY)return{content:[{type:"text",text:"Already authenticated via the REFLEX_API_KEY environment variable; no browser login needed."}]};let r=null;try{let n=await Et.login({onUrl:s=>{r=s,console.error("reflex login url: "+s)}});return await b.reinit({}).catch(()=>{}),{content:[{type:"text",text:`Signed in to Reflex${typeof n.balance=="number"?`, ${n.balance} credits`:""}. You can retry the call you wanted to make.`}]}}catch(n){let o=r?` If your browser did not open, sign in here: ${r}`:"";return k(`Reflex sign-in did not complete: ${String(n.message||n)}.${o}`)}}async function At(e,t){if(e==="reflex_session")try{return await nr(t||{})}catch(l){return k("bad arguments: "+String(l.message||l))}if(e==="reflex_auth")try{return await rr(t||{})}catch(l){return k("bad arguments: "+String(l.message||l))}let r=Yn[e];if(!r)return k(`unknown tool: ${e}`);if(e==="reflex_eval"&&!Xe())return k("reflex_eval is disabled (REFLEX_MCP_EVAL=0; unset to enable)");let n;t&&t.session!==void 0&&(n=Pe(t.session),t=Object.assign({},t),delete t.session);let o=Gn(e);if(!o.ok)return k(o.message);let s;try{s=r.map(t||{});let l={};s.args=Un(s.args,l),s.cmd==="act"&&Object.keys(l).length&&(s.args.__env=l)}catch(l){return Fe(o),k("bad arguments: "+String(l.message||l))}let c="";n===void 0&&(qe>1?(n=Pe(`lane${process.pid}x${++or}`),Be.add(n),c=`[reflex: another browser call was already running, so this one got its own browser, session "${n}". Pass session:"${n}" on the rest of this task to stay in it.] | ||
| `):n=await Qn());let u;try{u=await er(s.cmd,s.args,n)}catch(l){return l.transport?(Fe(o),k(tr(l.kind))):(Fe(o),k("error: "+String(l.message||l)))}let f=r.shape?r.shape(u,t||{},o):Tt(u,o);return Wn(o,u.ok,u.text,zn(f)),c&&Array.isArray(f.content)&&f.content[0]&&f.content[0].type==="text"&&(f.content[0].text=c+f.content[0].text),f}var Ue=new $n({name:"reflex",version:De.version},{capabilities:{tools:{}},instructions:Lt});Ue.setRequestHandler(Xn,async()=>({tools:Ce}));var qe=0,or=0;Ue.setRequestHandler(Bn,async e=>{let{name:t,arguments:r}=e.params||{};qe++;try{return await At(t,r)}catch(n){return k("error: "+String(n.message||n))}finally{qe--}});var Rt=!1;async function le(){if(Rt)return;Rt=!0;try{await Promise.race([b.shutdown(),je(2100)])}catch{}let e=process.env.REFLEX_STOP_ON_EXIT==="1"?"stop":"detach";try{let t=G();t&&await Promise.race([A(t,e,{caller:L},L),je(2e3)])}catch{}for(let t of Be)try{let r=G(t);r&&await Promise.race([A(r,e,{caller:L},L),je(1e3)])}catch{}process.exit(0)}async function sr(){try{let s=G();if(s){let c=await A(s,"ping",{});c&&c.v&&c.v!==De.version&&await A(s,"stop",{}).catch(()=>{})}}catch{}b.init({apiKey:process.env.REFLEX_API_KEY}).catch(()=>{});let e=process.env.REFLEX_API_KEY?"set":"none";try{let s=b.status();s&&s.keyTail&&(e=s.keyTail)}catch{}console.error(`reflex mcp v${De.version} session=${S} key=${e}`);let t=new Cn;await Ue.connect(t);let r=t.onclose;t.onclose=()=>{if(r)try{r()}catch{}le()};let n=process.ppid,o=setInterval(()=>{n!==1&&process.ppid===1&&le()},5e3);o.unref&&o.unref()}process.on("SIGINT",le);process.on("SIGTERM",le);module.exports={TOOLS:Ce,INSTRUCTIONS:Lt,callTool:At,classifyFailure:It,start:sr}; |
+2
-2
| { | ||
| "name": "reflex-browser", | ||
| "version": "0.10.0", | ||
| "version": "0.11.0", | ||
| "mcpName": "com.reflexmcp/reflex", | ||
@@ -25,3 +25,3 @@ "description": "Token-efficient browser automation for AI agents. Local MCP server + CLI: compressed page snapshots, batched actions, forensic failures.", | ||
| "test:memory": "node test/memory.js", | ||
| "test": "node test/profile.js && node test/smoke.js && node test/engine.js && node test/tenx.js && node test/mcp.js && node test/credits.js && node test/memory.js && node test/teardown.js && node test/hygiene.js && node test/parallel.js && node test/concurrency.js", | ||
| "test": "node test/profile.js && node test/smoke.js && node test/engine.js && node test/tenx.js && node test/mcp.js && node test/credits.js && node test/trial.js && node test/memory.js && node test/teardown.js && node test/hygiene.js && node test/parallel.js && node test/concurrency.js", | ||
| "test:parallel": "node test/parallel.js", | ||
@@ -28,0 +28,0 @@ "test:concurrency": "node test/concurrency.js", |
Sorry, the diff of this file is too big to display
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
212703
0.2%850
0.24%107
-0.93%