@zenovay/cli 0.1.64 → 0.1.65

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 (140) hide show
  1. package/dist/ai-eSlGP6ay.js +1 -0
  2. package/dist/alerts-CcKnqwmm.js +3 -0
  3. package/dist/analytical-screen-BrOFDrQ_.js +2 -0
  4. package/dist/analytics-B8yy7gjr.js +2 -0
  5. package/dist/{annotation-BuwTxCIH.js → annotation-BiviGSmz.js} +1 -1
  6. package/dist/{api-keys-CHRLCfrl.js → api-keys-DQob1q69.js} +1 -1
  7. package/dist/{apply-B19bFTz0.js → apply-oUMOH7u2.js} +1 -1
  8. package/dist/{audit-Demn5lBp.js → audit-B4a5u54T.js} +2 -3
  9. package/dist/banner-MAYlzjcP.js +1 -0
  10. package/dist/{bar-DWT-1xOE.js → bar-DG-MqgGx.js} +1 -1
  11. package/dist/bin.js +6 -5
  12. package/dist/chat-panel-dXLm3hUn.js +7 -0
  13. package/dist/{commands-BX5I2UyT.js → commands-B-NMyq2s.js} +1 -1
  14. package/dist/companies-CpDnB5NR.js +2 -0
  15. package/dist/csv-emit-DYTuKBke.js +1 -0
  16. package/dist/csv-emit-XJfJC5e2.js +1 -0
  17. package/dist/{data-table-BpbyyNSA.js → data-table-BvnWCG-w.js} +1 -1
  18. package/dist/deploys-CI88FRFO.js +2 -0
  19. package/dist/devices-DNkzamfH.js +2 -0
  20. package/dist/{doctor-C1O4DlbQ.js → doctor-DJbNKwdF.js} +5 -5
  21. package/dist/{domains-BCDiOFYb.js → domains-BoRRxWzR.js} +1 -1
  22. package/dist/{emit-DBYk96TD.js → emit-D4YlMlzk.js} +1 -1
  23. package/dist/{empty-state-CJxa1jUN.js → empty-state-DdLBcz4h.js} +1 -1
  24. package/dist/errors-BtGhPNBy.js +2 -0
  25. package/dist/events-tail-ig5nAsbQ.js +5 -0
  26. package/dist/export-CTI3xHqF.js +4 -0
  27. package/dist/funnel-DkcJHeX6.js +3 -0
  28. package/dist/geo-UBu3aUHh.js +2 -0
  29. package/dist/{globe-C_m7zGZM.js → globe-GU2r8P23.js} +2 -2
  30. package/dist/{goals-OQ1s7Vhq.js → goals-CcA4qOM5.js} +1 -1
  31. package/dist/health-C-efHHs0.js +1 -0
  32. package/dist/health-am28BgPf.js +2 -0
  33. package/dist/heatmaps-C6ynBgMW.js +1 -0
  34. package/dist/home-B0miYclo.js +2 -0
  35. package/dist/init-CqcqX8o5.js +79 -0
  36. package/dist/init-awEnG3zC.js +1 -0
  37. package/dist/insights-C8PBisLR.js +1 -0
  38. package/dist/{integrations-S-9EITZH.js → integrations-CS16nG51.js} +3 -3
  39. package/dist/journeys-DaqlziL4.js +1 -0
  40. package/dist/{keybar-DsYTkKZX.js → keybar-BcHUm3hI.js} +1 -1
  41. package/dist/keybar-deep-link-Dagnpllp.js +1 -0
  42. package/dist/live-cIPlpoWN.js +1 -0
  43. package/dist/login-CiJG9-gq.js +1 -0
  44. package/dist/login-RVU9FkAl.js +2 -0
  45. package/dist/{logout-eXZJMigi.js → logout-BSSOsDr7.js} +1 -1
  46. package/dist/{metric-card-COEIZmbN.js → metric-card-CaFIymSQ.js} +1 -1
  47. package/dist/open-url-dPoDcwsm.js +1 -0
  48. package/dist/pages-3tis8juF.js +2 -0
  49. package/dist/panel-DB1HLxAw.js +1 -0
  50. package/dist/{plans-CNWFx-qt.js → plans-DCon6c8N.js} +5 -5
  51. package/dist/progress-row-BS7fwhn_.js +3 -0
  52. package/dist/projects-B7xPHSK2.js +2 -0
  53. package/dist/{prompt-D-Uzz_GF.js → prompt-D7Ek9MYk.js} +1 -1
  54. package/dist/query-CC7wPhmz.js +8 -0
  55. package/dist/resolve-site-DYBsBK4c.js +2 -0
  56. package/dist/retention-DeG_P1-s.js +1 -0
  57. package/dist/revenue-Dobs3EQH.js +2 -0
  58. package/dist/secrets-BBaEWu03.js +1 -0
  59. package/dist/self-test-DKOYwgHD.js +16 -0
  60. package/dist/sessions-DM4XGC2N.js +1 -0
  61. package/dist/{share-BG5ipcQi.js → share-6Dt695rC.js} +1 -1
  62. package/dist/sources-BofnMkYR.js +2 -0
  63. package/dist/stats-DkrgaDDP.js +2 -0
  64. package/dist/{status-agent-Dej6dGvX.js → status-agent-CQ955HRn.js} +1 -1
  65. package/dist/{team-B1qfFxKA.js → team-N-Ycc7Mh.js} +1 -1
  66. package/dist/theme-Brz9wK0w.js +1 -0
  67. package/dist/themes-lGJ4GHVu.js +4 -0
  68. package/dist/{tour-Bwbv_E4Q.js → tour-BA4g04Qt.js} +1 -1
  69. package/dist/ui-DXrdVAc-.js +1 -0
  70. package/dist/{update-BDMLrzzb.js → update-CYLXsiSE.js} +1 -1
  71. package/dist/uptime-I3klxuzW.js +1 -0
  72. package/dist/{usage-kXVWbunU.js → usage-DIzd9nzk.js} +1 -1
  73. package/dist/{use-B8cSIrZL.js → use-DlyoJe6I.js} +1 -1
  74. package/dist/visitors-BFBitwBV.js +2 -0
  75. package/dist/vitals-Bq1y2LBt.js +2 -0
  76. package/dist/watch-BYIKjsGC.js +1 -0
  77. package/dist/{webhooks-BhZkT0SX.js → webhooks-DKBhl3fL.js} +1 -1
  78. package/dist/webhooks-forward-Cfzd9veV.js +3 -0
  79. package/dist/wizard-bin.js +1 -1
  80. package/package.json +3 -2
  81. package/dist/ai-CPogCNEQ.js +0 -7
  82. package/dist/alerts-DWVCFKlS.js +0 -3
  83. package/dist/analytical-screen-BasvNR-9.js +0 -1
  84. package/dist/analytics-C7mAE3gV.js +0 -2
  85. package/dist/banner-3iSWTDFy.js +0 -1
  86. package/dist/chat-panel-CqJaCIg3.js +0 -7
  87. package/dist/companies-DEdYd-bV.js +0 -2
  88. package/dist/csv-emit-BuRZNWYM.js +0 -1
  89. package/dist/csv-emit-Dn3c0RCG.js +0 -1
  90. package/dist/deploys-DTIU1Kqt.js +0 -2
  91. package/dist/devices-DK_o0JcI.js +0 -2
  92. package/dist/errors-Dig3nVCV.js +0 -2
  93. package/dist/events-tail-u_lwZas2.js +0 -5
  94. package/dist/export-DkAIRS9F.js +0 -4
  95. package/dist/funnel-Brtq8avo.js +0 -3
  96. package/dist/geo-c9hA42_9.js +0 -2
  97. package/dist/health-B5DBRP3C.js +0 -1
  98. package/dist/health-BttlLZWZ.js +0 -2
  99. package/dist/heatmaps-BPxqgMmV.js +0 -1
  100. package/dist/home-DGrXLbbO.js +0 -2
  101. package/dist/init-BIJkCrgc.js +0 -79
  102. package/dist/init-BhfcLbDE.js +0 -1
  103. package/dist/insights-CrUKfMD5.js +0 -1
  104. package/dist/journeys-BbySeXM2.js +0 -1
  105. package/dist/keybar-deep-link-DC31T3CP.js +0 -1
  106. package/dist/live-dcM0RwGp.js +0 -1
  107. package/dist/login-DgU__egg.js +0 -1
  108. package/dist/login-yhuXiFqh.js +0 -2
  109. package/dist/pages-Bk5gbJ2v.js +0 -1
  110. package/dist/panel-B_yDcIcn.js +0 -1
  111. package/dist/progress-row-BpAXjJPL.js +0 -3
  112. package/dist/projects-BOU9sd2x.js +0 -2
  113. package/dist/query-CFNNsz6m.js +0 -8
  114. package/dist/resolve-site-mj0esTrm.js +0 -2
  115. package/dist/retention-CYDhYbyf.js +0 -1
  116. package/dist/revenue-D8uN4mjW.js +0 -2
  117. package/dist/secrets-c-NB_plk.js +0 -1
  118. package/dist/self-test-Cc5PWB08.js +0 -16
  119. package/dist/sessions-DqTjJFcP.js +0 -1
  120. package/dist/sources-D0FxjzeB.js +0 -2
  121. package/dist/stats-DmkvUylD.js +0 -2
  122. package/dist/themes-Dqt--qhd.js +0 -4
  123. package/dist/ui-Cey-h6wI.js +0 -1
  124. package/dist/uptime-CNGVODGc.js +0 -1
  125. package/dist/visitors-D7Q6chjq.js +0 -2
  126. package/dist/vitals-DmMAuIdP.js +0 -2
  127. package/dist/watch-D5WeMSz2.js +0 -1
  128. package/dist/webhooks-forward-D9PZDQ77.js +0 -3
  129. /package/dist/{client-DTXWADkX.js → client-I4GTcUcm.js} +0 -0
  130. /package/dist/{completions-CaYLmArp.js → completions-Cy6kF9kp.js} +0 -0
  131. /package/dist/{examples-BtWVpY-G.js → examples-C0LrZPUl.js} +0 -0
  132. /package/dist/{fmt-gMsty5jy.js → fmt-iR2sYwsO.js} +0 -0
  133. /package/dist/{formatter-DutfcQAc.js → formatter-C4YSOKuq.js} +0 -0
  134. /package/dist/{notes-DUqpXghJ.js → notes-ZXJfqA4H.js} +0 -0
  135. /package/dist/{profile-CZm-_uy-.js → profile-CY1_dG5d.js} +0 -0
  136. /package/dist/{secrets-ApB7yh2A.js → secrets-DzueUVGL.js} +0 -0
  137. /package/dist/{settings-CTbX2BXa.js → settings-C_st_Aqq.js} +0 -0
  138. /package/dist/{sparkline-BZ0eMB-w.js → sparkline-8ucKVUV7.js} +0 -0
  139. /package/dist/{teams-BzLZoKsj.js → teams-BmzDAiAn.js} +0 -0
  140. /package/dist/{telemetry--Yk0J5zc.js → telemetry-Ckn12kyP.js} +0 -0
@@ -1,2 +0,0 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import{ApiError as t}from"./api-FCanTxsb.js";import{readToken as n}from"./token-store-BQuGH0z2.js";import"./telemetry-DRh10SvO.js";import{ApiV2Client as r}from"./api-v2-CI5hxW-O.js";import"./client-DTXWADkX.js";import"./formatter-DutfcQAc.js";import{emit$1 as i,isHeadless as a}from"./emit-DBYk96TD.js";import{Panel as o}from"./panel-B_yDcIcn.js";import{Banner as s}from"./banner-3iSWTDFy.js";import"./prompt-D-Uzz_GF.js";import{Keybar as c}from"./keybar-DsYTkKZX.js";import"./sparkline-BZ0eMB-w.js";import{ChatPanel as l}from"./chat-panel-CqJaCIg3.js";import{resolveSiteId as u}from"./resolve-site-mj0esTrm.js";import{stripUrlPrefix as d}from"./fmt-gMsty5jy.js";import{DataTable as f}from"./data-table-BpbyyNSA.js";import{EmptyState as p}from"./empty-state-CJxa1jUN.js";import{MetricCard as m}from"./metric-card-COEIZmbN.js";import{Bar as h}from"./bar-DWT-1xOE.js";import{deepLinkFor as g,openInBrowser as _}from"./keybar-deep-link-DC31T3CP.js";import{Box as v,Text as y,render as b,useApp as x,useInput as S}from"ink";import C,{useEffect as w,useState as T}from"react";import E from"ink-spinner";function D(e){if(!(e instanceof t))return!1;let n=e.status;if(n===401||n===403||n===404)return!0;let r=e.body,i=r?.code;return i===`forbidden`||i===`not_found`||i===`auth_required`||i===`auth_invalid`||i===`tier_insufficient`}function O(e,t){return e.catch(e=>{if(D(e))throw e;return t})}async function k(t){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 r({config:o,cliVersion:t.cliVersion,token:s}),l,d;try{({siteId:l,site:d}=await u(c,{explicit:t.siteId,headless:!!t.json,cliVersion:t.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let f=d?.url?d.url.replace(/^https?:\/\//,``).replace(/\/$/,``):d?.name??l;if(a(t))try{let e=await j(c,l,`24h`);if(t.csv||t.tsv){let{writeCsv:n}=await import(`./csv-emit-BuRZNWYM.js`);return n(e.topPages,[`path`,`views`,`uniqueVisitors`,`avgTime`,`bounceRate`],t.tsv?`tsv`:`csv`)}if(t.ndjson){for(let t of e.topPages)process.stdout.write(JSON.stringify(t)+`
2
- `);return 0}return i({type:`overview.snapshot`,data:e}),0}catch(e){let{emitErrorEnvelope:n}=await import(`./error-codes-fnm-9MRL.js`);return n(e,{command:`analytics`,cliVersion:t.cliVersion})}return new Promise(e=>{let{unmount:n}=b(C.createElement(M,{api:c,siteId:l,siteLabel:f,cliVersion:t.cliVersion,onExit:t=>{n(),e(t)}}))})}function A(e){return e===`24h`?`7d`:e}async function j(e,t,n){let[r,i,a,o,s]=await Promise.all([O(e.getStats(t,n),null),O(e.getPages(t),[]),O(e.getSources(t,A(n),`prev`),null),O(e.getGeo(t),null),O(e.getDevices(t),null)]),c=i.reduce((e,t)=>e+t.views,0),l=(r?.daily??[]).map(e=>e.visitors),u=(r?.daily??[]).map(e=>e.pageviews),d=Math.floor(l.length/2),f=l.slice(0,d).reduce((e,t)=>e+t,0),p=u.slice(0,d).reduce((e,t)=>e+t,0),m=(a?.sources??[]).filter(e=>e.channel!==`other`||!e.source.includes(`/`)).slice(0,6).map(e=>({name:e.source,visitors:e.visitors,delta:e.delta??null}));return{visitors:r?.visitors??0,pageviews:r?.pageviews??c,bounceRate:r?.bounceRate??null,avgSession:r?.avgSessionSec??null,series:l,pageviewsSeries:u,prevVisitors:f,prevPageviews:p,topPages:i.slice(0,10),channels:m,countries:(o?.countries??[]).slice(0,8),browsers:(s?.browsers??[]).slice(0,5),devices:(s?.devices??[]).slice(0,5)}}const M=({api:e,siteId:t,siteLabel:n,cliVersion:r,onExit:i})=>{let{exit:a}=x(),[u,b]=T(null),[D,O]=T(!0),[k,A]=T(null),[M,N]=T(`24h`),[P,F]=T(t),[I,L]=T(n),[R,z]=T(!1),[B,V]=T([]),[H,U]=T(!1);S(async t=>{if(!H){if(t===`/`){U(!0);return}if(t===`o`||t===`O`){_(g(`overview`,{siteId:P}));return}if(t===`q`){a(),i(0);return}if(t===`1`){N(`24h`);return}if(t===`2`){N(`7d`);return}if(t===`3`){N(`30d`);return}if(t===`4`){N(`90d`);return}if(t===`s`){if(B.length===0)try{let t=await e.getSites();V(t)}catch{}z(e=>!e);return}}}),w(()=>{let t=!1;return O(!0),(async()=>{try{let n=await j(e,P,M);t||(b(n),O(!1))}catch(e){t||(A(e.message),O(!1))}})(),()=>{t=!0}},[e,P,M]);let W=()=>C.createElement(o,{title:`Switch site`,state:`idle`},B.length===0?C.createElement(y,{color:`gray`},`Loading your sites…`):B.map(e=>C.createElement(v,{key:e.id},C.createElement(y,{color:e.id===P?`cyan`:`gray`},e.id===P?`› `:` `),C.createElement(y,{bold:e.id===P},e.name),C.createElement(y,{color:`gray`},` (`,e.url.replace(/^https?:\/\//,``).replace(/\/$/,``),`)`))),C.createElement(v,{marginTop:1},C.createElement(y,{color:`gray`},`Press `),C.createElement(y,{color:`cyan`},`[number]`),C.createElement(y,{color:`gray`},` to pick, `),C.createElement(y,{color:`cyan`},`[s]`),C.createElement(y,{color:`gray`},` to close.`)));S(e=>{if(H||!R)return;let t=Number(e);if(Number.isInteger(t)&&t>=1&&t<=B.length){let e=B[t-1];F(e.id),L(e.url.replace(/^https?:\/\//,``).replace(/\/$/,``)),z(!1)}});let G=`overview · ${I} · ${M}`,K=[{key:`q`,label:`quit`},{key:`/`,label:`ask AI`},{key:`o`,label:`open in browser`},{key:`s`,label:`site`},{key:`1-4`,label:`range (24h/7d/30d/90d)`}];if(H)return C.createElement(l,{cliVersion:r,api:e,dashboardContext:{commandName:`overview`,siteId:P,siteLabel:I,metricsSnapshot:u},onClose:()=>U(!1)});if(D)return C.createElement(v,{flexDirection:`column`},C.createElement(s,{version:r,subtitle:G}),C.createElement(o,{title:`Loading`,state:`busy`},C.createElement(v,null,C.createElement(y,{color:`cyan`},C.createElement(E,{type:`dots`})),C.createElement(y,null,` Fetching dashboard…`))),R?W():null);if(k)return C.createElement(v,{flexDirection:`column`},C.createElement(s,{version:r,subtitle:G}),C.createElement(p,{reason:`error`,headline:`Failed to load`,hint:k}),R?W():null,C.createElement(c,{items:K}));if(!u||u.visitors===0&&u.pageviews===0&&u.topPages.length===0)return C.createElement(v,{flexDirection:`column`},C.createElement(s,{version:r,subtitle:G}),C.createElement(p,{reason:`no-data`,headline:`No data yet`,hint:`Visit your site to send the first event — or press [s] to switch to a different site, or [1-4] to widen the time range.`}),R?W():null,C.createElement(c,{items:K}));let q=process.stdout.columns??80,J=Math.max(18,Math.floor(q/4)-1),Y=Math.max(28,Math.floor(q/2)-2),X=[{key:`path`,label:`path`,width:32,format:e=>d(String(e??``))},{key:`views`,label:`views`,align:`right`,width:8},{key:`uniqueVisitors`,label:`visitors`,align:`right`,width:8},{key:`avgTime`,label:`avg time`,align:`right`,width:9,format:e=>typeof e==`number`?`${Math.round(e/1e3)}s`:`—`},{key:`bounceRate`,label:`bounce`,align:`right`,width:7,format:e=>typeof e==`number`?`${(e*100).toFixed(0)}%`:`—`}],Z=u.prevVisitors>0?(u.visitors-u.prevVisitors)/u.prevVisitors:void 0,Q=u.prevPageviews>0?(u.pageviews-u.prevPageviews)/u.prevPageviews:void 0,ee=Math.max(1,...u.channels.map(e=>e.visitors)),te=Math.max(1,...u.countries.map(e=>e.visitors)),ne=Math.max(1,...u.browsers.map(e=>e.visitors)),re=Math.max(1,...u.devices.map(e=>e.visitors)),$=Math.max(8,Math.floor(Y/3));return C.createElement(v,{flexDirection:`column`},C.createElement(s,{version:r,subtitle:G}),C.createElement(v,{flexDirection:`row`},C.createElement(m,{title:`Visitors`,value:u.visitors,format:`number`,width:J,series:u.series,...typeof Z==`number`?{delta:Z}:{}}),C.createElement(m,{title:`Pageviews`,value:u.pageviews,format:`number`,width:J,series:u.pageviewsSeries,...typeof Q==`number`?{delta:Q}:{}}),C.createElement(m,{title:`Bounce rate`,value:u.bounceRate??``,emptyHint:`—`,format:`percent`,width:J}),C.createElement(m,{title:`Avg session`,value:u.avgSession??``,emptyHint:`—`,format:`duration`,width:J})),C.createElement(v,{flexDirection:`row`,flexWrap:`wrap`},C.createElement(v,{width:Y,flexDirection:`column`},C.createElement(o,{title:`Channels`},u.channels.length===0?C.createElement(y,{color:`gray`},`No channel data yet.`):u.channels.map(e=>C.createElement(v,{key:e.name,flexDirection:`row`},C.createElement(v,{width:12},C.createElement(y,null,e.name)),C.createElement(h,{value:e.visitors,max:ee,width:$,showPercent:!1,...typeof e.delta==`number`?{delta:e.delta}:{}}),C.createElement(y,{color:`gray`},` `,e.visitors))))),C.createElement(v,{width:Y,flexDirection:`column`},C.createElement(o,{title:`Top countries`},u.countries.length===0?C.createElement(y,{color:`gray`},`No geo data yet.`):u.countries.map(e=>C.createElement(v,{key:e.country,flexDirection:`row`},C.createElement(v,{width:5},C.createElement(y,null,e.country)),C.createElement(h,{value:e.visitors,max:te,width:$,showPercent:!1}),C.createElement(y,{color:`gray`},` `,e.visitors)))))),C.createElement(v,{flexDirection:`row`,flexWrap:`wrap`},C.createElement(v,{width:Y,flexDirection:`column`},C.createElement(o,{title:`Top browsers`},u.browsers.length===0?C.createElement(y,{color:`gray`},`No browser data yet.`):u.browsers.map(e=>C.createElement(v,{key:e.name,flexDirection:`row`},C.createElement(v,{width:12},C.createElement(y,null,e.name)),C.createElement(h,{value:e.visitors,max:ne,width:$,showPercent:!1}),C.createElement(y,{color:`gray`},` `,e.visitors))))),C.createElement(v,{width:Y,flexDirection:`column`},C.createElement(o,{title:`Top devices`},u.devices.length===0?C.createElement(y,{color:`gray`},`No device data yet.`):u.devices.map(e=>C.createElement(v,{key:e.name,flexDirection:`row`},C.createElement(v,{width:12},C.createElement(y,null,e.name)),C.createElement(h,{value:e.visitors,max:re,width:$,showPercent:!1}),C.createElement(y,{color:`gray`},` `,e.visitors)))))),C.createElement(o,{title:`Top pages (${M})`},u.topPages.length===0?C.createElement(y,{color:`gray`},`No pages with data in this window yet.`):C.createElement(f,{columns:X,data:u.topPages,zebra:!0})),R?W():null,C.createElement(c,{items:K}))};async function N(e){return k(e)}export{N as analyticsCommand};
@@ -1 +0,0 @@
1
- import{useTheme as e}from"./panel-B_yDcIcn.js";import{Box as t,Text as n}from"ink";import r from"react";function i(){let e=process.stdout.columns;return typeof e==`number`&&e>0?e:80}function a({version:a,subtitle:o}){let{theme:s}=e(),c=i(),l=`ZENOVAY`,u=`v${a}`,d=`╭─ `,f=` · `,p=` `,m=`─╮`,h=d.length+l.length+f.length+u.length+p.length+m.length,g=Math.max(2,c-h),_=`─`.repeat(g),v=`─`.repeat(Math.max(2,c-2)),y=o??``,b=y.slice(0,Math.max(0,c-4)),x=` `.repeat(Math.max(1,c-2-1-b.length-1));return r.createElement(t,{flexDirection:`column`},r.createElement(t,{flexDirection:`row`},r.createElement(n,{color:s.border},d),r.createElement(n,{color:s.accent,bold:!0},l),r.createElement(n,{color:s.dim},f,u),r.createElement(n,{color:s.border},p,_,m)),o?r.createElement(t,{flexDirection:`row`},r.createElement(n,{color:s.border},`│ `),r.createElement(n,{color:s.fg},b),r.createElement(n,{color:s.border},x,`│`)):null,r.createElement(t,{flexDirection:`row`},r.createElement(n,{color:s.border},`╰`,v,`╯`)))}export{a as Banner};
@@ -1,7 +0,0 @@
1
- import{emit as e}from"./telemetry-DRh10SvO.js";import{parseSseStream as t}from"./client-DTXWADkX.js";import{useTheme as n}from"./panel-B_yDcIcn.js";import{Banner as r}from"./banner-3iSWTDFy.js";import{Box as i,Static as a,Text as o,useApp as s,useInput as c}from"ink";import l,{useEffect as u,useRef as d,useState as f}from"react";import p from"ink-spinner";import m from"ink-text-input";const h=2048;async function*g(e){let n=[{role:`system`,content:_(e.context)},...e.transcript,{role:`user`,content:e.newUserMessage}],r;try{r=await e.api.openAiStream(`chat`,{messages:n,siteId:e.context.siteId},e.signal)}catch(e){yield{type:`error`,message:e.message??`request failed`};return}if(!r.ok){yield{type:`error`,message:`chat request failed (${r.status})`,code:String(r.status)};return}let i=``;try{for await(let e of t(r))if(e.type===`delta`)i+=e.content,yield{type:`delta`,text:e.content};else if(e.type===`tool_start`)yield{type:`tool_start`,id:e.id,name:e.name};else if(e.type===`tool_result`)yield{type:`tool_result`,id:e.id,name:e.name,summary:e.summary,error:e.error};else if(e.type===`done`){yield{type:`done`,fullText:i};return}else if(e.type===`error`){yield{type:`error`,message:e.message,code:e.code};return}yield{type:`done`,fullText:i}}catch(e){if(e.name===`AbortError`){yield{type:`error`,message:`cancelled`,code:`aborted`};return}yield{type:`error`,message:e.message??`stream parse failed`}}}function _(e){let t=new Date().toISOString(),n=e.metricsSnapshot?v(e.metricsSnapshot,h):`(no live data yet)`,r=e.siteLabel?`${e.siteLabel}${e.siteId?` (id: ${e.siteId})`:``}`:e.siteId??`(no site)`;return[`You are the Zenovay AI assistant, embedded in the Zenovay terminal CLI.`,``,`The user is currently looking at the \`${e.commandName}\` view for their site ${r}.`,`They can ask questions about their analytics in plain English. Be concise`,`(≤200 words unless they ask for more). Cite specific numbers from the snapshot`,`below. Use plain text only — the terminal does not render markdown.`,``,`Current dashboard snapshot (live as of ${t}):`,n,``,`When you do not have enough data to answer, say so explicitly and tell`,`the user which command would surface that data (e.g. "run zenovay sources`,`--period 30d to get monthly trends"). Do NOT fabricate numbers.`].join(`
2
- `)}function v(e,t){let n=JSON.stringify(e);if(n.length<=t)return JSON.stringify(e,null,2);let r=JSON.parse(n);for(let e=0;e<5;e+=1){r=y(r,10-e*2);let n=JSON.stringify(r);if(n.length<=t)return JSON.stringify(r,null,2)}let i=JSON.stringify(r).slice(0,t-16);return i+`… [truncated]`}function y(e,t){if(Array.isArray(e))return e.length>t?[...e.slice(0,t),`… ${e.length-t} more elided`]:e.map(e=>y(e,t));if(e&&typeof e==`object`){let n={};for(let[r,i]of Object.entries(e))n[r]=y(i,t);return n}return e}const b=30,x=6e4,S=({cliVersion:t,api:h,dashboardContext:_,onClose:v})=>{let{theme:y}=n(),{exit:S}=s(),[C,w]=f([]),[T,E]=f(``),[D,O]=f(!1),[k,A]=f(``),[j,M]=f(null),[N,P]=f([]),F=d(``),I=d(null);u(()=>{if(!D)return;let e=setInterval(()=>{F.current!==k&&A(F.current)},Math.floor(1e3/b));return()=>clearInterval(e)},[D,k]);let L=d(Date.now()),R=d(0),z=d(0);u(()=>(e(`chat.open`,{properties:{from:_.commandName,has_site:!!_.siteId}}),()=>{e(`chat.close`,{duration_ms:Date.now()-L.current,properties:{turns:R.current,tools_called:z.current}})}),[_.commandName,_.siteId]),c((e,t)=>{if(t.escape){I.current?.abort(),v();return}if(t.ctrl&&e===`c`){I.current?.abort(),v();return}});let B=async t=>{let n=t.trim();if(!n)return;if(n.startsWith(`/`)){V(n),E(``);return}if(D)return;E(``),M(null);let r={role:`user`,content:n};w(e=>[...e,r]),F.current=``,A(``),P([]),O(!0),I.current=new AbortController;let i=setTimeout(()=>{I.current?.abort(),M(`AI request timed out after ${x/1e3}s`)},x);try{let t=g({api:h,transcript:C,newUserMessage:n,context:_,signal:I.current.signal});R.current+=1;for await(let n of t)if(n.type===`delta`)F.current+=n.text;else if(n.type===`tool_start`)z.current+=1,e(`chat.tool_call`,{properties:{tool_name:n.name}}),P(e=>[...e,{id:n.id,name:n.name,status:`running`}]);else if(n.type===`tool_result`)n.error&&e(`chat.tool_error`,{properties:{tool_name:n.name??`unknown`,error:n.error.slice(0,128)}}),P(e=>e.map(e=>e.id===n.id?{...e,status:n.error?`error`:`done`,summary:n.summary,error:n.error,name:n.name??e.name}:e));else if(n.type===`done`){let e=n.fullText.length>0?n.fullText:F.current;w(t=>[...t,{role:`assistant`,content:e}]);break}else if(n.type===`error`){M(n.message),F.current.length>0&&w(e=>[...e,{role:`assistant`,content:F.current}]);break}}catch(e){M(e.message??`unknown error`)}finally{clearTimeout(i),F.current=``,A(``),P([]),O(!1),I.current=null}},V=e=>{let t=e.toLowerCase();if(t===`/clear`){w([]),M(null);return}if(t===`/exit`||t===`/quit`){I.current?.abort(),v();return}if(t===`/help`){w(e=>[...e,{role:`assistant`,content:`Slash commands:
3
- /clear — wipe the transcript
4
- /exit — close the chat (or press Esc)
5
- /help — show this list
6
-
7
- Ask anything about your current dashboard data.`}]);return}M(`Unknown slash command: ${e}. Try /help.`)},H=[`chat`,_.commandName,_.siteLabel].filter(e=>!!e);return l.createElement(i,{flexDirection:`column`},l.createElement(r,{version:t,subtitle:H.join(` · `)}),C.length===0&&!D?l.createElement(i,{marginTop:1,marginLeft:2},l.createElement(o,{color:y.dim},`Ask anything about your data. Try: "what's my top page today?"`)):null,l.createElement(a,{items:C},(e,t)=>l.createElement(i,{key:t,flexDirection:`column`,marginTop:1,marginLeft:2},l.createElement(o,{color:e.role===`user`?y.accent:y.dim,bold:!0},e.role===`user`?`you`:`ai`),l.createElement(o,{color:y.fg},e.content))),D?l.createElement(i,{flexDirection:`column`,marginTop:1,marginLeft:2},l.createElement(i,{flexDirection:`row`},l.createElement(o,{color:y.dim,bold:!0},`ai `),l.createElement(o,{color:`cyan`},l.createElement(p,{type:`dots`}))),N.length>0?l.createElement(i,{flexDirection:`column`,marginTop:0},N.map(e=>l.createElement(o,{key:e.id,color:e.status===`error`?y.error??`red`:y.dim},e.status===`running`?`… fetching `:e.status===`done`?`✓ `:`✗ `,e.name,e.status===`done`&&e.summary?` → ${e.summary}`:``,e.status===`error`&&e.error?`: ${e.error}`:``))):null,k.length>0?l.createElement(o,{color:y.fg},k):null):null,j?l.createElement(i,{marginTop:1,marginLeft:2},l.createElement(o,{color:y.error??`red`},`✗ `,j)):null,l.createElement(i,{marginTop:1,marginLeft:2,flexDirection:`column`},l.createElement(i,{flexDirection:`row`},l.createElement(o,{color:y.accent},D?`⋯ `:`> `),l.createElement(m,{value:T,onChange:E,onSubmit:e=>void B(e),placeholder:D?`streaming…`:`ask the AI`})),l.createElement(i,{marginTop:1},l.createElement(o,{color:y.dim},`[Enter] send · [/clear] reset · [/help] · [Esc] back to dashboard`))))};export{S as ChatPanel};
@@ -1,2 +0,0 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import"./api-FCanTxsb.js";import{readToken as t}from"./token-store-BQuGH0z2.js";import"./telemetry-DRh10SvO.js";import{ApiV2Client as n}from"./api-v2-CI5hxW-O.js";import"./client-DTXWADkX.js";import{formatTabular as r,selectFormat as i}from"./formatter-DutfcQAc.js";import"./panel-B_yDcIcn.js";import"./banner-3iSWTDFy.js";import"./prompt-D-Uzz_GF.js";import"./keybar-DsYTkKZX.js";import"./chat-panel-CqJaCIg3.js";import{resolveSiteId as a}from"./resolve-site-mj0esTrm.js";import{DataTable as o}from"./data-table-BpbyyNSA.js";import{deepLinkFor as s,openInBrowser as c}from"./keybar-deep-link-DC31T3CP.js";import{runAnalyticalScreen as l}from"./analytical-screen-BasvNR-9.js";import{Box as u,Text as d}from"ink";import f from"react";function p(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 m(e){return e==null?`—`:e>=500?`Enterprise`:e>=50?`Growth`:`SMB`}async function h(h){let g=await e(),_=await t({strict:!1}),v=new n({config:g,cliVersion:h.cliVersion,token:_}),y,b;try{({siteId:y,site:b}=await a(v,{explicit:h.siteId,headless:!!(h.json||h.csv||h.tsv||h.ndjson),cliVersion:h.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let x=i(h),S=h.window??`24h`,C=h.limit??100,w=[{key:`lastSeenAt`,label:`when`,width:6,format:e=>p(String(e))},{key:`name`,label:`company`,width:24,format:e=>String(e).slice(0,24)},{key:`employeeCount`,label:`tier`,width:11,format:e=>m(typeof e==`number`?e:null)},{key:`industry`,label:`industry`,width:18,format:e=>String(e??`—`).slice(0,18)},{key:`visitCount`,label:`visits`,width:6,align:`right`},{key:`isNew`,label:``,width:5,format:e=>e?`NEW`:``}];return l({cliVersion:h.cliVersion,title:`companies · ${y} · ${S}`,commandName:`companies`,ai:{api:v,siteId:y,siteLabel:b?.url?b.url.replace(/^https?:\/\//,``).replace(/\/$/,``):b?.name??y},authToken:_?.accessToken??null,refreshIntervalMs:h.watch?3e4:0,fetcher:e=>v.getCompaniesSnapshot(y,{window:S,limit:C},e),format:x,keybindings:{o:{label:`open in browser`,handler:()=>{c(s(`companies`,{siteId:y}))}}},headlessEmit:(e,t)=>{let n=h.newOnly?e.companies.filter(e=>e.isNew):e.companies;if(t===`json`||t===`ndjson`){if(t===`ndjson`)for(let e of n)process.stdout.write(JSON.stringify(e)+`
2
- `);else process.stdout.write(JSON.stringify({companies:n,total:n.length},null,2));return}process.stdout.write(r(n,[`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 f.createElement(u,{flexDirection:`column`},f.createElement(d,null,f.createElement(d,{bold:!0},e.total),f.createElement(d,{color:`gray`},` companies in `,S)),f.createElement(d,{color:`gray`},f.createElement(d,{color:`green`},`● `,t,` new`),` · `,n,` enterprise`))}},{id:`feed`,title:`Feed`,render:e=>{let t=h.newOnly?e.companies.filter(e=>e.isNew):e.companies;return t.length===0?f.createElement(d,{color:`gray`},`— no `,h.newOnly?`new `:``,`companies in window —`):f.createElement(o,{data:t.slice(0,30),columns:w,headerStyle:`accent`})}}]})}export{h as companiesCommand};
@@ -1 +0,0 @@
1
- import"./formatter-DutfcQAc.js";import{toCsv as e,writeCsv as t}from"./csv-emit-Dn3c0RCG.js";export{t as writeCsv};
@@ -1 +0,0 @@
1
- import{formatTabular as e}from"./formatter-DutfcQAc.js";function t(t,n,r){return e(t,n,r)}function n(e,n,r){return process.stdout.write(t(e,n,r)),0}export{t as toCsv,n as writeCsv};
@@ -1,2 +0,0 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import"./api-FCanTxsb.js";import{readToken as t}from"./token-store-BQuGH0z2.js";import"./telemetry-DRh10SvO.js";import{ApiV2Client as n}from"./api-v2-CI5hxW-O.js";import"./client-DTXWADkX.js";import{formatTabular as r,selectFormat as i}from"./formatter-DutfcQAc.js";import"./panel-B_yDcIcn.js";import"./banner-3iSWTDFy.js";import"./prompt-D-Uzz_GF.js";import"./keybar-DsYTkKZX.js";import"./chat-panel-CqJaCIg3.js";import{resolveSiteId as a}from"./resolve-site-mj0esTrm.js";import{DataTable as o}from"./data-table-BpbyyNSA.js";import{runAnalyticalScreen as s}from"./analytical-screen-BasvNR-9.js";import{Box as c,Text as l}from"ink";import u from"react";function d(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 f(f){if(f.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 p=await e(),m=await t({strict:!1}),h=new n({config:p,cliVersion:f.cliVersion,token:m}),g,_;try{({siteId:g,site:_}=await a(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 v=i(f),y=f.limit??50,b=[{key:`pushed_at`,label:`when`,width:6,format:e=>d(String(e))},{key:`branch`,label:`branch`,width:14,format:e=>String(e??`—`).slice(0,14)},{key:`commit_sha`,label:`commit`,width:9,format:e=>String(e).slice(0,8)},{key:`commit_author`,label:`author`,width:16,format:e=>String(e??`—`).slice(0,16)},{key:`commit_message`,label:`message`,width:40,format:e=>String(e??`—`).slice(0,40)},{key:`show_on_chart`,label:`chart`,width:5,format:e=>e?`●`:`○`}];return s({cliVersion:f.cliVersion,title:`deploys · ${g}`,commandName:`deploys`,ai:{api:h,siteId:g,siteLabel:_?.url?_.url.replace(/^https?:\/\//,``).replace(/\/$/,``):_?.name??g},authToken:m?.accessToken??null,refreshIntervalMs:0,fetcher:e=>h.getDeploys(g,{branch:f.branch,since:f.since,limit:y},e),format:v,headlessEmit:(e,t)=>{if(t===`json`||t===`ndjson`){if(t===`ndjson`)for(let t of e.deploys)process.stdout.write(JSON.stringify(t)+`
2
- `);else process.stdout.write(JSON.stringify(e,null,2));return}process.stdout.write(r(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 u.createElement(c,{flexDirection:`column`},u.createElement(l,null,u.createElement(l,{bold:!0},e.total),u.createElement(l,{color:`gray`},` commits`,f.branch?` · branch=${f.branch}`:``)),u.createElement(l,{color:`gray`},u.createElement(l,{color:`magenta`},`● `,t,` on chart`),u.createElement(l,null,` · `),u.createElement(l,null,n.size,` `,n.size===1?`repo`:`repos`)))}},{id:`list`,title:`Recent`,render:e=>e.deploys.length===0?u.createElement(c,{flexDirection:`column`},u.createElement(l,{color:`gray`},`— no commits yet —`),u.createElement(l,{color:`gray`},"Run `zenovay deploys --connect` to wire up the GitHub integration.")):u.createElement(o,{data:e.deploys.slice(0,30),columns:b,headerStyle:`accent`})}]})}export{f as deploysCommand};
@@ -1,2 +0,0 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import"./api-FCanTxsb.js";import{readToken as t}from"./token-store-BQuGH0z2.js";import{ApiV2Client as n}from"./api-v2-CI5hxW-O.js";import"./formatter-DutfcQAc.js";import{emit$1 as r,isHeadless as i}from"./emit-DBYk96TD.js";import{Panel as a}from"./panel-B_yDcIcn.js";import{Banner as o}from"./banner-3iSWTDFy.js";import"./prompt-D-Uzz_GF.js";import{Keybar as s}from"./keybar-DsYTkKZX.js";import{resolveSiteId as c}from"./resolve-site-mj0esTrm.js";import{DataTable as l}from"./data-table-BpbyyNSA.js";import{EmptyState as u}from"./empty-state-CJxa1jUN.js";import{deepLinkFor as d,openInBrowser as f}from"./keybar-deep-link-DC31T3CP.js";import{Box as p,Text as m,render as h,useApp as g,useInput as _}from"ink";import v,{useEffect as y,useState as b}from"react";import x from"ink-spinner";async function S(a){let o=await e(),s=await t({strict:!1});if(!s)return process.stderr.write("Not logged in — run `zenovay login` first.\n"),2;let l=new n({config:o,cliVersion:a.cliVersion,token:s}),u,d;try{({siteId:u,site:d}=await c(l,{explicit:a.siteId,headless:!!a.json,cliVersion:a.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let f=d?.url?d.url.replace(/^https?:\/\//,``).replace(/\/$/,``):d?.name??u;if(i(a)){let e=await l.getDevices(u);if(a.csv||a.tsv){let{writeCsv:t}=await import(`./csv-emit-BuRZNWYM.js`);return t(e.devices,[`name`,`visitors`],a.tsv?`tsv`:`csv`)}if(a.ndjson){for(let t of e.devices)process.stdout.write(JSON.stringify(t)+`
2
- `);return 0}return r({type:`devices.snapshot`,data:e}),0}return new Promise(e=>{let{unmount:t}=h(v.createElement(C,{api:l,siteId:u,siteLabel:f,cliVersion:a.cliVersion,onExit:n=>{t(),e(n)}}))})}const C=({api:e,siteId:t,siteLabel:n,cliVersion:r,onExit:i})=>{let{exit:c}=g(),[h,S]=b(null),[C,w]=b(!0),[T,E]=b(null);if(_(e=>{if(e===`o`||e===`O`){f(d(`devices`,{siteId:t}));return}e===`q`&&(c(),i(0))}),y(()=>{let n=!1;return(async()=>{try{let r=await e.getDevices(t);n||(S(r),w(!1))}catch(e){n||(E(e.message),w(!1))}})(),()=>{n=!0}},[e,t]),C)return v.createElement(p,{flexDirection:`column`},v.createElement(o,{version:r,subtitle:`devices · ${n}`}),v.createElement(a,{title:`Loading`,state:`busy`},v.createElement(p,null,v.createElement(m,{color:`magenta`},v.createElement(x,{type:`dots`})),v.createElement(m,null,` Fetching breakdown…`))));if(T)return v.createElement(p,{flexDirection:`column`},v.createElement(o,{version:r,subtitle:`devices · ${n}`}),v.createElement(u,{reason:`error`,headline:`Failed to load`,hint:T}));let D=!h||h.devices.length===0&&h.browsers.length===0&&h.os.length===0;if(D)return v.createElement(p,{flexDirection:`column`},v.createElement(o,{version:r,subtitle:`devices · ${n}`}),v.createElement(u,{reason:`no-data`,headline:`No data yet`,hint:`Visit your site to send the first event`}));let O=[{key:`name`,label:`name`,width:16},{key:`visitors`,label:`visitors`,align:`right`,width:8}];return v.createElement(p,{flexDirection:`column`},v.createElement(o,{version:r,subtitle:`devices · ${n}`}),v.createElement(p,{flexDirection:`row`},v.createElement(a,{title:`Devices`},h.devices.length===0?v.createElement(m,{color:`gray`},`— —`):v.createElement(l,{columns:O,data:h.devices,zebra:!0})),v.createElement(a,{title:`Browsers`},h.browsers.length===0?v.createElement(m,{color:`gray`},`— —`):v.createElement(l,{columns:O,data:h.browsers,zebra:!0})),v.createElement(a,{title:`OS`},h.os.length===0?v.createElement(m,{color:`gray`},`— —`):v.createElement(l,{columns:O,data:h.os,zebra:!0}))),v.createElement(s,{items:[{key:`o`,label:`open in browser`},{key:`q`,label:`quit`}]}))};export{S as devicesCommand};
@@ -1,2 +0,0 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import"./api-FCanTxsb.js";import{readToken as t}from"./token-store-BQuGH0z2.js";import"./telemetry-DRh10SvO.js";import{ApiV2Client as n}from"./api-v2-CI5hxW-O.js";import"./client-DTXWADkX.js";import{formatTabular as r,selectFormat as i}from"./formatter-DutfcQAc.js";import"./panel-B_yDcIcn.js";import"./banner-3iSWTDFy.js";import"./progress-row-BpAXjJPL.js";import"./prompt-D-Uzz_GF.js";import"./keybar-DsYTkKZX.js";import{spark as a}from"./sparkline-BZ0eMB-w.js";import"./chat-panel-CqJaCIg3.js";import{resolveSiteId as o}from"./resolve-site-mj0esTrm.js";import{DataTable as s}from"./data-table-BpbyyNSA.js";import"./bar-DWT-1xOE.js";import{deepLinkFor as c,openInBrowser as l}from"./keybar-deep-link-DC31T3CP.js";import{runAnalyticalScreen as u}from"./analytical-screen-BasvNR-9.js";import"./ui-Cey-h6wI.js";import{Box as d,Text as f}from"ink";import p from"react";function m(e,t){return e.length<=t?e:e.slice(0,t-1)+`…`}function h(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 g(g){let _=await e(),v=await t({strict:!1}),y=new n({config:_,cliVersion:g.cliVersion,token:v}),b,x;try{({siteId:b,site:x}=await o(y,{explicit:g.siteId,headless:!!(g.json||g.csv||g.tsv||g.ndjson),cliVersion:g.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let S=i(g),C=g.window??`24h`,w=g.limit??100,T=[{key:`ts`,label:`when`,width:6,format:e=>h(String(e))},{key:`class`,label:`class`,width:18,format:e=>String(e)},{key:`message`,label:`message`,width:42,format:e=>m(String(e??``),42)},{key:`page`,label:`page`,width:24,format:e=>String(e??`—`)},{key:`device`,label:`device`,width:8,format:e=>String(e??`—`)}];return u({cliVersion:g.cliVersion,title:`errors · ${b} · ${C}`,commandName:`errors`,ai:{api:y,siteId:b,siteLabel:x?.url?x.url.replace(/^https?:\/\//,``).replace(/\/$/,``):x?.name??b},authToken:v?.accessToken??null,refreshIntervalMs:g.watch?3e4:0,fetcher:e=>y.getErrors(b,{window:C,limit:w},e),format:S,keybindings:{o:{label:`open in browser`,handler:()=>{l(c(`errors`,{siteId:b}))}}},headlessEmit:(e,t)=>{let n=g.search?e.errors.filter(e=>e.class.toLowerCase().includes(g.search.toLowerCase())||e.message.toLowerCase().includes(g.search.toLowerCase())):e.errors;if(t===`json`||t===`ndjson`){if(t===`ndjson`)for(let e of n)process.stdout.write(JSON.stringify(e)+`
2
- `);else process.stdout.write(JSON.stringify({errors:n,total:n.length},null,2));return}process.stdout.write(r(n,[`ts`,`class`,`message`,`page`,`device`,`fingerprint`],t))},panels:[{id:`summary`,title:`Recent errors`,render:e=>{let t=g.search?e.errors.filter(e=>e.class.toLowerCase().includes(g.search.toLowerCase())||e.message.toLowerCase().includes(g.search.toLowerCase())):e.errors,n=new Map,r=Date.now(),i=60;for(let e of t){let t=new Date(e.ts).getTime(),a=Math.floor((r-t)/(60*1e3));if(a<0||a>=i)continue;let o=n.get(e.class)??Array(i).fill(0),s=i-1-a;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 p.createElement(d,{flexDirection:`column`},p.createElement(f,null,p.createElement(f,{bold:!0},t.length),p.createElement(f,{color:`gray`},` errors in `,C)),o.length===0?null:p.createElement(d,{flexDirection:`column`,marginTop:1},o.map(([e,t])=>p.createElement(f,{key:e},p.createElement(f,{color:`red`},e.padEnd(20).slice(0,20)),` `,p.createElement(f,{color:`gray`},a(t,30))))))}},{id:`table`,title:`Detail`,render:e=>{let t=g.search?e.errors.filter(e=>e.class.toLowerCase().includes(g.search.toLowerCase())||e.message.toLowerCase().includes(g.search.toLowerCase())):e.errors;return t.length===0?p.createElement(f,{color:`gray`},`— no errors `,g.search?`matching "${g.search}"`:`in window`,` —`):p.createElement(s,{data:t.slice(0,30),columns:T,headerStyle:`accent`})}}]})}export{g as errorsCommand};
@@ -1,5 +0,0 @@
1
- import{readConfig as e,updateConfig as t}from"./config--JRu_jFq.js";import{ApiClient as n}from"./api-FCanTxsb.js";import{readToken as r}from"./token-store-BQuGH0z2.js";import{parseSseStream as i}from"./client-DTXWADkX.js";import"./formatter-DutfcQAc.js";import{isHeadless as a}from"./emit-DBYk96TD.js";import{Panel as o}from"./panel-B_yDcIcn.js";import{Banner as s}from"./banner-3iSWTDFy.js";import{TextInput as c}from"./prompt-D-Uzz_GF.js";import{Keybar as l}from"./keybar-DsYTkKZX.js";import u from"node:path";import{promises as d}from"node:fs";import f from"node:os";import p from"node:crypto";import{Box as m,Static 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";const w=new Set([`type`,`page`,`country`,`device`,`user_id`,`sessionId`,`referrer`,`ts`,`url`,`method`,`status`]);function T(e){let t=[],n=0;for(;n<e.length;){let r=e[n];if(/\s/.test(r)){n+=1;continue}if(r===`(`){t.push({kind:`lparen`}),n+=1;continue}if(r===`)`){t.push({kind:`rparen`}),n+=1;continue}if(r===`"`||r===`'`){let i=r,a=n+1,o=``;for(;a<e.length&&e[a]!==i;)e[a]===`\\`&&a+1<e.length?(o+=e[a+1],a+=2):(o+=e[a],a+=1);if(a>=e.length)throw Error(`filter: unterminated string starting at column ${n+1}`);t.push({kind:`string`,value:o}),n=a+1;continue}if(r===`!`&&e[n+1]===`=`){t.push({kind:`op`,value:`!=`}),n+=2;continue}if(r===`!`&&e[n+1]===`~`){t.push({kind:`op`,value:`!~`}),n+=2;continue}if(r===`=`){t.push({kind:`op`,value:`=`}),n+=1;continue}if(r===`~`){t.push({kind:`op`,value:`~`}),n+=1;continue}let i=n;for(;n<e.length&&!/[\s()=!~]/.test(e[n])&&e[n]!==`"`&&e[n]!==`'`;)n+=1;let a=e.slice(i,n);if(a.length===0)throw Error(`filter: unexpected character at column ${i+1}`);let o=a.toUpperCase();o===`AND`?t.push({kind:`and`}):o===`OR`?t.push({kind:`or`}):t.push({kind:`ident`,value:a})}return t}function E(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function D(e,t,n){let r=e==null?``:String(e);switch(t){case`=`:return r===n;case`!=`:return r!==n;case`~`:{let e=new RegExp(E(n),`i`);return e.test(r)}case`!~`:{let e=new RegExp(E(n),`i`);return!e.test(r)}}}function O(e){return e.tokens[e.pos]}function k(e){let t=e.tokens[e.pos];return e.pos+=1,t}function A(e){let t=O(e);if(!t)throw Error(`filter: unexpected end of expression`);if(t.kind===`lparen`){k(e);let t=j(e),n=k(e);if(!n||n.kind!==`rparen`)throw Error(`filter: missing closing ")"`);return t}if(t.kind!==`ident`)throw Error(`filter: expected key, got ${t.kind}`);k(e);let n=t.value;if(!w.has(n))throw Error(`filter: unknown key "${n}". Allowed: ${[...w].join(`, `)}`);let r=k(e);if(!r||r.kind!==`op`)throw Error(`filter: expected operator after "${n}"`);let i=k(e);if(!i||i.kind!==`ident`&&i.kind!==`string`)throw Error(`filter: expected value after operator "${r.value}"`);let a=r.value,o=i.value;return e=>D(e[n],a,o)}function j(e){let t=A(e);for(;;){let n=O(e);if(!n)break;if(n.kind===`and`){k(e);let n=A(e),r=t;t=e=>r(e)&&n(e);continue}if(n.kind===`or`){k(e);let n=A(e),r=t;t=e=>r(e)||n(e);continue}break}return t}function M(e){if(typeof e!=`string`||e.trim().length===0)throw Error(`filter: expression is empty`);let t=T(e);if(t.length===0)throw Error(`filter: expression is empty`);let n={tokens:t,pos:0},r=j(n);if(n.pos!==t.length){let e=n.tokens[n.pos];throw Error(`filter: unexpected trailing token "${N(e)}"`)}return r}function N(e){return e.kind===`ident`||e.kind===`string`||e.kind===`op`?e.value:e.kind}const P=10*1024*1024;var F=class{currentBytes=0;initialized=!1;writeQueue=Promise.resolve();constructor(e,t=P){this.filePath=e,this.maxBytes=t}async init(){if(!this.initialized){this.initialized=!0;try{await d.mkdir(u.dirname(this.filePath),{recursive:!0,mode:448})}catch{}try{let e=await d.stat(this.filePath);this.currentBytes=e.size}catch{this.currentBytes=0}}}append(e){let t=(async()=>{await this.init();let t=e.endsWith(`
2
- `)?e:`${e}\n`,n=Buffer.byteLength(t,`utf8`);this.currentBytes+n>this.maxBytes&&await this.rotate();try{await d.appendFile(this.filePath,t,{mode:384}),this.currentBytes+=n}catch(e){process.stderr.write(`[scrollback] append failed: ${e.message}\n`)}})();return this.writeQueue=this.writeQueue.then(()=>t,()=>t),t}async rotate(){let e=e=>{if(e===0)return this.filePath;let t=u.parse(this.filePath);return u.join(t.dir,`${t.name}.${e}${t.ext}`)};try{await d.unlink(e(3))}catch{}for(let t=2;t>=0;--t)try{await d.rename(e(t),e(t+1))}catch(n){n.code!==`ENOENT`&&process.stderr.write(`[scrollback] rotate ${e(t)} failed: ${n.message}\n`)}this.currentBytes=0}async close(){await this.writeQueue}};const I=5e3,L=33,R=`─── replay end, live below ───`;async function z(i){if(i.setForwardSecret)return await t({forwardSecret:i.setForwardSecret}),process.stdout.write(`Forward secret saved.
3
- `),0;let o=await e(),s=await r({strict:!1});if(!s)return process.stderr.write("Not logged in — run `zenovay login` first.\n"),2;let c=new n({config:o,cliVersion:i.cliVersion,token:s}),l=null;if(i.filter)try{l=M(i.filter)}catch(e){return process.stderr.write(`Invalid --filter expression: ${e.message}\n`),2}if(a(i))return H(c,i,l,o.forwardSecret);let d=i.scrollbackPath??u.join(f.homedir(),`.zenovay`,`events-scrollback.log`);return new Promise(e=>{let{unmount:t}=_(b.createElement(U,{api:c,opts:i,predicate:l,forwardSecret:o.forwardSecret,scrollbackPath:d,onExit:n=>{t(),e(n)}}))})}function B(e){return{raw:JSON.stringify(e),parsed:e}}async function V(e,t,n){let r=JSON.stringify(n),i=p.createHmac(`sha256`,t).update(r).digest(`hex`);try{await fetch(e,{method:`POST`,headers:{"Content-Type":`application/json`,"X-Zenovay-Signature":`sha256=${i}`},body:r})}catch{}}async function H(e,t,n,r){let a=new AbortController;process.on(`SIGINT`,()=>a.abort());let o=()=>new Date().toISOString();try{let s=await e.openEventsStream(t.siteId,a.signal);for await(let e of i(s)){if(e.type===`error`)return process.stdout.write(`${JSON.stringify({ts:o(),type:`error`,code:e.code,message:e.message})}\n`),1;if(e.type===`done`)return 0;let i=e;if(n&&!n(i))continue;process.stdout.write(`${JSON.stringify({ts:o(),...i})}\n`),t.forwardTo&&r&&await V(t.forwardTo,r,{event:e,ts:o(),site_id:t.siteId})}return 0}catch(e){return process.stdout.write(`${JSON.stringify({ts:o(),type:`error`,code:`stream_failed`,message:e.message})}\n`),1}}const U=({api:e,opts:t,predicate:n,forwardSecret:r,scrollbackPath:a,onExit:u})=>{let{exit:f}=v(),p=S([]),_=S(null),[w,T]=C([]),[E,D]=C(null),[O,k]=C(!1),[A,j]=C(null);_.current||=new F(a),y(n=>{if(!O){if(E){D(null);return}if(n===`q`){f(),u(0);return}if(n===`f`){let e=p.current[p.current.length-1];e&&D(e);return}if(n===`w`){k(!0);return}if(n===`r`){G(e,t.siteId,p,j);return}}}),x(()=>{let e=setInterval(()=>{let e=p.current.slice(-100);T(e)},L);return()=>clearInterval(e)},[]),x(()=>{let a=new AbortController,o=!1;return(async()=>{t.replay24h&&await G(e,t.siteId,p,j);try{let s=await e.openEventsStream(t.siteId,a.signal);for await(let e of i(s)){if(o)break;if(e.type===`error`){let t={raw:`[ERR ${e.code}] ${e.message}`};W(p,t),_.current?.append(t.raw);continue}if(e.type===`done`)break;let i=e;if(n&&!n(i))continue;let a=B(e);W(p,a),_.current?.append(a.raw),t.forwardTo&&r&&V(t.forwardTo,r,{event:e,ts:new Date().toISOString(),site_id:t.siteId})}}catch(e){let t={raw:`[DISCONNECT] ${e.message}`};W(p,t)}})(),()=>{o=!0,a.abort(),_.current?.close()}},[e,t.siteId,t.replay24h,t.forwardTo,n,r]);let M=async e=>{let t=e.trim()||`events.ndjson`;try{let e=p.current.map(e=>e.raw).join(`
4
- `)+`
5
- `;await d.writeFile(t,e,{mode:384}),j(`Wrote ${p.current.length} events → ${t}`)}catch(e){j(`Write failed: ${e.message}`)}k(!1)};return b.createElement(m,{flexDirection:`column`},b.createElement(s,{version:t.cliVersion,subtitle:`events tail · ${t.siteId}`}),b.createElement(h,{items:w},(e,t)=>b.createElement(g,{key:`v-${t}`,color:e.marker?`cyan`:void 0},e.raw)),E?b.createElement(o,{title:`Frozen event (press any key to resume)`,state:`warn`},b.createElement(g,null,E.parsed?JSON.stringify(E.parsed,null,2):E.raw)):null,O?b.createElement(o,{title:`Write buffer to NDJSON`,state:`busy`},b.createElement(c,{question:`filename:`,placeholder:`events.ndjson`,onSubmit:M})):null,A?b.createElement(g,{color:`green`},A):null,b.createElement(l,{items:[{key:`f`,label:`freeze`},{key:`w`,label:`write`},{key:`r`,label:`replay 24h`},{key:`q`,label:`quit`}]}))};function W(e,t){e.current.push(t),e.current.length>I&&e.current.splice(0,e.current.length-I)}async function G(e,t,n,r){let i=e.getEventsHistory;if(typeof i==`function`)try{let a=await i.call(e,t,`24h`);if(Array.isArray(a))for(let e of a)W(n,{raw:JSON.stringify(e),parsed:e});W(n,{raw:R,marker:!0}),r(`Replayed ${Array.isArray(a)?a.length:0} events`);return}catch(e){r(`Replay failed: ${e.message}`);return}r(`Replay endpoint coming Wave 1`)}export{z as eventsTailCommand};
@@ -1,4 +0,0 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import"./api-FCanTxsb.js";import{readToken as t}from"./token-store-BQuGH0z2.js";import{emitErrorEnvelope as n}from"./error-codes-C5caZH9p.js";import{ApiV2Client as r}from"./api-v2-CI5hxW-O.js";import{requireTier as i}from"./tier-BneaO4vD.js";import"./formatter-DutfcQAc.js";import{emitEnvelope as a,wrapItem as o}from"./emit-DBYk96TD.js";import"./panel-B_yDcIcn.js";import"./banner-3iSWTDFy.js";import"./prompt-D-Uzz_GF.js";import{resolveSiteId as s}from"./resolve-site-mj0esTrm.js";import{toCsv as c}from"./csv-emit-Dn3c0RCG.js";import{resolve as l}from"node:path";import{writeFile as u}from"node:fs/promises";function d(e){let t=(e??`30d`).toLowerCase();return t===`7d`||t===`30d`||t===`90d`?t:`30d`}function f(e,t){t||process.stderr.isTTY&&process.stderr.write(`${e}\n`)}async function p(c){let p=await e(),g=await t({strict:!1}),_=new r({config:p,cliVersion:c.cliVersion,token:g});if(c.type!==`analytics`&&c.type!==`sessions`&&c.type!==`heatmaps`){let e=`Unknown export type '${c.type}'. Use one of: analytics, sessions, heatmaps.`;return c.json?n(Error(e),{command:`export`,cliVersion:c.cliVersion}):(process.stderr.write(`Error: ${e}\n`),2)}let v=c.format===`json`?`json`:`csv`,y=d(c.range),b=!!c.json;if(c.type===`sessions`||c.type===`heatmaps`)try{await i(_,`pro`)}catch(e){return c.json?n(e,{command:`export ${c.type}`,cliVersion:c.cliVersion}):(process.stderr.write(`${e.message}\n`),2)}let x;try{({siteId:x}=await s(_,{explicit:c.siteId,headless:b,cliVersion:c.cliVersion}))}catch(e){return c.json?n(e,{command:`export ${c.type}`,cliVersion:c.cliVersion}):(process.stderr.write(`${e.message}\n`),2)}try{f(`→ Fetching ${c.type} ${y}...`,b);let{rows:e,columns:t}=await m(_,c.type,x,y),n=h(e,t,v),r=c.out?l(process.cwd(),c.out):null;return r?(await u(r,n,`utf8`),c.json?(a(o({rowsWritten:e.length,file:r,format:v,range:y,type:c.type},`export.completed`,{siteId:x,command:`export ${c.type}`,cliVersion:c.cliVersion})),0):(process.stdout.write(`✓ Exported ${e.length} rows to ${r}\n`),0)):(process.stdout.write(n),n.endsWith(`
2
- `)||process.stdout.write(`
3
- `),c.json&&a(o({rowsWritten:e.length,file:null,format:v,range:y,type:c.type},`export.completed`,{siteId:x,command:`export ${c.type}`,cliVersion:c.cliVersion})),0)}catch(e){return c.json?n(e,{command:`export ${c.type}`,cliVersion:c.cliVersion}):(process.stderr.write(`✗ ${e.message}\n`),1)}}async function m(e,t,n,r){if(t===`analytics`){let t=await e.getStats(n,r);if(t.daily&&t.daily.length>0){let e=t.daily.map(e=>({date:e.date,visitors:e.visitors,pageviews:e.pageviews}));return{rows:e,columns:[`date`,`visitors`,`pageviews`]}}let i=[{range:r,visitors:t.visitors,pageviews:t.pageviews,sessions:t.sessions,bounceRate:t.bounceRate,avgSessionSec:t.avgSessionSec,windowStart:t.windowStart,windowEnd:t.windowEnd}];return{rows:i,columns:[`range`,`visitors`,`pageviews`,`sessions`,`bounceRate`,`avgSessionSec`,`windowStart`,`windowEnd`]}}if(t===`sessions`){let t=await e.getSessions(n),r=t.map(e=>({id:e.id,visitor:e.visitor,durationMs:e.duration,startedAt:e.startedAt,pageCount:e.pageCount,deviceType:e.deviceType??``}));return{rows:r,columns:[`id`,`visitor`,`durationMs`,`startedAt`,`pageCount`,`deviceType`]}}let i=await e.getHeatmaps(n),a=i.map(e=>({id:e.id,url:e.url,type:e.type,captureCount:e.captureCount,createdAt:e.createdAt}));return{rows:a,columns:[`id`,`url`,`type`,`captureCount`,`createdAt`]}}function h(e,t,n){if(n===`json`){let n=e.map(e=>{let n={};for(let r of t)n[String(r)]=e[r];return n});return JSON.stringify(n,null,2)+`
4
- `}return c(e,t,`csv`)}export{p as exportCommand};
@@ -1,3 +0,0 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import"./api-FCanTxsb.js";import{readToken as t}from"./token-store-BQuGH0z2.js";import"./telemetry-DRh10SvO.js";import{ApiV2Client as n}from"./api-v2-CI5hxW-O.js";import"./client-DTXWADkX.js";import{formatTabular as r,selectFormat as i}from"./formatter-DutfcQAc.js";import"./panel-B_yDcIcn.js";import"./banner-3iSWTDFy.js";import"./prompt-D-Uzz_GF.js";import"./keybar-DsYTkKZX.js";import"./chat-panel-CqJaCIg3.js";import{resolveSiteId as a}from"./resolve-site-mj0esTrm.js";import{DataTable as o}from"./data-table-BpbyyNSA.js";import{deepLinkFor as s,openInBrowser as c}from"./keybar-deep-link-DC31T3CP.js";import{runAnalyticalScreen as l}from"./analytical-screen-BasvNR-9.js";import{Box as u,Text as d}from"ink";import f from"react";function p(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 m(m){let g=await e(),_=await t({strict:!1}),v=new n({config:g,cliVersion:m.cliVersion,token:_}),y,b;try{({siteId:y,site:b}=await a(v,{explicit:m.siteId,headless:!!(m.json||m.csv||m.tsv||m.ndjson),cliVersion:m.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let x=i(m);if(!m.funnelId){let e=[{key:`name`,label:`name`,width:30},{key:`stepCount`,label:`steps`,width:6,align:`right`},{key:`id`,label:`id`,width:36,format:e=>String(e).slice(0,36)}];return l({cliVersion:m.cliVersion,title:`funnels · ${y}`,commandName:`funnels`,ai:{api:v,siteId:y,siteLabel:b?.url?b.url.replace(/^https?:\/\//,``).replace(/\/$/,``):b?.name??y},authToken:_?.accessToken??null,refreshIntervalMs:0,fetcher:e=>v.listFunnels(y,e),format:x,keybindings:{o:{label:`open in browser`,handler:()=>{c(s(`funnel`,{siteId:y}))}}},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(r(e.funnels,[`id`,`name`,`stepCount`],t))},panels:[{id:`funnels`,title:`Funnels`,render:t=>t.funnels.length===0?f.createElement(d,{color:`gray`},`— no funnels defined —`):f.createElement(o,{data:t.funnels,columns:e,headerStyle:`accent`})},{id:`hint`,title:`Next`,render:()=>f.createElement(d,{color:`gray`},"Run `zenovay funnel <id>` for drop-off detail.")}]})}let S=m.window??`30d`;return l({cliVersion:m.cliVersion,title:`funnel · ${m.funnelId} · ${S}`,commandName:`funnel`,ai:{api:v,siteId:y,siteLabel:b?.url?b.url.replace(/^https?:\/\//,``).replace(/\/$/,``):b?.name??y},authToken:_?.accessToken??null,refreshIntervalMs:0,fetcher:e=>v.getFunnel(y,m.funnelId,S,e),format:x,keybindings:{o:{label:`open in browser`,handler:()=>{c(s(`funnel`,{siteId:y}))}}},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(r(e.steps,[`id`,`name`,`visitors`,`conversions`],t))},panels:[{id:`overview`,title:h(`Overview`),render:e=>f.createElement(u,{flexDirection:`column`},f.createElement(d,{bold:!0},e.name),f.createElement(d,{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 f.createElement(u,{flexDirection:`column`},e.steps.map((n,r)=>{let i=n.visitors/t,a=e.steps[r-1],o=a?a.visitors-n.visitors:0,s=a?o/Math.max(1,a.visitors)*100:0;return f.createElement(u,{key:n.id,flexDirection:`column`},a?f.createElement(d,{color:`red`},` `,`↓ drop `,o.toLocaleString(),` (`,s.toFixed(1),`%)`):null,f.createElement(d,null,f.createElement(d,{bold:!0},`${r+1}. ${n.name}`.padEnd(22).slice(0,22)),` `,f.createElement(d,{color:`magenta`},p(i,30)),` `,f.createElement(d,null,(i*100).toFixed(1).padStart(5),`% `),f.createElement(d,{color:`gray`},n.visitors.toLocaleString())))}))}}]})}function h(e){return e}export{m as funnelCommand};
@@ -1,2 +0,0 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import"./api-FCanTxsb.js";import{readToken as t}from"./token-store-BQuGH0z2.js";import{ApiV2Client as n}from"./api-v2-CI5hxW-O.js";import"./formatter-DutfcQAc.js";import{emit$1 as r,isHeadless as i}from"./emit-DBYk96TD.js";import{Panel as a}from"./panel-B_yDcIcn.js";import{Banner as o}from"./banner-3iSWTDFy.js";import"./prompt-D-Uzz_GF.js";import{Keybar as s}from"./keybar-DsYTkKZX.js";import{resolveSiteId as c}from"./resolve-site-mj0esTrm.js";import{DataTable as l}from"./data-table-BpbyyNSA.js";import{EmptyState as u}from"./empty-state-CJxa1jUN.js";import{deepLinkFor as d,openInBrowser as f}from"./keybar-deep-link-DC31T3CP.js";import{Box as p,Text as m,render as h,useApp as g,useInput as _}from"ink";import v,{useEffect as y,useState as b}from"react";import x from"ink-spinner";async function S(a){let o=await e(),s=await t({strict:!1});if(!s)return process.stderr.write("Not logged in — run `zenovay login` first.\n"),2;let l=new n({config:o,cliVersion:a.cliVersion,token:s}),u,d;try{({siteId:u,site:d}=await c(l,{explicit:a.siteId,headless:!!a.json,cliVersion:a.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let f=d?.url?d.url.replace(/^https?:\/\//,``).replace(/\/$/,``):d?.name??u;if(i(a)){let e=await l.getGeo(u);if(a.csv||a.tsv){let{writeCsv:t}=await import(`./csv-emit-BuRZNWYM.js`);return t(e.countries,[`country`,`visitors`],a.tsv?`tsv`:`csv`)}if(a.ndjson){for(let t of e.countries)process.stdout.write(JSON.stringify(t)+`
2
- `);return 0}return r({type:`geo.snapshot`,data:e}),0}return new Promise(e=>{let{unmount:t}=h(v.createElement(C,{api:l,siteId:u,siteLabel:f,cliVersion:a.cliVersion,onExit:n=>{t(),e(n)}}))})}const C=({api:e,siteId:t,siteLabel:n,cliVersion:r,onExit:i})=>{let{exit:c}=g(),[h,S]=b(null),[C,w]=b(!0),[T,E]=b(null);if(_(e=>{if(e===`o`||e===`O`){f(d(`geo`,{siteId:t}));return}e===`q`&&(c(),i(0))}),y(()=>{let n=!1;return(async()=>{try{let r=await e.getGeo(t);n||(S(r),w(!1))}catch(e){n||(E(e.message),w(!1))}})(),()=>{n=!0}},[e,t]),C)return v.createElement(p,{flexDirection:`column`},v.createElement(o,{version:r,subtitle:`geo · ${n}`}),v.createElement(a,{title:`Loading`,state:`busy`},v.createElement(p,null,v.createElement(m,{color:`magenta`},v.createElement(x,{type:`dots`})),v.createElement(m,null,` Fetching geo…`))));if(T)return v.createElement(p,{flexDirection:`column`},v.createElement(o,{version:r,subtitle:`geo · ${n}`}),v.createElement(u,{reason:`error`,headline:`Failed to load`,hint:T}));let D=!h||h.countries.length===0&&h.cities.length===0;if(D)return v.createElement(p,{flexDirection:`column`},v.createElement(o,{version:r,subtitle:`geo · ${n}`}),v.createElement(u,{reason:`no-data`,headline:`No data yet`,hint:`Visit your site to send the first event`}));let O=[{key:`country`,label:`country`,width:18},{key:`visitors`,label:`visitors`,align:`right`,width:8}],k=[{key:`city`,label:`city`,width:20},{key:`country`,label:`country`,width:12},{key:`visitors`,label:`visitors`,align:`right`,width:8}],A=process.stdout.columns??80;return v.createElement(p,{flexDirection:`column`},v.createElement(o,{version:r,subtitle:`geo · ${n}`}),v.createElement(a,{title:`Countries`},h.countries.length===0?v.createElement(m,{color:`gray`},`— —`):v.createElement(l,{columns:O,data:h.countries.slice(0,15),zebra:!0})),v.createElement(a,{title:`Cities`},h.cities.length===0?v.createElement(m,{color:`gray`},`— —`):v.createElement(l,{columns:k,data:h.cities.slice(0,20),zebra:!0})),v.createElement(s,{items:[{key:`o`,label:`open in browser`},{key:`q`,label:`quit`}]}))};export{S as geoCommand};
@@ -1 +0,0 @@
1
- import"./config--JRu_jFq.js";import"./check-D9G0N7NB.js";import"./api-FCanTxsb.js";import"./token-store-BQuGH0z2.js";import"./formatter-DutfcQAc.js";import"./emit-DBYk96TD.js";import"./panel-B_yDcIcn.js";import{HealthReport as e,exitCodeFor as t,healthCommand as n,runHealthChecks as r}from"./health-BttlLZWZ.js";export{n as healthCommand};
@@ -1,2 +0,0 @@
1
- import{configPath as e,readConfig as t}from"./config--JRu_jFq.js";import{fetchManifest as n}from"./check-D9G0N7NB.js";import{ApiClient as r}from"./api-FCanTxsb.js";import{readToken as i}from"./token-store-BQuGH0z2.js";import{isHeadless as a}from"./emit-DBYk96TD.js";import{Panel as o}from"./panel-B_yDcIcn.js";import{spawnSync as s}from"node:child_process";import c from"node:path";import{existsSync as l,promises as u,statSync as d}from"node:fs";import f from"node:os";import{Box as p,Text as m,render as h}from"ink";import g from"react";const _=6*60*60*1e3;function v(){return c.join(f.homedir(),`.zenovay`,`update.json`)}async function y(){try{let e=await u.readFile(v(),`utf8`);return JSON.parse(e)}catch{return null}}async function b(e){let t=v();await u.mkdir(c.dirname(t),{recursive:!0,mode:448}),await u.writeFile(t,JSON.stringify(e,null,2))}async function x(){let e=await t();if(e.noUpdateCheck||process.env.ZENOVAY_NO_UPDATE_CHECK===`1`||process.env.CI===`true`)return null;let r=await y();if(r&&Date.now()-r.fetchedAt<_)return r;try{let t=await n({cliBase:e.cliBase}),i={manifest:t,fetchedAt:Date.now(),lastNoticeAt:r?.lastNoticeAt};return await b(i),i}catch{return r}}async function S(){try{await x()}catch{}process.exit(0)}process.env.ZENOVAY_UPDATE_WORKER_FORK===`1`&&S();function C(e){return e.includes(`/Cellar/`)||e.includes(`/opt/homebrew/`)||e.includes(`/usr/local/Cellar/`)?`brew`:e.includes(`.npm-global`)||e.includes(`node_modules/.bin`)||e.includes(`npm/bin`)?`npm-global`:e.endsWith(`/.local/bin/zenovay`)||e.endsWith(`\\.local\\bin\\zenovay.exe`)?`curl-installer`:e.includes(`/lib/node_modules/`)||e.includes(`\\nodejs\\`)?`npm-prefix`:`unknown`}function w(e){let t=process.platform===`win32`,n=t?`where`:`which`,r=t?[e]:[`-a`,e];try{let e=s(n,r,{encoding:`utf8`,timeout:3e3});if(e.status!==0||!e.stdout)return[];let t=e.stdout.split(/\r?\n/).map(e=>e.trim()).filter(Boolean);return[...new Set(t)]}catch{return[]}}function T(e){let t=process.platform===`win32`,n=t?`;`:`:`,r=(process.env.PATH??``).split(n).filter(Boolean),i=t?[`.exe`,`.cmd`,``]:[``],a=[];for(let t of r)for(let n of i){let r=c.join(t,e+n);if(l(r))try{let e=d(r);e.isFile()&&a.push(r)}catch{}}return[...new Set(a)]}function E(e=`zenovay`){let t=w(e);t.length===0&&(t=T(e));let n=t.map(e=>({path:e,kind:C(e)})),r=t[0]??null;return{paths:t,active:r,kinds:n}}function D(e,t){if(e.paths.length<2)return``;let n=[];n.push(`Multiple zenovay binaries detected on PATH:`);for(let r of e.kinds){let i=r.path===e.active,a=t&&r.path===t,o=[i&&`(first on PATH)`,a&&`(currently running)`].filter(Boolean).join(` `);n.push(` • ${r.path} [${r.kind}] ${o}`)}n.push(``),n.push(`Pick one and uninstall the others to avoid version drift:`);let r=new Set(e.kinds.map(e=>e.kind));return r.has(`npm-global`)&&n.push(` npm uninstall -g @zenovay/cli # remove the npm-installed one`),r.has(`brew`)&&n.push(` brew uninstall zenovay # remove the Homebrew-installed one`),r.has(`curl-installer`)&&n.push(` rm ~/.local/bin/zenovay # remove the curl-installer one`),n.join(`
2
- `)}const O=2e3,k=5e3;async function A(e,t){let n=`${e}/mcp`,r=Date.now(),i=new AbortController,a=setTimeout(()=>i.abort(),O);try{let a=await t(n,{method:`GET`,signal:i.signal}),o=Date.now()-r;return a.ok?{name:`MCP server`,status:`pass`,detail:`${e}/mcp · ${o}ms`,latencyMs:o}:{name:`MCP server`,status:`fail`,detail:`HTTP ${a.status}`,latencyMs:o}}catch(e){return{name:`MCP server`,status:`fail`,detail:e.message}}finally{clearTimeout(a)}}async function j(){try{let t=await u.readFile(e(),`utf8`),n=JSON.parse(t),r=n.openaiApiKey;return typeof r==`string`&&r.trim().length>0?{name:`OpenAI key`,status:`pass`,detail:`configured`}:{name:`OpenAI key`,status:`warn`,detail:"not set (run `zenovay ai` to configure)"}}catch(e){return e.code===`ENOENT`?{name:`OpenAI key`,status:`warn`,detail:`no config file`}:{name:`OpenAI key`,status:`warn`,detail:`unreadable config`}}}async function M(){let e=f.homedir(),t=[c.join(e,`.zshrc`),c.join(e,`.bashrc`),c.join(e,`.config`,`fish`,`completions`,`zenovay.fish`)],n=[];for(let e of t)try{let t=await u.readFile(e,`utf8`);(/zenovay\s+(complet|--?complet)/i.test(t)||/_zenovay/.test(t)||/complete\s+-c\s+zenovay/.test(t))&&n.push(c.basename(e))}catch{}return n.length>0?{name:`Completions`,status:`pass`,detail:n.join(`, `)}:{name:`Completions`,status:`warn`,detail:"not installed (run `zenovay completions` after Wave 3)"}}async function N(e,t,n,r){if(!e||!t)return{name:`Events stream`,status:`skip`,detail:`not authenticated`};let i=new AbortController,a=setTimeout(()=>i.abort(),k),o=Date.now();try{let t=await e.openEventsStream(`probe`,i.signal),r=t.body?.getReader();if(r){let e=Promise.race([r.read().then(()=>`first`),new Promise(e=>setTimeout(()=>e(`timeout`),1500))]);await e;try{r.cancel()}catch{}}let a=Date.now()-o;return{name:`Events stream`,status:`pass`,detail:`${n}/v1/cli/events/tail · ${a}ms`,latencyMs:a}}catch(e){let t=e.message;return/40\d/.test(t)?{name:`Events stream`,status:`pass`,detail:`endpoint reachable (auth-gated)`}:{name:`Events stream`,status:`fail`,detail:t}}finally{clearTimeout(a)}}async function P(n){let a=n.fetchImpl??fetch,o=[],s=await t().catch(()=>null);o.push({name:`Binary`,status:`pass`,detail:`v${n.cliVersion} (${n.binaryPath})`});let c=E(`zenovay`);if(c.paths.length>=2){let e=c.kinds.map(e=>e.kind).join(` + `);o.push({name:`Install paths`,status:`warn`,detail:`${c.paths.length} binaries on PATH (${e}). Active: ${c.active}. Run \`zenovay doctor\` for cleanup.`})}else o.push({name:`Install paths`,status:`pass`,detail:c.active??`no zenovay on PATH`});o.push({name:`Config file`,status:s?`pass`:`warn`,detail:e()});let l=await i({strict:!1}).catch(()=>null);o.push({name:`Auth`,status:l?`pass`:`fail`,detail:l?`logged in${l.email?` as ${l.email}`:``}`:`not logged in`});let u=null;if(s)try{u=new r({config:s,cliVersion:n.cliVersion,token:l,fetchImpl:a});let e=await u.ping();o.push({name:`API connection`,status:`pass`,detail:`${s.apiBase.replace(/^https?:\/\//,``)} · ${e.latencyMs}ms`,latencyMs:e.latencyMs})}catch(e){o.push({name:`API connection`,status:`fail`,detail:`${e.message}`})}let d=await y().catch(()=>null);o.push({name:`Auto-update`,status:s?.noUpdateCheck?`warn`:`pass`,detail:s?.noUpdateCheck?`disabled`:d?`latest=${d.manifest.latest}`:`manifest not yet fetched`});let f=s?.apiBase??`https://api.zenovay.com`;return o.push(await A(f,a)),o.push(await j()),o.push(await M()),o.push(await N(u,!!l,f,a)),o}function F(e){return e.some(e=>e.status===`fail`)?1:0}async function I(e){let t=await P(e),n=F(t),r=n===0;return a({json:e.json})?(process.stdout.write(`${JSON.stringify({checks:t,passed:r})}\n`),n):new Promise(e=>{let{unmount:r}=h(g.createElement(L,{checks:t}),{exitOnCtrlC:!0});setImmediate(()=>{r(),e(n)})})}const L=({checks:e})=>g.createElement(o,{title:`Zenovay CLI health check`,state:`idle`},e.map(e=>g.createElement(p,{key:e.name},g.createElement(m,{color:z(e.status)},R(e.status)),g.createElement(m,null,` `),g.createElement(m,{bold:!0},e.name.padEnd(18)),g.createElement(m,{color:`gray`},e.detail))));function R(e){return e===`pass`?`✔`:e===`warn`?`⚠`:e===`skip`?`∼`:`✗`}function z(e){return e===`pass`?`green`:e===`warn`?`yellow`:e===`skip`?`gray`:`red`}export{L as HealthReport,E as detectInstallPaths,F as exitCodeFor,I as healthCommand,D as remediationHint,P as runHealthChecks};
@@ -1 +0,0 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import"./api-FCanTxsb.js";import{readToken as t}from"./token-store-BQuGH0z2.js";import{ApiV2Client as n}from"./api-v2-CI5hxW-O.js";import{requireTier as r}from"./tier-BneaO4vD.js";import"./formatter-DutfcQAc.js";import{emit$1 as i,isHeadless as a}from"./emit-DBYk96TD.js";import{Panel as o}from"./panel-B_yDcIcn.js";import{Banner as s}from"./banner-3iSWTDFy.js";import"./prompt-D-Uzz_GF.js";import{Keybar as c}from"./keybar-DsYTkKZX.js";import{resolveSiteId as l}from"./resolve-site-mj0esTrm.js";import{DataTable as u}from"./data-table-BpbyyNSA.js";import{EmptyState as d}from"./empty-state-CJxa1jUN.js";import{deepLinkFor as f,openInBrowser as p}from"./keybar-deep-link-DC31T3CP.js";import{Box as m,Text as h,render as g,useApp as _,useInput as v}from"ink";import y,{useEffect as b,useState as x}from"react";import S from"ink-spinner";async function C(o){let s=await e(),c=await t({strict:!1});if(!c)return process.stderr.write("Not logged in — run `zenovay login` first.\n"),2;let u=new n({config:s,cliVersion:o.cliVersion,token:c});try{await r(u,`pro`)}catch(e){return process.stderr.write(`${e.message}\n`),2}let d,f;try{({siteId:d,site:f}=await l(u,{explicit:o.siteId,headless:!!o.json,cliVersion:o.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let p=f?.url?f.url.replace(/^https?:\/\//,``).replace(/\/$/,``):f?.name??d;if(a(o)){let e=await u.getHeatmaps(d);return i({type:`heatmaps.snapshot`,data:e}),0}return new Promise(e=>{let{unmount:t}=g(y.createElement(w,{api:u,siteId:d,siteLabel:p,cliVersion:o.cliVersion,onExit:n=>{t(),e(n)}}))})}const w=({api:e,siteId:t,siteLabel:n,cliVersion:r,onExit:i})=>{let{exit:a}=_(),[l,g]=x(null),[C,w]=x(!0),[T,E]=x(null);if(v(e=>{if(e===`o`||e===`O`){p(f(`heatmaps`,{siteId:t}));return}e===`q`&&(a(),i(0))}),b(()=>{let n=!1;return(async()=>{try{let r=await e.getHeatmaps(t);n||(g(r),w(!1))}catch(e){n||(E(e.message),w(!1))}})(),()=>{n=!0}},[e,t]),C)return y.createElement(m,{flexDirection:`column`},y.createElement(s,{version:r,subtitle:`heatmaps · ${n}`}),y.createElement(o,{title:`Loading`,state:`busy`},y.createElement(m,null,y.createElement(h,{color:`magenta`},y.createElement(S,{type:`dots`})),y.createElement(h,null,` Fetching heatmaps…`))));if(T)return y.createElement(m,{flexDirection:`column`},y.createElement(s,{version:r,subtitle:`heatmaps · ${n}`}),y.createElement(d,{reason:`error`,headline:`Failed to load`,hint:T}));if(!l||l.length===0)return y.createElement(m,{flexDirection:`column`},y.createElement(s,{version:r,subtitle:`heatmaps · ${n}`}),y.createElement(d,{reason:`no-data`,headline:`No heatmaps yet`,hint:`Enable heatmaps in your site settings`}));let D=[{key:`url`,label:`page`,width:36},{key:`type`,label:`type`,width:12},{key:`captureCount`,label:`captures`,align:`right`,width:10},{key:`createdAt`,label:`first seen`,width:24}];return y.createElement(m,{flexDirection:`column`},y.createElement(s,{version:r,subtitle:`heatmaps · ${n}`}),y.createElement(o,{title:`Heatmaps (${l.length})`},y.createElement(u,{columns:D,data:l,zebra:!0})),y.createElement(m,{marginTop:1},y.createElement(h,{color:`gray`},`Open any heatmap at https://app.zenovay.com/heatmaps`)),y.createElement(c,{items:[{key:`o`,label:`open in browser`},{key:`q`,label:`quit`}]}))};export{C as heatmapsCommand};
@@ -1,2 +0,0 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import"./api-FCanTxsb.js";import{readToken as t}from"./token-store-BQuGH0z2.js";import{ApiV2Client as n}from"./api-v2-CI5hxW-O.js";import"./formatter-DutfcQAc.js";import{isHeadless as r}from"./emit-DBYk96TD.js";import{Panel as i}from"./panel-B_yDcIcn.js";import{Banner as a}from"./banner-3iSWTDFy.js";import{Keybar as o}from"./keybar-DsYTkKZX.js";import{DataTable as s}from"./data-table-BpbyyNSA.js";import{EmptyState as c}from"./empty-state-CJxa1jUN.js";import{Box as l,Text as u,render as d,useApp as f,useInput as p}from"ink";import m,{useEffect as h,useState as g}from"react";import _ from"ink-spinner";function v(e){if(!e)return`—`;let t=new Date(e);return Number.isNaN(t.getTime())?`—`:t.toISOString().slice(0,10)}async function y(e){let t=await e.me().catch(()=>null),n=t?.user.name?.trim()||t?.user.email||`you`,r=await e.getSites().catch(()=>[]),i=r.map(e=>({id:e.id,name:e.name,domain:e.url.replace(/^https?:\/\//,``).replace(/\/$/,``),lastActive:e.lastActiveAt??null})),a={visitors:0,pageviews:0,deltaPct:null};if(r.length>0){let t=r[0].id,[n,i]=await Promise.all([e.getStats(t,`7d`).catch(()=>null),e.getSources(t,`7d`,`prev`).catch(()=>null)]);n&&(a.visitors=n.visitors,a.pageviews=n.pageviews);let o=i?.sources?.filter(e=>typeof e.delta==`number`)??[];if(o.length>0){let e=o.reduce((e,t)=>e+(t.delta??0),0);a.deltaPct=e/o.length*100}}return{sites:i,weekly:a,userLabel:n}}async function b(i){let a=await e(),o=await t({strict:!1});if(!o)return process.stderr.write("Not logged in — run `zenovay login` first.\n"),2;let s=new n({config:a,cliVersion:i.cliVersion,token:o});if(r(i))try{let e=await y(s);return process.stdout.write(JSON.stringify({sites:e.sites,weekly:{visitors:e.weekly.visitors,pageviews:e.weekly.pageviews,deltaPct:e.weekly.deltaPct}},null,2)+`
2
- `),0}catch(e){return process.stderr.write(`✗ ${e.message}\n`),1}return new Promise(e=>{let{unmount:t}=d(m.createElement(x,{api:s,cliVersion:i.cliVersion,onExit:n=>{t(),e(n)}}))})}const x=({api:e,cliVersion:t,onExit:n})=>{let{exit:r}=f(),[d,b]=g(null),[x,S]=g(!0),[C,w]=g(null);p(e=>{e===`q`&&(r(),n(0))}),h(()=>{let t=!1;return(async()=>{try{let n=await y(e);t||(b(n),S(!1))}catch(e){t||(w(e.message),S(!1))}})(),()=>{t=!0}},[e]);let T=`home · ${d?.userLabel??`…`}`,E=[{key:`q`,label:`quit`}];if(x)return m.createElement(l,{flexDirection:`column`},m.createElement(a,{version:t,subtitle:T}),m.createElement(i,{title:`Loading`,state:`busy`},m.createElement(l,null,m.createElement(u,{color:`cyan`},m.createElement(_,{type:`dots`})),m.createElement(u,null,` Fetching your home dashboard…`))));if(C)return m.createElement(l,{flexDirection:`column`},m.createElement(a,{version:t,subtitle:T}),m.createElement(c,{reason:`error`,headline:`Failed to load`,hint:C}),m.createElement(o,{items:E}));if(!d)return m.createElement(l,{flexDirection:`column`},m.createElement(a,{version:t,subtitle:T}),m.createElement(c,{reason:`no-data`,headline:`No data`}),m.createElement(o,{items:E}));let D=[{key:`name`,label:`site`,width:24},{key:`domain`,label:`domain`,width:32},{key:`lastActive`,label:`last active`,width:12,format:e=>v(e)}],O=d.weekly.deltaPct===null?`—`:`${d.weekly.deltaPct>=0?`+`:``}${d.weekly.deltaPct.toFixed(1)}%`;return m.createElement(l,{flexDirection:`column`},m.createElement(a,{version:t,subtitle:T}),m.createElement(i,{title:`Your sites (${d.sites.length})`},d.sites.length===0?m.createElement(u,{color:`gray`},"No sites yet — run `zenovay init` to add one."):m.createElement(s,{columns:D,data:d.sites,zebra:!0})),m.createElement(i,{title:`This week`},m.createElement(u,null,m.createElement(u,{color:`cyan`},`Visitors`),` `,d.weekly.visitors.toLocaleString(),` `,m.createElement(u,{color:`cyan`},`Pageviews`),` `,d.weekly.pageviews.toLocaleString(),` `,m.createElement(u,{color:`cyan`},`Δ vs last week`),` `,O)),m.createElement(o,{items:E}))};export{b as homeCommand};
@@ -1,79 +0,0 @@
1
- import{readConfig as e,updateConfig as t}from"./config--JRu_jFq.js";import{ApiClient as n}from"./api-FCanTxsb.js";import{readToken as r}from"./token-store-BQuGH0z2.js";import{parseSseStream as i}from"./client-DTXWADkX.js";import{emit$1 as a,isHeadless as o}from"./emit-DBYk96TD.js";import{scrubSecrets as s}from"./secrets-ApB7yh2A.js";import{loginCommand as c}from"./login-yhuXiFqh.js";import{Panel as l}from"./panel-B_yDcIcn.js";import{Banner as u}from"./banner-3iSWTDFy.js";import{BrandGradient as d,ProgressRow as f}from"./progress-row-BpAXjJPL.js";import{Select as p}from"./prompt-D-Uzz_GF.js";import{Keybar as m}from"./keybar-DsYTkKZX.js";import{spark as h}from"./sparkline-BZ0eMB-w.js";import g from"node:path";import{promises as _}from"node:fs";import{z as v}from"zod";import y from"node:os";import b from"node:crypto";import{ulid as x}from"ulid";import{Box as S,Text as C,render as w,useApp as ee,useInput as T}from"ink";import E,{useEffect as D,useRef as O,useState as k}from"react";import{globby as A}from"globby";import j from"ink-spinner";import{applyPatch as M}from"diff";const N=[`@zenovay/tracker`,`@zenovay/next`,`@zenovay/nuxt`,`@zenovay/svelte`,`@zenovay/astro`,`@zenovay/remix`,`@zenovay/node`],P=[`zenovay.config.ts`,`zenovay.config.js`,`zenovay.config.mjs`,`zenovay.config.json`],F=/<script[^>]*src\s*=\s*["']https:\/\/(?:api|cdn)\.zenovay\.com\/[^"']+["'][^>]*>\s*<\/script>/gi,te=/data-id\s*=\s*["'](ZV_[A-Za-z0-9]+)["']/i,I=/data-zenovay-site\s*=\s*["']([^"']+)["']/i,ne=[{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 re(e,t){let n={zenovayInstalled:!1,correctTrackingCode:!1,foundTrackingCodes:[],zenovayFiles:[],competitors:[],summary:``,recommendation:`fresh-install`};try{let t=await _.readFile(g.join(e,`package.json`),`utf8`),r=JSON.parse(t),i={...r.dependencies,...r.devDependencies};for(let e of N)if(e in i){n.zenovayInstalled=!0,n.packageMarker=e;break}}catch{}for(let t of P)try{await _.access(g.join(e,t)),n.zenovayInstalled=!0,n.configFile=t;break}catch{}let r=await A([`**/*.{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 _.readFile(t,`utf8`)}catch{continue}let o=g.relative(e,t),s=r.match(F);if(s&&s.length>0){n.zenovayInstalled=!0;let e=s[0].slice(0,200),t=e.match(te)??e.match(I),r=t?.[1]??null;r&&a.add(r),n.zenovayFiles.push({file:o,currentTrackingCode:r,scriptTagCount:s.length,matchSample:e})}for(let e of ne)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=ie(n,t),n}function ie(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 ae(e){let t=await re(e,``);return{installed:t.zenovayInstalled,reasons:t.summary?[t.summary]:[],packageMarker:t.packageMarker,configFile:t.configFile,scriptFile:t.zenovayFiles[0]?.file}}const oe=[/^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)$/],se=[/(^|\/)\.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??x(),this.cwd=e.cwd,this.cwdReal=_.realpath(e.cwd),this.undoRoot=e.undoRoot??g.join(y.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=g.isAbsolute(e)?e:g.join(n,e),i=g.normalize(r),a=i;try{a=await _.realpath(i)}catch(e){if(e.code!==`ENOENT`)throw new V(`escape`,`realpath failed: ${e.message}`);let t=g.dirname(i);try{let e=await _.realpath(t);a=g.join(e,g.basename(i))}catch{}}if(!this.isWithin(a,n))throw new V(`escape`,`Path escapes cwd: ${e}`);let o=g.relative(n,a);for(let e of se)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=oe.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=g.relative(t,e);return!n.startsWith(`..`)&&!g.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 _.stat(t);if(n.size>L)throw new V(`too-large`,`File exceeds ${L}B: ${e} (${n.size}B)`);let r=await _.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 _.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 _.mkdir(g.dirname(n),{recursive:!0}),await _.writeFile(n,t,`utf8`),this.writeCount++;let a=await this.cwdReal;return this.writtenPathsSet.add(g.relative(a,n)),{backupPath:i}}async journalBackup(e){let t=await _.readFile(e).catch(e=>{if(e.code===`ENOENT`)return null;throw e}),n=g.join(this.undoRoot,this.sessionId);await _.mkdir(n,{recursive:!0,mode:448});let r=b.createHash(`sha256`).update(e).digest(`hex`).slice(0,16),i=g.join(n,`${r}.bak`),a=g.join(n,`manifest.jsonl`);t&&await _.writeFile(i,t,{mode:384});let o=JSON.stringify({abs:e,backupPath:t?i:null,ts:Date.now()});return await _.appendFile(a,o+`
2
- `,{mode:384}),t?i:null}static wrapForModel(e,t){let n=b.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 s(e)}};const ce=[`astro.config.ts`,`astro.config.mjs`,`astro.config.js`];async function le(e){for(let t of ce)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 ue(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 de={id:`astro`,displayName:`Astro`,detect:le,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:ue},fe=[`app/layout.tsx`,`app/layout.ts`,`app/layout.jsx`,`app/layout.js`];async function pe(e){for(let t of fe)if(await e.exists(t))return t;return null}async function me(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 he(e){let t=await me(e),n=await e.exists(`app`),r=await pe(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 ge(e,t=`script`){let n=`app/layout.tsx`,r=e.trackingCode??e.siteId??``;return t===`npm`?ve(n,r):_e(n,r)}function _e(e,t){return[{targetPath:e,anchorKind:`after-imports`,code:`import Script from 'next/script';`,description:`Import next/script to inject the Zenovay tracker.`},{targetPath:e,anchorKind:`wrap-children`,code:`<Script
3
- defer
4
- data-id="${t}"
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.`}]}function ve(e,t){return[{targetPath:`components/zenovay-bootstrap.tsx`,anchorKind:`replace-file`,code:`'use client';
10
-
11
- import { useEffect } from 'react';
12
- import { init } from '@zenovay/tracker';
13
-
14
- /**
15
- * Mounts the Zenovay tracker exactly once on the client. Equivalent to the
16
- * canonical <script src="https://api.zenovay.com/z.js"> tag — init() injects
17
- * the same loader internally.
18
- */
19
- export function ZenovayBootstrap() {
20
- useEffect(() => {
21
- init('${t}', { allowLocalhost: true });
22
- }, []);
23
- return null;
24
- }
25
- `,description:`Create a client-component bootstrap that calls init() from @zenovay/tracker.`},{targetPath:e,anchorKind:`after-imports`,code:`import { ZenovayBootstrap } from '@/components/zenovay-bootstrap';`,description:`Import the Zenovay tracker bootstrap into the root layout.`},{targetPath:e,anchorKind:`wrap-children`,code:`<ZenovayBootstrap />
26
- {children}`,description:`Render the Zenovay tracker bootstrap alongside children in the root layout.`}]}const ye={id:`next-app-router`,displayName:`Next.js (App Router)`,detect:he,files:[{path:`app/layout.tsx`,kind:`mutate`,required:!0}],envVarName:`NEXT_PUBLIC_ZENOVAY_SITE`,packageDeps:[`@zenovay/tracker`],supportsNpmMode:!0,buildSnippets:ge},be=[`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 xe(e){for(let t of be)if(await e.exists(t))return t;return null}async function Se(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 Ce(e){let t=await Se(e);if(!t)return{matched:!1,confidence:0,reason:"package.json does not list `next` as a dependency."};let n=await xe(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 we(e){let t=`pages/_app.tsx`,n=e.trackingCode??e.siteId??``,r=`import type { AppProps } from 'next/app';
27
- import Script from 'next/script';
28
-
29
- export default function App({ Component, pageProps }: AppProps) {
30
- return (
31
- <>
32
- <Script
33
- defer
34
- data-id="${n}"
35
- data-allow-localhost="true"
36
- src="https://api.zenovay.com/z.js"
37
- strategy="afterInteractive"
38
- />
39
- <Component {...pageProps} />
40
- </>
41
- );
42
- }
43
- `;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 Te={id:`next-pages-router`,displayName:`Next.js (Pages Router)`,detect:Ce,files:[{path:`pages/_app.tsx`,kind:`mutate`,required:!0}],envVarName:`NEXT_PUBLIC_ZENOVAY_SITE`,buildSnippets:we},Ee=v.object({modules:v.array(v.string()).optional(),runtimeConfig:v.object({public:v.record(v.string(),v.unknown()).optional()}).optional()}).passthrough();async function De(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 Oe(e){let t=e.trackingCode??e.siteId??``,n=` app: {
44
- head: {
45
- script: [
46
- {
47
- defer: true,
48
- src: 'https://api.zenovay.com/z.js',
49
- 'data-id': '${t}',
50
- 'data-allow-localhost': 'true',
51
- },
52
- ],
53
- },
54
- },`;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 ke={id:`nuxt`,displayName:`Nuxt`,detect:De,files:[{path:`nuxt.config.ts`,kind:`mutate`,required:!0}],envVarName:`NUXT_PUBLIC_ZENOVAY_SITE`,buildSnippets:Oe},Ae=[`index.html`,`public/index.html`,`dist/index.html`];async function je(e){for(let t of Ae)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 Me(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 Ne={id:`plain-html`,displayName:`Plain HTML`,detect:je,files:[{path:`index.html`,kind:`mutate`,required:!0}],envVarName:`PUBLIC_ZENOVAY_SITE`,buildSnippets:Me};async function Pe(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 Fe(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 Ie={id:`remix`,displayName:`Remix`,detect:Pe,files:[{path:`app/root.tsx`,kind:`mutate`,required:!0}],envVarName:`PUBLIC_ZENOVAY_SITE`,buildSnippets:Fe};async function Le(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 Re(e){let t=e.trackingCode??e.siteId??``,n=`<svelte:head>
55
- <script defer data-id="${t}" data-allow-localhost="true" src="https://api.zenovay.com/z.js"></script>
56
- </svelte:head>
57
-
58
- <slot />
59
- `;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 ze={id:`sveltekit`,displayName:`SvelteKit`,detect:Le,files:[{path:`src/routes/+layout.svelte`,kind:`mutate`,required:!0}],envVarName:`PUBLIC_ZENOVAY_SITE`,buildSnippets:Re},Be=[ye,Te,ke,ze,de,Ie,Ne];async function G(e){let t=[];for(let n of Be){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=>g.resolve(e,t);return{cwd:e,async readFile(e){try{return await _.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 _.access(t(e)),!0}catch{return!1}},async glob(t){return A(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 Ve(e,t){let n=/[\s"'#=]/.test(t)||t===``,r=n?`"${t.replace(/\\/g,`\\\\`).replace(/"/g,`\\"`)}"`:t;return`${e}=${r}`}function He(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=g.resolve(e,r),a=``,o=!0;try{a=await _.readFile(i,`utf8`)}catch(e){if(e.code===`ENOENT`)o=!1;else throw e}let s=o?He(a):new Set,c=[],l=[],u=[];for(let[e,n]of Object.entries(t)){if(s.has(e)){l.push(e);continue}u.push(Ve(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(`
60
- `);f=a+(e?`
61
- `:``)+`
62
- `+d+`
63
- `+u.join(`
64
- `)+`
65
- `}else f=d+`
66
- `+u.join(`
67
- `)+`
68
- `;if(o)await _.writeFile(i,f,`utf8`);else{let e=await _.open(i,`w`,384);try{await e.writeFile(f,`utf8`)}finally{await e.close()}}return{created:!o,existing:o,addedKeys:c,skippedKeys:l}}const Ue=`https://api.zenovay.com/mcp`,We=v.object({url:v.string().url(),headers:v.record(v.string(),v.string()).optional()}),Ge=v.object({mcpServers:v.record(v.string(),We).optional()}).passthrough();function Ke(e){return e.HOME??e.USERPROFILE??y.homedir()}function qe(e){return e.APPDATA??null}function Je(e,t){let n=Ke(t),r=qe(t),i=[];return i.push({id:`cursor`,displayName:`Cursor`,configPath:g.join(n,`.cursor`,`mcp.json`)}),e===`win32`&&r&&i.push({id:`cursor`,displayName:`Cursor (AppData)`,configPath:g.join(r,`Cursor`,`User`,`globalStorage`,`cursor.mcp`,`mcp.json`)}),e===`darwin`?i.push({id:`claude-desktop`,displayName:`Claude Desktop`,configPath:g.join(n,`Library`,`Application Support`,`Claude`,`claude_desktop_config.json`)}):e===`win32`&&r?i.push({id:`claude-desktop`,displayName:`Claude Desktop`,configPath:g.join(r,`Claude`,`claude_desktop_config.json`)}):i.push({id:`claude-desktop`,displayName:`Claude Desktop`,configPath:g.join(n,`.config`,`Claude`,`claude_desktop_config.json`)}),i.push({id:`vscode`,displayName:`VS Code`,configPath:g.join(n,`.vscode`,`mcp.json`)}),i}async function Ye(e){try{return await _.access(e),!0}catch{return!1}}async function Xe(e){try{let t=await _.readFile(e,`utf8`);if(t.trim().length===0)return{};let n=JSON.parse(t),r=Ge.safeParse(n);return r.success?r.data:n&&typeof n==`object`?n:{}}catch{return{}}}function Ze(e){return{url:Ue,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=Ze(e.accessToken);for(let e of Je(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 Ye(e.configPath);if(!t){a.push(e.displayName);continue}let n=await Xe(e.configPath),r=`${e.configPath}.bak`;await _.copyFile(e.configPath,r);let o={...n,mcpServers:{...n.mcpServers??{},zenovay:c}};await _.mkdir(g.dirname(e.configPath),{recursive:!0}),await _.writeFile(e.configPath,JSON.stringify(o,null,2)+`
69
- `,`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 Qe(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 $e=v.object({path:v.string().min(1)}),et=v.object({path:v.string().min(1),content:v.string(),reason:v.string().min(1)}),tt=v.object({path:v.string().min(1),patch:v.string().min(1),reason:v.string().min(1)}),nt=v.object({}),rt=v.object({question:v.string().min(1),choices:v.array(v.string()).optional()});async function it(e,t){let n=$e.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 at(e,t,n){let r=et.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 ot(e,t,n){let r=tt.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=M(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.`}:at(e,{path:i,content:c,reason:o},n)}async function st(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 ct(e,t){let n=rt.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 lt(e){let{api:t,sandbox:n,approval:r,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 i(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 ut(e.name,e.arguments,{sandbox:n,cwd:n.cwd,approval:r,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 ut(e,t,n){try{switch(e){case`read_file`:return await it(n.sandbox,t);case`write_file`:return await at(n.sandbox,t,n.approval);case`patch_file`:return await ot(n.sandbox,t,n.approval);case`detect_framework`:return await st(n.cwd);case`ask_user`:return await ct(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 dt=e=>`<script defer\n data-id="${e}"\n data-allow-localhost="true"\n src="https://api.zenovay.com/z.js">\n</script>`;async function ft(e){let t={installed:[],skipped:[],errors:[]},n=await A([`**/*.html`,`!node_modules/**`,`!.git/**`,`!dist/**`,`!.next/**`,`!.nuxt/**`,`!build/**`,`!.output/**`],{cwd:e.cwd,gitignore:!0,absolute:!1});if(n.length===0)return t;let r=dt(e.trackingCode),i=RegExp(`data-id\\s*=\\s*["']${pt(e.trackingCode)}["']`);for(let a of n){let n=g.join(e.cwd,a),o;try{o=await _.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??`
70
- `,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 _.writeFile(n,s,`utf8`),t.installed.push(a)}catch(e){t.errors.push({file:a,error:e.message})}}return t}function pt(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function mt(){let e=[12,15,18,22,28,35,41,50,58,64,72,78],t=h(e,24);return[` ↑`,` ${t}`,` └────────────────────────`,` May Jun Jul Aug Sep`]}function ht(){return[` Landing page ████████████████████ 100%`,` ↓ -28%`,` Pricing ██████████████░░░░░░ 72%`,` ↓ -50%`,` Checkout ███████░░░░░░░░░░░░░ 36%`,` ↓ -64%`,` Purchased ███░░░░░░░░░░░░░░░░░ 13%`]}function gt(){return[` ▇▇▇▇▇▇▇▇▇▎ 89 Sarah K. /pricing 🇺🇸`,` ▇▇▇▇▇▇░░░░ 61 anon /docs 🇩🇪`,` ▇▇▇░░░░░░░ 34 anon /changelog 🇯🇵`]}function _t(){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:mt},{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:ht},{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:gt},{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:_t},{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.`]}],vt=8e3,yt=({width:e,height:t})=>{let[n,r]=k(0);D(()=>{let e=setInterval(()=>{r(e=>(e+1)%X.length)},vt);return()=>clearInterval(e)},[]);let i=X[n],a=i.visual?i.visual():[],o=X.map((e,t)=>t===n?`●`:`·`).join(` `);return E.createElement(S,{flexDirection:`column`,width:e,height:t,paddingX:2,paddingY:1},E.createElement(S,{marginBottom:1},E.createElement(C,{color:`magentaBright`,bold:!0},`Learn`)),E.createElement(S,{marginBottom:1},E.createElement(C,{bold:!0,color:`white`},i.title)),i.body.map((e,t)=>E.createElement(C,{key:t,color:`gray`},e||` `)),a.length>0&&E.createElement(S,{flexDirection:`column`,marginTop:1},a.map((e,t)=>E.createElement(C,{key:t,color:`cyan`},e))),E.createElement(S,{flexGrow:1}),E.createElement(S,{marginTop:1},E.createElement(C,{color:`gray`,dimColor:!0},o,` · `,n+1,` / `,X.length)))},bt={pending:`·`,active:`⠋`,done:`✓`,error:`✗`},xt={pending:`gray`,active:`magenta`,done:`green`,error:`red`},St=({tasks:e,width:t,height:n,liveLine:r})=>{let i=e.filter(e=>e.status===`done`).length;return E.createElement(S,{flexDirection:`column`,width:t,height:n,paddingX:2,paddingY:1},E.createElement(S,{marginBottom:1},E.createElement(C,{color:`magentaBright`,bold:!0},`Tasks`)),e.map(e=>E.createElement(S,{key:e.id,flexDirection:`column`},E.createElement(S,null,e.status===`active`?E.createElement(C,{color:`magenta`},E.createElement(j,{type:`dots`})):E.createElement(C,{color:xt[e.status]},bt[e.status]),E.createElement(C,null,` `),E.createElement(C,{color:e.status===`pending`?`gray`:`white`},e.label)),e.detail&&E.createElement(S,{paddingLeft:2},E.createElement(C,{color:`gray`,dimColor:!0},e.detail)))),E.createElement(S,{flexGrow:1}),r&&E.createElement(S,{marginTop:1},E.createElement(C,{color:`cyan`},`◆ `),E.createElement(C,{color:`white`},r)),E.createElement(S,{marginTop:1},E.createElement(C,{color:`gray`,dimColor:!0},i,` / `,e.length)))};async function Ct(e){if(o(e))return wt(e);let t=`quit`,n=null,r=await new Promise(r=>{let{unmount:i,waitUntilExit:a}=w(E.createElement(Tt,{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;let i=n.id;if(t===`watch`){let{watchCommand:t}=await import(`./watch-D5WeMSz2.js`);return t({cliVersion:e.cliVersion,siteId:i})}if(t===`events`){let{eventsTailCommand:t}=await import(`./events-tail-u_lwZas2.js`);return t({cliVersion:e.cliVersion,siteId:i})}return 0}async function wt(t){let i=await import(`./telemetry-C1045t6Q.js`).catch(()=>null);i?.emit(`install.start`,{properties:{mode:`headless`}});try{let o=await e(),s=await q(t.cwd);if(!s)return a({type:`error`,code:`no_framework`,message:`Could not detect framework (headless mode has no picker).`}),i?.emit(`install.error`,{error_code:`no_framework`,properties:{mode:`headless`}}),2;a({type:`framework.detected`,framework:s.id,confidence:1}),i?.emit(`install.framework_detected`,{properties:{framework:s.id}});let c=await r({strict:!1});if(!c&&!process.env.ZENOVAY_API_TOKEN)return a({type:`error`,code:`not_logged_in`,message:"Run `zenovay login` first (or set ZENOVAY_API_TOKEN)."}),2;let l=new n({config:o,cliVersion:t.cliVersion,token:c}),u=await l.getSites(),d=t.siteId?u.find(e=>e.id===t.siteId):u[0];if(!d&&t.siteId)return a({type:`error`,code:`site_not_found`,message:`Site ${t.siteId} not found.`}),2;if(!d)return a({type:`error`,code:`no_site`,message:`No sites exist; create one at app.zenovay.com or re-run interactively.`}),2;a({type:`info`,message:`Using site ${d.id} (${d.name}) trackingCode=${d.trackingCode??d.id}`});let f=await J(t.cwd,{[s.envVarName]:d.trackingCode??d.id});return a({type:`info`,message:`env vars added: ${f.addedKeys.join(`,`)}`}),a({type:`done`,command:`init`,exitCode:0}),i?.emit(`install.success`,{properties:{framework:s.id,mode:`headless`,env_keys_added:f.addedKeys.length}}),0}catch(e){return a({type:`error`,code:`init_failed`,message:e.message}),i?.emit(`install.error`,{error_code:`init_failed`,properties:{mode:`headless`,error:(e.message??`unknown`).slice(0,128)}}),1}}const Tt=({opts:t,onExit:i})=>{let{exit:a}=ee(),[o,s]=k(`intro`),[d,f]=k(null),[p,h]=k([]),[g,_]=k(null),[v,y]=k(null),[b,x]=k(null),[w,T]=k([]),[A,M]=k(void 0),[N,P]=k(null),[F,te]=k(0),I=O(!1);return D(()=>(process.stdout.isTTY&&process.stdout.write(`\x1B[?1049h\x1B[H`),()=>{process.stdout.isTTY&&process.stdout.write(`\x1B[?1049l`)}),[]),D(()=>{I.current||(I.current=!0,(async()=>{try{s(`detecting`);let i=await q(t.cwd);if(!i){x(`Could not detect your framework. Supported: Next.js, Nuxt, SvelteKit, Astro, Remix, plain HTML.`),s(`error`);return}f(i);let a=await r({strict:!1});!process.env.ZENOVAY_API_TOKEN&&!a&&(s(`login`),await c({cliVersion:t.cliVersion})),s(`loading-sites`);let o=await e(),l=await r({strict:!1}),u=new n({config:o,cliVersion:t.cliVersion,token:l}),d=await u.getSites(),p=await zt(t.cwd),m=Bt(d,p);if(h(d),_(p),d.length===0){s(`create-site`);return}if(t.siteId){let e=d.find(e=>e.id===t.siteId);if(!e){x(`Site ${t.siteId} not found in your account.`),s(`error`);return}y(e),Z(e,i,t,{setPhase:s,setErrorMsg:x,setTasks:T,setLiveLine:M,setSandboxStats:P});return}if(t.yes&&m){y(m),Z(m,i,t,{setPhase:s,setErrorMsg:x,setTasks:T,setLiveLine:M,setSandboxStats:P});return}s(`site-picker`)}catch(e){x(e.message),s(`error`)}})())},[]),D(()=>{o===`error`&&setTimeout(()=>{a(),i(1)},8e3)},[o]),E.createElement(S,{flexDirection:`column`},E.createElement(u,{version:t.cliVersion,subtitle:`AI install wizard`}),o===`intro`&&E.createElement(Et,null),o===`detecting`&&E.createElement(l,{title:`Scanning`,state:`busy`},E.createElement(S,null,E.createElement(C,{color:`magenta`},E.createElement(j,{type:`dots`})),E.createElement(C,null,` Detecting framework…`))),o===`login`&&E.createElement(l,{title:`Authenticating`,state:`busy`},E.createElement(C,null,`Opening browser for login… (paste ZENOVAY_API_TOKEN env var to skip)`)),o===`loading-sites`&&E.createElement(l,{title:`Loading your sites`,state:`busy`},E.createElement(S,null,E.createElement(C,{color:`magenta`},E.createElement(j,{type:`dots`})),E.createElement(C,null,` Fetching your Zenovay sites…`))),o===`site-picker`&&d&&E.createElement(Ot,{sites:p,preselectHint:g,onPick:e=>{if(e===`create-new`){s(`create-site`);return}y(e),Z(e,d,t,{setPhase:s,setErrorMsg:x,setTasks:T,setLiveLine:M,setSandboxStats:P})}}),o===`create-site`&&E.createElement(l,{title:`Create a new site`,state:`warn`},E.createElement(C,{color:`yellow`},"No site picked (or none exist yet). Visit https://app.zenovay.com/websites to create one, then re-run `zenovay init`."),E.createElement(C,{color:`gray`},`(Inline site creation from the CLI is scheduled for V1.1 — it requires a plan-limit check.)`)),o===`agent`&&d&&v&&E.createElement(Dt,{adapter:d,site:v,tasks:w,liveLine:A}),o===`install-complete`&&d&&v&&E.createElement(jt,{adapter:d,site:v,stats:N,onCommit:()=>s(`commit-prompt`),onSkipCommit:()=>s(`deploy-prompt`)}),o===`commit-prompt`&&v&&E.createElement(Mt,{cwd:t.cwd,onDone:e=>{e.committed&&M(`Pushed ${e.shortSha} to ${e.branch}`),s(`deploy-prompt`)},onError:e=>{x(e),s(`error`)}}),o===`deploy-prompt`&&v&&E.createElement(Nt,{site:v,onDeployed:()=>s(`visit-prompt`),onSkip:()=>s(`verify`)}),o===`visit-prompt`&&v&&E.createElement(Pt,{site:v,onContinue:()=>s(`verify`)}),o===`verify`&&v&&E.createElement(It,{site:v,elapsed:F,onTick:e=>te(e),onArrived:()=>s(`success`),onTimeout:()=>s(`success`)}),o===`success`&&d&&v&&E.createElement(At,{adapter:d,site:v,stats:N,onPick:e=>{a(),i(0,e,v)}}),o===`error`&&E.createElement(l,{title:`Install failed`,state:`err`},E.createElement(C,{color:`red`},b??`Unknown error`)),E.createElement(m,{items:[{key:`q`,label:`quit`},{key:`ctrl-c`,label:`abort`}]}))};async function Z(i,a,o,s){try{s.setPhase(`agent`);let c=await e(),l=await r({strict:!1}),u=new n({config:c,cliVersion:o.cliVersion,token:l}),d=new W({cwd:o.cwd}),f=i.trackingCode??i.id;await t({defaultSiteId:i.id,defaultSiteName:i.name}).catch(()=>void 0);let p=await re(o.cwd,f);if(p.recommendation===`no-op`){s.setTasks(e=>e.map(e=>e.id===`detect`||e.id===`read`||e.id===`write`?{...e,status:`done`,detail:`already installed correctly`}:e)),s.setLiveLine(p.summary),s.setSandboxStats?.({reads:0,writes:0,rounds:0}),!o.skipMcp&&l&&await Y({accessToken:l.accessToken}).catch(()=>void 0),s.setPhase(`install-complete`);return}p.competitors.length>0&&s.setLiveLine(`Detected ${p.competitors.map(e=>e.name).join(`, `)} — will install Zenovay alongside (won't touch their tags).`);let m=a.id===`plain-html`&&(p.recommendation===`fresh-install`||p.recommendation===`fresh-install-alongside-competitor`||p.recommendation===`update-tracking-code`);if(m){s.setTasks(e=>e.map(e=>e.id===`detect`?{...e,status:`done`,detail:`Plain HTML`}:e)),s.setLiveLine(`Plain HTML — using fast install path (no AI needed)…`);let e=await ft({cwd:o.cwd,trackingCode:f,updateOnly:p.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}`);s.setTasks(t=>t.map(t=>t.id===`read`||t.id===`write`?{...t,status:`done`,detail:`${e.installed.length} file(s)`}:t)),s.setLiveLine(`Tracker added to ${e.installed.length} file(s). Skipped ${e.skipped.length}, errored ${e.errors.length}.`);let t=await J(o.cwd,{[a.envVarName]:f});if(s.setTasks(e=>e.map(e=>e.id===`env`?{...e,status:`done`,detail:`${t.addedKeys.length} key(s) added`}:e)),!o.skipMcp&&l){let e=await Y({accessToken:l.accessToken}).catch(()=>null);s.setTasks(t=>t.map(t=>t.id===`mcp`?{...t,status:`done`,detail:e&&e.installed.length>0?e.installed.join(`, `):`none detected`}:t))}else s.setTasks(e=>e.map(e=>e.id===`mcp`?{...e,status:`done`,detail:`skipped`}:e));s.setLiveLine(void 0),s.setSandboxStats?.({reads:e.installed.length,writes:e.installed.length,rounds:0}),s.setPhase(`install-complete`);return}let h=a.buildSnippets({trackingCode:f,siteId:i.id}),g=`Install Zenovay tracking into this ${a.displayName} project.\nSite: ${i.name} (trackingCode: ${f}).\n1. Call detect_framework to confirm the framework.\n2. Read the entry file(s) for this framework:\n`+a.files.map(e=>` - ${e.path}`).join(`
71
- `)+`
72
- 3. Insert the tracker using the snippet below.
73
- 4. Confirm the change with a diff before writing.
74
-
75
- Snippet reference (anchored by anchorKind — adapt to the actual file):
76
- `+h.map(e=>` ${e.anchorKind} @ ${e.targetPath}:\n ${e.code.replace(/\n/g,`
77
- `)}`).join(`
78
-
79
- `);s.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 _=(e,t,n)=>{s.setTasks(r=>r.map(r=>r.id===e?{...r,status:t,detail:n??r.detail}:r))},v=null;try{await lt({api:u,sandbox:d,approval:{async approve(){return`y`}},prompter:{async ask({question:e}){return e}},handlers:{onToolStart:({name:e})=>{e===`detect_framework`?(_(`detect`,`active`),s.setLiveLine(`Inspecting package.json + config files…`)):e===`read_file`?(_(`detect`,`done`),_(`read`,`active`)):(e===`write_file`||e===`patch_file`)&&(_(`read`,`done`),_(`write`,`active`))},onToolResult:({name:e,result:t})=>{let n=t?.ok!==!1,r=t?.content??{};e===`detect_framework`&&n&&(_(`detect`,`done`,a.displayName),s.setLiveLine(`Detected ${a.displayName}`)),e===`read_file`&&n&&r.path&&s.setLiveLine(`Read ${r.path}`),(e===`write_file`||e===`patch_file`)&&n&&r.path&&s.setLiveLine(`Wrote ${r.path}`)},onDelta:e=>{let t=e.replace(/\s+/g,` `).trim();t.length>4&&s.setLiveLine(t.slice(0,80))}},initialMessages:[{role:`user`,content:g}],diagnosis:p,targetTrackingCode:f})}catch(e){v=e}let y=d.stats();if(y.writes===0){let e=v?`Agent error: ${v.message}`:`Agent returned without writing any files (${y.reads} reads, ${y.rounds} rounds). The model may have refused or the AI Gateway may be misconfigured. Check api.zenovay.com logs.`;throw Error(e)}let b=a.files.map(e=>e.path),x=y.writtenPaths.some(e=>b.some(t=>e===t||e.endsWith(`/${t}`)));if(!x)throw Error(`Agent wrote to: [${y.writtenPaths.join(`, `)}] but never modified the framework's tracker target file(s): [${b.join(`, `)}]. The tracker is NOT installed. The model likely put the trackingCode into .env.local instead of into the HTML/JSX entry file.`);_(`write`,`done`),_(`env`,`active`),s.setLiveLine(`Adding env var to .env.local`);let S=await J(o.cwd,{[a.envVarName]:f});if(_(`env`,`done`,`${S.addedKeys.length} key(s) added`),!o.skipMcp&&l){_(`mcp`,`active`),s.setLiveLine(`Detecting Cursor / Claude Desktop / VS Code…`);let e=await Y({accessToken:l.accessToken}).catch(()=>null);e&&e.installed.length>0?_(`mcp`,`done`,e.installed.join(`, `)):_(`mcp`,`done`,`none detected`)}else _(`mcp`,`done`,`skipped`);s.setTasks(e=>e.map(e=>e.id===`detect`||e.id===`read`||e.id===`write`?{...e,status:e.status===`pending`?`done`:e.status}:e)),s.setLiveLine(void 0),s.setSandboxStats?.(y),s.setPhase(`install-complete`)}catch(e){s.setErrorMsg(e.message),s.setPhase(`error`)}}const Et=()=>E.createElement(l,{title:`Zenovay wants to set up your project`,state:`idle`},E.createElement(C,null,`We'll use AI to analyze your codebase and add the Zenovay tracker.`),E.createElement(C,{color:`gray`},`.env* contents stay on your machine. Only framework metadata reaches api.zenovay.com.`)),Dt=({adapter:e,site:t,tasks:n,liveLine:r})=>{let i=process.stdout.columns??100,a=(process.stdout.rows??30)-8,o=Math.floor(i/2)-1,s=Math.max(14,a);return E.createElement(S,{flexDirection:`column`},E.createElement(S,{flexDirection:`row`,minHeight:s,borderStyle:`round`,borderColor:`gray`},E.createElement(S,{width:o,flexDirection:`column`},E.createElement(yt,{width:o,height:s})),E.createElement(S,{width:1,flexDirection:`column`},E.createElement(C,{color:`gray`},`│`)),E.createElement(S,{width:o,flexDirection:`column`},E.createElement(S,{paddingX:2,paddingTop:1},E.createElement(f,{done:n.filter(e=>e.status===`done`).length,total:n.length,label:n.find(e=>e.status===`active`)?.label})),E.createElement(St,{tasks:n,liveLine:r,width:o,height:s}))),E.createElement(S,{marginTop:1},E.createElement(C,{color:`gray`},`Site: `,t.name,` · code: `,t.trackingCode??t.id,` · Framework: `,e.displayName)))},Ot=({sites:e,preselectHint:t,onPick:n})=>{let r=Bt(e,t),i=e.filter(e=>e.id!==r?.id),a=r?[r,...i]:i,o=[...a.map(e=>({label:Rt(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 E.createElement(l,{title:t?`Pick a site (best match: ${t})`:`Pick a site`,state:`idle`},E.createElement(p,{items:o,onSelect:n}))};function kt(){let e=process.argv[1]??``;return e.includes(`/_npx/`)||e.includes(`\\_npx\\`)||process.env.npm_execpath?.includes(`npx`)?`npx`:`global`}const At=({adapter:e,site:t,stats:n,onPick:r})=>{let i=kt(),a=i===`npx`?`npx @zenovay/cli`:`zenovay`;return T((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}),E.createElement(l,{title:`You're live on Zenovay`,state:`ok`},E.createElement(C,null,E.createElement(d,null,`✔ Installed successfully`)),E.createElement(S,{marginTop:1,flexDirection:`column`},E.createElement(C,null,`Framework: `,E.createElement(C,{color:`cyan`},e.displayName)),E.createElement(C,null,`Site: `,E.createElement(C,{color:`cyan`},t.name),` (`,t.url,`)`),t.trackingCode?E.createElement(C,{color:`gray`},`Tracker: `,t.trackingCode):null,n&&n.rounds>0?E.createElement(C,{color:`gray`},`Modified: `,n.writes,` file(s) across `,n.rounds,` agent round(s)`):n&&n.writes>0?E.createElement(C,{color:`gray`},`Modified: `,n.writes,` file(s) (programmatic install — no AI calls)`):null),E.createElement(S,{marginTop:1,flexDirection:`column`},E.createElement(C,{bold:!0},`What's next?`),E.createElement(C,null,` `),E.createElement(S,null,E.createElement(C,{color:`cyan`},` [W] `),E.createElement(C,null,`Open the live dashboard `),E.createElement(C,{color:`gray`},`— real-time visitors, top pages, sources, vitals`)),E.createElement(S,null,E.createElement(C,{color:`cyan`},` [E] `),E.createElement(C,null,`Stream events as they fire `),E.createElement(C,{color:`gray`},`— page views, custom events, in real time`)),E.createElement(S,null,E.createElement(C,{color:`cyan`},` [S] `),E.createElement(C,null,`Exit to shell`))),i===`npx`?E.createElement(S,{marginTop:1,flexDirection:`column`,borderStyle:`single`,borderColor:`yellow`,paddingX:1},E.createElement(C,{color:`yellow`,bold:!0},`Heads up — you ran via npx`),E.createElement(C,null,E.createElement(C,null,`The `),E.createElement(C,{color:`cyan`},`zenovay`),E.createElement(C,null,` command isn't on your PATH yet. After you exit, run any of:`)),E.createElement(C,null,` `),E.createElement(C,{color:`cyan`},` npm i -g @zenovay/cli `),E.createElement(C,{color:`gray`},"→ then `zenovay watch` works directly"),E.createElement(C,{color:`cyan`},` npx @zenovay/cli watch `),E.createElement(C,{color:`gray`},`→ no install, slower start`)):E.createElement(S,{marginTop:1},E.createElement(C,{color:`gray`},`From your shell: `),E.createElement(C,{color:`cyan`},a,` watch`),E.createElement(C,{color:`gray`},` · `),E.createElement(C,{color:`cyan`},a,` --help`)),E.createElement(S,{marginTop:1},E.createElement(C,{color:`gray`},`Dashboard URL: https://app.zenovay.com/sites/`,t.id)))},jt=({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()}),E.createElement(l,{title:`Tracker installed`,state:`ok`},E.createElement(C,null,E.createElement(d,null,`✔ `),`The Zenovay tracker is in your project.`),E.createElement(S,{marginTop:1},E.createElement(C,{color:`gray`},`Framework: `),E.createElement(C,null,e.displayName)),E.createElement(S,null,E.createElement(C,{color:`gray`},`Site: `),E.createElement(C,null,t.name,` (`,t.url,`)`)),n&&E.createElement(S,null,E.createElement(C,{color:`gray`},`Modified: `),E.createElement(C,null,n.writes,` file(s)`)),E.createElement(S,{marginTop:1},E.createElement(C,null,`Commit + push these changes to git? `),E.createElement(C,{color:`cyan`},`[Y/n]`)))),Mt=({cwd:e,onDone:t,onError:n})=>{let[r,i]=k(`committing`),[a,o]=k(`Staging changes…`);return D(()=>{(async()=>{try{let n=await Lt(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)}})()},[]),E.createElement(l,{title:`Committing to git`,state:`busy`},E.createElement(S,null,E.createElement(C,{color:`magenta`},E.createElement(j,{type:`dots`})),E.createElement(C,null,` `,r===`pushing`?`Pushing to origin`:`Committing`,`…`)),E.createElement(S,{marginTop:1},E.createElement(C,{color:`gray`},a)))},Nt=({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()}),E.createElement(l,{title:`Ready to deploy?`,state:`idle`},E.createElement(C,null,`The tracker is installed locally. To capture events you need it on the live site:`),E.createElement(C,null,` `),E.createElement(S,null,E.createElement(C,{color:`cyan`},` → `),E.createElement(C,null,e.url)),E.createElement(C,null,` `),E.createElement(C,{color:`gray`},`Push the change through your normal deploy pipeline (Vercel auto-deploy, CI/CD, etc.).`),E.createElement(S,{marginTop:1},E.createElement(C,null,`Once it's deployed, press `),E.createElement(C,{color:`cyan`},`[Y]`),E.createElement(C,null,` to verify the tracker is firing. `),E.createElement(C,{color:`gray`},`[s] skip verification`)))),Pt=({site:e,onContinue:t})=>(Q(()=>t()),E.createElement(l,{title:`Visit your site`,state:`idle`},E.createElement(C,null,`To send a test event, open any page on your site:`),E.createElement(C,null,` `),E.createElement(S,null,E.createElement(C,{color:`cyan`},` → `),E.createElement(C,null,e.url)),E.createElement(C,null,` `),E.createElement(C,{color:`gray`},`The tracker fires automatically on page load. We'll verify the next event arrives.`),E.createElement(S,{marginTop:1},E.createElement(C,null,`Press `),E.createElement(C,{color:`cyan`},`[any key]`),E.createElement(C,null,` when you've visited the page.`))));async function Ft(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 It=({site:t,elapsed:i,onTick:a,onArrived:o,onTimeout:s})=>{let[c,u]=k(`preflight`),[d,f]=k(``),[p,m]=k([]),h=O(!1),g=t.trackingCode??t.id,_=async()=>{u(`preflight`),f(`Fetching ${t.url}…`);let e=await Ft(t.url,g);if(!h.current){if(e.state===`tracker-correct`){u(`polling`),f(`Tracker detected on live site — waiting for first hit…`),v();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 ${t.url}: ${e.networkError}`:e.httpStatus?`${t.url} returned HTTP ${e.httpStatus}`:`No Zenovay tracker found on ${t.url}.`)}},v=async()=>{let i=Date.now()-10*60*1e3;try{let s=await e(),c=await r({strict:!1}),l=new n({config:s,cliVersion:`0`,token:c}),d=await Qe(t.id,i,{api:l,timeoutMs:6e4,pollIntervalMs:2500,onTick:e=>{h.current||a(e)}});if(h.current)return;d.received?(u(`success`),o()):u(`timeout`)}catch{h.current||u(`timeout`)}};D(()=>(h.current=!1,_(),()=>{h.current=!0}),[]),T(e=>{(c===`awaiting-deploy`||c===`wrong-id-on-live`||c===`timeout`)&&(e===`r`||e===`R`?_():(e===`s`||e===`S`)&&s())},{isActive:!0});let y=Math.floor(i/1e3);return c===`preflight`?E.createElement(l,{title:`Verifying`,state:`busy`},E.createElement(S,null,E.createElement(C,{color:`magenta`},E.createElement(j,{type:`dots`})),E.createElement(C,null,` Checking your live site for the tracker…`)),E.createElement(S,{marginTop:1},E.createElement(C,{color:`gray`},d))):c===`awaiting-deploy`?E.createElement(l,{title:`Tracker not yet on your live site`,state:`warn`},E.createElement(C,{color:`yellow`},d),E.createElement(S,{marginTop:1,flexDirection:`column`},E.createElement(C,null,`The tracker is in your local repo but hasn't been deployed yet.`),E.createElement(C,{color:`gray`},`Push your changes and wait for your deploy to finish (Vercel / Cloudflare Pages / CI), then retry.`)),E.createElement(S,{marginTop:1},E.createElement(C,null,`Press `),E.createElement(C,{color:`cyan`},`[r]`),E.createElement(C,null,` to re-check, `),E.createElement(C,{color:`cyan`},`[s]`),E.createElement(C,null,` to skip verification.`))):c===`wrong-id-on-live`?E.createElement(l,{title:`Live site has a different tracking code`,state:`warn`},E.createElement(C,{color:`yellow`},`Expected: `,E.createElement(C,{color:`cyan`},g),` `,`Found on live: `,E.createElement(C,{color:`cyan`},p.join(`, `))),E.createElement(S,{marginTop:1,flexDirection:`column`},E.createElement(C,null,`Your local install uses a different ID than what's on `,t.url,`.`),E.createElement(C,{color:`gray`},`Deploy the new local version, then retry — or skip if the existing ID is intentional.`)),E.createElement(S,{marginTop:1},E.createElement(C,null,`Press `),E.createElement(C,{color:`cyan`},`[r]`),E.createElement(C,null,` to re-check, `),E.createElement(C,{color:`cyan`},`[s]`),E.createElement(C,null,` to skip.`))):c===`timeout`?E.createElement(l,{title:`No event arrived in 3 minutes`,state:`warn`},E.createElement(C,{color:`yellow`},`The tracker is on your live site but no hits reached api.zenovay.com.`),E.createElement(S,{marginTop:1},E.createElement(C,{color:`gray`},`Try opening `,t.url,` in a fresh browser tab (no ad-blocker), then retry.`)),E.createElement(S,{marginTop:1},E.createElement(C,null,`Press `),E.createElement(C,{color:`cyan`},`[r]`),E.createElement(C,null,` to re-check, `),E.createElement(C,{color:`cyan`},`[s]`),E.createElement(C,null,` to finish without verification.`))):E.createElement(l,{title:`Waiting for first event`,state:`busy`},E.createElement(S,null,E.createElement(C,{color:`magenta`},E.createElement(j,{type:`dots`})),E.createElement(C,null,` Polling api.zenovay.com for the first hit on `),E.createElement(C,{color:`cyan`},t.url),E.createElement(C,null,` (`,y,`s elapsed)`)),E.createElement(S,{marginTop:1},E.createElement(C,{color:`gray`},`Reload the page if nothing arrives within ~30 seconds.`)))};function Q(e){T((t,n)=>{e(t,{return:n.return,escape:n.escape})},{isActive:!0})}async function Lt(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 Rt(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 zt(e){try{let t=await _.readFile(g.join(e,`package.json`),`utf8`),n=JSON.parse(t);if(n.name)return String(n.name).replace(/^@[^/]+\//,``)}catch{}try{let t=await _.readFile(g.join(e,`.git`,`config`),`utf8`),n=t.match(/url\s*=\s*.*[/:]([^/]+?)(?:\.git)?\s*$/m);if(n&&n[1])return n[1]}catch{}return g.basename(e)}function Bt(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{ae as detectInstalled,Ct as initCommand};
@@ -1 +0,0 @@
1
- import"./config--JRu_jFq.js";import"./api-FCanTxsb.js";import"./token-store-BQuGH0z2.js";import{initCommand as e}from"./init-BIJkCrgc.js";import"./client-DTXWADkX.js";import"./formatter-DutfcQAc.js";import"./emit-DBYk96TD.js";import"./secrets-ApB7yh2A.js";import"./login-yhuXiFqh.js";import"./panel-B_yDcIcn.js";import"./banner-3iSWTDFy.js";import"./progress-row-BpAXjJPL.js";import"./prompt-D-Uzz_GF.js";import"./keybar-DsYTkKZX.js";import"./sparkline-BZ0eMB-w.js";export{e as initCommand};
@@ -1 +0,0 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import"./api-FCanTxsb.js";import{readToken as t}from"./token-store-BQuGH0z2.js";import{ApiV2Client as n}from"./api-v2-CI5hxW-O.js";import{requireTier as r}from"./tier-BneaO4vD.js";import"./formatter-DutfcQAc.js";import{emit$1 as i,isHeadless as a}from"./emit-DBYk96TD.js";import{Panel as o}from"./panel-B_yDcIcn.js";import{Banner as s}from"./banner-3iSWTDFy.js";import"./prompt-D-Uzz_GF.js";import{Keybar as c}from"./keybar-DsYTkKZX.js";import{resolveSiteId as l}from"./resolve-site-mj0esTrm.js";import{EmptyState as u}from"./empty-state-CJxa1jUN.js";import{deepLinkFor as d,openInBrowser as f}from"./keybar-deep-link-DC31T3CP.js";import{Box as p,Text as m,render as h,useApp as g,useInput as _}from"ink";import v,{useEffect as y,useState as b}from"react";import x from"ink-spinner";function S(e){return e===`critical`?`err`:e===`warning`?`warn`:`ok`}function C(e){return e===`anomaly`?`⚡ anomaly`:e===`recommendation`?`✦ recommendation`:`↗ trend`}async function w(o){let s=await e(),c=await t({strict:!1});if(!c)return process.stderr.write("Not logged in — run `zenovay login` first.\n"),2;let u=new n({config:s,cliVersion:o.cliVersion,token:c});try{await r(u,`pro`)}catch(e){return process.stderr.write(`${e.message}\n`),2}let d,f;try{({siteId:d,site:f}=await l(u,{explicit:o.siteId,headless:!!o.json,cliVersion:o.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let p=f?.url?f.url.replace(/^https?:\/\//,``).replace(/\/$/,``):f?.name??d;if(a(o)){let e=await u.getInsights(d);return i({type:`insights.snapshot`,data:e}),0}return new Promise(e=>{let{unmount:t}=h(v.createElement(T,{api:u,siteId:d,siteLabel:p,cliVersion:o.cliVersion,onExit:n=>{t(),e(n)}}))})}const T=({api:e,siteId:t,siteLabel:n,cliVersion:r,onExit:i})=>{let{exit:a}=g(),[l,h]=b(null),[w,T]=b(!0),[E,D]=b(null);return _(e=>{if(e===`o`||e===`O`){f(d(`insights`,{siteId:t}));return}e===`q`&&(a(),i(0))}),y(()=>{let n=!1;return(async()=>{try{let r=await e.getInsights(t);n||(h(r),T(!1))}catch(e){n||(D(e.message),T(!1))}})(),()=>{n=!0}},[e,t]),w?v.createElement(p,{flexDirection:`column`},v.createElement(s,{version:r,subtitle:`insights · ${n}`}),v.createElement(o,{title:`Loading`,state:`busy`},v.createElement(p,null,v.createElement(m,{color:`magenta`},v.createElement(x,{type:`dots`})),v.createElement(m,null,` Fetching insights…`)))):E?v.createElement(p,{flexDirection:`column`},v.createElement(s,{version:r,subtitle:`insights · ${n}`}),v.createElement(u,{reason:`error`,headline:`Failed to load`,hint:E})):!l||l.length===0?v.createElement(p,{flexDirection:`column`},v.createElement(s,{version:r,subtitle:`insights · ${n}`}),v.createElement(u,{reason:`no-data`,headline:`No insights yet`,hint:`Insights are generated nightly — check back tomorrow`})):v.createElement(p,{flexDirection:`column`},v.createElement(s,{version:r,subtitle:`insights · ${n}`}),l.map((e,t)=>v.createElement(o,{key:t,title:`${C(e.kind)} · ${e.severity}`,state:S(e.severity)},v.createElement(m,{bold:!0},e.title),e.body?v.createElement(m,{color:`gray`},e.body):null)),v.createElement(c,{items:[{key:`o`,label:`open in browser`},{key:`q`,label:`quit`}]}))};export{w as insightsCommand};
@@ -1 +0,0 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import"./api-FCanTxsb.js";import{readToken as t}from"./token-store-BQuGH0z2.js";import{ApiV2Client as n}from"./api-v2-CI5hxW-O.js";import{requireTier as r}from"./tier-BneaO4vD.js";import"./formatter-DutfcQAc.js";import{emit$1 as i,isHeadless as a}from"./emit-DBYk96TD.js";import{Panel as o}from"./panel-B_yDcIcn.js";import{Banner as s}from"./banner-3iSWTDFy.js";import"./prompt-D-Uzz_GF.js";import{Keybar as c}from"./keybar-DsYTkKZX.js";import{resolveSiteId as l}from"./resolve-site-mj0esTrm.js";import{EmptyState as u}from"./empty-state-CJxa1jUN.js";import{deepLinkFor as d,openInBrowser as f}from"./keybar-deep-link-DC31T3CP.js";import{Box as p,Text as m,render as h,useApp as g,useInput as _}from"ink";import v,{useEffect as y,useState as b}from"react";import x from"ink-spinner";async function S(o){let s=await e(),c=await t({strict:!1});if(!c)return process.stderr.write("Not logged in — run `zenovay login` first.\n"),2;let u=new n({config:s,cliVersion:o.cliVersion,token:c});try{await r(u,`pro`)}catch(e){return process.stderr.write(`${e.message}\n`),2}let d,f;try{({siteId:d,site:f}=await l(u,{explicit:o.siteId,headless:!!o.json,cliVersion:o.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let p=f?.url?f.url.replace(/^https?:\/\//,``).replace(/\/$/,``):f?.name??d;if(a(o)){let e=await u.getJourneys(d);return i({type:`journeys.snapshot`,data:e}),0}return new Promise(e=>{let{unmount:t}=h(v.createElement(C,{api:u,siteId:d,siteLabel:p,cliVersion:o.cliVersion,onExit:n=>{t(),e(n)}}))})}const C=({api:e,siteId:t,siteLabel:n,cliVersion:r,onExit:i})=>{let{exit:a}=g(),[l,h]=b(null),[S,C]=b(!0),[w,T]=b(null);if(_(e=>{if(e===`o`||e===`O`){f(d(`journeys`,{siteId:t}));return}e===`q`&&(a(),i(0))}),y(()=>{let n=!1;return(async()=>{try{let r=await e.getJourneys(t);n||(h(r.flows),C(!1))}catch(e){n||(T(e.message),C(!1))}})(),()=>{n=!0}},[e,t]),S)return v.createElement(p,{flexDirection:`column`},v.createElement(s,{version:r,subtitle:`journeys · ${n}`}),v.createElement(o,{title:`Loading`,state:`busy`},v.createElement(p,null,v.createElement(m,{color:`magenta`},v.createElement(x,{type:`dots`})),v.createElement(m,null,` Computing flows…`))));if(w)return v.createElement(p,{flexDirection:`column`},v.createElement(s,{version:r,subtitle:`journeys · ${n}`}),v.createElement(u,{reason:`error`,headline:`Failed to load`,hint:w}));if(!l||l.length===0)return v.createElement(p,{flexDirection:`column`},v.createElement(s,{version:r,subtitle:`journeys · ${n}`}),v.createElement(u,{reason:`no-data`,headline:`No journeys yet`,hint:`Need at least 2 page-views per session to compute flows`}));let E=Math.max(...l.map(e=>e.count),1),D=12;return v.createElement(p,{flexDirection:`column`},v.createElement(s,{version:r,subtitle:`journeys · ${n}`}),v.createElement(o,{title:`Top page transitions (${l.length})`},l.map((e,t)=>{let n=Math.max(1,Math.round(e.count/E*D));return v.createElement(p,{key:t,flexDirection:`row`},v.createElement(m,null,e.from.padEnd(22).slice(0,22)),v.createElement(m,{color:`cyan`},` → `),v.createElement(m,null,e.to.padEnd(22).slice(0,22)),v.createElement(m,{color:`magenta`},` `,`█`.repeat(n),`░`.repeat(D-n)),v.createElement(m,{color:`gray`},` ${e.count}`))})),v.createElement(c,{items:[{key:`o`,label:`open in browser`},{key:`q`,label:`quit`}]}))};export{S as journeysCommand};
@@ -1 +0,0 @@
1
- import e from"open";async function t(t){await e(t)}const n=process.env.ZENOVAY_APP_BASE||`https://app.zenovay.com`;function r(e,t={}){let r=new URL(n),i={analytics:`analytics`,overview:`analytics`,watch:`analytics`,stats:`analytics`,live:`analytics`,sources:`analytics`,pages:`analytics`,devices:`analytics`,geo:`analytics`,visitors:`analytics`,globe:`globe`,vitals:`performance`,revenue:`revenue`,sessions:`sessions`,heatmaps:`heatmaps`,funnels:`insights`,funnel:`insights`,journeys:`journeys`,retention:`retention`,uptime:`uptime`,insights:`insights`,companies:`companies`,errors:`errors`};if(t.siteId&&e in i)return r.pathname=`/domains/${encodeURIComponent(t.siteId)}`,r.searchParams.set(`tab`,i[e]),r.toString();switch(e){case`analytics`:case`overview`:case`watch`:r.pathname=`/analytics`;break;case`live`:r.pathname=`/analytics/live`;break;case`sources`:r.pathname=`/analytics`,r.searchParams.set(`tab`,`sources`);break;case`pages`:r.pathname=`/analytics`,r.searchParams.set(`tab`,`pages`);break;case`devices`:r.pathname=`/analytics`,r.searchParams.set(`tab`,`devices`);break;case`geo`:r.pathname=`/analytics`,r.searchParams.set(`tab`,`geo`);break;case`visitors`:r.pathname=`/analytics`,r.searchParams.set(`tab`,`profiles`);break;case`globe`:r.pathname=`/domains`;break;case`stats`:r.pathname=`/analytics`;break;case`vitals`:r.pathname=`/web-vitals`;break;case`revenue`:r.pathname=`/revenue`;break;case`sessions`:r.pathname=`/sessions`;break;case`heatmaps`:r.pathname=`/heatmaps`;break;case`funnels`:case`funnel`:r.pathname=`/funnels`;break;case`journeys`:r.pathname=`/journeys`;break;case`retention`:r.pathname=`/retention`;break;case`uptime`:r.pathname=`/uptime`;break;case`insights`:r.pathname=`/insights`;break;case`companies`:r.pathname=`/companies`;break;case`errors`:r.pathname=`/errors`;break;case`domains`:r.pathname=`/websites`;break;case`api-keys`:r.pathname=`/api-keys`;break;case`team`:r.pathname=`/team`;break;case`settings`:r.pathname=`/settings`;break;case`plans`:case`billing`:r.pathname=`/billing`;break;case`integrations`:r.pathname=`/integrations`;break;case`goals`:r.pathname=`/goals`;break;case`notes`:r.pathname=`/notes`;break;case`audit`:r.pathname=`/audit`;break;case`share`:r.pathname=`/settings/share`;break;case`alerts`:r.pathname=`/alerts`;break;case`agency`:r.pathname=`/agency`;break;case`profile`:r.pathname=`/profile`;break;case`usage`:r.pathname=`/usage`;break;case`deploys`:r.pathname=`/deploys`;break;case`webhooks`:r.pathname=`/webhooks`;break;default:r.pathname=`/`}return t.siteId&&r.searchParams.set(`site`,t.siteId),r.toString()}export{r as deepLinkFor,t as openInBrowser};
@@ -1 +0,0 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import"./api-FCanTxsb.js";import{readToken as t}from"./token-store-BQuGH0z2.js";import"./telemetry-DRh10SvO.js";import{ApiV2Client as n}from"./api-v2-CI5hxW-O.js";import"./client-DTXWADkX.js";import"./formatter-DutfcQAc.js";import{emit$1 as r,isHeadless as i}from"./emit-DBYk96TD.js";import{Panel as a}from"./panel-B_yDcIcn.js";import{Banner as o}from"./banner-3iSWTDFy.js";import"./prompt-D-Uzz_GF.js";import{Keybar as s}from"./keybar-DsYTkKZX.js";import"./sparkline-BZ0eMB-w.js";import{ChatPanel as c}from"./chat-panel-CqJaCIg3.js";import{resolveSiteId as l}from"./resolve-site-mj0esTrm.js";import{EmptyState as u}from"./empty-state-CJxa1jUN.js";import{MetricCard as d}from"./metric-card-COEIZmbN.js";import{deepLinkFor as f,openInBrowser as p}from"./keybar-deep-link-DC31T3CP.js";import{Box as m,Text as h,render as g,useApp as _,useInput as v}from"ink";import y,{useEffect as b,useState as x}from"react";import S from"ink-spinner";async function C(a){let o=await e(),s=await t({strict:!1});if(!s)return process.stderr.write("Not logged in — run `zenovay login` first.\n"),2;let c=new n({config:o,cliVersion:a.cliVersion,token:s}),u,d;try{({siteId:u,site:d}=await l(c,{explicit:a.siteId,headless:!!a.json,cliVersion:a.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let f=d?.url?d.url.replace(/^https?:\/\//,``).replace(/\/$/,``):d?.name??u;if(i(a)){let e=await c.getLive(u);return r({type:`live.snapshot`,data:e}),0}return new Promise(e=>{let{unmount:t}=g(y.createElement(w,{api:c,siteId:u,siteLabel:f,cliVersion:a.cliVersion,onExit:n=>{t(),e(n)}}))})}const w=({api:e,siteId:t,siteLabel:n,cliVersion:r,onExit:i})=>{let{exit:l}=_(),[g,C]=x(null),[w,T]=x(!0),[E,D]=x(null),[O,k]=x(!1);if(v(e=>{if(!O){if(e===`/`){k(!0);return}if(e===`o`||e===`O`){p(f(`live`,{siteId:t}));return}e===`q`&&(l(),i(0))}}),b(()=>{if(O)return;let n=!1,r=async()=>{try{let r=await e.getLive(t);n||(C(r),T(!1),D(null))}catch(e){n||(D(e.message),T(!1))}};r();let i=setInterval(r,2e3);return()=>{n=!0,clearInterval(i)}},[e,t,O]),O)return y.createElement(c,{cliVersion:r,api:e,dashboardContext:{commandName:`live`,siteId:t,siteLabel:n,metricsSnapshot:g},onClose:()=>k(!1)});if(w)return y.createElement(m,{flexDirection:`column`},y.createElement(o,{version:r,subtitle:`live · ${n}`}),y.createElement(a,{title:`Loading`,state:`busy`},y.createElement(m,null,y.createElement(h,{color:`magenta`},y.createElement(S,{type:`dots`})),y.createElement(h,null,` Connecting…`))));if(E&&!g)return y.createElement(m,{flexDirection:`column`},y.createElement(o,{version:r,subtitle:`live · ${n}`}),y.createElement(u,{reason:`error`,headline:`Failed to load`,hint:E}));let A=process.stdout.columns??80,j=Math.max(20,Math.min(40,Math.floor(A/3)));return y.createElement(m,{flexDirection:`column`},y.createElement(o,{version:r,subtitle:`live · ${n}`}),y.createElement(d,{title:`Active now`,value:g?.activeVisitors??0,format:`number`,width:j}),y.createElement(a,{title:`Recent events`},!g||g.recentEvents.length===0?y.createElement(h,{color:`gray`},`— waiting for events —`):g.recentEvents.slice(0,15).map((e,t)=>y.createElement(m,{key:t},y.createElement(h,{color:`cyan`},(e.type??`pageview`).padEnd(10)),y.createElement(h,null,e.path.padEnd(36).slice(0,36)),y.createElement(h,{color:`gray`},e.country??`—`)))),y.createElement(s,{items:[{key:`/`,label:`ask AI`},{key:`o`,label:`open in browser`},{key:`q`,label:`quit`}]}))};export{C as liveCommand};
@@ -1 +0,0 @@
1
- import"./config--JRu_jFq.js";import"./api-FCanTxsb.js";import"./token-store-BQuGH0z2.js";import"./formatter-DutfcQAc.js";import"./emit-DBYk96TD.js";import{loginCommand as e}from"./login-yhuXiFqh.js";export{e as loginCommand};
@@ -1,2 +0,0 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import{ApiClient as t,pollDeviceToken as n,startDeviceAuthorization as r}from"./api-FCanTxsb.js";import{writeToken as i}from"./token-store-BQuGH0z2.js";import{emit$1 as a,isHeadless as o}from"./emit-DBYk96TD.js";import s from"node:path";import{promises as c}from"node:fs";import l from"node:os";import u from"open";async function d(s){let c=await e(),l=o({json:s.json}),d=await r({apiBase:c.apiBase}),f=d.verification_uri_complete??d.verification_uri;l?a({type:`info`,message:`Open ${f} and enter code ${d.user_code}`}):s.onCode?s.onCode({userCode:d.user_code,verificationUri:d.verification_uri,verificationUriComplete:d.verification_uri_complete}):process.stdout.write(`\n Open this URL to authorize the CLI:\n ${f}\n Or enter code: ${d.user_code}\n\n`);let p=s.openBrowser??!l;if(p)try{await u(f)}catch{}let m=await n({apiBase:c.apiBase,deviceCode:d.device_code,interval:d.interval,expiresIn:d.expires_in});await i(m);let h=new t({config:c,cliVersion:s.cliVersion,token:m}),_=await h.me().catch(()=>null);if(_){let e={...m,userId:_.user.id,teamId:_.team?.id,email:_.user.email};await i(e)}return l?a({type:`done`,command:`login`,exitCode:0}):await g().catch(()=>void 0),{email:_?.user.email}}function f(){let e=process.env.SHELL??``,t=l.homedir();if(e.endsWith(`/zsh`)||e.endsWith(`zsh`))return{shell:`zsh`,rcPath:s.join(t,`.zshrc`)};if(e.endsWith(`/bash`)||e.endsWith(`bash`)){let e=process.platform===`darwin`?s.join(t,`.bash_profile`):s.join(t,`.bashrc`);return{shell:`bash`,rcPath:e}}return e.endsWith(`/fish`)||e.endsWith(`fish`)?{shell:`fish`,rcPath:s.join(t,`.config`,`fish`,`config.fish`)}:null}const p=/zenovay\s+completions/;async function m(e,t){try{let n=await c.readFile(e,`utf8`);return t.test(n)}catch{return!1}}function h(e){return process.stdin.isTTY?new Promise(t=>{process.stdout.write(e),process.stdin.setEncoding(`utf8`);let n=e=>{process.stdin.removeListener(`data`,n);try{process.stdin.pause()}catch{}let r=e.trim().toLowerCase();return t(r===``||r===`y`||r===`yes`)};process.stdin.resume(),process.stdin.on(`data`,n)}):Promise.resolve(!1)}async function g(){let e=f();if(!e||await m(e.rcPath,p))return;let t=await h(`Install shell completions for ${e.shell}? [Y/n] `);if(!t){process.stdout.write(`Skipped. You can install later with: zenovay completions ${e.shell} >> ${e.rcPath}\n`);return}let n=e.shell===`fish`?`zenovay completions fish | source
2
- `:`eval "$(zenovay completions ${e.shell})"\n`;try{await c.mkdir(s.dirname(e.rcPath),{recursive:!0}),await c.appendFile(e.rcPath,`\n# Added by zenovay login\n${n}`,`utf8`),process.stdout.write(`✓ Completions installed. Restart your shell or source ${e.rcPath}.\n`)}catch(t){process.stdout.write(`Could not write ${e.rcPath} (${t.message}). Run manually: zenovay completions ${e.shell} >> ${e.rcPath}\n`)}}export{d as loginCommand};
@@ -1 +0,0 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import"./api-FCanTxsb.js";import{readToken as t}from"./token-store-BQuGH0z2.js";import{ApiV2Client as n}from"./api-v2-CI5hxW-O.js";import"./formatter-DutfcQAc.js";import{emit$1 as r,isHeadless as i}from"./emit-DBYk96TD.js";import{Panel as a}from"./panel-B_yDcIcn.js";import{Banner as o}from"./banner-3iSWTDFy.js";import"./prompt-D-Uzz_GF.js";import{Keybar as s}from"./keybar-DsYTkKZX.js";import{resolveSiteId as c}from"./resolve-site-mj0esTrm.js";import{DataTable as l}from"./data-table-BpbyyNSA.js";import{EmptyState as u}from"./empty-state-CJxa1jUN.js";import{deepLinkFor as d,openInBrowser as f}from"./keybar-deep-link-DC31T3CP.js";import{Box as p,Text as m,render as h,useApp as g,useInput as _}from"ink";import v,{useEffect as y,useState as b}from"react";import x from"ink-spinner";async function S(a){let o=await e(),s=await t({strict:!1});if(!s)return process.stderr.write("Not logged in — run `zenovay login` first.\n"),2;let l=new n({config:o,cliVersion:a.cliVersion,token:s}),u,d;try{({siteId:u,site:d}=await c(l,{explicit:a.siteId,headless:!!a.json,cliVersion:a.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let f=d?.url?d.url.replace(/^https?:\/\//,``).replace(/\/$/,``):d?.name??u;if(i(a)){let e=await l.getPages(u);return r({type:`pages.snapshot`,data:e}),0}return new Promise(e=>{let{unmount:t}=h(v.createElement(C,{api:l,siteId:u,siteLabel:f,cliVersion:a.cliVersion,onExit:n=>{t(),e(n)}}))})}const C=({api:e,siteId:t,siteLabel:n,cliVersion:r,onExit:i})=>{let{exit:c}=g(),[h,S]=b(null),[C,w]=b(!0),[T,E]=b(null);if(_(e=>{if(e===`o`||e===`O`){f(d(`pages`,{siteId:t}));return}e===`q`&&(c(),i(0))}),y(()=>{let n=!1;return(async()=>{try{let r=await e.getPages(t);n||(S(r),w(!1))}catch(e){n||(E(e.message),w(!1))}})(),()=>{n=!0}},[e,t]),C)return v.createElement(p,{flexDirection:`column`},v.createElement(o,{version:r,subtitle:`pages · ${n}`}),v.createElement(a,{title:`Loading`,state:`busy`},v.createElement(p,null,v.createElement(m,{color:`magenta`},v.createElement(x,{type:`dots`})),v.createElement(m,null,` Fetching pages…`))));if(T)return v.createElement(p,{flexDirection:`column`},v.createElement(o,{version:r,subtitle:`pages · ${n}`}),v.createElement(u,{reason:`error`,headline:`Failed to load`,hint:T}));if(!h||h.length===0)return v.createElement(p,{flexDirection:`column`},v.createElement(o,{version:r,subtitle:`pages · ${n}`}),v.createElement(u,{reason:`no-data`,headline:`No pages yet`,hint:`Visit your site to send the first event`}));let D=[{key:`path`,label:`path`,width:36},{key:`views`,label:`views`,align:`right`,width:8},{key:`uniqueVisitors`,label:`unique`,align:`right`,width:8},{key:`avgTime`,label:`avg time`,align:`right`,width:9,format:e=>typeof e==`number`?`${Math.round(e/1e3)}s`:`—`},{key:`bounceRate`,label:`bounce`,align:`right`,width:7,format:e=>typeof e==`number`?`${(e*100).toFixed(0)}%`:`—`}];return v.createElement(p,{flexDirection:`column`},v.createElement(o,{version:r,subtitle:`pages · ${n}`}),v.createElement(a,{title:`Top pages (${h.length})`},v.createElement(l,{columns:D,data:h,zebra:!0})),v.createElement(s,{items:[{key:`o`,label:`open in browser`},{key:`q`,label:`quit`}]}))};export{S as pagesCommand};
@@ -1 +0,0 @@
1
- import{Box as e,Text as t}from"ink";import n,{createContext as r,useContext as i,useEffect as a,useState as o}from"react";const s={xs:1,sm:2,md:3,lg:5,xl:8},c=e=>({headline:{color:e.fg,bold:!0},title:{color:e.fg,bold:!0},body:{color:e.fg},label:{color:e.dim,dim:!0,uppercase:!0},mono:{color:e.fg},caption:{color:e.muted}}),l={name:`mocha`,bg:`#1E1E2E`,fg:`#CDD6F4`,muted:`#6C7086`,accent:`#7DD3FC`,accent2:`#FDA4AF`,success:`#A6E3A1`,warn:`#F9E2AF`,error:`#F38BA8`,border:`#45475A`,dim:`#585B70`,spacing:s,radius:`round`,typography:c({fg:`#CDD6F4`,muted:`#6C7086`,accent:`#7DD3FC`,dim:`#585B70`})},u={name:`latte`,bg:`#EFF1F5`,fg:`#4C4F69`,muted:`#8C8FA1`,accent:`#7287FD`,accent2:`#EA76CB`,success:`#40A02B`,warn:`#DF8E1D`,error:`#D20F39`,border:`#BCC0CC`,dim:`#ACB0BE`,spacing:s,radius:`round`,typography:c({fg:`#4C4F69`,muted:`#8C8FA1`,accent:`#7287FD`,dim:`#ACB0BE`})},d={name:`dracula`,bg:`#282A36`,fg:`#F8F8F2`,muted:`#6272A4`,accent:`#BD93F9`,accent2:`#FF79C6`,success:`#50FA7B`,warn:`#F1FA8C`,error:`#FF5555`,border:`#44475A`,dim:`#6272A4`,spacing:s,radius:`round`,typography:c({fg:`#F8F8F2`,muted:`#6272A4`,accent:`#BD93F9`,dim:`#6272A4`})},f={name:`tokyoNight`,bg:`#1A1B26`,fg:`#C0CAF5`,muted:`#565F89`,accent:`#7AA2F7`,accent2:`#BB9AF7`,success:`#9ECE6A`,warn:`#E0AF68`,error:`#F7768E`,border:`#3B4261`,dim:`#414868`,spacing:s,radius:`round`,typography:c({fg:`#C0CAF5`,muted:`#565F89`,accent:`#7AA2F7`,dim:`#414868`})},p={name:`nord`,bg:`#2E3440`,fg:`#D8DEE9`,muted:`#4C566A`,accent:`#88C0D0`,accent2:`#81A1C1`,success:`#A3BE8C`,warn:`#EBCB8B`,error:`#BF616A`,border:`#3B4252`,dim:`#434C5E`,spacing:s,radius:`round`,typography:c({fg:`#D8DEE9`,muted:`#4C566A`,accent:`#88C0D0`,dim:`#434C5E`})},m={from:`#7D56F4`,to:`#FF5FD1`},h=r({theme:l});function g(){return i(h)}function _(e,t,n){if(n)return e.accent;switch(t){case`busy`:return e.accent;case`ok`:return e.success;case`warn`:return e.warn;case`err`:return e.error;case`idle`:default:return e.border}}function v(){let e=process.stdout.columns;return typeof e==`number`&&e>0?e:80}function y({title:r,state:i=`idle`,pillColor:a,width:o,focused:s=!1,density:c=`comfortable`,children:l}){let{theme:u}=g(),d=_(u,i,s),f=o??v(),p=a??d,m=c===`compact`?``:` `,h=`╭─ `,y=` ─╮`,b=r??``,x=r?b.length:0,S=2,C=r?h.length+x+y.length+S<=f:!0,w=r?h.length+x+y.length:4,T=Math.max(S,f-w),E=r&&C?n.createElement(e,{flexDirection:`row`},n.createElement(t,{color:d},h),n.createElement(t,{color:p,bold:!0},b),n.createElement(t,{color:d},y,`─`.repeat(T))):r?n.createElement(e,{flexDirection:`column`},n.createElement(e,{flexDirection:`row`},n.createElement(t,{color:d},`╭`,`─`.repeat(Math.max(2,f-2)),`╮`)),n.createElement(e,{flexDirection:`row`},n.createElement(t,{color:d},`│ `),n.createElement(e,{flexGrow:1},n.createElement(t,{color:p,bold:!0},b)),n.createElement(t,{color:d},` │`))):n.createElement(e,{flexDirection:`row`},n.createElement(t,{color:d},`╭`,`─`.repeat(Math.max(2,f-2)),`╮`)),D=n.createElement(e,{flexDirection:`row`},n.createElement(t,{color:d},`╰`,`─`.repeat(Math.max(2,f-2)),`╯`));return n.createElement(e,{flexDirection:`column`},E,n.createElement(e,{flexDirection:`row`},n.createElement(t,{color:d},`│`,m),n.createElement(e,{flexDirection:`column`,flexGrow:1},l),n.createElement(t,{color:d},m,`│`)),D)}export{m as BRAND_GRADIENT,y as Panel,d as dracula,u as latte,l as mocha,p as nord,f as tokyoNight,g as useTheme};
@@ -1,3 +0,0 @@
1
- import{BRAND_GRADIENT as e,useTheme as t}from"./panel-B_yDcIcn.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)}const d=({done:e,total:a,label:o})=>{let{theme:s}=t(),c=a>0&&e>=a,l=c?s.success:s.accent,u=c?`Done`:o??``;return i.createElement(n,{flexDirection:`row`},i.createElement(r,{color:l},`[`,e,`/`,a,`]`),u?i.createElement(r,{color:s.fg},` `,u):null)};export{u as BrandGradient,d as ProgressRow};
@@ -1,2 +0,0 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import"./api-FCanTxsb.js";import{readToken as t}from"./token-store-BQuGH0z2.js";import"./telemetry-DRh10SvO.js";import{ApiV2Client as n}from"./api-v2-CI5hxW-O.js";import"./client-DTXWADkX.js";import{formatTabular as r,selectFormat as i}from"./formatter-DutfcQAc.js";import"./panel-B_yDcIcn.js";import"./banner-3iSWTDFy.js";import"./prompt-D-Uzz_GF.js";import"./keybar-DsYTkKZX.js";import"./chat-panel-CqJaCIg3.js";import{resolveSiteId as a}from"./resolve-site-mj0esTrm.js";import{DataTable as o}from"./data-table-BpbyyNSA.js";import{runAnalyticalScreen as s}from"./analytical-screen-BasvNR-9.js";import{Text as c}from"ink";import l from"react";function u(){let e=process.stdout.columns??80,t=Math.max(40,e-4-18),n=1,r=t-n,i=Math.max(8,Math.floor(r*.3)),a=Math.max(8,Math.floor(r*.32)),o=Math.max(4,Math.floor(r*.1)),s=Math.max(6,Math.floor(r*.12)),c=Math.max(4,r-i-a-o-s);return{current:n,name:i,domain:a,tier:o,pageviews24h:s,id:c}}async function d(d){let f=await e(),p=await t({strict:!1}),m=new n({config:f,cliVersion:d.cliVersion,token:p}),h,g;try{({siteId:h,site:g}=await a(m,{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 _=i(d),v=u(),y=[{key:`isCurrent`,label:``,width:v.current,format:e=>e?`*`:` `},{key:`name`,label:`project`,width:v.name},{key:`domain`,label:`domain`,width:v.domain,format:e=>String(e??`—`)},{key:`tier`,label:`tier`,width:v.tier},{key:`pageviews24h`,label:`24h pv`,width:v.pageviews24h,align:`right`},{key:`id`,label:`id`,width:v.id}];return s({cliVersion:d.cliVersion,title:`projects · ${p?.teamId??`—`}`,commandName:`projects`,authToken:p?.accessToken??null,refreshIntervalMs:0,fetcher:e=>m.getProjects(h,e),format:_,headlessEmit:(e,t)=>{if(t===`json`||t===`ndjson`){if(t===`ndjson`)for(let t of e.projects)process.stdout.write(JSON.stringify(t)+`
2
- `);else process.stdout.write(JSON.stringify(e,null,2));return}process.stdout.write(r(e.projects,[`id`,`name`,`domain`,`tier`,`pageviews24h`,`isCurrent`],t))},keybindings:{s:{label:`switch project (logout + login)`,handler:()=>{process.stderr.write("To switch project: run `zenovay logout` then `zenovay login`.\n")}}},panels:[{id:`projects`,title:`Projects`,render:e=>e.projects.length===0?l.createElement(c,{color:`gray`},`— no projects yet —`):l.createElement(o,{data:e.projects,columns:y,headerStyle:`accent`})}]})}export{d as projectsCommand};
@@ -1,8 +0,0 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import"./api-FCanTxsb.js";import{readToken as t}from"./token-store-BQuGH0z2.js";import{ApiV2Client as n}from"./api-v2-CI5hxW-O.js";import{requireTier as r}from"./tier-BneaO4vD.js";import{formatTabular as i,selectFormat as a}from"./formatter-DutfcQAc.js";import{Panel as o}from"./panel-B_yDcIcn.js";import{Banner as s}from"./banner-3iSWTDFy.js";import"./progress-row-BpAXjJPL.js";import"./prompt-D-Uzz_GF.js";import"./keybar-DsYTkKZX.js";import"./sparkline-BZ0eMB-w.js";import{resolveSiteId as c}from"./resolve-site-mj0esTrm.js";import{DataTable as l}from"./data-table-BpbyyNSA.js";import"./bar-DWT-1xOE.js";import"./ui-Cey-h6wI.js";import{Box as u,Text as d,useApp as f,useInput as p}from"ink";import m,{useMemo as h,useState as g}from"react";import _ from"ink-text-input";function v({api:e,siteId:t,maxRows:n}){let{exit:r}=f(),[i,a]=g(``),[c,v]=g(null),[y,b]=g(null),[x,S]=g(!1),[C,w]=g([]);p((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),a(``)}}},E=h(()=>c?c.columns.map(e=>({key:e,label:e,width:18,format:e=>e==null?`∅`:String(e).slice(0,18)})):[],[c]);return m.createElement(u,{flexDirection:`column`},m.createElement(s,{version:`query`}),m.createElement(o,{title:`History`,state:`idle`},C.length===0?m.createElement(d,{color:`gray`},`— no queries yet — Esc or \\q to exit —`):C.slice(-5).map((e,t)=>m.createElement(d,{key:t,color:`gray`},`> ${e.slice(0,80)}${e.length>80?`…`:``}`))),m.createElement(u,null,m.createElement(d,{color:`magenta`},`sql`,`>`,` `),m.createElement(_,{value:i,onChange:a,onSubmit:T})),x?m.createElement(d,{color:`gray`},`running…`):null,y?m.createElement(o,{title:`Error`,state:`err`},m.createElement(d,{color:`red`},y)):null,c?m.createElement(o,{title:`${c.row_count} rows · ${c.duration_ms}ms${c.truncated?` · truncated`:``}`,state:`ok`},c.row_count===0?m.createElement(d,{color:`gray`},`— empty —`):m.createElement(l,{data:c.rows.slice(0,50),columns:E,headerStyle:`accent`})):null)}async function y(o){let s=await e(),l=await t({strict:!1}),u=new n({config:s,cliVersion:o.cliVersion,token:l});try{await r(u,`scale`)}catch(e){return process.stderr.write(`${e.message}\n`),2}let d;try{({siteId:d}=await c(u,{explicit:o.siteId,headless:!!(o.json||o.csv||o.tsv||o.ndjson),cliVersion:o.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let f=o.maxRows??1e3,p=a(o);if(o.sql)try{let e=await u.runSqlQuery(d,o.sql,{maxRows:f});if(p===`json`)process.stdout.write(JSON.stringify(e,null,2)),process.stdout.write(`
2
- `);else if(p===`ndjson`)for(let t of e.rows)process.stdout.write(JSON.stringify(t)+`
3
- `);else if(p===`csv`||p===`tsv`)process.stdout.write(i(e.rows,e.columns,p));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:h}=await import(`ink`);return await h(m.createElement(v,{api:u,siteId:d,maxRows:f})).waitUntilExit(),0}export{y as queryCommand};
@@ -1,2 +0,0 @@
1
- import{readConfig as e,updateConfig as t}from"./config--JRu_jFq.js";import{Panel as n}from"./panel-B_yDcIcn.js";import{Banner as r}from"./banner-3iSWTDFy.js";import{Select as i}from"./prompt-D-Uzz_GF.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
- `),t=a[0]?a[0].url.replace(/^https?:\/\//,``).replace(/\/$/,``):`<domain>`;throw Error(`Multiple sites found — pick one:\n${e}\n\nPass --site-id <ID>, set ZENOVAY_SITE=<ID>, or run \`zenovay use ${t}\` 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};