@buoy-gg/mcp 7.0.69 → 7.0.71

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.
@@ -1,4 +1,4 @@
1
1
  import{createRequire as q}from"module";const fe=q(import.meta.url);import I from"fs";import R from"os";import y from"path";var G='// Buoy Web helper. Chrome starts it for the Buoy Web extension (native messaging) and\n// ends it when Chrome closes. It passes messages between the extension and Buoy MCP\n// sessions, which connect over a Unix socket only this user can open.\n//\n// extension <-- stdin/stdout (native messaging) --> helper <-- ~/.buoy/web/chrome-<pid>.sock --> MCP sessions\nimport fs from "node:fs";\nimport net from "node:net";\nimport os from "node:os";\nimport path from "node:path";\n\nconst dir = process.env.BUOY_WEB_DIR ?? path.join(os.homedir(), ".buoy", "web");\nfs.mkdirSync(dir, { recursive: true, mode: 0o700 });\nfs.chmodSync(dir, 0o700);\nconst sock = path.join(dir, `chrome-${process.pid}.sock`);\nconst info = path.join(dir, `chrome-${process.pid}.json`);\n\n// ---- native messaging: 4-byte little-endian length, then JSON -----------------\nlet inbuf = Buffer.alloc(0);\nprocess.stdin.on("data", (chunk) => {\n inbuf = Buffer.concat([inbuf, chunk]);\n while (inbuf.length >= 4) {\n const n = inbuf.readUInt32LE(0);\n if (inbuf.length < 4 + n) break;\n const msg = JSON.parse(inbuf.subarray(4, 4 + n).toString("utf8"));\n inbuf = inbuf.subarray(4 + n);\n fromExtension(msg);\n }\n});\nprocess.stdin.on("end", quit); // Chrome closed or the extension let go\nprocess.stdout.on("error", quit);\nfunction toExtension(msg) {\n const body = Buffer.from(JSON.stringify(msg), "utf8");\n if (body.length > 1024 * 1024) throw new Error("Message too big for Chrome (over 1 MB).");\n const head = Buffer.alloc(4);\n head.writeUInt32LE(body.length, 0);\n process.stdout.write(Buffer.concat([head, body]));\n}\n\n// ---- MCP sessions: one JSON message per line ------------------------------------\nconst clients = new Map(); // id -> socket\nlet nextClient = 1;\nfunction fromExtension(msg) {\n const s = clients.get(msg.c);\n if (!s) return;\n const { c, ...rest } = msg;\n s.write(JSON.stringify(rest) + "\\n");\n}\n\nconst server = net.createServer((s) => {\n const c = nextClient++;\n clients.set(c, s);\n let buf = "";\n s.setEncoding("utf8");\n s.on("data", (d) => {\n buf += d;\n let i;\n while ((i = buf.indexOf("\\n")) >= 0) {\n const line = buf.slice(0, i);\n buf = buf.slice(i + 1);\n if (!line) continue;\n let msg;\n try {\n msg = JSON.parse(line);\n toExtension({ ...msg, c });\n } catch (e) {\n if (msg?.id != null) s.write(JSON.stringify({ id: msg.id, error: String(e.message ?? e) }) + "\\n");\n }\n }\n });\n const gone = () => {\n if (!clients.delete(c)) return;\n try {\n toExtension({ c, method: "client.closed" });\n } catch {}\n };\n s.on("close", gone);\n s.on("error", gone);\n});\n\n// Clear out sockets left by helpers that died without cleaning up.\nfor (const f of fs.readdirSync(dir)) {\n const m = /^chrome-(\\d+)\\.(sock|json)$/.exec(f);\n if (!m || Number(m[1]) === process.pid) continue;\n try {\n process.kill(Number(m[1]), 0);\n } catch {\n fs.rmSync(path.join(dir, f), { force: true });\n }\n}\n\nconst old = process.umask(0o177); // the socket file is created 0600\nserver.listen(sock, () => {\n process.umask(old);\n fs.writeFileSync(info, JSON.stringify({ pid: process.pid, sock, started: Date.now() }), { mode: 0o600 });\n // Tells Buoy the extension is set up, so a closed Chrome isn\'t mistaken for "no extension".\n fs.writeFileSync(path.join(dir, "seen"), new Date().toISOString(), { mode: 0o600 });\n toExtension({ ready: true }); // the extension shows "connected" only after this\n});\n\nfunction quit() {\n for (const f of [sock, info]) fs.rmSync(f, { force: true });\n process.exit(0);\n}\nprocess.on("SIGTERM", quit);\nprocess.on("SIGINT", quit);\n';import V from"crypto";import N from"fs";import X from"http";import K from"net";import z from"os";import U from"path";import{WebSocketServer as Q}from"ws";var Z=process.env.BUOY_WEB_RELAYLOG==="1";var M=(...n)=>Z&&process.stderr.write(`[buoy-web relay] ${n.join(" ")}
2
2
  `);var x=()=>process.env.BUOY_WEB_DIR??U.join(z.homedir(),".buoy","web");function ee(n=x()){let e=[];try{e=N.readdirSync(n)}catch{return[]}const i=[];for(const o of e){const a=/^chrome-(\d+)\.json$/.exec(o);if(!a)continue;try{process.kill(Number(a[1]),0);const b=JSON.parse(N.readFileSync(U.join(n,o),"utf8"));if(N.existsSync(b.sock))i.push(b)}catch{}}return i.sort((o,a)=>a.started-o.started)}function te(n){return new Promise((e,i)=>{const o=K.createConnection(n);const a=new Map;let b=1;let l="";let d=false;let v=false;const w={onEvent:()=>{},onClose:()=>{},call(m,S){if(v)return Promise.reject(new Error("Chrome's Buoy helper closed."));const c=b++;o.write(JSON.stringify({id:c,method:m,params:S})+"\n");return new Promise((O,B)=>a.set(c,{res:O,rej:B}))},close:()=>o.end()};o.setEncoding("utf8");o.on("connect",()=>{d=true;e(w)});o.on("error",m=>{if(!d)i(m)});o.on("data",m=>{l+=m;let S;while((S=l.indexOf("\n"))>=0){const c=JSON.parse(l.slice(0,S));l=l.slice(S+1);if(c.id!=null&&a.has(c.id)){const{res:O,rej:B}=a.get(c.id);a.delete(c.id);if(c.error)B(new Error(c.error));else O(c.result)}else if(c.event)w.onEvent(c.event,c.params)}});o.on("close",()=>{v=true;for(const{rej:m}of a.values())m(new Error("Chrome's Buoy helper closed."));a.clear();w.onClose()})})}async function ne({sock:n}){const e=await te(n);const i=await e.call("hello");const o=new Map;let a=1;let b=false;let l=null;const d=new Set;const v=t=>{if(l?.readyState===1)l.send(JSON.stringify(t))};const w=t=>[...o.values()].find(t);const m={url:"",hello:i,onDetach:()=>{},onClose:()=>{},idle:()=>Promise.all([...d]),close:()=>{}};async function S(t,{settle:r=false}={}){const s=o.get(t);if(s)return s;await e.call("debugger.attach",{tabId:t});if(r){const E=Date.now();while(Date.now()-E<5e3){const T=await e.call("debugger.send",{tabId:t,method:"Runtime.evaluate",params:{expression:"[location.href, document.readyState]",returnByValue:true}}).catch(()=>null);const[D,L]=T?.result?.value??[];if(D&&D!=="about:blank"&&L!=="loading")break;await new Promise(H=>setTimeout(H,50))}}const{targetInfo:u}=await e.call("debugger.send",{tabId:t,method:"Target.getTargetInfo"});const{openerId:g,openerFrameId:f,...p}=u;p.canAccessOpener=false;const h={tabId:t,sessionId:`buoy-tab-${a++}`,targetInfo:p,children:new Set,framesSent:false,held:[]};o.set(t,h);v({method:"Target.attachedToTarget",params:{sessionId:h.sessionId,targetInfo:{...p,attached:true},waitingForDebugger:false}});return h}function c(t){const r=o.get(t);if(!r)return;o.delete(t);v({method:"Target.detachedFromTarget",params:{sessionId:r.sessionId,targetId:r.targetInfo?.targetId}})}e.onEvent=(t,r)=>{if(t==="debugger.event"){const s=o.get(r.tabId);if(!s)return;const u=r.params?.sessionId;if(r.method==="Target.attachedToTarget"&&u)s.children.add(u);if(r.method==="Target.detachedFromTarget"&&u)s.children.delete(u);const g={sessionId:r.sessionId||s.sessionId,method:r.method,params:r.params};if(!s.framesSent)s.held.push(g);else v(g)}else if(t==="debugger.detached"){c(r.tabId);m.onDetach(r)}else if(t==="tabs.created"){if(b){const s=S(r.id,{settle:true}).catch(()=>{});d.add(s);void s.finally(()=>d.delete(s))}}else if(t==="tabs.removed")c(r.tabId)};e.onClose=()=>{for(const t of[...o.keys()])c(t);l?.close();m.onClose()};async function O(t,r,s){if(!s){switch(t){case"Browser.getVersion":return{protocolVersion:"1.3",product:"Chrome/BuoyWeb",userAgent:i.userAgent,jsVersion:""};case"Browser.setDownloadBehavior":case"Target.setDiscoverTargets":case"Browser.close":return{};case"Target.setAutoAttach":b=true;return{};case"Target.getTargetInfo":return{targetInfo:{targetId:"buoy-browser",type:"browser",title:"",url:"",attached:true,canAccessOpener:false}};case"Target.getBrowserContexts":return{browserContextIds:[]};case"Target.createTarget":{const p=await e.call("tabs.create",{url:r?.url});const h=await S(p.id);return{targetId:h.targetInfo.targetId}}case"Target.closeTarget":{const p=w(h=>h.targetInfo?.targetId===r?.targetId);if(!p)return{success:false};await e.call("tabs.remove",{tabId:p.tabId});return{success:true}}}const f=o.values().next().value;if(!f)throw new Error(`No Buoy tab to run ${t} on.`);return e.call("debugger.send",{tabId:f.tabId,method:t,params:r})}if(t==="Target.getTargetInfo"){const f=w(p=>p.sessionId===s);if(f)return{targetInfo:f.targetInfo}}let u=w(f=>f.sessionId===s);let g;if(!u){u=w(f=>f.children.has(s));g=s}if(!u)throw new Error(`No Buoy tab for session ${s}.`);return e.call("debugger.send",{tabId:u.tabId,sessionId:g,method:t,params:r})}const B=V.randomUUID();const _=X.createServer((t,r)=>r.writeHead(404).end());const C=new Q({server:_});C.on("connection",(t,r)=>{if(r.url!==`/${B}`||l)return t.close(4004,"No.");l=t;t.on("message",async s=>{const{id:u,sessionId:g,method:f,params:p}=JSON.parse(s.toString());try{const h=await O(f,p,g);M("ok ",g??"-",f);t.send(JSON.stringify({id:u,sessionId:g,result:h??{}}));if(f==="Page.getFrameTree"){const E=w(T=>T.sessionId===g);if(E&&!E.framesSent){E.framesSent=true;for(const T of E.held.splice(0))v(T)}}}catch(h){M("ERR",g??"-",f,h.message);t.send(JSON.stringify({id:u,sessionId:g,error:{message:String(h.message??h)}}))}});t.on("close",()=>{l=null;e.close()})});await new Promise(t=>_.listen(0,"127.0.0.1",t));m.url=`ws://127.0.0.1:${_.address().port}/${B}`;m.close=()=>{e.close();C.close();_.close()};return m}var J="gg.buoy.web";var $=["cfolfiajhlenfifknbomdogooagnlamf","kjbgbjimhjiocnfifnemmenkondjeifp",...(process.env.BUOY_WEB_EXTENSION_IDS??"").split(",").filter(Boolean)];var A=["Google/Chrome","Google/Chrome Beta","Google/Chrome Dev","Google/Chrome Canary","Chromium","BraveSoftware/Brave-Browser","Microsoft Edge","Vivaldi","Arc/User Data"];function P(){if(process.env.BUOY_WEB_NMH_DIRS)return process.env.BUOY_WEB_NMH_DIRS.split(y.delimiter).filter(Boolean);if(process.platform!=="darwin")return[];const n=y.join(R.homedir(),"Library","Application Support");return A.map(e=>y.join(n,e)).filter(e=>I.existsSync(e)).map(e=>y.join(e,"NativeMessagingHosts"))}var j=(n,e,i)=>{try{if(I.readFileSync(n,"utf8")===e)return}catch{}I.writeFileSync(n,e,{mode:i});I.chmodSync(n,i)};function oe(){try{const n=y.join(x(),"helper");I.mkdirSync(n,{recursive:true,mode:448});const e=y.join(n,"helper.mjs");const i=y.join(n,"helper.sh");j(e,G,384);const o=d=>`'${d.replace(/'/g,`'\\''`)}'`;const a=process.env.BUOY_WEB_DIR?`BUOY_WEB_DIR=${o(process.env.BUOY_WEB_DIR)} `:"";j(i,`#!/bin/sh
3
3
  ${a}exec ${o(process.execPath)} ${o(e)} "$@"
4
- `,448);const b=JSON.stringify({name:J,description:"Buoy Web helper: lets the Buoy MCP use Buoy's own tabs through the Buoy Web extension.",path:i,type:"stdio",allowed_origins:$.map(d=>`chrome-extension://${d}/`)},null,2);const l=[];for(const d of P()){try{I.mkdirSync(d,{recursive:true});j(y.join(d,`${J}.json`),b+"\n",420);l.push(d)}catch{}}return l}catch{return[]}}function re(){if(process.env.BUOY_WEB_NMH_DIRS)return false;if(process.platform!=="darwin")return false;const n=y.join(R.homedir(),"Library","Application Support");for(const e of A){let i=[];try{i=I.readdirSync(y.join(n,e))}catch{continue}for(const o of i){if(o!=="Default"&&!/^Profile \d+$/.test(o))continue;if($.some(a=>I.existsSync(y.join(n,e,o,"Extensions",a))))return true}}return false}import se from"crypto";import k from"fs";import W from"path";var ie=process.env.BUOY_TELEMETRY_URL??"https://buoy.gg/api/t";var ae=24*60*60*1e3;function Y(){const n=(process.env.BUOY_TELEMETRY??"").toLowerCase();return n==="0"||n==="false"||n==="off"||process.env.DO_NOT_TRACK==="1"}var F=false;function ce(){if(F||Y())return;F=true;try{const n=W.join(x(),"install.json");let e={};try{e=JSON.parse(k.readFileSync(n,"utf8"))}catch{}if(typeof e.installId!=="string")e={installId:se.randomUUID(),lastPingAt:0};if(Date.now()-(e.lastPingAt??0)<ae)return;e.lastPingAt=Date.now();k.mkdirSync(W.dirname(n),{recursive:true,mode:448});k.writeFileSync(n,JSON.stringify(e),{mode:384});const i=JSON.stringify({installId:e.installId,version:"7.0.69",platform:process.platform==="darwin"?"macos":process.platform==="win32"?"windows":"linux",tier:"locked",surface:"web-mcp"});void fetch(ie,{method:"POST",headers:{"content-type":"application/json"},body:i,signal:AbortSignal.timeout(5e3)}).catch(()=>{})}catch{}}export{x as webDir,ee as findHelpers,ne as startRelay,P as helperManifestDirs,oe as ensureHelper,re as extensionInstalled,Y as telemetryOff,ce as noteUse};
4
+ `,448);const b=JSON.stringify({name:J,description:"Buoy Web helper: lets the Buoy MCP use Buoy's own tabs through the Buoy Web extension.",path:i,type:"stdio",allowed_origins:$.map(d=>`chrome-extension://${d}/`)},null,2);const l=[];for(const d of P()){try{I.mkdirSync(d,{recursive:true});j(y.join(d,`${J}.json`),b+"\n",420);l.push(d)}catch{}}return l}catch{return[]}}function re(){if(process.env.BUOY_WEB_NMH_DIRS)return false;if(process.platform!=="darwin")return false;const n=y.join(R.homedir(),"Library","Application Support");for(const e of A){let i=[];try{i=I.readdirSync(y.join(n,e))}catch{continue}for(const o of i){if(o!=="Default"&&!/^Profile \d+$/.test(o))continue;if($.some(a=>I.existsSync(y.join(n,e,o,"Extensions",a))))return true}}return false}import se from"crypto";import k from"fs";import W from"path";var ie=process.env.BUOY_TELEMETRY_URL??"https://buoy.gg/api/t";var ae=24*60*60*1e3;function Y(){const n=(process.env.BUOY_TELEMETRY??"").toLowerCase();return n==="0"||n==="false"||n==="off"||process.env.DO_NOT_TRACK==="1"}var F=false;function ce(){if(F||Y())return;F=true;try{const n=W.join(x(),"install.json");let e={};try{e=JSON.parse(k.readFileSync(n,"utf8"))}catch{}if(typeof e.installId!=="string")e={installId:se.randomUUID(),lastPingAt:0};if(Date.now()-(e.lastPingAt??0)<ae)return;e.lastPingAt=Date.now();k.mkdirSync(W.dirname(n),{recursive:true,mode:448});k.writeFileSync(n,JSON.stringify(e),{mode:384});const i=JSON.stringify({installId:e.installId,version:"7.0.71",platform:process.platform==="darwin"?"macos":process.platform==="win32"?"windows":"linux",tier:"locked",surface:"web-mcp"});void fetch(ie,{method:"POST",headers:{"content-type":"application/json"},body:i,signal:AbortSignal.timeout(5e3)}).catch(()=>{})}catch{}}export{x as webDir,ee as findHelpers,ne as startRelay,P as helperManifestDirs,oe as ensureHelper,re as extensionInstalled,Y as telemetryOff,ce as noteUse};