@zenovay/cli 1.0.0 → 1.0.2

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 (96) hide show
  1. package/README.md +1 -1
  2. package/dist/{agency-DHAyzKd-.js → agency-cNkRWBOo.js} +1 -1
  3. package/dist/{ai-xhCcy02q.js → ai-BkP3oeh2.js} +1 -1
  4. package/dist/{alerts-Be0XKEUX.js → alerts-BQ0EMdBT.js} +1 -1
  5. package/dist/{analytical-screen-BU2yCSg_.js → analytical-screen-BvQa8oH6.js} +1 -1
  6. package/dist/analytics-S6AFt20R.js +1 -0
  7. package/dist/{annotation-dveH657H.js → annotation-CZ2bEuyD.js} +1 -1
  8. package/dist/{api-hWp9s3Y8.js → api-CdcB84ie.js} +1 -1
  9. package/dist/{api-keys-DKQX5aL9.js → api-keys-CLol-4YC.js} +1 -1
  10. package/dist/api-v2-Co0dWAP5.js +1 -0
  11. package/dist/{api-v2-DqKh6FgZ.js → api-v2-D0mvt__4.js} +1 -1
  12. package/dist/{audit-DgHopH-O.js → audit-CFlSb0g5.js} +1 -1
  13. package/dist/bin.js +7 -7
  14. package/dist/{chat-panel-PSN5hjlF.js → chat-panel-D9IjovCR.js} +1 -1
  15. package/dist/{companies-uScE2uHf.js → companies-Cpb3yv2Q.js} +1 -1
  16. package/dist/{completions-DKyjFPMK.js → completions-XLznfo7H.js} +1 -1
  17. package/dist/{config-DB3jF5gG.js → config-B72_Kfe0.js} +1 -1
  18. package/dist/{config--JRu_jFq.js → config-JVhBplSX.js} +1 -1
  19. package/dist/{csv-emit-CmlDBfbA.js → csv-emit-B-5km-O-.js} +1 -1
  20. package/dist/{deploys-BqQmCzVb.js → deploys-DZ0IR9Re.js} +1 -1
  21. package/dist/{devices-CUgpkbAC.js → devices-C_NjBY89.js} +1 -1
  22. package/dist/{doctor-D1bGGwtN.js → doctor-BsEuqZTb.js} +1 -1
  23. package/dist/{domains-iRmYn9G7.js → domains-ByXV1O4R.js} +1 -1
  24. package/dist/error-codes-BiKo9PGm.js +1 -0
  25. package/dist/{error-codes-D4XO4okw.js → error-codes-ByhvHx2M.js} +1 -1
  26. package/dist/{errors-CEIyrEgF.js → errors-DPRcy7WT.js} +1 -1
  27. package/dist/{events-tail-CRgba_gO.js → events-tail-DEdVkmT0.js} +1 -1
  28. package/dist/{export-Csl7rWLW.js → export-DhSRfpg_.js} +1 -1
  29. package/dist/{funnel-B36lGX2i.js → funnel-Cb4-3RJB.js} +1 -1
  30. package/dist/{geo-CPt2etQd.js → geo-ReUNKl3F.js} +1 -1
  31. package/dist/{globe-yy_-G4K8.js → globe-DwaTDQns.js} +1 -1
  32. package/dist/{goals-BTzgvDOK.js → goals-Ds0QZ4H6.js} +1 -1
  33. package/dist/{health-D26VB-iZ.js → health-D6w7hF5q.js} +1 -1
  34. package/dist/{health-RsLcvYTb.js → health-DTR77eQW.js} +1 -1
  35. package/dist/{heatmaps-D4o0Ghjn.js → heatmaps-B-As729q.js} +1 -1
  36. package/dist/{home-B8CoN9Hd.js → home-DGYBSPWi.js} +1 -1
  37. package/dist/{init-Cee2-8Kd.js → init-igNlvq0N.js} +6 -6
  38. package/dist/init-x1CXZTzr.js +1 -0
  39. package/dist/{insights-B0L6kIxY.js → insights-BiqMftak.js} +1 -1
  40. package/dist/{integrations-CJ9Pa-II.js → integrations-CCvt4xb_.js} +1 -1
  41. package/dist/{journeys--jjaTA3C.js → journeys-CogDUObU.js} +1 -1
  42. package/dist/{live-CuVd6yRs.js → live-BNX4HBCf.js} +1 -1
  43. package/dist/login-CDAP0iKS.js +1 -0
  44. package/dist/{login-CsQ7fPVu.js → login-DU1fY88U.js} +1 -1
  45. package/dist/{logout-C3KOOdIM.js → logout-BoUfEnN9.js} +1 -1
  46. package/dist/{notes-jV1DYMp_.js → notes-BrY4efpr.js} +1 -1
  47. package/dist/{analytics-D7vhDrdG.js → overview-CmTIumZy.js} +2 -2
  48. package/dist/overview-L8jqiSuU.js +1 -0
  49. package/dist/{pages-0DLiuGYc.js → pages-BYVz90uO.js} +1 -1
  50. package/dist/{plans-D4o6-tbv.js → plans-DT8hilXl.js} +1 -1
  51. package/dist/{profile-Cm5RFs_L.js → profile-CDY3kFEq.js} +1 -1
  52. package/dist/{projects-BTTgnjOZ.js → projects-BdRZaLg8.js} +1 -1
  53. package/dist/{query-yn10M321.js → query-DLC0vi-K.js} +1 -1
  54. package/dist/{resolve-site-BLrtFOyW.js → resolve-site-BTVBMF1C.js} +1 -1
  55. package/dist/{retention-DpBuavgY.js → retention-DQHXVSG0.js} +1 -1
  56. package/dist/{revenue-Bv1Cqzjr.js → revenue-CitFZ4DN.js} +1 -1
  57. package/dist/{self-test-Cml0QXeA.js → self-test-BcCqMRQ9.js} +2 -2
  58. package/dist/{sessions-B0RwtHvP.js → sessions-dPZ32wpz.js} +1 -1
  59. package/dist/{settings-i4TqMmAY.js → settings-DO8UOasX.js} +1 -1
  60. package/dist/{share-DTHFqTzp.js → share-BkvKZuPo.js} +1 -1
  61. package/dist/{site-switcher-D_JBKFaR.js → site-switcher-BAoYWp18.js} +1 -1
  62. package/dist/{sources-B39BFFKF.js → sources-lvpcvTTz.js} +1 -1
  63. package/dist/{stats-Dh9MQAXx.js → stats-EeSDu70A.js} +1 -1
  64. package/dist/{status-agent-C3q7fOEs.js → status-agent-BLIJc81G.js} +1 -1
  65. package/dist/{team-DZtvClMF.js → team-Bw6dcpI2.js} +1 -1
  66. package/dist/{teams-CqJFecKB.js → teams-cwzXaqBH.js} +1 -1
  67. package/dist/{telemetry-DRh10SvO.js → telemetry-BV-xvfdt.js} +1 -1
  68. package/dist/telemetry-Bbh6Vtst.js +1 -0
  69. package/dist/{telemetry-BdWnMaJC.js → telemetry-CgyMy4hV.js} +1 -1
  70. package/dist/{tier-BneaO4vD.js → tier-DDIroQbc.js} +1 -1
  71. package/dist/{token-store-BQuGH0z2.js → token-store-BvSCse1t.js} +1 -1
  72. package/dist/token-store-QTNSg4TT.js +1 -0
  73. package/dist/{update-CoZzBsMu.js → update-DkMxLJbM.js} +1 -1
  74. package/dist/{uptime-Ck1GdjRR.js → uptime-BA8vRzJQ.js} +1 -1
  75. package/dist/{usage-BN_mEsal.js → usage-CkyXScnm.js} +1 -1
  76. package/dist/{use-NGqXzASp.js → use-BW8rVPgW.js} +1 -1
  77. package/dist/{visitors-BCz-O9rK.js → visitors-mjvSIKkI.js} +1 -1
  78. package/dist/{vitals-Dx_eY6tW.js → vitals-D3sMQksQ.js} +1 -1
  79. package/dist/{webhooks-BR1D3o5S.js → webhooks-D1PNfhgJ.js} +1 -1
  80. package/dist/{webhooks-forward-CpXm4GHn.js → webhooks-forward-B8nnKB4f.js} +1 -1
  81. package/dist/wizard-bin.js +1 -1
  82. package/package.json +1 -1
  83. package/dist/api-v2-C7-5GPx8.js +0 -1
  84. package/dist/error-codes-DpKbL-uM.js +0 -1
  85. package/dist/init-BrxmKAnU.js +0 -1
  86. package/dist/login-DeznxBjS.js +0 -1
  87. package/dist/telemetry-C1045t6Q.js +0 -1
  88. package/dist/token-store-TmBx42nv.js +0 -1
  89. package/dist/watch-CP-Klikt.js +0 -1
  90. /package/dist/{commands-BE8-kQ9U.js → commands-DVRYYbbn.js} +0 -0
  91. /package/dist/{csv-emit-C-9o-imN.js → csv-emit-BiRGo6SK.js} +0 -0
  92. /package/dist/{examples-DikBW-H2.js → examples-CsQBLv9W.js} +0 -0
  93. /package/dist/{range-tabs-BbJdVWNV.js → range-tabs-CH2cEXOf.js} +0 -0
  94. /package/dist/{themes-6H0KlK3b.js → themes-BC8U4Od4.js} +0 -0
  95. /package/dist/{tour-fOYY-mK0.js → tour-ChHRo89U.js} +0 -0
  96. /package/dist/{ui-C5Te-OTJ.js → ui-BTnLAro-.js} +0 -0
@@ -1,4 +1,4 @@
1
- import{readConfig as e,updateConfig as t}from"./config--JRu_jFq.js";import{ApiClient as n,dashboardUrlForSite as r}from"./api-hWp9s3Y8.js";import{readToken as i}from"./token-store-BQuGH0z2.js";import{emit$1 as a,isHeadless as o}from"./emit-D4YlMlzk.js";import{openInBrowser as s}from"./open-url-BtI5aLgL.js";import{scrubSecrets as c}from"./secrets-ApB7yh2A.js";import{parseSseStream as l}from"./client-ntsEXSVC.js";import{loginCommand as u,maybeInstallCompletions as d}from"./login-CsQ7fPVu.js";import{Banner as f,Panel as p,useTheme as m}from"./panel-CTtQ2ue6.js";import{DiffView as h,ProgressRow as g}from"./progress-row-Afnt5Ng8.js";import{Select as _}from"./prompt-BXvg2B4R.js";import{Keybar as v}from"./keybar-DO5OoZy9.js";import{spark as y}from"./sparkline-CpoBjjlc.js";import b from"node:path";import{promises as x}from"node:fs";import{z as S}from"zod";import C from"node:os";import w from"node:crypto";import{ulid as T}from"ulid";import{Box as E,Text as D,render as ee,useApp as te,useInput as O}from"ink";import k from"node:fs/promises";import A,{useEffect as j,useRef as M,useState as N}from"react";import{globby as P}from"globby";import F from"ink-spinner";import{applyPatch as ne}from"diff";const I=[`@zenovay/tracker`,`@zenovay/next`,`@zenovay/nuxt`,`@zenovay/svelte`,`@zenovay/astro`,`@zenovay/remix`,`@zenovay/node`],re=[`zenovay.config.ts`,`zenovay.config.js`,`zenovay.config.mjs`,`zenovay.config.json`],ie=/<[Ss]cript\b[^>]*\bsrc\s*=\s*["'`]https:\/\/(?:api|cdn)\.zenovay\.com\/[^"'`]+["'`][^>]*>/gi,ae=/["'`]https:\/\/(?:api|cdn)\.zenovay\.com\/[^"'`]*z\.js[^"'`]*["'`]/gi,oe=/["']?data-?[Ii]d["']?\s*[=:]\s*["'`](ZV_[A-Za-z0-9]+)["'`]/i,L=/data-zenovay-site\s*[=:]\s*["'`]([^"'`]+)["'`]/i,R=/\binit\s*\(\s*['"`](ZV_[A-Za-z0-9]+)['"`]/g,z=[{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 B(e,t){let n={zenovayInstalled:!1,correctTrackingCode:!1,foundTrackingCodes:[],zenovayFiles:[],competitors:[],summary:``,recommendation:`fresh-install`};try{let t=await x.readFile(b.join(e,`package.json`),`utf8`),r=JSON.parse(t),i={...r.dependencies,...r.devDependencies};for(let e of I)if(e in i){n.zenovayInstalled=!0,n.packageMarker=e;break}}catch{}for(let t of re)try{await x.access(b.join(e,t)),n.zenovayInstalled=!0,n.configFile=t;break}catch{}let r=await P([`**/*.{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 x.readFile(t,`utf8`)}catch{continue}let o=b.relative(e,t);ie.lastIndex=0,ae.lastIndex=0;let s=r.match(ie),c=r.match(ae),l=(s?.length??0)+(c?.length??0);if(l>0){n.zenovayInstalled=!0;let e=(s?.[0]??c?.[0]??``).slice(0,200),t=r.match(oe)??r.match(L),i=t?.[1]??null;i&&a.add(i),n.zenovayFiles.push({file:o,currentTrackingCode:i,scriptTagCount:l,matchSample:e})}if(l===0&&/\.[jt]sx?$/.test(t)){R.lastIndex=0;let e;for(;(e=R.exec(r))!==null;){let t=e[1];a.add(t),n.zenovayInstalled=!0,n.zenovayFiles.push({file:o,currentTrackingCode:t,scriptTagCount:0,matchSample:e[0].slice(0,80)})}}for(let e of z)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=se(n,t),n}function se(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 ce(e){let t=await B(e,``);return{installed:t.zenovayInstalled,reasons:t.summary?[t.summary]:[],packageMarker:t.packageMarker,configFile:t.configFile,scriptFile:t.zenovayFiles[0]?.file}}const le=[/^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)$/,/^src\/app\/.*\.(tsx|ts|jsx|js)$/,/^src\/pages\/.*\.(tsx|ts|jsx|js)$/,/^src\/components\/.*\.(astro|svelte|vue|tsx|ts|jsx|js)$/,/^src\/(root|app|entry-server|entry-client)\.(tsx|ts|jsx|js)$/,/^gatsby-(ssr|browser|config)\.(js|ts|mjs)$/,/\.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)$/],ue=[/(^|\/)\.env($|\.(?!example$)[^/]+$)/,/(^|\/)\.git(\/|$)/,/(^|\/)node_modules\//,/(^|\/)\.ssh\//,/(^|\/)\.aws\//,/\.pem$/,/\.key$/,/(^|\/)id_rsa($|\.)/,/(^|\/)\.npmrc$/,/(^|\/)credentials(\.|$)/],V=256*1024,de=50,fe=20,pe=40;var H=class extends Error{constructor(e,t){super(t),this.code=e,this.name=`SandboxError`}};const U=/<script[^>]*src\s*=\s*["']https:\/\/(?:api|cdn)\.zenovay\.com\/[^"']+["'][^>]*>\s*<\/script>/i,me=[{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 he=class{sessionId;cwd;cwdReal;undoRoot;readCount=0;writeCount=0;roundCount=0;writtenPathsSet=new Set;constructor(e){this.sessionId=e.sessionId??T(),this.cwd=e.cwd,this.cwdReal=x.realpath(e.cwd),this.undoRoot=e.undoRoot??b.join(C.homedir(),`.zenovay`,`undo`)}incrementRound(){if(this.roundCount++,this.roundCount>pe)throw new H(`round-cap`,`Tool-call recursion cap (${pe}) 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 H(`escape`,`Path must be a non-empty string.`);if(e.includes(`\0`))throw new H(`escape`,`Null byte in path.`);if(/^\\\\[?.]\\/.test(e)||/^\\\\[A-Za-z0-9]/.test(e))throw new H(`escape`,`Windows special path prefix: ${e}`);if(/%/.test(e))try{let t=decodeURIComponent(e);if(/%[0-9A-Fa-f]{2}/.test(t))throw new H(`escape`,`Double-encoded path: ${e}`);e=t}catch(t){throw t instanceof H?t:new H(`escape`,`Malformed percent-encoding: ${e}`)}if(e.includes(`\0`))throw new H(`escape`,`Null byte in decoded path.`);if(e.includes(`\\`))throw new H(`escape`,`Backslash in path (Windows-style separator not accepted): ${e}`);let n=await this.cwdReal,r=b.isAbsolute(e)?e:b.join(n,e),i=b.normalize(r),a=i;try{a=await x.realpath(i)}catch(e){if(e.code!==`ENOENT`)throw new H(`escape`,`realpath failed: ${e.message}`);let t=b.dirname(i);try{let e=await x.realpath(t);a=b.join(e,b.basename(i))}catch{}}if(!this.isWithin(a,n))throw new H(`escape`,`Path escapes cwd: ${e}`);let o=b.relative(n,a),s=o.toLowerCase();for(let e of ue)if(e.test(o)||e.test(s)){if(t===`read`&&/(^|\/)node_modules\//i.test(o))continue;throw new H(`blocklisted`,`Path is on the hard blocklist: ${o}`)}if(t===`write`){let e=le.some(e=>e.test(o));if(!e&&!/^\.env(\.local)?$/.test(o)&&!/^\.claude\//.test(o)&&!/^\.cursor\//.test(o))throw new H(`not-allowlisted`,`Write path not on allowlist: ${o}`)}return a}isWithin(e,t){let n=b.relative(t,e);return!n.startsWith(`..`)&&!b.isAbsolute(n)}async safeRead(e){if(this.readCount>=de)throw new H(`read-cap`,`Read cap (${de}) reached.`);let t=await this.resolveForRead(e),n=await x.stat(t);if(n.size>V)throw new H(`too-large`,`File exceeds ${V}B: ${e} (${n.size}B)`);let r=await x.readFile(t),i=r.subarray(0,Math.min(r.length,8192));if(i.includes(0))throw new H(`binary-rejected`,`Binary content in ${e}.`);return this.readCount++,r.toString(`utf8`)}async safeWrite(e,t){if(this.writeCount>=fe)throw new H(`write-cap`,`Write cap (${fe}) reached.`);if(t.length>V)throw new H(`too-large`,`Write exceeds ${V}B: ${e}`);let n=await this.resolveForWrite(e),r=await x.readFile(n,`utf8`).catch(e=>{if(e.code===`ENOENT`)return null;throw e});if(r!==null){if(U.test(r)&&!U.test(t))throw new H(`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 me)if(i.test(r)&&!i.test(t))throw new H(`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 x.mkdir(b.dirname(n),{recursive:!0}),await x.writeFile(n,t,`utf8`),this.writeCount++;let a=await this.cwdReal;return this.writtenPathsSet.add(b.relative(a,n)),{backupPath:i}}async journalBackup(e){let t=await x.readFile(e).catch(e=>{if(e.code===`ENOENT`)return null;throw e}),n=b.join(this.undoRoot,this.sessionId);await x.mkdir(n,{recursive:!0,mode:448});let r=w.createHash(`sha256`).update(e).digest(`hex`).slice(0,16),i=b.join(n,`${r}.bak`),a=b.join(n,`manifest.jsonl`);t&&await x.writeFile(i,t,{mode:384});let o=JSON.stringify({abs:e,backupPath:t?i:null,ts:Date.now()});return await x.appendFile(a,o+`
1
+ import{readConfig as e,updateConfig as t}from"./config-JVhBplSX.js";import{ApiClient as n,dashboardUrlForSite as r}from"./api-CdcB84ie.js";import{readToken as i}from"./token-store-BvSCse1t.js";import{emit$1 as a,isHeadless as o}from"./emit-D4YlMlzk.js";import{openInBrowser as s}from"./open-url-BtI5aLgL.js";import{scrubSecrets as c}from"./secrets-ApB7yh2A.js";import{parseSseStream as l}from"./client-ntsEXSVC.js";import{loginCommand as u,maybeInstallCompletions as d}from"./login-DU1fY88U.js";import{Banner as f,Panel as p,useTheme as m}from"./panel-CTtQ2ue6.js";import{DiffView as h,ProgressRow as g}from"./progress-row-Afnt5Ng8.js";import{Select as _}from"./prompt-BXvg2B4R.js";import{Keybar as v}from"./keybar-DO5OoZy9.js";import{spark as y}from"./sparkline-CpoBjjlc.js";import b from"node:path";import{promises as x}from"node:fs";import{z as S}from"zod";import C from"node:os";import w from"node:crypto";import{ulid as T}from"ulid";import{Box as E,Text as D,render as ee,useApp as te,useInput as O}from"ink";import k from"node:fs/promises";import A,{useEffect as j,useRef as ne,useState as M}from"react";import{globby as N}from"globby";import P from"ink-spinner";import{applyPatch as F}from"diff";const re=[`@zenovay/tracker`,`@zenovay/next`,`@zenovay/nuxt`,`@zenovay/svelte`,`@zenovay/astro`,`@zenovay/remix`,`@zenovay/node`],I=[`zenovay.config.ts`,`zenovay.config.js`,`zenovay.config.mjs`,`zenovay.config.json`],ie=/<[Ss]cript\b[^>]*\bsrc\s*=\s*["'`]https:\/\/(?:api|cdn)\.zenovay\.com\/[^"'`]+["'`][^>]*>/gi,ae=/["'`]https:\/\/(?:api|cdn)\.zenovay\.com\/[^"'`]*z\.js[^"'`]*["'`]/gi,oe=/["']?data-?[Ii]d["']?\s*[=:]\s*["'`](ZV_[A-Za-z0-9]+)["'`]/i,se=/data-zenovay-site\s*[=:]\s*["'`]([^"'`]+)["'`]/i,L=/\binit\s*\(\s*['"`](ZV_[A-Za-z0-9]+)['"`]/g,R=[{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 z(e,t){let n={zenovayInstalled:!1,correctTrackingCode:!1,foundTrackingCodes:[],zenovayFiles:[],competitors:[],summary:``,recommendation:`fresh-install`};try{let t=await x.readFile(b.join(e,`package.json`),`utf8`),r=JSON.parse(t),i={...r.dependencies,...r.devDependencies};for(let e of re)if(e in i){n.zenovayInstalled=!0,n.packageMarker=e;break}}catch{}for(let t of I)try{await x.access(b.join(e,t)),n.zenovayInstalled=!0,n.configFile=t;break}catch{}let r=await N([`**/*.{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 x.readFile(t,`utf8`)}catch{continue}let o=b.relative(e,t);ie.lastIndex=0,ae.lastIndex=0;let s=r.match(ie),c=r.match(ae),l=(s?.length??0)+(c?.length??0);if(l>0){n.zenovayInstalled=!0;let e=(s?.[0]??c?.[0]??``).slice(0,200),t=r.match(oe)??r.match(se),i=t?.[1]??null;i&&a.add(i),n.zenovayFiles.push({file:o,currentTrackingCode:i,scriptTagCount:l,matchSample:e})}if(l===0&&/\.[jt]sx?$/.test(t)){L.lastIndex=0;let e;for(;(e=L.exec(r))!==null;){let t=e[1];a.add(t),n.zenovayInstalled=!0,n.zenovayFiles.push({file:o,currentTrackingCode:t,scriptTagCount:0,matchSample:e[0].slice(0,80)})}}for(let e of R)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=B(n,t),n}function B(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 ce(e){let t=await z(e,``);return{installed:t.zenovayInstalled,reasons:t.summary?[t.summary]:[],packageMarker:t.packageMarker,configFile:t.configFile,scriptFile:t.zenovayFiles[0]?.file}}const le=[/^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)$/,/^src\/app\/.*\.(tsx|ts|jsx|js)$/,/^src\/pages\/.*\.(tsx|ts|jsx|js)$/,/^src\/components\/.*\.(astro|svelte|vue|tsx|ts|jsx|js)$/,/^src\/(root|app|entry-server|entry-client)\.(tsx|ts|jsx|js)$/,/^gatsby-(ssr|browser|config)\.(js|ts|mjs)$/,/\.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)$/],ue=[/(^|\/)\.env($|\.(?!example$)[^/]+$)/,/(^|\/)\.git(\/|$)/,/(^|\/)node_modules\//,/(^|\/)\.ssh\//,/(^|\/)\.aws\//,/\.pem$/,/\.key$/,/(^|\/)id_rsa($|\.)/,/(^|\/)\.npmrc$/,/(^|\/)credentials(\.|$)/],V=256*1024,de=50,fe=20,pe=40;var H=class extends Error{constructor(e,t){super(t),this.code=e,this.name=`SandboxError`}};const U=/<script[^>]*src\s*=\s*["']https:\/\/(?:api|cdn)\.zenovay\.com\/[^"']+["'][^>]*>\s*<\/script>/i,me=[{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 he=class{sessionId;cwd;cwdReal;undoRoot;readCount=0;writeCount=0;roundCount=0;writtenPathsSet=new Set;constructor(e){this.sessionId=e.sessionId??T(),this.cwd=e.cwd,this.cwdReal=x.realpath(e.cwd),this.undoRoot=e.undoRoot??b.join(C.homedir(),`.zenovay`,`undo`)}incrementRound(){if(this.roundCount++,this.roundCount>pe)throw new H(`round-cap`,`Tool-call recursion cap (${pe}) 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 H(`escape`,`Path must be a non-empty string.`);if(e.includes(`\0`))throw new H(`escape`,`Null byte in path.`);if(/^\\\\[?.]\\/.test(e)||/^\\\\[A-Za-z0-9]/.test(e))throw new H(`escape`,`Windows special path prefix: ${e}`);if(/%/.test(e))try{let t=decodeURIComponent(e);if(/%[0-9A-Fa-f]{2}/.test(t))throw new H(`escape`,`Double-encoded path: ${e}`);e=t}catch(t){throw t instanceof H?t:new H(`escape`,`Malformed percent-encoding: ${e}`)}if(e.includes(`\0`))throw new H(`escape`,`Null byte in decoded path.`);if(e.includes(`\\`))throw new H(`escape`,`Backslash in path (Windows-style separator not accepted): ${e}`);let n=await this.cwdReal,r=b.isAbsolute(e)?e:b.join(n,e),i=b.normalize(r),a=i;try{a=await x.realpath(i)}catch(e){if(e.code!==`ENOENT`)throw new H(`escape`,`realpath failed: ${e.message}`);let t=b.dirname(i);try{let e=await x.realpath(t);a=b.join(e,b.basename(i))}catch{}}if(!this.isWithin(a,n))throw new H(`escape`,`Path escapes cwd: ${e}`);let o=b.relative(n,a),s=o.toLowerCase();for(let e of ue)if(e.test(o)||e.test(s)){if(t===`read`&&/(^|\/)node_modules\//i.test(o))continue;throw new H(`blocklisted`,`Path is on the hard blocklist: ${o}`)}if(t===`write`){let e=le.some(e=>e.test(o));if(!e&&!/^\.env(\.local)?$/.test(o)&&!/^\.claude\//.test(o)&&!/^\.cursor\//.test(o))throw new H(`not-allowlisted`,`Write path not on allowlist: ${o}`)}return a}isWithin(e,t){let n=b.relative(t,e);return!n.startsWith(`..`)&&!b.isAbsolute(n)}async safeRead(e){if(this.readCount>=de)throw new H(`read-cap`,`Read cap (${de}) reached.`);let t=await this.resolveForRead(e),n=await x.stat(t);if(n.size>V)throw new H(`too-large`,`File exceeds ${V}B: ${e} (${n.size}B)`);let r=await x.readFile(t),i=r.subarray(0,Math.min(r.length,8192));if(i.includes(0))throw new H(`binary-rejected`,`Binary content in ${e}.`);return this.readCount++,r.toString(`utf8`)}async safeWrite(e,t){if(this.writeCount>=fe)throw new H(`write-cap`,`Write cap (${fe}) reached.`);if(t.length>V)throw new H(`too-large`,`Write exceeds ${V}B: ${e}`);let n=await this.resolveForWrite(e),r=await x.readFile(n,`utf8`).catch(e=>{if(e.code===`ENOENT`)return null;throw e});if(r!==null){if(U.test(r)&&!U.test(t))throw new H(`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 me)if(i.test(r)&&!i.test(t))throw new H(`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 x.mkdir(b.dirname(n),{recursive:!0}),await x.writeFile(n,t,`utf8`),this.writeCount++;let a=await this.cwdReal;return this.writtenPathsSet.add(b.relative(a,n)),{backupPath:i}}async journalBackup(e){let t=await x.readFile(e).catch(e=>{if(e.code===`ENOENT`)return null;throw e}),n=b.join(this.undoRoot,this.sessionId);await x.mkdir(n,{recursive:!0,mode:448});let r=w.createHash(`sha256`).update(e).digest(`hex`).slice(0,16),i=b.join(n,`${r}.bak`),a=b.join(n,`manifest.jsonl`);t&&await x.writeFile(i,t,{mode:384});let o=JSON.stringify({abs:e,backupPath:t?i:null,ts:Date.now()});return await x.appendFile(a,o+`
2
2
  `,{mode:384}),t?i:null}static wrapForModel(e,t){let n=w.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 c(e)}};async function ge(e){let t=await e.readFile(`package.json`),n=!1;if(t)try{let e=JSON.parse(t);n=!!(e.dependencies?.[`@angular/core`]??e.devDependencies?.[`@angular/core`])}catch{}let r=await e.exists(`angular.json`)||await e.exists(`.angular-cli.json`);if(n||r){let t=await e.exists(`src/index.html`)?`src/index.html`:`index.html`;return{matched:!0,confidence:.9,reason:`Detected Angular via ${n?"`@angular/core`":"`angular.json`"} (shell: ${t}).`}}return{matched:!1,confidence:0,reason:`No Angular dependency or angular.json found.`}}function _e(e){let t=e.trackingCode??e.siteId??``,n=e.targetPath||`src/index.html`,r=`<script defer\n data-id="${t}"\n data-allow-localhost="true"\n src="https://api.zenovay.com/z.js">\n</script>`;return[{targetPath:n,anchorKind:`head-tag`,code:r,description:`Inject the Zenovay tracker inside <head> of the Angular index.html shell.`}]}const ve={id:`angular`,displayName:`Angular`,detect:ge,files:[{path:`src/index.html`,kind:`mutate`,required:!0}],envVarName:`NG_ZENOVAY_SITE`,buildSnippets:_e},ye=[`astro.config.ts`,`astro.config.mjs`,`astro.config.js`];async function be(e){for(let t of ye)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 xe(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 Se={id:`astro`,displayName:`Astro`,detect:be,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:xe};async function Ce(e){let t=await e.readFile(`package.json`);if(t)try{let e=JSON.parse(t);if(e.dependencies?.gatsby??e.devDependencies?.gatsby)return!0}catch{}return await e.exists(`gatsby-config.js`)||await e.exists(`gatsby-config.ts`)}async function we(e){return await Ce(e)?{matched:!0,confidence:.95,reason:"Detected Gatsby via `gatsby` dependency / `gatsby-config`."}:{matched:!1,confidence:0,reason:`No Gatsby dependency or config found.`}}function Te(e){let t=e.trackingCode??e.siteId??``,n=`const React = require('react');
3
3
 
4
4
  exports.onRenderBody = ({ setHeadComponents }) => {
@@ -79,7 +79,7 @@ export default function App({ Component, pageProps }: AppProps) {
79
79
  </svelte:head>
80
80
 
81
81
  <slot />
82
- `;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 ot={id:`sveltekit`,displayName:`SvelteKit`,detect:it,files:[{path:`src/routes/+layout.svelte`,kind:`mutate`,required:!0}],envVarName:`PUBLIC_ZENOVAY_SITE`,buildSnippets:at},st=[`next`,`nuxt`,`nuxt3`,`@sveltejs/kit`,`astro`,`@remix-run/react`,`@builder.io/qwik-city`,`@builder.io/qwik`,`@solidjs/start`,`solid-start`,`@angular/core`,`gatsby`],ct=[`index.html`,`public/index.html`];async function lt(e){let t=await e.readFile(`package.json`);if(!t)return{};try{let e=JSON.parse(t);return{...e.dependencies??{},...e.devDependencies??{}}}catch{return{}}}async function ut(e){for(let t of ct)if(await e.exists(t))return t;return null}async function dt(e){let t=await lt(e);if(st.some(e=>t[e]))return{matched:!1,confidence:0,reason:`A Vite-based meta-framework (Next/Nuxt/SvelteKit/Astro/Remix/Qwik/Solid/Angular) owns this project.`};let n=!!t.vite,r=await ut(e);return n&&r?{matched:!0,confidence:.85,reason:`Detected a Vite app via \`vite\` dependency + \`${r}\`.`}:n?{matched:!0,confidence:.55,reason:"Detected `vite` but no index.html — the agent will locate the SPA entry."}:{matched:!1,confidence:0,reason:"No `vite` dependency found."}}function ft(e){let t=e.trackingCode??e.siteId??``,n=e.targetPath||`index.html`,r=`<script defer\n data-id="${t}"\n data-allow-localhost="true"\n src="https://api.zenovay.com/z.js">\n</script>`;return[{targetPath:n,anchorKind:`head-tag`,code:r,description:`Inject the Zenovay tracker inside <head> of the Vite entry HTML.`}]}const pt={id:`vite`,displayName:`Vite`,detect:dt,files:[{path:`index.html`,kind:`mutate`,required:!0}],envVarName:`VITE_ZENOVAY_SITE`,buildSnippets:ft},mt=[Pe,Be,We,ot,Se,et,Ee,ve,rt,Ze,pt,Je];async function ht(e){let t=[];for(let n of mt){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 gt(e){let t=t=>b.resolve(e,t);return{cwd:e,async readFile(e){try{return await x.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 x.access(t(e)),!0}catch{return!1}},async glob(t){return P(t,{cwd:e,dot:!1,gitignore:!0,onlyFiles:!0,followSymbolicLinks:!1})}}}async function _t(e,t){let n=gt(e),{adapter:r,ranked:i}=await ht(n),a=i[0];return r&&a&&a.result.confidence>=.7?r:t?t.pickInteractively(i):r}function vt(e,t){let n=/[\s"'#=]/.test(t)||t===``,r=n?`"${t.replace(/\\/g,`\\\\`).replace(/"/g,`\\"`)}"`:t;return`${e}=${r}`}function yt(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 W(e,t,n={}){let r=n.filename??`.env.local`,i=b.resolve(e,r),a=``,o=!0;try{a=await x.readFile(i,`utf8`)}catch(e){if(e.code===`ENOENT`)o=!1;else throw e}let s=o?yt(a):new Set,c=[],l=[],u=[];for(let[e,n]of Object.entries(t)){if(s.has(e)){l.push(e);continue}u.push(vt(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(`
82
+ `;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 ot={id:`sveltekit`,displayName:`SvelteKit`,detect:it,files:[{path:`src/routes/+layout.svelte`,kind:`mutate`,required:!0}],envVarName:`PUBLIC_ZENOVAY_SITE`,buildSnippets:at},st=[`next`,`nuxt`,`nuxt3`,`@sveltejs/kit`,`astro`,`@remix-run/react`,`@builder.io/qwik-city`,`@builder.io/qwik`,`@solidjs/start`,`solid-start`,`@angular/core`,`gatsby`],ct=[`index.html`,`public/index.html`];async function lt(e){let t=await e.readFile(`package.json`);if(!t)return{};try{let e=JSON.parse(t);return{...e.dependencies??{},...e.devDependencies??{}}}catch{return{}}}async function ut(e){for(let t of ct)if(await e.exists(t))return t;return null}async function dt(e){let t=await lt(e);if(st.some(e=>t[e]))return{matched:!1,confidence:0,reason:`A Vite-based meta-framework (Next/Nuxt/SvelteKit/Astro/Remix/Qwik/Solid/Angular) owns this project.`};let n=!!t.vite,r=await ut(e);return n&&r?{matched:!0,confidence:.85,reason:`Detected a Vite app via \`vite\` dependency + \`${r}\`.`}:n?{matched:!0,confidence:.55,reason:"Detected `vite` but no index.html — the agent will locate the SPA entry."}:{matched:!1,confidence:0,reason:"No `vite` dependency found."}}function ft(e){let t=e.trackingCode??e.siteId??``,n=e.targetPath||`index.html`,r=`<script defer\n data-id="${t}"\n data-allow-localhost="true"\n src="https://api.zenovay.com/z.js">\n</script>`;return[{targetPath:n,anchorKind:`head-tag`,code:r,description:`Inject the Zenovay tracker inside <head> of the Vite entry HTML.`}]}const pt={id:`vite`,displayName:`Vite`,detect:dt,files:[{path:`index.html`,kind:`mutate`,required:!0}],envVarName:`VITE_ZENOVAY_SITE`,buildSnippets:ft},mt=[Pe,Be,We,ot,Se,et,Ee,ve,rt,Ze,pt,Je];async function ht(e){let t=[];for(let n of mt){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 gt(e){let t=t=>b.resolve(e,t);return{cwd:e,async readFile(e){try{return await x.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 x.access(t(e)),!0}catch{return!1}},async glob(t){return N(t,{cwd:e,dot:!1,gitignore:!0,onlyFiles:!0,followSymbolicLinks:!1})}}}async function _t(e,t){let n=gt(e),{adapter:r,ranked:i}=await ht(n),a=i[0];return r&&a&&a.result.confidence>=.7?r:t?t.pickInteractively(i):r}function vt(e,t){let n=/[\s"'#=]/.test(t)||t===``,r=n?`"${t.replace(/\\/g,`\\\\`).replace(/"/g,`\\"`)}"`:t;return`${e}=${r}`}function yt(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 W(e,t,n={}){let r=n.filename??`.env.local`,i=b.resolve(e,r),a=``,o=!0;try{a=await x.readFile(i,`utf8`)}catch(e){if(e.code===`ENOENT`)o=!1;else throw e}let s=o?yt(a):new Set,c=[],l=[],u=[];for(let[e,n]of Object.entries(t)){if(s.has(e)){l.push(e);continue}u.push(vt(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(`
83
83
  `);f=a+(e?`
84
84
  `:``)+`
85
85
  `+d+`
@@ -89,11 +89,11 @@ export default function App({ Component, pageProps }: AppProps) {
89
89
  `+u.join(`
90
90
  `)+`
91
91
  `;if(o)await x.writeFile(i,f,`utf8`);else{let e=await x.open(i,`w`,384);try{await e.writeFile(f,`utf8`)}finally{await e.close()}}return{created:!o,existing:o,addedKeys:c,skippedKeys:l}}const bt=`https://api.zenovay.com/mcp`,xt=S.object({url:S.string().url(),headers:S.record(S.string(),S.string()).optional()}),St=S.object({mcpServers:S.record(S.string(),xt).optional()}).passthrough();function Ct(e){return e.HOME??e.USERPROFILE??C.homedir()}function wt(e){return e.APPDATA??null}function Tt(e,t){let n=Ct(t),r=wt(t),i=[];return i.push({id:`cursor`,displayName:`Cursor`,configPath:b.join(n,`.cursor`,`mcp.json`)}),e===`win32`&&r&&i.push({id:`cursor`,displayName:`Cursor (AppData)`,configPath:b.join(r,`Cursor`,`User`,`globalStorage`,`cursor.mcp`,`mcp.json`)}),e===`darwin`?i.push({id:`claude-desktop`,displayName:`Claude Desktop`,configPath:b.join(n,`Library`,`Application Support`,`Claude`,`claude_desktop_config.json`)}):e===`win32`&&r?i.push({id:`claude-desktop`,displayName:`Claude Desktop`,configPath:b.join(r,`Claude`,`claude_desktop_config.json`)}):i.push({id:`claude-desktop`,displayName:`Claude Desktop`,configPath:b.join(n,`.config`,`Claude`,`claude_desktop_config.json`)}),i.push({id:`vscode`,displayName:`VS Code`,configPath:b.join(n,`.vscode`,`mcp.json`)}),i}async function Et(e){try{return await x.access(e),!0}catch{return!1}}async function Dt(e){try{let t=await x.readFile(e,`utf8`);if(t.trim().length===0)return{};let n=JSON.parse(t),r=St.safeParse(n);return r.success?r.data:n&&typeof n==`object`?n:{}}catch{return{}}}function Ot(){return{url:bt}}async function G(e){let t=e.env??process.env,n=e.platform??process.platform,r=new Set(e.skip??[]),i=[],a=[],o=[],s=new Set,c=Ot();for(let e of Tt(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 Et(e.configPath);if(!t){a.push(e.displayName);continue}let n=await Dt(e.configPath),r=`${e.configPath}.bak`;await x.copyFile(e.configPath,r);let o={...n,mcpServers:{...n.mcpServers??{},zenovay:c}};await x.mkdir(b.dirname(e.configPath),{recursive:!0}),await x.writeFile(e.configPath,JSON.stringify(o,null,2)+`
92
- `,`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 kt(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 At=S.object({path:S.string().min(1)}),jt=S.object({path:S.string().min(1),content:S.string(),reason:S.string().min(1)}),Mt=S.object({path:S.string().min(1),patch:S.string().min(1),reason:S.string().min(1)}),Nt=S.object({}),Pt=S.object({question:S.string().min(1),choices:S.array(S.string()).optional()});async function Ft(e,t){let n=At.safeParse(t);if(!n.success)return{ok:!1,content:null,error:`invalid_args`};try{let t=await e.safeRead(n.data.path),r=he.scrubSecrets(t);return{ok:!0,content:he.wrapForModel(n.data.path,r)}}catch(e){return{ok:!1,content:null,error:e.message}}}async function It(e,t,n){let r=jt.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 Lt(e,t,n){let r=Mt.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=ne(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.`}:It(e,{path:i,content:c,reason:o},n)}async function Rt(e){try{let t=gt(e),{adapter:n,ranked:r}=await ht(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 zt(e,t){let n=Pt.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 Bt(e){let{api:t,sandbox:n,approval:r,prompter:i,handlers:a}=e,o=[...e.initialMessages],s=``,c=0;for(;c<pe;){n.incrementRound(),c++;let u=await t.openAiStream(`install`,{messages:o,cwd_fingerprint:n.sessionId,diagnosis:e.diagnosis,targetTrackingCode:e.targetTrackingCode}),d=[],f=``;for await(let e of l(u))switch(e.type){case`delta`:f+=e.content,a?.onDelta?.(e.content);break;case`tool_start`:a?.onToolStart?.({id:e.id,name:e.name});break;case`tool_call`:{let t=await Vt(e.name,e.arguments,{sandbox:n,cwd:n.cwd,approval:r,prompter:i});d.push({id:e.id,name:e.name,arguments:e.arguments,result:t}),a?.onToolResult?.({id:e.id,name:e.name,result:t});break}case`usage`:a?.onUsage?.(e);break;case`error`:throw a?.onError?.(e),Error(`[${e.code}] ${e.message}`);case`done`:break}if(f&&(s+=f),d.length===0){f&&o.push({role:`assistant`,content:f});break}o.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)o.push({role:`tool`,toolCallId:e.id,toolName:e.name,content:JSON.stringify(e.result)})}return{finalText:s,rounds:c}}async function Vt(e,t,n){try{switch(e){case`read_file`:return await Ft(n.sandbox,t);case`write_file`:return await It(n.sandbox,t,n.approval);case`patch_file`:return await Lt(n.sandbox,t,n.approval);case`detect_framework`:return await Rt(n.cwd);case`ask_user`:return await zt(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 Ht=e=>`<script defer\n data-id="${e}"\n data-allow-localhost="true"\n src="https://api.zenovay.com/z.js">\n</script>`;async function Ut(e){let t={installed:[],skipped:[],errors:[]},n=await P([`**/*.html`,`!node_modules/**`,`!.git/**`,`!dist/**`,`!.next/**`,`!.nuxt/**`,`!build/**`,`!.output/**`],{cwd:e.cwd,gitignore:!0,absolute:!1});if(n.length===0)return t;let r=Ht(e.trackingCode),i=RegExp(`data-id\\s*=\\s*["']${Wt(e.trackingCode)}["']`);for(let a of n){let n=b.join(e.cwd,a),o;try{o=await x.readFile(n,`utf8`)}catch(e){t.errors.push({file:a,error:e.message});continue}if(U.test(o)&&i.test(o)){t.skipped.push({file:a,reason:`already installed with correct tracking code`});continue}let s;if(U.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??`
92
+ `,`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 kt(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 At=S.object({path:S.string().min(1)}),jt=S.object({path:S.string().min(1),content:S.string(),reason:S.string().min(1)}),Mt=S.object({path:S.string().min(1),patch:S.string().min(1),reason:S.string().min(1)}),Nt=S.object({}),Pt=S.object({question:S.string().min(1),choices:S.array(S.string()).optional()});async function Ft(e,t){let n=At.safeParse(t);if(!n.success)return{ok:!1,content:null,error:`invalid_args`};try{let t=await e.safeRead(n.data.path),r=he.scrubSecrets(t);return{ok:!0,content:he.wrapForModel(n.data.path,r)}}catch(e){return{ok:!1,content:null,error:e.message}}}async function It(e,t,n){let r=jt.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 Lt(e,t,n){let r=Mt.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=F(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.`}:It(e,{path:i,content:c,reason:o},n)}async function Rt(e){try{let t=gt(e),{adapter:n,ranked:r}=await ht(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 zt(e,t){let n=Pt.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 Bt(e){let{api:t,sandbox:n,approval:r,prompter:i,handlers:a}=e,o=[...e.initialMessages],s=``,c=0;for(;c<pe;){n.incrementRound(),c++;let u=await t.openAiStream(`install`,{messages:o,cwd_fingerprint:n.sessionId,diagnosis:e.diagnosis,targetTrackingCode:e.targetTrackingCode}),d=[],f=``;for await(let e of l(u))switch(e.type){case`delta`:f+=e.content,a?.onDelta?.(e.content);break;case`tool_start`:a?.onToolStart?.({id:e.id,name:e.name});break;case`tool_call`:{let t=await Vt(e.name,e.arguments,{sandbox:n,cwd:n.cwd,approval:r,prompter:i});d.push({id:e.id,name:e.name,arguments:e.arguments,result:t}),a?.onToolResult?.({id:e.id,name:e.name,result:t});break}case`usage`:a?.onUsage?.(e);break;case`error`:throw a?.onError?.(e),Error(`[${e.code}] ${e.message}`);case`done`:break}if(f&&(s+=f),d.length===0){f&&o.push({role:`assistant`,content:f});break}o.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)o.push({role:`tool`,toolCallId:e.id,toolName:e.name,content:JSON.stringify(e.result)})}return{finalText:s,rounds:c}}async function Vt(e,t,n){try{switch(e){case`read_file`:return await Ft(n.sandbox,t);case`write_file`:return await It(n.sandbox,t,n.approval);case`patch_file`:return await Lt(n.sandbox,t,n.approval);case`detect_framework`:return await Rt(n.cwd);case`ask_user`:return await zt(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 Ht=e=>`<script defer\n data-id="${e}"\n data-allow-localhost="true"\n src="https://api.zenovay.com/z.js">\n</script>`;async function Ut(e){let t={installed:[],skipped:[],errors:[]},n=await N([`**/*.html`,`!node_modules/**`,`!.git/**`,`!dist/**`,`!.next/**`,`!.nuxt/**`,`!build/**`,`!.output/**`],{cwd:e.cwd,gitignore:!0,absolute:!1});if(n.length===0)return t;let r=Ht(e.trackingCode),i=RegExp(`data-id\\s*=\\s*["']${Wt(e.trackingCode)}["']`);for(let a of n){let n=b.join(e.cwd,a),o;try{o=await x.readFile(n,`utf8`)}catch(e){t.errors.push({file:a,error:e.message});continue}if(U.test(o)&&i.test(o)){t.skipped.push({file:a,reason:`already installed with correct tracking code`});continue}let s;if(U.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??`
93
93
  `,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 me)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 x.writeFile(n,s,`utf8`),t.installed.push(a)}catch(e){t.errors.push({file:a,error:e.message})}}return t}function Wt(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}const Gt=`https://api.zenovay.com/z.js`;function Kt(e,t){return e.includes(Gt)&&e.includes(t)}function qt(e){if(/from\s+['"]next\/script['"]/.test(e))return e;let t=e.split(`
94
94
  `),n=-1;for(let e=0;e<t.length;e++)/^\s*import\s/.test(t[e])&&(n=e);let r=`import Script from 'next/script';`;if(n>=0)t.splice(n+1,0,r);else{let e=/^\s*['"]use client['"];?\s*$/.test(t[0]??``);t.splice(e?1:0,0,r)}return t.join(`
95
- `)}function Jt(e,t){let n=/([ \t]*)<\/body>/,r=e.match(n);if(!r)return null;let i=r[1]??``,a=`${i} <Script defer data-id="${t}" data-allow-localhost="true" src="${Gt}" strategy="afterInteractive" />`;return e.replace(n,`${a}\n${i}</body>`)}async function Yt(e){let{cwd:t,trackingCode:n}=e,r={installed:[],skipped:[],errors:[],fellThrough:!1},i;try{i=await P([`app/**/layout.{tsx,ts,jsx,js}`,`src/app/**/layout.{tsx,ts,jsx,js}`],{cwd:t,gitignore:!1,ignore:[`**/node_modules/**`]})}catch(e){return r.errors.push({file:`app/**/layout`,error:e.message}),r.fellThrough=!0,r}if(i.length===0)return r.fellThrough=!0,r;let a=[];for(let e of i)try{let n=await k.readFile(b.join(t,e),`utf8`);/<body[\s/>]/.test(n)&&a.push({rel:e,src:n,depth:e.split(`/`).length})}catch{}if(a.length===0)return r.fellThrough=!0,r;a.sort((e,t)=>e.depth-t.depth);let o=a[0];if(Kt(o.src,n))return r.skipped.push({file:o.rel,reason:`already installed with correct tracking code`}),r;let s=qt(o.src),c=Jt(s,n);if(!c)return r.fellThrough=!0,r;try{await k.writeFile(b.join(t,o.rel),c),r.installed.push(o.rel)}catch(e){r.errors.push({file:o.rel,error:e.message}),r.fellThrough=!0}return r}const K=`api.zenovay.com/z.js`;async function q(e){try{return await x.readFile(e,`utf8`)}catch{return null}}function Xt(e,t){let n=e.toLowerCase().lastIndexOf(`</head>`);if(n===-1)return null;let r=e.lastIndexOf(`
96
- `,n-1)+1,i=(e.slice(r,n).match(/^[ \t]*/)??[``])[0],a=`${i}${t}\n`;return e.slice(0,r)+a+e.slice(r)}async function Zt(e){if(e.adapter.id===`nuxt`)return $t(e);if(e.adapter.id===`sveltekit`)return en(e);let{cwd:t,trackingCode:n,siteId:r,adapter:i}=e,a={installed:[],skipped:[],errors:[],fellThrough:!1},o;try{o=i.buildSnippets({trackingCode:n,siteId:r??``},`script`)}catch{return a.fellThrough=!0,a}if(!o||o.length===0)return a.fellThrough=!0,a;let s=new Set(o.map(e=>e.anchorKind));if(s.size===1&&s.has(`head-tag`)){let e=!1;for(let n of o){let r=b.join(t,n.targetPath),i=await q(r);if(i===null){a.skipped.push({file:n.targetPath,reason:`target file not present`});continue}if(i.includes(K)){a.skipped.push({file:n.targetPath,reason:`tracker already present`}),e=!0;break}let o=Xt(i,n.code);if(o===null){a.skipped.push({file:n.targetPath,reason:`no </head> anchor in target`});continue}try{await x.writeFile(r,o,`utf8`),a.installed.push(n.targetPath),e=!0;break}catch(e){a.errors.push({file:n.targetPath,error:e.message})}}return!e&&a.installed.length===0&&a.errors.length===0&&(a.fellThrough=!0),a}if(s.size===1&&s.has(`replace-file`)&&o.length===1){let e=o[0];if(!e)return a.fellThrough=!0,a;let n=i.files.find(t=>t.path===e.targetPath),r=b.join(t,e.targetPath),s=await q(r);if(s!==null)return s.includes(K)?(a.skipped.push({file:e.targetPath,reason:`tracker already present`}),a):(a.fellThrough=!0,a);if(n?.kind===`create`){try{await x.mkdir(b.dirname(r),{recursive:!0}),await x.writeFile(r,e.code,`utf8`),a.installed.push(e.targetPath)}catch(t){a.errors.push({file:e.targetPath,error:t.message}),a.fellThrough=a.installed.length===0}return a}return a.fellThrough=!0,a}return a.fellThrough=!0,a}function Qt(){return{installed:[],skipped:[],errors:[],fellThrough:!1}}async function $t(e){let t=Qt(),n=[`nuxt.config.ts`,`nuxt.config.mjs`,`nuxt.config.js`],r=null,i=null,a=null;for(let t of n){let n=b.join(e.cwd,t),o=await q(n);if(o!==null){r=t,i=n,a=o;break}}if(a===null||i===null||r===null)return t.skipped.push({file:`nuxt.config.ts`,reason:`nuxt.config not found`}),t.fellThrough=!0,t;if(a.includes(K))return t.skipped.push({file:r,reason:`tracker already present`}),t;if(/\bapp\s*:/.test(a))return t.fellThrough=!0,t;let o=a.match(/defineNuxtConfig\s*\(\s*\{/);if(!o||o.index===void 0)return t.fellThrough=!0,t;let s=e.adapter.buildSnippets({trackingCode:e.trackingCode,siteId:e.siteId??``},`script`)[0]?.code;if(!s)return t.fellThrough=!0,t;let c=o.index+o[0].length,l=`${a.slice(0,c)}\n${s}${a.slice(c)}`;try{await x.writeFile(i,l,`utf8`),t.installed.push(r)}catch(e){t.errors.push({file:r,error:e.message}),t.fellThrough=!0}return t}async function en(e){let t=Qt(),n=`src/routes/+layout.svelte`,r=b.join(e.cwd,n),i=await q(r),a=`<svelte:head>\n <script defer data-id="${e.trackingCode}" data-allow-localhost="true" src="https://api.zenovay.com/z.js"></script>\n</svelte:head>\n`;if(i!==null){if(i.includes(K))return t.skipped.push({file:n,reason:`tracker already present`}),t;try{await x.writeFile(r,`${a}\n${i}`,`utf8`),t.installed.push(n)}catch(e){t.errors.push({file:n,error:e.message}),t.fellThrough=!0}return t}let o=e.adapter.buildSnippets({trackingCode:e.trackingCode,siteId:e.siteId??``},`script`)[0]?.code;if(!o)return t.fellThrough=!0,t;try{await x.mkdir(b.dirname(r),{recursive:!0}),await x.writeFile(r,o,`utf8`),t.installed.push(n)}catch(e){t.errors.push({file:n,error:e.message}),t.fellThrough=!0}return t}const tn=`\x1B]8;;`,nn=`\x07`;function rn(){return process.env.FORCE_HYPERLINK?!0:!(process.env.NO_COLOR||!process.stdout.isTTY||process.env.CI||(process.env.TERM??``)===`dumb`)}function J({url:e,label:t,color:n,arrow:r=!0}){let{theme:i}=m(),a=n??i.fg,o=(t??e)+(r?` ↗`:``);return rn()?A.createElement(D,{color:a,underline:!0},tn,e,nn,o,tn,nn):t&&t!==e?A.createElement(D,{color:a},A.createElement(D,{underline:!0},t),A.createElement(D,{color:i.dim},` (`,e,`)`)):A.createElement(D,{color:a,underline:!0},e)}function Y({label:e,value:t,labelWidth:n=12}){let{theme:r}=m();return A.createElement(E,{flexDirection:`row`},A.createElement(E,{width:n,flexShrink:0},A.createElement(D,{color:r.dim},e.toUpperCase())),typeof t==`string`?A.createElement(D,{color:r.fg},t):t)}function an(e){return e.yes||!process.stdout.isTTY?`auto`:`interactive`}function on(e){let t=null,n=null,r=!1,i=!1,a=0,o=new Set,s=()=>{for(let e of o)e(t)};return{async approve(o){if(i)return`n`;if(e.mode===`auto`||r)return`y`;let c=String(++a);return new Promise(e=>{t={id:c,...o},n=t=>{t===`a`&&(r=!0),e(t)},s()})},subscribe(e){return o.add(e),()=>{o.delete(e)}},current(){return t},resolve(e,r){if(!t||t.id!==e||!n)return;let i=n;t=null,n=null,s(),i(r)},abort(){if(i=!0,n){let e=n;t=null,n=null,s(),e(`n`)}}}}function sn(){let e=[12,15,18,22,28,35,41,50,58,64,72,78],t=y(e,24);return[` ↑`,` ${t}`,` └────────────────────────`,` May Jun Jul Aug Sep`]}function cn(){return[` Landing page ████████████████████ 100%`,` ↓ -28%`,` Pricing ██████████████░░░░░░ 72%`,` ↓ -50%`,` Checkout ███████░░░░░░░░░░░░░ 36%`,` ↓ -64%`,` Purchased ███░░░░░░░░░░░░░░░░░ 13%`]}function ln(){return[` ▇▇▇▇▇▇▇▇▇▎ 89 Sarah K. /pricing 🇺🇸`,` ▇▇▇▇▇▇░░░░ 61 anon /docs 🇩🇪`,` ▇▇▇░░░░░░░ 34 anon /changelog 🇯🇵`]}function un(){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:sn},{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:cn},{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:ln},{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:un},{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.`]}],dn=8e3,fn=({width:e,height:t})=>{let{theme:n}=m(),[r,i]=N(0);j(()=>{if(X.length<=1)return;let e=setInterval(()=>{i(e=>(e+1)%X.length)},dn);return()=>clearInterval(e)},[]);let a=X[r],o=a.visual?a.visual():[];return A.createElement(E,{flexDirection:`column`,width:e,height:t,paddingX:2,paddingY:1},A.createElement(E,{marginBottom:1},A.createElement(D,{color:n.typography.label.color,dimColor:n.typography.label.dim},`LEARN`)),A.createElement(E,{marginBottom:1},A.createElement(D,{bold:!0,color:n.fg,wrap:`truncate`},a.title)),a.body.map((e,t)=>A.createElement(D,{key:t,color:n.muted,wrap:`truncate`},e||` `)),o.length>0&&A.createElement(E,{flexDirection:`column`,marginTop:1},o.map((e,t)=>A.createElement(D,{key:t,color:n.accent},e))),A.createElement(E,{flexGrow:1}),A.createElement(E,{flexDirection:`row`,marginTop:1},A.createElement(D,null,X.map((e,t)=>A.createElement(D,{key:t,color:t===r?n.accent:n.dim},t===r?`●`:`·`,t<X.length-1?` `:``))),A.createElement(D,{color:n.dim},` · `,r+1,` / `,X.length)))},pn={pending:`·`,active:`⠋`,done:`✓`,error:`✗`};function mn(e,t){switch(e){case`pending`:return t.dim;case`active`:return t.accent;case`done`:return t.success;case`error`:return t.error}}const hn=({tasks:e,width:t,height:n,liveLine:r})=>{let{theme:i}=m(),a=e.filter(e=>e.status===`done`).length;return A.createElement(E,{flexDirection:`column`,width:t,height:n,paddingX:2,paddingY:1},A.createElement(E,{marginBottom:1},A.createElement(D,{color:i.typography.label.color,dimColor:i.typography.label.dim},`TASKS`)),e.map(e=>A.createElement(E,{key:e.id,flexDirection:`column`},A.createElement(E,{flexDirection:`row`},e.status===`active`?A.createElement(D,{color:i.accent},A.createElement(F,{type:`dots`})):A.createElement(D,{color:mn(e.status,i)},pn[e.status]),A.createElement(D,null,` `),A.createElement(D,{color:e.status===`pending`?i.muted:i.fg,wrap:`truncate`},e.label)),e.detail&&A.createElement(E,{paddingLeft:2},A.createElement(D,{color:i.dim,wrap:`truncate`},e.detail)))),A.createElement(E,{flexGrow:1}),r&&A.createElement(E,{flexDirection:`row`,marginTop:1},A.createElement(D,{color:i.accent},`◆ `),A.createElement(D,{color:i.fg,wrap:`truncate`},r)),A.createElement(E,{marginTop:1},A.createElement(D,{color:i.dim},a,` / `,e.length)))};async function gn(e){if(o(e))return _n(e);let t=`quit`,n=null,r=await new Promise(r=>{let{unmount:i,waitUntilExit:a}=ee(A.createElement(vn,{opts:e,onExit:(e,a,o)=>{t=a??`quit`,n=o??null,i(),r(e)}}));a().catch(()=>r(1))});if(r===0&&await d().catch(()=>void 0),r!==0||t===`quit`||!n)return r;let i=n.id;if(t===`watch`){let{watchCommand:t}=await import(`./watch-CP-Klikt.js`);return t({cliVersion:e.cliVersion,siteId:i})}if(t===`events`){let{eventsTailCommand:t}=await import(`./events-tail-CRgba_gO.js`);return t({cliVersion:e.cliVersion,siteId:i})}return 0}async function _n(t){let r=await import(`./telemetry-C1045t6Q.js`).catch(()=>null);r?.emit(`install.start`,{properties:{mode:`headless`}});try{let o=await e(),s=await _t(t.cwd);if(!s)return a({type:`error`,code:`no_framework`,message:`Could not detect framework (headless mode has no picker).`}),r?.emit(`install.error`,{error_code:`no_framework`,properties:{mode:`headless`}}),2;a({type:`framework.detected`,framework:s.id,confidence:1}),r?.emit(`install.framework_detected`,{properties:{framework:s.id}});let c=await i({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,d]=await Promise.all([l.getSites(),B(t.cwd,``).catch(()=>null)]),f;if(t.siteId){if(f=u.find(e=>e.id===t.siteId),!f)return a({type:`error`,code:`site_not_found`,message:`Site ${t.siteId} not found.`}),2}else if(d?.foundTrackingCodes.length){for(let e of d.foundTrackingCodes){let t=u.find(t=>t.trackingCode===e);if(t){f=t;break}}f||=u[0]}else f=u[0];if(!f)return a({type:`error`,code:`no_site`,message:`No sites exist; create one at app.zenovay.com or re-run interactively.`}),2;let p=f.trackingCode??f.id;if(d&&(d.recommendation===`no-op`||d.foundTrackingCodes.includes(p)))return a({type:`info`,message:`Zenovay already installed correctly for ${f.name} (${p})`}),a({type:`done`,command:`init`,exitCode:0}),0;a({type:`info`,message:`Using site ${f.id} (${f.name}) trackingCode=${f.trackingCode??f.id}`});let m=f.trackingCode??f.id,h=await W(t.cwd,{[s.envVarName]:m});if(a({type:`info`,message:`env vars added: ${h.addedKeys.join(`,`)}`}),s.id===`plain-html`){let e=await Ut({cwd:t.cwd,trackingCode:m,updateOnly:d?.recommendation===`update-tracking-code`});if(e.installed.length===0&&e.skipped.length===0)return a({type:`error`,code:`install_failed`,message:`No .html files with a <head> block found to inject the tracker into (errors: ${e.errors.length}).`}),r?.emit(`install.error`,{error_code:`install_failed`,properties:{mode:`headless`,framework:s.id}}),1;a({type:`info`,message:`tracker injected into ${e.installed.length} file(s); ${e.skipped.length} already current; ${e.errors.length} error(s)`})}else return a({type:`error`,code:`headless_framework_unsupported`,message:`Headless install can only auto-inject the tracker for plain-HTML projects. For ${s.displayName}, run \`zenovay init\` interactively — the AI wizard places the <Script> in the correct entry file. (The env var ${h.addedKeys.join(`, `)||s.envVarName} was written.)`}),r?.emit(`install.error`,{error_code:`headless_framework_unsupported`,properties:{mode:`headless`,framework:s.id}}),1;return a({type:`done`,command:`init`,exitCode:0}),r?.emit(`install.success`,{properties:{framework:s.id,mode:`headless`,env_keys_added:h.addedKeys.length}}),0}catch(e){return a({type:`error`,code:`init_failed`,message:e.message}),r?.emit(`install.error`,{error_code:`init_failed`,properties:{mode:`headless`,error:(e.message??`unknown`).slice(0,128)}}),1}}const vn=({opts:t,onExit:r})=>{let{exit:a}=te(),{theme:o}=m(),[s,c]=N(`intro`),[l,d]=N(null),[h,g]=N([]),[_,y]=N(null),[b,x]=N(null),[S,C]=N(null),[w,T]=N([]),[ee,O]=N(void 0),[k,P]=N(null),[ne,I]=N(null),[re,ie]=N(0),[ae,oe]=N(!1),[L,R]=N(null),z=M(null),se=M(!1);return j(()=>(process.stdout.isTTY&&process.stdout.write(`\x1B[?1049h\x1B[H`),()=>{z.current?.abort(),process.stdout.isTTY&&process.stdout.write(`\x1B[?1049l`)}),[]),j(()=>{se.current||(se.current=!0,(async()=>{try{c(`detecting`);let r=await _t(t.cwd);if(!r){C(`Could not detect your framework. Supported: Next.js, Nuxt, SvelteKit, Astro, Remix, plain HTML.`),c(`error`);return}d(r);let a=await i({strict:!1});!process.env.ZENOVAY_API_TOKEN&&!a&&(c(`login`),await u({cliVersion:t.cliVersion,offerCompletions:!1})),c(`loading-sites`);let o=await e(),s=await i({strict:!1}),l=new n({config:o,cliVersion:t.cliVersion,token:s}),[f,p]=await Promise.all([l.getSites(),B(t.cwd,``).catch(()=>null)]),m=await Fn(t.cwd);if(g(f),y(m),f.length===0){c(`create-site`);return}if(p?.foundTrackingCodes.length)for(let e of p.foundTrackingCodes){let t=f.find(t=>t.trackingCode===e);if(t){x(t),c(`already-installed`);return}}if(t.siteId){let e=f.find(e=>e.id===t.siteId);if(!e){C(`Site ${t.siteId} not found in your account.`),c(`error`);return}x(e),yn(e,r,t,{setPhase:c,setErrorMsg:C,setTasks:T,setLiveLine:O,setSandboxStats:P,setVerifyResult:I,setPendingApproval:R,registerBridge:e=>{z.current=e}});return}let h=In(f,m);if(t.yes&&h){x(h),yn(h,r,t,{setPhase:c,setErrorMsg:C,setTasks:T,setLiveLine:O,setSandboxStats:P,setVerifyResult:I,setPendingApproval:R,registerBridge:e=>{z.current=e}});return}c(`site-picker`)}catch(e){C(e.message),c(`error`)}})())},[]),j(()=>{s===`error`&&(z.current?.abort(),setTimeout(()=>{a(),r(1)},8e3))},[s]),A.createElement(E,{flexDirection:`column`},A.createElement(f,{version:t.cliVersion,subtitle:`AI install wizard`}),s===`intro`&&A.createElement(bn,null),s===`detecting`&&A.createElement(p,{title:`Scanning`,state:`busy`},A.createElement(E,null,A.createElement(D,{color:o.accent},A.createElement(F,{type:`dots`})),A.createElement(D,null,` Detecting framework…`))),s===`login`&&A.createElement(p,{title:`Authenticating`,state:`busy`},A.createElement(D,null,`Opening browser for login… (paste ZENOVAY_API_TOKEN env var to skip)`)),s===`loading-sites`&&A.createElement(p,{title:`Loading your sites`,state:`busy`},A.createElement(E,null,A.createElement(D,{color:o.accent},A.createElement(F,{type:`dots`})),A.createElement(D,null,` Fetching your Zenovay sites…`))),s===`already-installed`&&b&&A.createElement(Sn,{site:b,onContinue:()=>{c(`site-picker`)},onExit:()=>{a(),r(0,`quit`,b)}}),s===`site-picker`&&l&&A.createElement(Cn,{sites:h,preselectHint:_,onPick:e=>{if(e===`create-new`){c(`create-site`);return}x(e),yn(e,l,t,{setPhase:c,setErrorMsg:C,setTasks:T,setLiveLine:O,setSandboxStats:P,setVerifyResult:I,setPendingApproval:R,registerBridge:e=>{z.current=e}})}}),s===`create-site`&&A.createElement(p,{title:`Create a new site`,state:`warn`},A.createElement(D,{color:o.warn},"No site picked (or none exist yet). Visit https://app.zenovay.com/websites to create one, then re-run `zenovay init`."),A.createElement(D,{color:o.muted},`(Inline site creation from the CLI is scheduled for V1.1 — it requires a plan-limit check.)`)),s===`agent`&&l&&b&&A.createElement(xn,{adapter:l,site:b,tasks:w,liveLine:ee,pendingApproval:L,onApprove:e=>{L&&z.current?.resolve(L.id,e)}}),s===`install-complete`&&l&&b&&A.createElement(En,{adapter:l,site:b,stats:k,verify:ne,onCommit:()=>c(`commit-prompt`),onSkipCommit:()=>c(`deploy-prompt`)}),s===`commit-prompt`&&b&&A.createElement(Dn,{cwd:t.cwd,onDone:e=>{e.committed&&O(`Pushed ${e.shortSha} to ${e.branch}`),c(`deploy-prompt`)},onError:e=>{C(e),c(`error`)}}),s===`deploy-prompt`&&b&&A.createElement(On,{site:b,onDeployed:()=>c(`visit-prompt`),onSkip:()=>c(`verify`)}),s===`visit-prompt`&&b&&A.createElement(kn,{site:b,onContinue:()=>c(`verify`)}),s===`verify`&&b&&A.createElement(jn,{site:b,elapsed:re,onTick:e=>ie(e),onArrived:()=>{oe(!0),c(`success`)},onTimeout:()=>c(`success`)}),s===`success`&&l&&b&&A.createElement(Tn,{adapter:l,site:b,stats:k,arrived:ae,onPick:e=>{a(),r(0,e,b)}}),s===`error`&&A.createElement(p,{title:`Install failed`,state:`err`},A.createElement(D,{color:o.error},S??`Unknown error`)),A.createElement(v,{items:s===`already-installed`?[{key:`q`,label:`quit`},{key:`r`,label:`re-run wizard`},{key:`ctrl-c`,label:`abort`}]:[{key:`q`,label:`quit`},{key:`ctrl-c`,label:`abort`}]}))};async function Z(e,t,n){n.setLiveLine(`Verifying the tracker is in your source…`);try{let r=await B(e,t),i=r.recommendation===`no-op`&&r.foundTrackingCodes.includes(t);n.setVerifyResult?.({ok:i,detail:i?`Tracker confirmed in your source files`:`Couldn't auto-confirm the tracker (diagnosis: ${r.recommendation}) — please double-check`})}catch{n.setVerifyResult?.({ok:!1,detail:`Verification check could not run`})}n.setLiveLine(void 0)}async function yn(r,a,o,s){try{s.setPhase(`agent`);let c=await e(),l=await i({strict:!1}),u=new n({config:c,cliVersion:o.cliVersion,token:l}),d=new he({cwd:o.cwd}),f=r.trackingCode??r.id;await t({defaultSiteId:r.id,defaultSiteName:r.name}).catch(()=>void 0);let p=await B(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 G({accessToken:l.accessToken}).catch(()=>void 0),s.setVerifyResult?.({ok:!0,detail:`Already installed correctly`}),s.setPhase(`install-complete`);return}if(p.competitors.length>0&&s.setLiveLine(`Detected ${p.competitors.map(e=>e.name).join(`, `)} — will install Zenovay alongside (won't touch their tags).`),a.id===`next-app-router`){s.setTasks([{id:`detect`,label:`Detect framework`,status:`done`,detail:`Next.js (App Router)`},{id:`read`,label:`Find the document shell layout`,status:`active`},{id:`write`,label:`Insert tracker <Script>`,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:`Verify the tracker in your source`,status:`pending`}]),s.setLiveLine(`Next.js — locating the document shell layout…`);let e=await Yt({cwd:o.cwd,trackingCode:f});if(!e.fellThrough&&e.errors.length===0){let t=e.installed[0]??`already installed`;s.setTasks(e=>e.map(e=>e.id===`read`||e.id===`write`?{...e,status:`done`,detail:t}:e));let n=await W(o.cwd,{[a.envVarName]:f});if(s.setTasks(e=>e.map(e=>e.id===`env`?{...e,status:`done`,detail:`${n.addedKeys.length} key(s) added`}:e)),!o.skipMcp&&l){let e=await G({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));await Z(o.cwd,f,s),s.setTasks(e=>e.map(e=>e.id===`verify`?{...e,status:`done`}:e)),s.setSandboxStats?.({reads:1,writes:e.installed.length,rounds:0}),s.setPhase(`install-complete`);return}s.setLiveLine(`Custom Next.js structure — handing off to the AI agent…`)}let m=a.id===`plain-html`;if(m){s.setTasks([{id:`detect`,label:`Detect framework`,status:`done`,detail:`Plain HTML`},{id:`read`,label:`Scan .html pages`,status:`active`},{id:`write`,label:`Insert tracker <script>`,status:`pending`},{id:`env`,label:`Write env vars`,status:`pending`},{id:`mcp`,label:`Install MCP clients (Cursor/Claude/VS Code)`,status:`pending`},{id:`verify`,label:`Verify the tracker in your source`,status:`pending`}]),s.setLiveLine(`Plain HTML — using fast install path (no AI needed)…`);let e=await Ut({cwd:o.cwd,trackingCode:f,updateOnly:p.recommendation===`update-tracking-code`});if(e.installed.length===0&&e.errors.length===0&&e.skipped.length===0)throw Error(`No .html files with a <head>...</head> block were found to inject the tracker into.`);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 W(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 G({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));await Z(o.cwd,f,s),s.setSandboxStats?.({reads:e.installed.length,writes:e.installed.length,rounds:0}),s.setPhase(`install-complete`);return}{let e=await Zt({cwd:o.cwd,trackingCode:f,siteId:r.id,adapter:a}),t=e.skipped.some(e=>/already present/.test(e.reason));if(!e.fellThrough&&e.errors.length===0&&(e.installed.length>0||t)){s.setTasks([{id:`detect`,label:`Detect framework`,status:`done`,detail:a.displayName},{id:`write`,label:`Insert tracker snippet`,status:`done`,detail:e.installed[0]??`already installed`},{id:`env`,label:`Write env vars (.env.local)`,status:`active`},{id:`mcp`,label:`Install MCP clients (Cursor/Claude/VS Code)`,status:`pending`},{id:`verify`,label:`Verify the tracker in your source`,status:`pending`}]),s.setLiveLine(`${a.displayName} — using fast install path (no AI needed)…`);let t=await W(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 G({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));await Z(o.cwd,f,s),s.setTasks(e=>e.map(e=>e.id===`verify`?{...e,status:`done`}:e)),s.setSandboxStats?.({reads:1,writes:e.installed.length,rounds:0}),s.setPhase(`install-complete`);return}s.setLiveLine(`${a.displayName} — handing off to the AI agent…`)}let h=a.buildSnippets({trackingCode:f,siteId:r.id}),g=`Install Zenovay tracking into this ${a.displayName} project.\nSite: ${r.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(`
95
+ `)}function Jt(e,t){let n=/([ \t]*)<\/body>/,r=e.match(n);if(!r)return null;let i=r[1]??``,a=`${i} <Script defer data-id="${t}" data-allow-localhost="true" src="${Gt}" strategy="afterInteractive" />`;return e.replace(n,`${a}\n${i}</body>`)}async function Yt(e){let{cwd:t,trackingCode:n}=e,r={installed:[],skipped:[],errors:[],fellThrough:!1},i;try{i=await N([`app/**/layout.{tsx,ts,jsx,js}`,`src/app/**/layout.{tsx,ts,jsx,js}`],{cwd:t,gitignore:!1,ignore:[`**/node_modules/**`]})}catch(e){return r.errors.push({file:`app/**/layout`,error:e.message}),r.fellThrough=!0,r}if(i.length===0)return r.fellThrough=!0,r;let a=[];for(let e of i)try{let n=await k.readFile(b.join(t,e),`utf8`);/<body[\s/>]/.test(n)&&a.push({rel:e,src:n,depth:e.split(`/`).length})}catch{}if(a.length===0)return r.fellThrough=!0,r;a.sort((e,t)=>e.depth-t.depth);let o=a[0];if(Kt(o.src,n))return r.skipped.push({file:o.rel,reason:`already installed with correct tracking code`}),r;let s=qt(o.src),c=Jt(s,n);if(!c)return r.fellThrough=!0,r;try{await k.writeFile(b.join(t,o.rel),c),r.installed.push(o.rel)}catch(e){r.errors.push({file:o.rel,error:e.message}),r.fellThrough=!0}return r}const K=`api.zenovay.com/z.js`;async function q(e){try{return await x.readFile(e,`utf8`)}catch{return null}}function Xt(e,t){let n=e.toLowerCase().lastIndexOf(`</head>`);if(n===-1)return null;let r=e.lastIndexOf(`
96
+ `,n-1)+1,i=(e.slice(r,n).match(/^[ \t]*/)??[``])[0],a=`${i}${t}\n`;return e.slice(0,r)+a+e.slice(r)}async function Zt(e){if(e.adapter.id===`nuxt`)return $t(e);if(e.adapter.id===`sveltekit`)return en(e);let{cwd:t,trackingCode:n,siteId:r,adapter:i}=e,a={installed:[],skipped:[],errors:[],fellThrough:!1},o;try{o=i.buildSnippets({trackingCode:n,siteId:r??``},`script`)}catch{return a.fellThrough=!0,a}if(!o||o.length===0)return a.fellThrough=!0,a;let s=new Set(o.map(e=>e.anchorKind));if(s.size===1&&s.has(`head-tag`)){let e=!1;for(let n of o){let r=b.join(t,n.targetPath),i=await q(r);if(i===null){a.skipped.push({file:n.targetPath,reason:`target file not present`});continue}if(i.includes(K)){a.skipped.push({file:n.targetPath,reason:`tracker already present`}),e=!0;break}let o=Xt(i,n.code);if(o===null){a.skipped.push({file:n.targetPath,reason:`no </head> anchor in target`});continue}try{await x.writeFile(r,o,`utf8`),a.installed.push(n.targetPath),e=!0;break}catch(e){a.errors.push({file:n.targetPath,error:e.message})}}return!e&&a.installed.length===0&&a.errors.length===0&&(a.fellThrough=!0),a}if(s.size===1&&s.has(`replace-file`)&&o.length===1){let e=o[0];if(!e)return a.fellThrough=!0,a;let n=i.files.find(t=>t.path===e.targetPath),r=b.join(t,e.targetPath),s=await q(r);if(s!==null)return s.includes(K)?(a.skipped.push({file:e.targetPath,reason:`tracker already present`}),a):(a.fellThrough=!0,a);if(n?.kind===`create`){try{await x.mkdir(b.dirname(r),{recursive:!0}),await x.writeFile(r,e.code,`utf8`),a.installed.push(e.targetPath)}catch(t){a.errors.push({file:e.targetPath,error:t.message}),a.fellThrough=a.installed.length===0}return a}return a.fellThrough=!0,a}return a.fellThrough=!0,a}function Qt(){return{installed:[],skipped:[],errors:[],fellThrough:!1}}async function $t(e){let t=Qt(),n=[`nuxt.config.ts`,`nuxt.config.mjs`,`nuxt.config.js`],r=null,i=null,a=null;for(let t of n){let n=b.join(e.cwd,t),o=await q(n);if(o!==null){r=t,i=n,a=o;break}}if(a===null||i===null||r===null)return t.skipped.push({file:`nuxt.config.ts`,reason:`nuxt.config not found`}),t.fellThrough=!0,t;if(a.includes(K))return t.skipped.push({file:r,reason:`tracker already present`}),t;if(/\bapp\s*:/.test(a))return t.fellThrough=!0,t;let o=a.match(/defineNuxtConfig\s*\(\s*\{/);if(!o||o.index===void 0)return t.fellThrough=!0,t;let s=e.adapter.buildSnippets({trackingCode:e.trackingCode,siteId:e.siteId??``},`script`)[0]?.code;if(!s)return t.fellThrough=!0,t;let c=o.index+o[0].length,l=`${a.slice(0,c)}\n${s}${a.slice(c)}`;try{await x.writeFile(i,l,`utf8`),t.installed.push(r)}catch(e){t.errors.push({file:r,error:e.message}),t.fellThrough=!0}return t}async function en(e){let t=Qt(),n=`src/routes/+layout.svelte`,r=b.join(e.cwd,n),i=await q(r),a=`<svelte:head>\n <script defer data-id="${e.trackingCode}" data-allow-localhost="true" src="https://api.zenovay.com/z.js"></script>\n</svelte:head>\n`;if(i!==null){if(i.includes(K))return t.skipped.push({file:n,reason:`tracker already present`}),t;try{await x.writeFile(r,`${a}\n${i}`,`utf8`),t.installed.push(n)}catch(e){t.errors.push({file:n,error:e.message}),t.fellThrough=!0}return t}let o=e.adapter.buildSnippets({trackingCode:e.trackingCode,siteId:e.siteId??``},`script`)[0]?.code;if(!o)return t.fellThrough=!0,t;try{await x.mkdir(b.dirname(r),{recursive:!0}),await x.writeFile(r,o,`utf8`),t.installed.push(n)}catch(e){t.errors.push({file:n,error:e.message}),t.fellThrough=!0}return t}const tn=`\x1B]8;;`,nn=`\x07`;function rn(){return process.env.FORCE_HYPERLINK?!0:!(process.env.NO_COLOR||!process.stdout.isTTY||process.env.CI||(process.env.TERM??``)===`dumb`)}function J({url:e,label:t,color:n,arrow:r=!0}){let{theme:i}=m(),a=n??i.fg,o=(t??e)+(r?` ↗`:``);return rn()?A.createElement(D,{color:a,underline:!0},tn,e,nn,o,tn,nn):t&&t!==e?A.createElement(D,{color:a},A.createElement(D,{underline:!0},t),A.createElement(D,{color:i.dim},` (`,e,`)`)):A.createElement(D,{color:a,underline:!0},e)}function Y({label:e,value:t,labelWidth:n=12}){let{theme:r}=m();return A.createElement(E,{flexDirection:`row`},A.createElement(E,{width:n,flexShrink:0},A.createElement(D,{color:r.dim},e.toUpperCase())),typeof t==`string`?A.createElement(D,{color:r.fg},t):t)}function an(e){return e.yes||!process.stdout.isTTY?`auto`:`interactive`}function on(e){let t=null,n=null,r=!1,i=!1,a=0,o=new Set,s=()=>{for(let e of o)e(t)};return{async approve(o){if(i)return`n`;if(e.mode===`auto`||r)return`y`;let c=String(++a);return new Promise(e=>{t={id:c,...o},n=t=>{t===`a`&&(r=!0),e(t)},s()})},subscribe(e){return o.add(e),()=>{o.delete(e)}},current(){return t},resolve(e,r){if(!t||t.id!==e||!n)return;let i=n;t=null,n=null,s(),i(r)},abort(){if(i=!0,n){let e=n;t=null,n=null,s(),e(`n`)}}}}function sn(){let e=[12,15,18,22,28,35,41,50,58,64,72,78],t=y(e,24);return[` ↑`,` ${t}`,` └────────────────────────`,` May Jun Jul Aug Sep`]}function cn(){return[` Landing page ████████████████████ 100%`,` ↓ -28%`,` Pricing ██████████████░░░░░░ 72%`,` ↓ -50%`,` Checkout ███████░░░░░░░░░░░░░ 36%`,` ↓ -64%`,` Purchased ███░░░░░░░░░░░░░░░░░ 13%`]}function ln(){return[` ▇▇▇▇▇▇▇▇▇▎ 89 Sarah K. /pricing 🇺🇸`,` ▇▇▇▇▇▇░░░░ 61 anon /docs 🇩🇪`,` ▇▇▇░░░░░░░ 34 anon /changelog 🇯🇵`]}function un(){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:sn},{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:cn},{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:ln},{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:un},{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.`]}],dn=8e3,fn=({width:e,height:t})=>{let{theme:n}=m(),[r,i]=M(0);j(()=>{if(X.length<=1)return;let e=setInterval(()=>{i(e=>(e+1)%X.length)},dn);return()=>clearInterval(e)},[]);let a=X[r],o=a.visual?a.visual():[];return A.createElement(E,{flexDirection:`column`,width:e,height:t,paddingX:2,paddingY:1},A.createElement(E,{marginBottom:1},A.createElement(D,{color:n.typography.label.color,dimColor:n.typography.label.dim},`LEARN`)),A.createElement(E,{marginBottom:1},A.createElement(D,{bold:!0,color:n.fg,wrap:`truncate`},a.title)),a.body.map((e,t)=>A.createElement(D,{key:t,color:n.muted,wrap:`truncate`},e||` `)),o.length>0&&A.createElement(E,{flexDirection:`column`,marginTop:1},o.map((e,t)=>A.createElement(D,{key:t,color:n.accent},e))),A.createElement(E,{flexGrow:1}),A.createElement(E,{flexDirection:`row`,marginTop:1},A.createElement(D,null,X.map((e,t)=>A.createElement(D,{key:t,color:t===r?n.accent:n.dim},t===r?`●`:`·`,t<X.length-1?` `:``))),A.createElement(D,{color:n.dim},` · `,r+1,` / `,X.length)))},pn={pending:`·`,active:`⠋`,done:`✓`,error:`✗`};function mn(e,t){switch(e){case`pending`:return t.dim;case`active`:return t.accent;case`done`:return t.success;case`error`:return t.error}}const hn=({tasks:e,width:t,height:n,liveLine:r})=>{let{theme:i}=m(),a=e.filter(e=>e.status===`done`).length;return A.createElement(E,{flexDirection:`column`,width:t,height:n,paddingX:2,paddingY:1},A.createElement(E,{marginBottom:1},A.createElement(D,{color:i.typography.label.color,dimColor:i.typography.label.dim},`TASKS`)),e.map(e=>A.createElement(E,{key:e.id,flexDirection:`column`},A.createElement(E,{flexDirection:`row`},e.status===`active`?A.createElement(D,{color:i.accent},A.createElement(P,{type:`dots`})):A.createElement(D,{color:mn(e.status,i)},pn[e.status]),A.createElement(D,null,` `),A.createElement(D,{color:e.status===`pending`?i.muted:i.fg,wrap:`truncate`},e.label)),e.detail&&A.createElement(E,{paddingLeft:2},A.createElement(D,{color:i.dim,wrap:`truncate`},e.detail)))),A.createElement(E,{flexGrow:1}),r&&A.createElement(E,{flexDirection:`row`,marginTop:1},A.createElement(D,{color:i.accent},`◆ `),A.createElement(D,{color:i.fg,wrap:`truncate`},r)),A.createElement(E,{marginTop:1},A.createElement(D,{color:i.dim},a,` / `,e.length)))};async function gn(e){if(o(e))return _n(e);let t=`quit`,n=null,r=await new Promise(r=>{let{unmount:i,waitUntilExit:a}=ee(A.createElement(vn,{opts:e,onExit:(e,a,o)=>{t=a??`quit`,n=o??null,i(),r(e)}}),{exitOnCtrlC:!0});a().catch(()=>r(1))});if(r===0&&await d().catch(()=>void 0),r!==0||t===`quit`||!n)return r;let i=n.id;if(t===`watch`){let{overviewCommand:t}=await import(`./overview-L8jqiSuU.js`);return t({cliVersion:e.cliVersion,siteId:i})}if(t===`events`){let{eventsTailCommand:t}=await import(`./events-tail-DEdVkmT0.js`);return t({cliVersion:e.cliVersion,siteId:i})}return 0}async function _n(t){let r=await import(`./telemetry-Bbh6Vtst.js`).catch(()=>null);r?.emit(`install.start`,{properties:{mode:`headless`}});try{let o=await e(),s=await _t(t.cwd);if(!s)return a({type:`error`,code:`no_framework`,message:`Could not detect framework (headless mode has no picker).`}),r?.emit(`install.error`,{error_code:`no_framework`,properties:{mode:`headless`}}),2;a({type:`framework.detected`,framework:s.id,confidence:1}),r?.emit(`install.framework_detected`,{properties:{framework:s.id}});let c=await i({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,d]=await Promise.all([l.getSites(),z(t.cwd,``).catch(()=>null)]),f;if(t.siteId){if(f=u.find(e=>e.id===t.siteId),!f)return a({type:`error`,code:`site_not_found`,message:`Site ${t.siteId} not found.`}),2}else if(d?.foundTrackingCodes.length){for(let e of d.foundTrackingCodes){let t=u.find(t=>t.trackingCode===e);if(t){f=t;break}}f||=u[0]}else f=u[0];if(!f)return a({type:`error`,code:`no_site`,message:`No sites exist; create one at app.zenovay.com or re-run interactively.`}),2;let p=f.trackingCode??f.id;if(d&&(d.recommendation===`no-op`||d.foundTrackingCodes.includes(p)))return a({type:`info`,message:`Zenovay already installed correctly for ${f.name} (${p})`}),a({type:`done`,command:`init`,exitCode:0}),0;a({type:`info`,message:`Using site ${f.id} (${f.name}) trackingCode=${f.trackingCode??f.id}`});let m=f.trackingCode??f.id,h=await W(t.cwd,{[s.envVarName]:m});if(a({type:`info`,message:`env vars added: ${h.addedKeys.join(`,`)}`}),s.id===`plain-html`){let e=await Ut({cwd:t.cwd,trackingCode:m,updateOnly:d?.recommendation===`update-tracking-code`});if(e.installed.length===0&&e.skipped.length===0)return a({type:`error`,code:`install_failed`,message:`No .html files with a <head> block found to inject the tracker into (errors: ${e.errors.length}).`}),r?.emit(`install.error`,{error_code:`install_failed`,properties:{mode:`headless`,framework:s.id}}),1;a({type:`info`,message:`tracker injected into ${e.installed.length} file(s); ${e.skipped.length} already current; ${e.errors.length} error(s)`})}else return a({type:`error`,code:`headless_framework_unsupported`,message:`Headless install can only auto-inject the tracker for plain-HTML projects. For ${s.displayName}, run \`zenovay init\` interactively — the AI wizard places the <Script> in the correct entry file. (The env var ${h.addedKeys.join(`, `)||s.envVarName} was written.)`}),r?.emit(`install.error`,{error_code:`headless_framework_unsupported`,properties:{mode:`headless`,framework:s.id}}),1;return a({type:`done`,command:`init`,exitCode:0}),r?.emit(`install.success`,{properties:{framework:s.id,mode:`headless`,env_keys_added:h.addedKeys.length}}),0}catch(e){return a({type:`error`,code:`init_failed`,message:e.message}),r?.emit(`install.error`,{error_code:`init_failed`,properties:{mode:`headless`,error:(e.message??`unknown`).slice(0,128)}}),1}}const vn=({opts:t,onExit:r})=>{let{exit:a}=te(),{theme:o}=m(),[s,c]=M(`intro`),[l,d]=M(null),[h,g]=M([]),[_,y]=M(null),[b,x]=M(null),[S,C]=M(null),[w,T]=M([]),[ee,k]=M(void 0),[N,F]=M(null),[re,I]=M(null),[ie,ae]=M(0),[oe,se]=M(!1),[L,R]=M(null),B=ne(null),ce=ne(!1);return O((e,t)=>{s===`error`&&(e.toLowerCase()===`q`||t.escape)&&(a(),r(1))}),j(()=>(process.stdout.isTTY&&process.stdout.write(`\x1B[?1049h\x1B[H`),()=>{B.current?.abort(),process.stdout.isTTY&&process.stdout.write(`\x1B[?1049l`)}),[]),j(()=>{ce.current||(ce.current=!0,(async()=>{try{c(`detecting`);let r=await _t(t.cwd);if(!r){C(`Could not detect your framework. Supported: Next.js, Nuxt, SvelteKit, Astro, Remix, plain HTML.`),c(`error`);return}d(r);let a=await i({strict:!1});!process.env.ZENOVAY_API_TOKEN&&!a&&(c(`login`),await u({cliVersion:t.cliVersion,offerCompletions:!1})),c(`loading-sites`);let o=await e(),s=await i({strict:!1}),l=new n({config:o,cliVersion:t.cliVersion,token:s}),[f,p]=await Promise.all([l.getSites(),z(t.cwd,``).catch(()=>null)]),m=await Fn(t.cwd);if(g(f),y(m),f.length===0){c(`create-site`);return}if(p?.foundTrackingCodes.length)for(let e of p.foundTrackingCodes){let t=f.find(t=>t.trackingCode===e);if(t){x(t),c(`already-installed`);return}}if(t.siteId){let e=f.find(e=>e.id===t.siteId);if(!e){C(`Site ${t.siteId} not found in your account.`),c(`error`);return}x(e),yn(e,r,t,{setPhase:c,setErrorMsg:C,setTasks:T,setLiveLine:k,setSandboxStats:F,setVerifyResult:I,setPendingApproval:R,registerBridge:e=>{B.current=e}});return}let h=In(f,m);if(t.yes&&h){x(h),yn(h,r,t,{setPhase:c,setErrorMsg:C,setTasks:T,setLiveLine:k,setSandboxStats:F,setVerifyResult:I,setPendingApproval:R,registerBridge:e=>{B.current=e}});return}c(`site-picker`)}catch(e){C(e.message),c(`error`)}})())},[]),j(()=>{s===`error`&&(B.current?.abort(),setTimeout(()=>{a(),r(1)},8e3))},[s]),A.createElement(E,{flexDirection:`column`},A.createElement(f,{version:t.cliVersion,subtitle:`AI install wizard`}),s===`intro`&&A.createElement(bn,null),s===`detecting`&&A.createElement(p,{title:`Scanning`,state:`busy`},A.createElement(E,null,A.createElement(D,{color:o.accent},A.createElement(P,{type:`dots`})),A.createElement(D,null,` Detecting framework…`))),s===`login`&&A.createElement(p,{title:`Authenticating`,state:`busy`},A.createElement(D,null,`Opening browser for login… (paste ZENOVAY_API_TOKEN env var to skip)`)),s===`loading-sites`&&A.createElement(p,{title:`Loading your sites`,state:`busy`},A.createElement(E,null,A.createElement(D,{color:o.accent},A.createElement(P,{type:`dots`})),A.createElement(D,null,` Fetching your Zenovay sites…`))),s===`already-installed`&&b&&A.createElement(Sn,{site:b,onContinue:()=>{c(`site-picker`)},onExit:()=>{a(),r(0,`quit`,b)}}),s===`site-picker`&&l&&A.createElement(Cn,{sites:h,preselectHint:_,onPick:e=>{if(e===`create-new`){c(`create-site`);return}x(e),yn(e,l,t,{setPhase:c,setErrorMsg:C,setTasks:T,setLiveLine:k,setSandboxStats:F,setVerifyResult:I,setPendingApproval:R,registerBridge:e=>{B.current=e}})}}),s===`create-site`&&A.createElement(p,{title:`Create a new site`,state:`warn`},A.createElement(D,{color:o.warn},"No site picked (or none exist yet). Visit https://app.zenovay.com/websites to create one, then re-run `zenovay init`."),A.createElement(D,{color:o.muted},`(Inline site creation from the CLI is scheduled for V1.1 — it requires a plan-limit check.)`)),s===`agent`&&l&&b&&A.createElement(xn,{adapter:l,site:b,tasks:w,liveLine:ee,pendingApproval:L,onApprove:e=>{L&&B.current?.resolve(L.id,e)}}),s===`install-complete`&&l&&b&&A.createElement(En,{adapter:l,site:b,stats:N,verify:re,onCommit:()=>c(`commit-prompt`),onSkipCommit:()=>c(`deploy-prompt`)}),s===`commit-prompt`&&b&&A.createElement(Dn,{cwd:t.cwd,onDone:e=>{e.committed&&k(`Pushed ${e.shortSha} to ${e.branch}`),c(`deploy-prompt`)},onError:e=>{C(e),c(`error`)}}),s===`deploy-prompt`&&b&&A.createElement(On,{site:b,onDeployed:()=>c(`visit-prompt`),onSkip:()=>c(`verify`)}),s===`visit-prompt`&&b&&A.createElement(kn,{site:b,onContinue:()=>c(`verify`)}),s===`verify`&&b&&A.createElement(jn,{site:b,elapsed:ie,onTick:e=>ae(e),onArrived:()=>{se(!0),c(`success`)},onTimeout:()=>c(`success`)}),s===`success`&&l&&b&&A.createElement(Tn,{adapter:l,site:b,stats:N,arrived:oe,onPick:e=>{a(),r(0,e,b)}}),s===`error`&&A.createElement(p,{title:`Install failed`,state:`err`},A.createElement(D,{color:o.error},S??`Unknown error`)),A.createElement(v,{items:s===`already-installed`?[{key:`q`,label:`quit`},{key:`r`,label:`re-run wizard`},{key:`ctrl-c`,label:`abort`}]:[{key:`q`,label:`quit`},{key:`ctrl-c`,label:`abort`}]}))};async function Z(e,t,n){n.setLiveLine(`Verifying the tracker is in your source…`);try{let r=await z(e,t),i=r.recommendation===`no-op`&&r.foundTrackingCodes.includes(t);n.setVerifyResult?.({ok:i,detail:i?`Tracker confirmed in your source files`:`Couldn't auto-confirm the tracker (diagnosis: ${r.recommendation}) — please double-check`})}catch{n.setVerifyResult?.({ok:!1,detail:`Verification check could not run`})}n.setLiveLine(void 0)}async function yn(r,a,o,s){try{s.setPhase(`agent`);let c=await e(),l=await i({strict:!1}),u=new n({config:c,cliVersion:o.cliVersion,token:l}),d=new he({cwd:o.cwd}),f=r.trackingCode??r.id;await t({defaultSiteId:r.id,defaultSiteName:r.name}).catch(()=>void 0);let p=await z(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 G({accessToken:l.accessToken}).catch(()=>void 0),s.setVerifyResult?.({ok:!0,detail:`Already installed correctly`}),s.setPhase(`install-complete`);return}if(p.competitors.length>0&&s.setLiveLine(`Detected ${p.competitors.map(e=>e.name).join(`, `)} — will install Zenovay alongside (won't touch their tags).`),a.id===`next-app-router`){s.setTasks([{id:`detect`,label:`Detect framework`,status:`done`,detail:`Next.js (App Router)`},{id:`read`,label:`Find the document shell layout`,status:`active`},{id:`write`,label:`Insert tracker <Script>`,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:`Verify the tracker in your source`,status:`pending`}]),s.setLiveLine(`Next.js — locating the document shell layout…`);let e=await Yt({cwd:o.cwd,trackingCode:f});if(!e.fellThrough&&e.errors.length===0){let t=e.installed[0]??`already installed`;s.setTasks(e=>e.map(e=>e.id===`read`||e.id===`write`?{...e,status:`done`,detail:t}:e));let n=await W(o.cwd,{[a.envVarName]:f});if(s.setTasks(e=>e.map(e=>e.id===`env`?{...e,status:`done`,detail:`${n.addedKeys.length} key(s) added`}:e)),!o.skipMcp&&l){let e=await G({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));await Z(o.cwd,f,s),s.setTasks(e=>e.map(e=>e.id===`verify`?{...e,status:`done`}:e)),s.setSandboxStats?.({reads:1,writes:e.installed.length,rounds:0}),s.setPhase(`install-complete`);return}s.setLiveLine(`Custom Next.js structure — handing off to the AI agent…`)}let m=a.id===`plain-html`;if(m){s.setTasks([{id:`detect`,label:`Detect framework`,status:`done`,detail:`Plain HTML`},{id:`read`,label:`Scan .html pages`,status:`active`},{id:`write`,label:`Insert tracker <script>`,status:`pending`},{id:`env`,label:`Write env vars`,status:`pending`},{id:`mcp`,label:`Install MCP clients (Cursor/Claude/VS Code)`,status:`pending`},{id:`verify`,label:`Verify the tracker in your source`,status:`pending`}]),s.setLiveLine(`Plain HTML — using fast install path (no AI needed)…`);let e=await Ut({cwd:o.cwd,trackingCode:f,updateOnly:p.recommendation===`update-tracking-code`});if(e.installed.length===0&&e.errors.length===0&&e.skipped.length===0)throw Error(`No .html files with a <head>...</head> block were found to inject the tracker into.`);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 W(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 G({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));await Z(o.cwd,f,s),s.setSandboxStats?.({reads:e.installed.length,writes:e.installed.length,rounds:0}),s.setPhase(`install-complete`);return}{let e=await Zt({cwd:o.cwd,trackingCode:f,siteId:r.id,adapter:a}),t=e.skipped.some(e=>/already present/.test(e.reason));if(!e.fellThrough&&e.errors.length===0&&(e.installed.length>0||t)){s.setTasks([{id:`detect`,label:`Detect framework`,status:`done`,detail:a.displayName},{id:`write`,label:`Insert tracker snippet`,status:`done`,detail:e.installed[0]??`already installed`},{id:`env`,label:`Write env vars (.env.local)`,status:`active`},{id:`mcp`,label:`Install MCP clients (Cursor/Claude/VS Code)`,status:`pending`},{id:`verify`,label:`Verify the tracker in your source`,status:`pending`}]),s.setLiveLine(`${a.displayName} — using fast install path (no AI needed)…`);let t=await W(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 G({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));await Z(o.cwd,f,s),s.setTasks(e=>e.map(e=>e.id===`verify`?{...e,status:`done`}:e)),s.setSandboxStats?.({reads:1,writes:e.installed.length,rounds:0}),s.setPhase(`install-complete`);return}s.setLiveLine(`${a.displayName} — handing off to the AI agent…`)}let h=a.buildSnippets({trackingCode:f,siteId:r.id}),g=`Install Zenovay tracking into this ${a.displayName} project.\nSite: ${r.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(`
97
97
  `)+`
98
98
  3. Insert the tracker using the snippet below.
99
99
  4. Confirm the change with a diff before writing.
@@ -102,4 +102,4 @@ Snippet reference (anchored by anchorKind — adapt to the actual file):
102
102
  `+h.map(e=>` ${e.anchorKind} @ ${e.targetPath}:\n ${e.code.replace(/\n/g,`
103
103
  `)}`).join(`
104
104
 
105
- `);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=on({mode:an(o)});s.registerBridge(v);let y=v.subscribe(e=>s.setPendingApproval(e)),b=null;try{await Bt({api:u,sandbox:d,approval:v,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){b=e}finally{y(),s.setPendingApproval(null)}let x=d.stats();if(x.writes===0){let e=b?`Agent error: ${b.message}`:`Agent returned without writing any files (${x.reads} reads, ${x.rounds} rounds). The model may have refused or the AI Gateway may be misconfigured. Check api.zenovay.com logs.`;throw Error(e)}let S=a.files.map(e=>e.path),C=x.writtenPaths.some(e=>S.some(t=>e===t||e.endsWith(`/${t}`)));if(!C)throw Error(`Agent wrote to: [${x.writtenPaths.join(`, `)}] but never modified the framework's tracker target file(s): [${S.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 w=await W(o.cwd,{[a.envVarName]:f});if(_(`env`,`done`,`${w.addedKeys.length} key(s) added`),!o.skipMcp&&l){_(`mcp`,`active`),s.setLiveLine(`Detecting Cursor / Claude Desktop / VS Code…`);let e=await G({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)),await Z(o.cwd,f,s),s.setSandboxStats?.(x),s.setPhase(`install-complete`)}catch(e){s.setErrorMsg(e.message),s.setPhase(`error`)}}const bn=()=>{let{theme:e}=m();return A.createElement(p,{title:`Zenovay wants to set up your project`,state:`idle`},A.createElement(D,null,`We'll use AI to analyze your codebase and add the Zenovay tracker.`),A.createElement(D,{color:e.muted},`.env* contents stay on your machine. Only framework metadata reaches api.zenovay.com.`))},xn=({adapter:e,site:t,tasks:n,liveLine:r,pendingApproval:i,onApprove:a})=>{let{theme:o}=m(),s=process.stdout.columns??100,c=(process.stdout.rows??30)-8,l=Math.floor(s/2)-1,u=Math.max(14,c);return A.createElement(E,{flexDirection:`column`},A.createElement(E,{flexDirection:`row`,minHeight:u,borderStyle:`round`,borderColor:o.border},A.createElement(E,{width:l,flexDirection:`column`},A.createElement(fn,{width:l,height:u})),A.createElement(E,{width:1,flexDirection:`column`},A.createElement(D,{color:o.border},`│`)),A.createElement(E,{width:l,flexDirection:`column`},i?A.createElement(E,{flexDirection:`column`,paddingX:2,paddingTop:1},A.createElement(D,{color:o.warn},`The agent wants to write `,i.path),i.reason?A.createElement(D,{color:o.muted},i.reason):null,A.createElement(h,{key:i.id,filePath:i.path,oldContent:i.oldContent,newContent:i.newContent,onApprove:a})):A.createElement(A.Fragment,null,A.createElement(E,{paddingX:2,paddingTop:1},A.createElement(g,{done:n.filter(e=>e.status===`done`).length,total:n.length,label:n.find(e=>e.status===`active`)?.label})),A.createElement(hn,{tasks:n,liveLine:r,width:l,height:u})))),A.createElement(E,{marginTop:1},A.createElement(D,{color:o.muted},`Site: `,t.name,` · code: `,t.trackingCode??t.id,` · Framework: `,e.displayName)))},Sn=({site:e,onContinue:t,onExit:n})=>{let{theme:r}=m();O((e,r)=>{if(e===`q`||r.escape){n();return}if(e===`r`||e===`R`){t();return}});let i=e.url.replace(/^https?:\/\//,``).replace(/\/$/,``);return A.createElement(p,{title:`Already installed`,state:`ok`},A.createElement(E,{flexDirection:`column`,gap:1},A.createElement(E,{flexDirection:`row`,gap:1},A.createElement(D,{color:r.success},`✓`),A.createElement(D,{bold:!0},e.name),A.createElement(D,{color:r.muted},`(`,i,`)`)),A.createElement(D,{color:r.muted},`Zenovay is already tracking this project. No changes needed.`),e.trackingCode?A.createElement(D,{color:r.dim},`tracking code: `,e.trackingCode):null))},Cn=({sites:e,preselectHint:t,onPick:n})=>{let r=In(e,t),i=e.filter(e=>e.id!==r?.id),a=r?[r,...i]:i,o=[...a.map(e=>({label:Pn(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 A.createElement(p,{title:t?`Pick a site (best match: ${t})`:`Pick a site`,state:`idle`},A.createElement(_,{items:o,onSelect:n}))};function wn(){let e=process.argv[1]??``;return e.includes(`/_npx/`)||e.includes(`\\_npx\\`)||process.env.npm_execpath?.includes(`npx`)?`npx`:`global`}const Q=({k:e,primary:t})=>{let{theme:n}=m();return A.createElement(D,null,A.createElement(D,{color:n.muted},`[`),A.createElement(D,{bold:!0,color:t?n.accent:n.fg},e),A.createElement(D,{color:n.muted},`] `))},Tn=({adapter:e,site:t,stats:n,arrived:i,onPick:a})=>{let{theme:o}=m(),c=wn(),l=c===`npx`?`npx @zenovay/cli`:`zenovay`,u=r(t),d=n&&n.rounds>0?`${n.writes} file(s) · ${n.rounds} agent round(s)`:n&&n.writes>0?`${n.writes} file(s) · programmatic (no AI calls)`:null;return O((e,t)=>{let n=e.toLowerCase();n===`w`||t.return?a(`watch`):n===`o`?s(u).catch(()=>void 0):n===`e`?a(`events`):(n===`s`||n===`q`||t.escape)&&a(`quit`)},{isActive:!0}),A.createElement(p,{title:`You're live on Zenovay`,state:`ok`},A.createElement(D,{bold:!0,color:o.success},i?`✓ First event received from ${t.name}`:`✓ Installed successfully`),A.createElement(D,{color:o.accent},`─`.repeat(18)),A.createElement(E,{marginTop:1,flexDirection:`column`},A.createElement(Y,{label:`Framework`,value:e.displayName}),A.createElement(Y,{label:`Site`,value:A.createElement(J,{url:t.url,label:t.name})}),t.trackingCode?A.createElement(Y,{label:`Tracker`,value:A.createElement(D,{color:o.muted},t.trackingCode)}):null,d?A.createElement(Y,{label:`Changes`,value:A.createElement(D,{color:o.muted},d)}):null,A.createElement(Y,{label:`Dashboard`,value:A.createElement(J,{url:u})})),A.createElement(E,{marginTop:1,flexDirection:`column`},A.createElement(D,{color:o.dim},`WHAT'S NEXT`),A.createElement(E,{marginTop:1},A.createElement(D,null,` `),A.createElement(Q,{k:`W`,primary:!0}),A.createElement(D,null,`Watch live in this terminal `),A.createElement(D,{color:o.muted},`— visitors, pages, sources, vitals`)),A.createElement(E,null,A.createElement(D,null,` `),A.createElement(Q,{k:`O`}),A.createElement(D,null,`Open the dashboard in your browser`)),A.createElement(E,null,A.createElement(D,null,` `),A.createElement(Q,{k:`E`}),A.createElement(D,null,`Stream events as they fire `),A.createElement(D,{color:o.muted},`— page views, custom events, live`)),A.createElement(E,null,A.createElement(D,null,` `),A.createElement(Q,{k:`S`}),A.createElement(D,null,`Exit to shell`))),c===`npx`?A.createElement(E,{marginTop:1,flexDirection:`column`,borderStyle:`single`,borderColor:o.warn,paddingX:1},A.createElement(D,{color:o.warn,bold:!0},`Heads up — you ran via npx`),A.createElement(D,{color:o.muted},"The `zenovay` command isn't on your PATH yet. After you exit, run:"),A.createElement(E,{marginTop:1},A.createElement(D,{color:o.fg},` npm i -g @zenovay/cli `),A.createElement(D,{color:o.muted},"→ then `zenovay watch` works directly"))):A.createElement(E,{marginTop:1},A.createElement(D,{color:o.muted},`From your shell: `),A.createElement(D,{color:o.fg},l,` watch`),A.createElement(D,{color:o.muted},` · `),A.createElement(D,{color:o.fg},l,` --help`)))},En=({adapter:e,site:t,stats:n,verify:r,onCommit:i,onSkipCommit:a})=>{let{theme:o}=m();return Mn(e=>{e===`y`||e===`Y`||e===`\r`?i():(e===`n`||e===`N`||e===`s`||e===`S`)&&a()}),A.createElement(p,{title:`Tracker installed`,state:r&&!r.ok?`warn`:`ok`},r?A.createElement(D,null,A.createElement(D,{color:r.ok?o.success:o.warn},r.ok?`✔ Verified — `:`⚠ `),r.detail):A.createElement(D,null,A.createElement(D,{color:o.success},`✔ `),`The Zenovay tracker is in your project.`),A.createElement(E,{marginTop:1},A.createElement(D,{color:o.muted},`Framework: `),A.createElement(D,null,e.displayName)),A.createElement(E,null,A.createElement(D,{color:o.muted},`Site: `),A.createElement(D,null,t.name,` (`,t.url,`)`)),n&&A.createElement(E,null,A.createElement(D,{color:o.muted},`Modified: `),A.createElement(D,null,n.writes,` file(s)`)),A.createElement(E,{marginTop:1},A.createElement(D,null,`Commit + push these changes to git? `),A.createElement(D,{color:o.accent},`[Y/n]`)))},Dn=({cwd:e,onDone:t,onError:n})=>{let{theme:r}=m(),[i,a]=N(`committing`),[o,s]=N(`Staging changes…`);return j(()=>{(async()=>{try{let n=await Nn(e,e=>s(e),e=>a(e));n.committed?s(`Pushed ${n.shortSha} to origin/${n.branch}`):s(`No changes to commit (already up-to-date).`),setTimeout(()=>t(n),800)}catch(e){n(e.message)}})()},[]),A.createElement(p,{title:`Committing to git`,state:`busy`},A.createElement(E,null,A.createElement(D,{color:r.accent},A.createElement(F,{type:`dots`})),A.createElement(D,null,` `,i===`pushing`?`Pushing to origin`:`Committing`,`…`)),A.createElement(E,{marginTop:1},A.createElement(D,{color:r.muted},o)))},On=({site:e,onDeployed:t,onSkip:n})=>{let{theme:r}=m();return Mn(e=>{e===`y`||e===`Y`||e===`\r`||e===`d`||e===`D`?t():(e===`n`||e===`N`||e===`s`||e===`S`)&&n()}),A.createElement(p,{title:`Ready to deploy?`,state:`idle`},A.createElement(D,null,`The tracker is installed locally. To capture events you need it on the live site:`),A.createElement(D,null,` `),A.createElement(E,null,A.createElement(D,{color:r.muted},` → `),A.createElement(J,{url:e.url})),A.createElement(D,null,` `),A.createElement(D,{color:r.muted},`Push the change through your normal deploy pipeline (Vercel auto-deploy, CI/CD, etc.).`),A.createElement(E,{marginTop:1},A.createElement(D,null,`Once it's deployed, press `),A.createElement(D,{color:r.accent},`[Y]`),A.createElement(D,null,` to verify the tracker is firing. `),A.createElement(D,{color:r.muted},`[s] skip verification`)))},kn=({site:e,onContinue:t})=>{let{theme:n}=m();return Mn(()=>t()),A.createElement(p,{title:`Visit your site`,state:`idle`},A.createElement(D,null,`To send a test event, open any page on your site:`),A.createElement(D,null,` `),A.createElement(E,null,A.createElement(D,{color:n.muted},` → `),A.createElement(J,{url:e.url})),A.createElement(D,null,` `),A.createElement(D,{color:n.muted},`The tracker fires automatically on page load. We'll verify the next event arrives.`),A.createElement(E,{marginTop:1},A.createElement(D,null,`Press `),A.createElement(D,{color:n.accent},`[any key]`),A.createElement(D,null,` when you've visited the page.`)))};async function An(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 jn=({site:t,elapsed:r,onTick:a,onArrived:o,onTimeout:s})=>{let{theme:c}=m(),[l,u]=N(`preflight`),[d,f]=N(``),[h,g]=N([]),_=M(!1),v=t.trackingCode??t.id,y=async()=>{u(`preflight`),f(`Fetching ${t.url}…`);let e=await An(t.url,v);if(!_.current){if(e.state===`tracker-correct`){u(`polling`),f(`Tracker detected on live site — waiting for first hit…`),b();return}if(e.state===`tracker-wrong-id`){u(`wrong-id-on-live`),g(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}.`)}},b=async()=>{let r=Date.now()-10*60*1e3;try{let s=await e(),c=await i({strict:!1}),l=new n({config:s,cliVersion:`0`,token:c}),d=await kt(t.id,r,{api:l,timeoutMs:6e4,pollIntervalMs:2500,onTick:e=>{_.current||a(e)}});if(_.current)return;d.received?(u(`success`),o()):u(`timeout`)}catch{_.current||u(`timeout`)}};j(()=>(_.current=!1,y(),()=>{_.current=!0}),[]),O(e=>{(l===`awaiting-deploy`||l===`wrong-id-on-live`||l===`timeout`)&&(e===`r`||e===`R`?y():(e===`s`||e===`S`)&&s())},{isActive:!0});let x=Math.floor(r/1e3);return l===`preflight`?A.createElement(p,{title:`Verifying`,state:`busy`},A.createElement(E,null,A.createElement(D,{color:c.accent},A.createElement(F,{type:`dots`})),A.createElement(D,null,` Checking your live site for the tracker…`)),A.createElement(E,{marginTop:1},A.createElement(D,{color:c.muted},d))):l===`awaiting-deploy`?A.createElement(p,{title:`Tracker not yet on your live site`,state:`warn`},A.createElement(D,{color:c.warn},d),A.createElement(E,{marginTop:1,flexDirection:`column`},A.createElement(D,null,`The tracker is in your local repo but hasn't been deployed yet.`),A.createElement(D,{color:c.muted},`Push your changes and wait for your deploy to finish (Vercel / Cloudflare Pages / CI), then retry.`)),A.createElement(E,{marginTop:1},A.createElement(D,null,`Press `),A.createElement(D,{color:c.accent},`[r]`),A.createElement(D,null,` to re-check, `),A.createElement(D,{color:c.accent},`[s]`),A.createElement(D,null,` to skip verification.`))):l===`wrong-id-on-live`?A.createElement(p,{title:`Live site has a different tracking code`,state:`warn`},A.createElement(D,{color:c.warn},`Expected: `,A.createElement(D,{color:c.accent},v),` `,`Found on live: `,A.createElement(D,{color:c.accent},h.join(`, `))),A.createElement(E,{marginTop:1,flexDirection:`column`},A.createElement(D,null,`Your local install uses a different ID than what's on `,t.url,`.`),A.createElement(D,{color:c.muted},`Deploy the new local version, then retry — or skip if the existing ID is intentional.`)),A.createElement(E,{marginTop:1},A.createElement(D,null,`Press `),A.createElement(D,{color:c.accent},`[r]`),A.createElement(D,null,` to re-check, `),A.createElement(D,{color:c.accent},`[s]`),A.createElement(D,null,` to skip.`))):l===`timeout`?A.createElement(p,{title:`No event arrived in 3 minutes`,state:`warn`},A.createElement(D,{color:c.warn},`The tracker is on your live site but no hits reached api.zenovay.com.`),A.createElement(E,{marginTop:1},A.createElement(D,{color:c.muted},`Try opening `,t.url,` in a fresh browser tab (no ad-blocker), then retry.`)),A.createElement(E,{marginTop:1},A.createElement(D,null,`Press `),A.createElement(D,{color:c.accent},`[r]`),A.createElement(D,null,` to re-check, `),A.createElement(D,{color:c.accent},`[s]`),A.createElement(D,null,` to finish without verification.`))):A.createElement(p,{title:`Waiting for first event`,state:`busy`},A.createElement(E,null,A.createElement(D,{color:c.accent},A.createElement(F,{type:`dots`})),A.createElement(D,null,` Polling api.zenovay.com for the first hit on `),A.createElement(D,{color:c.accent},t.url),A.createElement(D,null,` (`,x,`s elapsed)`)),A.createElement(E,{marginTop:1},A.createElement(D,{color:c.muted},`Reload the page if nothing arrives within ~30 seconds.`)))};function Mn(e){O((t,n)=>{e(t,{return:n.return,escape:n.escape})},{isActive:!0})}async function Nn(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 Pn(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 Fn(e){try{let t=await x.readFile(b.join(e,`package.json`),`utf8`),n=JSON.parse(t);if(n.name)return String(n.name).replace(/^@[^/]+\//,``)}catch{}try{let t=await x.readFile(b.join(e,`.git`,`config`),`utf8`),n=t.match(/url\s*=\s*.*[/:]([^/]+?)(?:\.git)?\s*$/m);if(n&&n[1])return n[1]}catch{}return b.basename(e)}function In(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=>{let t=$(e.name),r=$(e.url);return t.includes(n)||r.includes(n)||n.includes(t)||n.includes(r)});return a??e[0]??null}function $(e){return e.toLowerCase().replace(/[^a-z0-9]/g,``)}export{ce as detectInstalled,gn as initCommand};
105
+ `);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=on({mode:an(o)});s.registerBridge(v);let y=v.subscribe(e=>s.setPendingApproval(e)),b=null;try{await Bt({api:u,sandbox:d,approval:v,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){b=e}finally{y(),s.setPendingApproval(null)}let x=d.stats();if(x.writes===0){let e=b?`Agent error: ${b.message}`:`Agent returned without writing any files (${x.reads} reads, ${x.rounds} rounds). The model may have refused or the AI Gateway may be misconfigured. Check api.zenovay.com logs.`;throw Error(e)}let S=a.files.map(e=>e.path),C=x.writtenPaths.some(e=>S.some(t=>e===t||e.endsWith(`/${t}`)));if(!C)throw Error(`Agent wrote to: [${x.writtenPaths.join(`, `)}] but never modified the framework's tracker target file(s): [${S.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 w=await W(o.cwd,{[a.envVarName]:f});if(_(`env`,`done`,`${w.addedKeys.length} key(s) added`),!o.skipMcp&&l){_(`mcp`,`active`),s.setLiveLine(`Detecting Cursor / Claude Desktop / VS Code…`);let e=await G({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)),await Z(o.cwd,f,s),s.setSandboxStats?.(x),s.setPhase(`install-complete`)}catch(e){s.setErrorMsg(e.message),s.setPhase(`error`)}}const bn=()=>{let{theme:e}=m();return A.createElement(p,{title:`Zenovay wants to set up your project`,state:`idle`},A.createElement(D,null,`We'll use AI to analyze your codebase and add the Zenovay tracker.`),A.createElement(D,{color:e.muted},`.env* contents stay on your machine. Only framework metadata reaches api.zenovay.com.`))},xn=({adapter:e,site:t,tasks:n,liveLine:r,pendingApproval:i,onApprove:a})=>{let{theme:o}=m(),s=process.stdout.columns??100,c=(process.stdout.rows??30)-8,l=Math.floor(s/2)-1,u=Math.max(14,c);return A.createElement(E,{flexDirection:`column`},A.createElement(E,{flexDirection:`row`,minHeight:u,borderStyle:`round`,borderColor:o.border},A.createElement(E,{width:l,flexDirection:`column`},A.createElement(fn,{width:l,height:u})),A.createElement(E,{width:1,flexDirection:`column`},A.createElement(D,{color:o.border},`│`)),A.createElement(E,{width:l,flexDirection:`column`},i?A.createElement(E,{flexDirection:`column`,paddingX:2,paddingTop:1},A.createElement(D,{color:o.warn},`The agent wants to write `,i.path),i.reason?A.createElement(D,{color:o.muted},i.reason):null,A.createElement(h,{key:i.id,filePath:i.path,oldContent:i.oldContent,newContent:i.newContent,onApprove:a})):A.createElement(A.Fragment,null,A.createElement(E,{paddingX:2,paddingTop:1},A.createElement(g,{done:n.filter(e=>e.status===`done`).length,total:n.length,label:n.find(e=>e.status===`active`)?.label})),A.createElement(hn,{tasks:n,liveLine:r,width:l,height:u})))),A.createElement(E,{marginTop:1},A.createElement(D,{color:o.muted},`Site: `,t.name,` · code: `,t.trackingCode??t.id,` · Framework: `,e.displayName)))},Sn=({site:e,onContinue:t,onExit:n})=>{let{theme:r}=m();O((e,r)=>{if(e===`q`||r.escape){n();return}if(e===`r`||e===`R`){t();return}});let i=e.url.replace(/^https?:\/\//,``).replace(/\/$/,``);return A.createElement(p,{title:`Already installed`,state:`ok`},A.createElement(E,{flexDirection:`column`,gap:1},A.createElement(E,{flexDirection:`row`,gap:1},A.createElement(D,{color:r.success},`✓`),A.createElement(D,{bold:!0},e.name),A.createElement(D,{color:r.muted},`(`,i,`)`)),A.createElement(D,{color:r.muted},`Zenovay is already tracking this project. No changes needed.`),e.trackingCode?A.createElement(D,{color:r.dim},`tracking code: `,e.trackingCode):null))},Cn=({sites:e,preselectHint:t,onPick:n})=>{let r=In(e,t),i=e.filter(e=>e.id!==r?.id),a=r?[r,...i]:i,o=[...a.map(e=>({label:Pn(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 A.createElement(p,{title:t?`Pick a site (best match: ${t})`:`Pick a site`,state:`idle`},A.createElement(_,{items:o,onSelect:n}))};function wn(){let e=process.argv[1]??``;return e.includes(`/_npx/`)||e.includes(`\\_npx\\`)||process.env.npm_execpath?.includes(`npx`)?`npx`:`global`}const Q=({k:e,primary:t})=>{let{theme:n}=m();return A.createElement(D,null,A.createElement(D,{color:n.muted},`[`),A.createElement(D,{bold:!0,color:t?n.accent:n.fg},e),A.createElement(D,{color:n.muted},`] `))},Tn=({adapter:e,site:t,stats:n,arrived:i,onPick:a})=>{let{theme:o}=m(),c=wn(),l=c===`npx`?`npx @zenovay/cli`:`zenovay`,u=r(t),d=n&&n.rounds>0?`${n.writes} file(s) · ${n.rounds} agent round(s)`:n&&n.writes>0?`${n.writes} file(s) · programmatic (no AI calls)`:null;return O((e,t)=>{let n=e.toLowerCase();n===`w`||t.return?a(`watch`):n===`o`?s(u).catch(()=>void 0):n===`e`?a(`events`):(n===`s`||n===`q`||t.escape)&&a(`quit`)},{isActive:!0}),A.createElement(p,{title:`You're live on Zenovay`,state:`ok`},A.createElement(D,{bold:!0,color:o.success},i?`✓ First event received from ${t.name}`:`✓ Installed successfully`),A.createElement(D,{color:o.accent},`─`.repeat(18)),A.createElement(E,{marginTop:1,flexDirection:`column`},A.createElement(Y,{label:`Framework`,value:e.displayName}),A.createElement(Y,{label:`Site`,value:A.createElement(J,{url:t.url,label:t.name})}),t.trackingCode?A.createElement(Y,{label:`Tracker`,value:A.createElement(D,{color:o.muted},t.trackingCode)}):null,d?A.createElement(Y,{label:`Changes`,value:A.createElement(D,{color:o.muted},d)}):null,A.createElement(Y,{label:`Dashboard`,value:A.createElement(J,{url:u})})),A.createElement(E,{marginTop:1,flexDirection:`column`},A.createElement(D,{color:o.dim},`WHAT'S NEXT`),A.createElement(E,{marginTop:1},A.createElement(D,null,` `),A.createElement(Q,{k:`W`,primary:!0}),A.createElement(D,null,`Watch live in this terminal `),A.createElement(D,{color:o.muted},`— visitors, pages, sources, vitals`)),A.createElement(E,null,A.createElement(D,null,` `),A.createElement(Q,{k:`O`}),A.createElement(D,null,`Open the dashboard in your browser`)),A.createElement(E,null,A.createElement(D,null,` `),A.createElement(Q,{k:`E`}),A.createElement(D,null,`Stream events as they fire `),A.createElement(D,{color:o.muted},`— page views, custom events, live`)),A.createElement(E,null,A.createElement(D,null,` `),A.createElement(Q,{k:`S`}),A.createElement(D,null,`Exit to shell`))),c===`npx`?A.createElement(E,{marginTop:1,flexDirection:`column`,borderStyle:`single`,borderColor:o.warn,paddingX:1},A.createElement(D,{color:o.warn,bold:!0},`Heads up — you ran via npx`),A.createElement(D,{color:o.muted},"The `zenovay` command isn't on your PATH yet. After you exit, run:"),A.createElement(E,{marginTop:1},A.createElement(D,{color:o.fg},` npm i -g @zenovay/cli `),A.createElement(D,{color:o.muted},"→ then `zenovay overview` works directly"))):A.createElement(E,{marginTop:1},A.createElement(D,{color:o.muted},`From your shell: `),A.createElement(D,{color:o.fg},l,` overview`),A.createElement(D,{color:o.muted},` · `),A.createElement(D,{color:o.fg},l,` --help`)))},En=({adapter:e,site:t,stats:n,verify:r,onCommit:i,onSkipCommit:a})=>{let{theme:o}=m();return Mn(e=>{e===`y`||e===`Y`||e===`\r`?i():(e===`n`||e===`N`||e===`s`||e===`S`)&&a()}),A.createElement(p,{title:`Tracker installed`,state:r&&!r.ok?`warn`:`ok`},r?A.createElement(D,null,A.createElement(D,{color:r.ok?o.success:o.warn},r.ok?`✔ Verified — `:`⚠ `),r.detail):A.createElement(D,null,A.createElement(D,{color:o.success},`✔ `),`The Zenovay tracker is in your project.`),A.createElement(E,{marginTop:1},A.createElement(D,{color:o.muted},`Framework: `),A.createElement(D,null,e.displayName)),A.createElement(E,null,A.createElement(D,{color:o.muted},`Site: `),A.createElement(D,null,t.name,` (`,t.url,`)`)),n&&A.createElement(E,null,A.createElement(D,{color:o.muted},`Modified: `),A.createElement(D,null,n.writes,` file(s)`)),A.createElement(E,{marginTop:1},A.createElement(D,null,`Commit + push these changes to git? `),A.createElement(D,{color:o.accent},`[Y/n]`)))},Dn=({cwd:e,onDone:t,onError:n})=>{let{theme:r}=m(),[i,a]=M(`committing`),[o,s]=M(`Staging changes…`);return j(()=>{(async()=>{try{let n=await Nn(e,e=>s(e),e=>a(e));n.committed?s(`Pushed ${n.shortSha} to origin/${n.branch}`):s(`No changes to commit (already up-to-date).`),setTimeout(()=>t(n),800)}catch(e){n(e.message)}})()},[]),A.createElement(p,{title:`Committing to git`,state:`busy`},A.createElement(E,null,A.createElement(D,{color:r.accent},A.createElement(P,{type:`dots`})),A.createElement(D,null,` `,i===`pushing`?`Pushing to origin`:`Committing`,`…`)),A.createElement(E,{marginTop:1},A.createElement(D,{color:r.muted},o)))},On=({site:e,onDeployed:t,onSkip:n})=>{let{theme:r}=m();return Mn(e=>{e===`y`||e===`Y`||e===`\r`||e===`d`||e===`D`?t():(e===`n`||e===`N`||e===`s`||e===`S`)&&n()}),A.createElement(p,{title:`Ready to deploy?`,state:`idle`},A.createElement(D,null,`The tracker is installed locally. To capture events you need it on the live site:`),A.createElement(D,null,` `),A.createElement(E,null,A.createElement(D,{color:r.muted},` → `),A.createElement(J,{url:e.url})),A.createElement(D,null,` `),A.createElement(D,{color:r.muted},`Push the change through your normal deploy pipeline (Vercel auto-deploy, CI/CD, etc.).`),A.createElement(E,{marginTop:1},A.createElement(D,null,`Once it's deployed, press `),A.createElement(D,{color:r.accent},`[Y]`),A.createElement(D,null,` to verify the tracker is firing. `),A.createElement(D,{color:r.muted},`[s] skip verification`)))},kn=({site:e,onContinue:t})=>{let{theme:n}=m();return Mn(()=>t()),A.createElement(p,{title:`Visit your site`,state:`idle`},A.createElement(D,null,`To send a test event, open any page on your site:`),A.createElement(D,null,` `),A.createElement(E,null,A.createElement(D,{color:n.muted},` → `),A.createElement(J,{url:e.url})),A.createElement(D,null,` `),A.createElement(D,{color:n.muted},`The tracker fires automatically on page load. We'll verify the next event arrives.`),A.createElement(E,{marginTop:1},A.createElement(D,null,`Press `),A.createElement(D,{color:n.accent},`[any key]`),A.createElement(D,null,` when you've visited the page.`)))};async function An(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 jn=({site:t,elapsed:r,onTick:a,onArrived:o,onTimeout:s})=>{let{theme:c}=m(),[l,u]=M(`preflight`),[d,f]=M(``),[h,g]=M([]),_=ne(!1),v=t.trackingCode??t.id,y=async()=>{u(`preflight`),f(`Fetching ${t.url}…`);let e=await An(t.url,v);if(!_.current){if(e.state===`tracker-correct`){u(`polling`),f(`Tracker detected on live site — waiting for first hit…`),b();return}if(e.state===`tracker-wrong-id`){u(`wrong-id-on-live`),g(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}.`)}},b=async()=>{let r=Date.now()-10*60*1e3;try{let s=await e(),c=await i({strict:!1}),l=new n({config:s,cliVersion:`0`,token:c}),d=await kt(t.id,r,{api:l,timeoutMs:6e4,pollIntervalMs:2500,onTick:e=>{_.current||a(e)}});if(_.current)return;d.received?(u(`success`),o()):u(`timeout`)}catch{_.current||u(`timeout`)}};j(()=>(_.current=!1,y(),()=>{_.current=!0}),[]),O(e=>{(l===`awaiting-deploy`||l===`wrong-id-on-live`||l===`timeout`)&&(e===`r`||e===`R`?y():(e===`s`||e===`S`)&&s())},{isActive:!0});let x=Math.floor(r/1e3);return l===`preflight`?A.createElement(p,{title:`Verifying`,state:`busy`},A.createElement(E,null,A.createElement(D,{color:c.accent},A.createElement(P,{type:`dots`})),A.createElement(D,null,` Checking your live site for the tracker…`)),A.createElement(E,{marginTop:1},A.createElement(D,{color:c.muted},d))):l===`awaiting-deploy`?A.createElement(p,{title:`Tracker not yet on your live site`,state:`warn`},A.createElement(D,{color:c.warn},d),A.createElement(E,{marginTop:1,flexDirection:`column`},A.createElement(D,null,`The tracker is in your local repo but hasn't been deployed yet.`),A.createElement(D,{color:c.muted},`Push your changes and wait for your deploy to finish (Vercel / Cloudflare Pages / CI), then retry.`)),A.createElement(E,{marginTop:1},A.createElement(D,null,`Press `),A.createElement(D,{color:c.accent},`[r]`),A.createElement(D,null,` to re-check, `),A.createElement(D,{color:c.accent},`[s]`),A.createElement(D,null,` to skip verification.`))):l===`wrong-id-on-live`?A.createElement(p,{title:`Live site has a different tracking code`,state:`warn`},A.createElement(D,{color:c.warn},`Expected: `,A.createElement(D,{color:c.accent},v),` `,`Found on live: `,A.createElement(D,{color:c.accent},h.join(`, `))),A.createElement(E,{marginTop:1,flexDirection:`column`},A.createElement(D,null,`Your local install uses a different ID than what's on `,t.url,`.`),A.createElement(D,{color:c.muted},`Deploy the new local version, then retry — or skip if the existing ID is intentional.`)),A.createElement(E,{marginTop:1},A.createElement(D,null,`Press `),A.createElement(D,{color:c.accent},`[r]`),A.createElement(D,null,` to re-check, `),A.createElement(D,{color:c.accent},`[s]`),A.createElement(D,null,` to skip.`))):l===`timeout`?A.createElement(p,{title:`No event arrived in 3 minutes`,state:`warn`},A.createElement(D,{color:c.warn},`The tracker is on your live site but no hits reached api.zenovay.com.`),A.createElement(E,{marginTop:1},A.createElement(D,{color:c.muted},`Try opening `,t.url,` in a fresh browser tab (no ad-blocker), then retry.`)),A.createElement(E,{marginTop:1},A.createElement(D,null,`Press `),A.createElement(D,{color:c.accent},`[r]`),A.createElement(D,null,` to re-check, `),A.createElement(D,{color:c.accent},`[s]`),A.createElement(D,null,` to finish without verification.`))):A.createElement(p,{title:`Waiting for first event`,state:`busy`},A.createElement(E,null,A.createElement(D,{color:c.accent},A.createElement(P,{type:`dots`})),A.createElement(D,null,` Polling api.zenovay.com for the first hit on `),A.createElement(D,{color:c.accent},t.url),A.createElement(D,null,` (`,x,`s elapsed)`)),A.createElement(E,{marginTop:1},A.createElement(D,{color:c.muted},`Reload the page if nothing arrives within ~30 seconds.`)))};function Mn(e){O((t,n)=>{e(t,{return:n.return,escape:n.escape})},{isActive:!0})}async function Nn(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 Pn(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 Fn(e){try{let t=await x.readFile(b.join(e,`package.json`),`utf8`),n=JSON.parse(t);if(n.name)return String(n.name).replace(/^@[^/]+\//,``)}catch{}try{let t=await x.readFile(b.join(e,`.git`,`config`),`utf8`),n=t.match(/url\s*=\s*.*[/:]([^/]+?)(?:\.git)?\s*$/m);if(n&&n[1])return n[1]}catch{}return b.basename(e)}function In(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=>{let t=$(e.name),r=$(e.url);return t.includes(n)||r.includes(n)||n.includes(t)||n.includes(r)});return a??e[0]??null}function $(e){return e.toLowerCase().replace(/[^a-z0-9]/g,``)}export{ce as detectInstalled,gn as initCommand};
@@ -0,0 +1 @@
1
+ import"./config-JVhBplSX.js";import"./api-CdcB84ie.js";import"./token-store-BvSCse1t.js";import{initCommand as e}from"./init-igNlvq0N.js";import"./formatter-C4YSOKuq.js";import"./emit-D4YlMlzk.js";import"./open-url-BtI5aLgL.js";import"./secrets-ApB7yh2A.js";import"./client-ntsEXSVC.js";import"./login-DU1fY88U.js";import"./theme-Brz9wK0w.js";import"./panel-CTtQ2ue6.js";import"./progress-row-Afnt5Ng8.js";import"./prompt-BXvg2B4R.js";import"./keybar-DO5OoZy9.js";import"./sparkline-CpoBjjlc.js";export{e as initCommand};
@@ -1 +1 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import"./api-hWp9s3Y8.js";import{readToken as t}from"./token-store-BQuGH0z2.js";import{ApiV2Client as n}from"./api-v2-DqKh6FgZ.js";import{requireTier as r}from"./tier-BneaO4vD.js";import"./formatter-C4YSOKuq.js";import{emit$1 as i,isHeadless as a}from"./emit-D4YlMlzk.js";import{openInBrowser as o}from"./open-url-BtI5aLgL.js";import"./theme-Brz9wK0w.js";import{Banner as s,Panel as c,useTheme as l}from"./panel-CTtQ2ue6.js";import"./prompt-BXvg2B4R.js";import{Keybar as u}from"./keybar-DO5OoZy9.js";import{resolveSiteId as d}from"./resolve-site-BLrtFOyW.js";import{EmptyState as f}from"./empty-state-D-krMX62.js";import{deepLinkFor as p}from"./keybar-deep-link-B4VJn2ko.js";import{useFullscreen as m}from"./use-fullscreen-ucSyZkjO.js";import{useSiteSwitcher as h}from"./site-switcher-D_JBKFaR.js";import{Box as g,Text as _,render as v,useApp as y,useInput as b}from"ink";import x,{useEffect as S,useState as C}from"react";import w from"ink-spinner";function T(e){return e===`critical`?`err`:e===`warning`?`warn`:`ok`}function E(e){return e===`anomaly`?`⚡ anomaly`:e===`recommendation`?`✦ recommendation`:`↗ trend`}async function D(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 l=new n({config:s,cliVersion:o.cliVersion,token:c});try{await r(l,`pro`)}catch(e){return process.stderr.write(`${e.message}\n`),2}let u,f;try{({siteId:u,site:f}=await d(l,{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??u;if(a(o)){let e=await l.getInsights(u);return i({type:`insights.snapshot`,data:e}),0}return new Promise(e=>{let{unmount:t}=v(x.createElement(O,{api:l,siteId:u,siteLabel:p,cliVersion:o.cliVersion,onExit:n=>{t(),e(n)}}))})}const O=({api:e,siteId:t,siteLabel:n,cliVersion:r,onExit:i})=>{m();let{exit:a}=y(),{theme:d}=l(),[v,D]=C(null),[O,k]=C(!0),[A,j]=C(null),[M,N]=C(t),[P,F]=C(n),I=h(e,M,e=>{N(e.id),F(e.url.replace(/^https?:\/\//,``).replace(/\/$/,``)),D(null)});b((e,t)=>{if(I.open){(t.escape||e===`s`)&&I.close();return}if(e===`o`||e===`O`){o(p(`insights`,{siteId:M}));return}if(e===`s`){I.toggle();return}e===`q`&&(a(),i(0))}),S(()=>{let t=!1;return v===null&&k(!0),(async()=>{try{let n=await e.getInsights(M);t||(D(n),k(!1))}catch(e){t||(j(e.message),k(!1))}})(),()=>{t=!0}},[e,M]);let L=[{key:`s`,label:`site`},{key:`o`,label:`open in browser`},{key:`q`,label:`quit`}];if(O)return x.createElement(g,{flexDirection:`column`},x.createElement(s,{version:r,subtitle:`insights · ${P}`}),x.createElement(c,{title:`Loading`,state:`busy`},x.createElement(g,null,x.createElement(_,{color:d.accent},x.createElement(w,{type:`dots`})),x.createElement(_,null,` Fetching insights…`))));if(A)return x.createElement(g,{flexDirection:`column`},x.createElement(s,{version:r,subtitle:`insights · ${P}`}),x.createElement(f,{reason:`error`,headline:`Failed to load`,hint:A}),I.overlay,x.createElement(u,{items:L}));if(!v||v.length===0)return x.createElement(g,{flexDirection:`column`},x.createElement(s,{version:r,subtitle:`insights · ${P}`}),x.createElement(f,{reason:`no-data`,headline:`No insights yet`,hint:`Insights are generated nightly — check back tomorrow, send more traffic to give the model something to analyze, or press [s] to switch site.`}),I.overlay,x.createElement(u,{items:L}));let R=process.stdout.rows??40,z=Math.max(1,Math.floor((R-10)/4)),B=v.slice(0,z),V=v.length-B.length;return x.createElement(g,{flexDirection:`column`},x.createElement(s,{version:r,subtitle:`insights · ${P}`}),B.map((e,t)=>x.createElement(c,{key:t,title:`${E(e.kind)} · ${e.severity}`,state:T(e.severity)},x.createElement(_,{color:d.typography.title.color,bold:d.typography.title.bold,wrap:`truncate`},e.title),e.body?x.createElement(_,{color:d.muted,wrap:`truncate-end`},e.body):null)),V>0?x.createElement(g,{marginTop:1},x.createElement(_,{color:d.dim},` +${V} more insight${V===1?``:`s`} · run with --json for all`)):null,I.overlay,x.createElement(u,{items:L,active:`o`}))};export{D as insightsCommand};
1
+ import{readConfig as e}from"./config-JVhBplSX.js";import"./api-CdcB84ie.js";import{readToken as t}from"./token-store-BvSCse1t.js";import{ApiV2Client as n}from"./api-v2-D0mvt__4.js";import{requireTier as r}from"./tier-DDIroQbc.js";import"./formatter-C4YSOKuq.js";import{emit$1 as i,isHeadless as a}from"./emit-D4YlMlzk.js";import{openInBrowser as o}from"./open-url-BtI5aLgL.js";import"./theme-Brz9wK0w.js";import{Banner as s,Panel as c,useTheme as l}from"./panel-CTtQ2ue6.js";import"./prompt-BXvg2B4R.js";import{Keybar as u}from"./keybar-DO5OoZy9.js";import{resolveSiteId as d}from"./resolve-site-BTVBMF1C.js";import{EmptyState as f}from"./empty-state-D-krMX62.js";import{deepLinkFor as p}from"./keybar-deep-link-B4VJn2ko.js";import{useFullscreen as m}from"./use-fullscreen-ucSyZkjO.js";import{useSiteSwitcher as h}from"./site-switcher-BAoYWp18.js";import{Box as g,Text as _,render as v,useApp as y,useInput as b}from"ink";import x,{useEffect as S,useState as C}from"react";import w from"ink-spinner";function T(e){return e===`critical`?`err`:e===`warning`?`warn`:`ok`}function E(e){return e===`anomaly`?`⚡ anomaly`:e===`recommendation`?`✦ recommendation`:`↗ trend`}async function D(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 l=new n({config:s,cliVersion:o.cliVersion,token:c});try{await r(l,`pro`)}catch(e){return process.stderr.write(`${e.message}\n`),2}let u,f;try{({siteId:u,site:f}=await d(l,{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??u;if(a(o)){let e=await l.getInsights(u);return i({type:`insights.snapshot`,data:e}),0}return new Promise(e=>{let{unmount:t}=v(x.createElement(O,{api:l,siteId:u,siteLabel:p,cliVersion:o.cliVersion,onExit:n=>{t(),e(n)}}))})}const O=({api:e,siteId:t,siteLabel:n,cliVersion:r,onExit:i})=>{m();let{exit:a}=y(),{theme:d}=l(),[v,D]=C(null),[O,k]=C(!0),[A,j]=C(null),[M,N]=C(t),[P,F]=C(n),I=h(e,M,e=>{N(e.id),F(e.url.replace(/^https?:\/\//,``).replace(/\/$/,``)),D(null)});b((e,t)=>{if(I.open){(t.escape||e===`s`)&&I.close();return}if(e===`o`||e===`O`){o(p(`insights`,{siteId:M}));return}if(e===`s`){I.toggle();return}e===`q`&&(a(),i(0))}),S(()=>{let t=!1;return v===null&&k(!0),(async()=>{try{let n=await e.getInsights(M);t||(D(n),k(!1))}catch(e){t||(j(e.message),k(!1))}})(),()=>{t=!0}},[e,M]);let L=[{key:`s`,label:`site`},{key:`o`,label:`open in browser`},{key:`q`,label:`quit`}];if(O)return x.createElement(g,{flexDirection:`column`},x.createElement(s,{version:r,subtitle:`insights · ${P}`}),x.createElement(c,{title:`Loading`,state:`busy`},x.createElement(g,null,x.createElement(_,{color:d.accent},x.createElement(w,{type:`dots`})),x.createElement(_,null,` Fetching insights…`))));if(A)return x.createElement(g,{flexDirection:`column`},x.createElement(s,{version:r,subtitle:`insights · ${P}`}),x.createElement(f,{reason:`error`,headline:`Failed to load`,hint:A}),I.overlay,x.createElement(u,{items:L}));if(!v||v.length===0)return x.createElement(g,{flexDirection:`column`},x.createElement(s,{version:r,subtitle:`insights · ${P}`}),x.createElement(f,{reason:`no-data`,headline:`No insights yet`,hint:`Insights are generated nightly — check back tomorrow, send more traffic to give the model something to analyze, or press [s] to switch site.`}),I.overlay,x.createElement(u,{items:L}));let R=process.stdout.rows??40,z=Math.max(1,Math.floor((R-10)/4)),B=v.slice(0,z),V=v.length-B.length;return x.createElement(g,{flexDirection:`column`},x.createElement(s,{version:r,subtitle:`insights · ${P}`}),B.map((e,t)=>x.createElement(c,{key:t,title:`${E(e.kind)} · ${e.severity}`,state:T(e.severity)},x.createElement(_,{color:d.typography.title.color,bold:d.typography.title.bold,wrap:`truncate`},e.title),e.body?x.createElement(_,{color:d.muted,wrap:`truncate-end`},e.body):null)),V>0?x.createElement(g,{marginTop:1},x.createElement(_,{color:d.dim},` +${V} more insight${V===1?``:`s`} · run with --json for all`)):null,I.overlay,x.createElement(u,{items:L,active:`o`}))};export{D as insightsCommand};
@@ -1,4 +1,4 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import"./api-hWp9s3Y8.js";import{readToken as t}from"./token-store-BQuGH0z2.js";import{ApiV2Client as n}from"./api-v2-DqKh6FgZ.js";import{confirmDestructive as r}from"./confirm-DS5wux0g.js";import{openInBrowser as i}from"./open-url-BtI5aLgL.js";async function a(a){let o=await e(),s=await t({strict:!1}),c=new n({config:o,cliVersion:a.cliVersion,token:s});try{switch(a.action){case`list`:{let{integrations:e}=await c.listIntegrations();if(a.json)return process.stdout.write(JSON.stringify({integrations:e},null,2)+`
1
+ import{readConfig as e}from"./config-JVhBplSX.js";import"./api-CdcB84ie.js";import{readToken as t}from"./token-store-BvSCse1t.js";import{ApiV2Client as n}from"./api-v2-D0mvt__4.js";import{confirmDestructive as r}from"./confirm-DS5wux0g.js";import{openInBrowser as i}from"./open-url-BtI5aLgL.js";async function a(a){let o=await e(),s=await t({strict:!1}),c=new n({config:o,cliVersion:a.cliVersion,token:s});try{switch(a.action){case`list`:{let{integrations:e}=await c.listIntegrations();if(a.json)return process.stdout.write(JSON.stringify({integrations:e},null,2)+`
2
2
  `),0;let t=[10,30,14],n=e=>e.map((e,n)=>(e??``).padEnd(t[n])).join(` `);process.stdout.write(`
3
3
  `+n([`name`,`service`,`status`])+`
4
4
  `),process.stdout.write(n(t.map(e=>`─`.repeat(e)))+`
@@ -1 +1 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import"./api-hWp9s3Y8.js";import{readToken as t}from"./token-store-BQuGH0z2.js";import{ApiV2Client as n}from"./api-v2-DqKh6FgZ.js";import{requireTier as r}from"./tier-BneaO4vD.js";import"./formatter-C4YSOKuq.js";import{emit$1 as i,isHeadless as a}from"./emit-D4YlMlzk.js";import{openInBrowser as o}from"./open-url-BtI5aLgL.js";import"./theme-Brz9wK0w.js";import{Banner as s,Panel as c,usePanelWidth as l,useTheme as u}from"./panel-CTtQ2ue6.js";import"./prompt-BXvg2B4R.js";import{Keybar as d}from"./keybar-DO5OoZy9.js";import{resolveSiteId as f}from"./resolve-site-BLrtFOyW.js";import{stripUrlPrefix as p}from"./fmt-xxIPQJX-.js";import{EmptyState as m}from"./empty-state-D-krMX62.js";import{Bar as h}from"./bar-NfgovYHe.js";import{deepLinkFor as g}from"./keybar-deep-link-B4VJn2ko.js";import{useFullscreen as _}from"./use-fullscreen-ucSyZkjO.js";import{useSiteSwitcher as v}from"./site-switcher-D_JBKFaR.js";import{Box as y,Text as b,render as x,useApp as S,useInput as C}from"ink";import w,{useEffect as T,useState as E}from"react";import D from"ink-spinner";async function O(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 l=new n({config:s,cliVersion:o.cliVersion,token:c});try{await r(l,`pro`)}catch(e){return process.stderr.write(`${e.message}\n`),2}let u,d;try{({siteId:u,site:d}=await f(l,{explicit:o.siteId,headless:!!o.json,cliVersion:o.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let p=d?.url?d.url.replace(/^https?:\/\//,``).replace(/\/$/,``):d?.name??u;if(a(o)){let e=await l.getJourneys(u);return i({type:`journeys.snapshot`,data:e}),0}return new Promise(e=>{let{unmount:t}=x(w.createElement(k,{api:l,siteId:u,siteLabel:p,cliVersion:o.cliVersion,onExit:n=>{t(),e(n)}}))})}const k=({api:e,siteId:t,siteLabel:n,cliVersion:r,onExit:i})=>{_();let{theme:a}=u(),{exit:l}=S(),[f,p]=E(null),[h,x]=E(!0),[O,k]=E(null),[j,M]=E(t),[N,P]=E(n),F=v(e,j,e=>{M(e.id),P(e.url.replace(/^https?:\/\//,``).replace(/\/$/,``)),p(null)});C((e,t)=>{if(F.open){(t.escape||e===`s`)&&F.close();return}if(e===`o`||e===`O`){o(g(`journeys`,{siteId:j}));return}if(e===`s`){F.toggle();return}e===`q`&&(l(),i(0))}),T(()=>{let t=!1;return f===null&&x(!0),(async()=>{try{let n=await e.getJourneys(j);t||(p(n.flows),x(!1))}catch(e){t||(k(e.message),x(!1))}})(),()=>{t=!0}},[e,j]);let I=[{key:`o`,label:`open in browser`},{key:`s`,label:`site`},{key:`q`,label:`quit`}];if(h)return w.createElement(y,{flexDirection:`column`},w.createElement(s,{version:r,subtitle:`journeys · ${N}`}),w.createElement(c,{title:`Loading`,state:`busy`},w.createElement(y,null,w.createElement(b,{color:a.accent},w.createElement(D,{type:`dots`})),w.createElement(b,null,` Computing flows…`))));if(O)return w.createElement(y,{flexDirection:`column`},w.createElement(s,{version:r,subtitle:`journeys · ${N}`}),w.createElement(m,{reason:`error`,headline:`Failed to load`,hint:O}),w.createElement(d,{items:I}));if(!f||f.length===0)return w.createElement(y,{flexDirection:`column`},w.createElement(s,{version:r,subtitle:`journeys · ${N}`}),w.createElement(m,{reason:`no-data`,headline:`No journeys yet`,hint:`Need at least 2 page-views per session to compute flows — send more traffic, then re-run, or press [s] to switch site.`}),F.overlay,w.createElement(d,{items:I}));let L=Math.max(...f.map(e=>e.count),1),R=process.stdout.rows??40,z=Math.max(3,R-12),B=f.slice(0,z),V=f.length-B.length;return w.createElement(y,{flexDirection:`column`},w.createElement(s,{version:r,subtitle:`journeys · ${N}`}),w.createElement(c,{title:`Top page transitions (${f.length})`},B.map((e,t)=>w.createElement(A,{key:t,from:e.from,to:e.to,count:e.count,max:L})),V>0?w.createElement(b,{color:a.dim},` +${V} more · run with --json for all`):null),F.overlay,w.createElement(d,{items:I,active:`o`}))},A=({from:e,to:t,count:n,max:r})=>{let{theme:i}=u(),a=l()??(process.stdout.columns??80)-4,o=Math.max(8,Math.min(24,Math.floor((a-18)/3))),s=Math.max(4,a-o*2-3-4-7);return w.createElement(y,{flexDirection:`row`,width:a},w.createElement(y,{width:o,flexShrink:0},w.createElement(b,{wrap:`truncate`},p(e))),w.createElement(y,{flexShrink:0},w.createElement(b,{color:i.accent},` → `)),w.createElement(y,{width:o,flexShrink:0},w.createElement(b,{wrap:`truncate`},p(t))),w.createElement(y,{marginLeft:2,flexShrink:0},w.createElement(h,{value:n,max:r,width:s,showPercent:!1,track:!0})),w.createElement(y,{flexGrow:1,justifyContent:`flex-end`},w.createElement(b,{color:i.fg},n.toLocaleString())))};export{O as journeysCommand};
1
+ import{readConfig as e}from"./config-JVhBplSX.js";import"./api-CdcB84ie.js";import{readToken as t}from"./token-store-BvSCse1t.js";import{ApiV2Client as n}from"./api-v2-D0mvt__4.js";import{requireTier as r}from"./tier-DDIroQbc.js";import"./formatter-C4YSOKuq.js";import{emit$1 as i,isHeadless as a}from"./emit-D4YlMlzk.js";import{openInBrowser as o}from"./open-url-BtI5aLgL.js";import"./theme-Brz9wK0w.js";import{Banner as s,Panel as c,usePanelWidth as l,useTheme as u}from"./panel-CTtQ2ue6.js";import"./prompt-BXvg2B4R.js";import{Keybar as d}from"./keybar-DO5OoZy9.js";import{resolveSiteId as f}from"./resolve-site-BTVBMF1C.js";import{stripUrlPrefix as p}from"./fmt-xxIPQJX-.js";import{EmptyState as m}from"./empty-state-D-krMX62.js";import{Bar as h}from"./bar-NfgovYHe.js";import{deepLinkFor as g}from"./keybar-deep-link-B4VJn2ko.js";import{useFullscreen as _}from"./use-fullscreen-ucSyZkjO.js";import{useSiteSwitcher as v}from"./site-switcher-BAoYWp18.js";import{Box as y,Text as b,render as x,useApp as S,useInput as C}from"ink";import w,{useEffect as T,useState as E}from"react";import D from"ink-spinner";async function O(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 l=new n({config:s,cliVersion:o.cliVersion,token:c});try{await r(l,`pro`)}catch(e){return process.stderr.write(`${e.message}\n`),2}let u,d;try{({siteId:u,site:d}=await f(l,{explicit:o.siteId,headless:!!o.json,cliVersion:o.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let p=d?.url?d.url.replace(/^https?:\/\//,``).replace(/\/$/,``):d?.name??u;if(a(o)){let e=await l.getJourneys(u);return i({type:`journeys.snapshot`,data:e}),0}return new Promise(e=>{let{unmount:t}=x(w.createElement(k,{api:l,siteId:u,siteLabel:p,cliVersion:o.cliVersion,onExit:n=>{t(),e(n)}}))})}const k=({api:e,siteId:t,siteLabel:n,cliVersion:r,onExit:i})=>{_();let{theme:a}=u(),{exit:l}=S(),[f,p]=E(null),[h,x]=E(!0),[O,k]=E(null),[j,M]=E(t),[N,P]=E(n),F=v(e,j,e=>{M(e.id),P(e.url.replace(/^https?:\/\//,``).replace(/\/$/,``)),p(null)});C((e,t)=>{if(F.open){(t.escape||e===`s`)&&F.close();return}if(e===`o`||e===`O`){o(g(`journeys`,{siteId:j}));return}if(e===`s`){F.toggle();return}e===`q`&&(l(),i(0))}),T(()=>{let t=!1;return f===null&&x(!0),(async()=>{try{let n=await e.getJourneys(j);t||(p(n.flows),x(!1))}catch(e){t||(k(e.message),x(!1))}})(),()=>{t=!0}},[e,j]);let I=[{key:`o`,label:`open in browser`},{key:`s`,label:`site`},{key:`q`,label:`quit`}];if(h)return w.createElement(y,{flexDirection:`column`},w.createElement(s,{version:r,subtitle:`journeys · ${N}`}),w.createElement(c,{title:`Loading`,state:`busy`},w.createElement(y,null,w.createElement(b,{color:a.accent},w.createElement(D,{type:`dots`})),w.createElement(b,null,` Computing flows…`))));if(O)return w.createElement(y,{flexDirection:`column`},w.createElement(s,{version:r,subtitle:`journeys · ${N}`}),w.createElement(m,{reason:`error`,headline:`Failed to load`,hint:O}),w.createElement(d,{items:I}));if(!f||f.length===0)return w.createElement(y,{flexDirection:`column`},w.createElement(s,{version:r,subtitle:`journeys · ${N}`}),w.createElement(m,{reason:`no-data`,headline:`No journeys yet`,hint:`Need at least 2 page-views per session to compute flows — send more traffic, then re-run, or press [s] to switch site.`}),F.overlay,w.createElement(d,{items:I}));let L=Math.max(...f.map(e=>e.count),1),R=process.stdout.rows??40,z=Math.max(3,R-12),B=f.slice(0,z),V=f.length-B.length;return w.createElement(y,{flexDirection:`column`},w.createElement(s,{version:r,subtitle:`journeys · ${N}`}),w.createElement(c,{title:`Top page transitions (${f.length})`},B.map((e,t)=>w.createElement(A,{key:t,from:e.from,to:e.to,count:e.count,max:L})),V>0?w.createElement(b,{color:a.dim},` +${V} more · run with --json for all`):null),F.overlay,w.createElement(d,{items:I,active:`o`}))},A=({from:e,to:t,count:n,max:r})=>{let{theme:i}=u(),a=l()??(process.stdout.columns??80)-4,o=Math.max(8,Math.min(24,Math.floor((a-18)/3))),s=Math.max(4,a-o*2-3-4-7);return w.createElement(y,{flexDirection:`row`,width:a},w.createElement(y,{width:o,flexShrink:0},w.createElement(b,{wrap:`truncate`},p(e))),w.createElement(y,{flexShrink:0},w.createElement(b,{color:i.accent},` → `)),w.createElement(y,{width:o,flexShrink:0},w.createElement(b,{wrap:`truncate`},p(t))),w.createElement(y,{marginLeft:2,flexShrink:0},w.createElement(h,{value:n,max:r,width:s,showPercent:!1,track:!0})),w.createElement(y,{flexGrow:1,justifyContent:`flex-end`},w.createElement(b,{color:i.fg},n.toLocaleString())))};export{O as journeysCommand};
@@ -1 +1 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import"./api-hWp9s3Y8.js";import{readToken as t}from"./token-store-BQuGH0z2.js";import"./telemetry-DRh10SvO.js";import{ApiV2Client as n}from"./api-v2-DqKh6FgZ.js";import"./formatter-C4YSOKuq.js";import{emit$1 as r,isHeadless as i}from"./emit-D4YlMlzk.js";import{openInBrowser as a}from"./open-url-BtI5aLgL.js";import"./client-ntsEXSVC.js";import"./theme-Brz9wK0w.js";import{Banner as o,Panel as s,useTheme as c}from"./panel-CTtQ2ue6.js";import"./prompt-BXvg2B4R.js";import{Keybar as l}from"./keybar-DO5OoZy9.js";import"./sparkline-CpoBjjlc.js";import{ChatPanel as u}from"./chat-panel-PSN5hjlF.js";import{resolveSiteId as d}from"./resolve-site-BLrtFOyW.js";import{stripUrlPrefix as f}from"./fmt-xxIPQJX-.js";import{DataTable as p}from"./data-table-BhKjjiOS.js";import{EmptyState as ee}from"./empty-state-D-krMX62.js";import{tileWidths as m}from"./grid-CMwhs-Ms.js";import{MetricCard as h}from"./metric-card-C4iqxdww.js";import{deepLinkFor as g}from"./keybar-deep-link-B4VJn2ko.js";import{useFullscreen as te}from"./use-fullscreen-ucSyZkjO.js";import{useSiteSwitcher as ne}from"./site-switcher-D_JBKFaR.js";import{Box as _,Text as v,render as y,useApp as b,useInput as x}from"ink";import S,{useEffect as re,useState as C}from"react";import ie from"ink-spinner";function ae(e,t){let n=Math.max(0,Math.round((t-e)/1e3));if(n<5)return`just now`;if(n<60)return`${n}s ago`;let r=Math.floor(n/60);return r<60?`${r}m ago`:`${Math.floor(r/60)}h ago`}async function w(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}),l,u;try{({siteId:l,site:u}=await d(c,{explicit:a.siteId,headless:!!a.json,cliVersion:a.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let f=u?.url?u.url.replace(/^https?:\/\//,``).replace(/\/$/,``):u?.name??l;if(i(a)){let e=await c.getLive(l);return r({type:`live.snapshot`,data:e}),0}return new Promise(e=>{let{unmount:t}=y(S.createElement(T,{api:c,siteId:l,siteLabel:f,cliVersion:a.cliVersion,onExit:n=>{t(),e(n)}}))})}const T=({api:e,siteId:t,siteLabel:n,cliVersion:r,onExit:i})=>{te();let{exit:d}=b(),{theme:y}=c(),[w,T]=C(null),[E,D]=C(!0),[O,k]=C(null),[A,j]=C(null),[M,N]=C(()=>Date.now()),[P,F]=C(!1),[I,L]=C(t),[R,z]=C(n),B=ne(e,I,e=>{L(e.id),z(e.url.replace(/^https?:\/\//,``).replace(/\/$/,``)),T(null),D(!0)});if(x((e,t)=>{if(!P){if(B.open){(t.escape||e===`s`)&&B.close();return}if(e===`/`){F(!0);return}if(e===`o`||e===`O`){a(g(`live`,{siteId:I}));return}if(e===`s`){B.toggle();return}e===`q`&&(d(),i(0))}}),re(()=>{if(P)return;let t=!1,n=async()=>{try{let n=await e.getLive(I);t||(T(n),D(!1),k(null),j(Date.now()),N(Date.now()))}catch(e){t||(k(e.message),D(!1))}};n();let r=setInterval(n,2e3);return()=>{t=!0,clearInterval(r)}},[e,I,P]),P)return S.createElement(u,{cliVersion:r,api:e,dashboardContext:{commandName:`live`,siteId:I,siteLabel:R,metricsSnapshot:w},onClose:()=>F(!1)});let V=`live · ${R}`,H=[{key:`/`,label:`ask AI`},{key:`s`,label:`site`},{key:`o`,label:`browser`},{key:`q`,label:`quit`}];if(E)return S.createElement(_,{flexDirection:`column`},S.createElement(o,{version:r,subtitle:V,live:!1}),S.createElement(s,{title:`Loading`,state:`busy`},S.createElement(_,null,S.createElement(v,{color:y.accent},S.createElement(ie,{type:`dots`})),S.createElement(v,null,` Connecting…`))));if(O&&!w)return S.createElement(_,{flexDirection:`column`},S.createElement(o,{version:r,subtitle:V,live:!1}),S.createElement(ee,{reason:`error`,headline:`Failed to load`,hint:O}),B.overlay,S.createElement(l,{items:H}));let U=process.stdout.columns??80,oe=m(U,3,2)[0],W=w?.recentEvents??[],G=w?.activeVisitors??0,se=process.stdout.rows??40,K=Math.max(5,Math.min(20,se-16)),q=W.slice(0,K),J=W.length-q.length,Y=new Map;for(let e of W){let t=e.country??`—`;Y.set(t,(Y.get(t)??0)+1)}let X=[...Y.entries()].sort((e,t)=>t[1]-e[1]).slice(0,K),ce=[{key:`type`,label:`event`,width:10,format:e=>String(e??`pageview`)},{key:`path`,label:`path`,width:30,format:e=>f(String(e??``))},{key:`country`,label:`country`,width:8,format:e=>String(e??`—`)}],Z=X.length>0,[Q,$]=Z?(()=>{let[e,t]=m(U,3,2);return[e+t+2,m(U,3,2)[2]]})():[U,0];return S.createElement(_,{flexDirection:`column`},S.createElement(o,{version:r,subtitle:V,live:G>0}),S.createElement(_,{flexDirection:`row`,marginTop:1},S.createElement(h,{title:`Active now`,value:G,format:`number`,width:oe,gap:0})),S.createElement(_,{marginTop:1,flexDirection:`row`,width:U},S.createElement(_,{width:Q,flexShrink:0,marginRight:Z?2:0},S.createElement(s,{title:`Recent events`,width:Q},q.length===0?S.createElement(v,{color:y.dim},`No events in the last few seconds`):S.createElement(S.Fragment,null,S.createElement(p,{columns:ce,data:q,zebra:!0}),J>0?S.createElement(v,{color:y.dim},` +${J} more in this window`):null))),Z?S.createElement(_,{width:$,flexShrink:0},S.createElement(s,{title:`By country (live)`,width:$},X.map(([e,t])=>S.createElement(_,{key:e,flexDirection:`row`},S.createElement(_,{width:6},S.createElement(v,{wrap:`truncate`},e)),S.createElement(_,{flexGrow:1,justifyContent:`flex-end`},S.createElement(v,{color:y.fg},t.toLocaleString())))),Array.from({length:Math.max(0,K-X.length)},(e,t)=>S.createElement(_,{key:`pad-${t}`,height:1})))):null),S.createElement(_,{marginTop:1},S.createElement(v,{color:y.dim},A===null?``:`↻ live · updated ${ae(A,M)}`)),B.overlay,S.createElement(l,{items:H,active:`/`}))};export{w as liveCommand};
1
+ import{readConfig as e}from"./config-JVhBplSX.js";import"./api-CdcB84ie.js";import{readToken as t}from"./token-store-BvSCse1t.js";import"./telemetry-BV-xvfdt.js";import{ApiV2Client as n}from"./api-v2-D0mvt__4.js";import"./formatter-C4YSOKuq.js";import{emit$1 as r,isHeadless as i}from"./emit-D4YlMlzk.js";import{openInBrowser as a}from"./open-url-BtI5aLgL.js";import"./client-ntsEXSVC.js";import"./theme-Brz9wK0w.js";import{Banner as o,Panel as s,useTheme as c}from"./panel-CTtQ2ue6.js";import"./prompt-BXvg2B4R.js";import{Keybar as l}from"./keybar-DO5OoZy9.js";import"./sparkline-CpoBjjlc.js";import{ChatPanel as u}from"./chat-panel-D9IjovCR.js";import{resolveSiteId as d}from"./resolve-site-BTVBMF1C.js";import{stripUrlPrefix as f}from"./fmt-xxIPQJX-.js";import{DataTable as p}from"./data-table-BhKjjiOS.js";import{EmptyState as ee}from"./empty-state-D-krMX62.js";import{tileWidths as m}from"./grid-CMwhs-Ms.js";import{MetricCard as h}from"./metric-card-C4iqxdww.js";import{deepLinkFor as g}from"./keybar-deep-link-B4VJn2ko.js";import{useFullscreen as te}from"./use-fullscreen-ucSyZkjO.js";import{useSiteSwitcher as ne}from"./site-switcher-BAoYWp18.js";import{Box as _,Text as v,render as y,useApp as b,useInput as x}from"ink";import S,{useEffect as re,useState as C}from"react";import ie from"ink-spinner";function ae(e,t){let n=Math.max(0,Math.round((t-e)/1e3));if(n<5)return`just now`;if(n<60)return`${n}s ago`;let r=Math.floor(n/60);return r<60?`${r}m ago`:`${Math.floor(r/60)}h ago`}async function w(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}),l,u;try{({siteId:l,site:u}=await d(c,{explicit:a.siteId,headless:!!a.json,cliVersion:a.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let f=u?.url?u.url.replace(/^https?:\/\//,``).replace(/\/$/,``):u?.name??l;if(i(a)){let e=await c.getLive(l);return r({type:`live.snapshot`,data:e}),0}return new Promise(e=>{let{unmount:t}=y(S.createElement(T,{api:c,siteId:l,siteLabel:f,cliVersion:a.cliVersion,onExit:n=>{t(),e(n)}}))})}const T=({api:e,siteId:t,siteLabel:n,cliVersion:r,onExit:i})=>{te();let{exit:d}=b(),{theme:y}=c(),[w,T]=C(null),[E,D]=C(!0),[O,k]=C(null),[A,j]=C(null),[M,N]=C(()=>Date.now()),[P,F]=C(!1),[I,L]=C(t),[R,z]=C(n),B=ne(e,I,e=>{L(e.id),z(e.url.replace(/^https?:\/\//,``).replace(/\/$/,``)),T(null),D(!0)});if(x((e,t)=>{if(!P){if(B.open){(t.escape||e===`s`)&&B.close();return}if(e===`/`){F(!0);return}if(e===`o`||e===`O`){a(g(`live`,{siteId:I}));return}if(e===`s`){B.toggle();return}e===`q`&&(d(),i(0))}}),re(()=>{if(P)return;let t=!1,n=async()=>{try{let n=await e.getLive(I);t||(T(n),D(!1),k(null),j(Date.now()),N(Date.now()))}catch(e){t||(k(e.message),D(!1))}};n();let r=setInterval(n,2e3);return()=>{t=!0,clearInterval(r)}},[e,I,P]),P)return S.createElement(u,{cliVersion:r,api:e,dashboardContext:{commandName:`live`,siteId:I,siteLabel:R,metricsSnapshot:w},onClose:()=>F(!1)});let V=`live · ${R}`,H=[{key:`/`,label:`ask AI`},{key:`s`,label:`site`},{key:`o`,label:`browser`},{key:`q`,label:`quit`}];if(E)return S.createElement(_,{flexDirection:`column`},S.createElement(o,{version:r,subtitle:V,live:!1}),S.createElement(s,{title:`Loading`,state:`busy`},S.createElement(_,null,S.createElement(v,{color:y.accent},S.createElement(ie,{type:`dots`})),S.createElement(v,null,` Connecting…`))));if(O&&!w)return S.createElement(_,{flexDirection:`column`},S.createElement(o,{version:r,subtitle:V,live:!1}),S.createElement(ee,{reason:`error`,headline:`Failed to load`,hint:O}),B.overlay,S.createElement(l,{items:H}));let U=process.stdout.columns??80,oe=m(U,3,2)[0],W=w?.recentEvents??[],G=w?.activeVisitors??0,se=process.stdout.rows??40,K=Math.max(5,Math.min(20,se-16)),q=W.slice(0,K),J=W.length-q.length,Y=new Map;for(let e of W){let t=e.country??`—`;Y.set(t,(Y.get(t)??0)+1)}let X=[...Y.entries()].sort((e,t)=>t[1]-e[1]).slice(0,K),ce=[{key:`type`,label:`event`,width:10,format:e=>String(e??`pageview`)},{key:`path`,label:`path`,width:30,format:e=>f(String(e??``))},{key:`country`,label:`country`,width:8,format:e=>String(e??`—`)}],Z=X.length>0,[Q,$]=Z?(()=>{let[e,t]=m(U,3,2);return[e+t+2,m(U,3,2)[2]]})():[U,0];return S.createElement(_,{flexDirection:`column`},S.createElement(o,{version:r,subtitle:V,live:G>0}),S.createElement(_,{flexDirection:`row`,marginTop:1},S.createElement(h,{title:`Active now`,value:G,format:`number`,width:oe,gap:0})),S.createElement(_,{marginTop:1,flexDirection:`row`,width:U},S.createElement(_,{width:Q,flexShrink:0,marginRight:Z?2:0},S.createElement(s,{title:`Recent events`,width:Q},q.length===0?S.createElement(v,{color:y.dim},`No events in the last few seconds`):S.createElement(S.Fragment,null,S.createElement(p,{columns:ce,data:q,zebra:!0}),J>0?S.createElement(v,{color:y.dim},` +${J} more in this window`):null))),Z?S.createElement(_,{width:$,flexShrink:0},S.createElement(s,{title:`By country (live)`,width:$},X.map(([e,t])=>S.createElement(_,{key:e,flexDirection:`row`},S.createElement(_,{width:6},S.createElement(v,{wrap:`truncate`},e)),S.createElement(_,{flexGrow:1,justifyContent:`flex-end`},S.createElement(v,{color:y.fg},t.toLocaleString())))),Array.from({length:Math.max(0,K-X.length)},(e,t)=>S.createElement(_,{key:`pad-${t}`,height:1})))):null),S.createElement(_,{marginTop:1},S.createElement(v,{color:y.dim},A===null?``:`↻ live · updated ${ae(A,M)}`)),B.overlay,S.createElement(l,{items:H,active:`/`}))};export{w as liveCommand};
@@ -0,0 +1 @@
1
+ import"./config-JVhBplSX.js";import"./api-CdcB84ie.js";import"./token-store-BvSCse1t.js";import"./formatter-C4YSOKuq.js";import"./emit-D4YlMlzk.js";import"./open-url-BtI5aLgL.js";import{loginCommand as e,maybeInstallCompletions as t}from"./login-DU1fY88U.js";export{e as loginCommand};
@@ -1,2 +1,2 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import{ApiClient as t,pollDeviceToken as n,startDeviceAuthorization as r}from"./api-hWp9s3Y8.js";import{writeToken as i}from"./token-store-BQuGH0z2.js";import{emit$1 as a,isHeadless as o}from"./emit-D4YlMlzk.js";import{openInBrowser as s}from"./open-url-BtI5aLgL.js";import c from"node:path";import{promises as l}from"node:fs";import u from"node:os";async function d(c){let l=await e(),u=o({json:c.json}),d=await r({apiBase:l.apiBase}),f=d.verification_uri_complete??d.verification_uri;u?a({type:`info`,message:`Open ${f} and enter code ${d.user_code}`}):c.onCode?c.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=c.openBrowser??!u;if(p)try{await s(f)}catch{}let m=await n({apiBase:l.apiBase,deviceCode:d.device_code,interval:d.interval,expiresIn:d.expires_in});await i(m);let h=new t({config:l,cliVersion:c.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 u?a({type:`done`,command:`login`,exitCode:0}):c.offerCompletions!==!1&&await g().catch(()=>void 0),{email:_?.user.email}}function f(){let e=process.env.SHELL??``,t=u.homedir();if(e.endsWith(`/zsh`)||e.endsWith(`zsh`))return{shell:`zsh`,rcPath:c.join(t,`.zshrc`)};if(e.endsWith(`/bash`)||e.endsWith(`bash`)){let e=process.platform===`darwin`?c.join(t,`.bash_profile`):c.join(t,`.bashrc`);return{shell:`bash`,rcPath:e}}return e.endsWith(`/fish`)||e.endsWith(`fish`)?{shell:`fish`,rcPath:c.join(t,`.config`,`fish`,`config.fish`)}:null}const p=/zenovay\s+completions/;async function m(e,t){try{let n=await l.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
1
+ import{readConfig as e}from"./config-JVhBplSX.js";import{ApiClient as t,pollDeviceToken as n,startDeviceAuthorization as r}from"./api-CdcB84ie.js";import{writeToken as i}from"./token-store-BvSCse1t.js";import{emit$1 as a,isHeadless as o}from"./emit-D4YlMlzk.js";import{openInBrowser as s}from"./open-url-BtI5aLgL.js";import c from"node:path";import{promises as l}from"node:fs";import u from"node:os";async function d(c){let l=await e(),u=o({json:c.json}),d=await r({apiBase:l.apiBase}),f=d.verification_uri_complete??d.verification_uri;u?a({type:`info`,message:`Open ${f} and enter code ${d.user_code}`}):c.onCode?c.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=c.openBrowser??!u;if(p)try{await s(f)}catch{}let m=await n({apiBase:l.apiBase,deviceCode:d.device_code,interval:d.interval,expiresIn:d.expires_in});await i(m);let h=new t({config:l,cliVersion:c.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 u?a({type:`done`,command:`login`,exitCode:0}):c.offerCompletions!==!1&&await g().catch(()=>void 0),{email:_?.user.email}}function f(){let e=process.env.SHELL??``,t=u.homedir();if(e.endsWith(`/zsh`)||e.endsWith(`zsh`))return{shell:`zsh`,rcPath:c.join(t,`.zshrc`)};if(e.endsWith(`/bash`)||e.endsWith(`bash`)){let e=process.platform===`darwin`?c.join(t,`.bash_profile`):c.join(t,`.bashrc`);return{shell:`bash`,rcPath:e}}return e.endsWith(`/fish`)||e.endsWith(`fish`)?{shell:`fish`,rcPath:c.join(t,`.config`,`fish`,`config.fish`)}:null}const p=/zenovay\s+completions/;async function m(e,t){try{let n=await l.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
2
  `:`eval "$(zenovay completions ${e.shell})"\n`;try{await l.mkdir(c.dirname(e.rcPath),{recursive:!0}),await l.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,g as maybeInstallCompletions};
@@ -1,2 +1,2 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import{ApiClient as t}from"./api-hWp9s3Y8.js";import{clearToken as n,readToken as r}from"./token-store-BQuGH0z2.js";import"./formatter-C4YSOKuq.js";import{emit$1 as i,isHeadless as a}from"./emit-D4YlMlzk.js";async function o(o){let s=await e(),c=await r({strict:!1}).catch(()=>null);if(c)try{let e=new t({config:s,cliVersion:o.cliVersion,token:c});await e.revokeCurrentToken()}catch{}await n(),a({json:o.json})?i({type:`done`,command:`logout`,exitCode:0}):process.stdout.write(`Logged out.
1
+ import{readConfig as e}from"./config-JVhBplSX.js";import{ApiClient as t}from"./api-CdcB84ie.js";import{clearToken as n,readToken as r}from"./token-store-BvSCse1t.js";import"./formatter-C4YSOKuq.js";import{emit$1 as i,isHeadless as a}from"./emit-D4YlMlzk.js";async function o(o){let s=await e(),c=await r({strict:!1}).catch(()=>null);if(c)try{let e=new t({config:s,cliVersion:o.cliVersion,token:c});await e.revokeCurrentToken()}catch{}await n(),a({json:o.json})?i({type:`done`,command:`logout`,exitCode:0}):process.stdout.write(`Logged out.
2
2
  `)}export{o as logoutCommand};
@@ -1,4 +1,4 @@
1
- import{readConfig as e}from"./config--JRu_jFq.js";import{ApiError as t}from"./api-hWp9s3Y8.js";import{readToken as n}from"./token-store-BQuGH0z2.js";import{ApiV2Client as r}from"./api-v2-DqKh6FgZ.js";import{confirmDestructive as i}from"./confirm-DS5wux0g.js";function a(e){return e.length>12?`${e.slice(0,8)}…${e.slice(-4)}`:e}function o(e){return e?new Date(e).toISOString().slice(0,10):`—`}async function s(s){let c=await e(),l=await n({strict:!1}),u=new r({config:c,cliVersion:s.cliVersion,token:l});try{switch(s.action){case`list`:{let{notes:e}=await u.listNotes();if(s.json)return process.stdout.write(JSON.stringify({notes:e},null,2)+`
1
+ import{readConfig as e}from"./config-JVhBplSX.js";import{ApiError as t}from"./api-CdcB84ie.js";import{readToken as n}from"./token-store-BvSCse1t.js";import{ApiV2Client as r}from"./api-v2-D0mvt__4.js";import{confirmDestructive as i}from"./confirm-DS5wux0g.js";function a(e){return e.length>12?`${e.slice(0,8)}…${e.slice(-4)}`:e}function o(e){return e?new Date(e).toISOString().slice(0,10):`—`}async function s(s){let c=await e(),l=await n({strict:!1}),u=new r({config:c,cliVersion:s.cliVersion,token:l});try{switch(s.action){case`list`:{let{notes:e}=await u.listNotes();if(s.json)return process.stdout.write(JSON.stringify({notes:e},null,2)+`
2
2
  `),0;if(e.length===0)return process.stdout.write('No notes yet. Create one with `zenovay notes create --content "<text>"`.\n'),0;let t=[14,12,50],n=e=>e.map((e,n)=>(e??``).padEnd(t[n])).join(` `);process.stdout.write(`
3
3
  `+n([`id`,`created`,`content`])+`
4
4
  `),process.stdout.write(n(t.map(e=>`─`.repeat(e)))+`
@@ -1,2 +1,2 @@
1
- import{readConfig as e,updateConfig as t}from"./config--JRu_jFq.js";import{ApiError as n}from"./api-hWp9s3Y8.js";import{readToken as r}from"./token-store-BQuGH0z2.js";import"./telemetry-DRh10SvO.js";import{ApiV2Client as i}from"./api-v2-DqKh6FgZ.js";import"./formatter-C4YSOKuq.js";import{emit$1 as a,isHeadless as o}from"./emit-D4YlMlzk.js";import{openInBrowser as s}from"./open-url-BtI5aLgL.js";import"./client-ntsEXSVC.js";import"./theme-Brz9wK0w.js";import{Banner as c,Panel as l,useTheme as u}from"./panel-CTtQ2ue6.js";import{Select as d}from"./prompt-BXvg2B4R.js";import{Keybar as f}from"./keybar-DO5OoZy9.js";import"./sparkline-CpoBjjlc.js";import{ChatPanel as p}from"./chat-panel-PSN5hjlF.js";import{resolveSiteId as m}from"./resolve-site-BLrtFOyW.js";import{stripUrlPrefix as ee}from"./fmt-xxIPQJX-.js";import{DataTable as h}from"./data-table-BhKjjiOS.js";import{EmptyState as g}from"./empty-state-D-krMX62.js";import{ResponsiveGrid as te,panelInnerWidth as ne,tileWidths as re}from"./grid-CMwhs-Ms.js";import{MetricCard as _}from"./metric-card-C4iqxdww.js";import{Bar as ie}from"./bar-NfgovYHe.js";import{deepLinkFor as ae}from"./keybar-deep-link-B4VJn2ko.js";import{useFullscreen as oe}from"./use-fullscreen-ucSyZkjO.js";import{Box as v,Text as y,render as b,useApp as se,useInput as ce}from"ink";import x,{useEffect as le,useState as S}from"react";import ue from"ink-spinner";function C(e){if(!(e instanceof n))return!1;let t=e.status;if(t===401||t===403||t===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 w(e,t){return e.catch(e=>{if(C(e))throw e;return t})}async function T(t){let n=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 i({config:n,cliVersion:t.cliVersion,token:s}),l,u;try{({siteId:l,site:u}=await m(c,{explicit:t.siteId,headless:!!t.json,cliVersion:t.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let d=u?.url?u.url.replace(/^https?:\/\//,``).replace(/\/$/,``):u?.name??l;if(o(t))try{let e=await pe(c,l,`24h`);if(t.csv||t.tsv){let{writeCsv:n}=await import(`./csv-emit-CmlDBfbA.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 a({type:`overview.snapshot`,data:e}),0}catch(e){let{emitErrorEnvelope:n}=await import(`./error-codes-DpKbL-uM.js`);return n(e,{command:`analytics`,cliVersion:t.cliVersion})}return new Promise(e=>{let{unmount:n}=b(x.createElement(D,{api:c,siteId:l,siteLabel:d,siteSlug:u?.slug??null,cliVersion:t.cliVersion,onExit:t=>{n(),e(t)}}))})}const de=[{key:`1`,value:`24h`},{key:`2`,value:`7d`},{key:`3`,value:`30d`},{key:`4`,value:`90d`}];function fe(e,t){let n=Math.max(0,Math.round((t-e)/1e3));if(n<5)return`just now`;if(n<60)return`${n}s ago`;let r=Math.floor(n/60);return r<60?`${r}m ago`:`${Math.floor(r/60)}h ago`}function E(e){return e===`24h`?`7d`:e}async function pe(e,t,n){let[r,i,a,o,s]=await Promise.all([w(e.getStats(t,n),null),w(e.getPages(t,n),[]),e.getSources(t,E(n),`prev`).catch(()=>null),w(e.getGeo(t,n),null),w(e.getDevices(t,n),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=(r?.daily??[]).map(e=>typeof e.bounceRate==`number`?e.bounceRate*100:0),f=(r?.daily??[]).map(e=>typeof e.avgSession==`number`?e.avgSession:0),p=Math.floor(l.length/2),m=l.slice(0,p).reduce((e,t)=>e+t,0),ee=u.slice(0,p).reduce((e,t)=>e+t,0),h=e=>[...e].sort((e,t)=>t.visitors-e.visitors),g=h((a?.sources??[]).filter(e=>e.channel!==`other`||!e.source.includes(`/`))).slice(0,50).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,bounceSeries:d,sessionSeries:f,prevVisitors:m,prevPageviews:ee,topPages:i.slice(0,100),channels:g,countries:h(o?.countries??[]).slice(0,50),browsers:h(s?.browsers??[]).slice(0,50),devices:h(s?.devices??[]).slice(0,50)}}const D=({api:e,siteId:n,siteLabel:r,siteSlug:i,cliVersion:a,onExit:o})=>{oe();let{exit:m}=se(),{theme:b}=u(),[C,w]=S(null),[T,E]=S(!0),[D,me]=S(null),[O,k]=S(`24h`),[A,j]=S(!1),[M,he]=S(n),[N,ge]=S(r),[_e,ve]=S(i??null),[P,F]=S(!1),[I,ye]=S([]),[be,L]=S(0),[xe,R]=S(!1),[z,Se]=S(null),[Ce,we]=S(()=>Date.now()),[B,V]=S(null),[Te,H]=S(0),[U,Ee]=S(!1);le(()=>{if(U)return;let e=setInterval(()=>we(Date.now()),5e3),t=setInterval(()=>L(e=>e+1),15e3);return()=>{clearInterval(e),clearInterval(t)}},[U]),ce(async(t,n)=>{if(!U){if(P){(n.escape||t===`s`)&&F(!1);return}if(B){if(n.escape||t===`q`){V(null),H(0);return}if(n.upArrow||t===`k`){H(e=>Math.max(0,e-1));return}if(n.downArrow||t===`j`){H(e=>e+1);return}if(n.pageUp){H(e=>Math.max(0,e-10));return}if(n.pageDown){H(e=>e+10);return}return}if(t===`/`){Ee(!0);return}if(t===`r`||t===`R`){L(e=>e+1);return}if(t===`o`||t===`O`){s(ae(`overview`,{siteId:M,siteSlug:_e}));return}if(t===`q`){m(),o(0);return}if(t===`1`){j(!1),k(`24h`);return}if(t===`2`){j(!1),k(`7d`);return}if(t===`3`){j(!1),k(`30d`);return}if(t===`4`){j(!1),k(`90d`);return}if(!P){if(t===`c`){H(0),V(`channels`);return}if(t===`g`){H(0),V(`countries`);return}if(t===`b`){H(0),V(`browsers`);return}if(t===`d`){H(0),V(`devices`);return}if(t===`p`){H(0),V(`pages`);return}}if(t===`s`){if(I.length===0)try{let t=await e.getSites();ye(t)}catch{}F(e=>!e);return}}}),le(()=>{let t=!1;return C===null?E(!0):R(!0),(async()=>{try{let n=await pe(e,M,O);if(t)return;let r=n.visitors===0&&n.pageviews===0&&n.topPages.length===0;if(r&&O===`24h`&&!A){j(!0),k(`7d`);return}w(n),E(!1),R(!1),Se(Date.now())}catch(e){t||(me(e.message),E(!1),R(!1))}})(),()=>{t=!0}},[e,M,O,be]);let De=e=>{he(e.id),ge(e.url.replace(/^https?:\/\//,``).replace(/\/$/,``)),ve(e.slug??null),F(!1),w(null),t({defaultSiteId:e.id,defaultSiteName:e.name})},W=()=>x.createElement(l,{title:`Switch site`,state:`idle`},I.length===0?x.createElement(y,{color:b.muted},`Loading your sites…`):x.createElement(d,{items:I.map(e=>({label:`${e.name} · ${e.url.replace(/^https?:\/\//,``).replace(/\/$/,``)}${e.id===M?` (current)`:``}`,value:e})),onSelect:De}),x.createElement(v,{marginTop:1},x.createElement(y,{color:b.dim},`[↑↓ navigate] · [enter] select · [s/esc] close`))),G=`overview · ${N} · ${O}${A?` (auto)`:``}`,K=[{key:`/`,label:`AI chat`},{key:`r`,label:`refresh`},{key:`s`,label:`site`},{key:`o`,label:`browser`},{key:`q`,label:`quit`}];if(U)return x.createElement(p,{cliVersion:a,api:e,dashboardContext:{commandName:`overview`,siteId:M,siteLabel:N,metricsSnapshot:C},onClose:()=>Ee(!1)});if(T)return x.createElement(v,{flexDirection:`column`},x.createElement(c,{version:a,subtitle:G,live:!1}),x.createElement(l,{title:`Loading`,state:`busy`},x.createElement(v,null,x.createElement(y,{color:b.accent},x.createElement(ue,{type:`dots`})),x.createElement(y,null,` Fetching dashboard…`))),P?W():null);if(D)return x.createElement(v,{flexDirection:`column`},x.createElement(c,{version:a,subtitle:G,live:!1}),x.createElement(g,{reason:`error`,headline:`Failed to load`,hint:D}),P?W():null,x.createElement(f,{items:K}));if(!C||C.visitors===0&&C.pageviews===0&&C.topPages.length===0)return x.createElement(v,{flexDirection:`column`},x.createElement(c,{version:a,subtitle:G,live:!1}),x.createElement(g,{reason:`no-data`,headline:`No data yet`,hint:A?`No data in 7d either. Visit your site to send the first event — press [s] to switch site.`:`Visit your site to send the first event, or press [3] for 30d / [4] for 90d to widen the window.`}),P?W():null,x.createElement(f,{items:K}));let q=process.stdout.columns??80,J=re(q,4,2),Y=process.stdout.rows??40,Oe=Math.max(10,Y-32),X=Math.max(3,Math.min(7,Math.floor((Oe-4)/2))),Z=Math.max(4,Math.min(14,Oe-2*X)),ke=[{key:`path`,label:`path`,width:32,format:e=>ee(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)}s`:`—`},{key:`bounceRate`,label:`bounce`,align:`right`,width:7,format:e=>typeof e==`number`?`${(e*100).toFixed(0)}%`:`—`}],Ae=C.prevVisitors>0?(C.visitors-C.prevVisitors)/C.prevVisitors:void 0,je=C.prevPageviews>0?(C.pageviews-C.prevPageviews)/C.prevPageviews:void 0,Me=Math.max(1,...C.channels.map(e=>e.visitors)),Ne=Math.max(1,...C.countries.map(e=>e.visitors)),Pe=Math.max(1,...C.browsers.map(e=>e.visitors)),Fe=Math.max(1,...C.devices.map(e=>e.visitors)),Ie=(e,t,n,r,i,a)=>{let o=Math.max(6,a-n-1-9);return x.createElement(v,{key:e,flexDirection:`row`},x.createElement(v,{width:n,marginRight:1},x.createElement(y,{wrap:`truncate`},t)),x.createElement(ie,{value:r,max:i,width:o,showPercent:!1,track:!0}),x.createElement(v,{flexGrow:1,justifyContent:`flex-end`},x.createElement(y,{color:b.fg},r.toLocaleString())))},Le=[{key:`channels`,hotkey:`c`,title:`Channels`,labelWidth:16,display:X,max:Me,rows:C.channels.map(e=>({label:e.name,value:e.visitors}))},{key:`countries`,hotkey:`g`,title:`Top countries`,labelWidth:5,display:X,max:Ne,rows:C.countries.map(e=>({label:e.country,value:e.visitors}))},{key:`browsers`,hotkey:`b`,title:`Top browsers`,labelWidth:16,display:X,max:Pe,rows:C.browsers.map(e=>({label:e.name,value:e.visitors}))},{key:`devices`,hotkey:`d`,title:`Top devices`,labelWidth:16,display:X,max:Fe,rows:C.devices.map(e=>({label:e.name,value:e.visitors}))}],Re=Le.filter(e=>e.rows.length>0).map(e=>({key:e.key,title:e.title,render:t=>{let n=e.rows.slice(0,X),r=e.rows.length-n.length,i=Math.max(0,X-n.length);return x.createElement(x.Fragment,null,n.map((n,r)=>Ie(`${e.key}-${r}`,n.label,e.labelWidth,n.value,e.max,t)),Array.from({length:i},(e,t)=>x.createElement(v,{key:`pad-${t}`,height:1})),x.createElement(y,{color:b.dim},r>0?` +${r} more · [${e.hotkey}] expand`:` `))}})),Q=Math.max(5,Y-9),$=e=>{let t=Math.max(0,e-Q),n=Math.min(Te,t),r=Math.min(e,n+Q);return{from:n,window:Q,label:e>Q?` ${n+1}-${r} of ${e} · ↑↓ scroll`:` ${e} total`}};if(B===`pages`){let e=C.topPages.length,t=$(e);return x.createElement(v,{flexDirection:`column`},x.createElement(c,{version:a,subtitle:`pages · ${N} · ${O}`,live:!1}),x.createElement(v,{marginTop:1},x.createElement(l,{title:`Top pages — all ${e}`},e===0?x.createElement(y,{color:b.muted},`No pages with data in this window yet.`):x.createElement(x.Fragment,null,x.createElement(h,{columns:ke,data:C.topPages.slice(t.from,t.from+t.window),zebra:!0}),x.createElement(y,{color:b.dim},t.label)))),x.createElement(f,{items:[{key:`↑↓`,label:`scroll`},{key:`esc`,label:`back`},{key:`q`,label:`quit`}],active:`↑↓`}))}if(B){let e=Le.find(e=>e.key===B);if(e){let t=Math.min(q,84),n=$(e.rows.length);return x.createElement(v,{flexDirection:`column`},x.createElement(c,{version:a,subtitle:`${e.title.toLowerCase()} · ${N} · ${O}`,live:!1}),x.createElement(v,{marginTop:1},x.createElement(l,{title:`${e.title} — all ${e.rows.length}`,width:t},e.rows.length===0?x.createElement(y,{color:b.muted},`No data.`):x.createElement(x.Fragment,null,e.rows.slice(n.from,n.from+n.window).map((r,i)=>Ie(`x-${n.from+i}`,r.label,e.labelWidth,r.value,e.max,ne(t))),x.createElement(y,{color:b.dim},n.label)))),x.createElement(f,{items:[{key:`↑↓`,label:`scroll`},{key:`esc`,label:`back`},{key:`q`,label:`quit`}],active:`↑↓`}))}}return x.createElement(v,{flexDirection:`column`},x.createElement(c,{version:a,subtitle:G,live:!0}),x.createElement(v,{flexDirection:`row`,marginTop:1},de.map(e=>{let t=e.value===O;return x.createElement(v,{key:e.value,flexDirection:`row`,marginRight:3},x.createElement(y,{color:b.dim},e.key,` `),x.createElement(y,{color:t?b.accent:b.muted,bold:t},e.value))}),A?x.createElement(y,{color:b.dim},` (auto)`):null),x.createElement(v,{flexDirection:`row`,marginTop:1},x.createElement(_,{title:`Visitors`,value:C.visitors,format:`number`,width:J[0],gap:2,series:C.series,...typeof Ae==`number`?{delta:Ae}:{}}),x.createElement(_,{title:`Pageviews`,value:C.pageviews,format:`number`,width:J[1],gap:2,series:C.pageviewsSeries,...typeof je==`number`?{delta:je}:{}}),x.createElement(_,{title:`Bounce rate`,value:C.bounceRate??``,emptyHint:`—`,format:`percent`,width:J[2],gap:2,series:C.bounceSeries}),x.createElement(_,{title:`Avg session`,value:C.avgSession??``,emptyHint:`—`,format:`duration`,width:J[3],gap:0,series:C.sessionSeries})),Re.length>0&&x.createElement(v,{marginTop:1},x.createElement(te,{totalWidth:q,panels:Re,minColWidth:40,maxCols:2,gap:2})),x.createElement(v,{marginTop:1},x.createElement(l,{title:`Top pages (${O})`},C.topPages.length===0?x.createElement(y,{color:b.muted},`No pages with data in this window yet.`):x.createElement(x.Fragment,null,x.createElement(h,{columns:ke,data:C.topPages.slice(0,Z),zebra:!0}),C.topPages.length>Z?x.createElement(y,{color:b.dim},` +${C.topPages.length-Z} more · [p] expand`):null))),P?W():null,x.createElement(v,{marginTop:1},x.createElement(y,{color:b.dim},xe?`↻ refreshing…`:z===null?``:`↻ updated ${fe(z,Ce)} · [r] refresh`)),x.createElement(f,{items:K}))};async function me(e){return T(e)}export{me as analyticsCommand};
1
+ import{readConfig as e,updateConfig as t}from"./config-JVhBplSX.js";import{ApiError as n}from"./api-CdcB84ie.js";import{readToken as r}from"./token-store-BvSCse1t.js";import{ApiV2Client as i}from"./api-v2-D0mvt__4.js";import{emit$1 as a,isHeadless as o}from"./emit-D4YlMlzk.js";import{openInBrowser as s}from"./open-url-BtI5aLgL.js";import{Banner as c,Panel as l,useTheme as u}from"./panel-CTtQ2ue6.js";import{Select as d}from"./prompt-BXvg2B4R.js";import{Keybar as f}from"./keybar-DO5OoZy9.js";import{ChatPanel as p}from"./chat-panel-D9IjovCR.js";import{resolveSiteId as m}from"./resolve-site-BTVBMF1C.js";import{stripUrlPrefix as ee}from"./fmt-xxIPQJX-.js";import{DataTable as h}from"./data-table-BhKjjiOS.js";import{EmptyState as g}from"./empty-state-D-krMX62.js";import{ResponsiveGrid as te,panelInnerWidth as ne,tileWidths as re}from"./grid-CMwhs-Ms.js";import{MetricCard as _}from"./metric-card-C4iqxdww.js";import{Bar as ie}from"./bar-NfgovYHe.js";import{deepLinkFor as ae}from"./keybar-deep-link-B4VJn2ko.js";import{useFullscreen as oe}from"./use-fullscreen-ucSyZkjO.js";import{Box as v,Text as y,render as b,useApp as se,useInput as ce}from"ink";import x,{useEffect as le,useState as S}from"react";import ue from"ink-spinner";function C(e){if(!(e instanceof n))return!1;let t=e.status;if(t===401||t===403||t===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 w(e,t){return e.catch(e=>{if(C(e))throw e;return t})}async function T(t){let n=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 i({config:n,cliVersion:t.cliVersion,token:s}),l,u;try{({siteId:l,site:u}=await m(c,{explicit:t.siteId,headless:!!t.json,cliVersion:t.cliVersion}))}catch(e){return process.stderr.write(`${e.message}\n`),2}let d=u?.url?u.url.replace(/^https?:\/\//,``).replace(/\/$/,``):u?.name??l;if(o(t))try{let e=await pe(c,l,`24h`);if(t.csv||t.tsv){let{writeCsv:n}=await import(`./csv-emit-B-5km-O-.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 a({type:`overview.snapshot`,data:e}),0}catch(e){let{emitErrorEnvelope:n}=await import(`./error-codes-BiKo9PGm.js`);return n(e,{command:`analytics`,cliVersion:t.cliVersion})}return new Promise(e=>{let{unmount:n}=b(x.createElement(D,{api:c,siteId:l,siteLabel:d,siteSlug:u?.slug??null,cliVersion:t.cliVersion,onExit:t=>{n(),e(t)}}))})}const de=[{key:`1`,value:`24h`},{key:`2`,value:`7d`},{key:`3`,value:`30d`},{key:`4`,value:`90d`}];function fe(e,t){let n=Math.max(0,Math.round((t-e)/1e3));if(n<5)return`just now`;if(n<60)return`${n}s ago`;let r=Math.floor(n/60);return r<60?`${r}m ago`:`${Math.floor(r/60)}h ago`}function E(e){return e===`24h`?`7d`:e}async function pe(e,t,n){let[r,i,a,o,s]=await Promise.all([w(e.getStats(t,n),null),w(e.getPages(t,n),[]),e.getSources(t,E(n),`prev`).catch(()=>null),w(e.getGeo(t,n),null),w(e.getDevices(t,n),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=(r?.daily??[]).map(e=>typeof e.bounceRate==`number`?e.bounceRate*100:0),f=(r?.daily??[]).map(e=>typeof e.avgSession==`number`?e.avgSession:0),p=Math.floor(l.length/2),m=l.slice(0,p).reduce((e,t)=>e+t,0),ee=u.slice(0,p).reduce((e,t)=>e+t,0),h=e=>[...e].sort((e,t)=>t.visitors-e.visitors),g=h((a?.sources??[]).filter(e=>e.channel!==`other`||!e.source.includes(`/`))).slice(0,50).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,bounceSeries:d,sessionSeries:f,prevVisitors:m,prevPageviews:ee,topPages:i.slice(0,100),channels:g,countries:h(o?.countries??[]).slice(0,50),browsers:h(s?.browsers??[]).slice(0,50),devices:h(s?.devices??[]).slice(0,50)}}const D=({api:e,siteId:n,siteLabel:r,siteSlug:i,cliVersion:a,onExit:o})=>{oe();let{exit:m}=se(),{theme:b}=u(),[C,w]=S(null),[T,E]=S(!0),[D,me]=S(null),[O,k]=S(`24h`),[A,j]=S(!1),[M,he]=S(n),[N,ge]=S(r),[_e,ve]=S(i??null),[P,F]=S(!1),[I,ye]=S([]),[be,L]=S(0),[xe,R]=S(!1),[z,Se]=S(null),[Ce,we]=S(()=>Date.now()),[B,V]=S(null),[Te,H]=S(0),[U,Ee]=S(!1);le(()=>{if(U)return;let e=setInterval(()=>we(Date.now()),5e3),t=setInterval(()=>L(e=>e+1),15e3);return()=>{clearInterval(e),clearInterval(t)}},[U]),ce(async(t,n)=>{if(!U){if(P){(n.escape||t===`s`)&&F(!1);return}if(B){if(n.escape||t===`q`){V(null),H(0);return}if(n.upArrow||t===`k`){H(e=>Math.max(0,e-1));return}if(n.downArrow||t===`j`){H(e=>e+1);return}if(n.pageUp){H(e=>Math.max(0,e-10));return}if(n.pageDown){H(e=>e+10);return}return}if(t===`/`){Ee(!0);return}if(t===`r`||t===`R`){L(e=>e+1);return}if(t===`o`||t===`O`){s(ae(`overview`,{siteId:M,siteSlug:_e}));return}if(t===`q`){m(),o(0);return}if(t===`1`){j(!1),k(`24h`);return}if(t===`2`){j(!1),k(`7d`);return}if(t===`3`){j(!1),k(`30d`);return}if(t===`4`){j(!1),k(`90d`);return}if(!P){if(t===`c`){H(0),V(`channels`);return}if(t===`g`){H(0),V(`countries`);return}if(t===`b`){H(0),V(`browsers`);return}if(t===`d`){H(0),V(`devices`);return}if(t===`p`){H(0),V(`pages`);return}}if(t===`s`){if(I.length===0)try{let t=await e.getSites();ye(t)}catch{}F(e=>!e);return}}}),le(()=>{let t=!1;return C===null?E(!0):R(!0),(async()=>{try{let n=await pe(e,M,O);if(t)return;let r=n.visitors===0&&n.pageviews===0&&n.topPages.length===0;if(r&&O===`24h`&&!A){j(!0),k(`7d`);return}w(n),E(!1),R(!1),Se(Date.now())}catch(e){t||(me(e.message),E(!1),R(!1))}})(),()=>{t=!0}},[e,M,O,be]);let De=e=>{he(e.id),ge(e.url.replace(/^https?:\/\//,``).replace(/\/$/,``)),ve(e.slug??null),F(!1),w(null),t({defaultSiteId:e.id,defaultSiteName:e.name})},W=()=>x.createElement(l,{title:`Switch site`,state:`idle`},I.length===0?x.createElement(y,{color:b.muted},`Loading your sites…`):x.createElement(d,{items:I.map(e=>({label:`${e.name} · ${e.url.replace(/^https?:\/\//,``).replace(/\/$/,``)}${e.id===M?` (current)`:``}`,value:e})),onSelect:De}),x.createElement(v,{marginTop:1},x.createElement(y,{color:b.dim},`[↑↓ navigate] · [enter] select · [s/esc] close`))),G=`overview · ${N} · ${O}${A?` (auto)`:``}`,K=[{key:`/`,label:`AI chat`},{key:`r`,label:`refresh`},{key:`s`,label:`site`},{key:`o`,label:`browser`},{key:`q`,label:`quit`}];if(U)return x.createElement(p,{cliVersion:a,api:e,dashboardContext:{commandName:`overview`,siteId:M,siteLabel:N,metricsSnapshot:C},onClose:()=>Ee(!1)});if(T)return x.createElement(v,{flexDirection:`column`},x.createElement(c,{version:a,subtitle:G,live:!1}),x.createElement(l,{title:`Loading`,state:`busy`},x.createElement(v,null,x.createElement(y,{color:b.accent},x.createElement(ue,{type:`dots`})),x.createElement(y,null,` Fetching dashboard…`))),P?W():null);if(D)return x.createElement(v,{flexDirection:`column`},x.createElement(c,{version:a,subtitle:G,live:!1}),x.createElement(g,{reason:`error`,headline:`Failed to load`,hint:D}),P?W():null,x.createElement(f,{items:K}));if(!C||C.visitors===0&&C.pageviews===0&&C.topPages.length===0)return x.createElement(v,{flexDirection:`column`},x.createElement(c,{version:a,subtitle:G,live:!1}),x.createElement(g,{reason:`no-data`,headline:`No data yet`,hint:A?`No data in 7d either. Visit your site to send the first event — press [s] to switch site.`:`Visit your site to send the first event, or press [3] for 30d / [4] for 90d to widen the window.`}),P?W():null,x.createElement(f,{items:K}));let q=process.stdout.columns??80,J=re(q,4,2),Y=process.stdout.rows??40,Oe=Math.max(10,Y-32),X=Math.max(3,Math.min(7,Math.floor((Oe-4)/2))),Z=Math.max(4,Math.min(14,Oe-2*X)),ke=[{key:`path`,label:`path`,width:32,format:e=>ee(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)}s`:`—`},{key:`bounceRate`,label:`bounce`,align:`right`,width:7,format:e=>typeof e==`number`?`${(e*100).toFixed(0)}%`:`—`}],Ae=C.prevVisitors>0?(C.visitors-C.prevVisitors)/C.prevVisitors:void 0,je=C.prevPageviews>0?(C.pageviews-C.prevPageviews)/C.prevPageviews:void 0,Me=Math.max(1,...C.channels.map(e=>e.visitors)),Ne=Math.max(1,...C.countries.map(e=>e.visitors)),Pe=Math.max(1,...C.browsers.map(e=>e.visitors)),Fe=Math.max(1,...C.devices.map(e=>e.visitors)),Ie=(e,t,n,r,i,a)=>{let o=Math.max(6,a-n-1-9);return x.createElement(v,{key:e,flexDirection:`row`},x.createElement(v,{width:n,marginRight:1},x.createElement(y,{wrap:`truncate`},t)),x.createElement(ie,{value:r,max:i,width:o,showPercent:!1,track:!0}),x.createElement(v,{flexGrow:1,justifyContent:`flex-end`},x.createElement(y,{color:b.fg},r.toLocaleString())))},Le=[{key:`channels`,hotkey:`c`,title:`Channels`,labelWidth:16,display:X,max:Me,rows:C.channels.map(e=>({label:e.name,value:e.visitors}))},{key:`countries`,hotkey:`g`,title:`Top countries`,labelWidth:5,display:X,max:Ne,rows:C.countries.map(e=>({label:e.country,value:e.visitors}))},{key:`browsers`,hotkey:`b`,title:`Top browsers`,labelWidth:16,display:X,max:Pe,rows:C.browsers.map(e=>({label:e.name,value:e.visitors}))},{key:`devices`,hotkey:`d`,title:`Top devices`,labelWidth:16,display:X,max:Fe,rows:C.devices.map(e=>({label:e.name,value:e.visitors}))}],Re=Le.filter(e=>e.rows.length>0).map(e=>({key:e.key,title:e.title,render:t=>{let n=e.rows.slice(0,X),r=e.rows.length-n.length,i=Math.max(0,X-n.length);return x.createElement(x.Fragment,null,n.map((n,r)=>Ie(`${e.key}-${r}`,n.label,e.labelWidth,n.value,e.max,t)),Array.from({length:i},(e,t)=>x.createElement(v,{key:`pad-${t}`,height:1})),x.createElement(y,{color:b.dim},r>0?` +${r} more · [${e.hotkey}] expand`:` `))}})),Q=Math.max(5,Y-9),$=e=>{let t=Math.max(0,e-Q),n=Math.min(Te,t),r=Math.min(e,n+Q);return{from:n,window:Q,label:e>Q?` ${n+1}-${r} of ${e} · ↑↓ scroll`:` ${e} total`}};if(B===`pages`){let e=C.topPages.length,t=$(e);return x.createElement(v,{flexDirection:`column`},x.createElement(c,{version:a,subtitle:`pages · ${N} · ${O}`,live:!1}),x.createElement(v,{marginTop:1},x.createElement(l,{title:`Top pages — all ${e}`},e===0?x.createElement(y,{color:b.muted},`No pages with data in this window yet.`):x.createElement(x.Fragment,null,x.createElement(h,{columns:ke,data:C.topPages.slice(t.from,t.from+t.window),zebra:!0}),x.createElement(y,{color:b.dim},t.label)))),x.createElement(f,{items:[{key:`↑↓`,label:`scroll`},{key:`esc`,label:`back`},{key:`q`,label:`quit`}],active:`↑↓`}))}if(B){let e=Le.find(e=>e.key===B);if(e){let t=Math.min(q,84),n=$(e.rows.length);return x.createElement(v,{flexDirection:`column`},x.createElement(c,{version:a,subtitle:`${e.title.toLowerCase()} · ${N} · ${O}`,live:!1}),x.createElement(v,{marginTop:1},x.createElement(l,{title:`${e.title} — all ${e.rows.length}`,width:t},e.rows.length===0?x.createElement(y,{color:b.muted},`No data.`):x.createElement(x.Fragment,null,e.rows.slice(n.from,n.from+n.window).map((r,i)=>Ie(`x-${n.from+i}`,r.label,e.labelWidth,r.value,e.max,ne(t))),x.createElement(y,{color:b.dim},n.label)))),x.createElement(f,{items:[{key:`↑↓`,label:`scroll`},{key:`esc`,label:`back`},{key:`q`,label:`quit`}],active:`↑↓`}))}}return x.createElement(v,{flexDirection:`column`},x.createElement(c,{version:a,subtitle:G,live:!0}),x.createElement(v,{flexDirection:`row`,marginTop:1},de.map(e=>{let t=e.value===O;return x.createElement(v,{key:e.value,flexDirection:`row`,marginRight:3},x.createElement(y,{color:b.dim},e.key,` `),x.createElement(y,{color:t?b.accent:b.muted,bold:t},e.value))}),A?x.createElement(y,{color:b.dim},` (auto)`):null),x.createElement(v,{flexDirection:`row`,marginTop:1},x.createElement(_,{title:`Visitors`,value:C.visitors,format:`number`,width:J[0],gap:2,series:C.series,...typeof Ae==`number`?{delta:Ae}:{}}),x.createElement(_,{title:`Pageviews`,value:C.pageviews,format:`number`,width:J[1],gap:2,series:C.pageviewsSeries,...typeof je==`number`?{delta:je}:{}}),x.createElement(_,{title:`Bounce rate`,value:C.bounceRate??``,emptyHint:`—`,format:`percent`,width:J[2],gap:2,series:C.bounceSeries}),x.createElement(_,{title:`Avg session`,value:C.avgSession??``,emptyHint:`—`,format:`duration`,width:J[3],gap:0,series:C.sessionSeries})),Re.length>0&&x.createElement(v,{marginTop:1},x.createElement(te,{totalWidth:q,panels:Re,minColWidth:40,maxCols:2,gap:2})),x.createElement(v,{marginTop:1},x.createElement(l,{title:`Top pages (${O})`},C.topPages.length===0?x.createElement(y,{color:b.muted},`No pages with data in this window yet.`):x.createElement(x.Fragment,null,x.createElement(h,{columns:ke,data:C.topPages.slice(0,Z),zebra:!0}),C.topPages.length>Z?x.createElement(y,{color:b.dim},` +${C.topPages.length-Z} more · [p] expand`):null))),P?W():null,x.createElement(v,{marginTop:1},x.createElement(y,{color:b.dim},xe?`↻ refreshing…`:z===null?``:`↻ updated ${fe(z,Ce)} · [r] refresh`)),x.createElement(f,{items:K}))};export{T as overviewCommand};
@@ -0,0 +1 @@
1
+ import"./config-JVhBplSX.js";import"./api-CdcB84ie.js";import"./token-store-BvSCse1t.js";import"./telemetry-BV-xvfdt.js";import"./api-v2-D0mvt__4.js";import"./formatter-C4YSOKuq.js";import"./emit-D4YlMlzk.js";import"./open-url-BtI5aLgL.js";import"./client-ntsEXSVC.js";import"./theme-Brz9wK0w.js";import"./panel-CTtQ2ue6.js";import"./prompt-BXvg2B4R.js";import"./keybar-DO5OoZy9.js";import"./sparkline-CpoBjjlc.js";import"./chat-panel-D9IjovCR.js";import"./resolve-site-BTVBMF1C.js";import"./fmt-xxIPQJX-.js";import"./data-table-BhKjjiOS.js";import"./empty-state-D-krMX62.js";import"./grid-CMwhs-Ms.js";import"./metric-card-C4iqxdww.js";import"./bar-NfgovYHe.js";import"./keybar-deep-link-B4VJn2ko.js";import"./use-fullscreen-ucSyZkjO.js";import{overviewCommand as e}from"./overview-CmTIumZy.js";export{e as overviewCommand};