@zenovay/cli 0.1.14 → 0.1.16

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.
Files changed (57) hide show
  1. package/dist/{ai-bBoxoKB9.js → ai-QwPVHbiS.js} +1 -1
  2. package/dist/analytical-screen-DQwA5IZ1.js +1 -0
  3. package/dist/{api-BhdaCghp.js → api-0Qf43hhF.js} +1 -1
  4. package/dist/{api-v2-B03fp6KF.js → api-v2-DnMJJmhi.js} +1 -1
  5. package/dist/bin.js +1 -1
  6. package/dist/companies-BPwvvD2o.js +2 -0
  7. package/dist/config-Ddkbfelp.js +1 -0
  8. package/dist/deploys-BUnVkaEg.js +2 -0
  9. package/dist/{doctor-y7_iOaxP.js → doctor-DyNONZGx.js} +1 -1
  10. package/dist/errors-DND9r91m.js +2 -0
  11. package/dist/{events-tail-C35jGarq.js → events-tail-D6UfbRj7.js} +2 -2
  12. package/dist/funnel-BpMHOOaE.js +3 -0
  13. package/dist/health-B4NtoJtP.js +1 -0
  14. package/dist/{health-B_x_w2CV.js → health-B7BBVo2z.js} +1 -1
  15. package/dist/init-B9fjLwAP.js +62 -0
  16. package/dist/init-QiTMBqJb.js +1 -0
  17. package/dist/keybar-CWo5rhK_.js +1 -0
  18. package/dist/login-2h7PjSlW.js +1 -0
  19. package/dist/{login-DHLIZV8C.js → login-CpJeUOCR.js} +1 -1
  20. package/dist/{logout-DvGiNVs9.js → logout-DBIL_bPH.js} +1 -1
  21. package/dist/projects-CYmKX2WM.js +2 -0
  22. package/dist/prompt-B1QrBhyZ.js +3 -0
  23. package/dist/query-DD6ZGKsY.js +8 -0
  24. package/dist/resolve-site-CPY8XSeq.js +2 -0
  25. package/dist/revenue-C6YPnOvr.js +2 -0
  26. package/dist/sources-BYSCTIBA.js +2 -0
  27. package/dist/stats-C0AJtjVS.js +2 -0
  28. package/dist/{themes-F-HUBXpr.js → themes-Bhj-4q-r.js} +1 -1
  29. package/dist/{ui-Bk5nl2yb.js → ui-CVGR9Ffn.js} +1 -1
  30. package/dist/{update-2SafBiSk.js → update-CgGLjHBM.js} +1 -1
  31. package/dist/use-jF2EdP8H.js +5 -0
  32. package/dist/vitals-rttZVRnn.js +2 -0
  33. package/dist/watch-Bgjke7jm.js +1 -0
  34. package/dist/{webhooks-forward-QnE7MdSy.js → webhooks-forward-DQaXTq3w.js} +1 -1
  35. package/dist/wizard-bin.js +1 -1
  36. package/package.json +1 -1
  37. package/dist/analytical-screen-Boiw3NTp.js +0 -1
  38. package/dist/companies-Z4LkcGcD.js +0 -3
  39. package/dist/config-ZTGpKEWg.js +0 -1
  40. package/dist/deploys-28qQkagZ.js +0 -3
  41. package/dist/errors-CUUuLToC.js +0 -3
  42. package/dist/funnel-BCa_5jW3.js +0 -4
  43. package/dist/health-D-nDYCrN.js +0 -1
  44. package/dist/init-C6maV1Ia.js +0 -1
  45. package/dist/init-DacZiEma.js +0 -62
  46. package/dist/keybar-D2OI-8rx.js +0 -3
  47. package/dist/login-D4kNEDVO.js +0 -1
  48. package/dist/projects-BCK7Jspy.js +0 -3
  49. package/dist/prompt-hjzdzlyj.js +0 -1
  50. package/dist/query-B8PDpxhG.js +0 -9
  51. package/dist/revenue-39qQFWdR.js +0 -3
  52. package/dist/sources-BzZK-YOD.js +0 -3
  53. package/dist/stats-CstuCrtH.js +0 -3
  54. package/dist/vitals-D_r_rBbw.js +0 -3
  55. package/dist/watch-CtIJ1ZAz.js +0 -2
  56. /package/dist/{check-S0ACFIfq.js → check-CmOnrU4W.js} +0 -0
  57. /package/dist/{completions-GDtTbG3B.js → completions-Bqs_uGx6.js} +0 -0
@@ -0,0 +1,3 @@
1
+ import{BRAND_GRADIENT as e,useTheme as t}from"./panel-DglZ755S.js";import{Box as n,Text as r,useInput as i}from"ink";import a,{useCallback as o,useState as s}from"react";import c from"ink-select-input";import l from"ink-text-input";function u(e){let t=e.replace(`#`,``).trim(),n=t.length===3?t.split(``).map(e=>e+e).join(``):t,r=parseInt(n.slice(0,2),16),i=parseInt(n.slice(2,4),16),a=parseInt(n.slice(4,6),16);return{r:Number.isNaN(r)?0:r,g:Number.isNaN(i)?0:i,b:Number.isNaN(a)?0:a}}function d({r:e,g:t,b:n}){let r=e=>{let t=Math.max(0,Math.min(255,Math.round(e)));return t.toString(16).padStart(2,`0`)};return`#${r(e)}${r(t)}${r(n)}`}function f(e,t,n){return{r:e.r+(t.r-e.r)*n,g:e.g+(t.g-e.g)*n,b:e.b+(t.b-e.b)*n}}function p(e,t,n,i){if(e.length===0)return[];if(e.length===1)return[a.createElement(r,{key:`${i}-0`,color:d(t)},e)];let o=Array.from(e),s=o.length-1;return o.map((e,o)=>{let c=o/s,l=d(f(t,n,c));return a.createElement(r,{key:`${i}-${o}`,color:l},e)})}function m({from:e,to:t,children:n}){let i=u(e),o=u(t),s=n.split(`
2
+ `),c=[];return s.forEach((e,t)=>{t>0&&c.push(a.createElement(r,{key:`nl-${t}`},`
3
+ `));let n=p(e,i,o,`l${t}`);c.push(...n)}),a.createElement(r,null,c)}function h({children:t}){return a.createElement(m,{from:e.from,to:e.to},t)}function g(){let e=process.stdout.columns;return typeof e==`number`&&e>0?e:80}function _({version:e,subtitle:i}){let{theme:o}=t(),s=g(),c=`ZENOVAY · v${e}`,l=`╭─ `,u=` `,d=`─╮`,f=l.length+c.length+u.length+d.length,p=Math.max(2,s-f),m=`─`.repeat(p),_=`─`.repeat(Math.max(2,s-2)),v=i??``,y=v.slice(0,Math.max(0,s-4)),b=` `.repeat(Math.max(1,s-2-1-y.length-1));return a.createElement(n,{flexDirection:`column`},a.createElement(n,{flexDirection:`row`},a.createElement(r,{color:o.border},l),a.createElement(h,null,c),a.createElement(r,{color:o.border},u,m,d)),i?a.createElement(n,{flexDirection:`row`},a.createElement(r,{color:o.border},`│ `),a.createElement(r,{color:o.muted},y),a.createElement(r,{color:o.border},b,`│`)):null,a.createElement(n,{flexDirection:`row`},a.createElement(r,{color:o.border},`╰`,_,`╯`)))}function v({hints:e}){let{theme:n}=t();return a.createElement(r,{color:n.dim},e)}function y({items:e,onSelect:i}){let{theme:l}=t(),[u,d]=s(e[0]),f=o(e=>{i(e.value)},[i]),p=o(e=>{d(e)},[]);return a.createElement(n,{flexDirection:`column`},a.createElement(c,{items:e.map((e,t)=>({key:`${t}`,label:e.label,value:e.value})),onSelect:t=>{let n=e.find(e=>e.value===t.value);n&&f(n)},onHighlight:t=>{let n=e.find(e=>e.value===t.value);n&&p(n)}}),u?.description?a.createElement(n,{marginTop:1},a.createElement(r,{color:l.muted},u.description)):null,a.createElement(n,{marginTop:1},a.createElement(v,{hints:`[↑↓/jk nav] [enter select]`})))}function b({question:e,onSubmit:i,placeholder:o,mask:c}){let{theme:u}=t(),[d,f]=s(``);return a.createElement(n,{flexDirection:`column`},a.createElement(n,null,a.createElement(r,{color:u.fg},e,` `),a.createElement(l,{value:d,onChange:f,onSubmit:e=>i(e),placeholder:o,mask:c?`•`:void 0})),a.createElement(v,{hints:`[enter submit]`}))}export{_ as Banner,h as BrandGradient,y as Select,b as TextInput};
@@ -0,0 +1,8 @@
1
+ import{readConfig as e}from"./config-Ddkbfelp.js";import{readToken as t}from"./api-0Qf43hhF.js";import{formatTabular as n,selectFormat as r}from"./formatter-45-fT1Hv.js";import{Panel as i}from"./panel-DglZ755S.js";import{Banner as a}from"./prompt-B1QrBhyZ.js";import"./keybar-CWo5rhK_.js";import"./sparkline-CR_bzxwB.js";import{Table as o}from"./ui-CVGR9Ffn.js";import{resolveSiteId as s}from"./resolve-site-CPY8XSeq.js";import{ApiV2Client as c}from"./api-v2-DnMJJmhi.js";import{Box as l,Text as u,useApp as d,useInput as f}from"ink";import p,{useMemo as m,useState as h}from"react";import g from"ink-text-input";function _({api:e,siteId:t,maxRows:n}){let{exit:r}=d(),[s,c]=h(``),[_,v]=h(null),[y,b]=h(null),[x,S]=h(!1),[C,w]=h([]);f((e,t)=>{t.escape&&r()});let T=async i=>{if(i.trim()){if(i.trim()===`\\q`||i.trim()===`exit`||i.trim()===`quit`){r();return}w(e=>[...e,i]),S(!0),b(null);try{let r=await e.runSqlQuery(t,i,{maxRows:n});v(r)}catch(e){b(e.message),v(null)}finally{S(!1),c(``)}}},E=m(()=>_?_.columns.map(e=>({key:e,header:e,width:18,format:e=>e==null?`∅`:String(e).slice(0,18)})):[],[_]);return p.createElement(l,{flexDirection:`column`},p.createElement(a,{version:`query`}),p.createElement(i,{title:`History`,state:`idle`},C.length===0?p.createElement(u,{color:`gray`},`— no queries yet — Esc or \\q to exit —`):C.slice(-5).map((e,t)=>p.createElement(u,{key:t,color:`gray`},`> ${e.slice(0,80)}${e.length>80?`…`:``}`))),p.createElement(l,null,p.createElement(u,{color:`magenta`},`sql`,`>`,` `),p.createElement(g,{value:s,onChange:c,onSubmit:T})),x?p.createElement(u,{color:`gray`},`running…`):null,y?p.createElement(i,{title:`Error`,state:`err`},p.createElement(u,{color:`red`},y)):null,_?p.createElement(i,{title:`${_.row_count} rows · ${_.duration_ms}ms${_.truncated?` · truncated`:``}`,state:`ok`},_.row_count===0?p.createElement(u,{color:`gray`},`— empty —`):p.createElement(o,{data:_.rows.slice(0,50),columns:E})):null)}async function v(i){let a=await e(),o=await t({strict:!1}),l=new c({config:a,cliVersion:i.cliVersion,token:o}),u;try{({siteId:u}=await s(l,{explicit:i.siteId,headless:!!(i.json||i.csv||i.tsv||i.ndjson),cliVersion:i.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let d=i.maxRows??1e3,f=r(i);if(i.sql)try{let e=await l.runSqlQuery(u,i.sql,{maxRows:d});if(f===`json`)process.stdout.write(JSON.stringify(e,null,2)),process.stdout.write(`
2
+ `);else if(f===`ndjson`)for(let t of e.rows)process.stdout.write(JSON.stringify(t)+`
3
+ `);else if(f===`csv`||f===`tsv`)process.stdout.write(n(e.rows,e.columns,f));else{let t=e.columns.map(t=>Math.max(t.length,...e.rows.map(e=>String(e[t]??``).length))),n=`+`+t.map(e=>`-`.repeat(e+2)).join(`+`)+`+`;process.stdout.write(n+`
4
+ `),process.stdout.write(`|`+e.columns.map((e,n)=>` ${e.padEnd(t[n]??0)} `).join(`|`)+`|
5
+ `),process.stdout.write(n+`
6
+ `);for(let n of e.rows.slice(0,200))process.stdout.write(`|`+e.columns.map((e,r)=>` ${String(n[e]??``).padEnd(t[r]??0)} `).join(`|`)+`|
7
+ `);process.stdout.write(n+`
8
+ `),process.stdout.write(`${e.row_count} rows · ${e.duration_ms}ms${e.truncated?` · truncated`:``}\n`)}return 0}catch(e){return process.stderr.write(`✗ ${e.message}\n`),1}let{render:m}=await import(`ink`);return await m(p.createElement(_,{api:l,siteId:u,maxRows:d})).waitUntilExit(),0}export{v as queryCommand};
@@ -0,0 +1,2 @@
1
+ import{readConfig as e,updateConfig as t}from"./config-Ddkbfelp.js";import{Panel as n}from"./panel-DglZ755S.js";import{Banner as r,Select as i}from"./prompt-B1QrBhyZ.js";import{Box as a,Text as o,render as s}from"ink";import c from"react";async function l(n,r){if(r.explicit&&r.explicit.trim())return{siteId:r.explicit.trim(),saved:!1};let i=await e(),a;try{a=await n.getSites()}catch(e){if(i.defaultSiteId)return{siteId:i.defaultSiteId,saved:!1};throw Error(`Could not fetch your sites (${e.message}). Pass --site-id <ID> to bypass.`)}if(i.defaultSiteId){let e=a.find(e=>e.id===i.defaultSiteId);if(e)return{siteId:e.id,site:e,saved:!1};await t({defaultSiteId:void 0,defaultSiteName:void 0})}if(a.length===0)throw Error("No sites in your account. Run `zenovay init` to add one, or create one at app.zenovay.com.");if(a.length===1){let e=a[0];return await t({defaultSiteId:e.id,defaultSiteName:e.name}),{siteId:e.id,site:e,saved:!0}}if(r.headless||!process.stdout.isTTY){let e=a.map(e=>` ${e.name.padEnd(24)} ${e.url.padEnd(36)} ${e.id}`).join(`
2
+ `);throw Error(`Multiple sites found — pick one:\n${e}\n\nPass --site-id <ID>, set ZENOVAY_SITE=<ID>, or run \`zenovay use <domain>\` to set a default.`)}let o=await u(a,r.cliVersion);return await t({defaultSiteId:o.id,defaultSiteName:o.name}),{siteId:o.id,site:o,saved:!0}}function u(e,t=`0`){return new Promise((n,r)=>{let i,a=e=>{i?.(),n(e)},o=()=>{i?.(),r(Error(`Site selection cancelled`))},l=s(c.createElement(d,{sites:e,cliVersion:t,onPick:a,onCancel:o}));i=l.unmount})}const d=({sites:e,cliVersion:t,onPick:s})=>{let l=e.map(e=>({label:`${e.name.padEnd(28)} ${e.url.replace(/^https?:\/\//,``).padEnd(28)}`,value:e,description:e.trackingCode?`tracking: ${e.trackingCode}`:void 0}));return c.createElement(a,{flexDirection:`column`},c.createElement(r,{version:t,subtitle:`pick a site`}),c.createElement(n,{title:`Which site?`,state:`idle`},c.createElement(a,{marginBottom:1},c.createElement(o,{color:`gray`},"We'll save your pick as the default — re-run with `zenovay use --reset` to change it.")),c.createElement(i,{items:l,onSelect:s})))};export{l as resolveSiteId};
@@ -0,0 +1,2 @@
1
+ import{readConfig as e}from"./config-Ddkbfelp.js";import{readToken as t}from"./api-0Qf43hhF.js";import{formatTabular as n,selectFormat as r}from"./formatter-45-fT1Hv.js";import"./panel-DglZ755S.js";import"./prompt-B1QrBhyZ.js";import"./keybar-CWo5rhK_.js";import{spark as i}from"./sparkline-CR_bzxwB.js";import{runAnalyticalScreen as a}from"./analytical-screen-DQwA5IZ1.js";import"./ui-CVGR9Ffn.js";import{resolveSiteId as o}from"./resolve-site-CPY8XSeq.js";import{ApiV2Client as s}from"./api-v2-DnMJJmhi.js";import{Box as c,Text as l}from"ink";import u from"react";function d(e,t){let n=e/100,r=new Intl.NumberFormat(`en-US`,{minimumFractionDigits:0,maximumFractionDigits:0}).format(n),i=(t||`USD`).toUpperCase();return i===`USD`?`$${r}`:i===`EUR`?`€${r}`:i===`GBP`?`£${r}`:`${r} ${i}`}async function f(f){let p=await e(),m=await t({strict:!1}),h=new s({config:p,cliVersion:f.cliVersion,token:m}),g;try{({siteId:g}=await o(h,{explicit:f.siteId,headless:!!(f.json||f.csv||f.tsv||f.ndjson),cliVersion:f.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let _=r(f),v=f.range??`30d`;return a({cliVersion:f.cliVersion,title:`revenue · ${g} · ${v}`,commandName:`revenue`,authToken:m?.accessToken??null,refreshIntervalMs:f.watch?5*6e4:0,fetcher:e=>h.getRevenue(g,v,e),format:_,headlessEmit:(e,t)=>{if(t===`json`||t===`ndjson`){process.stdout.write(JSON.stringify(e,null,t===`json`?2:0)),t===`ndjson`&&process.stdout.write(`
2
+ `);return}process.stdout.write(n(e.series,[`bucket`,`amount`,`currency`,`transactions`],t))},panels:[{id:`totals`,title:`Top line`,render:e=>u.createElement(c,{flexDirection:`column`},u.createElement(l,null,u.createElement(l,{color:`green`,bold:!0},d(e.totalAmount,e.currency)),` `,u.createElement(l,{color:`gray`},`total · `,e.totalTransactions,` transactions`)),typeof e.mrr==`number`?u.createElement(l,null,u.createElement(l,{bold:!0},`MRR `),u.createElement(l,{color:`magenta`},d(e.mrr,e.currency)),typeof e.arpu==`number`?u.createElement(l,{color:`gray`},` · ARPU `,d(e.arpu,e.currency)):null):null)},{id:`series`,title:`Daily (${v})`,render:e=>{let t=e.series.map(e=>e.amount);if(t.length===0)return u.createElement(l,{color:`gray`},`— no transactions —`);let n=Math.max(...t,1);return u.createElement(c,{flexDirection:`column`},u.createElement(l,{color:`magenta`},i(t,Math.min(60,t.length*2))),u.createElement(l,{color:`gray`},`peak: `,d(n,e.currency),` ·`,` `,`avg: `,d(e.totalAmount/Math.max(1,t.length),e.currency)))}},{id:`window`,title:`Window`,render:e=>u.createElement(l,{color:`gray`},new Date(e.windowStart).toISOString().slice(0,10),` →`,` `,new Date(e.windowEnd).toISOString().slice(0,10))}]})}export{f as revenueCommand};
@@ -0,0 +1,2 @@
1
+ import{readConfig as e}from"./config-Ddkbfelp.js";import{readToken as t}from"./api-0Qf43hhF.js";import{formatTabular as n,selectFormat as r}from"./formatter-45-fT1Hv.js";import"./panel-DglZ755S.js";import"./prompt-B1QrBhyZ.js";import"./keybar-CWo5rhK_.js";import"./sparkline-CR_bzxwB.js";import{runAnalyticalScreen as i}from"./analytical-screen-DQwA5IZ1.js";import{Table as a}from"./ui-CVGR9Ffn.js";import{resolveSiteId as o}from"./resolve-site-CPY8XSeq.js";import{ApiV2Client as s}from"./api-v2-DnMJJmhi.js";import{Box as c,Text as l}from"ink";import u from"react";function d(e,t){let n=Math.round(e/100*t);return`█`.repeat(n)+`░`.repeat(Math.max(0,t-n))}function f(e){return e==null?{glyph:`·`,color:`gray`}:e>.5?{glyph:`▲`,color:`green`}:e<-.5?{glyph:`▼`,color:`red`}:{glyph:`→`,color:`gray`}}async function p(p){let m=await e(),h=await t({strict:!1}),g=new s({config:m,cliVersion:p.cliVersion,token:h}),_;try{({siteId:_}=await o(g,{explicit:p.siteId,headless:!!(p.json||p.csv||p.tsv||p.ndjson),cliVersion:p.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let v=r(p),y=p.period??`30d`,b=[{key:`source`,header:`source`,width:22},{key:`channel`,header:`channel`,width:10,format:e=>String(e??`—`)},{key:`visitors`,header:`visitors`,width:8,align:`right`},{key:`delta`,header:`Δ`,width:6,align:`right`,format:e=>typeof e==`number`?`${e>0?`+`:``}${(e*100).toFixed(1)}%`:`—`}];return i({cliVersion:p.cliVersion,title:`sources · ${_} · ${y}`,commandName:`sources`,authToken:h?.accessToken??null,refreshIntervalMs:6e4,fetcher:e=>g.getSources(_,y,p.compare,e),format:v,headlessEmit:(e,t)=>{if(t===`json`||t===`ndjson`){process.stdout.write(JSON.stringify(e,null,t===`json`?2:0)),t===`ndjson`&&process.stdout.write(`
2
+ `);return}process.stdout.write(n(e.sources,[`source`,`channel`,`visitors`,`conversions`,`revenue`,`delta`],t))},panels:[{id:`summary`,title:`Total`,render:e=>u.createElement(l,null,u.createElement(l,{bold:!0},e.totalVisitors.toLocaleString()),` `,u.createElement(l,{color:`gray`},`visitors · `,e.sources.length,` sources`))},{id:`channels`,title:`By channel`,render:e=>{if(e.sources.length===0)return u.createElement(l,{color:`gray`},`— no source data —`);let t=e.totalVisitors||1,n=[...e.sources].sort((e,t)=>t.visitors-e.visitors).slice(0,12);return u.createElement(c,{flexDirection:`column`},n.map((e,n)=>{let r=e.visitors/t*100,i=f(e.delta);return u.createElement(c,{key:`${e.source}-${n}`},u.createElement(l,null,u.createElement(l,{color:`cyan`},e.source.padEnd(20).slice(0,20)),` `,u.createElement(l,{color:`magenta`},d(r,30)),` `,u.createElement(l,null,e.visitors.toString().padStart(6),` `),u.createElement(l,{color:`gray`},`(`,r.toFixed(1),`%)`),` `,u.createElement(l,{color:i.color},i.glyph)))}))}},{id:`table`,title:`Detail`,render:e=>e.sources.length===0?u.createElement(l,{color:`gray`},`— —`):u.createElement(a,{data:e.sources.slice(0,20),columns:b})}]})}export{p as sourcesCommand};
@@ -0,0 +1,2 @@
1
+ import{readConfig as e}from"./config-Ddkbfelp.js";import{readToken as t}from"./api-0Qf43hhF.js";import{formatTabular as n,selectFormat as r}from"./formatter-45-fT1Hv.js";import"./panel-DglZ755S.js";import"./prompt-B1QrBhyZ.js";import"./keybar-CWo5rhK_.js";import"./sparkline-CR_bzxwB.js";import{runAnalyticalScreen as i}from"./analytical-screen-DQwA5IZ1.js";import{Table as a}from"./ui-CVGR9Ffn.js";import{resolveSiteId as o}from"./resolve-site-CPY8XSeq.js";import{ApiV2Client as s}from"./api-v2-DnMJJmhi.js";import{Box as c,Text as l}from"ink";import u from"react";function d(e){return`${(e*100).toFixed(1)}%`}function f(e){return e<60?`${Math.round(e)}s`:e<3600?`${Math.floor(e/60)}m ${Math.round(e%60)}s`:`${Math.floor(e/3600)}h ${Math.floor(e%3600/60)}m`}async function p(p){let m=await e(),h=await t({strict:!1}),g=new s({config:m,cliVersion:p.cliVersion,token:h}),_;try{({siteId:_}=await o(g,{explicit:p.siteId,headless:!!(p.json||p.csv||p.tsv||p.ndjson),cliVersion:p.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let v=r(p),y=p.range??`24h`,b=[{key:`url`,header:`page`,width:40,format:e=>String(e??`—`)},{key:`views`,header:`views`,width:8,align:`right`}],x=[{key:`country`,header:`country`,width:8},{key:`visitors`,header:`visitors`,width:8,align:`right`}];return i({cliVersion:p.cliVersion,title:`stats · ${_} · ${y}`,commandName:`stats`,authToken:h?.accessToken??null,refreshIntervalMs:p.watch?6e4:0,fetcher:e=>g.getStats(_,y,e),format:v,headlessEmit:(e,t)=>{if(t===`json`||t===`ndjson`){process.stdout.write(JSON.stringify(e,null,t===`json`?2:0)),t===`ndjson`&&process.stdout.write(`
2
+ `);return}process.stdout.write(n([{range:y,visitors:e.visitors,pageviews:e.pageviews,sessions:e.sessions,bounceRate:d(e.bounceRate),avgSession:f(e.avgSessionSec)}],[`range`,`visitors`,`pageviews`,`sessions`,`bounceRate`,`avgSession`],t))},panels:[{id:`summary`,title:`Summary`,render:e=>u.createElement(c,{flexDirection:`column`},u.createElement(l,null,u.createElement(l,{bold:!0},e.visitors.toLocaleString()),u.createElement(l,{color:`gray`},` visitors `),u.createElement(l,{bold:!0},e.pageviews.toLocaleString()),u.createElement(l,{color:`gray`},` pageviews `),u.createElement(l,{bold:!0},e.sessions.toLocaleString()),u.createElement(l,{color:`gray`},` sessions`)),u.createElement(l,{color:`gray`},`bounce `,d(e.bounceRate),` · avg session `,f(e.avgSessionSec)))},{id:`pages`,title:`Top pages`,render:e=>e.topPages.length===0?u.createElement(l,{color:`gray`},`— no pages —`):u.createElement(a,{data:e.topPages.slice(0,10),columns:b})},{id:`countries`,title:`Top countries`,render:e=>e.topCountries.length===0?u.createElement(l,{color:`gray`},`— no country data —`):u.createElement(a,{data:e.topCountries.slice(0,10),columns:x})}]})}export{p as statsCommand};
@@ -1,4 +1,4 @@
1
- import{dracula as e,latte as t,mocha as n,nord as r,tokyoNight as i}from"./panel-DglZ755S.js";import{Banner as a}from"./keybar-D2OI-8rx.js";import"./prompt-hjzdzlyj.js";import"./sparkline-CR_bzxwB.js";import"./ui-Bk5nl2yb.js";import{promises as o}from"node:fs";import{Box as s,Text as c,render as l}from"ink";import u from"react";const d=[{name:`mocha`,theme:n,mode:`dark`},{name:`latte`,theme:t,mode:`light`},{name:`dracula`,theme:e,mode:`dark`},{name:`tokyoNight`,theme:i,mode:`dark`},{name:`nord`,theme:r,mode:`dark`}],f=[`name`,`bg`,`fg`,`muted`,`accent`,`accent2`,`success`,`warn`,`error`,`border`,`dim`];function p({name:e,theme:t,mode:n}){let r=[t.accent,t.accent2,t.success,t.warn,t.error];return u.createElement(s,{flexDirection:`row`},u.createElement(c,{bold:!0},e.padEnd(14)),u.createElement(c,{color:`gray`},n.padEnd(7)),r.map((e,t)=>u.createElement(c,{key:t,color:e},`████`,` `)),u.createElement(c,{color:`gray`},t.bg))}function m({themes:e}){return u.createElement(s,{flexDirection:`column`},u.createElement(a,{version:`themes`}),u.createElement(s,{marginTop:1,marginBottom:1},u.createElement(c,{color:`gray`},e.length,` themes — pass --theme <name> to any command, or set in your config.`)),u.createElement(s,{flexDirection:`column`},u.createElement(s,null,u.createElement(c,{bold:!0},`name`.padEnd(14)),u.createElement(c,{bold:!0},`mode`.padEnd(7)),u.createElement(c,{bold:!0},`swatch`.padEnd(28)),u.createElement(c,{bold:!0},`bg`)),e.map(({name:e,theme:t,mode:n})=>u.createElement(p,{key:e,name:e,theme:t,mode:n}))))}async function h(e){if(e.validate){let t;try{let n=await o.readFile(e.validate,`utf8`);t=JSON.parse(n)}catch(t){return process.stderr.write(`✗ Failed to read ${e.validate}: ${t.message}\n`),1}let n=f.filter(e=>t[e]==null);return n.length>0?(process.stderr.write(`✗ Missing required tokens: ${n.join(`, `)}\n`),e.json&&process.stdout.write(JSON.stringify({ok:!1,missing:n},null,2)+`
1
+ import{dracula as e,latte as t,mocha as n,nord as r,tokyoNight as i}from"./panel-DglZ755S.js";import{Banner as a}from"./prompt-B1QrBhyZ.js";import"./keybar-CWo5rhK_.js";import"./sparkline-CR_bzxwB.js";import"./ui-CVGR9Ffn.js";import{promises as o}from"node:fs";import{Box as s,Text as c,render as l}from"ink";import u from"react";const d=[{name:`mocha`,theme:n,mode:`dark`},{name:`latte`,theme:t,mode:`light`},{name:`dracula`,theme:e,mode:`dark`},{name:`tokyoNight`,theme:i,mode:`dark`},{name:`nord`,theme:r,mode:`dark`}],f=[`name`,`bg`,`fg`,`muted`,`accent`,`accent2`,`success`,`warn`,`error`,`border`,`dim`];function p({name:e,theme:t,mode:n}){let r=[t.accent,t.accent2,t.success,t.warn,t.error];return u.createElement(s,{flexDirection:`row`},u.createElement(c,{bold:!0},e.padEnd(14)),u.createElement(c,{color:`gray`},n.padEnd(7)),r.map((e,t)=>u.createElement(c,{key:t,color:e},`████`,` `)),u.createElement(c,{color:`gray`},t.bg))}function m({themes:e}){return u.createElement(s,{flexDirection:`column`},u.createElement(a,{version:`themes`}),u.createElement(s,{marginTop:1,marginBottom:1},u.createElement(c,{color:`gray`},e.length,` themes — pass --theme <name> to any command, or set in your config.`)),u.createElement(s,{flexDirection:`column`},u.createElement(s,null,u.createElement(c,{bold:!0},`name`.padEnd(14)),u.createElement(c,{bold:!0},`mode`.padEnd(7)),u.createElement(c,{bold:!0},`swatch`.padEnd(28)),u.createElement(c,{bold:!0},`bg`)),e.map(({name:e,theme:t,mode:n})=>u.createElement(p,{key:e,name:e,theme:t,mode:n}))))}async function h(e){if(e.validate){let t;try{let n=await o.readFile(e.validate,`utf8`);t=JSON.parse(n)}catch(t){return process.stderr.write(`✗ Failed to read ${e.validate}: ${t.message}\n`),1}let n=f.filter(e=>t[e]==null);return n.length>0?(process.stderr.write(`✗ Missing required tokens: ${n.join(`, `)}\n`),e.json&&process.stdout.write(JSON.stringify({ok:!1,missing:n},null,2)+`
2
2
  `),1):(process.stdout.write(`✔ Valid theme (${f.length} tokens present).\n`),e.json&&process.stdout.write(JSON.stringify({ok:!0,theme:t},null,2)+`
3
3
  `),0)}if(e.json)return process.stdout.write(JSON.stringify({themes:d.map(({name:e,theme:t,mode:n})=>({name:e,mode:n,background:t.bg,foreground:t.fg,accent:t.accent}))},null,2)+`
4
4
  `),0;let{waitUntilExit:t}=l(u.createElement(m,{themes:d}));return await t(),0}export{h as themesCommand};
@@ -1 +1 @@
1
- import{useTheme as e}from"./panel-DglZ755S.js";import{BrandGradient as t}from"./keybar-D2OI-8rx.js";import{Box as n,Text as r,useInput as i}from"ink";import a,{useMemo as o,useState as s}from"react";import"diff";function c(e,t){return e.length<=t?e:t<=1?e.slice(0,t):`${e.slice(0,t-1)}…`}function l(e,t,n){if(e.length>=t)return c(e,t);let r=t-e.length;if(n===`right`)return` `.repeat(r)+e;if(n===`center`){let t=Math.floor(r/2),n=r-t;return` `.repeat(t)+e+` `.repeat(n)}return e+` `.repeat(r)}function u(e,t){return e.map(e=>{if(typeof e.width==`number`&&e.width>0)return e.width;let n=e.header.length;for(let r of t){let t=r[e.key],i=e.format?e.format(t,r):String(t??``);i.length>n&&(n=i.length)}return Math.max(3,n)})}function d({columns:i,data:o,zebra:s=!1}){let{theme:c}=e(),d=u(i,o),f=d.reduce((e,t)=>e+t,0)+i.length*3+1,p=(e,t,n)=>{let r=e;return d.forEach((e,i)=>{r+=`─`.repeat(e+2),r+=i===d.length-1?n:t}),r},m=p(`╭`,`┬`,`╮`),h=p(`├`,`┼`,`┤`),g=p(`╰`,`┴`,`╯`),_=i.map((e,t)=>l(e.header,d[t]??e.header.length,e.align??`left`)).join(` │ `);return a.createElement(n,{flexDirection:`column`,width:f},a.createElement(r,{color:c.border},m),a.createElement(n,{flexDirection:`row`},a.createElement(r,{color:c.border},`│ `),a.createElement(t,null,_),a.createElement(r,{color:c.border},` │`)),a.createElement(r,{color:c.border},h),o.map((e,t)=>{let o=s&&t%2==1,u=o?c.muted:c.fg,f=i.map((t,n)=>{let r=e[t.key],i=t.format?t.format(r,e):String(r??``);return l(i,d[n]??i.length,t.align??`left`)}).join(` │ `);return a.createElement(n,{key:t,flexDirection:`row`},a.createElement(r,{color:c.border},`│ `),a.createElement(r,{color:u},f),a.createElement(r,{color:c.border},` │`))}),a.createElement(r,{color:c.border},g))}export{d as Table};
1
+ import{useTheme as e}from"./panel-DglZ755S.js";import{BrandGradient as t}from"./prompt-B1QrBhyZ.js";import{Box as n,Text as r,useInput as i}from"ink";import a,{useMemo as o,useState as s}from"react";import"diff";function c(e,t){return e.length<=t?e:t<=1?e.slice(0,t):`${e.slice(0,t-1)}…`}function l(e,t,n){if(e.length>=t)return c(e,t);let r=t-e.length;if(n===`right`)return` `.repeat(r)+e;if(n===`center`){let t=Math.floor(r/2),n=r-t;return` `.repeat(t)+e+` `.repeat(n)}return e+` `.repeat(r)}function u(e,t){return e.map(e=>{if(typeof e.width==`number`&&e.width>0)return e.width;let n=e.header.length;for(let r of t){let t=r[e.key],i=e.format?e.format(t,r):String(t??``);i.length>n&&(n=i.length)}return Math.max(3,n)})}function d({columns:i,data:o,zebra:s=!1}){let{theme:c}=e(),d=u(i,o),f=d.reduce((e,t)=>e+t,0)+i.length*3+1,p=(e,t,n)=>{let r=e;return d.forEach((e,i)=>{r+=`─`.repeat(e+2),r+=i===d.length-1?n:t}),r},m=p(`╭`,`┬`,`╮`),h=p(`├`,`┼`,`┤`),g=p(`╰`,`┴`,`╯`),_=i.map((e,t)=>l(e.header,d[t]??e.header.length,e.align??`left`)).join(` │ `);return a.createElement(n,{flexDirection:`column`,width:f},a.createElement(r,{color:c.border},m),a.createElement(n,{flexDirection:`row`},a.createElement(r,{color:c.border},`│ `),a.createElement(t,null,_),a.createElement(r,{color:c.border},` │`)),a.createElement(r,{color:c.border},h),o.map((e,t)=>{let o=s&&t%2==1,u=o?c.muted:c.fg,f=i.map((t,n)=>{let r=e[t.key],i=t.format?t.format(r,e):String(r??``);return l(i,d[n]??i.length,t.align??`left`)}).join(` │ `);return a.createElement(n,{key:t,flexDirection:`row`},a.createElement(r,{color:c.border},`│ `),a.createElement(r,{color:u},f),a.createElement(r,{color:c.border},` │`))}),a.createElement(r,{color:c.border},g))}export{d as Table};
@@ -1 +1 @@
1
- import{readConfig as e}from"./config-ZTGpKEWg.js";import"./formatter-45-fT1Hv.js";import{emit as t,isHeadless as n}from"./emit-0WJ_OGeT.js";import{classifyBump as r,fetchManifest as i,platformKey as a}from"./check-S0ACFIfq.js";import o from"node:path";import{promises as s}from"node:fs";import c from"node:os";import l from"node:crypto";import u from"semver";const d=`AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=`;async function f(e){let t=await i({cliBase:e.cliBase,fetchImpl:e.fetchImpl});return p({...e,manifest:t})}async function p(e){let{manifest:t,currentVersion:n,forceDowngrade:i}=e,o=r(n,t.latest);if(o===`none`)return{updated:!1,from:n,to:t.latest,reason:`already-latest`};if(o===`downgrade`&&!i)return{updated:!1,from:n,to:t.latest,reason:`downgrade-blocked`};t.minSupported&&u.lt(n,t.minSupported);let c=a(),l=t.platforms[c];if(!l)throw Error(`No release binary for platform ${c}`);let d=await m(l,e.fetchImpl);try{return await h(d,l.sha256),await g(l,t.latest,c),await _(d,e.binaryPath),{updated:!0,from:n,to:t.latest}}catch(e){throw await s.unlink(d).catch(()=>void 0),e}}async function m(e,t=fetch){let n=await t(e.url);if(!n.ok)throw Error(`Download failed: ${n.status}`);let r=Buffer.from(await n.arrayBuffer()),i=await s.mkdtemp(o.join(c.tmpdir(),`zenovay-update-`)),a=o.join(i,`zenovay.new`);return await s.writeFile(a,r,{mode:493}),a}async function h(e,t){let n=await s.readFile(e),r=l.createHash(`sha256`).update(n).digest(`hex`);if(r.toLowerCase()!==t.toLowerCase())throw Error(`Checksum mismatch: expected ${t}, got ${r}. Update REFUSED.`)}async function g(e,t,n){let r=Buffer.from(d,`base64`);if(r.length!==32)throw Error(`Invalid release public key — update REFUSED.`);let i=Buffer.from(`${e.sha256}|${t}|${n}`),a=Buffer.from(e.sig,`base64`),o=l.createPublicKey({key:Buffer.concat([Buffer.from(`302a300506032b6570032100`,`hex`),r]),format:`der`,type:`spki`}),s=l.verify(null,i,o,a);if(!s)throw Error(`Signature verification FAILED. Update REFUSED.`)}async function _(e,t){let n=`${t}.old-${Date.now()}`;try{await s.rename(t,n)}catch(e){if(e.code!==`ENOENT`)throw e}try{await s.rename(e,t),process.platform!==`win32`&&await s.chmod(t,493),await s.unlink(n).catch(()=>void 0)}catch(e){try{await s.rename(n,t)}catch{}throw e}}async function v(a){let o=await e(),s=await i({cliBase:o.cliBase}),c=r(a.cliVersion,s.latest);if(a.check)return n({json:a.json})?t({type:`info`,message:`latest=${s.latest} current=${a.cliVersion} bump=${c}`}):process.stdout.write(`Current: ${a.cliVersion}\nLatest: ${s.latest}\nBump: ${c}\n`),{updated:!1,from:a.cliVersion,to:s.latest};if(c===`none`)return n({json:a.json})||process.stdout.write(`Already on latest (${a.cliVersion}).\n`),{updated:!1,from:a.cliVersion,to:s.latest};if(c===`downgrade`&&!a.forceDowngrade)throw Error(`Refused to downgrade ${a.cliVersion} → ${s.latest}. Pass --force-downgrade if you really want this.`);let l=await f({currentVersion:a.cliVersion,cliBase:o.cliBase,binaryPath:a.binaryPath,forceDowngrade:a.forceDowngrade});return n({json:a.json})?l.updated&&t({type:`update.applied`,from:l.from,to:l.to}):l.updated?process.stdout.write(`Updated ${l.from} → ${l.to}\n`):process.stdout.write(`Not updated (${l.reason??`unknown`}).\n`),l}export{v as updateCommand};
1
+ import{readConfig as e}from"./config-Ddkbfelp.js";import"./formatter-45-fT1Hv.js";import{emit as t,isHeadless as n}from"./emit-0WJ_OGeT.js";import{classifyBump as r,fetchManifest as i,platformKey as a}from"./check-CmOnrU4W.js";import o from"node:path";import{promises as s}from"node:fs";import c from"node:os";import l from"node:crypto";import u from"semver";const d=`AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=`;async function f(e){let t=await i({cliBase:e.cliBase,fetchImpl:e.fetchImpl});return p({...e,manifest:t})}async function p(e){let{manifest:t,currentVersion:n,forceDowngrade:i}=e,o=r(n,t.latest);if(o===`none`)return{updated:!1,from:n,to:t.latest,reason:`already-latest`};if(o===`downgrade`&&!i)return{updated:!1,from:n,to:t.latest,reason:`downgrade-blocked`};t.minSupported&&u.lt(n,t.minSupported);let c=a(),l=t.platforms[c];if(!l)throw Error(`No release binary for platform ${c}`);let d=await m(l,e.fetchImpl);try{return await h(d,l.sha256),await g(l,t.latest,c),await _(d,e.binaryPath),{updated:!0,from:n,to:t.latest}}catch(e){throw await s.unlink(d).catch(()=>void 0),e}}async function m(e,t=fetch){let n=await t(e.url);if(!n.ok)throw Error(`Download failed: ${n.status}`);let r=Buffer.from(await n.arrayBuffer()),i=await s.mkdtemp(o.join(c.tmpdir(),`zenovay-update-`)),a=o.join(i,`zenovay.new`);return await s.writeFile(a,r,{mode:493}),a}async function h(e,t){let n=await s.readFile(e),r=l.createHash(`sha256`).update(n).digest(`hex`);if(r.toLowerCase()!==t.toLowerCase())throw Error(`Checksum mismatch: expected ${t}, got ${r}. Update REFUSED.`)}async function g(e,t,n){let r=Buffer.from(d,`base64`);if(r.length!==32)throw Error(`Invalid release public key — update REFUSED.`);let i=Buffer.from(`${e.sha256}|${t}|${n}`),a=Buffer.from(e.sig,`base64`),o=l.createPublicKey({key:Buffer.concat([Buffer.from(`302a300506032b6570032100`,`hex`),r]),format:`der`,type:`spki`}),s=l.verify(null,i,o,a);if(!s)throw Error(`Signature verification FAILED. Update REFUSED.`)}async function _(e,t){let n=`${t}.old-${Date.now()}`;try{await s.rename(t,n)}catch(e){if(e.code!==`ENOENT`)throw e}try{await s.rename(e,t),process.platform!==`win32`&&await s.chmod(t,493),await s.unlink(n).catch(()=>void 0)}catch(e){try{await s.rename(n,t)}catch{}throw e}}async function v(a){let o=await e(),s=await i({cliBase:o.cliBase}),c=r(a.cliVersion,s.latest);if(a.check)return n({json:a.json})?t({type:`info`,message:`latest=${s.latest} current=${a.cliVersion} bump=${c}`}):process.stdout.write(`Current: ${a.cliVersion}\nLatest: ${s.latest}\nBump: ${c}\n`),{updated:!1,from:a.cliVersion,to:s.latest};if(c===`none`)return n({json:a.json})||process.stdout.write(`Already on latest (${a.cliVersion}).\n`),{updated:!1,from:a.cliVersion,to:s.latest};if(c===`downgrade`&&!a.forceDowngrade)throw Error(`Refused to downgrade ${a.cliVersion} → ${s.latest}. Pass --force-downgrade if you really want this.`);let l=await f({currentVersion:a.cliVersion,cliBase:o.cliBase,binaryPath:a.binaryPath,forceDowngrade:a.forceDowngrade});return n({json:a.json})?l.updated&&t({type:`update.applied`,from:l.from,to:l.to}):l.updated?process.stdout.write(`Updated ${l.from} → ${l.to}\n`):process.stdout.write(`Not updated (${l.reason??`unknown`}).\n`),l}export{v as updateCommand};
@@ -0,0 +1,5 @@
1
+ import{readConfig as e,updateConfig as t}from"./config-Ddkbfelp.js";import{ApiClient as n,readToken as r}from"./api-0Qf43hhF.js";import"./panel-DglZ755S.js";import"./prompt-B1QrBhyZ.js";import{resolveSiteId as i}from"./resolve-site-CPY8XSeq.js";async function a(a){if(a.reset)return await t({defaultSiteId:void 0,defaultSiteName:void 0}),process.stdout.write(`Default site cleared.
2
+ `),0;if(a.show){let t=await e();return t.defaultSiteId?process.stdout.write(a.json?`${JSON.stringify({defaultSiteId:t.defaultSiteId,defaultSiteName:t.defaultSiteName??null})}\n`:`Default site: ${t.defaultSiteName??t.defaultSiteId} (${t.defaultSiteId})\n`):process.stdout.write(a.json?`{"defaultSiteId":null}
3
+ `:`No default site set.
4
+ `),0}let s=await e(),c=await r({strict:!1});if(!c&&!process.env.ZENOVAY_API_TOKEN)return process.stderr.write("Not logged in — run `zenovay login` first.\n"),2;let l=new n({config:s,cliVersion:a.cliVersion,token:c});if(a.match&&a.match.trim()){let e=a.match.trim().toLowerCase(),n=await l.getSites(),r=n.find(e=>e.id===a.match||e.trackingCode===a.match||e.url===a.match),i=r??n.find(t=>o(t.url).includes(e)||t.name.toLowerCase().includes(e));return i?(await t({defaultSiteId:i.id,defaultSiteName:i.name}),process.stdout.write(`Default site → ${i.name} (${i.url})\n`),0):(process.stderr.write(`No site matched "${a.match}". Your sites:\n${n.map(e=>` ${e.name} — ${e.url} — ${e.id}`).join(`
5
+ `)}\n`),2)}let{site:u}=await i(l,{headless:!!a.json,cliVersion:a.cliVersion}).catch(e=>(process.stderr.write(`${e.message}\n`),{siteId:``,site:void 0,saved:!1}));return u?(process.stdout.write(`Default site → ${u.name} (${u.url})\n`),0):2}function o(e){return e.toLowerCase().replace(/^https?:\/\//,``).replace(/\/.*$/,``)}export{a as useCommand};
@@ -0,0 +1,2 @@
1
+ import{readConfig as e}from"./config-Ddkbfelp.js";import{readToken as t}from"./api-0Qf43hhF.js";import{formatTabular as n,selectFormat as r}from"./formatter-45-fT1Hv.js";import"./panel-DglZ755S.js";import"./prompt-B1QrBhyZ.js";import"./keybar-CWo5rhK_.js";import"./sparkline-CR_bzxwB.js";import{runAnalyticalScreen as i}from"./analytical-screen-DQwA5IZ1.js";import{Table as a}from"./ui-CVGR9Ffn.js";import{resolveSiteId as o}from"./resolve-site-CPY8XSeq.js";import{ApiV2Client as s}from"./api-v2-DnMJJmhi.js";import{Box as c,Text as l}from"ink";import u from"react";const d={lcp:{good:2500,poor:4e3},inp:{good:200,poor:500},cls:{good:.1,poor:.25},ttfb:{good:800,poor:1800},fcp:{good:1800,poor:3e3}};function f(e,t){let n=d[e];return t<=n.good?{label:`good`,color:`green`}:t<=n.poor?{label:`needs`,color:`yellow`}:{label:`poor`,color:`red`}}function p(e,t){return e===`cls`?t.toFixed(3):t<1e3?`${Math.round(t)}ms`:`${(t/1e3).toFixed(2)}s`}async function m(d){let m=await e(),h=await t({strict:!1}),g=new s({config:m,cliVersion:d.cliVersion,token:h}),_;try{({siteId:_}=await o(g,{explicit:d.siteId,headless:!!(d.json||d.csv||d.tsv||d.ndjson),cliVersion:d.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let v=r(d),y=[{key:`url`,header:`url`,width:32},{key:`device`,header:`device`,width:7,format:e=>String(e??`—`)},{key:`lcp`,header:`LCP p75`,width:9,align:`right`,format:e=>e&&typeof e==`object`&&`p75`in e?p(`lcp`,e.p75):`—`},{key:`inp`,header:`INP p75`,width:9,align:`right`,format:e=>e&&typeof e==`object`&&`p75`in e?p(`inp`,e.p75):`—`},{key:`cls`,header:`CLS p75`,width:9,align:`right`,format:e=>e&&typeof e==`object`&&`p75`in e?p(`cls`,e.p75):`—`},{key:`samples`,header:`n`,width:6,align:`right`}];return i({cliVersion:d.cliVersion,title:`vitals · ${_}`,commandName:`vitals`,authToken:h?.accessToken??null,refreshIntervalMs:d.watch?5*6e4:0,fetcher:e=>g.getVitals(_,{url:d.url,device:d.device,window:d.window},e),format:v,headlessEmit:(e,t)=>{if(t===`json`||t===`ndjson`){process.stdout.write(JSON.stringify(e,null,t===`json`?2:0)),t===`ndjson`&&process.stdout.write(`
2
+ `);return}process.stdout.write(n(e.vitals,[`url`,`device`,`samples`],t))},panels:[{id:`summary`,title:`Site-wide p75`,render:e=>{let t=t=>{let n=0,r=0;for(let i of e.vitals){let e=i[t]?.p75;typeof e==`number`&&(n+=e*i.samples,r+=i.samples)}return r>0?n/r:0},n=[`lcp`,`inp`,`cls`,`ttfb`,`fcp`];return u.createElement(c,{flexDirection:`column`},n.map(e=>{let n=t(e),r=f(e,n);return u.createElement(l,{key:e},u.createElement(l,{color:r.color},`● `),u.createElement(l,{bold:!0},e.toUpperCase().padEnd(5)),` `,u.createElement(l,null,p(e,n).padStart(8)),` `,u.createElement(l,{color:r.color},r.label))}))}},{id:`pages`,title:`Per-page`,render:e=>e.vitals.length===0?u.createElement(l,{color:`gray`},`— no vitals data yet —`):u.createElement(a,{data:e.vitals.slice(0,15),columns:y})}]})}export{m as vitalsCommand};
@@ -0,0 +1 @@
1
+ import{readConfig as e}from"./config-Ddkbfelp.js";import{ApiClient as t,readToken as n}from"./api-0Qf43hhF.js";import{parseSseStream as r}from"./client-DZ4Awt8u.js";import"./formatter-45-fT1Hv.js";import{emit as i,isHeadless as a}from"./emit-0WJ_OGeT.js";import{Panel as o}from"./panel-DglZ755S.js";import{Banner as s}from"./prompt-B1QrBhyZ.js";import{Keybar as c}from"./keybar-CWo5rhK_.js";import{spark as l}from"./sparkline-CR_bzxwB.js";import{resolveSiteId as u}from"./resolve-site-CPY8XSeq.js";import{Box as d,Text as f,render as p,useApp as m,useInput as h}from"ink";import g,{useEffect as _,useState as v}from"react";import y from"ink-spinner";import b from"ink-text-input";const x=Math.PI*2;function S(e){let t=e,n=Math.PI*Math.sin(e);for(let e=0;e<6;e++){let e=2*t+Math.sin(2*t)-n,r=2+2*Math.cos(2*t);if(r===0)break;t-=e/r}return t}function C(e,t){if(e<-90||e>90||t<-180||t>180)return null;let n=e*Math.PI/180,r=t*Math.PI/180,i=S(n),a=r*Math.cos(i)/Math.PI,o=Math.sin(i);return{x:a,y:o}}function w(e){if(e)return!0;let t=process.env;if(t.NO_COLOR||t.ZENOVAY_GLOBE===`ascii`)return!0;let n=(t.LANG||t.LC_ALL||t.LC_CTYPE||``).toLowerCase();return!!(n&&!n.includes(`utf`))}function T(e,t){let n=e*2,r=t*4;return{dw:n,dh:r,bits:new Uint8Array(n*r)}}function E(e,t,n){t<0||t>=e.dw||n<0||n>=e.dh||(e.bits[n*e.dw+t]=1)}function D(e){let t=e.dw/2,n=e.dh/2,r=e.dw/2-1,i=e.dh/2-1,a=Math.max(e.dw,e.dh)*2;for(let o=0;o<a;o++){let s=o/a*x,c=Math.round(t+r*Math.cos(s)),l=Math.round(n+i*Math.sin(s));E(e,c,l)}}function O(e){let t=Math.floor(e.dh/2);for(let n=0;n<e.dw;n+=4)E(e,n,t)}function k(e,t){let n=e.dw/2,r=e.dh/2,i=e.dw/2-1,a=e.dh/2-1;for(let o of t){let t=C(o.lat,o.lng);if(!t)continue;let s=Math.round(n+t.x*i),c=Math.round(r-t.y*a);E(e,s,c),E(e,s+1,c),E(e,s,c+1),E(e,s+1,c+1)}}const A=[[0,0],[0,1],[0,2],[1,0],[1,1],[1,2],[0,3],[1,3]];function j(e,t,n){let r=0;for(let i=0;i<A.length;i++){let[a,o]=A[i],s=t*2+a,c=n*4+o;e.bits[c*e.dw+s]&&(r|=1<<i)}return r===0?` `:String.fromCodePoint(10240+r)}function M(e,t,n){let r=0;for(let i=0;i<4;i++)for(let a=0;a<2;a++){let o=t*2+a,s=n*4+i;e.bits[s*e.dw+o]&&r++}return r===0?` `:r<=2?`.`:r<=4?`:`:r<=6?`*`:`#`}function N({data:e,width:t=80,height:n=20,asciiOnly:r}){let i=w(r),a=T(t,n);D(a),O(a),k(a,e);let o=[];for(let e=0;e<n;e++){let n=``;for(let r=0;r<t;r++)n+=i?M(a,r,e):j(a,r,e);o.push(n)}return g.createElement(d,{flexDirection:`column`},o.map((e,t)=>g.createElement(f,{key:t,color:`magenta`},e)),g.createElement(f,{color:`gray`},e.length,` live · `,i?`ascii mode`:`braille mode`))}async function P(r){let o=await e(),s=await n({strict:!1});if(!s)return process.stderr.write("Not logged in — run `zenovay login` first.\n"),2;let c=new t({config:o,cliVersion:r.cliVersion,token:s}),l;try{({siteId:l}=await u(c,{explicit:r.siteId,headless:!!r.json,cliVersion:r.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}if(a(r)){let e=await c.getDashboardSnapshot(l);return i({type:`watch.tick`,snapshot:e}),0}return new Promise(e=>{let{unmount:t}=p(g.createElement(F,{api:c,siteId:l,intervalMs:r.intervalMs??15e3,cliVersion:r.cliVersion,onExit:n=>{t(),e(n)}}))})}const F=({api:e,siteId:t,intervalMs:n,cliVersion:i,onExit:a})=>{let{exit:l}=m(),[u,p]=v(null),[b,x]=v(null),[S,C]=v(null),[w,T]=v([]),[E,D]=v(!0),[O,k]=v(null),[A,j]=v(1),[M,P]=v(!1),[F,U]=v(!1);if(h((e,t)=>{if(e===`q`){l(),a(0);return}if(e===`?`||e===`/`){U(e=>!e);return}if(e===`g`){P(e=>!e);return}if(t.tab){j(e=>{let n=t.shift?(e+4)%6+1:e%6+1;return n});return}(e===`1`||e===`2`||e===`3`||e===`4`||e===`5`||e===`6`)&&j(Number(e))}),_(()=>{let r=!1,i=async()=>{try{let n=await e.getDashboardSnapshot(t);if(r)return;p(n);let i=e.getVitals;typeof i==`function`&&i.call(e,t).then(e=>{r||x(e)},()=>{});let a=e.getGoals;typeof a==`function`&&a.call(e,t).then(e=>{r||C(e)},()=>{}),D(!1),k(null)}catch(e){r||k(e.message)}};i();let a=setInterval(i,n);return()=>{r=!0,clearInterval(a)}},[e,t,n]),_(()=>{let n=new AbortController;return(async()=>{try{let i=await e.openEventsStream(t,n.signal);for await(let e of r(i))e.type===`error`&&T(t=>[...t,`[ERR ${e.code}] ${e.message}`].slice(-10))}catch{}})(),()=>n.abort()},[e,t]),E)return g.createElement(d,{flexDirection:`column`},g.createElement(s,{version:i,subtitle:`watch · ${t}`}),g.createElement(o,{title:`Loading`,state:`busy`},g.createElement(d,null,g.createElement(f,{color:`magenta`},g.createElement(y,{type:`dots`})),g.createElement(f,null,` Fetching snapshot…`))));if(O&&!u)return g.createElement(d,{flexDirection:`column`},g.createElement(s,{version:i,subtitle:`watch · ${t}`}),g.createElement(o,{title:`Error`,state:`err`},g.createElement(f,{color:`red`},O)));let W=process.stdout.columns??80,G=Math.max(20,Math.floor(W/3)-1),K=[];return g.createElement(d,{flexDirection:`column`},g.createElement(s,{version:i,subtitle:`watch · ${t}${M?` · globe`:``}`}),g.createElement(d,{flexDirection:`row`},g.createElement(d,{flexDirection:`column`},M?g.createElement(o,{title:`Live globe`,focused:A===1,width:G},g.createElement(N,{data:K,width:Math.max(40,G-4),height:12})):g.createElement(L,{snapshot:u,focused:A===1,width:G}),g.createElement(B,{events:w,focused:A===4,width:G})),g.createElement(d,{flexDirection:`column`},g.createElement(R,{snapshot:u,focused:A===2,width:G}),g.createElement(V,{vitals:b,focused:A===5,width:G})),g.createElement(d,{flexDirection:`column`},g.createElement(z,{snapshot:u,focused:A===3,width:G}),g.createElement(H,{goals:S,focused:A===6,width:G}))),F?g.createElement(I,{api:e,siteId:t,width:W-2}):null,g.createElement(c,{items:[{key:`tab`,label:`next`},{key:`1-6`,label:`jump`},{key:`g`,label:M?`panels`:`globe`},{key:`?/`,label:F?`close chat`:`ai chat`},{key:`q`,label:`quit`}]}))},I=({api:e,siteId:t,width:n})=>{let[i,a]=v(``),[s,c]=v([]),[l,u]=v(!1),[p,m]=v(``),[h,_]=v(null),y=async n=>{let i=n.trim();if(!i||l)return;_(null),a(``);let o=[...s,{role:`user`,content:i}];c(o),u(!0),m(``);try{let n=o.map(e=>({role:e.role,content:e.content})),i=await e.openAiStream(`chat`,{messages:n,siteId:t},void 0),a=``;for await(let e of r(i))if(e.type===`delta`)a+=e.content,m(a);else if(e.type===`error`)_(`${e.code}: ${e.message}`);else if(e.type===`done`)break;c([...o,{role:`assistant`,content:a}]),m(``)}catch(e){_(e instanceof Error?e.message:`chat failed`)}finally{u(!1)}};return g.createElement(d,{marginTop:1},g.createElement(o,{title:`AI chat (esc / ?/ to close)`,focused:!0,width:n},g.createElement(d,{flexDirection:`column`},s.slice(-6).map((e,t)=>g.createElement(d,{key:t,flexDirection:`column`,marginBottom:1},g.createElement(f,{color:e.role===`user`?`cyan`:`magenta`,bold:!0},e.role===`user`?`you`:`zenovay`),g.createElement(f,null,e.content))),l&&p?g.createElement(d,{flexDirection:`column`,marginBottom:1},g.createElement(f,{color:`magenta`,bold:!0},`zenovay`),g.createElement(f,null,p)):null,h?g.createElement(f,{color:`red`},`✗ `,h):null,g.createElement(d,null,g.createElement(f,{color:`cyan`},l?`⠋ `:`▸ `),g.createElement(b,{value:i,onChange:a,onSubmit:y,placeholder:l?`streaming…`:`ask anything about your analytics`})))))},L=({snapshot:e,focused:t,width:n})=>{let r=e?.visitors?.count??0,i=e?.visitors?.series??[];return g.createElement(o,{title:`Visitors`,focused:t,width:n},g.createElement(f,{bold:!0},r.toString()),g.createElement(f,{color:`gray`},i.length>0?l(i,Math.max(8,n-6)):`— no data —`))},R=({snapshot:e,focused:t,width:n})=>{let r=e?.topPages?.slice(0,5)??[];return g.createElement(o,{title:`Top pages`,focused:t,width:n},r.length===0?g.createElement(f,{color:`gray`},`— no data —`):r.map(e=>g.createElement(d,{key:e.path},g.createElement(f,null,e.path.padEnd(n-10).slice(0,n-10)),g.createElement(f,{color:`gray`},` `,e.views))))},z=({snapshot:e,focused:t,width:n})=>{let r=e?.sources?.slice(0,5)??[];return g.createElement(o,{title:`Sources`,focused:t,width:n},r.length===0?g.createElement(f,{color:`gray`},`— no data —`):r.map(e=>g.createElement(d,{key:e.source},g.createElement(f,null,e.source.padEnd(n-10).slice(0,n-10)),g.createElement(f,{color:`gray`},` `,e.visitors))))},B=({events:e,focused:t,width:n})=>g.createElement(o,{title:`Events`,focused:t,width:n},e.length===0?g.createElement(f,{color:`gray`},`— waiting —`):e.slice(-10).map((e,t)=>g.createElement(f,{key:t},e.slice(0,n-4)))),V=({vitals:e,focused:t,width:n})=>{let r=(e,t,n)=>g.createElement(d,{key:e},g.createElement(f,{bold:!0},e.padEnd(6)),g.createElement(f,{color:`gray`},typeof t==`number`?`${t.toFixed(0)}${n}`:`—`));return g.createElement(o,{title:`Vitals`,focused:t,width:n},r(`LCP`,e?.lcpP75,`ms`),r(`INP`,e?.inpP75,`ms`),r(`CLS`,e?.clsP75?e.clsP75*1e3:void 0,`/1k`),r(`TTFB`,e?.ttfbP75,`ms`),r(`FCP`,e?.fcpP75,`ms`))},H=({goals:e,focused:t,width:n})=>{let r=e?.goals?.slice(0,5)??[];return g.createElement(o,{title:`Goals`,focused:t,width:n},r.length===0?g.createElement(f,{color:`gray`},`— no data —`):r.map(e=>g.createElement(d,{key:e.name},g.createElement(f,null,e.name.padEnd(n-10).slice(0,n-10)),g.createElement(f,{color:`gray`},` `,e.completions))))};export{P as watchCommand};
@@ -1,3 +1,3 @@
1
- import{readConfig as e}from"./config-ZTGpKEWg.js";import{readToken as t}from"./api-BhdaCghp.js";import{Panel as n}from"./panel-DglZ755S.js";import{Banner as r}from"./keybar-D2OI-8rx.js";import"./prompt-hjzdzlyj.js";import"./sparkline-CR_bzxwB.js";import"./ui-Bk5nl2yb.js";import{ApiV2Client as i}from"./api-v2-B03fp6KF.js";import{Box as a,Text as o,render as s,useApp as c,useInput as l}from"ink";import u,{useEffect as d,useState as f}from"react";async function p(e,t){let n=new TextEncoder,r=await crypto.subtle.importKey(`raw`,n.encode(e),{name:`HMAC`,hash:`SHA-256`},!1,[`sign`]),i=await crypto.subtle.sign(`HMAC`,r,n.encode(t));return Array.from(new Uint8Array(i),e=>e.toString(16).padStart(2,`0`)).join(``)}function m({stats:e}){return u.createElement(n,{title:`webhooks forward`,state:e.connected?`ok`:`busy`},u.createElement(a,{flexDirection:`column`},u.createElement(o,null,u.createElement(o,{color:`gray`},`public URL `),u.createElement(o,{color:`cyan`},e.publicUrl)),u.createElement(o,null,u.createElement(o,{color:`gray`},`→ forwarding to `),u.createElement(o,{color:`magenta`},e.wsUrl)),u.createElement(o,null,e.connected?u.createElement(o,{color:`green`},`● connected`):u.createElement(o,{color:`yellow`},`○ connecting…`),u.createElement(o,{color:`gray`},` · `,e.total,` requests · `,e.ok,` ok · `),u.createElement(o,{color:e.err>0?`red`:`gray`},e.err,` err`),e.lastStatus===null?null:u.createElement(o,{color:`gray`},` · last: HTTP `,e.lastStatus)),e.lastError?u.createElement(o,{color:`red`},`last error: `,e.lastError.slice(0,80)):null))}async function h(n){let h=await e(),g=await t({strict:!1});if(!g?.accessToken)return process.stderr.write("Not authenticated. Run `zenovay login` first.\n"),2;let _=n.siteId??g.teamId??``;if(!_)return process.stderr.write(`No site selected — pass --site-id or set ZENOVAY_SITE.
1
+ import{readConfig as e}from"./config-Ddkbfelp.js";import{readToken as t}from"./api-0Qf43hhF.js";import{Panel as n}from"./panel-DglZ755S.js";import{Banner as r}from"./prompt-B1QrBhyZ.js";import"./keybar-CWo5rhK_.js";import"./sparkline-CR_bzxwB.js";import"./ui-CVGR9Ffn.js";import{ApiV2Client as i}from"./api-v2-DnMJJmhi.js";import{Box as a,Text as o,render as s,useApp as c,useInput as l}from"ink";import u,{useEffect as d,useState as f}from"react";async function p(e,t){let n=new TextEncoder,r=await crypto.subtle.importKey(`raw`,n.encode(e),{name:`HMAC`,hash:`SHA-256`},!1,[`sign`]),i=await crypto.subtle.sign(`HMAC`,r,n.encode(t));return Array.from(new Uint8Array(i),e=>e.toString(16).padStart(2,`0`)).join(``)}function m({stats:e}){return u.createElement(n,{title:`webhooks forward`,state:e.connected?`ok`:`busy`},u.createElement(a,{flexDirection:`column`},u.createElement(o,null,u.createElement(o,{color:`gray`},`public URL `),u.createElement(o,{color:`cyan`},e.publicUrl)),u.createElement(o,null,u.createElement(o,{color:`gray`},`→ forwarding to `),u.createElement(o,{color:`magenta`},e.wsUrl)),u.createElement(o,null,e.connected?u.createElement(o,{color:`green`},`● connected`):u.createElement(o,{color:`yellow`},`○ connecting…`),u.createElement(o,{color:`gray`},` · `,e.total,` requests · `,e.ok,` ok · `),u.createElement(o,{color:e.err>0?`red`:`gray`},e.err,` err`),e.lastStatus===null?null:u.createElement(o,{color:`gray`},` · last: HTTP `,e.lastStatus)),e.lastError?u.createElement(o,{color:`red`},`last error: `,e.lastError.slice(0,80)):null))}async function h(n){let h=await e(),g=await t({strict:!1});if(!g?.accessToken)return process.stderr.write("Not authenticated. Run `zenovay login` first.\n"),2;let _=n.siteId??g.teamId??``;if(!_)return process.stderr.write(`No site selected — pass --site-id or set ZENOVAY_SITE.
2
2
  `),2;if(!n.to)return process.stderr.write(`Missing --to <url> (e.g. --to localhost:3000/webhook).
3
3
  `),2;let v=n.to.match(/^https?:\/\//)?n.to:`http://${n.to}`,y=new i({config:h,cliVersion:n.cliVersion,token:g}),b;try{b=await y.createTunnel(_,n.to)}catch(e){return process.stderr.write(`Failed to register tunnel: ${e.message}\n`),1}let x=n.sign?n.secret??b.tunnelKey:null,S=()=>{let{exit:e}=c(),[t,i]=f({total:0,ok:0,err:0,lastStatus:null,lastError:null,publicUrl:b.publicUrl,wsUrl:b.wsUrl,connected:!1});return l((t,n)=>{(t===`q`||n.escape)&&e()}),d(()=>{let e=new AbortController,t=async e=>{try{let t={...e.headers};delete t.host,delete t[`content-length`],x&&(t[`X-Zenovay-Signature`]=`sha256=${await p(x,e.body)}`);let n=await fetch(v,{method:e.method,headers:t,body:e.method===`GET`||e.method===`HEAD`?void 0:e.body}),r=await n.text(),a={};return n.headers.forEach((e,t)=>{a[t]=e}),i(e=>({...e,total:e.total+1,ok:e.ok+(n.ok?1:0),err:e.err+(n.ok?0:1),lastStatus:n.status,lastError:n.ok?null:`HTTP ${n.status}`})),{status:n.status,headers:a,body:r}}catch(e){let t=e instanceof Error?e.message:String(e);return i(e=>({...e,total:e.total+1,err:e.err+1,lastError:t})),{status:502,body:JSON.stringify({error:`cli_local_failed`,detail:t})}}};return(async()=>{let n=y.tunnelClient(b.wsUrl);i(e=>({...e,connected:!0}));try{await n.start(t,e.signal)}catch(e){i(t=>({...t,connected:!1,lastError:e.message}))}})(),()=>{e.abort()}},[]),u.createElement(a,{flexDirection:`column`},u.createElement(r,{version:`webhooks forward`}),u.createElement(m,{stats:t}),u.createElement(o,{color:`gray`},`target: `,v,` `,n.sign?`· HMAC-signed`:``),u.createElement(o,{color:`gray`},`[q | Esc] quit`))},{waitUntilExit:C}=s(u.createElement(S,null));return await C(),0}export{h as webhooksForwardCommand};
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import(`./init-C6maV1Ia.js`).then(async({initCommand:e})=>{let{readFileSync:t}=await import(`node:fs`),n=await import(`node:path`),{fileURLToPath:r}=await import(`node:url`),i=n.dirname(r(import.meta.url)),a=JSON.parse(t(n.join(i,`..`,`package.json`),`utf8`)),o=process.argv.slice(2),s=o.includes(`--json`),c=o.includes(`--yes`),l=o.includes(`--skip-mcp`),u=o.includes(`--skip-verify`),d=await e({cliVersion:a.version,cwd:process.cwd(),json:s,yes:c,skipMcp:l,skipVerify:u});process.exit(d)});
2
+ import(`./init-QiTMBqJb.js`).then(async({initCommand:e})=>{let{readFileSync:t}=await import(`node:fs`),n=await import(`node:path`),{fileURLToPath:r}=await import(`node:url`),i=n.dirname(r(import.meta.url)),a=JSON.parse(t(n.join(i,`..`,`package.json`),`utf8`)),o=process.argv.slice(2),s=o.includes(`--json`),c=o.includes(`--yes`),l=o.includes(`--skip-mcp`),u=o.includes(`--skip-verify`),d=await e({cliVersion:a.version,cwd:process.cwd(),json:s,yes:c,skipMcp:l,skipVerify:u});process.exit(d)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenovay/cli",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "Zenovay CLI — AI install wizard + full terminal analytics dashboard",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1 +0,0 @@
1
- import{ApiError as e}from"./api-BhdaCghp.js";import{formatEvent as t}from"./formatter-45-fT1Hv.js";import{Panel as n}from"./panel-DglZ755S.js";import{Banner as r,Keybar as i}from"./keybar-D2OI-8rx.js";import{Box as a,Text as o,render as s,useApp as c,useInput as l}from"ink";import u,{useEffect as d,useMemo as f,useReducer as p,useRef as m}from"react";import h from"ink-spinner";function g(e,t){switch(t.type){case`set`:return{...e,data:t.data,status:`ready`,error:null};case`merge`:{let n=e.data?{...e.data,...t.partial}:t.partial;return{...e,data:n,status:`ready`,error:null}}case`error`:return{...e,status:`error`,error:{message:t.message,status:t.status,upgradeUrl:t.upgradeUrl}};case`refresh`:return{...e,refreshTick:e.refreshTick+1};case`focus`:return{...e,focusIndex:t.index};case`help-toggle`:return{...e,showHelp:!e.showHelp};default:return e}}async function _(e,n){let r=new AbortController,i=()=>r.abort();process.on(`SIGINT`,i);try{let i=await e.fetcher(r.signal);if(e.headlessEmit?e.headlessEmit(i,n):process.stdout.write(t(i,n)),e.streamer)for await(let i of e.streamer(r.signal))process.stdout.write(t(i,n));return 0}catch(e){if(e.name===`AbortError`)return 0;let t=e.message;return process.stderr.write(`${t}\n`),1}finally{process.off(`SIGINT`,i)}}const v=({cliVersion:e})=>u.createElement(a,{flexDirection:`column`},u.createElement(r,{version:e,subtitle:`login required`}),u.createElement(n,{title:`Not logged in`,state:`warn`},u.createElement(o,null,`You need to authenticate before running this command.`),u.createElement(o,null,` `),u.createElement(o,{color:`gray`},`Run `),u.createElement(o,{color:`cyan`},`zenovay login`),u.createElement(o,{color:`gray`},` to start the device-flow.`)));function y(t){let{exit:s}=c(),[_,v]=p(g,{data:null,status:`loading`,error:null,refreshTick:0,focusIndex:0,showHelp:!1}),y=m(v);y.current=v;let b=f(()=>({q:{label:`quit`,handler:()=>{s(),t.onExit(0)}},r:{label:`refresh`,handler:()=>y.current({type:`refresh`})},"?":{label:`help`,handler:()=>y.current({type:`help-toggle`})}}),[s,t]),x=f(()=>({...t.keybindings??{},...b}),[t.keybindings,b]);if(l((e,n)=>{if(n.tab&&n.shift){v({type:`focus`,index:(_.focusIndex-1+t.panels.length)%t.panels.length});return}if(n.tab){v({type:`focus`,index:(_.focusIndex+1)%t.panels.length});return}if(e>=`1`&&e<=`9`){let n=Number(e)-1;n<t.panels.length&&v({type:`focus`,index:n});return}let r=x[e];r&&r.handler()}),d(()=>{let n=new AbortController,r=!1,i=async()=>{try{let e=await t.fetcher(n.signal);r||y.current({type:`set`,data:e})}catch(t){if(r)return;if(t instanceof e){if(t.status===402){let e=t.body,n=typeof e==`object`&&e&&`upgradeUrl`in e?e.upgradeUrl:void 0;y.current({type:`error`,message:`This command requires a higher plan.`,status:402,upgradeUrl:n});return}y.current({type:`error`,message:t.message,status:t.status});return}if(t.name===`AbortError`)return;y.current({type:`error`,message:t.message})}};i();let a=null,o=t.refreshIntervalMs??15e3;return o>0&&!t.streamer&&(a=setInterval(i,o)),()=>{r=!0,n.abort(),a&&clearInterval(a)}},[t.fetcher,t.refreshIntervalMs,t.streamer,_.refreshTick]),d(()=>{if(!t.streamer)return;let e=new AbortController,n=!1;return(async()=>{try{for await(let r of t.streamer(e.signal)){if(n)return;y.current({type:`merge`,partial:r})}}catch(e){if(n||e.name===`AbortError`)return;y.current({type:`error`,message:e.message})}})(),()=>{n=!0,e.abort()}},[t.streamer]),_.status===`loading`&&_.data===null)return u.createElement(a,{flexDirection:`column`},u.createElement(r,{version:t.cliVersion,subtitle:t.title}),u.createElement(n,{title:`Loading`,state:`busy`},u.createElement(a,null,u.createElement(o,{color:`magenta`},u.createElement(h,{type:`dots`})),u.createElement(o,null,` Fetching `,t.commandName,`…`))),u.createElement(i,{items:[{key:`q`,label:`quit`}]}));if(_.status===`error`&&_.error){let e=_.error.status===402;return u.createElement(a,{flexDirection:`column`},u.createElement(r,{version:t.cliVersion,subtitle:t.title}),u.createElement(n,{title:e?`Upgrade required`:`Error`,state:e?`warn`:`err`},u.createElement(o,{color:e?`yellow`:`red`},_.error.message),e&&_.error.upgradeUrl?u.createElement(u.Fragment,null,u.createElement(o,null,` `),u.createElement(o,{color:`gray`},`Upgrade: `),u.createElement(o,{color:`cyan`},_.error.upgradeUrl)):null),u.createElement(i,{items:[{key:`r`,label:`retry`},{key:`q`,label:`quit`}]}))}let S=_.data,C=Object.entries(x).map(([e,t])=>({key:e,label:t.label})),w=Math.ceil(t.panels.length/2),T=t.panels.slice(0,w),E=t.panels.slice(w);return u.createElement(a,{flexDirection:`column`},u.createElement(r,{version:t.cliVersion,subtitle:t.title}),u.createElement(a,{flexDirection:`row`},T.map((e,t)=>{let r=_.focusIndex===t;return u.createElement(a,{key:e.id,flexDirection:`column`,marginRight:1,flexGrow:1},u.createElement(n,{title:e.title,state:r?`busy`:`idle`},e.render(S,r)))})),E.length>0?u.createElement(a,{flexDirection:`row`},E.map((e,t)=>{let r=t+w,i=_.focusIndex===r;return u.createElement(a,{key:e.id,flexDirection:`column`,marginRight:1,flexGrow:1},u.createElement(n,{title:e.title,state:i?`busy`:`idle`},e.render(S,i)))})):null,_.showHelp?u.createElement(n,{title:`Help`,state:`idle`},Object.entries(x).map(([e,t])=>u.createElement(o,{key:e},`[`,e,`] `,t.label)),u.createElement(o,{color:`gray`},`[tab/shift+tab] cycle focus [1-9] focus panel`)):null,u.createElement(i,{items:C}))}async function b(e){return e.authToken===null?e.format?(process.stderr.write("Not logged in — run `zenovay login` first.\n"),2):new Promise(t=>{let{unmount:n}=s(u.createElement(v,{cliVersion:e.cliVersion}));setTimeout(()=>{n(),t(2)},50)}):e.format?_(e,e.format):new Promise(t=>{let{unmount:n}=s(u.createElement(y,{...e,onExit:e=>{n(),t(e)}}))})}export{b as runAnalyticalScreen};
@@ -1,3 +0,0 @@
1
- import{readConfig as e}from"./config-ZTGpKEWg.js";import{readToken as t}from"./api-BhdaCghp.js";import{formatTabular as n,selectFormat as r}from"./formatter-45-fT1Hv.js";import"./panel-DglZ755S.js";import"./keybar-D2OI-8rx.js";import"./prompt-hjzdzlyj.js";import"./sparkline-CR_bzxwB.js";import{runAnalyticalScreen as i}from"./analytical-screen-Boiw3NTp.js";import{Table as a}from"./ui-Bk5nl2yb.js";import{ApiV2Client as o}from"./api-v2-B03fp6KF.js";import{Box as s,Text as c}from"ink";import l from"react";function u(e){let t=Math.max(0,Math.floor((Date.now()-new Date(e).getTime())/1e3));return t<60?`${t}s`:t<3600?`${Math.floor(t/60)}m`:t<86400?`${Math.floor(t/3600)}h`:`${Math.floor(t/86400)}d`}function d(e){return e==null?`—`:e>=500?`Enterprise`:e>=50?`Growth`:`SMB`}async function f(f){let p=await e(),m=await t({strict:!1}),h=f.siteId??m?.teamId??``;if(!h)return process.stderr.write(`No site selected — pass --site-id or set ZENOVAY_SITE.
2
- `),2;let g=new o({config:p,cliVersion:f.cliVersion,token:m}),_=r(f),v=f.window??`24h`,y=f.limit??100,b=[{key:`lastSeenAt`,header:`when`,width:6,format:e=>u(String(e))},{key:`name`,header:`company`,width:24,format:e=>String(e).slice(0,24)},{key:`employeeCount`,header:`tier`,width:11,format:e=>d(typeof e==`number`?e:null)},{key:`industry`,header:`industry`,width:18,format:e=>String(e??`—`).slice(0,18)},{key:`visitCount`,header:`visits`,width:6,align:`right`},{key:`isNew`,header:``,width:5,format:e=>e?`NEW`:``}];return i({cliVersion:f.cliVersion,title:`companies · ${h} · ${v}`,commandName:`companies`,authToken:m?.accessToken??null,refreshIntervalMs:f.watch?3e4:0,fetcher:e=>g.getCompaniesSnapshot(h,{window:v,limit:y},e),format:_,headlessEmit:(e,t)=>{let r=f.newOnly?e.companies.filter(e=>e.isNew):e.companies;if(t===`json`||t===`ndjson`){if(t===`ndjson`)for(let e of r)process.stdout.write(JSON.stringify(e)+`
3
- `);else process.stdout.write(JSON.stringify({companies:r,total:r.length},null,2));return}process.stdout.write(n(r,[`name`,`domain`,`industry`,`employeeCount`,`visitCount`,`firstSeenAt`,`lastSeenAt`,`isNew`],t))},panels:[{id:`summary`,title:`Now`,render:e=>{let t=e.companies.filter(e=>e.isNew).length,n=e.companies.filter(e=>(e.employeeCount??0)>=500).length;return l.createElement(s,{flexDirection:`column`},l.createElement(c,null,l.createElement(c,{bold:!0},e.total),l.createElement(c,{color:`gray`},` companies in `,v)),l.createElement(c,{color:`gray`},l.createElement(c,{color:`green`},`● `,t,` new`),` · `,n,` enterprise`))}},{id:`feed`,title:`Feed`,render:e=>{let t=f.newOnly?e.companies.filter(e=>e.isNew):e.companies;return t.length===0?l.createElement(c,{color:`gray`},`— no `,f.newOnly?`new `:``,`companies in window —`):l.createElement(a,{data:t.slice(0,30),columns:b})}}]})}export{f as companiesCommand};
@@ -1 +0,0 @@
1
- import e from"node:path";import{promises as t}from"node:fs";import n from"node:os";import{z as r}from"zod";const i=r.object({theme:r.string().optional(),apiBase:r.string().url().default(`https://api.zenovay.com`),cliBase:r.string().url().default(`https://cli.zenovay.com`),region:r.enum([`us`,`eu`,`auto`]).default(`auto`),telemetry:r.boolean().default(!1),noUpdateCheck:r.boolean().default(!1),lastUpdateNotice:r.number().optional(),forwardSecret:r.string().optional()}),a={apiBase:`https://api.zenovay.com`,cliBase:`https://cli.zenovay.com`,region:`auto`,telemetry:!1,noUpdateCheck:!1};function o(){if(process.platform===`win32`){let t=process.env.APPDATA??e.join(n.homedir(),`AppData`,`Roaming`);return e.join(t,`zenovay`)}let t=process.env.XDG_CONFIG_HOME??e.join(n.homedir(),`.config`);return e.join(t,`zenovay`)}function s(){return e.join(o(),`config.json`)}async function c(){let e=s();try{let n=await t.readFile(e,`utf8`),r=i.safeParse(JSON.parse(n));return r.success?r.data:a}catch(e){if(e.code===`ENOENT`)return a;throw e}}async function l(e){let n=o();await t.mkdir(n,{recursive:!0,mode:448});let r=s();await t.writeFile(r,JSON.stringify(e,null,2),{mode:384}),process.platform!==`win32`&&await t.chmod(r,384)}async function u(e){let t=await c(),n=i.parse({...t,...e});return await l(n),n}export{o as configDir,s as configPath,c as readConfig,u as updateConfig};
@@ -1,3 +0,0 @@
1
- import{readConfig as e}from"./config-ZTGpKEWg.js";import{readToken as t}from"./api-BhdaCghp.js";import{formatTabular as n,selectFormat as r}from"./formatter-45-fT1Hv.js";import"./panel-DglZ755S.js";import"./keybar-D2OI-8rx.js";import"./prompt-hjzdzlyj.js";import"./sparkline-CR_bzxwB.js";import{runAnalyticalScreen as i}from"./analytical-screen-Boiw3NTp.js";import{Table as a}from"./ui-Bk5nl2yb.js";import{ApiV2Client as o}from"./api-v2-B03fp6KF.js";import{Box as s,Text as c}from"ink";import l from"react";function u(e){let t=Math.max(0,Math.floor((Date.now()-new Date(e).getTime())/1e3));return t<60?`${t}s`:t<3600?`${Math.floor(t/60)}m`:t<86400?`${Math.floor(t/3600)}h`:`${Math.floor(t/86400)}d`}async function d(d){if(d.connect){let t=await e(),n=t.apiBase.replace(`api.zenovay.com`,`app.zenovay.com`),r=`${n}/settings/integrations/github`;return process.stdout.write(`\n Connect GitHub to Zenovay:\n ${r}\n\n Open this URL in your browser. Zenovay re-uses the same GitHub\n OAuth app you already authorized for login (auth-zenovay), so\n no separate "Zenovay Deploys" app is needed. Pick the repos you\n want to track and deploys will appear here automatically.\n\n`),0}let f=await e(),p=await t({strict:!1}),m=d.siteId??p?.teamId??``;if(!m)return process.stderr.write(`No site selected — pass --site-id or set ZENOVAY_SITE.
2
- `),2;let h=new o({config:f,cliVersion:d.cliVersion,token:p}),g=r(d),_=d.limit??50,v=[{key:`pushed_at`,header:`when`,width:6,format:e=>u(String(e))},{key:`branch`,header:`branch`,width:14,format:e=>String(e??`—`).slice(0,14)},{key:`commit_sha`,header:`commit`,width:9,format:e=>String(e).slice(0,8)},{key:`commit_author`,header:`author`,width:16,format:e=>String(e??`—`).slice(0,16)},{key:`commit_message`,header:`message`,width:40,format:e=>String(e??`—`).slice(0,40)},{key:`show_on_chart`,header:`chart`,width:5,format:e=>e?`●`:`○`}];return i({cliVersion:d.cliVersion,title:`deploys · ${m}`,commandName:`deploys`,authToken:p?.accessToken??null,refreshIntervalMs:0,fetcher:e=>h.getDeploys(m,{branch:d.branch,since:d.since,limit:_},e),format:g,headlessEmit:(e,t)=>{if(t===`json`||t===`ndjson`){if(t===`ndjson`)for(let t of e.deploys)process.stdout.write(JSON.stringify(t)+`
3
- `);else process.stdout.write(JSON.stringify(e,null,2));return}process.stdout.write(n(e.deploys,[`pushed_at`,`branch`,`commit_sha`,`commit_author`,`commit_message`,`repository`,`commit_url`,`show_on_chart`],t))},panels:[{id:`summary`,title:`Summary`,render:e=>{let t=e.deploys.filter(e=>e.show_on_chart).length,n=new Set(e.deploys.map(e=>e.repository).filter(e=>!!e));return l.createElement(s,{flexDirection:`column`},l.createElement(c,null,l.createElement(c,{bold:!0},e.total),l.createElement(c,{color:`gray`},` commits`,d.branch?` · branch=${d.branch}`:``)),l.createElement(c,{color:`gray`},l.createElement(c,{color:`magenta`},`● `,t,` on chart`),l.createElement(c,null,` · `),l.createElement(c,null,n.size,` `,n.size===1?`repo`:`repos`)))}},{id:`list`,title:`Recent`,render:e=>e.deploys.length===0?l.createElement(s,{flexDirection:`column`},l.createElement(c,{color:`gray`},`— no commits yet —`),l.createElement(c,{color:`gray`},"Run `zenovay deploys --connect` to wire up the GitHub integration.")):l.createElement(a,{data:e.deploys.slice(0,30),columns:v})}]})}export{d as deploysCommand};
@@ -1,3 +0,0 @@
1
- import{readConfig as e}from"./config-ZTGpKEWg.js";import{readToken as t}from"./api-BhdaCghp.js";import{formatTabular as n,selectFormat as r}from"./formatter-45-fT1Hv.js";import"./panel-DglZ755S.js";import"./keybar-D2OI-8rx.js";import"./prompt-hjzdzlyj.js";import{spark as i}from"./sparkline-CR_bzxwB.js";import{runAnalyticalScreen as a}from"./analytical-screen-Boiw3NTp.js";import{Table as o}from"./ui-Bk5nl2yb.js";import{ApiV2Client as s}from"./api-v2-B03fp6KF.js";import{Box as c,Text as l}from"ink";import u from"react";function d(e,t){return e.length<=t?e:e.slice(0,t-1)+`…`}function f(e){let t=Math.max(0,Math.floor((Date.now()-new Date(e).getTime())/1e3));return t<60?`${t}s`:t<3600?`${Math.floor(t/60)}m`:t<86400?`${Math.floor(t/3600)}h`:`${Math.floor(t/86400)}d`}async function p(p){let m=await e(),h=await t({strict:!1}),g=p.siteId??h?.teamId??``;if(!g)return process.stderr.write(`No site selected — pass --site-id or set ZENOVAY_SITE.
2
- `),2;let _=new s({config:m,cliVersion:p.cliVersion,token:h}),v=r(p),y=p.window??`24h`,b=p.limit??100,x=[{key:`ts`,header:`when`,width:6,format:e=>f(String(e))},{key:`class`,header:`class`,width:18,format:e=>String(e)},{key:`message`,header:`message`,width:42,format:e=>d(String(e??``),42)},{key:`page`,header:`page`,width:24,format:e=>String(e??`—`)},{key:`device`,header:`device`,width:8,format:e=>String(e??`—`)}];return a({cliVersion:p.cliVersion,title:`errors · ${g} · ${y}`,commandName:`errors`,authToken:h?.accessToken??null,refreshIntervalMs:p.watch?3e4:0,fetcher:e=>_.getErrors(g,{window:y,limit:b},e),format:v,headlessEmit:(e,t)=>{let r=p.search?e.errors.filter(e=>e.class.toLowerCase().includes(p.search.toLowerCase())||e.message.toLowerCase().includes(p.search.toLowerCase())):e.errors;if(t===`json`||t===`ndjson`){if(t===`ndjson`)for(let e of r)process.stdout.write(JSON.stringify(e)+`
3
- `);else process.stdout.write(JSON.stringify({errors:r,total:r.length},null,2));return}process.stdout.write(n(r,[`ts`,`class`,`message`,`page`,`device`,`fingerprint`],t))},panels:[{id:`summary`,title:`Recent errors`,render:e=>{let t=p.search?e.errors.filter(e=>e.class.toLowerCase().includes(p.search.toLowerCase())||e.message.toLowerCase().includes(p.search.toLowerCase())):e.errors,n=new Map,r=Date.now(),a=60;for(let e of t){let t=new Date(e.ts).getTime(),i=Math.floor((r-t)/(60*1e3));if(i<0||i>=a)continue;let o=n.get(e.class)??Array(a).fill(0),s=a-1-i;o[s]+=1,n.set(e.class,o)}let o=[...n.entries()].sort((e,t)=>t[1].reduce((e,t)=>e+t,0)-e[1].reduce((e,t)=>e+t,0)).slice(0,6);return u.createElement(c,{flexDirection:`column`},u.createElement(l,null,u.createElement(l,{bold:!0},t.length),u.createElement(l,{color:`gray`},` errors in `,y)),o.length===0?null:u.createElement(c,{flexDirection:`column`,marginTop:1},o.map(([e,t])=>u.createElement(l,{key:e},u.createElement(l,{color:`red`},e.padEnd(20).slice(0,20)),` `,u.createElement(l,{color:`gray`},i(t,30))))))}},{id:`table`,title:`Detail`,render:e=>{let t=p.search?e.errors.filter(e=>e.class.toLowerCase().includes(p.search.toLowerCase())||e.message.toLowerCase().includes(p.search.toLowerCase())):e.errors;return t.length===0?u.createElement(l,{color:`gray`},`— no errors `,p.search?`matching "${p.search}"`:`in window`,` —`):u.createElement(o,{data:t.slice(0,30),columns:x})}}]})}export{p as errorsCommand};
@@ -1,4 +0,0 @@
1
- import{readConfig as e}from"./config-ZTGpKEWg.js";import{readToken as t}from"./api-BhdaCghp.js";import{formatTabular as n,selectFormat as r}from"./formatter-45-fT1Hv.js";import"./panel-DglZ755S.js";import"./keybar-D2OI-8rx.js";import"./prompt-hjzdzlyj.js";import"./sparkline-CR_bzxwB.js";import{runAnalyticalScreen as i}from"./analytical-screen-Boiw3NTp.js";import{Table as a}from"./ui-Bk5nl2yb.js";import{ApiV2Client as o}from"./api-v2-B03fp6KF.js";import{Box as s,Text as c}from"ink";import l from"react";function u(e,t){let n=Math.round(e*t);return`█`.repeat(Math.max(0,Math.min(t,n)))+`░`.repeat(Math.max(0,t-n))}async function d(d){let p=await e(),m=await t({strict:!1}),h=d.siteId??m?.teamId??``;if(!h)return process.stderr.write(`No site selected — pass --site-id or set ZENOVAY_SITE.
2
- `),2;let g=new o({config:p,cliVersion:d.cliVersion,token:m}),_=r(d);if(!d.funnelId){let e=[{key:`name`,header:`name`,width:30},{key:`stepCount`,header:`steps`,width:6,align:`right`},{key:`id`,header:`id`,width:36,format:e=>String(e).slice(0,36)}];return i({cliVersion:d.cliVersion,title:`funnels · ${h}`,commandName:`funnels`,authToken:m?.accessToken??null,refreshIntervalMs:0,fetcher:e=>g.listFunnels(h,e),format:_,headlessEmit:(e,t)=>{if(t===`json`||t===`ndjson`){process.stdout.write(JSON.stringify(e,null,t===`json`?2:0)),t===`ndjson`&&process.stdout.write(`
3
- `);return}process.stdout.write(n(e.funnels,[`id`,`name`,`stepCount`],t))},panels:[{id:`funnels`,title:`Funnels`,render:t=>t.funnels.length===0?l.createElement(c,{color:`gray`},`— no funnels defined —`):l.createElement(a,{data:t.funnels,columns:e})},{id:`hint`,title:`Next`,render:()=>l.createElement(c,{color:`gray`},"Run `zenovay funnel <id>` for drop-off detail.")}]})}let v=d.window??`30d`;return i({cliVersion:d.cliVersion,title:`funnel · ${d.funnelId} · ${v}`,commandName:`funnel`,authToken:m?.accessToken??null,refreshIntervalMs:0,fetcher:e=>g.getFunnel(h,d.funnelId,v,e),format:_,headlessEmit:(e,t)=>{if(t===`json`||t===`ndjson`){process.stdout.write(JSON.stringify(e,null,t===`json`?2:0)),t===`ndjson`&&process.stdout.write(`
4
- `);return}process.stdout.write(n(e.steps,[`id`,`name`,`visitors`,`conversions`],t))},panels:[{id:`overview`,title:f(`Overview`),render:e=>l.createElement(s,{flexDirection:`column`},l.createElement(c,{bold:!0},e.name),l.createElement(c,{color:`gray`},e.totalEntries.toLocaleString(),` entries · `,e.totalCompletions.toLocaleString(),` completed (`,(e.conversionRate*100).toFixed(1),`%)`))},{id:`flow`,title:`Flow`,render:e=>{let t=e.totalEntries||1;return l.createElement(s,{flexDirection:`column`},e.steps.map((n,r)=>{let i=n.visitors/t,a=e.steps[r-1],o=a?a.visitors-n.visitors:0,d=a?o/Math.max(1,a.visitors)*100:0;return l.createElement(s,{key:n.id,flexDirection:`column`},a?l.createElement(c,{color:`red`},` `,`↓ drop `,o.toLocaleString(),` (`,d.toFixed(1),`%)`):null,l.createElement(c,null,l.createElement(c,{bold:!0},`${r+1}. ${n.name}`.padEnd(22).slice(0,22)),` `,l.createElement(c,{color:`magenta`},u(i,30)),` `,l.createElement(c,null,(i*100).toFixed(1).padStart(5),`% `),l.createElement(c,{color:`gray`},n.visitors.toLocaleString())))}))}}]})}function f(e){return e}export{d as funnelCommand};
@@ -1 +0,0 @@
1
- import"./config-ZTGpKEWg.js";import"./api-BhdaCghp.js";import"./formatter-45-fT1Hv.js";import"./emit-0WJ_OGeT.js";import"./panel-DglZ755S.js";import"./check-S0ACFIfq.js";import{HealthReport as e,exitCodeFor as t,healthCommand as n,runHealthChecks as r}from"./health-B_x_w2CV.js";export{n as healthCommand};
@@ -1 +0,0 @@
1
- import"./config-ZTGpKEWg.js";import"./api-BhdaCghp.js";import{initCommand as e}from"./init-DacZiEma.js";import"./client-DZ4Awt8u.js";import"./formatter-45-fT1Hv.js";import"./emit-0WJ_OGeT.js";import"./login-DHLIZV8C.js";import"./panel-DglZ755S.js";import"./keybar-D2OI-8rx.js";import"./prompt-hjzdzlyj.js";import"./sparkline-CR_bzxwB.js";export{e as initCommand};
@@ -1,62 +0,0 @@
1
- import{readConfig as e}from"./config-ZTGpKEWg.js";import{ApiClient as t,readToken as n}from"./api-BhdaCghp.js";import{parseSseStream as r}from"./client-DZ4Awt8u.js";import{emit as i,isHeadless as a}from"./emit-0WJ_OGeT.js";import{loginCommand as o}from"./login-DHLIZV8C.js";import{Panel as s}from"./panel-DglZ755S.js";import{Banner as c,BrandGradient as l,Keybar as u}from"./keybar-D2OI-8rx.js";import{Select as d}from"./prompt-hjzdzlyj.js";import{spark as f}from"./sparkline-CR_bzxwB.js";import p from"node:path";import{promises as m}from"node:fs";import{Box as h,Text as g,render as _,useApp as v,useInput as y}from"ink";import b,{useEffect as x,useRef as S,useState as C}from"react";import w from"node:os";import{z as T}from"zod";import{globby as E}from"globby";import D from"ink-spinner";import O from"node:crypto";import{ulid as k}from"ulid";import{applyPatch as ee}from"diff";const A=[`@zenovay/tracker`,`@zenovay/next`,`@zenovay/nuxt`,`@zenovay/svelte`,`@zenovay/astro`,`@zenovay/remix`,`@zenovay/node`],te=[`zenovay.config.ts`,`zenovay.config.js`,`zenovay.config.mjs`,`zenovay.config.json`],j=/<script[^>]*src\s*=\s*["']https:\/\/(?:api|cdn)\.zenovay\.com\/[^"']+["'][^>]*>\s*<\/script>/gi,M=/data-id\s*=\s*["'](ZV_[A-Za-z0-9]+)["']/i,N=/data-zenovay-site\s*=\s*["']([^"']+)["']/i,P=[{name:`PostHog`,patterns:[/posthog\.com\b/i,/posthog-js/,/window\.posthog/]},{name:`Plausible`,patterns:[/plausible\.io\/js/i,/window\.plausible/]},{name:`Google Analytics`,patterns:[/googletagmanager\.com\/gtag\/js/i,/www\.google-analytics\.com\/analytics\.js/i,/window\.gtag\b/]},{name:`Mixpanel`,patterns:[/cdn\.mxpnl\.com/i,/mixpanel-browser/]},{name:`Segment`,patterns:[/cdn\.segment\.com\/analytics\.js/i,/window\.analytics\b/]},{name:`Hotjar`,patterns:[/static\.hotjar\.com/i,/\(h,o,t,j,a,r\)/i]},{name:`Amplitude`,patterns:[/cdn\.amplitude\.com/i,/amplitude\.getInstance/]},{name:`Heap`,patterns:[/cdn\.heapanalytics\.com/i]},{name:`FullStory`,patterns:[/fullstory\.com\/s\/fs\.js/i,/window\.FS\.identify/]}];async function F(e,t){let n={zenovayInstalled:!1,correctTrackingCode:!1,foundTrackingCodes:[],zenovayFiles:[],competitors:[],summary:``,recommendation:`fresh-install`};try{let t=await m.readFile(p.join(e,`package.json`),`utf8`),r=JSON.parse(t),i={...r.dependencies,...r.devDependencies};for(let e of A)if(e in i){n.zenovayInstalled=!0,n.packageMarker=e;break}}catch{}for(let t of te)try{await m.access(p.join(e,t)),n.zenovayInstalled=!0,n.configFile=t;break}catch{}let r=await E([`**/*.{html,htm,tsx,jsx,vue,svelte,astro,ts,js,mjs}`,`!node_modules/**`,`!.git/**`,`!dist/**`,`!.next/**`,`!.nuxt/**`,`!build/**`,`!.output/**`],{cwd:e,gitignore:!0,deep:4,absolute:!0}).catch(()=>[]),i=new Map,a=new Set;for(let t of r.slice(0,300)){let r;try{r=await m.readFile(t,`utf8`)}catch{continue}let o=p.relative(e,t),s=r.match(j);if(s&&s.length>0){n.zenovayInstalled=!0;let e=s[0].slice(0,200),t=e.match(M)??e.match(N),r=t?.[1]??null;r&&a.add(r),n.zenovayFiles.push({file:o,currentTrackingCode:r,scriptTagCount:s.length,matchSample:e})}for(let e of P)if(e.patterns.some(e=>e.test(r))){let t=i.get(e.name)??new Set;t.add(o),i.set(e.name,t)}}if(n.foundTrackingCodes=Array.from(a),n.competitors=Array.from(i.entries()).map(([e,t])=>({name:e,files:Array.from(t).slice(0,5)})),n.zenovayInstalled)if(n.foundTrackingCodes.length>0){let e=n.foundTrackingCodes.every(e=>e===t);n.correctTrackingCode=e,n.recommendation=e?`no-op`:`update-tracking-code`}else n.correctTrackingCode=!1,n.recommendation=`no-op`;else n.competitors.length>0?n.recommendation=`fresh-install-alongside-competitor`:n.recommendation=`fresh-install`;return n.summary=I(n,t),n}function I(e,t){let n=[];return e.zenovayInstalled?e.foundTrackingCodes.length===0?n.push(`Zenovay package or config detected but no <script> tag found.`):e.correctTrackingCode?n.push(`Zenovay tracker present in ${e.zenovayFiles.length} file(s) with correct ID ${t}.`):n.push(`Zenovay tracker present in ${e.zenovayFiles.length} file(s), but with mismatching ID(s): ${e.foundTrackingCodes.join(`, `)} (target: ${t}).`):n.push(`No Zenovay tracker found.`),e.competitors.length>0&&n.push(`Competitor tracker(s) present (DO NOT modify): ${e.competitors.map(e=>e.name).join(`, `)}.`),n.join(` `)}async function ne(e){let t=await F(e,``);return{installed:t.zenovayInstalled,reasons:t.summary?[t.summary]:[],packageMarker:t.packageMarker,configFile:t.configFile,scriptFile:t.zenovayFiles[0]?.file}}const re=[{name:`openai-proj`,regex:/\bsk-proj-[A-Za-z0-9_-]{20,}\b/g},{name:`anthropic`,regex:/\bsk-ant-[A-Za-z0-9_-]{20,}\b/g},{name:`openai-sk`,regex:/\bsk-[A-Za-z0-9]{20,}\b/g},{name:`github-pat-new`,regex:/\bgithub_pat_[A-Za-z0-9_]{82}\b/g},{name:`github-pat`,regex:/\bghp_[A-Za-z0-9]{36}\b/g},{name:`github-oauth`,regex:/\bgho_[A-Za-z0-9]{36}\b/g},{name:`aws-access-key`,regex:/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g},{name:`stripe-live`,regex:/\b(?:sk|pk)_live_[A-Za-z0-9]{24,}\b/g},{name:`stripe-test`,regex:/\b(?:sk|pk)_test_[A-Za-z0-9]{24,}\b/g},{name:`stripe-restricted`,regex:/\brk_(?:live|test)_[A-Za-z0-9]{24,}\b/g},{name:`stripe-webhook`,regex:/\bwhsec_[A-Za-z0-9]{24,}\b/g},{name:`slack-bot`,regex:/\bxox[bpoa]-[A-Za-z0-9-]{10,}\b/g},{name:`google-api`,regex:/\bAIza[0-9A-Za-z_-]{35}\b/g},{name:`jwt`,regex:/\beyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g},{name:`private-key-rsa`,regex:/-----BEGIN (?:RSA|EC|OPENSSH|DSA|PGP) PRIVATE KEY(?: BLOCK)?-----/g},{name:`private-key-pkcs8`,regex:/-----BEGIN PRIVATE KEY-----/g}];function ie(e){let t=e;for(let e of re){let n=new RegExp(e.regex.source,e.regex.flags);t=t.replace(n,`[REDACTED:${e.name}]`)}return t}const ae=[/^package\.json$/,/^package-lock\.json$/,/^pnpm-lock\.yaml$/,/^yarn\.lock$/,/^bun\.lock$/,/^tsconfig.*\.json$/,/^(next|nuxt|vite|astro|remix|svelte|tailwind|postcss)\.config\.(ts|mts|cts|js|mjs|cjs)$/,/^app\/.*\.(tsx|ts|jsx|js|svelte|astro|vue)$/,/^pages\/.*\.(tsx|ts|jsx|js)$/,/^public\/index\.html$/,/^index\.html$/,/^src\/main\.(tsx|ts|jsx|js)$/,/^src\/App\.(tsx|ts|jsx|js|svelte|vue)$/,/^src\/routes\/\+layout\.(svelte|ts|js)$/,/^src\/routes\/root\..*$/,/^src\/layouts\/.*\.(astro|svelte|vue)$/,/^\.env\.example$/,/^README\.md$/,/^\.gitignore$/,/^nuxt\.config\.(ts|js|mjs)$/,/^plugins\/.*\.(ts|js)$/],oe=[/(^|\/)\.env($|\.(?!example$)[^/]+$)/,/(^|\/)\.git(\/|$)/,/(^|\/)node_modules\//,/(^|\/)\.ssh\//,/(^|\/)\.aws\//,/\.pem$/,/\.key$/,/(^|\/)id_rsa($|\.)/,/(^|\/)\.npmrc$/,/(^|\/)credentials(\.|$)/],L=256*1024,R=50,z=20,B=40;var V=class extends Error{constructor(e,t){super(t),this.code=e,this.name=`SandboxError`}};const H=/<script[^>]*src\s*=\s*["']https:\/\/(?:api|cdn)\.zenovay\.com\/[^"']+["'][^>]*>\s*<\/script>/i,U=[{name:`PostHog`,re:/posthog\.com\b|posthog-js|window\.posthog/i},{name:`Plausible`,re:/plausible\.io\/js|window\.plausible/i},{name:`Google Analytics`,re:/googletagmanager\.com\/gtag\/js|google-analytics\.com\/analytics\.js|window\.gtag\b/i},{name:`Mixpanel`,re:/cdn\.mxpnl\.com|mixpanel-browser/i},{name:`Segment`,re:/cdn\.segment\.com\/analytics\.js|window\.analytics\b/i},{name:`Hotjar`,re:/static\.hotjar\.com|\(h,o,t,j,a,r\)/i},{name:`Amplitude`,re:/cdn\.amplitude\.com|amplitude\.getInstance/i},{name:`Heap`,re:/cdn\.heapanalytics\.com/i},{name:`FullStory`,re:/fullstory\.com\/s\/fs\.js|window\.FS\.identify/i}];var W=class{sessionId;cwd;cwdReal;undoRoot;readCount=0;writeCount=0;roundCount=0;writtenPathsSet=new Set;constructor(e){this.sessionId=e.sessionId??k(),this.cwd=e.cwd,this.cwdReal=m.realpath(e.cwd),this.undoRoot=e.undoRoot??p.join(w.homedir(),`.zenovay`,`undo`)}incrementRound(){if(this.roundCount++,this.roundCount>B)throw new V(`round-cap`,`Tool-call recursion cap (${B}) exceeded.`)}stats(){return{sessionId:this.sessionId,reads:this.readCount,writes:this.writeCount,rounds:this.roundCount,writtenPaths:[...this.writtenPathsSet]}}async resolveForRead(e){return this.resolveSafe(e,`read`)}async resolveForWrite(e){return this.resolveSafe(e,`write`)}async resolveSafe(e,t){if(typeof e!=`string`||e.length===0)throw new V(`escape`,`Path must be a non-empty string.`);if(e.includes(`\0`))throw new V(`escape`,`Null byte in path.`);if(/^\\\\[?.]\\/.test(e)||/^\\\\[A-Za-z0-9]/.test(e))throw new V(`escape`,`Windows special path prefix: ${e}`);if(/%/.test(e))try{let t=decodeURIComponent(e);if(/%[0-9A-Fa-f]{2}/.test(t))throw new V(`escape`,`Double-encoded path: ${e}`);e=t}catch(t){throw t instanceof V?t:new V(`escape`,`Malformed percent-encoding: ${e}`)}if(e.includes(`\0`))throw new V(`escape`,`Null byte in decoded path.`);if(e.includes(`\\`))throw new V(`escape`,`Backslash in path (Windows-style separator not accepted): ${e}`);let n=await this.cwdReal,r=p.isAbsolute(e)?e:p.join(n,e),i=p.normalize(r),a=i;try{a=await m.realpath(i)}catch(e){if(e.code!==`ENOENT`)throw new V(`escape`,`realpath failed: ${e.message}`);let t=p.dirname(i);try{let e=await m.realpath(t);a=p.join(e,p.basename(i))}catch{}}if(!this.isWithin(a,n))throw new V(`escape`,`Path escapes cwd: ${e}`);let o=p.relative(n,a);for(let e of oe)if(e.test(o)){if(t===`read`&&/(^|\/)node_modules\//.test(o))continue;throw new V(`blocklisted`,`Path is on the hard blocklist: ${o}`)}if(t===`write`){let e=ae.some(e=>e.test(o));if(!e&&!/^\.env(\.local)?$/.test(o)&&!/^\.claude\//.test(o)&&!/^\.cursor\//.test(o))throw new V(`not-allowlisted`,`Write path not on allowlist: ${o}`)}return a}isWithin(e,t){let n=p.relative(t,e);return!n.startsWith(`..`)&&!p.isAbsolute(n)}async safeRead(e){if(this.readCount>=R)throw new V(`read-cap`,`Read cap (${R}) reached.`);let t=await this.resolveForRead(e),n=await m.stat(t);if(n.size>L)throw new V(`too-large`,`File exceeds ${L}B: ${e} (${n.size}B)`);let r=await m.readFile(t),i=r.subarray(0,Math.min(r.length,8192));if(i.includes(0))throw new V(`binary-rejected`,`Binary content in ${e}.`);return this.readCount++,r.toString(`utf8`)}async safeWrite(e,t){if(this.writeCount>=z)throw new V(`write-cap`,`Write cap (${z}) reached.`);if(t.length>L)throw new V(`too-large`,`Write exceeds ${L}B: ${e}`);let n=await this.resolveForWrite(e),r=await m.readFile(n,`utf8`).catch(e=>{if(e.code===`ENOENT`)return null;throw e});if(r!==null){if(H.test(r)&&!H.test(t))throw new V(`destructive-tracker-removal`,`Refusing to write ${e}: existing Zenovay tracker tag would be removed. If you want to change the data-id, use patch_file to swap the attribute value instead of overwriting the file.`);for(let{name:n,re:i}of U)if(i.test(r)&&!i.test(t))throw new V(`destructive-competitor-removal`,`Refusing to write ${e}: existing ${n} tracker would be removed. Zenovay installs alongside competitors — never replace them.`)}let i=await this.journalBackup(n);await m.mkdir(p.dirname(n),{recursive:!0}),await m.writeFile(n,t,`utf8`),this.writeCount++;let a=await this.cwdReal;return this.writtenPathsSet.add(p.relative(a,n)),{backupPath:i}}async journalBackup(e){let t=await m.readFile(e).catch(e=>{if(e.code===`ENOENT`)return null;throw e}),n=p.join(this.undoRoot,this.sessionId);await m.mkdir(n,{recursive:!0,mode:448});let r=O.createHash(`sha256`).update(e).digest(`hex`).slice(0,16),i=p.join(n,`${r}.bak`),a=p.join(n,`manifest.jsonl`);t&&await m.writeFile(i,t,{mode:384});let o=JSON.stringify({abs:e,backupPath:t?i:null,ts:Date.now()});return await m.appendFile(a,o+`
2
- `,{mode:384}),t?i:null}static wrapForModel(e,t){let n=O.createHash(`sha256`).update(t).digest(`hex`).slice(0,16),r=t.replaceAll(`&`,`&amp;`).replaceAll(`<`,`&lt;`).replaceAll(`>`,`&gt;`);return`<FILE path="${e}" sha256="${n}">\n${r}\n</FILE>`}static scrubSecrets(e){return ie(e)}};const se=[`astro.config.ts`,`astro.config.mjs`,`astro.config.js`];async function ce(e){for(let t of se)if(await e.exists(t))return{matched:!0,confidence:.95,reason:`Detected Astro via \`${t}\`.`};let t=await e.readFile(`package.json`);if(t)try{let e=JSON.parse(t);if(e.dependencies?.astro??e.devDependencies?.astro)return{matched:!0,confidence:.8,reason:"Detected Astro via `astro` dependency."}}catch{}return{matched:!1,confidence:0,reason:"No astro.config.* or `astro` dependency found."}}function le(e){let t=e.trackingCode??e.siteId??``,n=`<script defer data-id="${t}" data-allow-localhost="true" src="https://api.zenovay.com/z.js" is:inline></script>`;return[{targetPath:`src/layouts/Layout.astro`,anchorKind:`head-tag`,code:n,description:`Inject the Zenovay tracker inside <head> of the primary layout.`},{targetPath:`src/layouts/BaseHead.astro`,anchorKind:`head-tag`,code:n,description:"Fallback target when the project uses a dedicated `BaseHead.astro`."}]}const ue={id:`astro`,displayName:`Astro`,detect:ce,files:[{path:`src/layouts/Layout.astro`,kind:`mutate`,required:!1},{path:`src/layouts/BaseHead.astro`,kind:`mutate`,required:!1},{path:`.env`,kind:`create`,required:!0}],envVarName:`PUBLIC_ZENOVAY_SITE`,buildSnippets:le},de=[`app/layout.tsx`,`app/layout.ts`,`app/layout.jsx`,`app/layout.js`];async function fe(e){for(let t of de)if(await e.exists(t))return t;return null}async function pe(e){let t=await e.readFile(`package.json`);if(!t)return!1;try{let e=JSON.parse(t);return!!(e.dependencies?.next??e.devDependencies?.next)}catch{return!1}}async function me(e){let t=await pe(e),n=await e.exists(`app`),r=await fe(e);return t?n?r?{matched:!0,confidence:.95,reason:`Detected Next.js App Router via \`next\` dep + \`${r}\`.`}:{matched:!1,confidence:.4,reason:"Found `app/` but no root layout file (layout.tsx/ts/jsx/js)."}:{matched:!1,confidence:0,reason:"No `app/` directory found — not an App Router project."}:{matched:!1,confidence:0,reason:"package.json does not list `next` as a dependency."}}function he(e){let t=`app/layout.tsx`,n=e.trackingCode??e.siteId??``;return[{targetPath:t,anchorKind:`after-imports`,code:`import Script from 'next/script';`,description:`Import next/script to inject the Zenovay tracker.`},{targetPath:t,anchorKind:`wrap-children`,code:`<Script
3
- defer
4
- data-id="${n}"
5
- data-allow-localhost="true"
6
- src="https://api.zenovay.com/z.js"
7
- strategy="afterInteractive"
8
- />
9
- {children}`,description:`Add the Zenovay tracker <Script> next to children in the root layout.`}]}const ge={id:`next-app-router`,displayName:`Next.js (App Router)`,detect:me,files:[{path:`app/layout.tsx`,kind:`mutate`,required:!0}],envVarName:`NEXT_PUBLIC_ZENOVAY_SITE`,buildSnippets:he},_e=[`pages/_app.tsx`,`pages/_app.ts`,`pages/_app.jsx`,`pages/_app.js`,`src/pages/_app.tsx`,`src/pages/_app.ts`,`src/pages/_app.jsx`,`src/pages/_app.js`];async function ve(e){for(let t of _e)if(await e.exists(t))return t;return null}async function ye(e){let t=await e.readFile(`package.json`);if(!t)return!1;try{let e=JSON.parse(t);return!!(e.dependencies?.next??e.devDependencies?.next)}catch{return!1}}async function be(e){let t=await ye(e);if(!t)return{matched:!1,confidence:0,reason:"package.json does not list `next` as a dependency."};let n=await ve(e);if(n)return{matched:!0,confidence:.9,reason:`Detected Next.js Pages Router via \`${n}\`.`};let r=await e.exists(`app`),i=await e.glob(`pages/**/*.{tsx,ts,jsx,js}`);return i.length>0&&!r?{matched:!0,confidence:.7,reason:"Found `pages/` directory with route files but no `_app` — will create one."}:{matched:!1,confidence:.2,reason:`Next.js detected, but no pages-router entry point found.`}}function xe(e){let t=`pages/_app.tsx`,n=e.trackingCode??e.siteId??``,r=`import type { AppProps } from 'next/app';
10
- import Script from 'next/script';
11
-
12
- export default function App({ Component, pageProps }: AppProps) {
13
- return (
14
- <>
15
- <Script
16
- defer
17
- data-id="${n}"
18
- data-allow-localhost="true"
19
- src="https://api.zenovay.com/z.js"
20
- strategy="afterInteractive"
21
- />
22
- <Component {...pageProps} />
23
- </>
24
- );
25
- }
26
- `;return[{targetPath:t,anchorKind:`after-imports`,code:`import Script from 'next/script';`,description:"Import next/script in `_app`."},{targetPath:t,anchorKind:`wrap-children`,code:`<><Script defer data-id="${n}" data-allow-localhost="true" src="https://api.zenovay.com/z.js" strategy="afterInteractive" /><Component {...pageProps} /></>`,description:`Render the Zenovay tracker alongside the page component.`},{targetPath:t,anchorKind:`replace-file`,code:r,description:"Full replacement when `_app` does not exist yet."}]}const Se={id:`next-pages-router`,displayName:`Next.js (Pages Router)`,detect:be,files:[{path:`pages/_app.tsx`,kind:`mutate`,required:!0}],envVarName:`NEXT_PUBLIC_ZENOVAY_SITE`,buildSnippets:xe},Ce=T.object({modules:T.array(T.string()).optional(),runtimeConfig:T.object({public:T.record(T.string(),T.unknown()).optional()}).optional()}).passthrough();async function we(e){let t=await e.readFile(`package.json`);if(!t)return{matched:!1,confidence:0,reason:`No package.json found.`};try{let e=JSON.parse(t),n=!!(e.dependencies?.nuxt??e.devDependencies?.nuxt??e.dependencies?.nuxt3??e.devDependencies?.nuxt3);if(n)return{matched:!0,confidence:.95,reason:"Detected Nuxt via `nuxt` / `nuxt3` dependency."}}catch{}let n=await e.exists(`nuxt.config.ts`)||await e.exists(`nuxt.config.js`)||await e.exists(`nuxt.config.mjs`);return n?{matched:!0,confidence:.6,reason:"Found `nuxt.config.*` but no explicit dependency listing."}:{matched:!1,confidence:0,reason:`No Nuxt dependency or config detected.`}}function Te(e){let t=e.trackingCode??e.siteId??``,n=` app: {
27
- head: {
28
- script: [
29
- {
30
- defer: true,
31
- src: 'https://api.zenovay.com/z.js',
32
- 'data-id': '${t}',
33
- 'data-allow-localhost': 'true',
34
- },
35
- ],
36
- },
37
- },`;return[{targetPath:`nuxt.config.ts`,anchorKind:`head-tag`,code:n,description:"Add the Zenovay tracker to Nuxt's `app.head.script` so every page loads it."}]}const Ee={id:`nuxt`,displayName:`Nuxt`,detect:we,files:[{path:`nuxt.config.ts`,kind:`mutate`,required:!0}],envVarName:`NUXT_PUBLIC_ZENOVAY_SITE`,buildSnippets:Te},De=[`index.html`,`public/index.html`,`dist/index.html`];async function Oe(e){for(let t of De)if(await e.exists(t))return{matched:!0,confidence:.5,reason:`Detected plain HTML project via \`${t}\`.`};let t=await e.glob(`**/*.html`);return t.length>0?{matched:!0,confidence:.3,reason:`Found ${t.length} HTML file(s); plain-HTML adapter is usable as fallback.`}:{matched:!1,confidence:0,reason:`No HTML files found in the project.`}}function ke(e){let t=e.siteId??``,n=`<script defer\n data-id="${t}"\n data-allow-localhost="true"\n src="https://api.zenovay.com/z.js">\n</script>`;return[{targetPath:`index.html`,anchorKind:`head-tag`,code:n,description:`Inject the Zenovay tracker inside <head>. Repeat for every HTML file that contains a <head>.`}]}const Ae={id:`plain-html`,displayName:`Plain HTML`,detect:Oe,files:[{path:`index.html`,kind:`mutate`,required:!0}],envVarName:`PUBLIC_ZENOVAY_SITE`,buildSnippets:ke};async function je(e){let t=await e.readFile(`package.json`);if(t)try{let e=JSON.parse(t),n={...e.dependencies??{},...e.devDependencies??{}},r=Object.keys(n).some(e=>e.startsWith(`@remix-run/`));if(r)return{matched:!0,confidence:.95,reason:"Detected Remix via `@remix-run/*` dependencies."}}catch{}return await e.exists(`remix.config.js`)||await e.exists(`remix.config.ts`)?{matched:!0,confidence:.8,reason:"Detected Remix via `remix.config.*`."}:{matched:!1,confidence:0,reason:`No Remix dependency or config detected.`}}function Me(e){let t=e.trackingCode??e.siteId??``;return[{targetPath:`app/root.tsx`,anchorKind:`head-tag`,code:`<script defer data-id="${t}" data-allow-localhost="true" src="https://api.zenovay.com/z.js"></script>`,description:`Inline the Zenovay tracker <script> inside the document <head>.`}]}const Ne={id:`remix`,displayName:`Remix`,detect:je,files:[{path:`app/root.tsx`,kind:`mutate`,required:!0}],envVarName:`PUBLIC_ZENOVAY_SITE`,buildSnippets:Me};async function Pe(e){let t=await e.readFile(`package.json`);if(!t)return{matched:!1,confidence:0,reason:`No package.json found.`};try{let e=JSON.parse(t),n=!!(e.dependencies?.[`@sveltejs/kit`]??e.devDependencies?.[`@sveltejs/kit`]);return n?{matched:!0,confidence:.95,reason:"Detected SvelteKit via `@sveltejs/kit` dependency."}:{matched:!1,confidence:0,reason:"`@sveltejs/kit` not in dependencies."}}catch{return{matched:!1,confidence:0,reason:`package.json is not valid JSON.`}}}function Fe(e){let t=e.trackingCode??e.siteId??``,n=`<svelte:head>
38
- <script defer data-id="${t}" data-allow-localhost="true" src="https://api.zenovay.com/z.js"></script>
39
- </svelte:head>
40
-
41
- <slot />
42
- `;return[{targetPath:`src/routes/+layout.svelte`,anchorKind:`replace-file`,code:n,description:`Root layout that loads the Zenovay tracker in every route via <svelte:head>.`}]}const Ie={id:`sveltekit`,displayName:`SvelteKit`,detect:Pe,files:[{path:`src/routes/+layout.svelte`,kind:`mutate`,required:!0}],envVarName:`PUBLIC_ZENOVAY_SITE`,buildSnippets:Fe},Le=[ge,Se,Ee,Ie,ue,Ne,Ae];async function G(e){let t=[];for(let n of Le){let r=await n.detect(e);t.push({adapter:n,result:r})}let n=[...t].sort((e,t)=>t.result.confidence-e.result.confidence),r=n[0],i=r&&r.result.matched?r.adapter:null;return{adapter:i,ranked:n}}function K(e){let t=t=>p.resolve(e,t);return{cwd:e,async readFile(e){try{return await m.readFile(t(e),`utf8`)}catch(e){let t=e.code;if(t===`ENOENT`||t===`EISDIR`)return null;throw e}},async exists(e){try{return await m.access(t(e)),!0}catch{return!1}},async glob(t){return E(t,{cwd:e,dot:!1,gitignore:!0,onlyFiles:!0,followSymbolicLinks:!1})}}}async function q(e,t){let n=K(e),{adapter:r,ranked:i}=await G(n),a=i[0];return r&&a&&a.result.confidence>=.7?r:t?t.pickInteractively(i):r}function Re(e,t){let n=/[\s"'#=]/.test(t)||t===``,r=n?`"${t.replace(/\\/g,`\\\\`).replace(/"/g,`\\"`)}"`:t;return`${e}=${r}`}function ze(e){let t=new Set;for(let n of e.split(/\r?\n/)){let e=n.trim();if(!e||e.startsWith(`#`))continue;let r=e.indexOf(`=`);if(r<=0)continue;let i=e.slice(0,r).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&t.add(i)}return t}async function J(e,t,n={}){let r=n.filename??`.env.local`,i=p.resolve(e,r),a=``,o=!0;try{a=await m.readFile(i,`utf8`)}catch(e){if(e.code===`ENOENT`)o=!1;else throw e}let s=o?ze(a):new Set,c=[],l=[],u=[];for(let[e,n]of Object.entries(t)){if(s.has(e)){l.push(e);continue}u.push(Re(e,n)),c.push(e)}if(c.length===0)return{created:!1,existing:o,addedKeys:c,skippedKeys:l};let d=`# Added by Zenovay CLI`,f;if(o){let e=a.length>0&&!a.endsWith(`
43
- `);f=a+(e?`
44
- `:``)+`
45
- `+d+`
46
- `+u.join(`
47
- `)+`
48
- `}else f=d+`
49
- `+u.join(`
50
- `)+`
51
- `;if(o)await m.writeFile(i,f,`utf8`);else{let e=await m.open(i,`w`,384);try{await e.writeFile(f,`utf8`)}finally{await e.close()}}return{created:!o,existing:o,addedKeys:c,skippedKeys:l}}const Be=`https://api.zenovay.com/mcp`,Ve=T.object({url:T.string().url(),headers:T.record(T.string(),T.string()).optional()}),He=T.object({mcpServers:T.record(T.string(),Ve).optional()}).passthrough();function Ue(e){return e.HOME??e.USERPROFILE??w.homedir()}function We(e){return e.APPDATA??null}function Ge(e,t){let n=Ue(t),r=We(t),i=[];return i.push({id:`cursor`,displayName:`Cursor`,configPath:p.join(n,`.cursor`,`mcp.json`)}),e===`win32`&&r&&i.push({id:`cursor`,displayName:`Cursor (AppData)`,configPath:p.join(r,`Cursor`,`User`,`globalStorage`,`cursor.mcp`,`mcp.json`)}),e===`darwin`?i.push({id:`claude-desktop`,displayName:`Claude Desktop`,configPath:p.join(n,`Library`,`Application Support`,`Claude`,`claude_desktop_config.json`)}):e===`win32`&&r?i.push({id:`claude-desktop`,displayName:`Claude Desktop`,configPath:p.join(r,`Claude`,`claude_desktop_config.json`)}):i.push({id:`claude-desktop`,displayName:`Claude Desktop`,configPath:p.join(n,`.config`,`Claude`,`claude_desktop_config.json`)}),i.push({id:`vscode`,displayName:`VS Code`,configPath:p.join(n,`.vscode`,`mcp.json`)}),i}async function Ke(e){try{return await m.access(e),!0}catch{return!1}}async function qe(e){try{let t=await m.readFile(e,`utf8`);if(t.trim().length===0)return{};let n=JSON.parse(t),r=He.safeParse(n);return r.success?r.data:n&&typeof n==`object`?n:{}}catch{return{}}}function Je(e){return{url:Be,headers:{Authorization:`Bearer ${e}`}}}async function Y(e){let t=e.env??process.env,n=e.platform??process.platform,r=new Set(e.skip??[]),i=[],a=[],o=[],s=new Set,c=Je(e.accessToken);for(let e of Ge(n,t)){if(r.has(e.id)){a.push(e.displayName);continue}if(s.has(e.configPath))continue;s.add(e.configPath);try{let t=await Ke(e.configPath);if(!t){a.push(e.displayName);continue}let n=await qe(e.configPath),r=`${e.configPath}.bak`;await m.copyFile(e.configPath,r);let o={...n,mcpServers:{...n.mcpServers??{},zenovay:c}};await m.mkdir(p.dirname(e.configPath),{recursive:!0}),await m.writeFile(e.configPath,JSON.stringify(o,null,2)+`
52
- `,`utf8`),i.push(e.displayName)}catch(t){o.push({client:e.displayName,message:t instanceof Error?t.message:String(t)})}}return{installed:i,skipped:a,errors:o}}async function Ye(e,t,n){let r=n.timeoutMs??18e4,i=n.pollIntervalMs??2e3,a=n.now??(()=>Date.now()),o=n.sleep??(e=>new Promise(t=>setTimeout(t,e))),s=a(),c=s+r;for(n.onTick?.(0);;){let l=await n.api.getFirstEvent({siteId:e,since:t});if(l.received)return{received:!0,event:l.event};let u=a()-s;if(u>=r)return{received:!1};let d=c-a(),f=Math.min(i,Math.max(0,d));if(f<=0)return{received:!1};await o(f),n.onTick?.(a()-s)}}const Xe=T.object({path:T.string().min(1)}),Ze=T.object({path:T.string().min(1),content:T.string(),reason:T.string().min(1)}),Qe=T.object({path:T.string().min(1),patch:T.string().min(1),reason:T.string().min(1)}),$e=T.object({}),et=T.object({question:T.string().min(1),choices:T.array(T.string()).optional()});async function tt(e,t){let n=Xe.safeParse(t);if(!n.success)return{ok:!1,content:null,error:`invalid_args`};try{let t=await e.safeRead(n.data.path),r=W.scrubSecrets(t);return{ok:!0,content:W.wrapForModel(n.data.path,r)}}catch(e){return{ok:!1,content:null,error:e.message}}}async function nt(e,t,n){let r=Ze.safeParse(t);if(!r.success)return{ok:!1,content:null,error:`invalid_args`};let{path:i,content:a,reason:o}=r.data,s=``;try{s=await e.safeRead(i)}catch{s=``}let c=await n.approve({path:i,oldContent:s,newContent:a,reason:o});if(c===`n`)return{ok:!1,content:null,error:`skipped_by_user`};if(c===`e`)return{ok:!1,content:null,error:`deferred_to_user_edit`};try{let{backupPath:t}=await e.safeWrite(i,a);return{ok:!0,content:{path:i,backupPath:t}}}catch(e){return{ok:!1,content:null,error:e.message}}}async function rt(e,t,n){let r=Qe.safeParse(t);if(!r.success)return{ok:!1,content:null,error:`invalid_args`};let{path:i,patch:a,reason:o}=r.data;if(/^\*\*\*\s+Begin Patch/m.test(a)||/^\*\*\*\s+Update File:/m.test(a))return{ok:!1,content:null,error:'unsupported_patch_format: This tool only accepts STANDARD unified diff with `--- a/...`, `+++ b/...`, and `@@ -N,M +N,M @@` headers. The "*** Begin Patch / *** Update File:" V4A format is NOT supported. Please call write_file with the full new file content instead.'};let s;try{s=await e.safeRead(i)}catch(e){return{ok:!1,content:null,error:e.message}}let c;try{c=ee(s,a)}catch(e){return{ok:!1,content:null,error:`patch_failed: ${e.message}. Please call write_file with the full new file content instead — write_file is more reliable than patch_file for this use case.`}}return c===!1||typeof c!=`string`?{ok:!1,content:null,error:`patch_did_not_apply_cleanly. The patch context may not match the file. Please call write_file with the full new file content instead.`}:nt(e,{path:i,content:c,reason:o},n)}async function it(e){try{let t=K(e),{adapter:n,ranked:r}=await G(t);return{ok:!0,content:{matched:n!==null,adapter:n?.id,displayName:n?.displayName,ranked:r.map(e=>({id:e.adapter.id,confidence:e.result.confidence,reason:e.result.reason}))}}}catch(e){return{ok:!1,content:null,error:e.message}}}async function at(e,t){let n=et.safeParse(t);if(!n.success)return{ok:!1,content:null,error:`invalid_args`};try{let t=await e.ask(n.data);return{ok:!0,content:{answer:t}}}catch(e){return{ok:!1,content:null,error:e.message}}}async function ot(e){let{api:t,sandbox:n,approval:i,prompter:a,handlers:o}=e,s=[...e.initialMessages],c=``,l=0;for(;l<B;){n.incrementRound(),l++;let u=await t.openAiStream(`install`,{messages:s,cwd_fingerprint:n.sessionId,diagnosis:e.diagnosis,targetTrackingCode:e.targetTrackingCode}),d=[],f=``;for await(let e of r(u))switch(e.type){case`delta`:f+=e.content,o?.onDelta?.(e.content);break;case`tool_start`:o?.onToolStart?.({id:e.id,name:e.name});break;case`tool_call`:{let t=await st(e.name,e.arguments,{sandbox:n,cwd:n.cwd,approval:i,prompter:a});d.push({id:e.id,name:e.name,arguments:e.arguments,result:t}),o?.onToolResult?.({id:e.id,name:e.name,result:t});break}case`usage`:o?.onUsage?.(e);break;case`error`:throw o?.onError?.(e),Error(`[${e.code}] ${e.message}`);case`done`:break}if(f&&(c+=f),d.length===0){f&&s.push({role:`assistant`,content:f});break}s.push({role:`assistant`,content:f,toolCalls:d.map(e=>({id:e.id,type:`function`,function:{name:e.name,arguments:JSON.stringify(e.arguments)}}))});for(let e of d)s.push({role:`tool`,toolCallId:e.id,toolName:e.name,content:JSON.stringify(e.result)})}return{finalText:c,rounds:l}}async function st(e,t,n){try{switch(e){case`read_file`:return await tt(n.sandbox,t);case`write_file`:return await nt(n.sandbox,t,n.approval);case`patch_file`:return await rt(n.sandbox,t,n.approval);case`detect_framework`:return await it(n.cwd);case`ask_user`:return await at(n.prompter,t);default:return{ok:!1,content:null,error:`unknown_tool:${e}`}}}catch(e){return{ok:!1,content:null,error:`tool_threw: ${e.message}`}}}const ct=e=>`<script defer\n data-id="${e}"\n data-allow-localhost="true"\n src="https://api.zenovay.com/z.js">\n</script>`;async function lt(e){let t={installed:[],skipped:[],errors:[]},n=await E([`**/*.html`,`!node_modules/**`,`!.git/**`,`!dist/**`,`!.next/**`,`!.nuxt/**`,`!build/**`,`!.output/**`],{cwd:e.cwd,gitignore:!0,absolute:!1});if(n.length===0)return t;let r=ct(e.trackingCode),i=RegExp(`data-id\\s*=\\s*["']${ut(e.trackingCode)}["']`);for(let a of n){let n=p.join(e.cwd,a),o;try{o=await m.readFile(n,`utf8`)}catch(e){t.errors.push({file:a,error:e.message});continue}if(H.test(o)&&i.test(o)){t.skipped.push({file:a,reason:`already installed with correct tracking code`});continue}let s;if(H.test(o))s=o.replace(/(<script[^>]*src\s*=\s*["']https:\/\/(?:api|cdn)\.zenovay\.com\/[^"']+["'][^>]*>)/i,t=>t.replace(/data-id\s*=\s*["']ZV_\w+["']/i,`data-id="${e.trackingCode}"`)),s===o&&(s=o.replace(/<script(\s)/i,`<script$1data-id="${e.trackingCode}"$1`));else if(e.updateOnly){t.skipped.push({file:a,reason:`updateOnly=true and no Zenovay tag present`});continue}else if(/<\/head>/i.test(o)){if(s=o.replace(/(\n[\t ]*)?<\/head>/i,(e,t)=>{let n=t??`
53
- `,i=r.replace(/\n/g,`${n}`);return`${n}${i}${n}</head>`}),s===o){t.skipped.push({file:a,reason:`</head> regex did not match unexpectedly`});continue}}else{t.skipped.push({file:a,reason:`no <head>...</head> in file (fragment or non-page)`});continue}let c=null;for(let{name:e,re:t}of U)if(t.test(o)&&!t.test(s)){c=e;break}if(c){t.errors.push({file:a,error:`would remove ${c} tracker — refusing to write`});continue}try{await m.writeFile(n,s,`utf8`),t.installed.push(a)}catch(e){t.errors.push({file:a,error:e.message})}}return t}function ut(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function dt(){let e=[12,15,18,22,28,35,41,50,58,64,72,78],t=f(e,24);return[` ↑`,` ${t}`,` └────────────────────────`,` May Jun Jul Aug Sep`]}function ft(){return[` Landing page ████████████████████ 100%`,` ↓ -28%`,` Pricing ██████████████░░░░░░ 72%`,` ↓ -50%`,` Checkout ███████░░░░░░░░░░░░░ 36%`,` ↓ -64%`,` Purchased ███░░░░░░░░░░░░░░░░░ 13%`]}function pt(){return[` ▇▇▇▇▇▇▇▇▇▎ 89 Sarah K. /pricing 🇺🇸`,` ▇▇▇▇▇▇░░░░ 61 anon /docs 🇩🇪`,` ▇▇▇░░░░░░░ 34 anon /changelog 🇯🇵`]}function mt(){return[` LCP ● 2.1s good ████████████░░░░░░`,` INP ● 89ms good ██████████████████`,` CLS ⚠ 0.14 needs ████████████░░░░░░`,` TTFB ● 380ms good ███████████████░░░`]}const X=[{title:`Welcome`,body:[`The wizard is an agent — it handles the entire`,`Zenovay setup process on your behalf.`,``,`Reading your project, deciding where the tracker`,`belongs, and writing the snippet for you.`]},{title:`Events`,body:[`Events are the foundation of Zenovay analytics.`,``,`Every pageview, click, and custom action is an`,`event. Group them into Goals to track conversions.`]},{title:`Trends`,body:[`Use trends to measure growth.`,``,`See how visitors, signups, and revenue have`,`changed over the last week, month, or quarter.`],visual:dt},{title:`Funnels`,body:[`Funnels reveal where users drop off.`,``,`Define the steps you care about — landing,`,`pricing, checkout, purchase — and Zenovay shows`,`the per-step conversion rate.`],visual:ft},{title:`Live visitors`,body:[`Watch every visitor in real time, ranked by an`,`AI score that highlights high-intent traffic.`,``,"Use `zenovay visitors --live` after install."],visual:pt},{title:`Core Web Vitals`,body:[`LCP, INP, CLS — Google's page-experience metrics,`,`collected automatically once the tracker is in.`,``,"Use `zenovay vitals` to see them per page + device."],visual:mt},{title:`MCP integration`,body:[`Your CLI session can install Zenovay's MCP server`,`into Cursor / Claude Desktop / VS Code.`,``,`Then ask your AI: "what were my top pages today?"`,`and it queries Zenovay directly.`]},{title:`AI insights`,body:[`Zenovay watches your data and surfaces anomalies`,`automatically — traffic spikes, error bursts,`,`revenue drops — without you needing to ask.`,``,"Run `zenovay ai` after install to chat with them."]},{title:`Privacy-first`,body:[`No cookies required. No third-party trackers.`,`Cookieless mode is one toggle in your dashboard.`,``,`GDPR, CCPA, and PECR-compliant out of the box.`]}],ht=8e3,gt=({width:e,height:t})=>{let[n,r]=C(0);x(()=>{let e=setInterval(()=>{r(e=>(e+1)%X.length)},ht);return()=>clearInterval(e)},[]);let i=X[n],a=i.visual?i.visual():[],o=X.map((e,t)=>t===n?`●`:`·`).join(` `);return b.createElement(h,{flexDirection:`column`,width:e,height:t,paddingX:2,paddingY:1},b.createElement(h,{marginBottom:1},b.createElement(g,{color:`magentaBright`,bold:!0},`Learn`)),b.createElement(h,{marginBottom:1},b.createElement(g,{bold:!0,color:`white`},i.title)),i.body.map((e,t)=>b.createElement(g,{key:t,color:`gray`},e||` `)),a.length>0&&b.createElement(h,{flexDirection:`column`,marginTop:1},a.map((e,t)=>b.createElement(g,{key:t,color:`cyan`},e))),b.createElement(h,{flexGrow:1}),b.createElement(h,{marginTop:1},b.createElement(g,{color:`gray`,dimColor:!0},o,` · `,n+1,` / `,X.length)))},_t={pending:`·`,active:`⠋`,done:`✓`,error:`✗`},vt={pending:`gray`,active:`magenta`,done:`green`,error:`red`},yt=({tasks:e,width:t,height:n,liveLine:r})=>{let i=e.filter(e=>e.status===`done`).length;return b.createElement(h,{flexDirection:`column`,width:t,height:n,paddingX:2,paddingY:1},b.createElement(h,{marginBottom:1},b.createElement(g,{color:`magentaBright`,bold:!0},`Tasks`)),e.map(e=>b.createElement(h,{key:e.id,flexDirection:`column`},b.createElement(h,null,e.status===`active`?b.createElement(g,{color:`magenta`},b.createElement(D,{type:`dots`})):b.createElement(g,{color:vt[e.status]},_t[e.status]),b.createElement(g,null,` `),b.createElement(g,{color:e.status===`pending`?`gray`:`white`},e.label)),e.detail&&b.createElement(h,{paddingLeft:2},b.createElement(g,{color:`gray`,dimColor:!0},e.detail)))),b.createElement(h,{flexGrow:1}),r&&b.createElement(h,{marginTop:1},b.createElement(g,{color:`cyan`},`◆ `),b.createElement(g,{color:`white`},r)),b.createElement(h,{marginTop:1},b.createElement(g,{color:`gray`,dimColor:!0},i,` / `,e.length)))};async function bt(e){if(a(e))return xt(e);let t=`quit`,n=null,r=await new Promise(r=>{let{unmount:i,waitUntilExit:a}=_(b.createElement(St,{opts:e,onExit:(e,a,o)=>{t=a??`quit`,n=o??null,i(),r(e)}}));a().catch(()=>r(1))});if(r!==0||t===`quit`||!n)return r;process.stdout.isTTY&&process.stdout.write(`\x1B[?1049l\x1B[2J\x1B[H`);let i=n.id;if(t===`watch`){let{watchCommand:t}=await import(`./watch-CtIJ1ZAz.js`);return t({cliVersion:e.cliVersion,siteId:i})}if(t===`events`){let{eventsTailCommand:t}=await import(`./events-tail-C35jGarq.js`);return t({cliVersion:e.cliVersion,siteId:i})}return 0}async function xt(r){try{let a=await e(),o=await q(r.cwd);if(!o)return i({type:`error`,code:`no_framework`,message:`Could not detect framework (headless mode has no picker).`}),2;i({type:`framework.detected`,framework:o.id,confidence:1});let s=await n({strict:!1});if(!s&&!process.env.ZENOVAY_API_TOKEN)return i({type:`error`,code:`not_logged_in`,message:"Run `zenovay login` first (or set ZENOVAY_API_TOKEN)."}),2;let c=new t({config:a,cliVersion:r.cliVersion,token:s}),l=await c.getSites(),u=r.siteId?l.find(e=>e.id===r.siteId):l[0];if(!u&&r.siteId)return i({type:`error`,code:`site_not_found`,message:`Site ${r.siteId} not found.`}),2;if(!u)return i({type:`error`,code:`no_site`,message:`No sites exist; create one at app.zenovay.com or re-run interactively.`}),2;i({type:`info`,message:`Using site ${u.id} (${u.name}) trackingCode=${u.trackingCode??u.id}`});let d=await J(r.cwd,{[o.envVarName]:u.trackingCode??u.id});return i({type:`info`,message:`env vars added: ${d.addedKeys.join(`,`)}`}),i({type:`done`,command:`init`,exitCode:0}),0}catch(e){return i({type:`error`,code:`init_failed`,message:e.message}),1}}const St=({opts:r,onExit:i})=>{let{exit:a}=v(),[l,d]=C(`intro`),[f,p]=C(null),[m,_]=C([]),[y,w]=C(null),[T,E]=C(null),[O,k]=C(null),[ee,A]=C([]),[te,j]=C(void 0),[M,N]=C(null),[P,F]=C(0),I=S(!1);return x(()=>(process.stdout.isTTY&&process.stdout.write(`\x1B[?1049h\x1B[H`),()=>{process.stdout.isTTY&&process.stdout.write(`\x1B[?1049l`)}),[]),x(()=>{I.current||(I.current=!0,(async()=>{try{d(`detecting`);let i=await q(r.cwd);if(!i){k(`Could not detect your framework. Supported: Next.js, Nuxt, SvelteKit, Astro, Remix, plain HTML.`),d(`error`);return}p(i);let a=await n({strict:!1});!process.env.ZENOVAY_API_TOKEN&&!a&&(d(`login`),await o({cliVersion:r.cliVersion})),d(`loading-sites`);let s=await e(),c=await n({strict:!1}),l=new t({config:s,cliVersion:r.cliVersion,token:c}),u=await l.getSites(),f=await Ft(r.cwd),m=It(u,f);if(_(u),w(f),u.length===0){d(`create-site`);return}if(r.siteId){let e=u.find(e=>e.id===r.siteId);if(!e){k(`Site ${r.siteId} not found in your account.`),d(`error`);return}E(e),Z(e,i,r,{setPhase:d,setErrorMsg:k,setTasks:A,setLiveLine:j,setSandboxStats:N});return}if(r.yes&&m){E(m),Z(m,i,r,{setPhase:d,setErrorMsg:k,setTasks:A,setLiveLine:j,setSandboxStats:N});return}d(`site-picker`)}catch(e){k(e.message),d(`error`)}})())},[]),x(()=>{process.stdout.isTTY&&process.stdout.write(`\x1B[2J\x1B[H`),l===`error`&&setTimeout(()=>{a(),i(1)},8e3)},[l]),b.createElement(h,{flexDirection:`column`},b.createElement(c,{version:r.cliVersion,subtitle:`AI install wizard`}),l===`intro`&&b.createElement(Ct,null),l===`detecting`&&b.createElement(s,{title:`Scanning`,state:`busy`},b.createElement(h,null,b.createElement(g,{color:`magenta`},b.createElement(D,{type:`dots`})),b.createElement(g,null,` Detecting framework…`))),l===`login`&&b.createElement(s,{title:`Authenticating`,state:`busy`},b.createElement(g,null,`Opening browser for login… (paste ZENOVAY_API_TOKEN env var to skip)`)),l===`loading-sites`&&b.createElement(s,{title:`Loading your sites`,state:`busy`},b.createElement(h,null,b.createElement(g,{color:`magenta`},b.createElement(D,{type:`dots`})),b.createElement(g,null,` Fetching your Zenovay sites…`))),l===`site-picker`&&f&&b.createElement(Tt,{sites:m,preselectHint:y,onPick:e=>{if(e===`create-new`){d(`create-site`);return}E(e),Z(e,f,r,{setPhase:d,setErrorMsg:k,setTasks:A,setLiveLine:j,setSandboxStats:N})}}),l===`create-site`&&b.createElement(s,{title:`Create a new site`,state:`warn`},b.createElement(g,{color:`yellow`},"No site picked (or none exist yet). Visit https://app.zenovay.com/websites to create one, then re-run `zenovay init`."),b.createElement(g,{color:`gray`},`(Inline site creation from the CLI is scheduled for V1.1 — it requires a plan-limit check.)`)),l===`agent`&&f&&T&&b.createElement(wt,{adapter:f,site:T,tasks:ee,liveLine:te}),l===`install-complete`&&f&&T&&b.createElement(Dt,{adapter:f,site:T,stats:M,onCommit:()=>d(`commit-prompt`),onSkipCommit:()=>d(`deploy-prompt`)}),l===`commit-prompt`&&T&&b.createElement(Ot,{cwd:r.cwd,onDone:e=>{e.committed&&j(`Pushed ${e.shortSha} to ${e.branch}`),d(`deploy-prompt`)},onError:e=>{k(e),d(`error`)}}),l===`deploy-prompt`&&T&&b.createElement(kt,{site:T,onDeployed:()=>d(`visit-prompt`),onSkip:()=>d(`verify`)}),l===`visit-prompt`&&T&&b.createElement(At,{site:T,onContinue:()=>d(`verify`)}),l===`verify`&&T&&b.createElement(Mt,{site:T,elapsed:P,onTick:e=>F(e),onArrived:()=>d(`success`),onTimeout:()=>d(`success`)}),l===`success`&&f&&T&&b.createElement(Et,{adapter:f,site:T,stats:M,onPick:e=>{a(),i(0,e,T)}}),l===`error`&&b.createElement(s,{title:`Install failed`,state:`err`},b.createElement(g,{color:`red`},O??`Unknown error`)),b.createElement(u,{items:[{key:`q`,label:`quit`},{key:`ctrl-c`,label:`abort`}]}))};async function Z(r,i,a,o){try{o.setPhase(`agent`);let s=await e(),c=await n({strict:!1}),l=new t({config:s,cliVersion:a.cliVersion,token:c}),u=new W({cwd:a.cwd}),d=r.trackingCode??r.id,f=await F(a.cwd,d);if(f.recommendation===`no-op`){o.setTasks(e=>e.map(e=>e.id===`detect`||e.id===`read`||e.id===`write`?{...e,status:`done`,detail:`already installed correctly`}:e)),o.setLiveLine(f.summary),o.setSandboxStats?.({reads:0,writes:0,rounds:0}),!a.skipMcp&&c&&await Y({accessToken:c.accessToken}).catch(()=>void 0),o.setPhase(`install-complete`);return}f.competitors.length>0&&o.setLiveLine(`Detected ${f.competitors.map(e=>e.name).join(`, `)} — will install Zenovay alongside (won't touch their tags).`);let p=i.id===`plain-html`&&(f.recommendation===`fresh-install`||f.recommendation===`fresh-install-alongside-competitor`||f.recommendation===`update-tracking-code`);if(p){o.setTasks(e=>e.map(e=>e.id===`detect`?{...e,status:`done`,detail:`Plain HTML`}:e)),o.setLiveLine(`Plain HTML — using fast install path (no AI needed)…`);let e=await lt({cwd:a.cwd,trackingCode:d,updateOnly:f.recommendation===`update-tracking-code`});if(e.installed.length===0&&e.errors.length===0)throw Error(`No HTML files were modified. Either no .html files contain a <head>...</head> block, or every file already has the correct tracker.`);if(e.installed.length===0&&e.errors.length>0)throw Error(`Programmatic install failed for all ${e.errors.length} file(s). First error: ${e.errors[0].file}: ${e.errors[0].error}`);o.setTasks(t=>t.map(t=>t.id===`read`||t.id===`write`?{...t,status:`done`,detail:`${e.installed.length} file(s)`}:t)),o.setLiveLine(`Tracker added to ${e.installed.length} file(s). Skipped ${e.skipped.length}, errored ${e.errors.length}.`);let t=await J(a.cwd,{[i.envVarName]:d});if(o.setTasks(e=>e.map(e=>e.id===`env`?{...e,status:`done`,detail:`${t.addedKeys.length} key(s) added`}:e)),!a.skipMcp&&c){let e=await Y({accessToken:c.accessToken}).catch(()=>null);o.setTasks(t=>t.map(t=>t.id===`mcp`?{...t,status:`done`,detail:e&&e.installed.length>0?e.installed.join(`, `):`none detected`}:t))}else o.setTasks(e=>e.map(e=>e.id===`mcp`?{...e,status:`done`,detail:`skipped`}:e));o.setLiveLine(void 0),o.setSandboxStats?.({reads:e.installed.length,writes:e.installed.length,rounds:0}),o.setPhase(`install-complete`);return}let m=i.buildSnippets({trackingCode:d,siteId:r.id}),h=`Install Zenovay tracking into this ${i.displayName} project.\nSite: ${r.name} (trackingCode: ${d}).\n1. Call detect_framework to confirm the framework.\n2. Read the entry file(s) for this framework:\n`+i.files.map(e=>` - ${e.path}`).join(`
54
- `)+`
55
- 3. Insert the tracker using the snippet below.
56
- 4. Confirm the change with a diff before writing.
57
-
58
- Snippet reference (anchored by anchorKind — adapt to the actual file):
59
- `+m.map(e=>` ${e.anchorKind} @ ${e.targetPath}:\n ${e.code.replace(/\n/g,`
60
- `)}`).join(`
61
-
62
- `);o.setTasks([{id:`detect`,label:`Detect framework`,status:`active`},{id:`read`,label:`Read project entry files`,status:`pending`},{id:`write`,label:`Insert tracker snippet`,status:`pending`},{id:`env`,label:`Write env vars (.env.local)`,status:`pending`},{id:`mcp`,label:`Install MCP clients (Cursor/Claude/VS Code)`,status:`pending`},{id:`verify`,label:`Wait for first event`,status:`pending`}]);let g=(e,t,n)=>{o.setTasks(r=>r.map(r=>r.id===e?{...r,status:t,detail:n??r.detail}:r))},_=null;try{await ot({api:l,sandbox:u,approval:{async approve(){return`y`}},prompter:{async ask({question:e}){return e}},handlers:{onToolStart:({name:e})=>{e===`detect_framework`?(g(`detect`,`active`),o.setLiveLine(`Inspecting package.json + config files…`)):e===`read_file`?(g(`detect`,`done`),g(`read`,`active`)):(e===`write_file`||e===`patch_file`)&&(g(`read`,`done`),g(`write`,`active`))},onToolResult:({name:e,result:t})=>{let n=t?.ok!==!1,r=t?.content??{};e===`detect_framework`&&n&&(g(`detect`,`done`,i.displayName),o.setLiveLine(`Detected ${i.displayName}`)),e===`read_file`&&n&&r.path&&o.setLiveLine(`Read ${r.path}`),(e===`write_file`||e===`patch_file`)&&n&&r.path&&o.setLiveLine(`Wrote ${r.path}`)},onDelta:e=>{let t=e.replace(/\s+/g,` `).trim();t.length>4&&o.setLiveLine(t.slice(0,80))}},initialMessages:[{role:`user`,content:h}],diagnosis:f,targetTrackingCode:d})}catch(e){_=e}let v=u.stats();if(v.writes===0){let e=_?`Agent error: ${_.message}`:`Agent returned without writing any files (${v.reads} reads, ${v.rounds} rounds). The model may have refused or the AI Gateway may be misconfigured. Check api.zenovay.com logs.`;throw Error(e)}let y=i.files.map(e=>e.path),b=v.writtenPaths.some(e=>y.some(t=>e===t||e.endsWith(`/${t}`)));if(!b)throw Error(`Agent wrote to: [${v.writtenPaths.join(`, `)}] but never modified the framework's tracker target file(s): [${y.join(`, `)}]. The tracker is NOT installed. The model likely put the trackingCode into .env.local instead of into the HTML/JSX entry file.`);g(`write`,`done`),g(`env`,`active`),o.setLiveLine(`Adding env var to .env.local`);let x=await J(a.cwd,{[i.envVarName]:d});if(g(`env`,`done`,`${x.addedKeys.length} key(s) added`),!a.skipMcp&&c){g(`mcp`,`active`),o.setLiveLine(`Detecting Cursor / Claude Desktop / VS Code…`);let e=await Y({accessToken:c.accessToken}).catch(()=>null);e&&e.installed.length>0?g(`mcp`,`done`,e.installed.join(`, `)):g(`mcp`,`done`,`none detected`)}else g(`mcp`,`done`,`skipped`);o.setTasks(e=>e.map(e=>e.id===`detect`||e.id===`read`||e.id===`write`?{...e,status:e.status===`pending`?`done`:e.status}:e)),o.setLiveLine(void 0),o.setSandboxStats?.(v),o.setPhase(`install-complete`)}catch(e){o.setErrorMsg(e.message),o.setPhase(`error`)}}const Ct=()=>b.createElement(s,{title:`Zenovay wants to set up your project`,state:`idle`},b.createElement(g,null,`We'll use AI to analyze your codebase and add the Zenovay tracker.`),b.createElement(g,{color:`gray`},`.env* contents stay on your machine. Only framework metadata reaches api.zenovay.com.`)),wt=({adapter:e,site:t,tasks:n,liveLine:r})=>{let i=process.stdout.columns??100,a=(process.stdout.rows??30)-6,o=Math.floor(i/2)-1,s=Math.max(14,a);return b.createElement(h,{flexDirection:`column`},b.createElement(h,{flexDirection:`row`,height:s,borderStyle:`round`,borderColor:`gray`},b.createElement(h,{width:o,flexDirection:`column`},b.createElement(gt,{width:o,height:s})),b.createElement(h,{width:1,flexDirection:`column`,height:s},b.createElement(g,{color:`gray`},`│`)),b.createElement(h,{width:o,flexDirection:`column`},b.createElement(yt,{tasks:n,liveLine:r,width:o,height:s}))),b.createElement(h,{marginTop:1},b.createElement(g,{color:`gray`},`Site: `,t.name,` · code: `,t.trackingCode??t.id,` · Framework: `,e.displayName)))},Tt=({sites:e,preselectHint:t,onPick:n})=>{let r=It(e,t),i=e.filter(e=>e.id!==r?.id),a=r?[r,...i]:i,o=[...a.map(e=>({label:Pt(e,e.id===r?.id),value:e,description:e.trackingCode?`trackingCode: ${e.trackingCode}`:void 0})),{label:`+ Create new site on app.zenovay.com`,value:`create-new`,description:`Open the dashboard to add a new website`}];return b.createElement(s,{title:t?`Pick a site (best match: ${t})`:`Pick a site`,state:`idle`},b.createElement(d,{items:o,onSelect:n}))},Et=({adapter:e,site:t,stats:n,onPick:r})=>(y((e,t)=>{let n=e.toLowerCase();n===`w`||t.return?r(`watch`):n===`e`?r(`events`):(n===`s`||n===`q`||t.escape)&&r(`quit`)},{isActive:!0}),b.createElement(s,{title:`You're live on Zenovay`,state:`ok`},b.createElement(g,null,b.createElement(l,null,`✔ Installed successfully`)),b.createElement(h,{marginTop:1,flexDirection:`column`},b.createElement(g,null,`Framework: `,b.createElement(g,{color:`cyan`},e.displayName)),b.createElement(g,null,`Site: `,b.createElement(g,{color:`cyan`},t.name),` (`,t.url,`)`),t.trackingCode?b.createElement(g,{color:`gray`},`Tracker: `,t.trackingCode):null,n&&n.rounds>0?b.createElement(g,{color:`gray`},`Modified: `,n.writes,` file(s) across `,n.rounds,` agent round(s)`):n&&n.writes>0?b.createElement(g,{color:`gray`},`Modified: `,n.writes,` file(s) (programmatic install — no AI calls)`):null),b.createElement(h,{marginTop:1,flexDirection:`column`},b.createElement(g,{bold:!0},`What's next?`),b.createElement(g,null,` `),b.createElement(h,null,b.createElement(g,{color:`cyan`},` [W] `),b.createElement(g,null,`Open the live dashboard `),b.createElement(g,{color:`gray`},`— real-time visitors, top pages, sources, vitals`)),b.createElement(h,null,b.createElement(g,{color:`cyan`},` [E] `),b.createElement(g,null,`Stream events as they fire `),b.createElement(g,{color:`gray`},`— page views, custom events, in real time`)),b.createElement(h,null,b.createElement(g,{color:`cyan`},` [S] `),b.createElement(g,null,`Exit to shell `),b.createElement(g,{color:`gray`},"— run `zenovay --help` to see all commands"))),b.createElement(h,{marginTop:1},b.createElement(g,{color:`gray`},`Dashboard URL: https://app.zenovay.com/sites/`,t.id)))),Dt=({adapter:e,site:t,stats:n,onCommit:r,onSkipCommit:i})=>(Q(e=>{e===`y`||e===`Y`||e===`\r`?r():(e===`n`||e===`N`||e===`s`||e===`S`)&&i()}),b.createElement(s,{title:`Tracker installed`,state:`ok`},b.createElement(g,null,b.createElement(l,null,`✔ `),`The Zenovay tracker is in your project.`),b.createElement(h,{marginTop:1},b.createElement(g,{color:`gray`},`Framework: `),b.createElement(g,null,e.displayName)),b.createElement(h,null,b.createElement(g,{color:`gray`},`Site: `),b.createElement(g,null,t.name,` (`,t.url,`)`)),n&&b.createElement(h,null,b.createElement(g,{color:`gray`},`Modified: `),b.createElement(g,null,n.writes,` file(s)`)),b.createElement(h,{marginTop:1},b.createElement(g,null,`Commit + push these changes to git? `),b.createElement(g,{color:`cyan`},`[Y/n]`)))),Ot=({cwd:e,onDone:t,onError:n})=>{let[r,i]=C(`committing`),[a,o]=C(`Staging changes…`);return x(()=>{(async()=>{try{let n=await Nt(e,e=>o(e),e=>i(e));n.committed?o(`Pushed ${n.shortSha} to origin/${n.branch}`):o(`No changes to commit (already up-to-date).`),setTimeout(()=>t(n),800)}catch(e){n(e.message)}})()},[]),b.createElement(s,{title:`Committing to git`,state:`busy`},b.createElement(h,null,b.createElement(g,{color:`magenta`},b.createElement(D,{type:`dots`})),b.createElement(g,null,` `,r===`pushing`?`Pushing to origin`:`Committing`,`…`)),b.createElement(h,{marginTop:1},b.createElement(g,{color:`gray`},a)))},kt=({site:e,onDeployed:t,onSkip:n})=>(Q(e=>{e===`y`||e===`Y`||e===`\r`||e===`d`||e===`D`?t():(e===`n`||e===`N`||e===`s`||e===`S`)&&n()}),b.createElement(s,{title:`Ready to deploy?`,state:`idle`},b.createElement(g,null,`The tracker is installed locally. To capture events you need it on the live site:`),b.createElement(g,null,` `),b.createElement(h,null,b.createElement(g,{color:`cyan`},` → `),b.createElement(g,null,e.url)),b.createElement(g,null,` `),b.createElement(g,{color:`gray`},`Push the change through your normal deploy pipeline (Vercel auto-deploy, CI/CD, etc.).`),b.createElement(h,{marginTop:1},b.createElement(g,null,`Once it's deployed, press `),b.createElement(g,{color:`cyan`},`[Y]`),b.createElement(g,null,` to verify the tracker is firing. `),b.createElement(g,{color:`gray`},`[s] skip verification`)))),At=({site:e,onContinue:t})=>(Q(()=>t()),b.createElement(s,{title:`Visit your site`,state:`idle`},b.createElement(g,null,`To send a test event, open any page on your site:`),b.createElement(g,null,` `),b.createElement(h,null,b.createElement(g,{color:`cyan`},` → `),b.createElement(g,null,e.url)),b.createElement(g,null,` `),b.createElement(g,{color:`gray`},`The tracker fires automatically on page load. We'll verify the next event arrives.`),b.createElement(h,{marginTop:1},b.createElement(g,null,`Press `),b.createElement(g,{color:`cyan`},`[any key]`),b.createElement(g,null,` when you've visited the page.`))));async function jt(e,t){try{let n=await fetch(e,{headers:{"User-Agent":`zenovay-cli/preflight`},signal:AbortSignal.timeout(8e3),redirect:`follow`});if(!n.ok)return{state:`tracker-missing`,httpStatus:n.status};let r=await n.text(),i=/<script[^>]*src\s*=\s*["']https:\/\/(?:api|cdn)\.zenovay\.com\/[^"']+["'][^>]*>\s*<\/script>/gi,a=/data-id\s*=\s*["'](ZV_[A-Za-z0-9]+)["']/i,o=r.match(i)??[];if(o.length===0)return{state:`tracker-missing`};let s=Array.from(new Set(o.map(e=>e.match(a)?.[1]).filter(e=>!!e)));return s.includes(t)?{state:`tracker-correct`}:{state:`tracker-wrong-id`,foundCodes:s}}catch(e){return{state:`tracker-missing`,networkError:e.message}}}const Mt=({site:r,elapsed:i,onTick:a,onArrived:o,onTimeout:c})=>{let[l,u]=C(`preflight`),[d,f]=C(``),[p,m]=C([]),_=S(!1),v=r.trackingCode??r.id,w=async()=>{u(`preflight`),f(`Fetching ${r.url}…`);let e=await jt(r.url,v);if(!_.current){if(e.state===`tracker-correct`){u(`polling`),f(`Tracker detected on live site — waiting for first hit…`),T();return}if(e.state===`tracker-wrong-id`){u(`wrong-id-on-live`),m(e.foundCodes),f(`Live site has Zenovay but with id(s): ${e.foundCodes.join(`, `)}`);return}u(`awaiting-deploy`),f(e.networkError?`Couldn't reach ${r.url}: ${e.networkError}`:e.httpStatus?`${r.url} returned HTTP ${e.httpStatus}`:`No Zenovay tracker found on ${r.url}.`)}},T=async()=>{let i=Date.now();try{let s=await e(),c=await n({strict:!1}),l=new t({config:s,cliVersion:`0`,token:c}),d=await Ye(r.id,i,{api:l,timeoutMs:18e4,pollIntervalMs:2500,onTick:e=>{_.current||a(e)}});if(_.current)return;d.received?(u(`success`),o()):u(`timeout`)}catch{_.current||u(`timeout`)}};x(()=>(_.current=!1,w(),()=>{_.current=!0}),[]),y(e=>{(l===`awaiting-deploy`||l===`wrong-id-on-live`||l===`timeout`)&&(e===`r`||e===`R`?w():(e===`s`||e===`S`)&&c())},{isActive:!0});let E=Math.floor(i/1e3);return l===`preflight`?b.createElement(s,{title:`Verifying`,state:`busy`},b.createElement(h,null,b.createElement(g,{color:`magenta`},b.createElement(D,{type:`dots`})),b.createElement(g,null,` Checking your live site for the tracker…`)),b.createElement(h,{marginTop:1},b.createElement(g,{color:`gray`},d))):l===`awaiting-deploy`?b.createElement(s,{title:`Tracker not yet on your live site`,state:`warn`},b.createElement(g,{color:`yellow`},d),b.createElement(h,{marginTop:1,flexDirection:`column`},b.createElement(g,null,`The tracker is in your local repo but hasn't been deployed yet.`),b.createElement(g,{color:`gray`},`Push your changes and wait for your deploy to finish (Vercel / Cloudflare Pages / CI), then retry.`)),b.createElement(h,{marginTop:1},b.createElement(g,null,`Press `),b.createElement(g,{color:`cyan`},`[r]`),b.createElement(g,null,` to re-check, `),b.createElement(g,{color:`cyan`},`[s]`),b.createElement(g,null,` to skip verification.`))):l===`wrong-id-on-live`?b.createElement(s,{title:`Live site has a different tracking code`,state:`warn`},b.createElement(g,{color:`yellow`},`Expected: `,b.createElement(g,{color:`cyan`},v),` `,`Found on live: `,b.createElement(g,{color:`cyan`},p.join(`, `))),b.createElement(h,{marginTop:1,flexDirection:`column`},b.createElement(g,null,`Your local install uses a different ID than what's on `,r.url,`.`),b.createElement(g,{color:`gray`},`Deploy the new local version, then retry — or skip if the existing ID is intentional.`)),b.createElement(h,{marginTop:1},b.createElement(g,null,`Press `),b.createElement(g,{color:`cyan`},`[r]`),b.createElement(g,null,` to re-check, `),b.createElement(g,{color:`cyan`},`[s]`),b.createElement(g,null,` to skip.`))):l===`timeout`?b.createElement(s,{title:`No event arrived in 3 minutes`,state:`warn`},b.createElement(g,{color:`yellow`},`The tracker is on your live site but no hits reached api.zenovay.com.`),b.createElement(h,{marginTop:1},b.createElement(g,{color:`gray`},`Try opening `,r.url,` in a fresh browser tab (no ad-blocker), then retry.`)),b.createElement(h,{marginTop:1},b.createElement(g,null,`Press `),b.createElement(g,{color:`cyan`},`[r]`),b.createElement(g,null,` to re-check, `),b.createElement(g,{color:`cyan`},`[s]`),b.createElement(g,null,` to finish without verification.`))):b.createElement(s,{title:`Waiting for first event`,state:`busy`},b.createElement(h,null,b.createElement(g,{color:`magenta`},b.createElement(D,{type:`dots`})),b.createElement(g,null,` Polling api.zenovay.com for the first hit on `),b.createElement(g,{color:`cyan`},r.url),b.createElement(g,null,` (`,E,`s elapsed)`)),b.createElement(h,{marginTop:1},b.createElement(g,{color:`gray`},`Reload the page if nothing arrives within ~30 seconds.`)))};function Q(e){y((t,n)=>{e(t,{return:n.return,escape:n.escape})},{isActive:!0})}async function Nt(e,t,n){let{execFile:r}=await import(`node:child_process`),{promisify:i}=await import(`node:util`),a=i(r),o=async(t,n)=>{let{stdout:r}=await a(t,n,{cwd:e,maxBuffer:4e6});return r.trim()};try{await o(`git`,[`rev-parse`,`--is-inside-work-tree`])}catch{return t(`Not a git repository — skipped.`),{committed:!1}}let s=await o(`git`,[`status`,`--porcelain`]);if(!s)return{committed:!1};t(`Staging tracker changes…`),await o(`git`,[`add`,`-A`]),t(`Creating commit…`),await o(`git`,[`commit`,`-m`,`chore(zenovay): install tracking script via @zenovay/cli`]);let c=await o(`git`,[`rev-parse`,`--short`,`HEAD`]),l=await o(`git`,[`rev-parse`,`--abbrev-ref`,`HEAD`]);n(`pushing`),t(`Pushing to origin/${l}…`);try{await o(`git`,[`push`,`origin`,l])}catch(e){return t(`Commit ${c} created locally; push failed (${e.message.slice(0,80)}). Push manually with: git push origin ${l}`),{committed:!0,shortSha:c,branch:l}}return n(`done`),{committed:!0,shortSha:c,branch:l}}function Pt(e,t){let n=`${e.name}`.padEnd(30,` `).slice(0,30),r=e.url.replace(/^https?:\/\//,``).padEnd(28,` `).slice(0,28),i=t?` ← best match`:``;return`${n} ${r}${i}`}async function Ft(e){try{let t=await m.readFile(p.join(e,`package.json`),`utf8`),n=JSON.parse(t);if(n.name)return String(n.name).replace(/^@[^/]+\//,``)}catch{}try{let t=await m.readFile(p.join(e,`.git`,`config`),`utf8`),n=t.match(/url\s*=\s*.*[/:]([^/]+?)(?:\.git)?\s*$/m);if(n&&n[1])return n[1]}catch{}return p.basename(e)}function It(e,t){if(!t||e.length===0)return e[0]??null;let n=$(t),r=e.find(e=>$(e.name)===n);if(r)return r;let i=e.find(e=>{let t=e.url.replace(/^https?:\/\//,``).replace(/\/.*$/,``),[r]=t.split(`.`);return $(r??``)===n});if(i)return i;let a=e.find(e=>$(e.name).includes(n)||$(e.url).includes(n));return a??e[0]??null}function $(e){return e.toLowerCase().replace(/[^a-z0-9]/g,``)}export{ne as detectInstalled,bt as initCommand};
@@ -1,3 +0,0 @@
1
- import{BRAND_GRADIENT as e,useTheme as t}from"./panel-DglZ755S.js";import{Box as n,Text as r}from"ink";import i from"react";function a(e){let t=e.replace(`#`,``).trim(),n=t.length===3?t.split(``).map(e=>e+e).join(``):t,r=parseInt(n.slice(0,2),16),i=parseInt(n.slice(2,4),16),a=parseInt(n.slice(4,6),16);return{r:Number.isNaN(r)?0:r,g:Number.isNaN(i)?0:i,b:Number.isNaN(a)?0:a}}function o({r:e,g:t,b:n}){let r=e=>{let t=Math.max(0,Math.min(255,Math.round(e)));return t.toString(16).padStart(2,`0`)};return`#${r(e)}${r(t)}${r(n)}`}function s(e,t,n){return{r:e.r+(t.r-e.r)*n,g:e.g+(t.g-e.g)*n,b:e.b+(t.b-e.b)*n}}function c(e,t,n,a){if(e.length===0)return[];if(e.length===1)return[i.createElement(r,{key:`${a}-0`,color:o(t)},e)];let c=Array.from(e),l=c.length-1;return c.map((e,c)=>{let u=c/l,d=o(s(t,n,u));return i.createElement(r,{key:`${a}-${c}`,color:d},e)})}function l({from:e,to:t,children:n}){let o=a(e),s=a(t),l=n.split(`
2
- `),u=[];return l.forEach((e,t)=>{t>0&&u.push(i.createElement(r,{key:`nl-${t}`},`
3
- `));let n=c(e,o,s,`l${t}`);u.push(...n)}),i.createElement(r,null,u)}function u({children:t}){return i.createElement(l,{from:e.from,to:e.to},t)}function d(){let e=process.stdout.columns;return typeof e==`number`&&e>0?e:80}function f({version:e,subtitle:a}){let{theme:o}=t(),s=d(),c=`ZENOVAY · v${e}`,l=`╭─ `,f=` `,p=`─╮`,m=l.length+c.length+f.length+p.length,h=Math.max(2,s-m),g=`─`.repeat(h),_=`─`.repeat(Math.max(2,s-2)),v=a??``,y=v.slice(0,Math.max(0,s-4)),b=` `.repeat(Math.max(1,s-2-1-y.length-1));return i.createElement(n,{flexDirection:`column`},i.createElement(n,{flexDirection:`row`},i.createElement(r,{color:o.border},l),i.createElement(u,null,c),i.createElement(r,{color:o.border},f,g,p)),a?i.createElement(n,{flexDirection:`row`},i.createElement(r,{color:o.border},`│ `),i.createElement(r,{color:o.muted},y),i.createElement(r,{color:o.border},b,`│`)):null,i.createElement(n,{flexDirection:`row`},i.createElement(r,{color:o.border},`╰`,_,`╯`)))}function p({items:e}){let{theme:a}=t();return i.createElement(n,{flexDirection:`row`},e.map((e,t)=>i.createElement(n,{key:`${e.key}-${t}`,flexDirection:`row`},t>0?i.createElement(r,{color:a.dim},` `):null,i.createElement(r,{color:a.muted},`[`),i.createElement(r,{color:a.accent},e.key),i.createElement(r,{color:a.muted},` `,e.label),i.createElement(r,{color:a.muted},`]`))))}export{f as Banner,u as BrandGradient,p as Keybar};
@@ -1 +0,0 @@
1
- import"./config-ZTGpKEWg.js";import"./api-BhdaCghp.js";import"./formatter-45-fT1Hv.js";import"./emit-0WJ_OGeT.js";import{loginCommand as e}from"./login-DHLIZV8C.js";export{e as loginCommand};
@@ -1,3 +0,0 @@
1
- import{readConfig as e}from"./config-ZTGpKEWg.js";import{readToken as t}from"./api-BhdaCghp.js";import{formatTabular as n,selectFormat as r}from"./formatter-45-fT1Hv.js";import"./panel-DglZ755S.js";import"./keybar-D2OI-8rx.js";import"./prompt-hjzdzlyj.js";import"./sparkline-CR_bzxwB.js";import{runAnalyticalScreen as i}from"./analytical-screen-Boiw3NTp.js";import{Table as a}from"./ui-Bk5nl2yb.js";import{ApiV2Client as o}from"./api-v2-B03fp6KF.js";import{Box as s,Text as c}from"ink";import l from"react";async function u(u){let d=await e(),f=await t({strict:!1}),p=u.siteId??f?.teamId??``;if(!p)return process.stderr.write(`No site selected — pass --site-id or set ZENOVAY_SITE.
2
- `),2;let m=new o({config:d,cliVersion:u.cliVersion,token:f}),h=r(u),g=[{key:`isCurrent`,header:``,width:2,format:e=>e?`*`:` `},{key:`name`,header:`project`,width:26},{key:`domain`,header:`domain`,width:28,format:e=>String(e??`—`)},{key:`tier`,header:`tier`,width:10},{key:`pageviews24h`,header:`24h pv`,width:8,align:`right`},{key:`id`,header:`id`,width:38,format:e=>String(e).slice(0,38)}];return i({cliVersion:u.cliVersion,title:`projects · ${f?.teamId??`—`}`,commandName:`projects`,authToken:f?.accessToken??null,refreshIntervalMs:0,fetcher:e=>m.getProjects(p,e),format:h,headlessEmit:(e,t)=>{if(t===`json`||t===`ndjson`){if(t===`ndjson`)for(let t of e.projects)process.stdout.write(JSON.stringify(t)+`
3
- `);else process.stdout.write(JSON.stringify(e,null,2));return}process.stdout.write(n(e.projects,[`id`,`name`,`domain`,`tier`,`pageviews24h`,`isCurrent`],t))},panels:[{id:`summary`,title:`Tracked sites`,render:e=>{let t=e.projects.find(e=>e.isCurrent);return l.createElement(s,{flexDirection:`column`},l.createElement(c,null,l.createElement(c,{bold:!0},e.projects.length),l.createElement(c,{color:`gray`},` projects`)),t?l.createElement(c,{color:`gray`},`current: `,l.createElement(c,{color:`cyan`},t.name),` `,`(`,t.domain??`—`,`, `,t.tier,`)`):l.createElement(c,{color:`gray`},`no current project bound to this token`))}},{id:`list`,title:`List`,render:e=>e.projects.length===0?l.createElement(c,{color:`gray`},`— no projects yet —`):l.createElement(a,{data:e.projects,columns:g})},{id:`hint`,title:`Switch`,render:()=>l.createElement(c,{color:`gray`},"To switch project: run `zenovay logout` then `zenovay login` (V2.1 adds a faster /switch flow).")}]})}export{u as projectsCommand};
@@ -1 +0,0 @@
1
- import{useTheme as e}from"./panel-DglZ755S.js";import{Box as t,Text as n,useInput as r}from"ink";import i,{useCallback as a,useState as o}from"react";import s from"ink-select-input";import c from"ink-text-input";function l({hints:t}){let{theme:r}=e();return i.createElement(n,{color:r.dim},t)}function u({items:r,onSelect:c}){let{theme:u}=e(),[d,f]=o(r[0]),p=a(e=>{c(e.value)},[c]),m=a(e=>{f(e)},[]);return i.createElement(t,{flexDirection:`column`},i.createElement(s,{items:r.map((e,t)=>({key:`${t}`,label:e.label,value:e.value})),onSelect:e=>{let t=r.find(t=>t.value===e.value);t&&p(t)},onHighlight:e=>{let t=r.find(t=>t.value===e.value);t&&m(t)}}),d?.description?i.createElement(t,{marginTop:1},i.createElement(n,{color:u.muted},d.description)):null,i.createElement(t,{marginTop:1},i.createElement(l,{hints:`[↑↓/jk nav] [enter select]`})))}function d({question:r,onSubmit:a,placeholder:s,mask:u}){let{theme:d}=e(),[f,p]=o(``);return i.createElement(t,{flexDirection:`column`},i.createElement(t,null,i.createElement(n,{color:d.fg},r,` `),i.createElement(c,{value:f,onChange:p,onSubmit:e=>a(e),placeholder:s,mask:u?`•`:void 0})),i.createElement(l,{hints:`[enter submit]`}))}export{u as Select,d as TextInput};
@@ -1,9 +0,0 @@
1
- import{readConfig as e}from"./config-ZTGpKEWg.js";import{readToken as t}from"./api-BhdaCghp.js";import{formatTabular as n,selectFormat as r}from"./formatter-45-fT1Hv.js";import{Panel as i}from"./panel-DglZ755S.js";import{Banner as a}from"./keybar-D2OI-8rx.js";import"./prompt-hjzdzlyj.js";import"./sparkline-CR_bzxwB.js";import{Table as o}from"./ui-Bk5nl2yb.js";import{ApiV2Client as s}from"./api-v2-B03fp6KF.js";import{Box as c,Text as l,useApp as u,useInput as d}from"ink";import f,{useMemo as p,useState as m}from"react";import h from"ink-text-input";function g({api:e,siteId:t,maxRows:n}){let{exit:r}=u(),[s,g]=m(``),[_,v]=m(null),[y,b]=m(null),[x,S]=m(!1),[C,w]=m([]);d((e,t)=>{t.escape&&r()});let T=async i=>{if(i.trim()){if(i.trim()===`\\q`||i.trim()===`exit`||i.trim()===`quit`){r();return}w(e=>[...e,i]),S(!0),b(null);try{let r=await e.runSqlQuery(t,i,{maxRows:n});v(r)}catch(e){b(e.message),v(null)}finally{S(!1),g(``)}}},E=p(()=>_?_.columns.map(e=>({key:e,header:e,width:18,format:e=>e==null?`∅`:String(e).slice(0,18)})):[],[_]);return f.createElement(c,{flexDirection:`column`},f.createElement(a,{version:`query`}),f.createElement(i,{title:`History`,state:`idle`},C.length===0?f.createElement(l,{color:`gray`},`— no queries yet — Esc or \\q to exit —`):C.slice(-5).map((e,t)=>f.createElement(l,{key:t,color:`gray`},`> ${e.slice(0,80)}${e.length>80?`…`:``}`))),f.createElement(c,null,f.createElement(l,{color:`magenta`},`sql`,`>`,` `),f.createElement(h,{value:s,onChange:g,onSubmit:T})),x?f.createElement(l,{color:`gray`},`running…`):null,y?f.createElement(i,{title:`Error`,state:`err`},f.createElement(l,{color:`red`},y)):null,_?f.createElement(i,{title:`${_.row_count} rows · ${_.duration_ms}ms${_.truncated?` · truncated`:``}`,state:`ok`},_.row_count===0?f.createElement(l,{color:`gray`},`— empty —`):f.createElement(o,{data:_.rows.slice(0,50),columns:E})):null)}async function _(i){let a=await e(),o=await t({strict:!1}),c=i.siteId??o?.teamId??``;if(!c)return process.stderr.write(`No site selected — pass --site-id or set ZENOVAY_SITE.
2
- `),2;let l=new s({config:a,cliVersion:i.cliVersion,token:o}),u=i.maxRows??1e3,d=r(i);if(i.sql)try{let e=await l.runSqlQuery(c,i.sql,{maxRows:u});if(d===`json`)process.stdout.write(JSON.stringify(e,null,2)),process.stdout.write(`
3
- `);else if(d===`ndjson`)for(let t of e.rows)process.stdout.write(JSON.stringify(t)+`
4
- `);else if(d===`csv`||d===`tsv`)process.stdout.write(n(e.rows,e.columns,d));else{let t=e.columns.map(t=>Math.max(t.length,...e.rows.map(e=>String(e[t]??``).length))),n=`+`+t.map(e=>`-`.repeat(e+2)).join(`+`)+`+`;process.stdout.write(n+`
5
- `),process.stdout.write(`|`+e.columns.map((e,n)=>` ${e.padEnd(t[n]??0)} `).join(`|`)+`|
6
- `),process.stdout.write(n+`
7
- `);for(let n of e.rows.slice(0,200))process.stdout.write(`|`+e.columns.map((e,r)=>` ${String(n[e]??``).padEnd(t[r]??0)} `).join(`|`)+`|
8
- `);process.stdout.write(n+`
9
- `),process.stdout.write(`${e.row_count} rows · ${e.duration_ms}ms${e.truncated?` · truncated`:``}\n`)}return 0}catch(e){return process.stderr.write(`✗ ${e.message}\n`),1}let{render:p}=await import(`ink`);return await p(f.createElement(g,{api:l,siteId:c,maxRows:u})).waitUntilExit(),0}export{_ as queryCommand};
@@ -1,3 +0,0 @@
1
- import{readConfig as e}from"./config-ZTGpKEWg.js";import{readToken as t}from"./api-BhdaCghp.js";import{formatTabular as n,selectFormat as r}from"./formatter-45-fT1Hv.js";import"./panel-DglZ755S.js";import"./keybar-D2OI-8rx.js";import"./prompt-hjzdzlyj.js";import{spark as i}from"./sparkline-CR_bzxwB.js";import{runAnalyticalScreen as a}from"./analytical-screen-Boiw3NTp.js";import"./ui-Bk5nl2yb.js";import{ApiV2Client as o}from"./api-v2-B03fp6KF.js";import{Box as s,Text as c}from"ink";import l from"react";function u(e,t){let n=e/100,r=new Intl.NumberFormat(`en-US`,{minimumFractionDigits:0,maximumFractionDigits:0}).format(n),i=(t||`USD`).toUpperCase();return i===`USD`?`$${r}`:i===`EUR`?`€${r}`:i===`GBP`?`£${r}`:`${r} ${i}`}async function d(d){let f=await e(),p=await t({strict:!1}),m=d.siteId??p?.teamId??``;if(!m)return process.stderr.write(`No site selected — pass --site-id or set ZENOVAY_SITE.
2
- `),2;let h=new o({config:f,cliVersion:d.cliVersion,token:p}),g=r(d),_=d.range??`30d`;return a({cliVersion:d.cliVersion,title:`revenue · ${m} · ${_}`,commandName:`revenue`,authToken:p?.accessToken??null,refreshIntervalMs:d.watch?5*6e4:0,fetcher:e=>h.getRevenue(m,_,e),format:g,headlessEmit:(e,t)=>{if(t===`json`||t===`ndjson`){process.stdout.write(JSON.stringify(e,null,t===`json`?2:0)),t===`ndjson`&&process.stdout.write(`
3
- `);return}process.stdout.write(n(e.series,[`bucket`,`amount`,`currency`,`transactions`],t))},panels:[{id:`totals`,title:`Top line`,render:e=>l.createElement(s,{flexDirection:`column`},l.createElement(c,null,l.createElement(c,{color:`green`,bold:!0},u(e.totalAmount,e.currency)),` `,l.createElement(c,{color:`gray`},`total · `,e.totalTransactions,` transactions`)),typeof e.mrr==`number`?l.createElement(c,null,l.createElement(c,{bold:!0},`MRR `),l.createElement(c,{color:`magenta`},u(e.mrr,e.currency)),typeof e.arpu==`number`?l.createElement(c,{color:`gray`},` · ARPU `,u(e.arpu,e.currency)):null):null)},{id:`series`,title:`Daily (${_})`,render:e=>{let t=e.series.map(e=>e.amount);if(t.length===0)return l.createElement(c,{color:`gray`},`— no transactions —`);let n=Math.max(...t,1);return l.createElement(s,{flexDirection:`column`},l.createElement(c,{color:`magenta`},i(t,Math.min(60,t.length*2))),l.createElement(c,{color:`gray`},`peak: `,u(n,e.currency),` ·`,` `,`avg: `,u(e.totalAmount/Math.max(1,t.length),e.currency)))}},{id:`window`,title:`Window`,render:e=>l.createElement(c,{color:`gray`},new Date(e.windowStart).toISOString().slice(0,10),` →`,` `,new Date(e.windowEnd).toISOString().slice(0,10))}]})}export{d as revenueCommand};
@@ -1,3 +0,0 @@
1
- import{readConfig as e}from"./config-ZTGpKEWg.js";import{readToken as t}from"./api-BhdaCghp.js";import{formatTabular as n,selectFormat as r}from"./formatter-45-fT1Hv.js";import"./panel-DglZ755S.js";import"./keybar-D2OI-8rx.js";import"./prompt-hjzdzlyj.js";import"./sparkline-CR_bzxwB.js";import{runAnalyticalScreen as i}from"./analytical-screen-Boiw3NTp.js";import{Table as a}from"./ui-Bk5nl2yb.js";import{ApiV2Client as o}from"./api-v2-B03fp6KF.js";import{Box as s,Text as c}from"ink";import l from"react";function u(e,t){let n=Math.round(e/100*t);return`█`.repeat(n)+`░`.repeat(Math.max(0,t-n))}function d(e){return e==null?{glyph:`·`,color:`gray`}:e>.5?{glyph:`▲`,color:`green`}:e<-.5?{glyph:`▼`,color:`red`}:{glyph:`→`,color:`gray`}}async function f(f){let p=await e(),m=await t({strict:!1}),h=f.siteId??m?.teamId??``;if(!h)return process.stderr.write(`No site selected — pass --site-id or set ZENOVAY_SITE.
2
- `),2;let g=new o({config:p,cliVersion:f.cliVersion,token:m}),_=r(f),v=f.period??`30d`,y=[{key:`source`,header:`source`,width:22},{key:`channel`,header:`channel`,width:10,format:e=>String(e??`—`)},{key:`visitors`,header:`visitors`,width:8,align:`right`},{key:`delta`,header:`Δ`,width:6,align:`right`,format:e=>typeof e==`number`?`${e>0?`+`:``}${(e*100).toFixed(1)}%`:`—`}];return i({cliVersion:f.cliVersion,title:`sources · ${h} · ${v}`,commandName:`sources`,authToken:m?.accessToken??null,refreshIntervalMs:6e4,fetcher:e=>g.getSources(h,v,f.compare,e),format:_,headlessEmit:(e,t)=>{if(t===`json`||t===`ndjson`){process.stdout.write(JSON.stringify(e,null,t===`json`?2:0)),t===`ndjson`&&process.stdout.write(`
3
- `);return}process.stdout.write(n(e.sources,[`source`,`channel`,`visitors`,`conversions`,`revenue`,`delta`],t))},panels:[{id:`summary`,title:`Total`,render:e=>l.createElement(c,null,l.createElement(c,{bold:!0},e.totalVisitors.toLocaleString()),` `,l.createElement(c,{color:`gray`},`visitors · `,e.sources.length,` sources`))},{id:`channels`,title:`By channel`,render:e=>{if(e.sources.length===0)return l.createElement(c,{color:`gray`},`— no source data —`);let t=e.totalVisitors||1,n=[...e.sources].sort((e,t)=>t.visitors-e.visitors).slice(0,12);return l.createElement(s,{flexDirection:`column`},n.map((e,n)=>{let r=e.visitors/t*100,i=d(e.delta);return l.createElement(s,{key:`${e.source}-${n}`},l.createElement(c,null,l.createElement(c,{color:`cyan`},e.source.padEnd(20).slice(0,20)),` `,l.createElement(c,{color:`magenta`},u(r,30)),` `,l.createElement(c,null,e.visitors.toString().padStart(6),` `),l.createElement(c,{color:`gray`},`(`,r.toFixed(1),`%)`),` `,l.createElement(c,{color:i.color},i.glyph)))}))}},{id:`table`,title:`Detail`,render:e=>e.sources.length===0?l.createElement(c,{color:`gray`},`— —`):l.createElement(a,{data:e.sources.slice(0,20),columns:y})}]})}export{f as sourcesCommand};
@@ -1,3 +0,0 @@
1
- import{readConfig as e}from"./config-ZTGpKEWg.js";import{readToken as t}from"./api-BhdaCghp.js";import{formatTabular as n,selectFormat as r}from"./formatter-45-fT1Hv.js";import"./panel-DglZ755S.js";import"./keybar-D2OI-8rx.js";import"./prompt-hjzdzlyj.js";import"./sparkline-CR_bzxwB.js";import{runAnalyticalScreen as i}from"./analytical-screen-Boiw3NTp.js";import{Table as a}from"./ui-Bk5nl2yb.js";import{ApiV2Client as o}from"./api-v2-B03fp6KF.js";import{Box as s,Text as c}from"ink";import l from"react";function u(e){return`${(e*100).toFixed(1)}%`}function d(e){return e<60?`${Math.round(e)}s`:e<3600?`${Math.floor(e/60)}m ${Math.round(e%60)}s`:`${Math.floor(e/3600)}h ${Math.floor(e%3600/60)}m`}async function f(f){let p=await e(),m=await t({strict:!1}),h=f.siteId??m?.teamId??``;if(!h)return process.stderr.write(`No site selected — pass --site-id or set ZENOVAY_SITE.
2
- `),2;let g=new o({config:p,cliVersion:f.cliVersion,token:m}),_=r(f),v=f.range??`24h`,y=[{key:`url`,header:`page`,width:40,format:e=>String(e??`—`)},{key:`views`,header:`views`,width:8,align:`right`}],b=[{key:`country`,header:`country`,width:8},{key:`visitors`,header:`visitors`,width:8,align:`right`}];return i({cliVersion:f.cliVersion,title:`stats · ${h} · ${v}`,commandName:`stats`,authToken:m?.accessToken??null,refreshIntervalMs:f.watch?6e4:0,fetcher:e=>g.getStats(h,v,e),format:_,headlessEmit:(e,t)=>{if(t===`json`||t===`ndjson`){process.stdout.write(JSON.stringify(e,null,t===`json`?2:0)),t===`ndjson`&&process.stdout.write(`
3
- `);return}process.stdout.write(n([{range:v,visitors:e.visitors,pageviews:e.pageviews,sessions:e.sessions,bounceRate:u(e.bounceRate),avgSession:d(e.avgSessionSec)}],[`range`,`visitors`,`pageviews`,`sessions`,`bounceRate`,`avgSession`],t))},panels:[{id:`summary`,title:`Summary`,render:e=>l.createElement(s,{flexDirection:`column`},l.createElement(c,null,l.createElement(c,{bold:!0},e.visitors.toLocaleString()),l.createElement(c,{color:`gray`},` visitors `),l.createElement(c,{bold:!0},e.pageviews.toLocaleString()),l.createElement(c,{color:`gray`},` pageviews `),l.createElement(c,{bold:!0},e.sessions.toLocaleString()),l.createElement(c,{color:`gray`},` sessions`)),l.createElement(c,{color:`gray`},`bounce `,u(e.bounceRate),` · avg session `,d(e.avgSessionSec)))},{id:`pages`,title:`Top pages`,render:e=>e.topPages.length===0?l.createElement(c,{color:`gray`},`— no pages —`):l.createElement(a,{data:e.topPages.slice(0,10),columns:y})},{id:`countries`,title:`Top countries`,render:e=>e.topCountries.length===0?l.createElement(c,{color:`gray`},`— no country data —`):l.createElement(a,{data:e.topCountries.slice(0,10),columns:b})}]})}export{f as statsCommand};
@@ -1,3 +0,0 @@
1
- import{readConfig as e}from"./config-ZTGpKEWg.js";import{readToken as t}from"./api-BhdaCghp.js";import{formatTabular as n,selectFormat as r}from"./formatter-45-fT1Hv.js";import"./panel-DglZ755S.js";import"./keybar-D2OI-8rx.js";import"./prompt-hjzdzlyj.js";import"./sparkline-CR_bzxwB.js";import{runAnalyticalScreen as i}from"./analytical-screen-Boiw3NTp.js";import{Table as a}from"./ui-Bk5nl2yb.js";import{ApiV2Client as o}from"./api-v2-B03fp6KF.js";import{Box as s,Text as c}from"ink";import l from"react";const u={lcp:{good:2500,poor:4e3},inp:{good:200,poor:500},cls:{good:.1,poor:.25},ttfb:{good:800,poor:1800},fcp:{good:1800,poor:3e3}};function d(e,t){let n=u[e];return t<=n.good?{label:`good`,color:`green`}:t<=n.poor?{label:`needs`,color:`yellow`}:{label:`poor`,color:`red`}}function f(e,t){return e===`cls`?t.toFixed(3):t<1e3?`${Math.round(t)}ms`:`${(t/1e3).toFixed(2)}s`}async function p(u){let p=await e(),m=await t({strict:!1}),h=u.siteId??m?.teamId??``;if(!h)return process.stderr.write(`No site selected — pass --site-id or set ZENOVAY_SITE.
2
- `),2;let g=new o({config:p,cliVersion:u.cliVersion,token:m}),_=r(u),v=[{key:`url`,header:`url`,width:32},{key:`device`,header:`device`,width:7,format:e=>String(e??`—`)},{key:`lcp`,header:`LCP p75`,width:9,align:`right`,format:e=>e&&typeof e==`object`&&`p75`in e?f(`lcp`,e.p75):`—`},{key:`inp`,header:`INP p75`,width:9,align:`right`,format:e=>e&&typeof e==`object`&&`p75`in e?f(`inp`,e.p75):`—`},{key:`cls`,header:`CLS p75`,width:9,align:`right`,format:e=>e&&typeof e==`object`&&`p75`in e?f(`cls`,e.p75):`—`},{key:`samples`,header:`n`,width:6,align:`right`}];return i({cliVersion:u.cliVersion,title:`vitals · ${h}`,commandName:`vitals`,authToken:m?.accessToken??null,refreshIntervalMs:u.watch?5*6e4:0,fetcher:e=>g.getVitals(h,{url:u.url,device:u.device,window:u.window},e),format:_,headlessEmit:(e,t)=>{if(t===`json`||t===`ndjson`){process.stdout.write(JSON.stringify(e,null,t===`json`?2:0)),t===`ndjson`&&process.stdout.write(`
3
- `);return}process.stdout.write(n(e.vitals,[`url`,`device`,`samples`],t))},panels:[{id:`summary`,title:`Site-wide p75`,render:e=>{let t=t=>{let n=0,r=0;for(let i of e.vitals){let e=i[t]?.p75;typeof e==`number`&&(n+=e*i.samples,r+=i.samples)}return r>0?n/r:0},n=[`lcp`,`inp`,`cls`,`ttfb`,`fcp`];return l.createElement(s,{flexDirection:`column`},n.map(e=>{let n=t(e),r=d(e,n);return l.createElement(c,{key:e},l.createElement(c,{color:r.color},`● `),l.createElement(c,{bold:!0},e.toUpperCase().padEnd(5)),` `,l.createElement(c,null,f(e,n).padStart(8)),` `,l.createElement(c,{color:r.color},r.label))}))}},{id:`pages`,title:`Per-page`,render:e=>e.vitals.length===0?l.createElement(c,{color:`gray`},`— no vitals data yet —`):l.createElement(a,{data:e.vitals.slice(0,15),columns:v})}]})}export{p as vitalsCommand};