@vibro/bro 0.0.1-alpha.2 → 0.0.1-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -30,12 +30,35 @@ export default defineConfig({
30
30
  });
31
31
  ```
32
32
 
33
- Run some CLI commands:
33
+ Run as **CLI commands:**
34
34
  ```bash
35
35
  pnpm vibro -h
36
- pnpm pnpm vibro --screenshot --to-file ./tmp/screenshot.png
36
+ pnpm vibro --screenshot --to-file ./tmp/screenshot.png
37
37
  ```
38
38
 
39
+ Or directly:
40
+ ```bash
41
+ node_modules/.bin/vibro --mcp
42
+ ```
43
+
44
+ Use **MCP** server mode:
45
+ ```json
46
+ {
47
+ "mcpServers": {
48
+ "vibro": {
49
+ "command": "vibro",
50
+ "args": ["--mcp"]
51
+ }
52
+ }
53
+ }
54
+ ```
55
+
56
+
57
+ Available MCP tools:
58
+ - `vibro_list`
59
+ - `vibro_request`
60
+ - `vibro_screenshot`
61
+
39
62
 
40
63
  ## License
41
64
 
@@ -47,6 +47,7 @@ type VibroBridgeRequestHandler = (request: VibroBridgeRequest) => VibroBridgeRes
47
47
  declare global {
48
48
  interface Window {
49
49
  __vibroRequestHandler?: VibroBridgeRequestHandler;
50
+ __vibroVerboseClient?: boolean;
50
51
  }
51
52
  }
52
53
 
@@ -1 +1 @@
1
- var _="__vibro__:request",b="__vibro__:response",f="__vibro__:tab-register",T="__vibro__:tab-heartbeat",w="__vibro__:tab-focus",y="__vibro__:list-request",h="__vibro__:list-response";function v(e){return e!==null&&typeof e=="object"}var N=5e3,R="__vibroBridgeTabId";function k(){let e=window,r=e[R];if(typeof r=="string"&&r.length>0)return r;let t=x();return e[R]=t,t}var a=k(),i,S=false,I=false;function q(e){return e!==null&&typeof e=="object"}function M(e){return q(e)&&"ok"in e&&typeof e.ok=="boolean"&&("payload"in e||"error"in e)}function L(e){return e instanceof Error?e.message:String(e)}function O(e,r=.92){if(typeof e!="string")return r;let t=Number.parseFloat(e);return !Number.isFinite(t)||t<=0?r:t>1?1:t}function P(e){if(typeof e=="string"){let r=e.toLowerCase();if(r==="jpeg"||r==="jpg")return "jpeg"}return "png"}function x(){let e=new Uint8Array(4);return crypto.getRandomValues(e),Array.from(e).map(r=>r.toString(16).padStart(2,"0")).join("")}function D(){if(I)return;let e=window.__vibroRequestHandler;window.__vibroRequestHandler=async r=>r.path==="/screenshot"?j(r):typeof e=="function"?e(r):{ok:false,error:"No vibro request handler found on window.__vibroRequestHandler"},I=true;}function H(e){return e.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA&&e.videoWidth>0&&e.videoHeight>0?Promise.resolve():new Promise((r,t)=>{let n=setTimeout(()=>t(new Error("Timed out waiting for camera frame")),5e3),s=()=>{clearTimeout(n),e.removeEventListener("loadedmetadata",d),e.removeEventListener("error",o);},d=()=>{s(),r();},o=c=>{s(),t(new Error(`Video error: ${String(c)}`));};e.addEventListener("loadedmetadata",d,{once:true}),e.addEventListener("error",o,{once:true});})}function U(e){e!==void 0&&e.getTracks().forEach(r=>{r.stop();});}async function F(e){if(!navigator.mediaDevices||!("getDisplayMedia"in navigator.mediaDevices))throw new Error("Screen capture is not supported in this browser");let r,t=null;try{let n={audio:!1,preferCurrentTab:!0,video:{frameRate:{ideal:30}}};r=await navigator.mediaDevices.getDisplayMedia({...n,selfBrowserSurface:"include",surfaceSwitching:"exclude"}),t=document.createElement("video"),t.srcObject=r,t.muted=!0,t.autoplay=!0,t.playsInline=!0,await t.play().catch(()=>{}),await H(t);let s=t.videoWidth,d=t.videoHeight;if(s<=0||d<=0)throw new Error("Failed to read video frame size for screenshot");let o=document.createElement("canvas");o.width=s,o.height=d;let c=o.getContext("2d");if(c===null)throw new Error("Canvas context is not available");c.drawImage(t,0,0,s,d);let g=e.format==="jpeg"?"image/jpeg":"image/png";return {dataUrl:e.format==="png"?o.toDataURL(g):o.toDataURL(g,e.quality),width:s,height:d,format:e.format,quality:e.quality}}finally{t!==null&&t.remove(),U(r);}}async function j(e){let r=P(e.query.format??e.query.quality),t=O(e.query.quality,r==="png"?.92:.75);try{let n=await F({format:r,quality:t});return {ok:!0,payload:{dataUrl:n.dataUrl,width:n.width,height:n.height,format:n.format,quality:n.quality}}}catch(n){return {ok:false,error:L(n)}}}function C(){return `${location.protocol==="https:"?"wss:":"ws:"}//${location.host}/@vite/client`}function u(){let e=Date.now();return {title:document.title||"",pathname:location.pathname,href:location.href,focused:document.visibilityState==="visible",wsUrl:C(),userAgent:navigator.userAgent,registeredAt:e,lastSeenAt:e}}function W(e){return v(e)&&typeof e.requestId=="string"&&e.requestId.length>0}function l(e){import.meta.hot&&import.meta.hot.send(b,e);}function E(e,r){if(!import.meta.hot)return;let t=u();if(e===f){import.meta.hot.send(e,{tabId:a,metadata:r});return}import.meta.hot.send(e,{tabId:a,metadata:{...t,focused:r.focused,lastSeenAt:Date.now()}});}function z(e){if(!W(e)||!import.meta.hot)return;let r=u(),t={requestId:e.requestId,tabId:a,metadata:{...r,lastSeenAt:Date.now()},state:"open"};import.meta.hot.send(h,t);}function Q(e){import.meta.hot&&z(e);}function m(){import.meta.hot&&E(w,u());}function $(e){if(D(),e.targetTabId&&e.targetTabId!==a)return;let r=window.__vibroRequestHandler;if(typeof r!="function"){l({id:e.id,sourceTabId:a,ok:false,error:"No Srv request handler found on window.__vibroRequestHandler"});return}(async()=>{try{let t=await r(e);if(M(t)){l({id:e.id,sourceTabId:a,ok:t.ok,payload:t.payload,error:t.error});return}l({id:e.id,sourceTabId:a,ok:!0,payload:t});}catch(t){l({id:e.id,sourceTabId:a,ok:false,error:L(t)});}})();}function G(){E(f,u());}function V(){E(T,u());}function p(e=0){if(!S){if(import.meta.hot){console.log("[vibro] initialized"),S=true,G(),V(),i===void 0&&(i=setInterval(V,N)),import.meta.hot.on(_,$),import.meta.hot.on(y,Q),document.addEventListener("visibilitychange",m),window.addEventListener("focus",m),window.addEventListener("blur",m),window.addEventListener("beforeunload",()=>{i!==void 0&&(clearInterval(i),i=void 0);}),import.meta.hot.on("vite:beforeFullReload",()=>{i!==void 0&&(clearInterval(i),i=void 0);});return}if(e>=20){console.warn("[vibro] HMR is not available, bridge is disabled");return}setTimeout(()=>{p(e+1);},50);}}document.readyState==="loading"?window.addEventListener("DOMContentLoaded",()=>{p();},{once:true}):p();
1
+ var _="__vibro__:request",b="__vibro__:response",f="__vibro__:tab-register",T="__vibro__:tab-heartbeat",w="__vibro__:tab-focus",y="__vibro__:list-request",h="__vibro__:list-response";function v(e){return e!==null&&typeof e=="object"}var k=5e3,R="__vibroBridgeTabId",S=window.__vibroVerboseClient===true;function q(){let e=window,r=e[R];if(typeof r=="string"&&r.length>0)return r;let t=D();return e[R]=t,t}var a=q(),i,I=false,V=false;function M(e){return e!==null&&typeof e=="object"}function O(e){return M(e)&&"ok"in e&&typeof e.ok=="boolean"&&("payload"in e||"error"in e)}function A(e){return e instanceof Error?e.message:String(e)}function P(e,r=.92){if(typeof e!="string")return r;let t=Number.parseFloat(e);return !Number.isFinite(t)||t<=0?r:t>1?1:t}function x(e){if(typeof e=="string"){let r=e.toLowerCase();if(r==="jpeg"||r==="jpg")return "jpeg"}return "png"}function D(){let e=new Uint8Array(4);return crypto.getRandomValues(e),Array.from(e).map(r=>r.toString(16).padStart(2,"0")).join("")}function H(){if(V)return;let e=window.__vibroRequestHandler;window.__vibroRequestHandler=async r=>r.path==="/screenshot"?j(r):typeof e=="function"?e(r):{ok:false,error:"No vibro request handler found on window.__vibroRequestHandler"},V=true;}function U(e){return e.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA&&e.videoWidth>0&&e.videoHeight>0?Promise.resolve():new Promise((r,t)=>{let n=setTimeout(()=>t(new Error("Timed out waiting for camera frame")),1e4),s=()=>{clearTimeout(n),e.removeEventListener("loadedmetadata",d),e.removeEventListener("error",o);},d=()=>{s(),r();},o=c=>{s(),t(new Error(`Video error: ${String(c)}`));};e.addEventListener("loadedmetadata",d,{once:true}),e.addEventListener("error",o,{once:true});})}function F(e){e!==void 0&&e.getTracks().forEach(r=>{r.stop();});}async function C(e){if(!navigator.mediaDevices||!("getDisplayMedia"in navigator.mediaDevices))throw new Error("Screen capture is not supported in this browser");let r,t=null;try{let n={audio:!1,preferCurrentTab:!0,video:{frameRate:{ideal:30}}};r=await navigator.mediaDevices.getDisplayMedia({...n,selfBrowserSurface:"include",surfaceSwitching:"exclude"}),t=document.createElement("video"),t.srcObject=r,t.muted=!0,t.autoplay=!0,t.playsInline=!0,await t.play().catch(()=>{}),await U(t);let s=t.videoWidth,d=t.videoHeight;if(s<=0||d<=0)throw new Error("Failed to read video frame size for screenshot");let o=document.createElement("canvas");o.width=s,o.height=d;let c=o.getContext("2d");if(c===null)throw new Error("Canvas context is not available");c.drawImage(t,0,0,s,d);let g=e.format==="jpeg"?"image/jpeg":"image/png";return {dataUrl:e.format==="png"?o.toDataURL(g):o.toDataURL(g,e.quality),width:s,height:d,format:e.format,quality:e.quality}}finally{t!==null&&t.remove(),F(r);}}async function j(e){let r=x(e.query.format??e.query.quality),t=P(e.query.quality,r==="png"?.92:.75);try{let n=await C({format:r,quality:t});return {ok:!0,payload:{dataUrl:n.dataUrl,width:n.width,height:n.height,format:n.format,quality:n.quality}}}catch(n){return {ok:false,error:A(n)}}}function W(){return `${location.protocol==="https:"?"wss:":"ws:"}//${location.host}/@vite/client`}function u(){let e=Date.now();return {title:document.title||"",pathname:location.pathname,href:location.href,focused:document.visibilityState==="visible",wsUrl:W(),userAgent:navigator.userAgent,registeredAt:e,lastSeenAt:e}}function z(e){return v(e)&&typeof e.requestId=="string"&&e.requestId.length>0}function l(e){import.meta.hot&&import.meta.hot.send(b,e);}function E(e,r){if(!import.meta.hot)return;let t=u();if(e===f){import.meta.hot.send(e,{tabId:a,metadata:r});return}import.meta.hot.send(e,{tabId:a,metadata:{...t,focused:r.focused,lastSeenAt:Date.now()}});}function Q(e){if(!z(e)||!import.meta.hot)return;let r=u(),t={requestId:e.requestId,tabId:a,metadata:{...r,lastSeenAt:Date.now()},state:"open"};import.meta.hot.send(h,t);}function $(e){import.meta.hot&&Q(e);}function m(){import.meta.hot&&E(w,u());}function G(e){if(H(),e.targetTabId&&e.targetTabId!==a)return;let r=window.__vibroRequestHandler;if(typeof r!="function"){l({id:e.id,sourceTabId:a,ok:false,error:"No Srv request handler found on window.__vibroRequestHandler"});return}(async()=>{try{let t=await r(e);if(O(t)){l({id:e.id,sourceTabId:a,ok:t.ok,payload:t.payload,error:t.error});return}l({id:e.id,sourceTabId:a,ok:!0,payload:t});}catch(t){l({id:e.id,sourceTabId:a,ok:false,error:A(t)});}})();}function K(){E(f,u());}function L(){E(T,u());}function p(e=0){if(!I){if(import.meta.hot){S&&console.log("[vibro] initialized"),I=true,K(),L(),i===void 0&&(i=setInterval(L,k)),import.meta.hot.on(_,G),import.meta.hot.on(y,$),document.addEventListener("visibilitychange",m),window.addEventListener("focus",m),window.addEventListener("blur",m),window.addEventListener("beforeunload",()=>{i!==void 0&&(clearInterval(i),i=void 0);}),import.meta.hot.on("vite:beforeFullReload",()=>{i!==void 0&&(clearInterval(i),i=void 0);});return}if(e>=20){S&&console.warn("[vibro] HMR is not available, bridge is disabled");return}setTimeout(()=>{p(e+1);},50);}}document.readyState==="loading"?window.addEventListener("DOMContentLoaded",()=>{p();},{once:true}):p();
@@ -8,6 +8,8 @@ type VibroBridgePluginOptions = {
8
8
  registryFileName?: string;
9
9
  registryRetries?: number;
10
10
  registryRetryDelayMs?: number;
11
+ verboseServer?: boolean;
12
+ verboseClient?: boolean;
11
13
  };
12
14
  declare function vibroVitePlugin(options?: VibroBridgePluginOptions): Plugin;
13
15
 
@@ -60,6 +62,7 @@ type VibroBridgeRequestHandler = (request: VibroBridgeRequest) => VibroBridgeRes
60
62
  declare global {
61
63
  interface Window {
62
64
  __vibroRequestHandler?: VibroBridgeRequestHandler;
65
+ __vibroVerboseClient?: boolean;
63
66
  }
64
67
  }
65
68
 
@@ -1,11 +1,11 @@
1
- 'use strict';var crypto=require('crypto'),promises=require('fs/promises'),fs=require('fs'),path=require('path'),vite=require('vite');var L="/__vibro__",ct="__vibro__:request",ut="__vibro__:response",W="__vibro__:tab-register",z="__vibro__:tab-heartbeat",Q="__vibro__:tab-focus",dt="__vibro__:list-request",ft="__vibro__:list-response",$="node_modules",Y="vibro-sessions.json";function T(t){return t!==null&&typeof t=="object"}var C="dist",pt="vibro-cli.js",mt="vibro-client.js",j="vibro",qt=path.join($,".bin");function Jt(){let t=c=>`/@fs/${c.replace(/\\/g,"/")}`,e=__dirname;for(;;){let c=path.join(e,C),d=path.join(c,pt),u=path.join(c,mt);if(fs.existsSync(d)&&fs.existsSync(u))return {packageRoot:e,cliSourceFilePath:d,clientScriptPathForVite:t(u)};let f=path.dirname(e);if(f===e)break;e=f;}let r=path.resolve(__dirname,"../.."),a=path.join(r,C,mt);return {packageRoot:r,cliSourceFilePath:path.join(r,C,pt),clientScriptPathForVite:t(a)}}var{packageRoot:Z,cliSourceFilePath:Gt,clientScriptPathForVite:Wt}=Jt(),bt=path.join(Z,C);function zt(t){let e=new Map;for(let r of t)e.set(r,true);return Array.from(e.keys())}function ht(t){try{return fs.realpathSync(t)}catch{return t}}var Qt=4e3,Yt=4e3,Kt=8e3,Xt=3e4,Rt=3e4,Zt=12e4,te=3,ee=50;function P(t){return promises.stat(t).then(()=>true,()=>false)}function ne(t){return promises.readFile(t,"utf8").then(e=>{try{return JSON.parse(e)}catch{return}},()=>{})}function re(t){return Array.isArray(t)?t.length>0:T(t)&&Object.keys(t).length>0}async function oe(t){async function e(c){if(await Promise.all([P(path.join(c,".git")),P(path.join(c,"pnpm-workspace.yaml")),P(path.join(c,".pnpm-workspace-state-v1.json")),P(path.join(c,"lerna.json")),P(path.join(c,"nx.json")),P(path.join(c,"turbo.json"))]).then(g=>g.some(Boolean)))return true;let u=path.join(c,"package.json"),f=await ne(u);return f!==void 0&&re(f.workspaces)}let r=path.resolve(t),a="";for(;;){await e(r)&&(a=r);let c=path.dirname(r);if(c===r)break;r=c;}return a.length>0?a:path.resolve(t)}function F(t,e){return typeof t=="number"&&Number.isFinite(t)?t:e}function k(t,e){return typeof t=="string"?t:e}function se(t){try{return process.kill(t,0),!0}catch(e){if(!(e instanceof Error))return false;let r=e.code;return !(r==="ESRCH"||r==="EINVAL")}}function At(t){let e=k(t.config.server.host,"localhost");return e==="0.0.0.0"||e==="::"?"localhost":e}function It(t){return t.config.server.https?"https":"http"}function ie(t){let e=t.httpServer?.address();if(!(e==null||typeof e=="string"))return Number.isFinite(e.port)?e.port:void 0}function ae(t){let e=t.config.configFile;return typeof e=="string"?e:void 0}function tt(){return {updatedAt:Date.now(),instances:{}}}function H(t,e){let r=Date.now(),a={};for(let[c,d]of Object.entries(t)){if(d.pid<=0||!Number.isFinite(d.pid)||!se(d.pid)||r-d.lastSeenAt>e)continue;let u=String(d.pid);c===u&&(a[c]=d);}return a}function ce(t,e){if(!T(t))return tt();let r=t.updatedAt,a=t.instances;if(!T(a))return tt();let c={};for(let[d,u]of Object.entries(a)){if(!T(u))continue;let f=F(u.pid,NaN);if(!Number.isFinite(f)||String(Math.trunc(f))!==d)continue;let g=F(u.port,NaN);if(!Number.isFinite(g))continue;let m=F(u.startedAt,Date.now()),b=F(u.lastSeenAt,Date.now()),S=k(u.protocol,"http");if(S!=="http"&&S!=="https")continue;let _=k(u.host,"localhost"),y=k(u.cacheDir,"");if(y.length<=0)continue;let I=k(u.projectRoot,"");I.length<=0||(c[d]={pid:f,port:g,host:_,protocol:S,cacheDir:y,projectRoot:I,configFile:k(u.configFile,""),startedAt:m,lastSeenAt:b});}return {updatedAt:F(r,Date.now()),instances:H(c,e)}}function ue(t,e){return path.join(t,$,e)}async function de(t,e){try{let r=await promises.readFile(t,"utf8");return ce(JSON.parse(r),e)}catch{return tt()}}async function fe(t,e){await promises.mkdir(path.dirname(t),{recursive:true});let r=`${t}.tmp`;await promises.writeFile(r,JSON.stringify(e,null,2),"utf8"),await promises.rename(r,t);}function le(t){return new Promise(e=>{setTimeout(e,t);})}function x(t,e){console.error("[vibro]",t,e);}async function nt(t,e,r,a,c,d){for(let u=0;u<=a;u+=1)try{let f=await de(t,r),g=d(f);await fe(t,g);return}catch(f){if(u>=a)throw f;await le(c);}}function yt(t){return `'${t.replace(/'/g,`'"'"'`)}'`}function St(t){return `"${t.replace(/"/g,'""')}"`}function Tt(t){return `'${t.replace(/'/g,"''")}'`}function D(t,e=j){return path.join(t,qt,e)}async function ge(t,e,r){let a=D(t),c=D(t,`${j}.CMD`),d=D(t,`${j}.ps1`),u=D(t,`${j}.cli.mjs`),f=yt(e),g=yt(r),m=St(r),b=Tt(r),S=`#!/usr/bin/env sh
1
+ 'use strict';var crypto=require('crypto'),promises=require('fs/promises'),fs=require('fs'),path=require('path'),vite=require('vite');var L="/__vibro__",de="__vibro__:request",fe="__vibro__:response",W="__vibro__:tab-register",z="__vibro__:tab-heartbeat",Y="__vibro__:tab-focus",le="__vibro__:list-request",ge="__vibro__:list-response",$="node_modules",K="vibro-sessions.json";function y(e){return e!==null&&typeof e=="object"}var x="dist",be="vibro-cli.js",he="vibro-client.js",j="vibro",Ge=path.join($,".bin");function We(){let e=c=>`/@fs/${c.replace(/\\/g,"/")}`,t=__dirname;for(;;){let c=path.join(t,x),d=path.join(c,be),u=path.join(c,he);if(fs.existsSync(d)&&fs.existsSync(u))return {packageRoot:t,cliSourceFilePath:d,clientScriptPathForVite:e(u)};let f=path.dirname(t);if(f===t)break;t=f;}let r=path.resolve(__dirname,"../.."),a=path.join(r,x,he);return {packageRoot:r,cliSourceFilePath:path.join(r,x,be),clientScriptPathForVite:e(a)}}var{packageRoot:Z,cliSourceFilePath:ze,clientScriptPathForVite:Ye}=We(),Se=path.join(Z,x);function Ke(e){let t=new Map;for(let r of e)t.set(r,true);return Array.from(t.keys())}function Re(e){try{return fs.realpathSync(e)}catch{return e}}var Qe=4e3,Xe=4e3,Ze=8e3,et=3e4,ye=3e4,tt=12e4,nt=3,rt=50;function P(e){return promises.stat(e).then(()=>true,()=>false)}function ot(e){return promises.readFile(e,"utf8").then(t=>{try{return JSON.parse(t)}catch{return}},()=>{})}function it(e){return Array.isArray(e)?e.length>0:y(e)&&Object.keys(e).length>0}async function st(e){async function t(c){if(await Promise.all([P(path.join(c,".git")),P(path.join(c,"pnpm-workspace.yaml")),P(path.join(c,".pnpm-workspace-state-v1.json")),P(path.join(c,"lerna.json")),P(path.join(c,"nx.json")),P(path.join(c,"turbo.json"))]).then(g=>g.some(Boolean)))return true;let u=path.join(c,"package.json"),f=await ot(u);return f!==void 0&&it(f.workspaces)}let r=path.resolve(e),a="";for(;;){await t(r)&&(a=r);let c=path.dirname(r);if(c===r)break;r=c;}return a.length>0?a:path.resolve(e)}function F(e,t){return typeof e=="number"&&Number.isFinite(e)?e:t}function B(e,t){return typeof e=="string"?e:t}function at(e){try{return process.kill(e,0),!0}catch(t){if(!(t instanceof Error))return false;let r=t.code;return !(r==="ESRCH"||r==="EINVAL")}}function Ve(e){let t=B(e.config.server.host,"localhost");return t==="0.0.0.0"||t==="::"?"localhost":t}function ve(e){return e.config.server.https?"https":"http"}function ct(e){let t=e.httpServer?.address();if(!(t==null||typeof t=="string"))return Number.isFinite(t.port)?t.port:void 0}function ut(e){let t=e.config.configFile;return typeof t=="string"?t:void 0}function ee(){return {updatedAt:Date.now(),instances:{}}}function H(e,t){let r=Date.now(),a={};for(let[c,d]of Object.entries(e)){if(d.pid<=0||!Number.isFinite(d.pid)||!at(d.pid)||r-d.lastSeenAt>t)continue;let u=String(d.pid);c===u&&(a[c]=d);}return a}function dt(e,t){if(!y(e))return ee();let r=e.updatedAt,a=e.instances;if(!y(a))return ee();let c={};for(let[d,u]of Object.entries(a)){if(!y(u))continue;let f=F(u.pid,NaN);if(!Number.isFinite(f)||String(Math.trunc(f))!==d)continue;let g=F(u.port,NaN);if(!Number.isFinite(g))continue;let b=F(u.startedAt,Date.now()),S=F(u.lastSeenAt,Date.now()),V=B(u.protocol,"http");if(V!=="http"&&V!=="https")continue;let R=B(u.host,"localhost"),T=B(u.cacheDir,"");if(T.length<=0)continue;let _=B(u.projectRoot,"");_.length<=0||(c[d]={pid:f,port:g,host:R,protocol:V,cacheDir:T,projectRoot:_,configFile:B(u.configFile,""),startedAt:b,lastSeenAt:S});}return {updatedAt:F(r,Date.now()),instances:H(c,t)}}function ft(e,t){return path.join(e,$,t)}async function lt(e,t){try{let r=await promises.readFile(e,"utf8");return dt(JSON.parse(r),t)}catch{return ee()}}async function gt(e,t){await promises.mkdir(path.dirname(e),{recursive:true});let r=`${e}.tmp`;await promises.writeFile(r,JSON.stringify(t,null,2),"utf8"),await promises.rename(r,e);}function pt(e){return new Promise(t=>{setTimeout(t,e);})}function mt(e,t,...r){e&&t(...r);}function C(e,t,r){mt(r,console.error,"[vibro]",e,t);}async function ne(e,t,r,a,c,d){for(let u=0;u<=a;u+=1)try{let f=await lt(e,r),g=d(f);await gt(e,g);return}catch(f){if(u>=a)throw f;await pt(c);}}function Te(e){return `'${e.replace(/'/g,`'"'"'`)}'`}function _e(e){return `"${e.replace(/"/g,'""')}"`}function Ee(e){return `'${e.replace(/'/g,"''")}'`}function D(e,t=j){return path.join(e,Ge,t)}async function bt(e,t,r){let a=D(e),c=D(e,`${j}.CMD`),d=D(e,`${j}.ps1`),u=D(e,`${j}.cli.mjs`),f=Te(t),g=Te(r),b=_e(r),S=Ee(r),V=`#!/usr/bin/env sh
2
2
  exec node ${f} --sessions-file ${g} "$@"
3
- `,_=`@ECHO OFF
4
- node ${St(e)} --sessions-file ${m} %*
5
- `,y=`$ErrorActionPreference = 'Stop'
6
- $cli = ${Tt(e)}
7
- $sessionFile = ${b}
3
+ `,R=`@ECHO OFF
4
+ node ${_e(t)} --sessions-file ${b} %*
5
+ `,T=`$ErrorActionPreference = 'Stop'
6
+ $cli = ${Ee(t)}
7
+ $sessionFile = ${S}
8
8
  & node $cli --sessions-file $sessionFile @args
9
9
  exit $LASTEXITCODE
10
- `,I=[{path:a,content:S,executable:true},{path:c,content:_},{path:d,content:y}];await promises.unlink(u).catch(()=>{});for(let h of I){try{if(await promises.readFile(h.path,"utf8")===h.content){h.executable&&await promises.chmod(h.path,493);continue}}catch{}await promises.mkdir(path.dirname(h.path),{recursive:true});let B=`${h.path}.tmp`;await promises.writeFile(B,h.content,"utf8"),await promises.rename(B,h.path),h.executable&&await promises.chmod(h.path,493);}}async function pe(t,e,r,a,c,d){await nt(t,e,r,a,c,u=>{let f=Date.now(),g=String(process.pid),m=H(u.instances,r),b=m[g]?.startedAt??f;return m[g]={pid:process.pid,port:d,host:At(e),protocol:It(e),cacheDir:e.config.cacheDir,projectRoot:e.config.root,configFile:ae(e),startedAt:b,lastSeenAt:f},{updatedAt:f,instances:m}});}async function me(t,e,r,a,c){await nt(t,e,r,a,c,d=>{let u=Date.now(),f=String(process.pid),g=d.instances[f];if(!g)return d;let m=H(d.instances,r);return m[f]={...g,lastSeenAt:u},{updatedAt:u,instances:m}});}async function be(t,e,r,a,c){await nt(t,e,r,a,c,d=>{let u=Date.now(),f=H(d.instances,r);return delete f[String(process.pid)],{updatedAt:u,instances:f}});}function he(t){let e={};for(let[r,a]of Object.entries(t))a!==void 0&&(typeof a=="string"?e[r]=a:Array.isArray(a)&&(e[r]=a.join(",")));return e}function Re(t){return new Promise((e,r)=>{let a="";t.on("data",c=>{a+=c.toString();}),t.on("error",r),t.on("end",()=>{e(a||void 0);});})}function ye(t,e){let r=t===void 0?NaN:Number.parseInt(t,10);return Number.isFinite(r)&&r>=0?r:e}function Se(t){return typeof t=="string"&&t.length>0}function Te(t){return !(!T(t)||typeof t.id!="string"||typeof t.ok!="boolean")}function _e(t){return !(!T(t)||typeof t.requestId!="string"||typeof t.tabId!="string"||!T(t.metadata)||"state"in t&&typeof t.state!="string")}function K(t){let e=Date.now();if(!T(t))return {title:"",pathname:"",href:"",focused:false,wsUrl:"",userAgent:"",registeredAt:e,lastSeenAt:e};let r=typeof t.registeredAt=="number"?t.registeredAt:e,a=typeof t.lastSeenAt=="number"?t.lastSeenAt:e;return {title:typeof t.title=="string"?t.title:"",pathname:typeof t.pathname=="string"?t.pathname:"",href:typeof t.href=="string"?t.href:"",focused:typeof t.focused=="boolean"?t.focused:false,wsUrl:typeof t.wsUrl=="string"?t.wsUrl:"",userAgent:typeof t.userAgent=="string"?t.userAgent:"",registeredAt:r,lastSeenAt:a}}function A(t,e){let r=e-t;return r>Xt?"closed":r>Kt?"stale":"open"}function Ee(t={}){let e=new Map,r=new Map,a=new Map,c=t.removeFromListOnReload??false,d=t.instanceHeartbeatMs??Rt,u=t.instanceTtlMs??Zt,f=t.sessionFileName??t.registryFileName??Y,g=t.registryRetries??te,m=t.registryRetryDelayMs??ee,b="",S="",_,y,I=false,B=false;function q(){_!==void 0&&(clearInterval(_),_=void 0);}async function rt(n){S=await oe(n.config.root),b=ue(S,f);let s=Gt;if(!await P(s))throw new Error(`vibro cli source file not found: ${s}`);await ge(S,s,b);}async function Vt(n){let s=y;if(s===void 0)return;(b.length<=0||S.length<=0)&&await rt(n);let o=Number.isFinite(d)&&d>0?d:Rt;await pe(b,n,u,g,m,s),I=true,_!==void 0&&q(),_=setInterval(()=>{me(b,n,u,g,m).catch(i=>{x("failed to touch Vite instance",i);});},o);}async function ot(n){!b.length||!I||(I=false,q(),await be(b,n,u,g,m));}function vt(n){return new Promise((s,o)=>{let i=setTimeout(()=>{e.delete(n),o(new Error(`Bridge request timeout (${n})`));},Qt);e.set(n,{resolve:s,reject:o,timeout:i});})}function Pt(n){let s=e.get(n.id);s&&(clearTimeout(s.timeout),e.delete(n.id),s.resolve(n));}function M(){let n=Date.now();return Array.from(a.values()).map(s=>({...s,state:A(s.metadata.lastSeenAt,n),metadata:{...s.metadata,lastSeenAt:s.metadata.lastSeenAt}}))}function Nt(){let n=Date.now(),o=M().filter(l=>A(l.metadata.lastSeenAt,n)!=="closed");if(o.length<=0)return;let i=o.find(l=>l.metadata.focused);return i!==void 0?i.id:o[0].id}function st(n,s,o){let i=Date.now(),l=K(s),E=a.get(n),V={id:n,state:o??A(l.lastSeenAt,i),metadata:{...l,registeredAt:E?.metadata.registeredAt??l.registeredAt,lastSeenAt:i}};return a.set(n,V),V}function kt(n,s,o){let i=Date.now();return s<=0?Promise.resolve(M().map(l=>({...l,state:A(l.metadata.lastSeenAt,i)}))):new Promise((l,E)=>{let V=setTimeout(()=>{it(n);},o);r.set(n,{expected:s,resolve:l,reject:E,timeout:V,responses:new Map});})}function it(n){let s=r.get(n);if(!s)return;clearTimeout(s.timeout),r.delete(n);let o=Date.now(),i=new Map;M().forEach(l=>{i.set(l.id,{...l,state:A(l.metadata.lastSeenAt,o)});}),s.responses.forEach(l=>{i.set(l.id,{...l,state:A(l.metadata.lastSeenAt,o)});}),s.resolve(Array.from(i.values()));}function Bt(n){let s=r.get(n.requestId);if(!s)return;let o=n.state??A(n.metadata.lastSeenAt,Date.now()),i={...K(n.metadata),lastSeenAt:Date.now()},l=st(n.tabId,i,o);s.responses.set(n.tabId,l),s.expected>0&&s.responses.size>=s.expected&&it(n.requestId);}function J(n,s){if(!T(s))return;let o=s.tabId,i=s.metadata;if(!Se(o)||!T(i))return;let l=K(i);st(o,l);}function Ft(n){let s=n.split("/").filter(Boolean);if(s.length<2)return;let o=s[0];if(!(o!=="ping"&&o!=="screenshot"))return {commandPath:`/${o}`,targetTabId:s[1]}}return {name:"vibro-plugin",apply:"serve",config(n){let s=vite.searchForWorkspaceRoot(process.cwd()),o=n.server?.fs?.allow,i=Array.isArray(o)?o:[];return {server:{fs:{allow:zt([...i,s,Z,bt,ht(Z),ht(bt)])}}}},configureServer(n){let s=async()=>{if(y=ie(n),y!==void 0)try{if(await rt(n),await Vt(n),!B){let o=It(n),i=At(n);console.info(` \u25A0 Registered server ${i?`${o}://${i}:${y}`:`:${y}`}`),console.info(` [vibro] registry ready at ${i?`${o}://${i}:${y}`:`:${y}`}`),console.info(` [vibro] sessions: ${b}`),console.info(` [vibro] cli: ${D(S)}`),B=!0;}}catch(o){x("failed to register Vite instance",o);}};n.httpServer?.listening?s():n.httpServer&&n.httpServer.once("listening",()=>{s();}),n.httpServer?.once("close",()=>{ot(n).catch(o=>{x("failed to detach Vite instance",o);});}),c&&n.ws.on("vite:beforeFullReload",()=>{ot(n).catch(o=>{x("failed to detach Vite instance on reload",o);});}),n.ws.on(ut,o=>{Te(o)&&Pt(o);}),n.ws.on(W,o=>{J(W,o);}),n.ws.on(z,o=>{J(z,o);}),n.ws.on(Q,o=>{J(Q,o);}),n.ws.on(ft,o=>{_e(o)&&Bt(o);}),n.middlewares.use(L,async(o,i,l)=>{if(!o.url||!o.method){l();return}let E=new URL(o.url,"http://localhost"),V=o.method.toUpperCase(),Dt=!["GET","HEAD"].includes(V),w={id:crypto.randomUUID(),path:E.pathname.startsWith(L)?E.pathname.substring(L.length)||"/":E.pathname,method:V,query:Object.fromEntries(E.searchParams.entries()),headers:he(o.headers),body:Dt?await Re(o).catch(()=>{}):void 0};if(console.log(`[vibro] Received a signal: ${V} ${E}`),w.path==="/list"){let R=ye(w.query.timeout,Yt),N=w.id,Ot=Date.now(),at=M().map(O=>({...O,state:A(O.metadata.lastSeenAt,Ot)})).filter(O=>O.state!=="closed").length,Lt=kt(N,at,R);at>0&&n.ws.send(dt,{requestId:N});let $t=await Lt;i.statusCode=200,i.setHeader("content-type","application/json; charset=utf-8"),i.end(JSON.stringify({ok:true,payload:{tabs:$t}}));return}let v,G=Ft(w.path);if(G!==void 0?(v=G.targetTabId,w.path=G.commandPath):w.path==="/screenshot"&&(v=Nt()),v!==void 0&&(w.targetTabId=v),v!==void 0){let R=a.get(v),N=Date.now();if(!R||A(R.metadata.lastSeenAt,N)==="closed"){i.statusCode=404,i.setHeader("content-type","application/json; charset=utf-8"),i.end(JSON.stringify({ok:false,error:`Unknown target tab: ${v}`}));return}}let Mt=vt(w.id);n.ws.send(ct,w);try{let R=await Mt;i.statusCode=R.ok?200:500,i.setHeader("content-type","application/json; charset=utf-8"),i.end(JSON.stringify({ok:R.ok,payload:R.payload,error:R.error}));}catch(R){let N=R instanceof Error?R.message:String(R);i.statusCode=504,i.setHeader("content-type","application/json; charset=utf-8"),i.end(JSON.stringify({ok:false,error:N}));}});},transformIndexHtml(n){return {html:n,tags:[{tag:"script",injectTo:"body-prepend",attrs:{type:"module",src:Wt}}]}}}}
11
- exports.vibroVitePlugin=Ee;
10
+ `,_=[{path:a,content:V,executable:true},{path:c,content:R},{path:d,content:T}];await promises.unlink(u).catch(()=>{});for(let p of _){try{if(await promises.readFile(p.path,"utf8")===p.content){p.executable&&await promises.chmod(p.path,493);continue}}catch{}await promises.mkdir(path.dirname(p.path),{recursive:true});let N=`${p.path}.tmp`;await promises.writeFile(N,p.content,"utf8"),await promises.rename(N,p.path),p.executable&&await promises.chmod(p.path,493);}}async function ht(e,t,r,a,c,d){await ne(e,t,r,a,c,u=>{let f=Date.now(),g=String(process.pid),b=H(u.instances,r),S=b[g]?.startedAt??f;return b[g]={pid:process.pid,port:d,host:Ve(t),protocol:ve(t),cacheDir:t.config.cacheDir,projectRoot:t.config.root,configFile:ut(t),startedAt:S,lastSeenAt:f},{updatedAt:f,instances:b}});}async function St(e,t,r,a,c){await ne(e,t,r,a,c,d=>{let u=Date.now(),f=String(process.pid),g=d.instances[f];if(!g)return d;let b=H(d.instances,r);return b[f]={...g,lastSeenAt:u},{updatedAt:u,instances:b}});}async function Rt(e,t,r,a,c){await ne(e,t,r,a,c,d=>{let u=Date.now(),f=H(d.instances,r);return delete f[String(process.pid)],{updatedAt:u,instances:f}});}function yt(e){let t={};for(let[r,a]of Object.entries(e))a!==void 0&&(typeof a=="string"?t[r]=a:Array.isArray(a)&&(t[r]=a.join(",")));return t}function Tt(e){return new Promise((t,r)=>{let a="";e.on("data",c=>{a+=c.toString();}),e.on("error",r),e.on("end",()=>{t(a||void 0);});})}function _t(e,t){let r=e===void 0?NaN:Number.parseInt(e,10);return Number.isFinite(r)&&r>=0?r:t}function Et(e){return typeof e=="string"&&e.length>0}function wt(e){return !(!y(e)||typeof e.id!="string"||typeof e.ok!="boolean")}function At(e){return !(!y(e)||typeof e.requestId!="string"||typeof e.tabId!="string"||!y(e.metadata)||"state"in e&&typeof e.state!="string")}function Q(e){let t=Date.now();if(!y(e))return {title:"",pathname:"",href:"",focused:false,wsUrl:"",userAgent:"",registeredAt:t,lastSeenAt:t};let r=typeof e.registeredAt=="number"?e.registeredAt:t,a=typeof e.lastSeenAt=="number"?e.lastSeenAt:t;return {title:typeof e.title=="string"?e.title:"",pathname:typeof e.pathname=="string"?e.pathname:"",href:typeof e.href=="string"?e.href:"",focused:typeof e.focused=="boolean"?e.focused:false,wsUrl:typeof e.wsUrl=="string"?e.wsUrl:"",userAgent:typeof e.userAgent=="string"?e.userAgent:"",registeredAt:r,lastSeenAt:a}}function A(e,t){let r=t-e;return r>et?"closed":r>Ze?"stale":"open"}function It(e={}){let t=new Map,r=new Map,a=new Map,c=e.removeFromListOnReload??false,d=e.instanceHeartbeatMs??ye,u=e.instanceTtlMs??tt,f=e.sessionFileName??e.registryFileName??K,g=e.registryRetries??nt,b=e.registryRetryDelayMs??rt,S=e.verboseServer??false,V=e.verboseClient??false,R="",T="",_,p,N=false,re=false;function oe(){_!==void 0&&(clearInterval(_),_=void 0);}async function ie(n){T=await st(n.config.root),R=ft(T,f);let i=ze;if(!await P(i))throw new Error(`vibro cli source file not found: ${i}`);await bt(T,i,R);}async function Pe(n){let i=p;if(i===void 0)return;(R.length<=0||T.length<=0)&&await ie(n);let o=Number.isFinite(d)&&d>0?d:ye;await ht(R,n,u,g,b,i),N=true,_!==void 0&&oe(),_=setInterval(()=>{St(R,n,u,g,b).catch(s=>{C("failed to touch Vite instance",s,S);});},o);}async function se(n){!R.length||!N||(N=false,oe(),await Rt(R,n,u,g,b));}function Ne(n){return new Promise((i,o)=>{let s=setTimeout(()=>{t.delete(n),o(new Error(`Bridge request timeout (${n})`));},Qe);t.set(n,{resolve:i,reject:o,timeout:s});})}function ke(n){let i=t.get(n.id);i&&(clearTimeout(i.timeout),t.delete(n.id),i.resolve(n));}function M(){let n=Date.now();return Array.from(a.values()).map(i=>({...i,state:A(i.metadata.lastSeenAt,n),metadata:{...i.metadata,lastSeenAt:i.metadata.lastSeenAt}}))}function Be(){let n=Date.now(),o=M().filter(l=>A(l.metadata.lastSeenAt,n)!=="closed");if(o.length<=0)return;let s=o.find(l=>l.metadata.focused);return s!==void 0?s.id:o[0].id}function ae(n,i,o){let s=Date.now(),l=Q(i),E=a.get(n),I={id:n,state:o??A(l.lastSeenAt,s),metadata:{...l,registeredAt:E?.metadata.registeredAt??l.registeredAt,lastSeenAt:s}};return a.set(n,I),I}function Fe(n,i,o){let s=Date.now();return i<=0?Promise.resolve(M().map(l=>({...l,state:A(l.metadata.lastSeenAt,s)}))):new Promise((l,E)=>{let I=setTimeout(()=>{ce(n);},o);r.set(n,{expected:i,resolve:l,reject:E,timeout:I,responses:new Map});})}function ce(n){let i=r.get(n);if(!i)return;clearTimeout(i.timeout),r.delete(n);let o=Date.now(),s=new Map;M().forEach(l=>{s.set(l.id,{...l,state:A(l.metadata.lastSeenAt,o)});}),i.responses.forEach(l=>{s.set(l.id,{...l,state:A(l.metadata.lastSeenAt,o)});}),i.resolve(Array.from(s.values()));}function De(n){let i=r.get(n.requestId);if(!i)return;let o=n.state??A(n.metadata.lastSeenAt,Date.now()),s={...Q(n.metadata),lastSeenAt:Date.now()},l=ae(n.tabId,s,o);i.responses.set(n.tabId,l),i.expected>0&&i.responses.size>=i.expected&&ce(n.requestId);}function J(n,i){if(!y(i))return;let o=i.tabId,s=i.metadata;if(!Et(o)||!y(s))return;let l=Q(s);ae(o,l);}function Me(n){let i=n.split("/").filter(Boolean);if(i.length<2)return;let o=i[0];if(!(o!=="ping"&&o!=="screenshot"))return {commandPath:`/${o}`,targetTabId:i[1]}}return {name:"vibro-plugin",apply:"serve",config(n){let i=vite.searchForWorkspaceRoot(process.cwd()),o=n.server?.fs?.allow,s=Array.isArray(o)?o:[];return {server:{fs:{allow:Ke([...s,i,Z,Se,Re(Z),Re(Se)])}}}},configureServer(n){let i=async()=>{if(p=ct(n),p!==void 0)try{if(await ie(n),await Pe(n),!re){let o=ve(n),s=Ve(n);S&&(console.info(` \u279C Registered Vibro ${s?`${o}://${s}:${p}`:`:${p}`}`),console.info(`[vibro] registry ready at ${s?`${o}://${s}:${p}`:`:${p}`}`),console.info(`[vibro] sessions: ${R}`),console.info(`[vibro] cli: ${D(T)}`)),re=!0;}}catch(o){C("failed to register Vite instance",o,S);}};n.httpServer?.listening?i():n.httpServer&&n.httpServer.once("listening",()=>{i();}),n.httpServer?.once("close",()=>{se(n).catch(o=>{C("failed to detach Vite instance",o,S);});}),c&&n.ws.on("vite:beforeFullReload",()=>{se(n).catch(o=>{C("failed to detach Vite instance on reload",o,S);});}),n.ws.on(fe,o=>{wt(o)&&ke(o);}),n.ws.on(W,o=>{J(W,o);}),n.ws.on(z,o=>{J(z,o);}),n.ws.on(Y,o=>{J(Y,o);}),n.ws.on(ge,o=>{At(o)&&De(o);}),n.middlewares.use(L,async(o,s,l)=>{if(!o.url||!o.method){l();return}let E=new URL(o.url,"http://localhost"),I=o.method.toUpperCase(),Oe=!["GET","HEAD"].includes(I),w={id:crypto.randomUUID(),path:E.pathname.startsWith(L)?E.pathname.substring(L.length)||"/":E.pathname,method:I,query:Object.fromEntries(E.searchParams.entries()),headers:yt(o.headers),body:Oe?await Tt(o).catch(()=>{}):void 0};if(S&&console.log(`[vibro] Received a signal: ${I} ${E}`),w.path==="/list"){let h=_t(w.query.timeout,Xe),k=w.id,$e=Date.now(),ue=M().map(O=>({...O,state:A(O.metadata.lastSeenAt,$e)})).filter(O=>O.state!=="closed").length,Ce=Fe(k,ue,h);ue>0&&n.ws.send(le,{requestId:k});let xe=await Ce;s.statusCode=200,s.setHeader("content-type","application/json; charset=utf-8"),s.end(JSON.stringify({ok:true,payload:{tabs:xe}}));return}let v,G=Me(w.path);if(G!==void 0?(v=G.targetTabId,w.path=G.commandPath):w.path==="/screenshot"&&(v=Be()),v!==void 0&&(w.targetTabId=v),v!==void 0){let h=a.get(v),k=Date.now();if(!h||A(h.metadata.lastSeenAt,k)==="closed"){s.statusCode=404,s.setHeader("content-type","application/json; charset=utf-8"),s.end(JSON.stringify({ok:false,error:`Unknown target tab: ${v}`}));return}}let Le=Ne(w.id);n.ws.send(de,w);try{let h=await Le;s.statusCode=h.ok?200:500,s.setHeader("content-type","application/json; charset=utf-8"),s.end(JSON.stringify({ok:h.ok,payload:h.payload,error:h.error}));}catch(h){let k=h instanceof Error?h.message:String(h);s.statusCode=504,s.setHeader("content-type","application/json; charset=utf-8"),s.end(JSON.stringify({ok:false,error:k}));}});},transformIndexHtml(n){return {html:n,tags:[{tag:"script",injectTo:"body-prepend",children:`window.__vibroVerboseClient = ${V};`},{tag:"script",injectTo:"body-prepend",attrs:{type:"module",src:Ye}}]}}}}
11
+ exports.vibroVitePlugin=It;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibro/bro",
3
- "version": "0.0.1-alpha.2",
3
+ "version": "0.0.1-alpha.3",
4
4
  "description": "Vibro plugin and runtime bridge",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -44,7 +44,11 @@
44
44
  "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
45
45
  },
46
46
  "files": [
47
- "dist",
47
+ "dist/vibro-plugin.js",
48
+ "dist/vibro-plugin.d.ts",
49
+ "dist/vibro-cli.js",
50
+ "dist/vibro-client.js",
51
+ "dist/vibro-client.d.mts",
48
52
  "package.json",
49
53
  "README.md",
50
54
  "LICENSE"