@verirun/cli 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -51,7 +51,7 @@ verirun logout # disconnect this machine
51
51
 
52
52
  | | |
53
53
  | --- | --- |
54
- | `~/.verirun/config.json` | Holds the device token. Per user, not per project. |
54
+ | `~/.verirun/config.json` | Holds the device token. Per user, not per project. Restricted to your account (0600, or an `icacls` ACL on Windows). |
55
55
  | `~/.verirun/state.json` | The last **server-signed lease** (Ed25519) plus a local tamper check. Editing it, or a lease not signed by Verirun's key, is ignored and forces a fresh online check. |
56
56
  | `$VERIRUN_LICENSE_KEY` | A raw key for CI, used instead of `verirun login`. |
57
57
  | `$VERIRUN_LICENSE_SERVER` | Point the CLI at a different server. |
@@ -99,8 +99,12 @@ Opens a headed browser. Perform the workflow by hand — click, type, navigate.
99
99
  | `-f, --force` | Overwrite an existing workflow of the same name. Without it, recording onto an existing name errors. |
100
100
 
101
101
  **Name rules.** `<name>` becomes a filename: letters, digits, dot, dash,
102
- underscore; must start with a letter or digit; 64 chars max. It is not
103
- sanitised — an invalid name errors rather than being rewritten.
102
+ underscore; must start with a letter or digit; 64 chars max. Two Windows rules
103
+ are enforced on every platform, so a workflow you record stays usable for a
104
+ teammate who checks the repo out on Windows: no trailing dot (Windows drops it,
105
+ colliding with the bare name), and no reserved device stem — `con`, `prn`, `aux`,
106
+ `nul`, `com1`–`com9`, `lpt1`–`lpt9`, at any extension. Names are not sanitised —
107
+ an invalid name errors rather than being rewritten.
104
108
 
105
109
  **Selectors.** Recording goes through Playwright's codegen engine, so each step
106
110
  gets its stable selector — `getByTestId`, then `getByRole` with an accessible
@@ -140,19 +144,37 @@ verirun record checkout --channel chrome --user-data-dir "$HOME/.verirun-profile
140
144
  verirun run checkout --channel chrome --user-data-dir "$HOME/.verirun-profile"
141
145
  ```
142
146
 
147
+ On Windows pass an absolute path instead — cmd and PowerShell don't expand `~`
148
+ inside an argument like this, and verirun never expands it either, so a literal
149
+ `~` just creates a directory called `~` and the run starts logged out:
150
+
151
+ ```powershell
152
+ verirun run checkout --channel chrome --user-data-dir "$env:USERPROFILE\.verirun-profile"
153
+ ```
154
+
143
155
  Create that profile once, by hand, and sign in there — identity providers block
144
156
  sign-in in an automation-launched browser:
145
157
 
146
158
  ```bash
159
+ # macOS / Linux
147
160
  google-chrome --user-data-dir="$HOME/.verirun-profile" --password-store=basic
148
161
  ```
149
162
 
163
+ ```powershell
164
+ # Windows (PowerShell)
165
+ & "$env:ProgramFiles\Google\Chrome\Application\chrome.exe" `
166
+ --user-data-dir="$env:USERPROFILE\.verirun-profile"
167
+ ```
168
+
150
169
  `--password-store=basic` (plus `--use-mock-keychain` on macOS) is not optional:
151
170
  Playwright always launches Chrome with those flags, and cookies written under
152
171
  your OS keyring can't be decrypted without them — the run starts logged out with
153
- no error. That is also why you can't reuse your everyday Chrome profile, whose
154
- cookies are keyring-encrypted; use a dedicated one. Close the profile before
155
- recording or running, since Chrome locks it.
172
+ no error. Both switches are Unix-only, so on Windows they're ignored — there just
173
+ create the profile as the same Windows user that runs verirun. **The Windows path
174
+ is untested:** if a run starts logged out despite a signed-in profile, that's the
175
+ first thing to suspect. On every platform, don't reuse your everyday Chrome
176
+ profile; use a dedicated one. Close the profile before recording or running, since
177
+ Chrome locks it.
156
178
 
157
179
  To check it took, reopen the profile on its own — if that window is signed in,
158
180
  verirun will be too.
@@ -334,7 +356,10 @@ Non-interactive shells get the env/config values to set instead of a prompt.
334
356
 
335
357
  An unknown `<source>` errors. A flag meant for another source is ignored.
336
358
  Each `verirun log <source>` connect flow *writes* its own block of
337
- `.verirun/config.json` (0600); the overview is read-only. A secret supplied via
359
+ `.verirun/config.json`, restricted to your user account — mode 0600 on macOS and
360
+ Linux, and an `icacls` ACL granting only you on Windows, since mode bits mean
361
+ nothing there. If that cannot be applied the flow warns rather than leaving you
362
+ to assume the token is protected. The overview is read-only. A secret supplied via
338
363
  `$VERIRUN_SUPABASE_ACCESS_TOKEN` / `$VERIRUN_VERCEL_TOKEN` /
339
364
  `$VERIRUN_VERCEL_DRAIN_SECRET` / `$VERIRUN_RAILWAY_TOKEN` is never written to
340
365
  the file.
@@ -613,6 +638,35 @@ run this often.
613
638
 
614
639
  ## Changelog
615
640
 
641
+ ### 0.2.1
642
+
643
+ Windows support pass. Nothing in the CLI was Unix-only by design, but several
644
+ paths had never been exercised on Windows.
645
+
646
+ - **Workflow names** reject the two spellings Windows cannot store: a trailing
647
+ dot (Windows drops it, colliding with the bare name) and a reserved device
648
+ stem — `con`, `prn`, `aux`, `nul`, `com1`–`com9`, `lpt1`–`lpt9`, at any
649
+ extension. Enforced on every platform, so a workflow recorded on macOS or
650
+ Linux stays usable for a teammate on Windows.
651
+ - **Config permissions on Windows** — `.verirun/config.json`, `~/.verirun/` and
652
+ the files in it are now restricted with an `icacls` ACL granting only the
653
+ current user. Mode bits are not an access control on Windows, so these held
654
+ provider tokens and the device token on whatever ACL they inherited. A
655
+ connect flow that cannot lock the file down now warns instead of implying
656
+ protection it did not get.
657
+ - **`verirun log supabase`** can find the `supabase` CLI on Windows, where it
658
+ is a `.cmd` shim that needs a shell to launch. It previously always fell
659
+ through to the manual project-ref prompt.
660
+ - **Hardware fingerprint** filters Windows virtual adapters (Hyper-V, WSL,
661
+ VMware, VirtualBox, VPN and loopback), which were being counted as physical
662
+ and could shift the machine id — consuming an extra seat against the license.
663
+ - Docs: `--user-data-dir` needs an absolute path on Windows, since neither cmd,
664
+ PowerShell nor verirun expands `~`.
665
+
666
+ **Not verified on Windows.** These fixes are from reading the code and the
667
+ platform rules, not from a Windows test run. The signed-in Chrome profile path
668
+ in particular is untested there.
669
+
616
670
  ### 0.2.0
617
671
 
618
672
  - **`verirun map`** — static interaction graph of a React/TypeScript app:
package/dist/cli.js CHANGED
@@ -1,39 +1,39 @@
1
1
  #!/usr/bin/env node
2
2
  import{createRequire as __cr}from'node:module';const require=__cr(import.meta.url);
3
- import{createPublicKey as In,verify as jn}from"node:crypto";import{readFileSync as xn}from"node:fs";import yr from"node:path";import{fileURLToPath as An}from"node:url";import{Command as Ln}from"commander";import oe from"node:os";import{setTimeout as Se}from"node:timers/promises";import{spawn as $r}from"node:child_process";function L(e){let r=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",o=process.platform==="win32"?["/c","start","",e]:[e];try{let t=$r(r,o,{stdio:"ignore",detached:!0});t.on("error",()=>{}),t.unref()}catch{}}var Rr=!!process.stdout.isTTY&&!process.env.NO_COLOR,T=(e,r)=>Rr?`\x1B[${e}m${r}\x1B[0m`:r,n={info:e=>console.log(e),step:e=>console.log(`${T("90","\xB7")} ${e}`),success:e=>console.log(`${T("32","\u2713")} ${e}`),warn:e=>console.warn(`${T("33","!")} ${e}`),error:e=>console.error(`${T("31","\u2717")} ${e}`),dim:e=>T("90",e),bold:e=>T("1",e)};var N="0.2.0";var Cr=1440*60*1e3;function ie(){return import("./gate.mjs")}async function $e(e){let{getMachineId:r,saveGlobalConfig:o,clearLicenseState:t,loadGlobalConfig:i,resolveServer:s,persistLease:a}=await ie(),c=await i(),l=e.server?e.server.replace(/\/+$/,""):s(c.licenseServer);if(c.token&&!e.force){n.info("This machine is already connected. Run `verirun whoami`, or"),n.info("`verirun login --force` to connect it to a different account.");return}let d=await r(),p=await fetch(`${l}/api/cli/link`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({fingerprint:d,hostname:oe.hostname(),os:`${oe.platform()} ${oe.release()}`,cliVersion:N})}).catch(()=>{});if(!p||!p.ok)throw new Error(`Could not start login against ${l}. Check your connection.`);let f=await p.json(),m=`${f.verifyUrl}?code=${encodeURIComponent(f.userCode)}`;n.info(""),n.info("To connect this machine to your Verirun account:"),n.info(""),n.info(` 1. Open ${n.bold(f.verifyUrl)}`),n.info(` 2. Enter ${n.bold(f.userCode)}`),n.info(""),n.info(n.dim(`(trying to open ${m} for you)`)),L(m),n.info(""),n.step("Waiting for approval in the browser..."),e.server&&await o({licenseServer:l});let h=Date.now()+f.expiresIn*1e3,y=Math.max(2,f.interval)*1e3;for(;Date.now()<h;){await Se(y);let g=await fetch(`${l}/api/cli/link/poll`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({deviceCode:f.deviceCode,fingerprint:d})}).catch(()=>{});if(!g)continue;if(g.status===429){await Se(y);continue}let u=await g.json().catch(()=>({status:"server_error"}));if(u.status==="ok"&&u.token){await o({token:u.token,licenseKey:void 0}),await t();let v={kind:"token",value:u.token,server:l},k=u.license?.lease;if(k){await a(v,k);let S=u.license,j=S?.planName??S?.plan??"trial",x=typeof S?.seats=="number"&&S.seats>1?`, ${S.seats} machine seats`:"";n.success(`Connected. Plan: ${j} (${S?.status??"ok"})${x}.`)}else u.license&&u.license.valid===!1?(n.success("Connected."),u.license.reason==="trial_device_limit"?n.warn("This machine has already been used for the free trial on two other accounts, so record and run are blocked. Email support to request another trial, or subscribe from your account."):n.warn(`The account is connected but not active (${u.license.reason??u.license.status??"unknown"}). Check your subscription at your account page.`)):n.success("Connected.");return}if(u.status!=="pending"){if(u.status==="expired")throw new Error("The code expired. Run `verirun login` again.");if(u.status==="denied")throw new Error("The request was denied in the browser.");if(u.status==="no_license")throw new Error("That account has no license. Contact support.");if(u.status==="fingerprint_mismatch")throw new Error("This machine does not match the one that started the login.")}}throw new Error("Timed out waiting for approval. Run `verirun login` again.")}async function Re(){let{loadGlobalConfig:e,resolveServer:r,saveGlobalConfig:o,clearLicenseState:t}=await ie(),i=await e(),s=r(i.licenseServer);i.token&&await fetch(`${s}/api/cli/logout`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:i.token})}).catch(()=>{}),await o({token:void 0,licenseKey:void 0}),await t(),n.success("Disconnected this machine. Run `verirun login` to reconnect.")}async function Ce(e){let{resolveCredential:r,checkWithServer:o,persistLease:t,readStoredLease:i}=await ie(),s=await r();if(n.info(""),!s){n.info(n.bold("Verirun: not connected")),n.info(""),n.info(`Run ${n.bold("verirun login")} to connect this machine.`),n.info("");return}let a=e.server?e.server.replace(/\/+$/,""):s.server,c={...s,server:a};n.info(n.bold("Verirun")),n.info(` credential ${s.kind==="token"?"device token":"license key"}`+(process.env.VERIRUN_LICENSE_KEY?n.dim(" (from $VERIRUN_LICENSE_KEY)"):"")),n.info(` server ${a}`);let l=await o(c);if(l.reachable&&l.lease){await t(c,l.lease);let f=(await i(c))?.payload;if(n.info(` status ${n.bold(f?.status??"valid")}`),f?.planName||f?.plan){let m=f.planName&&f.plan&&f.planName!==f.plan?n.dim(` (${f.plan})`):"";n.info(` plan ${f.planName??f.plan}${m}`)}typeof f?.seats=="number"&&n.info(` seats ${f.seats} machine${f.seats===1?"":"s"}`),f?.exp&&n.info(` lease until ${new Date(f.exp*1e3).toISOString()}`),n.info(""),n.info(n.dim("Checked just now, lease signature verified.")),n.info("");return}if(l.reachable&&l.result&&!l.result.valid){n.info(` status ${l.result.status??"invalid"} (${l.result.reason??"\u2014"})`),n.info(""),n.info("record and run will not proceed."),n.info("");return}n.warn(" the license server is not reachable right now.");let d=await i(c);if(d){let p=Math.floor((Date.now()-d.payload.iat*1e3)/Cr);n.info(` lease valid, issued ${p} day${p===1?"":"s"} ago`),n.info(n.dim(" Nags after 15 days offline, stops after 30."))}else n.info(n.dim(" No valid lease stored. Connect to the internet and run this again."));n.info("")}import{existsSync as Ne}from"node:fs";import{mkdir as Lr,readdir as Pe,writeFile as Nr}from"node:fs/promises";import{join as Te}from"node:path";import{existsSync as Ee}from"node:fs";import{chmod as Er,mkdir as Ir,readFile as Ie,writeFile as jr}from"node:fs/promises";import xr from"node:path";var je="data-testid";async function A(e){let r={};if(Ee(e)){let a=await Ie(e,"utf8");try{r=JSON.parse(a)}catch(c){throw new Error(`Config file is not valid JSON: ${e}`,{cause:c})}}let o=process.env.VERIRUN_SUPABASE_ACCESS_TOKEN;o&&(r.supabase={...r.supabase,accessToken:o});let t=process.env.VERIRUN_RAILWAY_TOKEN;t&&(r.railway={...r.railway,token:t});let i=process.env.VERIRUN_VERCEL_DRAIN_SECRET;i&&(r.vercel={...r.vercel,drainSecret:i});let s=process.env.VERIRUN_VERCEL_TOKEN?.trim();return s&&(r.vercel={...r.vercel,token:s}),r}async function V(e,r){let o={};if(Ee(e))try{o=JSON.parse(await Ie(e,"utf8"))}catch(i){throw new Error(`Config file is not valid JSON: ${e}`,{cause:i})}let t={...o,...r,supabase:r.supabase?{...o.supabase,...r.supabase}:o.supabase,vercel:r.vercel?{...o.vercel,...r.vercel}:o.vercel,railway:r.railway?{...o.railway,...r.railway}:o.railway};await Ir(xr.dirname(e),{recursive:!0,mode:448}),await jr(e,`${JSON.stringify(t,null,2)}
4
- `,{mode:384}),await Er(e,384).catch(()=>{})}import{existsSync as xe}from"node:fs";import C from"node:path";var B=".verirun";function Ar(e=process.cwd()){let r=C.resolve(e),o;for(;;){if(xe(C.join(r,".git")))return r;!o&&xe(C.join(r,"package.json"))&&(o=r);let t=C.dirname(r);if(t===r)break;r=t}return o??C.resolve(e)}function w(e){let r=Ar(e),o=C.join(r,B);return{repoRoot:r,dataDir:o,workflowsDir:C.join(o,"workflows"),runsDir:C.join(o,"runs"),configPath:C.join(o,"config.json")}}function P(e,r){return C.join(e.workflowsDir,`${r}.json`)}function Ae(e=new Date){return e.toISOString().replace(/[:.]/g,"-")}function Le(e,r,o){return C.join(e.runsDir,`${r}-${o}`)}var G=1;function Tr(e){return e.commands.filter(r=>r.name()!=="help").map(r=>{let o=r.registeredArguments.map(t=>t.required?`<${t.name()}>`:`[${t.name()}]`).join(" ");return{name:r.name(),usage:`verirun ${r.name()}${o?` ${o}`:""}${r.options.length?" [options]":""}`,description:r.description(),options:r.options.map(t=>({flags:t.flags,description:t.description}))}})}async function Pr(e){try{return(await Pe(e)).filter(r=>r.endsWith(".json")).map(r=>r.slice(0,-5)).sort()}catch{return[]}}async function _r(e,r){try{return(await Pe(e,{withFileTypes:!0})).filter(t=>t.isDirectory()).map(t=>t.name).sort().slice(-r).reverse()}catch{return[]}}async function Or(){let e=w(),r={};try{r=await A(e.configPath)}catch{}let o=["supabase","vercel","railway"].filter(t=>r[t]);return{repoRoot:e.repoRoot,dataDir:e.dataDir,dataDirExists:Ne(e.dataDir),configPath:e.configPath,configExists:Ne(e.configPath),logSources:[...o],userFilter:typeof r.userFilter=="string"?r.userFilter:null,workflows:await Pr(e.workflowsDir),recentRuns:await _r(e.runsDir,5)}}var se="verirun records a browser workflow once, replays those exact steps headless on demand, and captures the backend logs produced during the replay. Deterministic: the same recording gives the same run and the same answer. `verirun map` is the static half: it reads a React/TypeScript repo and emits the interaction graph \u2014 every page, the interactive elements on it, where they navigate, and the backend calls they make \u2014 without running anything.",ae=["```jsonc","{",' "schemaVersion": 1,',' "name": "<same as the filename>",',' "createdAt": "<ISO>",',' "startUrl": "https://app.example.com/login", // optional',' "browser": "chromium", // chromium | firefox | webkit',' "channel": "chrome", // optional: installed browser',' "steps": [',' { "index": 0, "action": "navigate", "params": { "url": "https://app.example.com/login" }, "signals": [] },',' { "index": 1, "action": "fill", "selector": "role=textbox[name=\\"Email\\"i]", "params": { "text": "ada@example.com" }, "signals": [] },',' { "index": 2, "action": "click", "selector": "role=button[name=\\"Log in\\"i]", "params": {}, "signals": [] }'," ]","}","```","","**Click your way through the app; do not walk it by URL.** Use `navigate` for the","first step, and after that reach a page by clicking the thing that goes there \u2014 a","workflow that jumps between URLs proves nothing about the UI, and a dead link or a","button that stopped submitting still passes. `verirun map --bfs <route> --depth 2`","prints each reachable page with the element that gets you there, and every element","in `map --json` carries the `selector` to click. Navigate mid-workflow only for a","page with no path to it, or to deliberately deep-link into a state.","","Actions and their required `params`: `navigate` (`url`, absolute), `click` /","`dblclick`, `fill` (`text`), `press` (`key`), `check` / `uncheck`, `select`","(`values`), `setInputFiles` (`files`). Everything except `navigate` needs a","`selector`. An unknown action stops the run; `assert*` is skipped with a warning.","`selector` goes straight to `page.locator()`, so it must be Playwright selector",'syntax \u2014 `role=button[name="Log in"i]`, `[data-testid="x"]`, or CSS.'],ce=["Anything behind a login needs a browser profile that is already signed in.","Pass the profile to `record` and `run`:","","```bash","verirun run <name> --channel chrome --user-data-dir ~/.verirun-profile","verirun record <name> --channel chrome --user-data-dir ~/.verirun-profile","```","","The profile has to be created once **by a human**, because identity providers","refuse to authenticate an automation-launched browser:","","```bash",'google-chrome --user-data-dir="$HOME/.verirun-profile" --password-store=basic',"# \u2192 sign in to the app in that window, then close it","```","","`--password-store=basic` (and `--use-mock-keychain` on macOS) matters: Playwright","always launches Chrome with those, and cookies written under the OS keyring cannot","be decrypted without them \u2014 the run would silently start logged out. For the same","reason you cannot point `--user-data-dir` at the human's everyday Chrome profile.","","If you are asked to test a signed-in flow and no such profile exists, say so and","give the command above rather than trying to script the login."],le=["A human records the workflow once: `verirun record <name> --url <app-url>` (needs a display).","After a code change, run it: `verirun run <name>`. Add `--user <email>` to keep only that user's log lines.","Exit code 0 = every step replayed. Exit code 1 = a step failed, or a licensing / setup error.","Read `.verirun/runs/<name>-<newest>/logs.json`: check `status`; on `failed` read `error` and `steps.failedAt`; then scan `entries` for the backend's side \u2014 a 200 that hid an exception, a write that never landed, a job that threw after the screen said done.","`verirun run` writes logs.json even when replay fails, so partial logs survive.","Do not edit files under `.verirun/workflows/` by hand unless you understand the selector format; re-record instead.","`verirun map` needs no recording and no run: use it to find what a page can do before writing a workflow, `--json` for the whole graph, `--bfs <route> --depth N` for what is reachable from one page."];function Dr(e,r){let o=[],t=(i="")=>{o.push(i)};t("# verirun \u2014 agent reference"),t(),t(se),t(),t(`Version ${N}. Full docs: https://get-verirun.duely.in and the bundled README.md / \`man verirun\`.`),t(),t("## This checkout"),t(),t(`- repo root: ${e.repoRoot}`),t(`- data dir: ${e.dataDir} ${e.dataDirExists?"(exists)":"(not created yet)"}`),t(`- config: ${e.configPath} ${e.configExists?"(present)":"(absent)"}`),t(`- log sources: ${e.logSources.length?e.logSources.join(", "):"none configured \u2014 `verirun run` still replays, just with no backend logs"}`),t(`- user filter: ${e.userFilter??"none"}`),t(`- workflows: ${e.workflows.length?e.workflows.join(", "):"none recorded yet"}`),t(`- recent runs: ${e.recentRuns.length?e.recentRuns.join(", "):"none yet"}`),t(),t("Account: `record`, `run` and `map` need a connected account (`verirun login`, or `$VERIRUN_LICENSE_KEY` in CI). `verirun whoami` shows status. `--help`, `--version`, `verirun log`, and `verirun agent` do not need one."),t(),t("## Commands");for(let i of r){t(),t(`### ${i.usage}`),i.description&&t(i.description);for(let s of i.options)t(`- \`${s.flags}\` \u2014 ${s.description}`)}t(),t("## `.verirun/` layout (at the repo root shown above)"),t(),t("```"),t(".verirun/"),t(" config.json log sources, userFilter, testIdAttribute"),t(" workflows/<name>.json one recorded workflow each"),t(" runs/<name>-<timestamp>/logs.json captured logs, one directory per run"),t("```"),t(),t("Per-user, not per-project: `~/.verirun/config.json` (device token), `~/.verirun/state.json` (signed license lease)."),t(),t(`## logs.json (schemaVersion ${G})`),t(),t("```jsonc"),t("{"),t(` "schemaVersion": ${G},`),t(' "workflow": "<name>",'),t(' "status": "ok" | "failed", // "failed" => process exit code 1'),t(' "window": { "startedAt": "<ISO>", "endedAt": "<ISO>" },'),t(' "steps": { "total": N, "replayed": N, "failedAt"?: N },'),t(' "error"?: "<message>", // present only when status is "failed"'),t(' "filter"?: { "user": "<needle>" }, // present when --user / config.userFilter narrowed entries'),t(' "sources": [ { "id": "supabase"|"vercel"|"railway", "name": "...", "entries": N } ],'),t(' "entries": ['),t(" {"),t(' "source": "supabase"|"vercel"|"railway",'),t(' "stream": "<sub-stream, e.g. edge_logs / lambda>",'),t(' "timestamp": "<ISO>",'),t(' "level": "<info|warn|error|...>",'),t(' "message": "<rendered log line>",'),t(' "raw": { /* provider payload, untouched */ }'),t(" }"),t(" ]"),t("}"),t("```"),t(),t("`entries` is every source merged and sorted by `timestamp`. When a `--user` filter is active, `entries` and every `sources[].entries` count are post-filter."),t(),t("## Writing a workflow yourself"),t(),t("`verirun map --json` gives every page element a `selector`, a `selectorConfidence` (`high` / `medium` / `low`) and a suggested `action`. That is enough to author `.verirun/workflows/<name>.json` without recording:"),t();for(let i of ae)t(i);t(),t("Then `verirun workflow check <name>` (add `--json` for machine-readable findings) validates shape, actions, selectors and params without opening a browser. It cannot tell you a selector matches the live page \u2014 only `verirun run <name>` can. Prefer `high`-confidence selectors; a `low` one is a guess. A recorded workflow is still more faithful, so do not overwrite one with a generated file: pick a different name."),t(),t("## Signed-in runs"),t();for(let i of ce)t(i);return t(),t("## Recommended agent loop"),t(),le.forEach((i,s)=>t(`${s+1}. ${i}`)),t(),t("Save this into your agent context: `verirun agent > .verirun/AGENT.md`, or paste it into `CLAUDE.md` / `.cursorrules` / an AGENTS.md. `verirun agent --json` emits the same information as JSON."),t(),o.join(`
5
- `)}function Vr(e,r){let o=[],t=(i="")=>{o.push(i)};t("---"),t("name: verirun"),t("description: >-"),t(" Test this app end to end with verirun: map the interaction graph to find what a"),t(" page does, replay a recorded browser workflow, and read the backend logs that the"),t(" replay produced. Use when asked to test a user flow, verify a change end to end,"),t(" reproduce a bug, or find out what a page can do and which API calls it makes."),t("---"),t(),t("# verirun"),t(),t(se),t(),t("## Decide which command you need"),t(),t("| You want to | Command | Needs a recording? |"),t("|---|---|---|"),t("| Know what a page does / which endpoints it calls | `verirun map` | no |"),t("| Know what is reachable from a page | `verirun map --bfs /route --depth 2` | no |"),t("| Re-run a user flow after a change | `verirun run <name>` | yes |"),t("| Write a test for a flow yourself | `verirun map --json` then author the workflow | no |"),t("| Validate what you wrote | `verirun workflow check <name>` | no |"),t("| Capture a flow faithfully (incl. auth) | ask the human to run `verirun record <name>` | \u2014 |"),t(),t("## Static analysis first \u2014 `verirun map`"),t(),t("`map` reads the source and needs no browser, so reach for it before anything else."),t("It reports every page, the interactive elements on it, where they navigate, and the"),t("backend calls each one makes. `--json` gives the whole graph for programmatic use."),t("Limits to keep in mind: a target computed at runtime shows as `unresolved`, an"),t("endpoint passed through a variable as `?`, and Supabase `.auth.*` calls are not"),t("classified yet. `verirun map --reach` shows how much of each page it actually"),t("attached, so check it before trusting a page that looks empty."),t(),t("## Replay \u2014 `verirun run <name>`"),t(),t("A workflow is either recorded by a human (ground truth) or written by you from the"),t("map (a guess until `run` confirms it). Do not edit a recorded one by hand. Recording"),t("needs a display and a human, so ask for it rather than attempting it. For anything"),t("behind a login, see **Signed-in runs** below."),t(),le.slice(1).forEach((i,s)=>t(`${s+1}. ${i}`)),t(),t("## Writing a workflow from the map"),t(),t("`verirun map --json` gives each element a `selector`, a `selectorConfidence`"),t("(`high`/`medium`/`low`) and a suggested `action`, so you can author"),t("`.verirun/workflows/<name>.json` yourself instead of asking for a recording:"),t();for(let i of ae)t(i);t(),t("Loop: write the file \u2192 `verirun workflow check <name>` (static: shape, actions,"),t("params, selectors \u2014 no browser) \u2192 fix \u2192 `verirun run <name>` to find out whether"),t("the selectors actually match. Prefer `high` confidence; `low` means the selector"),t("matches more than one element. Never overwrite a recorded workflow with a"),t("generated one \u2014 use a new name; a recording is ground truth and yours is a guess."),t(),t("## Signed-in runs"),t();for(let i of ce)t(i);return t(),t("## Reading the result"),t(),t(`\`.verirun/runs/<name>-<newest>/logs.json\` (schemaVersion ${G}): check \`status\`;`),t("on `failed` read `error` and `steps.failedAt`; then scan `entries` (every source"),t("merged, sorted by `timestamp`, each with `source` / `level` / `message` / `raw`) for"),t("the backend side of the failure. Exit code 1 means a step failed or setup is wrong."),t(),t("## This checkout"),t(),t(`- repo root: ${e.repoRoot}`),t(`- log sources configured: ${e.logSources.length?e.logSources.join(", "):"none \u2014 `run` replays but captures nothing"}`),t(`- workflows: ${e.workflows.length?e.workflows.join(", "):"none recorded yet"}`),t(),t("## Full reference"),t(),t(`Run \`verirun agent\` for every command and flag (${r.length} commands), the`),t("`.verirun/` layout and the complete `logs.json` schema. `verirun <command> --help`"),t("works for any single one."),t(),o.join(`
6
- `)}async function _e(e,r){let o=await Or(),t=Tr(e);if(r.json){process.stdout.write(`${JSON.stringify({about:se,version:N,docs:"https://get-verirun.duely.in",checkout:o,commands:t,layout:{config:"<repo>/.verirun/config.json",workflows:"<repo>/.verirun/workflows/<name>.json",runs:"<repo>/.verirun/runs/<name>-<timestamp>/logs.json",userConfig:"~/.verirun/config.json",userState:"~/.verirun/state.json"},logsJsonSchemaVersion:G,signedIn:ce.join(`
7
- `),workflowSchema:{version:1,authoring:ae.join(`
8
- `),validate:"verirun workflow check <name> --json"},agentLoop:le},null,2)}
9
- `);return}if(r.skill){let i=`${Vr(o,t)}
10
- `;if(!r.install){process.stdout.write(i);return}let s=Te(w().repoRoot,".claude","skills","verirun");await Lr(s,{recursive:!0});let a=Te(s,"SKILL.md");await Nr(a,i),n.success(`Wrote ${a}`),n.info(n.dim("Claude Code loads it automatically when a task looks like app testing."));return}process.stdout.write(`${Dr(o,t)}
11
- `)}import{spawnSync as et}from"node:child_process";import{existsSync as rt,readFileSync as tt}from"node:fs";import nt from"node:path";import{createInterface as ot}from"node:readline/promises";var Ur="https://backboard.railway.com/graphql/v2",ue="https://railway.com/account/tokens";async function Oe(e,r,o){let t;try{t=await fetch(Ur,{method:"POST",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({query:r,variables:o})})}catch(s){return{error:s instanceof Error?s.message:String(s)}}let i=await t.json().catch(()=>{});return t.ok?i?.errors?.length?{error:i.errors.map(s=>s.message).filter(Boolean).join("; ")||"GraphQL error"}:i?.data?{data:i.data}:{error:"Railway returned no data."}:{error:i?.errors?.[0]?.message??`HTTP ${t.status}`}}async function K(e){if(e.deploymentId)return{deploymentId:e.deploymentId};if(!e.token||!e.projectId||!e.environmentId||!e.serviceId)return{error:"set railway.deploymentId, or railway.projectId + railway.environmentId + railway.serviceId"};let o=await Oe(e.token,`
3
+ import{createPublicKey as On,verify as _n}from"node:crypto";import{readFileSync as Dn}from"node:fs";import br from"node:path";import{fileURLToPath as Vn}from"node:url";import{Command as Un}from"commander";import oe from"node:os";import{setTimeout as Re}from"node:timers/promises";import{spawn as Cr}from"node:child_process";function L(e){let r=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",o=process.platform==="win32"?["/c","start","",e]:[e];try{let t=Cr(r,o,{stdio:"ignore",detached:!0});t.on("error",()=>{}),t.unref()}catch{}}var Er=!!process.stdout.isTTY&&!process.env.NO_COLOR,T=(e,r)=>Er?`\x1B[${e}m${r}\x1B[0m`:r,n={info:e=>console.log(e),step:e=>console.log(`${T("90","\xB7")} ${e}`),success:e=>console.log(`${T("32","\u2713")} ${e}`),warn:e=>console.warn(`${T("33","!")} ${e}`),error:e=>console.error(`${T("31","\u2717")} ${e}`),dim:e=>T("90",e),bold:e=>T("1",e)};var N="0.2.1";var Ir=1440*60*1e3;function ie(){return import("./gate.mjs")}async function Ce(e){let{getMachineId:r,saveGlobalConfig:o,clearLicenseState:t,loadGlobalConfig:i,resolveServer:s,persistLease:a}=await ie(),c=await i(),l=e.server?e.server.replace(/\/+$/,""):s(c.licenseServer);if(c.token&&!e.force){n.info("This machine is already connected. Run `verirun whoami`, or"),n.info("`verirun login --force` to connect it to a different account.");return}let d=await r(),p=await fetch(`${l}/api/cli/link`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({fingerprint:d,hostname:oe.hostname(),os:`${oe.platform()} ${oe.release()}`,cliVersion:N})}).catch(()=>{});if(!p||!p.ok)throw new Error(`Could not start login against ${l}. Check your connection.`);let f=await p.json(),m=`${f.verifyUrl}?code=${encodeURIComponent(f.userCode)}`;n.info(""),n.info("To connect this machine to your Verirun account:"),n.info(""),n.info(` 1. Open ${n.bold(f.verifyUrl)}`),n.info(` 2. Enter ${n.bold(f.userCode)}`),n.info(""),n.info(n.dim(`(trying to open ${m} for you)`)),L(m),n.info(""),n.step("Waiting for approval in the browser..."),e.server&&await o({licenseServer:l});let h=Date.now()+f.expiresIn*1e3,y=Math.max(2,f.interval)*1e3;for(;Date.now()<h;){await Re(y);let g=await fetch(`${l}/api/cli/link/poll`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({deviceCode:f.deviceCode,fingerprint:d})}).catch(()=>{});if(!g)continue;if(g.status===429){await Re(y);continue}let u=await g.json().catch(()=>({status:"server_error"}));if(u.status==="ok"&&u.token){await o({token:u.token,licenseKey:void 0}),await t();let v={kind:"token",value:u.token,server:l},S=u.license?.lease;if(S){await a(v,S);let $=u.license,j=$?.planName??$?.plan??"trial",x=typeof $?.seats=="number"&&$.seats>1?`, ${$.seats} machine seats`:"";n.success(`Connected. Plan: ${j} (${$?.status??"ok"})${x}.`)}else u.license&&u.license.valid===!1?(n.success("Connected."),u.license.reason==="trial_device_limit"?n.warn("This machine has already been used for the free trial on two other accounts, so record and run are blocked. Email support to request another trial, or subscribe from your account."):n.warn(`The account is connected but not active (${u.license.reason??u.license.status??"unknown"}). Check your subscription at your account page.`)):n.success("Connected.");return}if(u.status!=="pending"){if(u.status==="expired")throw new Error("The code expired. Run `verirun login` again.");if(u.status==="denied")throw new Error("The request was denied in the browser.");if(u.status==="no_license")throw new Error("That account has no license. Contact support.");if(u.status==="fingerprint_mismatch")throw new Error("This machine does not match the one that started the login.")}}throw new Error("Timed out waiting for approval. Run `verirun login` again.")}async function Ee(){let{loadGlobalConfig:e,resolveServer:r,saveGlobalConfig:o,clearLicenseState:t}=await ie(),i=await e(),s=r(i.licenseServer);i.token&&await fetch(`${s}/api/cli/logout`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:i.token})}).catch(()=>{}),await o({token:void 0,licenseKey:void 0}),await t(),n.success("Disconnected this machine. Run `verirun login` to reconnect.")}async function Ie(e){let{resolveCredential:r,checkWithServer:o,persistLease:t,readStoredLease:i}=await ie(),s=await r();if(n.info(""),!s){n.info(n.bold("Verirun: not connected")),n.info(""),n.info(`Run ${n.bold("verirun login")} to connect this machine.`),n.info("");return}let a=e.server?e.server.replace(/\/+$/,""):s.server,c={...s,server:a};n.info(n.bold("Verirun")),n.info(` credential ${s.kind==="token"?"device token":"license key"}`+(process.env.VERIRUN_LICENSE_KEY?n.dim(" (from $VERIRUN_LICENSE_KEY)"):"")),n.info(` server ${a}`);let l=await o(c);if(l.reachable&&l.lease){await t(c,l.lease);let f=(await i(c))?.payload;if(n.info(` status ${n.bold(f?.status??"valid")}`),f?.planName||f?.plan){let m=f.planName&&f.plan&&f.planName!==f.plan?n.dim(` (${f.plan})`):"";n.info(` plan ${f.planName??f.plan}${m}`)}typeof f?.seats=="number"&&n.info(` seats ${f.seats} machine${f.seats===1?"":"s"}`),f?.exp&&n.info(` lease until ${new Date(f.exp*1e3).toISOString()}`),n.info(""),n.info(n.dim("Checked just now, lease signature verified.")),n.info("");return}if(l.reachable&&l.result&&!l.result.valid){n.info(` status ${l.result.status??"invalid"} (${l.result.reason??"\u2014"})`),n.info(""),n.info("record and run will not proceed."),n.info("");return}n.warn(" the license server is not reachable right now.");let d=await i(c);if(d){let p=Math.floor((Date.now()-d.payload.iat*1e3)/Ir);n.info(` lease valid, issued ${p} day${p===1?"":"s"} ago`),n.info(n.dim(" Nags after 15 days offline, stops after 30."))}else n.info(n.dim(" No valid lease stored. Connect to the internet and run this again."));n.info("")}import{existsSync as Pe}from"node:fs";import{mkdir as Vr,readdir as _e,writeFile as Ur}from"node:fs/promises";import{join as Oe}from"node:path";import{existsSync as ae}from"node:fs";import{mkdir as Pr,readFile as je,writeFile as Or}from"node:fs/promises";import _r from"node:path";import{execFile as jr}from"node:child_process";import{chmod as xr}from"node:fs/promises";import Ar from"node:os";import{promisify as Lr}from"node:util";var Nr=Lr(jr);async function se(e,r){if(process.platform!=="win32")try{return await xr(e,r==="dir"?448:384),!0}catch{return!1}let o=Tr();if(!o)return!1;let t=r==="dir"?`${o}:(OI)(CI)F`:`${o}:F`;try{return await Nr("icacls",[e,"/inheritance:r","/grant:r",t],{timeout:1e4,windowsHide:!0}),!0}catch{return!1}}function Tr(){let e=process.env.USERNAME;if(!e)try{e=Ar.userInfo().username}catch{return}if(!e)return;let r=process.env.USERDOMAIN;return r&&r!==e?`${r}\\${e}`:e}var xe="data-testid";async function A(e){let r={};if(ae(e)){let a=await je(e,"utf8");try{r=JSON.parse(a)}catch(c){throw new Error(`Config file is not valid JSON: ${e}`,{cause:c})}}let o=process.env.VERIRUN_SUPABASE_ACCESS_TOKEN;o&&(r.supabase={...r.supabase,accessToken:o});let t=process.env.VERIRUN_RAILWAY_TOKEN;t&&(r.railway={...r.railway,token:t});let i=process.env.VERIRUN_VERCEL_DRAIN_SECRET;i&&(r.vercel={...r.vercel,drainSecret:i});let s=process.env.VERIRUN_VERCEL_TOKEN?.trim();return s&&(r.vercel={...r.vercel,token:s}),r}async function Ae(e,r){let o={};if(ae(e))try{o=JSON.parse(await je(e,"utf8"))}catch(a){throw new Error(`Config file is not valid JSON: ${e}`,{cause:a})}let t={...o,...r,supabase:r.supabase?{...o.supabase,...r.supabase}:o.supabase,vercel:r.vercel?{...o.vercel,...r.vercel}:o.vercel,railway:r.railway?{...o.railway,...r.railway}:o.railway},i=_r.dirname(e),s=ae(i);return await Pr(i,{recursive:!0,mode:448}),s||await se(i,"dir"),await Or(e,`${JSON.stringify(t,null,2)}
4
+ `,{mode:384}),se(e,"file")}import{existsSync as Le}from"node:fs";import C from"node:path";var W=".verirun";function Dr(e=process.cwd()){let r=C.resolve(e),o;for(;;){if(Le(C.join(r,".git")))return r;!o&&Le(C.join(r,"package.json"))&&(o=r);let t=C.dirname(r);if(t===r)break;r=t}return o??C.resolve(e)}function w(e){let r=Dr(e),o=C.join(r,W);return{repoRoot:r,dataDir:o,workflowsDir:C.join(o,"workflows"),runsDir:C.join(o,"runs"),configPath:C.join(o,"config.json")}}function P(e,r){return C.join(e.workflowsDir,`${r}.json`)}function Ne(e=new Date){return e.toISOString().replace(/[:.]/g,"-")}function Te(e,r,o){return C.join(e.runsDir,`${r}-${o}`)}var B=1;function Fr(e){return e.commands.filter(r=>r.name()!=="help").map(r=>{let o=r.registeredArguments.map(t=>t.required?`<${t.name()}>`:`[${t.name()}]`).join(" ");return{name:r.name(),usage:`verirun ${r.name()}${o?` ${o}`:""}${r.options.length?" [options]":""}`,description:r.description(),options:r.options.map(t=>({flags:t.flags,description:t.description}))}})}async function Mr(e){try{return(await _e(e)).filter(r=>r.endsWith(".json")).map(r=>r.slice(0,-5)).sort()}catch{return[]}}async function Wr(e,r){try{return(await _e(e,{withFileTypes:!0})).filter(t=>t.isDirectory()).map(t=>t.name).sort().slice(-r).reverse()}catch{return[]}}async function Br(){let e=w(),r={};try{r=await A(e.configPath)}catch{}let o=["supabase","vercel","railway"].filter(t=>r[t]);return{repoRoot:e.repoRoot,dataDir:e.dataDir,dataDirExists:Pe(e.dataDir),configPath:e.configPath,configExists:Pe(e.configPath),logSources:[...o],userFilter:typeof r.userFilter=="string"?r.userFilter:null,workflows:await Mr(e.workflowsDir),recentRuns:await Wr(e.runsDir,5)}}var ce="verirun records a browser workflow once, replays those exact steps headless on demand, and captures the backend logs produced during the replay. Deterministic: the same recording gives the same run and the same answer. `verirun map` is the static half: it reads a React/TypeScript repo and emits the interaction graph \u2014 every page, the interactive elements on it, where they navigate, and the backend calls they make \u2014 without running anything.",le=["```jsonc","{",' "schemaVersion": 1,',' "name": "<same as the filename>",',' "createdAt": "<ISO>",',' "startUrl": "https://app.example.com/login", // optional',' "browser": "chromium", // chromium | firefox | webkit',' "channel": "chrome", // optional: installed browser',' "steps": [',' { "index": 0, "action": "navigate", "params": { "url": "https://app.example.com/login" }, "signals": [] },',' { "index": 1, "action": "fill", "selector": "role=textbox[name=\\"Email\\"i]", "params": { "text": "ada@example.com" }, "signals": [] },',' { "index": 2, "action": "click", "selector": "role=button[name=\\"Log in\\"i]", "params": {}, "signals": [] }'," ]","}","```","","**Click your way through the app; do not walk it by URL.** Use `navigate` for the","first step, and after that reach a page by clicking the thing that goes there \u2014 a","workflow that jumps between URLs proves nothing about the UI, and a dead link or a","button that stopped submitting still passes. `verirun map --bfs <route> --depth 2`","prints each reachable page with the element that gets you there, and every element","in `map --json` carries the `selector` to click. Navigate mid-workflow only for a","page with no path to it, or to deliberately deep-link into a state.","","Actions and their required `params`: `navigate` (`url`, absolute), `click` /","`dblclick`, `fill` (`text`), `press` (`key`), `check` / `uncheck`, `select`","(`values`), `setInputFiles` (`files`). Everything except `navigate` needs a","`selector`. An unknown action stops the run; `assert*` is skipped with a warning.","`selector` goes straight to `page.locator()`, so it must be Playwright selector",'syntax \u2014 `role=button[name="Log in"i]`, `[data-testid="x"]`, or CSS.'],de=["Anything behind a login needs a browser profile that is already signed in.","Pass the profile to `record` and `run`:","","```bash","# macOS / Linux \u2014 the shell expands ~ before verirun sees it","verirun run <name> --channel chrome --user-data-dir ~/.verirun-profile","verirun record <name> --channel chrome --user-data-dir ~/.verirun-profile","```","","```powershell","# Windows \u2014 cmd and PowerShell do NOT expand ~ inside this argument, so pass an",'# absolute path. A literal ~ creates a directory named "~" and the run silently',"# starts logged out.",'verirun run <name> --channel chrome --user-data-dir "$env:USERPROFILE\\.verirun-profile"',"```","","verirun never expands `~` itself \u2014 the path goes straight through to Playwright.","","The profile has to be created once **by a human**, because identity providers","refuse to authenticate an automation-launched browser:","","```bash","# macOS / Linux",'google-chrome --user-data-dir="$HOME/.verirun-profile" --password-store=basic',"```","","```powershell","# Windows (PowerShell)",'& "$env:ProgramFiles\\Google\\Chrome\\Application\\chrome.exe" `',' --user-data-dir="$env:USERPROFILE\\.verirun-profile"',"```","","Sign in to the app in that window, then close it.","","`--password-store=basic` (and `--use-mock-keychain` on macOS) matter on Unix:","Playwright passes both on every platform, and cookies written under the OS keyring","cannot be decrypted without them \u2014 the run would silently start logged out.","Both switches are Unix-only, so on Windows they are ignored and the profile just","has to be created by the same Windows user that runs verirun. The Windows path is","untested \u2014 if a run there starts logged out despite a signed-in profile, report","that rather than guessing.","","On every platform, do not point `--user-data-dir` at the human's everyday Chrome","profile.","","If you are asked to test a signed-in flow and no such profile exists, say so and","give the command above rather than trying to script the login."],ue=["A human records the workflow once: `verirun record <name> --url <app-url>` (needs a display).","After a code change, run it: `verirun run <name>`. Add `--user <email>` to keep only that user's log lines.","Exit code 0 = every step replayed. Exit code 1 = a step failed, or a licensing / setup error.","Read `.verirun/runs/<name>-<newest>/logs.json`: check `status`; on `failed` read `error` and `steps.failedAt`; then scan `entries` for the backend's side \u2014 a 200 that hid an exception, a write that never landed, a job that threw after the screen said done.","`verirun run` writes logs.json even when replay fails, so partial logs survive.","Do not edit files under `.verirun/workflows/` by hand unless you understand the selector format; re-record instead.","`verirun map` needs no recording and no run: use it to find what a page can do before writing a workflow, `--json` for the whole graph, `--bfs <route> --depth N` for what is reachable from one page."];function Gr(e,r){let o=[],t=(i="")=>{o.push(i)};t("# verirun \u2014 agent reference"),t(),t(ce),t(),t(`Version ${N}. Full docs: https://get-verirun.duely.in and the bundled README.md / \`man verirun\`.`),t(),t("## This checkout"),t(),t(`- repo root: ${e.repoRoot}`),t(`- data dir: ${e.dataDir} ${e.dataDirExists?"(exists)":"(not created yet)"}`),t(`- config: ${e.configPath} ${e.configExists?"(present)":"(absent)"}`),t(`- log sources: ${e.logSources.length?e.logSources.join(", "):"none configured \u2014 `verirun run` still replays, just with no backend logs"}`),t(`- user filter: ${e.userFilter??"none"}`),t(`- workflows: ${e.workflows.length?e.workflows.join(", "):"none recorded yet"}`),t(`- recent runs: ${e.recentRuns.length?e.recentRuns.join(", "):"none yet"}`),t(),t("Account: `record`, `run` and `map` need a connected account (`verirun login`, or `$VERIRUN_LICENSE_KEY` in CI). `verirun whoami` shows status. `--help`, `--version`, `verirun log`, and `verirun agent` do not need one."),t(),t("## Commands");for(let i of r){t(),t(`### ${i.usage}`),i.description&&t(i.description);for(let s of i.options)t(`- \`${s.flags}\` \u2014 ${s.description}`)}t(),t("## `.verirun/` layout (at the repo root shown above)"),t(),t("```"),t(".verirun/"),t(" config.json log sources, userFilter, testIdAttribute"),t(" workflows/<name>.json one recorded workflow each"),t(" runs/<name>-<timestamp>/logs.json captured logs, one directory per run"),t("```"),t(),t("Per-user, not per-project: `~/.verirun/config.json` (device token), `~/.verirun/state.json` (signed license lease)."),t(),t(`## logs.json (schemaVersion ${B})`),t(),t("```jsonc"),t("{"),t(` "schemaVersion": ${B},`),t(' "workflow": "<name>",'),t(' "status": "ok" | "failed", // "failed" => process exit code 1'),t(' "window": { "startedAt": "<ISO>", "endedAt": "<ISO>" },'),t(' "steps": { "total": N, "replayed": N, "failedAt"?: N },'),t(' "error"?: "<message>", // present only when status is "failed"'),t(' "filter"?: { "user": "<needle>" }, // present when --user / config.userFilter narrowed entries'),t(' "sources": [ { "id": "supabase"|"vercel"|"railway", "name": "...", "entries": N } ],'),t(' "entries": ['),t(" {"),t(' "source": "supabase"|"vercel"|"railway",'),t(' "stream": "<sub-stream, e.g. edge_logs / lambda>",'),t(' "timestamp": "<ISO>",'),t(' "level": "<info|warn|error|...>",'),t(' "message": "<rendered log line>",'),t(' "raw": { /* provider payload, untouched */ }'),t(" }"),t(" ]"),t("}"),t("```"),t(),t("`entries` is every source merged and sorted by `timestamp`. When a `--user` filter is active, `entries` and every `sources[].entries` count are post-filter."),t(),t("## Writing a workflow yourself"),t(),t("`verirun map --json` gives every page element a `selector`, a `selectorConfidence` (`high` / `medium` / `low`) and a suggested `action`. That is enough to author `.verirun/workflows/<name>.json` without recording:"),t();for(let i of le)t(i);t(),t("Then `verirun workflow check <name>` (add `--json` for machine-readable findings) validates shape, actions, selectors and params without opening a browser. It cannot tell you a selector matches the live page \u2014 only `verirun run <name>` can. Prefer `high`-confidence selectors; a `low` one is a guess. A recorded workflow is still more faithful, so do not overwrite one with a generated file: pick a different name."),t(),t("## Signed-in runs"),t();for(let i of de)t(i);return t(),t("## Recommended agent loop"),t(),ue.forEach((i,s)=>t(`${s+1}. ${i}`)),t(),t("Save this into your agent context: `verirun agent > .verirun/AGENT.md`, or paste it into `CLAUDE.md` / `.cursorrules` / an AGENTS.md. `verirun agent --json` emits the same information as JSON."),t(),o.join(`
5
+ `)}function Kr(e,r){let o=[],t=(i="")=>{o.push(i)};t("---"),t("name: verirun"),t("description: >-"),t(" Test this app end to end with verirun: map the interaction graph to find what a"),t(" page does, replay a recorded browser workflow, and read the backend logs that the"),t(" replay produced. Use when asked to test a user flow, verify a change end to end,"),t(" reproduce a bug, or find out what a page can do and which API calls it makes."),t("---"),t(),t("# verirun"),t(),t(ce),t(),t("## Decide which command you need"),t(),t("| You want to | Command | Needs a recording? |"),t("|---|---|---|"),t("| Know what a page does / which endpoints it calls | `verirun map` | no |"),t("| Know what is reachable from a page | `verirun map --bfs /route --depth 2` | no |"),t("| Re-run a user flow after a change | `verirun run <name>` | yes |"),t("| Write a test for a flow yourself | `verirun map --json` then author the workflow | no |"),t("| Validate what you wrote | `verirun workflow check <name>` | no |"),t("| Capture a flow faithfully (incl. auth) | ask the human to run `verirun record <name>` | \u2014 |"),t(),t("## Static analysis first \u2014 `verirun map`"),t(),t("`map` reads the source and needs no browser, so reach for it before anything else."),t("It reports every page, the interactive elements on it, where they navigate, and the"),t("backend calls each one makes. `--json` gives the whole graph for programmatic use."),t("Limits to keep in mind: a target computed at runtime shows as `unresolved`, an"),t("endpoint passed through a variable as `?`, and Supabase `.auth.*` calls are not"),t("classified yet. `verirun map --reach` shows how much of each page it actually"),t("attached, so check it before trusting a page that looks empty."),t(),t("## Replay \u2014 `verirun run <name>`"),t(),t("A workflow is either recorded by a human (ground truth) or written by you from the"),t("map (a guess until `run` confirms it). Do not edit a recorded one by hand. Recording"),t("needs a display and a human, so ask for it rather than attempting it. For anything"),t("behind a login, see **Signed-in runs** below."),t(),ue.slice(1).forEach((i,s)=>t(`${s+1}. ${i}`)),t(),t("## Writing a workflow from the map"),t(),t("`verirun map --json` gives each element a `selector`, a `selectorConfidence`"),t("(`high`/`medium`/`low`) and a suggested `action`, so you can author"),t("`.verirun/workflows/<name>.json` yourself instead of asking for a recording:"),t();for(let i of le)t(i);t(),t("Loop: write the file \u2192 `verirun workflow check <name>` (static: shape, actions,"),t("params, selectors \u2014 no browser) \u2192 fix \u2192 `verirun run <name>` to find out whether"),t("the selectors actually match. Prefer `high` confidence; `low` means the selector"),t("matches more than one element. Never overwrite a recorded workflow with a"),t("generated one \u2014 use a new name; a recording is ground truth and yours is a guess."),t(),t("## Signed-in runs"),t();for(let i of de)t(i);return t(),t("## Reading the result"),t(),t(`\`.verirun/runs/<name>-<newest>/logs.json\` (schemaVersion ${B}): check \`status\`;`),t("on `failed` read `error` and `steps.failedAt`; then scan `entries` (every source"),t("merged, sorted by `timestamp`, each with `source` / `level` / `message` / `raw`) for"),t("the backend side of the failure. Exit code 1 means a step failed or setup is wrong."),t(),t("## This checkout"),t(),t(`- repo root: ${e.repoRoot}`),t(`- log sources configured: ${e.logSources.length?e.logSources.join(", "):"none \u2014 `run` replays but captures nothing"}`),t(`- workflows: ${e.workflows.length?e.workflows.join(", "):"none recorded yet"}`),t(),t("## Full reference"),t(),t(`Run \`verirun agent\` for every command and flag (${r.length} commands), the`),t("`.verirun/` layout and the complete `logs.json` schema. `verirun <command> --help`"),t("works for any single one."),t(),o.join(`
6
+ `)}async function De(e,r){let o=await Br(),t=Fr(e);if(r.json){process.stdout.write(`${JSON.stringify({about:ce,version:N,docs:"https://get-verirun.duely.in",checkout:o,commands:t,layout:{config:"<repo>/.verirun/config.json",workflows:"<repo>/.verirun/workflows/<name>.json",runs:"<repo>/.verirun/runs/<name>-<timestamp>/logs.json",userConfig:"~/.verirun/config.json",userState:"~/.verirun/state.json"},logsJsonSchemaVersion:B,signedIn:de.join(`
7
+ `),workflowSchema:{version:1,authoring:le.join(`
8
+ `),validate:"verirun workflow check <name> --json"},agentLoop:ue},null,2)}
9
+ `);return}if(r.skill){let i=`${Kr(o,t)}
10
+ `;if(!r.install){process.stdout.write(i);return}let s=Oe(w().repoRoot,".claude","skills","verirun");await Vr(s,{recursive:!0});let a=Oe(s,"SKILL.md");await Ur(a,i),n.success(`Wrote ${a}`),n.info(n.dim("Claude Code loads it automatically when a task looks like app testing."));return}process.stdout.write(`${Gr(o,t)}
11
+ `)}import{spawnSync as at}from"node:child_process";import{existsSync as ct,readFileSync as lt}from"node:fs";import dt from"node:path";import{createInterface as ut}from"node:readline/promises";var Jr="https://backboard.railway.com/graphql/v2",pe="https://railway.com/account/tokens";async function Ve(e,r,o){let t;try{t=await fetch(Jr,{method:"POST",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({query:r,variables:o})})}catch(s){return{error:s instanceof Error?s.message:String(s)}}let i=await t.json().catch(()=>{});return t.ok?i?.errors?.length?{error:i.errors.map(s=>s.message).filter(Boolean).join("; ")||"GraphQL error"}:i?.data?{data:i.data}:{error:"Railway returned no data."}:{error:i?.errors?.[0]?.message??`HTTP ${t.status}`}}async function G(e){if(e.deploymentId)return{deploymentId:e.deploymentId};if(!e.token||!e.projectId||!e.environmentId||!e.serviceId)return{error:"set railway.deploymentId, or railway.projectId + railway.environmentId + railway.serviceId"};let o=await Ve(e.token,`
12
12
  query($input: JSON!) {
13
13
  deployments(input: $input, first: 1) {
14
14
  edges { node { id status createdAt } }
15
15
  }
16
- }`,{input:{projectId:e.projectId,environmentId:e.environmentId,serviceId:e.serviceId}});if("error"in o)return o;let t=o.data.deployments.edges[0]?.node;return t?{deploymentId:t.id}:{error:"no deployments found for that project / environment / service"}}async function fe(e,r,o,t={}){let i=t.userNeedle?.trim(),s=i?`"${i.replace(/"/g,"")}"`:void 0,c=await Oe(e,`
16
+ }`,{input:{projectId:e.projectId,environmentId:e.environmentId,serviceId:e.serviceId}});if("error"in o)return o;let t=o.data.deployments.edges[0]?.node;return t?{deploymentId:t.id}:{error:"no deployments found for that project / environment / service"}}async function me(e,r,o,t={}){let i=t.userNeedle?.trim(),s=i?`"${i.replace(/"/g,"")}"`:void 0,c=await Ve(e,`
17
17
  query($id: String!, $start: DateTime, $end: DateTime, $filter: String) {
18
18
  deploymentLogs(deploymentId: $id, startDate: $start, endDate: $end, filter: $filter, limit: 1000) {
19
19
  timestamp message severity tags attributes
20
20
  }
21
- }`,{id:r,start:o.startedAt,end:o.endedAt,filter:s});return"error"in c?c:{entries:Array.isArray(c.data.deploymentLogs)?c.data.deploymentLogs:[]}}function Mr(e){let r=typeof e.severity=="string"?e.severity:void 0;return{source:"railway",stream:r?r.toLowerCase():"deploy",timestamp:typeof e.timestamp=="string"?e.timestamp:void 0,level:r,message:typeof e.message=="string"?e.message:void 0,raw:e}}var de=class{id="railway";name="Railway";cfg;constructor(r){this.cfg=r}async start(){if(!this.cfg.token)throw new Error("Railway log capture needs an API token. Set VERIRUN_RAILWAY_TOKEN or railway.token in .verirun/config.json.");if(!this.cfg.deploymentId&&!(this.cfg.projectId&&this.cfg.environmentId&&this.cfg.serviceId))throw new Error("Railway log capture needs railway.deploymentId, or railway.projectId + railway.environmentId + railway.serviceId, in .verirun/config.json.")}async collect(r,o){let t=await K(this.cfg);if("error"in t)return n.warn(`Railway: ${t.error}`),[];let i=await fe(this.cfg.token,t.deploymentId,o,{userNeedle:r.userFilter});if("error"in i)return n.warn(`Railway: ${i.error}`),[];let s=i.entries.map(Mr);return s.sort((a,c)=>(a.timestamp??"").localeCompare(c.timestamp??"")),s}async dispose(){}};function De(e){return e.railway?new de(e.railway):void 0}var Fr="https://api.supabase.com",me=["postgres_logs","edge_logs","auth_logs"],pe=class{id="supabase";name="Supabase";projectRef;accessToken;sources;constructor(r){this.projectRef=r.projectRef,this.accessToken=r.accessToken,this.sources=r.sources&&r.sources.length>0?r.sources:me}async start(){if(!this.projectRef)throw new Error("Supabase log capture needs supabase.projectRef in .verirun/config.json.");if(!this.accessToken)throw new Error("Supabase log capture needs an access token. Set VERIRUN_SUPABASE_ACCESS_TOKEN or supabase.accessToken in .verirun/config.json.")}async collect(r,o){let t=r.userFilter,i=[],s=!1;for(let a of this.sources){let c=await J(this.projectRef,this.accessToken,a,o,{userNeedle:t});if("error"in c){n.warn(`Supabase ${a}: ${c.error}`);continue}t&&!c.serverFiltered&&(s=!0);for(let l of c.rows)i.push(Br(a,l))}return t&&s&&n.info(n.dim("Supabase: user filter applied client-side for a source (more rows pulled).")),i.sort((a,c)=>(a.timestamp??"").localeCompare(c.timestamp??"")),i}async dispose(){}},Wr=/^[A-Za-z0-9._@%+-]{1,256}$/;async function Ve(e,r,o,t){let i=new URL(`/v1/projects/${e}/analytics/endpoints/logs.all`,Fr);i.searchParams.set("sql",o),i.searchParams.set("iso_timestamp_start",t.startedAt),i.searchParams.set("iso_timestamp_end",t.endedAt);let s;try{s=await fetch(i,{headers:{Authorization:`Bearer ${r}`,Accept:"application/json"}})}catch(c){return{error:c instanceof Error?c.message:String(c)}}let a=await s.json().catch(()=>{});if(!s.ok){let c=(typeof a?.error=="string"?a.error:a?.error?.message)??a?.message??`HTTP ${s.status}`;return{error:`${c}${c.startsWith("HTTP")?"":` (HTTP ${s.status})`}`}}return{rows:Array.isArray(a?.result)?a.result:[]}}async function J(e,r,o,t,i={}){let s=i.userNeedle?.trim().toLowerCase(),a=s&&Wr.test(s)?s:void 0,c=p=>{let f=p&&a?` where strpos(lower(event_message), '${a}') > 0 or strpos(lower(to_json_string(metadata)), '${a}') > 0`:"";return`select id, timestamp, event_message, metadata from ${o}${f} order by timestamp asc limit 1000`},l=await Ve(e,r,c(!0),t);if(!("error"in l))return{rows:l.rows,serverFiltered:!!a};if(!a)return l;let d=await Ve(e,r,c(!1),t);return"error"in d?d:{rows:d.rows,serverFiltered:!1}}function Br(e,r){return{source:"supabase",stream:e,timestamp:Gr(r.timestamp),message:typeof r.event_message=="string"?r.event_message:void 0,raw:r}}function Gr(e){if(typeof e=="string")return e;if(typeof e=="number"&&Number.isFinite(e)){let r=e>1e14?e/1e3:e;return new Date(r).toISOString()}}function Ue(e){return e.supabase?new pe(e.supabase):void 0}import{createHmac as qr,timingSafeEqual as Yr}from"node:crypto";import{createServer as zr}from"node:http";import{setTimeout as Qr}from"node:timers/promises";var Me="https://api.vercel.com",q="https://vercel.com/account/settings/tokens",Kr=8e3,Jr=1500,Hr=3e3;function ge(e){return e?`&teamId=${encodeURIComponent(e)}`:""}async function he(e,r){let o;try{o=await fetch(`${Me}${e}`,{headers:{Authorization:`Bearer ${r}`,Accept:"application/json"}})}catch(i){return{error:i instanceof Error?i.message:String(i)}}let t=await o.json().catch(()=>{});return o.ok?{data:t}:{error:t?.error?.message??`HTTP ${o.status}`}}async function Fe(e,r){let o=await he(`/v9/projects?limit=100${ge(r)}`,e);return"error"in o?o:{projects:o.data.projects??[]}}async function We(e){let r=await he("/v2/teams?limit=100",e);return"error"in r?r:{teams:r.data.teams??[]}}async function Y(e){if(e.deploymentId)return{deploymentId:e.deploymentId,label:e.deploymentId};if(!e.token)return{error:"no token"};if(!e.projectId)return{error:"no projectId"};let r=e.environment??"production",o=await he(`/v6/deployments?projectId=${encodeURIComponent(e.projectId)}&limit=1&state=READY&target=${encodeURIComponent(r)}${ge(e.teamId)}`,e.token);if("error"in o)return{error:o.error};let t=o.data.deployments?.[0];return t?{deploymentId:t.uid,label:t.url??t.uid}:{error:`no READY ${r} deployment found for this project`}}async function z(e,r,o){let t=`/v1/projects/${encodeURIComponent(e.projectId)}/deployments/${encodeURIComponent(r)}/runtime-logs?limit=1000${ge(e.teamId)}`,i=new AbortController,s=setTimeout(()=>i.abort(),o),a,c=()=>{a&&clearTimeout(a),a=setTimeout(()=>i.abort(),Jr)},l=[];try{let d=await fetch(`${Me}${t}`,{headers:{Authorization:`Bearer ${e.token}`,Accept:"application/x-ndjson, application/json"},signal:i.signal});if(!d.ok)return{error:(await d.json().catch(()=>{}))?.error?.message??`HTTP ${d.status}`};if(!d.body)return{rows:l};c();let p=new TextDecoder,f="";for await(let m of d.body){f+=p.decode(m,{stream:!0});let h=f.split(`
22
- `);f=h.pop()??"";for(let y of h){let g=y.trim();if(g)try{let u=JSON.parse(g);Array.isArray(u)?l.push(...u):l.push(u)}catch{}}c()}}catch(d){if(!(d instanceof Error&&d.name==="AbortError"))return{error:d instanceof Error?d.message:String(d)}}finally{clearTimeout(s),a&&clearTimeout(a)}return{rows:l}}function we(e){let r=e.requestPath?` ${e.requestMethod??""} ${e.requestPath}`.trim():"",o=e.responseStatusCode?` (${e.responseStatusCode})`:"";return{source:"vercel",...e.source?{stream:e.source}:{},...e.timestampInMs?{timestamp:new Date(e.timestampInMs).toISOString()}:{},...e.level?{level:e.level}:{},message:e.message??`${r}${o}`.trim(),raw:e}}var H=class{id="vercel";name="Vercel";config;constructor(r){this.config=r}async start(){if(!this.config.token)throw new Error("Vercel log capture needs an API token. Run `verirun log vercel`, or set VERIRUN_VERCEL_TOKEN / vercel.token in .verirun/config.json.");if(!this.config.projectId)throw new Error("Vercel log capture needs vercel.projectId. Run `verirun log vercel`.")}async collect(r,o){let t=await Y(this.config);if("error"in t)return n.warn(`Vercel: ${t.error}`),[];let i=await z(this.config,t.deploymentId,this.config.readMs??Kr);if("error"in i)return n.warn(`Vercel: ${i.error}`),[];let s=Date.parse(o.startedAt),a=Date.parse(o.endedAt)+(this.config.tailGraceMs??Hr);return i.rows.filter(c=>typeof c.timestampInMs!="number"?!0:c.timestampInMs>=s&&c.timestampInMs<=a).map(we)}async dispose(){}};var Q=4319,X="/drain",ye=3e3,U=class{id="vercel";name="Vercel";port;path;secret;graceMs;project;onEntry;server;received=[];droppedByProject=0;constructor(r,o={}){this.port=r.listenerPort??Q,this.path=r.listenerPath??X,this.secret=r.drainSecret,this.graceMs=r.drainGraceMs??ye,this.project=r.project?.trim()||void 0,this.onEntry=o.onEntry}projectMatches(r){return this.project?r.projectId===this.project||r.projectName===this.project:!0}async start(){let r=zr((o,t)=>this.handle(o,t));this.server=r,await new Promise((o,t)=>{let i=s=>{t(s.code==="EADDRINUSE"?new Error(`Vercel log listener: port ${this.port} is already in use.`):s)};r.once("error",i),r.listen(this.port,()=>{r.off("error",i),o()})}),n.step(`Vercel log listener on http://localhost:${this.port}${this.path}`)}async collect(){return this.graceMs>0&&await Qr(this.graceMs),this.received.length===0&&this.droppedByProject>0&&n.warn(`Vercel: ${this.droppedByProject} log line(s) arrived but none matched project "${this.project}". Check the name/ID in .verirun/config.json (vercel.project).`),[...this.received]}async dispose(){let r=this.server;r&&(this.server=void 0,await new Promise(o=>r.close(()=>o())))}handle(r,o){let t=r.headers["x-vercel-verify"];if(typeof t=="string"&&o.setHeader("x-vercel-verify",t),r.method!=="POST"||!this.matchesPath(r.url)){o.statusCode=r.method==="POST"?404:200,o.end();return}let i=[];r.on("data",s=>i.push(s)),r.on("error",()=>{o.statusCode=400,o.end()}),r.on("end",()=>{let s=Buffer.concat(i);if(!this.verifySignature(r,s)){n.warn("Vercel log drain: rejected a delivery with a bad signature."),o.statusCode=401,o.end();return}try{for(let a of Xr(s.toString("utf8"))){if(!this.projectMatches(a)){this.droppedByProject+=1;continue}let c=Zr(a);this.received.push(c),this.onEntry?.(c)}}catch{n.warn("Vercel log drain: could not parse a delivery body.")}o.statusCode=200,o.end()})}matchesPath(r){return r?(r.split("?")[0]??"")===this.path:!1}verifySignature(r,o){if(!this.secret)return!0;let t=r.headers["x-vercel-signature"];if(typeof t!="string")return!1;let i=qr("sha1",this.secret).update(o).digest("hex"),s=Buffer.from(i),a=Buffer.from(t);return s.length===a.length&&Yr(s,a)}};function Xr(e){let r=e.trim();if(!r)return[];if(r.startsWith("[")){let o=JSON.parse(r);return Array.isArray(o)?o:[]}return r.split(`
23
- `).map(o=>o.trim()).filter(Boolean).map(o=>JSON.parse(o))}function Zr(e){return{source:"vercel",stream:typeof e.source=="string"?e.source:void 0,timestamp:typeof e.timestamp=="number"?new Date(e.timestamp).toISOString():void 0,level:typeof e.level=="string"?e.level:void 0,message:typeof e.message=="string"?e.message:void 0,raw:e}}function Be(e){if(e.vercel)return e.vercel.token?new H(e.vercel):new U(e.vercel)}var Ge=["vercel","supabase","railway"];async function Ke(e,r){if(e!==void 0&&!Ge.includes(e))throw new Error(`Unknown log source "${e}". Use one of: ${Ge.join(", ")}.`);let o=w(),t=await A(o.configPath);if(e===void 0){it(t);return}if(e==="vercel"){await dt(t,r);return}if(e==="railway"){await vt(t,r);return}await ht(t,r)}function it(e){let r=e.vercel,o=e.supabase,t=e.railway;n.info(""),n.info(n.bold("Log sources")),n.info(""),n.info(` ${"vercel".padEnd(10)} ${r?.token&&r.projectId?`configured project ${r.projectId}`:r?`drain mode listener :${r.listenerPort??Q}${r.listenerPath??X}`:n.dim("not configured")}`),n.info(` ${"supabase".padEnd(10)} ${o?`configured project ${o.projectRef??n.dim("(no projectRef)")}`:n.dim("not configured")}`),n.info(` ${"railway".padEnd(10)} ${t?`configured ${t.deploymentId?`deployment ${t.deploymentId}`:`service ${t.serviceId??n.dim("(none)")}`}`:n.dim("not configured")}`),n.info(""),n.info(`Run ${n.bold("verirun log vercel")}, ${n.bold("verirun log supabase")} or ${n.bold("verirun log railway")} to connect one.`)}var st="https://vercel.com/d?to=%2F%5Bteam%5D%2F~%2Fsettings%2Flog-drains&title=Log%20Drains";function at(e){let r=nt.join(e,".vercel","project.json");if(rt(r))try{let o=JSON.parse(tt(r,"utf8"));return o.projectId?{projectId:o.projectId,...o.orgId?.startsWith("team_")?{teamId:o.orgId}:{}}:void 0}catch{return}}async function ct(e){let r=await We(e),o;if("error"in r)n.warn(` Could not list teams: ${r.error}`);else if(r.teams.length===1)o=r.teams[0].id,n.info(` team ${r.teams[0].name??o}`);else if(r.teams.length>1){n.info(" Which team?"),n.info(` 1. ${n.dim("(personal account)")}`),r.teams.forEach((c,l)=>n.info(` ${l+2}. ${c.name??c.slug??c.id}`));let a=Number.parseInt(await b(" Number: "),10)-2;r.teams[a]&&(o=r.teams[a].id)}let t=await Fe(e,o);if("error"in t){n.error(` Could not list projects: ${t.error}`);return}if(t.projects.length===0){n.warn(" That token can see no projects.");return}if(t.projects.length===1){let a=t.projects[0];return n.info(` project ${a.name} (${a.id})`),{projectId:a.id,...o?{teamId:o}:{}}}n.info(" Which project?"),t.projects.forEach((a,c)=>n.info(` ${c+1}. ${a.name}`));let i=Number.parseInt(await b(" Number: "),10)-1,s=t.projects[i];if(!s){n.warn(" Not one of the choices.");return}return{projectId:s.id,...o?{teamId:o}:{}}}async function lt(e){if(!e.token||!e.projectId)throw new Error("--test needs a connected project. Run `verirun log vercel` first.");let r=await Y(e);if("error"in r){n.error(` ${r.error}`),process.exitCode=1;return}n.info(""),n.info(`Reading runtime logs for ${n.bold(r.label)}\u2026`);let o=await z(e,r.deploymentId,e.readMs??8e3);if("error"in o){n.error(` ${o.error}`),process.exitCode=1;return}let t=Date.now()-5*6e4,i=o.rows.filter(s=>typeof s.timestampInMs!="number"||s.timestampInMs>=t);n.success(` ${o.rows.length} line(s) on the stream, ${i.length} from the last 5 minutes.`);for(let s of i.slice(-5)){let a=we(s);n.info(` ${n.dim(a.timestamp??"")} ${a.message??""}`)}o.rows.length===0&&n.info(n.dim(" No lines yet \u2014 hit the deployed app once, then re-run with --test."))}async function dt(e,r){let{configPath:o,repoRoot:t}=w(),i=e.vercel??{},s=process.env.VERIRUN_VERCEL_TOKEN;if(r.drain||r.listen){await ut(e,r);return}if(r.test){await lt(i);return}if(i.token&&i.projectId&&!r.reconnect){n.info(""),n.info(n.bold("Vercel logs \u2014 connected")),n.info(` project ${i.projectId}`),i.teamId&&n.info(` team ${i.teamId}`),n.info(` token ${s?"from $VERIRUN_VERCEL_TOKEN":"from config.json"}`),n.info(` deployment ${i.deploymentId??n.dim(`newest ready ${i.environment??"production"}`)}`),n.info(""),n.info(n.dim("--reconnect to replace it \xB7 --test to read the last 5 minutes"));return}n.info(""),n.info(n.bold("Connect Vercel logs"));let a=s??i.token;if(!a||r.reconnect){if(!process.stdin.isTTY){n.info(""),n.info("Not an interactive shell. Set these and re-run:"),n.info(` export VERIRUN_VERCEL_TOKEN=... ${n.dim(`(create at ${q})`)}`),n.info(` ${n.dim("and vercel.projectId (+ vercel.teamId) in .verirun/config.json")}`);return}n.info(` Opening ${n.bold(q)}`),n.info(" Create a token, copy it, come back here."),L(q),n.info("");let h=await b(" Paste the token: ");if(!h){n.warn(" Nothing pasted. No changes made.");return}a=h}let c=r.reconnect?void 0:at(t);c&&n.info(` project ${c.projectId} ${n.dim("\u2014 from .vercel/project.json")}`);let l=c??await ct(a);if(!l){n.warn(" No project chosen. No changes made.");return}let d={projectId:l.projectId,...l.teamId?{teamId:l.teamId}:{}};s||(d.token=a),await V(o,{vercel:d}),n.info(""),n.info(` Saved to ${n.dim(o)}`),n.info(" Checking it works\u2026");let p={...i,...d,token:a},f=await Y(p);if("error"in f){n.error(` ${f.error}`),n.info(n.dim(" Token or project looks wrong. Re-run `verirun log vercel --reconnect`.")),process.exitCode=1;return}let m=await z(p,f.deploymentId,4e3);if("error"in m){n.error(` Reading logs failed: ${m.error}`),n.info(n.dim(" The token may lack access to this project. Re-run with --reconnect.")),process.exitCode=1;return}n.success(` Connected to ${f.label}. \`verirun run\` now includes Vercel logs.`),m.rows.length===0&&n.info(n.dim(" (No log lines in the stream right now \u2014 that is normal for an idle app.)"))}async function ut(e,r){let{configPath:o}=w(),t=e.vercel??{},i=t.listenerPort??Q,s=t.listenerPath??X,a=t.drainGraceMs??ye;if(r.listen){await ft({...t,listenerPort:i,listenerPath:s});return}let c=process.env.VERIRUN_VERCEL_DRAIN_SECRET;if((t.drainSecret||c)&&!r.reconnect){n.info(""),n.info(n.bold("Vercel logs \u2014 drain mode")),n.info(` endpoint http://localhost:${i}${s}`),n.info(` drain secret ${c?"from $VERIRUN_VERCEL_DRAIN_SECRET":"from config.json"}`),n.info(` grace ${a}ms`),n.info(` project ${t.project??n.dim("all projects on the drain")}`),n.info(""),n.info(n.dim("--reconnect to change it \xB7 --listen to run the verification listener")),n.info(n.dim("`verirun log vercel` (no --drain) switches to the simpler API mode"));return}if(n.info(""),n.info(n.bold("Connect Vercel logs the old way (drain) \u2014 do these in order:")),n.info(n.dim(" You probably want `verirun log vercel` instead: a token, no tunnel.")),n.info(""),n.info(" 1. New terminal. Start a tunnel to port "+i+" and copy the https URL it prints:"),n.info(` ${n.bold(`ngrok http ${i}`)}`),n.info(n.dim(` (or: cloudflared tunnel --url http://localhost:${i})`)),n.info(""),n.info(" 2. Another new terminal. Start the listener and leave it running:"),n.info(` ${n.bold("verirun log vercel --listen")}`),n.info(""),n.info(" 3. Vercel page opening now (your team \u2192 Settings \u2192 Log Drains) \u2192 Add a drain:"),n.info(" Sources ......... check "+n.bold("Edge")+" and "+n.bold("Serverless")+", uncheck the rest"),n.info(" Delivery format . "+n.bold("JSON")),n.info(` Endpoint ........ ${n.bold(`<https URL from step 1>${s}`)}`),n.info(" then Save."),n.info(""),n.info(" 4. Vercel shows a Signing Secret. Copy it, paste it below."),!process.stdin.isTTY){n.info(""),n.info(n.dim(" Then: VERIRUN_VERCEL_DRAIN_SECRET=<secret> (or vercel.drainSecret in .verirun/config.json)"));return}L(st),n.info("");let l=await b(" Signing secret: ");if(!l){n.warn(" No secret. Deliveries would NOT be verified \u2014 anyone who finds the tunnel URL"),n.warn(" could feed fake logs into your runs.");let f=(await b(" Save without a secret anyway? [y/N]: ")).toLowerCase();if(f!=="y"&&f!=="yes"){n.info(" Nothing saved. Re-run `verirun log vercel --drain` once you have the secret.");return}l=""}let d=await b(" Only one project's logs? Paste its name or prj_\u2026 ID, or press Enter for all: "),p={};l&&(p.drainSecret=l),d&&(p.project=d),await V(o,{vercel:p}),n.info(""),n.info(` Saved to ${n.dim(o)}`),n.success(" Done. `verirun run` starts its own listener \u2014 you only need --listen for tailing.")}async function ft(e){let r=new U(e,{onEntry:o=>{let t=o.timestamp??new Date().toISOString(),i=(o.level??"log").padEnd(5),s=o.stream?`${o.stream} `:"";n.info(`${n.dim(t)} ${i} ${n.dim(s)}${o.message??""}`)}});await r.start(),e.project&&n.info(n.dim(`Filtering to project "${e.project}".`)),n.info(n.dim("Waiting for deliveries. Press Ctrl+C to stop.")),n.info(""),await new Promise(o=>{let t=()=>{process.off("SIGINT",t),process.off("SIGTERM",t),n.info(""),r.dispose().then(o)};process.on("SIGINT",t),process.on("SIGTERM",t)}),n.step("Listener stopped.")}var ve="https://supabase.com/dashboard/account/tokens";async function b(e){if(!process.stdin.isTTY)return"";let r=ot({input:process.stdin,output:process.stdout});try{return(await r.question(e)).trim()}finally{r.close()}}function pt(){let e=et("supabase",["projects","list","--output","json"],{encoding:"utf8"});if(!(e.error||e.status!==0))try{let o=JSON.parse(e.stdout).map(t=>({ref:String(t.id??t.ref??t.reference_id??""),name:String(t.name??"")})).filter(t=>t.ref!=="");return o.length>0?o:void 0}catch{return}}async function mt(e){if(e)return e;let r=pt();if(r&&r.length===1){let t=r[0];return n.info(` project ${t.name} (${t.ref}) ${n.dim("\u2014 from the supabase CLI")}`),t.ref}if(r&&r.length>1){n.info(" Which project?"),r.forEach((i,s)=>n.info(` ${s+1}. ${i.name} (${i.ref})`));let t=Number.parseInt(await b(" Number: "),10)-1;if(r[t])return r[t].ref;n.warn(" Not one of the choices.")}return await b(" Project ref (the <ref> in dashboard/project/<ref>): ")||void 0}async function gt(e,r,o){if(!e.projectRef)throw new Error("--test needs a connected project. Run `verirun log supabase` first.");if(!o)throw new Error("--test needs an access token. Run `verirun log supabase`, or set $VERIRUN_SUPABASE_ACCESS_TOKEN.");let t=new Date,i={startedAt:new Date(t.getTime()-5*6e4).toISOString(),endedAt:t.toISOString()};n.info(""),n.info(`Querying ${r.length} source${r.length===1?"":"s"} for the last 5 minutes\u2026`),n.info("");let s=!1;for(let a of r){let c=await J(e.projectRef,o,a,i);"error"in c?(s=!0,n.error(`${a.padEnd(16)} ${c.error}`)):n.success(`${a.padEnd(16)} ${c.rows.length} row${c.rows.length===1?"":"s"}`)}s&&(process.exitCode=1)}async function ht(e,r){let{configPath:o}=w(),t=e.supabase??{},i=t.sources&&t.sources.length>0?t.sources:me,s=process.env.VERIRUN_SUPABASE_ACCESS_TOKEN,a=s??t.accessToken;if(r.test){await gt(t,i,a);return}if(t.projectRef&&a&&!r.reconnect){n.info(""),n.info(n.bold("Supabase logs \u2014 connected")),n.info(` project ${t.projectRef}`),n.info(` token ${s?"from $VERIRUN_SUPABASE_ACCESS_TOKEN":"from config.json"}`),n.info(` sources ${i.join(", ")}`),n.info(""),n.info(n.dim("--reconnect to replace the token \xB7 --test to query the last 5 minutes"));return}if(n.info(""),n.info(n.bold("Connect Supabase logs")),!a||r.reconnect){if(!process.stdin.isTTY){n.info(""),n.info("Not an interactive shell. Set these and re-run:"),n.info(` export VERIRUN_SUPABASE_ACCESS_TOKEN=sbp_... ${n.dim(`(create at ${ve})`)}`),n.info(` ${n.dim("and supabase.projectRef in .verirun/config.json")}`);return}n.info(` Opening ${n.bold(ve)}`),n.info(' Click "Generate new token", copy it, come back here.'),L(ve),n.info("");let m=await b(" Paste the token: ");if(!m){n.warn(" Nothing pasted. No changes made.");return}m.startsWith("sbp_")||n.warn(" That does not look like a Supabase token (expected sbp_\u2026). Saving it anyway."),a=m}let c=await mt(r.reconnect?void 0:t.projectRef);if(!c){n.warn(" No project ref given. No changes made.");return}let l={projectRef:c};s||(l.accessToken=a),await V(o,{supabase:l}),n.info(""),n.info(` Saved to ${n.dim(o)}`),n.info(" Checking it works\u2026");let d=new Date,p={startedAt:new Date(d.getTime()-5*6e4).toISOString(),endedAt:d.toISOString()},f=await J(c,a,i[0],p);if("error"in f){n.error(` ${i[0]} query failed: ${f.error}`),n.info(n.dim(" Token or project ref looks wrong. Re-run `verirun log supabase --reconnect`.")),process.exitCode=1;return}n.success(` Connected. \`verirun run\` now includes Supabase logs (${i.join(", ")}).`)}function Je(e){return!!(e.deploymentId||e.projectId&&e.environmentId&&e.serviceId)}function wt(e){try{let r=new URL(e.trim());if(!/(^|\.)railway\.(com|app)$/.test(r.hostname))return;let o=r.pathname.match(/\/project\/([^/]+)\/service\/([^/?#]+)/),t=r.searchParams.get("environmentId");return!o||!o[1]||!o[2]||!t?void 0:{projectId:o[1],environmentId:t,serviceId:o[2]}}catch{return}}async function yt(e,r){if(!r)throw new Error("--test needs a token. Run `verirun log railway`, or set $VERIRUN_RAILWAY_TOKEN.");if(!Je(e))throw new Error("--test needs a connected deployment. Run `verirun log railway` first.");let o=await K({...e,token:r});if("error"in o)throw new Error(`Railway: ${o.error}`);let t=new Date,i={startedAt:new Date(t.getTime()-5*6e4).toISOString(),endedAt:t.toISOString()};n.info(""),n.info(`Querying deployment ${o.deploymentId} for the last 5 minutes\u2026`);let s=await fe(r,o.deploymentId,i);if("error"in s){n.error(`railway ${s.error}`),process.exitCode=1;return}n.success(`railway ${s.entries.length} row${s.entries.length===1?"":"s"}`)}async function vt(e,r){let{configPath:o}=w(),t=e.railway??{},i=process.env.VERIRUN_RAILWAY_TOKEN,s=i??t.token;if(r.test){await yt(t,s);return}if(s&&Je(t)&&!r.reconnect){n.info(""),n.info(n.bold("Railway logs \u2014 connected")),n.info(` token ${i?"from $VERIRUN_RAILWAY_TOKEN":"from config.json"}`),t.deploymentId?n.info(` deployment ${t.deploymentId} ${n.dim("(pinned)")}`):(n.info(` project ${t.projectId}`),n.info(` environment ${t.environmentId}`),n.info(` service ${t.serviceId} ${n.dim("(latest deployment resolved per run)")}`)),n.info(""),n.info(n.dim("--reconnect to change it \xB7 --test to query the last 5 minutes"));return}if(n.info(""),n.info(n.bold("Connect Railway logs \u2014 2 things:")),n.info(""),n.info(` 1. On the page opening now (${ue}):`),n.info(' "Create Token" \u2192 name it \u2192 pick your team \u2192 Create \u2192 copy the value.'),n.info(" 2. In Railway, open the service you want logs from. Copy its URL from the"),n.info(" address bar \u2014 looks like:"),n.info(" https://railway.com/project/PROJECT/service/SERVICE?environmentId=ENV"),!process.stdin.isTTY){n.info(""),n.info(n.dim("Then: VERIRUN_RAILWAY_TOKEN=<token>, and railway.projectId / environmentId / serviceId (from that URL) in .verirun/config.json."));return}if(!s||r.reconnect){L(ue),n.info("");let d=await b(" Railway token: ");if(!d){n.warn(" Nothing pasted. No changes made.");return}s=d}let a={};i||(a.token=s);let c=wt(await b(" Service URL (paste the whole thing): "));if(c)a.projectId=c.projectId,a.environmentId=c.environmentId,a.serviceId=c.serviceId;else{n.warn(" Couldn't read that URL. Enter the three IDs from it by hand:");let d=await b(" Project ID: "),p=await b(" Environment ID: "),f=await b(" Service ID: ");if(!d||!p||!f){n.warn(" Need all three. No changes made.");return}a.projectId=d,a.environmentId=p,a.serviceId=f}await V(o,{railway:a}),n.info(""),n.info(` Saved to ${n.dim(o)}`),n.info(" Checking it works\u2026");let l=await K({...t,...a,token:s});if("error"in l){n.error(` ${l.error}`),n.info(n.dim(" Re-run `verirun log railway --reconnect` with the right token / IDs.")),process.exitCode=1;return}n.success(` Connected. Deployment ${l.deploymentId}. \`verirun run\` now includes Railway logs.`)}import{existsSync as qe,readFileSync as Ye}from"node:fs";import{mkdir as bt,readdir as kt,writeFile as He}from"node:fs/promises";import E from"node:path";var St=new Set(["node_modules",".git",".next",".verirun","dist","build","out","coverage",".turbo",".vercel"]);async function $t(e){let r=[],o=async t=>{for(let i of await kt(t,{withFileTypes:!0})){if(i.name.startsWith(".")&&i.name!==".")continue;let s=E.join(t,i.name);if(i.isDirectory()){if(St.has(i.name))continue;await o(s)}else/\.tsx?$/.test(i.name)&&!i.name.endsWith(".d.ts")&&r.push({file:E.relative(e,s).split(E.sep).join("/"),source:Ye(s,"utf8")})}};return await o(e),r}function Rt(e){let r=E.join(e,"tsconfig.json");if(!qe(r))return{};try{let o=Ye(r,"utf8").replace(/\/\*[\s\S]*?\*\//g,"").replace(/(^|[^:])\/\/.*$/gm,"$1").replace(/,(\s*[}\]])/g,"$1"),t=JSON.parse(o),i={};for(let[s,a]of Object.entries(t.compilerOptions?.paths??{})){let c=a[0];!s.endsWith("/*")||!c?.endsWith("/*")||(i[s.slice(0,-1)]=c.slice(0,-2).replace(/^\.\//,""))}return i}catch{return{}}}function Ct(e,r){let o={...r};for(let t of e??[]){let[i,s]=t.split("=");i&&(o[i]=s??"")}return o}function Et(e,r){let o=e.nodes.pages.filter(i=>!i.inferred);n.info(`${n.bold(String(o.length))} pages \xB7 ${n.bold(String(e.nodes.leaves.length))} backend effects \xB7 ${n.bold(String(e.edges.length))} edges ${n.dim(`(${r.length} files)`)}`),n.info("");for(let i of e.nodes.pages){let s=e.edges.filter(d=>d.from===i.id),a=s.filter(d=>d.kind==="nav").length,c=s.filter(d=>d.kind==="effect").length,l=i.inferred?n.dim(" (inferred)"):"";n.info(` ${i.path}${l} ${n.dim(`\u2014 ${i.component}, ${i.elements.length} element(s), ${a} nav, ${c} effect`)}`)}let t=e.diagnostics;t.parseErrors.length>0&&n.warn(`${t.parseErrors.length} file(s) failed to parse`),t.unresolvedTargets.length>0&&(n.info(""),n.info(n.dim(`${t.unresolvedTargets.length} nav target(s) could not be resolved to a page`)))}async function ze(e){let{assertLicensed:r}=await import("./gate.mjs"),{assembleTree:o,bfs:t,buildCoverage:i,measureReach:s,renderBfs:a,renderMarkdown:c,renderReachTable:l}=await import("./graph.mjs"),d=await r();d.note&&n.warn(d.note);let p=w(),f=e.dir?E.resolve(e.dir):p.repoRoot;if(!qe(f))throw new Error(`no such directory: ${f}`);let m=await $t(f);if(m.length===0)throw new Error(`no .ts/.tsx files found under ${f}`);let y={aliases:Ct(e.alias,Rt(f)),...e.followChildren===!1?{followChildren:!1}:{},...e.appFile?{appFile:e.appFile}:{}};if(e.bfs){let u=o(m,y),v=e.kind==="nav"||e.kind==="effect"?[e.kind]:void 0,k=t(u,e.bfs,{depth:e.depth?Number(e.depth):2,...v?{kinds:v}:{}});n.info(n.dim(`${k.order.length-1} node(s) within ${k.maxDepth} step(s) of ${k.from}`)),n.info(a(k));return}if(e.reach){let u=s(m,y);n.info(l(u));for(let v of u.unreachedFiles)n.info(n.dim(`unreached: ${v.file} (${v.elements} elements)`));return}let g=o(m,y);if(e.json){process.stdout.write(`${JSON.stringify(g,null,2)}
24
- `);return}if(e.report){let u=e.out?E.resolve(e.out):E.join(p.dataDir,"map");await bt(u,{recursive:!0});let v=i(m,g);await He(E.join(u,"interaction-tree.json"),`${JSON.stringify(g,null,2)}
25
- `),await He(E.join(u,"coverage.md"),`${c(v,g)}
26
- `);let k=E.relative(process.cwd(),u),S=k.startsWith("..")?u:k;n.success(`wrote ${S}/interaction-tree.json + coverage.md`);let j=v.bar.filter(x=>x.pass===!1).length;n.info(n.dim(`${v.bar.length-j}/${v.bar.length} coverage checks pass`));return}Et(g,m)}import{existsSync as en}from"node:fs";import{mkdir as rn}from"node:fs/promises";import or from"node:path";import{spawnSync as It}from"node:child_process";var jt={browser:"chromium",channel:"chrome",label:"Chrome",approximated:!1},xt={browser:"chromium",channel:"msedge",label:"Edge",approximated:!1},At={browser:"firefox",label:"Firefox",approximated:!1},Lt={browser:"chromium",label:"Chromium",approximated:!1};function be(e,r){let o=e.toLowerCase(),t=i=>r?{...i,label:r}:i;if(o.includes("firefox")||o.includes("mozilla"))return t(At);if(o.includes("msedge")||o.includes("microsoft-edge")||o.includes("edgemac")||o.includes("microsoftedge"))return t(xt);if(o.includes("google-chrome")||o.includes("com.google.chrome")||o==="chromehtml"||o.includes("chrome"))return t(jt);if(o.includes("chromium"))return t(Lt);if(o.includes("safari"))return{browser:"webkit",label:"Safari",approximated:!0};if(o.includes("brave"))return{browser:"chromium",label:"Brave",approximated:!0};if(o.includes("thebrowser")||o.includes("arc"))return{browser:"chromium",label:"Arc",approximated:!0};if(o.includes("vivaldi"))return{browser:"chromium",label:"Vivaldi",approximated:!0};if(o.includes("opera")||o.includes("opr"))return{browser:"chromium",label:"Opera",approximated:!0}}function Z(e,r){let o=It(e,r,{encoding:"utf8",timeout:4e3});if(!(o.error||o.status!==0))return(o.stdout||"").trim()||void 0}function Nt(){let e=Z("xdg-settings",["get","default-web-browser"])??Z("xdg-mime",["query","default","x-scheme-handler/https"]);return e?be(e):void 0}function Tt(){let e=Z("plutil",["-convert","json","-o","-",`${process.env.HOME}/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist`]);if(e)try{let o=(JSON.parse(e).LSHandlers??[]).find(i=>i.LSHandlerURLScheme==="https"),t=typeof o?.LSHandlerRoleAll=="string"?o.LSHandlerRoleAll:void 0;return t?be(t):void 0}catch{return}}function Pt(){let r=Z("reg",["query","HKCU\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\https\\UserChoice","/v","ProgId"])?.match(/ProgId\s+REG_SZ\s+(\S+)/i)?.[1];return r?be(r):void 0}function Qe(){try{if(process.platform==="darwin")return Tt();if(process.platform==="linux")return Nt();if(process.platform==="win32")return Pt()}catch{}}import{spawn as _t}from"node:child_process";import{mkdtemp as Ot,readFile as Dt,rm as Vt}from"node:fs/promises";import{createRequire as Ut}from"node:module";import Mt from"node:os";import ee from"node:path";var Ft=new Set(["name","selector","locator","signals","pageGuid","ariaSnapshot"]);function Xe(e){let r={};for(let[o,t]of Object.entries(e))!Ft.has(o)&&t!==void 0&&(r[o]=t);return r}function Wt(){let e=Ut(import.meta.url),r=e.resolve("playwright/package.json"),o=e("playwright/package.json"),t=typeof o.bin=="string"?o.bin:o.bin?.playwright;if(!t)throw new Error("Could not locate the Playwright CLI entrypoint in playwright/package.json.");return ee.join(ee.dirname(r),t)}async function Ze(e){let r=Wt(),o=await Ot(ee.join(Mt.tmpdir(),"verirun-record-")),t=ee.join(o,"recording.jsonl"),i=[r,"codegen","--target=jsonl",`--output=${t}`];e.browser&&i.push(`--browser=${e.browser}`),e.channel&&i.push(`--channel=${e.channel}`),e.userDataDir&&i.push(`--user-data-dir=${e.userDataDir}`),e.testIdAttribute&&i.push(`--test-id-attribute=${e.testIdAttribute}`),e.url&&i.push(e.url);try{let s=await new Promise((c,l)=>{let d=_t(process.execPath,i,{stdio:["ignore","inherit","inherit"]});d.on("error",l),d.on("close",p=>c(p))}),a=await Dt(t,"utf8").catch(()=>"");return{...Bt(a),exitCode:s}}finally{await Vt(o,{recursive:!0,force:!0})}}function Bt(e){let r=e.split(`
27
- `).filter(i=>i.trim().length>0),o={},t=[];for(let[i,s]of r.entries()){let a;try{a=JSON.parse(s)}catch{continue}if(i===0&&a&&typeof a=="object"&&!("name"in a)){o=a;continue}a&&typeof a=="object"&&"name"in a&&t.push(a)}return{header:o,actions:t}}import{existsSync as Gt}from"node:fs";import{appendFile as Kt,readFile as Jt}from"node:fs/promises";import Ht from"node:path";function qt(e){return e.split(`
28
- `).map(r=>r.trim()).filter(r=>r&&!r.startsWith("#")).some(r=>r.replace(/^\//,"").replace(/\/$/,"")===B)}async function er(e){let r=Ht.join(e,".gitignore");if(!Gt(r))return"no-gitignore";let o=await Jt(r,"utf8");if(qt(o))return"already-present";let t=o.length===0||o.endsWith(`
21
+ }`,{id:r,start:o.startedAt,end:o.endedAt,filter:s});return"error"in c?c:{entries:Array.isArray(c.data.deploymentLogs)?c.data.deploymentLogs:[]}}function Hr(e){let r=typeof e.severity=="string"?e.severity:void 0;return{source:"railway",stream:r?r.toLowerCase():"deploy",timestamp:typeof e.timestamp=="string"?e.timestamp:void 0,level:r,message:typeof e.message=="string"?e.message:void 0,raw:e}}var fe=class{id="railway";name="Railway";cfg;constructor(r){this.cfg=r}async start(){if(!this.cfg.token)throw new Error("Railway log capture needs an API token. Set VERIRUN_RAILWAY_TOKEN or railway.token in .verirun/config.json.");if(!this.cfg.deploymentId&&!(this.cfg.projectId&&this.cfg.environmentId&&this.cfg.serviceId))throw new Error("Railway log capture needs railway.deploymentId, or railway.projectId + railway.environmentId + railway.serviceId, in .verirun/config.json.")}async collect(r,o){let t=await G(this.cfg);if("error"in t)return n.warn(`Railway: ${t.error}`),[];let i=await me(this.cfg.token,t.deploymentId,o,{userNeedle:r.userFilter});if("error"in i)return n.warn(`Railway: ${i.error}`),[];let s=i.entries.map(Hr);return s.sort((a,c)=>(a.timestamp??"").localeCompare(c.timestamp??"")),s}async dispose(){}};function Ue(e){return e.railway?new fe(e.railway):void 0}var qr="https://api.supabase.com",he=["postgres_logs","edge_logs","auth_logs"],ge=class{id="supabase";name="Supabase";projectRef;accessToken;sources;constructor(r){this.projectRef=r.projectRef,this.accessToken=r.accessToken,this.sources=r.sources&&r.sources.length>0?r.sources:he}async start(){if(!this.projectRef)throw new Error("Supabase log capture needs supabase.projectRef in .verirun/config.json.");if(!this.accessToken)throw new Error("Supabase log capture needs an access token. Set VERIRUN_SUPABASE_ACCESS_TOKEN or supabase.accessToken in .verirun/config.json.")}async collect(r,o){let t=r.userFilter,i=[],s=!1;for(let a of this.sources){let c=await K(this.projectRef,this.accessToken,a,o,{userNeedle:t});if("error"in c){n.warn(`Supabase ${a}: ${c.error}`);continue}t&&!c.serverFiltered&&(s=!0);for(let l of c.rows)i.push(zr(a,l))}return t&&s&&n.info(n.dim("Supabase: user filter applied client-side for a source (more rows pulled).")),i.sort((a,c)=>(a.timestamp??"").localeCompare(c.timestamp??"")),i}async dispose(){}},Yr=/^[A-Za-z0-9._@%+-]{1,256}$/;async function Fe(e,r,o,t){let i=new URL(`/v1/projects/${e}/analytics/endpoints/logs.all`,qr);i.searchParams.set("sql",o),i.searchParams.set("iso_timestamp_start",t.startedAt),i.searchParams.set("iso_timestamp_end",t.endedAt);let s;try{s=await fetch(i,{headers:{Authorization:`Bearer ${r}`,Accept:"application/json"}})}catch(c){return{error:c instanceof Error?c.message:String(c)}}let a=await s.json().catch(()=>{});if(!s.ok){let c=(typeof a?.error=="string"?a.error:a?.error?.message)??a?.message??`HTTP ${s.status}`;return{error:`${c}${c.startsWith("HTTP")?"":` (HTTP ${s.status})`}`}}return{rows:Array.isArray(a?.result)?a.result:[]}}async function K(e,r,o,t,i={}){let s=i.userNeedle?.trim().toLowerCase(),a=s&&Yr.test(s)?s:void 0,c=p=>{let f=p&&a?` where strpos(lower(event_message), '${a}') > 0 or strpos(lower(to_json_string(metadata)), '${a}') > 0`:"";return`select id, timestamp, event_message, metadata from ${o}${f} order by timestamp asc limit 1000`},l=await Fe(e,r,c(!0),t);if(!("error"in l))return{rows:l.rows,serverFiltered:!!a};if(!a)return l;let d=await Fe(e,r,c(!1),t);return"error"in d?d:{rows:d.rows,serverFiltered:!1}}function zr(e,r){return{source:"supabase",stream:e,timestamp:Qr(r.timestamp),message:typeof r.event_message=="string"?r.event_message:void 0,raw:r}}function Qr(e){if(typeof e=="string")return e;if(typeof e=="number"&&Number.isFinite(e)){let r=e>1e14?e/1e3:e;return new Date(r).toISOString()}}function Me(e){return e.supabase?new ge(e.supabase):void 0}import{createHmac as rt,timingSafeEqual as tt}from"node:crypto";import{createServer as nt}from"node:http";import{setTimeout as ot}from"node:timers/promises";var We="https://api.vercel.com",H="https://vercel.com/account/settings/tokens",Xr=8e3,Zr=1500,et=3e3;function we(e){return e?`&teamId=${encodeURIComponent(e)}`:""}async function ye(e,r){let o;try{o=await fetch(`${We}${e}`,{headers:{Authorization:`Bearer ${r}`,Accept:"application/json"}})}catch(i){return{error:i instanceof Error?i.message:String(i)}}let t=await o.json().catch(()=>{});return o.ok?{data:t}:{error:t?.error?.message??`HTTP ${o.status}`}}async function Be(e,r){let o=await ye(`/v9/projects?limit=100${we(r)}`,e);return"error"in o?o:{projects:o.data.projects??[]}}async function Ge(e){let r=await ye("/v2/teams?limit=100",e);return"error"in r?r:{teams:r.data.teams??[]}}async function q(e){if(e.deploymentId)return{deploymentId:e.deploymentId,label:e.deploymentId};if(!e.token)return{error:"no token"};if(!e.projectId)return{error:"no projectId"};let r=e.environment??"production",o=await ye(`/v6/deployments?projectId=${encodeURIComponent(e.projectId)}&limit=1&state=READY&target=${encodeURIComponent(r)}${we(e.teamId)}`,e.token);if("error"in o)return{error:o.error};let t=o.data.deployments?.[0];return t?{deploymentId:t.uid,label:t.url??t.uid}:{error:`no READY ${r} deployment found for this project`}}async function Y(e,r,o){let t=`/v1/projects/${encodeURIComponent(e.projectId)}/deployments/${encodeURIComponent(r)}/runtime-logs?limit=1000${we(e.teamId)}`,i=new AbortController,s=setTimeout(()=>i.abort(),o),a,c=()=>{a&&clearTimeout(a),a=setTimeout(()=>i.abort(),Zr)},l=[];try{let d=await fetch(`${We}${t}`,{headers:{Authorization:`Bearer ${e.token}`,Accept:"application/x-ndjson, application/json"},signal:i.signal});if(!d.ok)return{error:(await d.json().catch(()=>{}))?.error?.message??`HTTP ${d.status}`};if(!d.body)return{rows:l};c();let p=new TextDecoder,f="";for await(let m of d.body){f+=p.decode(m,{stream:!0});let h=f.split(`
22
+ `);f=h.pop()??"";for(let y of h){let g=y.trim();if(g)try{let u=JSON.parse(g);Array.isArray(u)?l.push(...u):l.push(u)}catch{}}c()}}catch(d){if(!(d instanceof Error&&d.name==="AbortError"))return{error:d instanceof Error?d.message:String(d)}}finally{clearTimeout(s),a&&clearTimeout(a)}return{rows:l}}function ve(e){let r=e.requestPath?` ${e.requestMethod??""} ${e.requestPath}`.trim():"",o=e.responseStatusCode?` (${e.responseStatusCode})`:"";return{source:"vercel",...e.source?{stream:e.source}:{},...e.timestampInMs?{timestamp:new Date(e.timestampInMs).toISOString()}:{},...e.level?{level:e.level}:{},message:e.message??`${r}${o}`.trim(),raw:e}}var J=class{id="vercel";name="Vercel";config;constructor(r){this.config=r}async start(){if(!this.config.token)throw new Error("Vercel log capture needs an API token. Run `verirun log vercel`, or set VERIRUN_VERCEL_TOKEN / vercel.token in .verirun/config.json.");if(!this.config.projectId)throw new Error("Vercel log capture needs vercel.projectId. Run `verirun log vercel`.")}async collect(r,o){let t=await q(this.config);if("error"in t)return n.warn(`Vercel: ${t.error}`),[];let i=await Y(this.config,t.deploymentId,this.config.readMs??Xr);if("error"in i)return n.warn(`Vercel: ${i.error}`),[];let s=Date.parse(o.startedAt),a=Date.parse(o.endedAt)+(this.config.tailGraceMs??et);return i.rows.filter(c=>typeof c.timestampInMs!="number"?!0:c.timestampInMs>=s&&c.timestampInMs<=a).map(ve)}async dispose(){}};var z=4319,Q="/drain",be=3e3,V=class{id="vercel";name="Vercel";port;path;secret;graceMs;project;onEntry;server;received=[];droppedByProject=0;constructor(r,o={}){this.port=r.listenerPort??z,this.path=r.listenerPath??Q,this.secret=r.drainSecret,this.graceMs=r.drainGraceMs??be,this.project=r.project?.trim()||void 0,this.onEntry=o.onEntry}projectMatches(r){return this.project?r.projectId===this.project||r.projectName===this.project:!0}async start(){let r=nt((o,t)=>this.handle(o,t));this.server=r,await new Promise((o,t)=>{let i=s=>{t(s.code==="EADDRINUSE"?new Error(`Vercel log listener: port ${this.port} is already in use.`):s)};r.once("error",i),r.listen(this.port,()=>{r.off("error",i),o()})}),n.step(`Vercel log listener on http://localhost:${this.port}${this.path}`)}async collect(){return this.graceMs>0&&await ot(this.graceMs),this.received.length===0&&this.droppedByProject>0&&n.warn(`Vercel: ${this.droppedByProject} log line(s) arrived but none matched project "${this.project}". Check the name/ID in .verirun/config.json (vercel.project).`),[...this.received]}async dispose(){let r=this.server;r&&(this.server=void 0,await new Promise(o=>r.close(()=>o())))}handle(r,o){let t=r.headers["x-vercel-verify"];if(typeof t=="string"&&o.setHeader("x-vercel-verify",t),r.method!=="POST"||!this.matchesPath(r.url)){o.statusCode=r.method==="POST"?404:200,o.end();return}let i=[];r.on("data",s=>i.push(s)),r.on("error",()=>{o.statusCode=400,o.end()}),r.on("end",()=>{let s=Buffer.concat(i);if(!this.verifySignature(r,s)){n.warn("Vercel log drain: rejected a delivery with a bad signature."),o.statusCode=401,o.end();return}try{for(let a of it(s.toString("utf8"))){if(!this.projectMatches(a)){this.droppedByProject+=1;continue}let c=st(a);this.received.push(c),this.onEntry?.(c)}}catch{n.warn("Vercel log drain: could not parse a delivery body.")}o.statusCode=200,o.end()})}matchesPath(r){return r?(r.split("?")[0]??"")===this.path:!1}verifySignature(r,o){if(!this.secret)return!0;let t=r.headers["x-vercel-signature"];if(typeof t!="string")return!1;let i=rt("sha1",this.secret).update(o).digest("hex"),s=Buffer.from(i),a=Buffer.from(t);return s.length===a.length&&tt(s,a)}};function it(e){let r=e.trim();if(!r)return[];if(r.startsWith("[")){let o=JSON.parse(r);return Array.isArray(o)?o:[]}return r.split(`
23
+ `).map(o=>o.trim()).filter(Boolean).map(o=>JSON.parse(o))}function st(e){return{source:"vercel",stream:typeof e.source=="string"?e.source:void 0,timestamp:typeof e.timestamp=="number"?new Date(e.timestamp).toISOString():void 0,level:typeof e.level=="string"?e.level:void 0,message:typeof e.message=="string"?e.message:void 0,raw:e}}function Ke(e){if(e.vercel)return e.vercel.token?new J(e.vercel):new V(e.vercel)}var Je=["vercel","supabase","railway"];async function He(e,r){if(e!==void 0&&!Je.includes(e))throw new Error(`Unknown log source "${e}". Use one of: ${Je.join(", ")}.`);let o=w(),t=await A(o.configPath);if(e===void 0){ft(t);return}if(e==="vercel"){await wt(t,r);return}if(e==="railway"){await Et(t,r);return}await kt(t,r)}function ft(e){let r=e.vercel,o=e.supabase,t=e.railway;n.info(""),n.info(n.bold("Log sources")),n.info(""),n.info(` ${"vercel".padEnd(10)} ${r?.token&&r.projectId?`configured project ${r.projectId}`:r?`drain mode listener :${r.listenerPort??z}${r.listenerPath??Q}`:n.dim("not configured")}`),n.info(` ${"supabase".padEnd(10)} ${o?`configured project ${o.projectRef??n.dim("(no projectRef)")}`:n.dim("not configured")}`),n.info(` ${"railway".padEnd(10)} ${t?`configured ${t.deploymentId?`deployment ${t.deploymentId}`:`service ${t.serviceId??n.dim("(none)")}`}`:n.dim("not configured")}`),n.info(""),n.info(`Run ${n.bold("verirun log vercel")}, ${n.bold("verirun log supabase")} or ${n.bold("verirun log railway")} to connect one.`)}var pt="https://vercel.com/d?to=%2F%5Bteam%5D%2F~%2Fsettings%2Flog-drains&title=Log%20Drains";function mt(e){let r=dt.join(e,".vercel","project.json");if(ct(r))try{let o=JSON.parse(lt(r,"utf8"));return o.projectId?{projectId:o.projectId,...o.orgId?.startsWith("team_")?{teamId:o.orgId}:{}}:void 0}catch{return}}async function gt(e){let r=await Ge(e),o;if("error"in r)n.warn(` Could not list teams: ${r.error}`);else if(r.teams.length===1)o=r.teams[0].id,n.info(` team ${r.teams[0].name??o}`);else if(r.teams.length>1){n.info(" Which team?"),n.info(` 1. ${n.dim("(personal account)")}`),r.teams.forEach((c,l)=>n.info(` ${l+2}. ${c.name??c.slug??c.id}`));let a=Number.parseInt(await b(" Number: "),10)-2;r.teams[a]&&(o=r.teams[a].id)}let t=await Be(e,o);if("error"in t){n.error(` Could not list projects: ${t.error}`);return}if(t.projects.length===0){n.warn(" That token can see no projects.");return}if(t.projects.length===1){let a=t.projects[0];return n.info(` project ${a.name} (${a.id})`),{projectId:a.id,...o?{teamId:o}:{}}}n.info(" Which project?"),t.projects.forEach((a,c)=>n.info(` ${c+1}. ${a.name}`));let i=Number.parseInt(await b(" Number: "),10)-1,s=t.projects[i];if(!s){n.warn(" Not one of the choices.");return}return{projectId:s.id,...o?{teamId:o}:{}}}async function ht(e){if(!e.token||!e.projectId)throw new Error("--test needs a connected project. Run `verirun log vercel` first.");let r=await q(e);if("error"in r){n.error(` ${r.error}`),process.exitCode=1;return}n.info(""),n.info(`Reading runtime logs for ${n.bold(r.label)}\u2026`);let o=await Y(e,r.deploymentId,e.readMs??8e3);if("error"in o){n.error(` ${o.error}`),process.exitCode=1;return}let t=Date.now()-5*6e4,i=o.rows.filter(s=>typeof s.timestampInMs!="number"||s.timestampInMs>=t);n.success(` ${o.rows.length} line(s) on the stream, ${i.length} from the last 5 minutes.`);for(let s of i.slice(-5)){let a=ve(s);n.info(` ${n.dim(a.timestamp??"")} ${a.message??""}`)}o.rows.length===0&&n.info(n.dim(" No lines yet \u2014 hit the deployed app once, then re-run with --test."))}async function wt(e,r){let{configPath:o,repoRoot:t}=w(),i=e.vercel??{},s=process.env.VERIRUN_VERCEL_TOKEN;if(r.drain||r.listen){await yt(e,r);return}if(r.test){await ht(i);return}if(i.token&&i.projectId&&!r.reconnect){n.info(""),n.info(n.bold("Vercel logs \u2014 connected")),n.info(` project ${i.projectId}`),i.teamId&&n.info(` team ${i.teamId}`),n.info(` token ${s?"from $VERIRUN_VERCEL_TOKEN":"from config.json"}`),n.info(` deployment ${i.deploymentId??n.dim(`newest ready ${i.environment??"production"}`)}`),n.info(""),n.info(n.dim("--reconnect to replace it \xB7 --test to read the last 5 minutes"));return}n.info(""),n.info(n.bold("Connect Vercel logs"));let a=s??i.token;if(!a||r.reconnect){if(!process.stdin.isTTY){n.info(""),n.info("Not an interactive shell. Set these and re-run:"),n.info(` export VERIRUN_VERCEL_TOKEN=... ${n.dim(`(create at ${H})`)}`),n.info(` ${n.dim("and vercel.projectId (+ vercel.teamId) in .verirun/config.json")}`);return}n.info(` Opening ${n.bold(H)}`),n.info(" Create a token, copy it, come back here."),L(H),n.info("");let h=await b(" Paste the token: ");if(!h){n.warn(" Nothing pasted. No changes made.");return}a=h}let c=r.reconnect?void 0:mt(t);c&&n.info(` project ${c.projectId} ${n.dim("\u2014 from .vercel/project.json")}`);let l=c??await gt(a);if(!l){n.warn(" No project chosen. No changes made.");return}let d={projectId:l.projectId,...l.teamId?{teamId:l.teamId}:{}};s||(d.token=a),await X(o,{vercel:d}),n.info(""),n.info(` Saved to ${n.dim(o)}`),n.info(" Checking it works\u2026");let p={...i,...d,token:a},f=await q(p);if("error"in f){n.error(` ${f.error}`),n.info(n.dim(" Token or project looks wrong. Re-run `verirun log vercel --reconnect`.")),process.exitCode=1;return}let m=await Y(p,f.deploymentId,4e3);if("error"in m){n.error(` Reading logs failed: ${m.error}`),n.info(n.dim(" The token may lack access to this project. Re-run with --reconnect.")),process.exitCode=1;return}n.success(` Connected to ${f.label}. \`verirun run\` now includes Vercel logs.`),m.rows.length===0&&n.info(n.dim(" (No log lines in the stream right now \u2014 that is normal for an idle app.)"))}async function yt(e,r){let{configPath:o}=w(),t=e.vercel??{},i=t.listenerPort??z,s=t.listenerPath??Q,a=t.drainGraceMs??be;if(r.listen){await vt({...t,listenerPort:i,listenerPath:s});return}let c=process.env.VERIRUN_VERCEL_DRAIN_SECRET;if((t.drainSecret||c)&&!r.reconnect){n.info(""),n.info(n.bold("Vercel logs \u2014 drain mode")),n.info(` endpoint http://localhost:${i}${s}`),n.info(` drain secret ${c?"from $VERIRUN_VERCEL_DRAIN_SECRET":"from config.json"}`),n.info(` grace ${a}ms`),n.info(` project ${t.project??n.dim("all projects on the drain")}`),n.info(""),n.info(n.dim("--reconnect to change it \xB7 --listen to run the verification listener")),n.info(n.dim("`verirun log vercel` (no --drain) switches to the simpler API mode"));return}if(n.info(""),n.info(n.bold("Connect Vercel logs the old way (drain) \u2014 do these in order:")),n.info(n.dim(" You probably want `verirun log vercel` instead: a token, no tunnel.")),n.info(""),n.info(" 1. New terminal. Start a tunnel to port "+i+" and copy the https URL it prints:"),n.info(` ${n.bold(`ngrok http ${i}`)}`),n.info(n.dim(` (or: cloudflared tunnel --url http://localhost:${i})`)),n.info(""),n.info(" 2. Another new terminal. Start the listener and leave it running:"),n.info(` ${n.bold("verirun log vercel --listen")}`),n.info(""),n.info(" 3. Vercel page opening now (your team \u2192 Settings \u2192 Log Drains) \u2192 Add a drain:"),n.info(" Sources ......... check "+n.bold("Edge")+" and "+n.bold("Serverless")+", uncheck the rest"),n.info(" Delivery format . "+n.bold("JSON")),n.info(` Endpoint ........ ${n.bold(`<https URL from step 1>${s}`)}`),n.info(" then Save."),n.info(""),n.info(" 4. Vercel shows a Signing Secret. Copy it, paste it below."),!process.stdin.isTTY){n.info(""),n.info(n.dim(" Then: VERIRUN_VERCEL_DRAIN_SECRET=<secret> (or vercel.drainSecret in .verirun/config.json)"));return}L(pt),n.info("");let l=await b(" Signing secret: ");if(!l){n.warn(" No secret. Deliveries would NOT be verified \u2014 anyone who finds the tunnel URL"),n.warn(" could feed fake logs into your runs.");let f=(await b(" Save without a secret anyway? [y/N]: ")).toLowerCase();if(f!=="y"&&f!=="yes"){n.info(" Nothing saved. Re-run `verirun log vercel --drain` once you have the secret.");return}l=""}let d=await b(" Only one project's logs? Paste its name or prj_\u2026 ID, or press Enter for all: "),p={};l&&(p.drainSecret=l),d&&(p.project=d),await X(o,{vercel:p}),n.info(""),n.info(` Saved to ${n.dim(o)}`),n.success(" Done. `verirun run` starts its own listener \u2014 you only need --listen for tailing.")}async function vt(e){let r=new V(e,{onEntry:o=>{let t=o.timestamp??new Date().toISOString(),i=(o.level??"log").padEnd(5),s=o.stream?`${o.stream} `:"";n.info(`${n.dim(t)} ${i} ${n.dim(s)}${o.message??""}`)}});await r.start(),e.project&&n.info(n.dim(`Filtering to project "${e.project}".`)),n.info(n.dim("Waiting for deliveries. Press Ctrl+C to stop.")),n.info(""),await new Promise(o=>{let t=()=>{process.off("SIGINT",t),process.off("SIGTERM",t),n.info(""),r.dispose().then(o)};process.on("SIGINT",t),process.on("SIGTERM",t)}),n.step("Listener stopped.")}var Se="https://supabase.com/dashboard/account/tokens";async function b(e){if(!process.stdin.isTTY)return"";let r=ut({input:process.stdin,output:process.stdout});try{return(await r.question(e)).trim()}finally{r.close()}}async function X(e,r){await Ae(e,r)||n.warn(`Could not restrict ${e} to your account. It holds an API token \u2014 check its permissions.`)}function bt(){let e=at("supabase",["projects","list","--output","json"],{encoding:"utf8",shell:process.platform==="win32"});if(!(e.error||e.status!==0))try{let o=JSON.parse(e.stdout).map(t=>({ref:String(t.id??t.ref??t.reference_id??""),name:String(t.name??"")})).filter(t=>t.ref!=="");return o.length>0?o:void 0}catch{return}}async function St(e){if(e)return e;let r=bt();if(r&&r.length===1){let t=r[0];return n.info(` project ${t.name} (${t.ref}) ${n.dim("\u2014 from the supabase CLI")}`),t.ref}if(r&&r.length>1){n.info(" Which project?"),r.forEach((i,s)=>n.info(` ${s+1}. ${i.name} (${i.ref})`));let t=Number.parseInt(await b(" Number: "),10)-1;if(r[t])return r[t].ref;n.warn(" Not one of the choices.")}return await b(" Project ref (the <ref> in dashboard/project/<ref>): ")||void 0}async function $t(e,r,o){if(!e.projectRef)throw new Error("--test needs a connected project. Run `verirun log supabase` first.");if(!o)throw new Error("--test needs an access token. Run `verirun log supabase`, or set $VERIRUN_SUPABASE_ACCESS_TOKEN.");let t=new Date,i={startedAt:new Date(t.getTime()-5*6e4).toISOString(),endedAt:t.toISOString()};n.info(""),n.info(`Querying ${r.length} source${r.length===1?"":"s"} for the last 5 minutes\u2026`),n.info("");let s=!1;for(let a of r){let c=await K(e.projectRef,o,a,i);"error"in c?(s=!0,n.error(`${a.padEnd(16)} ${c.error}`)):n.success(`${a.padEnd(16)} ${c.rows.length} row${c.rows.length===1?"":"s"}`)}s&&(process.exitCode=1)}async function kt(e,r){let{configPath:o}=w(),t=e.supabase??{},i=t.sources&&t.sources.length>0?t.sources:he,s=process.env.VERIRUN_SUPABASE_ACCESS_TOKEN,a=s??t.accessToken;if(r.test){await $t(t,i,a);return}if(t.projectRef&&a&&!r.reconnect){n.info(""),n.info(n.bold("Supabase logs \u2014 connected")),n.info(` project ${t.projectRef}`),n.info(` token ${s?"from $VERIRUN_SUPABASE_ACCESS_TOKEN":"from config.json"}`),n.info(` sources ${i.join(", ")}`),n.info(""),n.info(n.dim("--reconnect to replace the token \xB7 --test to query the last 5 minutes"));return}if(n.info(""),n.info(n.bold("Connect Supabase logs")),!a||r.reconnect){if(!process.stdin.isTTY){n.info(""),n.info("Not an interactive shell. Set these and re-run:"),n.info(` export VERIRUN_SUPABASE_ACCESS_TOKEN=sbp_... ${n.dim(`(create at ${Se})`)}`),n.info(` ${n.dim("and supabase.projectRef in .verirun/config.json")}`);return}n.info(` Opening ${n.bold(Se)}`),n.info(' Click "Generate new token", copy it, come back here.'),L(Se),n.info("");let m=await b(" Paste the token: ");if(!m){n.warn(" Nothing pasted. No changes made.");return}m.startsWith("sbp_")||n.warn(" That does not look like a Supabase token (expected sbp_\u2026). Saving it anyway."),a=m}let c=await St(r.reconnect?void 0:t.projectRef);if(!c){n.warn(" No project ref given. No changes made.");return}let l={projectRef:c};s||(l.accessToken=a),await X(o,{supabase:l}),n.info(""),n.info(` Saved to ${n.dim(o)}`),n.info(" Checking it works\u2026");let d=new Date,p={startedAt:new Date(d.getTime()-5*6e4).toISOString(),endedAt:d.toISOString()},f=await K(c,a,i[0],p);if("error"in f){n.error(` ${i[0]} query failed: ${f.error}`),n.info(n.dim(" Token or project ref looks wrong. Re-run `verirun log supabase --reconnect`.")),process.exitCode=1;return}n.success(` Connected. \`verirun run\` now includes Supabase logs (${i.join(", ")}).`)}function qe(e){return!!(e.deploymentId||e.projectId&&e.environmentId&&e.serviceId)}function Rt(e){try{let r=new URL(e.trim());if(!/(^|\.)railway\.(com|app)$/.test(r.hostname))return;let o=r.pathname.match(/\/project\/([^/]+)\/service\/([^/?#]+)/),t=r.searchParams.get("environmentId");return!o||!o[1]||!o[2]||!t?void 0:{projectId:o[1],environmentId:t,serviceId:o[2]}}catch{return}}async function Ct(e,r){if(!r)throw new Error("--test needs a token. Run `verirun log railway`, or set $VERIRUN_RAILWAY_TOKEN.");if(!qe(e))throw new Error("--test needs a connected deployment. Run `verirun log railway` first.");let o=await G({...e,token:r});if("error"in o)throw new Error(`Railway: ${o.error}`);let t=new Date,i={startedAt:new Date(t.getTime()-5*6e4).toISOString(),endedAt:t.toISOString()};n.info(""),n.info(`Querying deployment ${o.deploymentId} for the last 5 minutes\u2026`);let s=await me(r,o.deploymentId,i);if("error"in s){n.error(`railway ${s.error}`),process.exitCode=1;return}n.success(`railway ${s.entries.length} row${s.entries.length===1?"":"s"}`)}async function Et(e,r){let{configPath:o}=w(),t=e.railway??{},i=process.env.VERIRUN_RAILWAY_TOKEN,s=i??t.token;if(r.test){await Ct(t,s);return}if(s&&qe(t)&&!r.reconnect){n.info(""),n.info(n.bold("Railway logs \u2014 connected")),n.info(` token ${i?"from $VERIRUN_RAILWAY_TOKEN":"from config.json"}`),t.deploymentId?n.info(` deployment ${t.deploymentId} ${n.dim("(pinned)")}`):(n.info(` project ${t.projectId}`),n.info(` environment ${t.environmentId}`),n.info(` service ${t.serviceId} ${n.dim("(latest deployment resolved per run)")}`)),n.info(""),n.info(n.dim("--reconnect to change it \xB7 --test to query the last 5 minutes"));return}if(n.info(""),n.info(n.bold("Connect Railway logs \u2014 2 things:")),n.info(""),n.info(` 1. On the page opening now (${pe}):`),n.info(' "Create Token" \u2192 name it \u2192 pick your team \u2192 Create \u2192 copy the value.'),n.info(" 2. In Railway, open the service you want logs from. Copy its URL from the"),n.info(" address bar \u2014 looks like:"),n.info(" https://railway.com/project/PROJECT/service/SERVICE?environmentId=ENV"),!process.stdin.isTTY){n.info(""),n.info(n.dim("Then: VERIRUN_RAILWAY_TOKEN=<token>, and railway.projectId / environmentId / serviceId (from that URL) in .verirun/config.json."));return}if(!s||r.reconnect){L(pe),n.info("");let d=await b(" Railway token: ");if(!d){n.warn(" Nothing pasted. No changes made.");return}s=d}let a={};i||(a.token=s);let c=Rt(await b(" Service URL (paste the whole thing): "));if(c)a.projectId=c.projectId,a.environmentId=c.environmentId,a.serviceId=c.serviceId;else{n.warn(" Couldn't read that URL. Enter the three IDs from it by hand:");let d=await b(" Project ID: "),p=await b(" Environment ID: "),f=await b(" Service ID: ");if(!d||!p||!f){n.warn(" Need all three. No changes made.");return}a.projectId=d,a.environmentId=p,a.serviceId=f}await X(o,{railway:a}),n.info(""),n.info(` Saved to ${n.dim(o)}`),n.info(" Checking it works\u2026");let l=await G({...t,...a,token:s});if("error"in l){n.error(` ${l.error}`),n.info(n.dim(" Re-run `verirun log railway --reconnect` with the right token / IDs.")),process.exitCode=1;return}n.success(` Connected. Deployment ${l.deploymentId}. \`verirun run\` now includes Railway logs.`)}import{existsSync as ze,readFileSync as Qe}from"node:fs";import{mkdir as It,readdir as jt,writeFile as Ye}from"node:fs/promises";import E from"node:path";var xt=new Set(["node_modules",".git",".next",".verirun","dist","build","out","coverage",".turbo",".vercel"]);async function At(e){let r=[],o=async t=>{for(let i of await jt(t,{withFileTypes:!0})){if(i.name.startsWith(".")&&i.name!==".")continue;let s=E.join(t,i.name);if(i.isDirectory()){if(xt.has(i.name))continue;await o(s)}else/\.tsx?$/.test(i.name)&&!i.name.endsWith(".d.ts")&&r.push({file:E.relative(e,s).split(E.sep).join("/"),source:Qe(s,"utf8")})}};return await o(e),r}function Lt(e){let r=E.join(e,"tsconfig.json");if(!ze(r))return{};try{let o=Qe(r,"utf8").replace(/\/\*[\s\S]*?\*\//g,"").replace(/(^|[^:])\/\/.*$/gm,"$1").replace(/,(\s*[}\]])/g,"$1"),t=JSON.parse(o),i={};for(let[s,a]of Object.entries(t.compilerOptions?.paths??{})){let c=a[0];!s.endsWith("/*")||!c?.endsWith("/*")||(i[s.slice(0,-1)]=c.slice(0,-2).replace(/^\.\//,""))}return i}catch{return{}}}function Nt(e,r){let o={...r};for(let t of e??[]){let[i,s]=t.split("=");i&&(o[i]=s??"")}return o}function Tt(e,r){let o=e.nodes.pages.filter(i=>!i.inferred);n.info(`${n.bold(String(o.length))} pages \xB7 ${n.bold(String(e.nodes.leaves.length))} backend effects \xB7 ${n.bold(String(e.edges.length))} edges ${n.dim(`(${r.length} files)`)}`),n.info("");for(let i of e.nodes.pages){let s=e.edges.filter(d=>d.from===i.id),a=s.filter(d=>d.kind==="nav").length,c=s.filter(d=>d.kind==="effect").length,l=i.inferred?n.dim(" (inferred)"):"";n.info(` ${i.path}${l} ${n.dim(`\u2014 ${i.component}, ${i.elements.length} element(s), ${a} nav, ${c} effect`)}`)}let t=e.diagnostics;t.parseErrors.length>0&&n.warn(`${t.parseErrors.length} file(s) failed to parse`),t.unresolvedTargets.length>0&&(n.info(""),n.info(n.dim(`${t.unresolvedTargets.length} nav target(s) could not be resolved to a page`)))}async function Xe(e){let{assertLicensed:r}=await import("./gate.mjs"),{assembleTree:o,bfs:t,buildCoverage:i,measureReach:s,renderBfs:a,renderMarkdown:c,renderReachTable:l}=await import("./graph.mjs"),d=await r();d.note&&n.warn(d.note);let p=w(),f=e.dir?E.resolve(e.dir):p.repoRoot;if(!ze(f))throw new Error(`no such directory: ${f}`);let m=await At(f);if(m.length===0)throw new Error(`no .ts/.tsx files found under ${f}`);let y={aliases:Nt(e.alias,Lt(f)),...e.followChildren===!1?{followChildren:!1}:{},...e.appFile?{appFile:e.appFile}:{}};if(e.bfs){let u=o(m,y),v=e.kind==="nav"||e.kind==="effect"?[e.kind]:void 0,S=t(u,e.bfs,{depth:e.depth?Number(e.depth):2,...v?{kinds:v}:{}});n.info(n.dim(`${S.order.length-1} node(s) within ${S.maxDepth} step(s) of ${S.from}`)),n.info(a(S));return}if(e.reach){let u=s(m,y);n.info(l(u));for(let v of u.unreachedFiles)n.info(n.dim(`unreached: ${v.file} (${v.elements} elements)`));return}let g=o(m,y);if(e.json){process.stdout.write(`${JSON.stringify(g,null,2)}
24
+ `);return}if(e.report){let u=e.out?E.resolve(e.out):E.join(p.dataDir,"map");await It(u,{recursive:!0});let v=i(m,g);await Ye(E.join(u,"interaction-tree.json"),`${JSON.stringify(g,null,2)}
25
+ `),await Ye(E.join(u,"coverage.md"),`${c(v,g)}
26
+ `);let S=E.relative(process.cwd(),u),$=S.startsWith("..")?u:S;n.success(`wrote ${$}/interaction-tree.json + coverage.md`);let j=v.bar.filter(x=>x.pass===!1).length;n.info(n.dim(`${v.bar.length-j}/${v.bar.length} coverage checks pass`));return}Tt(g,m)}import{existsSync as ln}from"node:fs";import{mkdir as dn}from"node:fs/promises";import sr from"node:path";import{spawnSync as Pt}from"node:child_process";var Ot={browser:"chromium",channel:"chrome",label:"Chrome",approximated:!1},_t={browser:"chromium",channel:"msedge",label:"Edge",approximated:!1},Dt={browser:"firefox",label:"Firefox",approximated:!1},Vt={browser:"chromium",label:"Chromium",approximated:!1};function $e(e,r){let o=e.toLowerCase(),t=i=>r?{...i,label:r}:i;if(o.includes("firefox")||o.includes("mozilla"))return t(Dt);if(o.includes("msedge")||o.includes("microsoft-edge")||o.includes("edgemac")||o.includes("microsoftedge"))return t(_t);if(o.includes("google-chrome")||o.includes("com.google.chrome")||o==="chromehtml"||o.includes("chrome"))return t(Ot);if(o.includes("chromium"))return t(Vt);if(o.includes("safari"))return{browser:"webkit",label:"Safari",approximated:!0};if(o.includes("brave"))return{browser:"chromium",label:"Brave",approximated:!0};if(o.includes("thebrowser")||o.includes("arc"))return{browser:"chromium",label:"Arc",approximated:!0};if(o.includes("vivaldi"))return{browser:"chromium",label:"Vivaldi",approximated:!0};if(o.includes("opera")||o.includes("opr"))return{browser:"chromium",label:"Opera",approximated:!0}}function Z(e,r){let o=Pt(e,r,{encoding:"utf8",timeout:4e3});if(!(o.error||o.status!==0))return(o.stdout||"").trim()||void 0}function Ut(){let e=Z("xdg-settings",["get","default-web-browser"])??Z("xdg-mime",["query","default","x-scheme-handler/https"]);return e?$e(e):void 0}function Ft(){let e=Z("plutil",["-convert","json","-o","-",`${process.env.HOME}/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist`]);if(e)try{let o=(JSON.parse(e).LSHandlers??[]).find(i=>i.LSHandlerURLScheme==="https"),t=typeof o?.LSHandlerRoleAll=="string"?o.LSHandlerRoleAll:void 0;return t?$e(t):void 0}catch{return}}function Mt(){let r=Z("reg",["query","HKCU\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\https\\UserChoice","/v","ProgId"])?.match(/ProgId\s+REG_SZ\s+(\S+)/i)?.[1];return r?$e(r):void 0}function Ze(){try{if(process.platform==="darwin")return Ft();if(process.platform==="linux")return Ut();if(process.platform==="win32")return Mt()}catch{}}import{spawn as Wt}from"node:child_process";import{mkdtemp as Bt,readFile as Gt,rm as Kt}from"node:fs/promises";import{createRequire as Jt}from"node:module";import Ht from"node:os";import ee from"node:path";var qt=new Set(["name","selector","locator","signals","pageGuid","ariaSnapshot"]);function er(e){let r={};for(let[o,t]of Object.entries(e))!qt.has(o)&&t!==void 0&&(r[o]=t);return r}function Yt(){let e=Jt(import.meta.url),r=e.resolve("playwright/package.json"),o=e("playwright/package.json"),t=typeof o.bin=="string"?o.bin:o.bin?.playwright;if(!t)throw new Error("Could not locate the Playwright CLI entrypoint in playwright/package.json.");return ee.join(ee.dirname(r),t)}async function rr(e){let r=Yt(),o=await Bt(ee.join(Ht.tmpdir(),"verirun-record-")),t=ee.join(o,"recording.jsonl"),i=[r,"codegen","--target=jsonl",`--output=${t}`];e.browser&&i.push(`--browser=${e.browser}`),e.channel&&i.push(`--channel=${e.channel}`),e.userDataDir&&i.push(`--user-data-dir=${e.userDataDir}`),e.testIdAttribute&&i.push(`--test-id-attribute=${e.testIdAttribute}`),e.url&&i.push(e.url);try{let s=await new Promise((c,l)=>{let d=Wt(process.execPath,i,{stdio:["ignore","inherit","inherit"]});d.on("error",l),d.on("close",p=>c(p))}),a=await Gt(t,"utf8").catch(()=>"");return{...zt(a),exitCode:s}}finally{await Kt(o,{recursive:!0,force:!0})}}function zt(e){let r=e.split(`
27
+ `).filter(i=>i.trim().length>0),o={},t=[];for(let[i,s]of r.entries()){let a;try{a=JSON.parse(s)}catch{continue}if(i===0&&a&&typeof a=="object"&&!("name"in a)){o=a;continue}a&&typeof a=="object"&&"name"in a&&t.push(a)}return{header:o,actions:t}}import{existsSync as Qt}from"node:fs";import{appendFile as Xt,readFile as Zt}from"node:fs/promises";import en from"node:path";function rn(e){return e.split(`
28
+ `).map(r=>r.trim()).filter(r=>r&&!r.startsWith("#")).some(r=>r.replace(/^\//,"").replace(/\/$/,"")===W)}async function tr(e){let r=en.join(e,".gitignore");if(!Qt(r))return"no-gitignore";let o=await Zt(r,"utf8");if(rn(o))return"already-present";let t=o.length===0||o.endsWith(`
29
29
  `)?"":`
30
- `;return await Kt(r,`${t}
30
+ `;return await Xt(r,`${t}
31
31
  # verirun: recorded workflows and captured run logs (may contain secrets)
32
- ${B}/
33
- `,"utf8"),"added"}function _(e){return`'${e.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(/\n/g,"\\n")}'`}function M(e){if(e&&typeof e=="object"&&"source"in e){let r=e;return`/${r.source??""}/${r.flags??""}`}return _(String(e))}function Yt(e){let r=e.options??{},o=e.body;switch(e.kind){case"role":{let t=[];r.name!==void 0&&t.push(`name: ${M(r.name)}`),r.exact===!0&&t.push("exact: true");for(let i of r.attrs??[])t.push(`${i.name}: ${JSON.stringify(i.value)}`);return t.length?`getByRole(${_(o)}, { ${t.join(", ")} })`:`getByRole(${_(o)})`}case"test-id":return`getByTestId(${_(o)})`;case"text":case"label":case"placeholder":case"alt":case"title":{let t={text:"getByText",label:"getByLabel",placeholder:"getByPlaceholder",alt:"getByAltText",title:"getByTitle"}[e.kind];return r.exact===!0?`${t}(${M(o)}, { exact: true })`:`${t}(${M(o)})`}case"nth":return`nth(${o})`;case"first":return"first()";case"last":return"last()";case"visible":return`filter({ visible: ${o==="true"} })`;case"frame":return"contentFrame()";case"frame-locator":return`frameLocator(${_(o)})`;case"has-text":return`filter({ hasText: ${M(o)} })`;case"has-not-text":return`filter({ hasNotText: ${M(o)} })`;default:return`locator(${_(o)})`}}function rr(e){if(!e)return;let r=[],o=e;for(;o;)r.push(Yt(o)),o=o.next;return r.join(".")}var zt=/^[A-Za-z0-9][A-Za-z0-9._-]*$/;function O(e){if(!e)throw new Error("Workflow name is required.");if(e.length>64)throw new Error("Workflow name must be 64 characters or fewer.");if(!zt.test(e))throw new Error(`Invalid workflow name "${e}". Use letters, digits, dot, dash or underscore, starting with a letter or digit.`);if(e==="."||e==="..")throw new Error(`Invalid workflow name "${e}".`)}import{mkdir as Qt,readFile as Xt,writeFile as Zt}from"node:fs/promises";import tr from"node:path";var D=1;async function nr(e,r){await Qt(tr.dirname(e),{recursive:!0}),await Zt(e,`${JSON.stringify(r,null,2)}
34
- `,"utf8")}async function re(e){let r=await Xt(e,"utf8"),o;try{o=JSON.parse(r)}catch(i){throw new Error(`Workflow file is not valid JSON: ${e}`,{cause:i})}let t=o;if(!t||typeof t!="object"||!Array.isArray(t.steps))throw new Error(`Workflow file is malformed (no steps array): ${e}`);if(t.schemaVersion!==D)throw new Error(`Workflow "${t.name??tr.basename(e)}" uses schema version ${t.schemaVersion}, but this build expects ${D}. Re-record it.`);return t}function tn(e){return!(e.name==="openPage"&&e.url==="about:blank")}function nn(e){let r=e.length;for(;r>0&&e[r-1]?.name==="closePage";)r-=1;return e.slice(0,r)}function on(e,r){let o={index:r,action:e.name,params:Xe(e),signals:Array.isArray(e.signals)?e.signals:[]};e.selector&&(o.selector=e.selector),e.locator&&(o.locator=e.locator);let t=rr(e.locator);return t&&(o.description=t),e.pageGuid&&(o.pageGuid=e.pageGuid),o}function sn(e){let r=e.description??e.selector??"";switch(e.action){case"navigate":return`navigate ${String(e.params.url??"")}`;case"fill":return`fill ${r} ${n.dim(`= ${JSON.stringify(e.params.text??"")}`)}`;case"press":return`press ${r} ${n.dim(String(e.params.key??""))}`;default:return`${e.action.padEnd(9)} ${r}`.trimEnd()}}async function ir(e,r){let{assertLicensed:o}=await import("./gate.mjs"),t=await o();t.note&&n.warn(t.note),O(e);let i=w(),s=await A(i.configPath),a=P(i,e);if(en(a)&&!r.force)throw new Error(`Workflow "${e}" already exists at ${or.relative(i.repoRoot,a)}. Re-run with --force to overwrite it.`);await rn(i.workflowsDir,{recursive:!0});let c=await er(i.repoRoot);c==="added"?n.step("Added .verirun/ to .gitignore"):c==="no-gitignore"&&n.warn("No .gitignore at the repo root, so .verirun/ is not ignored. Recorded values and run logs may contain secrets.");let l=r.testIdAttribute??s.testIdAttribute??je,d=r.browser,p=r.channel;if(r.defaultBrowser){(r.browser||r.channel)&&n.warn("--default-browser overrides -b / --channel.");let u=Qe();u?(d=u.browser,p=u.channel,u.approximated?n.warn(`Your default browser is ${u.label}, which Playwright can't drive directly \u2014 recording in ${p??d}.`):n.info(n.dim(`Recording in your default browser: ${u.label}`))):(n.warn("Couldn't detect your default browser; recording in bundled Chromium."),d="chromium",p=void 0)}n.info(""),n.info(`Recording ${n.bold(e)}. A browser window will open.`),n.info(n.dim("Perform the workflow, then close the browser to save.")),n.info("");let f=await Ze({url:r.url,browser:d,channel:p,userDataDir:r.userDataDir,testIdAttribute:l}),m=nn(f.actions.filter(tn));if(m.length===0){if(f.exitCode!==0)throw new Error(`Playwright codegen exited with code ${f.exitCode} and recorded nothing. If this persists, the installed Playwright may no longer support the \`jsonl\` codegen target that recording depends on.`);n.warn("No actions were recorded, so nothing was saved.");return}let h=m.map(on),y=h.find(u=>u.action==="navigate"),g={schemaVersion:D,name:e,createdAt:new Date().toISOString(),startUrl:r.url??y?.params.url,browser:f.header.browserName??d??"chromium",channel:p,testIdAttribute:l,steps:h};await nr(a,g),n.info("");for(let u of h)n.info(` ${n.dim(String(u.index).padStart(2))} ${sn(u)}`);n.info(""),n.success(`Saved ${h.length} step${h.length===1?"":"s"} to ${or.relative(i.repoRoot,a)}`),h.some(u=>u.action==="fill"&&u.params.text)&&n.warn("Recorded steps include text you typed. Check the workflow file before sharing it.")}import{existsSync as pn}from"node:fs";import{mkdir as mn,writeFile as gn}from"node:fs/promises";import mr from"node:path";import{chromium as F,firefox as an,selectors as cn,webkit as ln}from"playwright";var dn={chromium:F,firefox:an,webkit:ln};async function un(e,r){let o=!r.headed,t=r.slowMoMs&&r.slowMoMs>0?r.slowMoMs:void 0;if(r.cdpEndpoint){let c=await F.connectOverCDP(r.cdpEndpoint,{slowMo:t}),l=c.contexts()[0]??await c.newContext(),d=l.pages()[0]??await l.newPage();return{context:l,page:d,close:()=>c.close()}}if(r.userDataDir){let c=await F.launchPersistentContext(r.userDataDir,{headless:o,channel:r.channel,slowMo:t}),l=c.pages()[0]??await c.newPage();return{context:c,page:l,close:()=>c.close()}}if(r.channel){let c=await F.launch({headless:o,channel:r.channel,slowMo:t}),l=await c.newContext();return{context:l,page:await l.newPage(),close:()=>c.close()}}let s=await(dn[e.browser]??F).launch({headless:o,slowMo:t}),a=await s.newContext();return{context:a,page:await a.newPage(),close:()=>s.close()}}function sr(e){let r=typeof e=="number"?e:0,o=[];return r&1&&o.push("Alt"),r&2&&o.push("Control"),r&4&&o.push("Meta"),r&8&&o.push("Shift"),o}function te(e){return typeof e=="string"?e:void 0}function ar(e){return Array.isArray(e)?e.filter(r=>typeof r=="string"):[]}async function fn(e,r){let o=()=>{if(!r.selector)throw new Error(`Step ${r.index} (${r.action}) has no selector to act on.`);return e.locator(r.selector)};switch(r.action){case"navigate":{let t=te(r.params.url);if(!t)throw new Error(`Step ${r.index} (navigate) has no url.`);await e.goto(t);return}case"openPage":return;case"closePage":await e.close();return;case"click":case"dblclick":{await o().click({button:te(r.params.button)??"left",clickCount:typeof r.params.clickCount=="number"?r.params.clickCount:r.action==="dblclick"?2:1,modifiers:sr(r.params.modifiers)});return}case"fill":await o().fill(te(r.params.text)??"");return;case"press":{let t=te(r.params.key);if(!t)throw new Error(`Step ${r.index} (press) has no key.`);await o().press([...sr(r.params.modifiers),t].join("+"));return}case"check":await o().check();return;case"uncheck":await o().uncheck();return;case"select":await o().selectOption(ar(r.params.options));return;case"setInputFiles":await o().setInputFiles(ar(r.params.files));return;default:if(r.action.startsWith("assert")){n.warn(`Step ${r.index}: skipping ${r.action} (assertions are not replayed).`);return}throw new Error(`Step ${r.index}: don't know how to replay a "${r.action}" action.`)}}async function cr(e,r={}){e.testIdAttribute&&cn.setTestIdAttribute(e.testIdAttribute);let o={...r,channel:r.channel??e.channel},t=await un(e,o),i=0;try{let{context:s}=t;r.timeoutMs!==void 0&&s.setDefaultTimeout(r.timeoutMs);let a=t.page;s.on("page",c=>{a=c});for(let c of e.steps){n.step(`${String(c.index).padStart(2)} ${c.action}`+(c.description?` ${n.dim(c.description)}`:""));try{await fn(a,c)}catch(l){return{stepsTotal:e.steps.length,stepsReplayed:i,error:l instanceof Error?l:new Error(String(l)),failedStepIndex:c.index}}if(i+=1,a.isClosed()){let l=s.pages().at(-1);l&&(a=l)}}return{stepsTotal:e.steps.length,stepsReplayed:i}}finally{await t.close()}}function lr(e,r){let o=r.toLowerCase();if(!o||typeof e.message=="string"&&e.message.toLowerCase().includes(o))return!0;if(e.raw!==void 0)try{return JSON.stringify(e.raw).toLowerCase().includes(o)}catch{return!1}return!1}var dr=[];function ne(e){dr.push(e)}function ur(e){return dr.map(r=>r(e)).filter(r=>!!r)}var fr=!1;function pr(){fr||(fr=!0,ne(Ue),ne(Be),ne(De))}var hn=1,wn=500;function yn(e){if(e.slowMo!==void 0){let r=Number(e.slowMo);if(!Number.isFinite(r)||r<0)throw new Error(`--slow-mo needs a number of milliseconds, got "${e.slowMo}".`);return r}return e.headed?wn:0}function W(e){return e instanceof Error?e.message:String(e)}function vn(e){return e.replace(/\x1b\[[0-9;]*m/g,"")}async function gr(e){for(let r of[...e].reverse())try{await r.dispose()}catch(o){n.warn(`${r.name}: dispose failed: ${W(o)}`)}}async function hr(e,r){let{assertLicensed:o}=await import("./gate.mjs"),t=await o();t.note&&n.warn(t.note),O(e);let i=w(),s=await A(i.configPath),a=P(i,e);if(!pn(a))throw new Error(`No workflow named "${e}". Record it first with: verirun record ${e}`);let c=await re(a),l;if(r.timeout!==void 0&&(l=Number(r.timeout),!Number.isFinite(l)||l<0))throw new Error(`--timeout must be a non-negative number of milliseconds, got "${r.timeout}".`);let d=(r.user??s.userFilter)?.trim()||void 0;pr();let p=ur(s),f=Ae(),m=Le(i,e,f);await mn(m,{recursive:!0});let h={config:s,runDir:m,workflowName:e,userFilter:d};n.info(""),n.info(`Running ${n.bold(e)} ${n.dim(`${c.steps.length} steps \xB7 ${c.browser}`)}`),p.length===0?n.warn("No log sources configured. Add a supabase or vercel block to .verirun/config.json."):n.info(n.dim(`Log sources: ${p.map(g=>g.name).join(", ")}`)),d&&n.info(n.dim(`User filter: entries mentioning "${d}"`)),n.info("");let y=[];try{for(let g of p)await g.start(h),y.push(g)}catch(g){let u=p[y.length];throw await gr(y),new Error(`Log source "${u?.name??"?"}" failed to start: ${W(g)}`)}try{let g=new Date().toISOString(),u=await cr(c,{headed:r.headed,slowMoMs:yn(r),timeoutMs:l,channel:r.channel,userDataDir:r.userDataDir,cdpEndpoint:r.cdp}),v=new Date().toISOString(),k={startedAt:g,endedAt:v};u.error?n.error(`Replay failed at step ${u.failedStepIndex}: ${W(u.error)}`):n.success(`Replayed ${u.stepsReplayed} step${u.stepsReplayed===1?"":"s"}`);let S=[],j=[],x=0;for(let $ of y)try{let I=await $.collect(h,k);x+=I.length,d&&(I=I.filter(Sr=>lr(Sr,d))),j.push(...I),S.push({id:$.id,name:$.name,entries:I.length})}catch(I){n.warn(`${$.name}: log collection failed: ${W(I)}`),S.push({id:$.id,name:$.name,entries:0})}d&&j.length===0&&x>0&&n.warn(`${x} log entr${x===1?"y":"ies"} collected, none mention "${d}".`),j.sort(($,I)=>($.timestamp??"").localeCompare(I.timestamp??""));let kr={schemaVersion:hn,workflow:e,status:u.error?"failed":"ok",window:k,steps:{total:u.stepsTotal,replayed:u.stepsReplayed,...u.failedStepIndex!==void 0?{failedAt:u.failedStepIndex}:{}},...u.error?{error:vn(W(u.error))}:{},...d?{filter:{user:d}}:{},sources:S,entries:j},ke=mr.join(m,"logs.json");await gn(ke,`${JSON.stringify(kr,null,2)}
35
- `,"utf8"),n.info("");for(let $ of S)n.info(` ${$.name.padEnd(10)} ${$.entries} entr${$.entries===1?"y":"ies"}`);n.info(""),n.success(`Logs written to ${mr.relative(i.repoRoot,ke)}`),u.error&&(process.exitCode=1)}finally{await gr(y)}}import{existsSync as bn}from"node:fs";import kn from"node:path";var Sn=new Set(["navigate","click","dblclick","fill","press","check","uncheck","select","setInputFiles","openPage","closePage"]),$n=/^assert/,Rn=new Set(["click","dblclick","fill","press","check","uncheck","select","setInputFiles"]),Cn={navigate:["url"],fill:["text"],press:["key"],select:["values"],setInputFiles:["files"]};function En(e){let r=[],o=(i,s,a)=>{r.push({step:i,level:s,message:a})};e.length===0&&r.push({step:0,level:"error",message:"no steps"}),e.forEach((i,s)=>{let a=s+1;if(typeof i.action!="string"||i.action===""){o(a,"error",'missing "action"');return}if($n.test(i.action)){o(a,"warning",`"${i.action}" is skipped at replay \u2014 it asserts nothing`);return}if(!Sn.has(i.action)){o(a,"error",`unknown action "${i.action}" \u2014 a run stops here`);return}Rn.has(i.action)&&!i.selector&&o(a,"error",`"${i.action}" needs a "selector"`);for(let c of Cn[i.action]??[])i.params?.[c]===void 0&&o(a,"error",`"${i.action}" needs params.${c}`);if(i.action==="navigate"){let c=i.params?.url;typeof c=="string"&&!/^https?:\/\//.test(c)&&o(a,"error",`params.url must be absolute, got "${c}"`)}i.selector?.startsWith("role=")&&!/\[name=/.test(i.selector)&&o(a,"warning",`"${i.selector}" matches every such element on the page`),typeof i.index!="number"&&o(a,"warning",`missing "index" \u2014 set it to the step's position`)}),e.length>0&&e[0]?.action!=="navigate"&&r.push({step:1,level:"warning",message:'first step is not "navigate" \u2014 replay opens a blank page, so start with one'});let t=e.map((i,s)=>({step:i,n:s+1})).filter(({step:i,n:s})=>s>1&&i.action==="navigate");for(let{n:i}of t)r.push({step:i,level:"warning",message:"navigating by URL skips the UI \u2014 click the link or button that goes there instead (`verirun map --bfs <route>` names it). Fine only for a deep link with no path to it."});return r}async function wr(e,r,o){if(e!=="check")throw new Error(`Unknown workflow action "${e}". Only "check" exists.`);if(!r)throw new Error("workflow check needs a workflow name or a path to a .json file.");let t=w(),i;if(r.endsWith(".json")?i=kn.resolve(r):(O(r),i=P(t,r)),!bn(i))throw new Error(`No such workflow file: ${i}`);let s=await re(i),a=En(s.steps),c=a.filter(l=>l.level==="error");if(o.json){process.stdout.write(`${JSON.stringify({file:i,name:s.name,steps:s.steps.length,ok:c.length===0,findings:a},null,2)}
36
- `),c.length>0&&(process.exitCode=1);return}n.info(""),n.info(`${n.bold(s.name)} ${n.dim(`\u2014 ${s.steps.length} step(s), schemaVersion ${s.schemaVersion}`)}`),n.info(n.dim(` ${i}`)),n.info("");for(let l of a){let d=`step ${l.step}`.padEnd(8);l.level==="error"?n.error(`${d} ${l.message}`):n.warn(`${d} ${l.message}`)}a.length===0?n.success(` Looks runnable. Try it: verirun run ${s.name}`):c.length===0?(n.info(""),n.success(` No errors. Try it: verirun run ${s.name}`)):(n.info(""),n.error(` ${c.length} error(s) \u2014 a run would fail. Fix them and check again.`),process.exitCode=1),n.info(""),n.info(n.dim(` Static checks only: selectors are not resolved against a page. Schema version ${D}.`))}var vr="wAdEDaQtIHSp1cj15A0y1+qHzRKBfs5bakVbVCwcmbZsNDaGznkGDLzrUUL6tV/JvDjfW1knb8dC3YypNHa6Aw==",br="MCowBQYDK2VwAyEATFTl78zmb+BITZuy9mdPMtujnz1tAeVidJT3dccuhLg=";function Nn(){if(vr.startsWith("@@")||br.startsWith("@@"))return!0;try{let e=yr.dirname(An(import.meta.url)),r=xn(yr.join(e,"gate.mjs")),o=In({key:Buffer.from(br,"base64"),format:"der",type:"spki"});return jn(null,r,o,Buffer.from(vr,"base64"))}catch{return!1}}var R=new Ln;R.name("verirun").description("Record and replay app workflows, and capture backend logs for each run.").version(N);R.command("record").argument("<name>","name for the workflow").description("Record a workflow in a headed browser and save it to .verirun/workflows").option("-u, --url <url>","URL to open the browser at").option("-b, --browser <browser>","browser to record in: chromium, firefox or webkit").option("--channel <channel>","use an installed browser: chrome, msedge, chrome-beta, ...").option("--default-browser","record in your OS default browser (falls back to bundled Chromium)").option("--user-data-dir <dir>","record in a persistent profile directory (keeps you logged in)").option("--test-id-attribute <attribute>","attribute to prefer for getByTestId selectors").option("-f, --force","overwrite an existing workflow with this name").action(async(e,r)=>{await ir(e,r)});R.command("run").argument("<name>","name of the workflow to replay").description("Replay a recorded workflow and capture Supabase / Vercel / Railway logs for the run window").option("--headed","run with a visible browser window instead of headless (paced so you can watch)").option("--slow-mo <ms>","pause before each action; default 500 when --headed, 0 otherwise").option("--timeout <ms>","per-action timeout in milliseconds (default: Playwright 30000)").option("--channel <channel>","replay in an installed browser: chrome, msedge, ...").option("--user-data-dir <dir>","replay in a persistent profile directory (keeps you logged in)").option("--cdp <url>","attach to a browser already running with --remote-debugging-port, e.g. http://localhost:9222").option("--user <id>","keep only log entries mentioning this string, e.g. an email (overrides config.userFilter)").action(async(e,r)=>{await hr(e,r)});R.command("login").description("Connect this machine to your Verirun account").option("-f, --force","connect even if this machine is already linked").option("--server <url>","account server base URL (default: https://get-verirun.duely.in)").action(async e=>{await $e(e)});R.command("logout").description("Disconnect this machine from your Verirun account").action(async()=>{await Re()});R.command("whoami").description("Show the connected account and subscription status").option("--server <url>","account server base URL").action(async e=>{await Ce(e)});R.command("map").description("Build an interaction graph of this repo: pages, the elements on them, and the backend calls they make").option("-d, --dir <dir>","directory to analyze (default: the repo root)").option("--json","print the full interaction graph as JSON").option("--report","write interaction-tree.json + coverage.md (default: .verirun/map)").option("--out <dir>","output directory for --report").option("--reach","per-route table of reachable vs attached elements").option("--bfs <node>","walk the graph from a node: a route path, page id or component name").option("--depth <n>","steps to follow for --bfs (default: 2)").option("--kind <kind>","--bfs: follow only nav or only effect edges").option("--alias <prefix=dir...>","extra import alias, e.g. @/=src (tsconfig paths are read automatically)").option("--no-follow-children","do not follow child components out of a page file").option("--app-file <file>","file declaring <Routes> (react-router apps; auto-detected by default)").action(async e=>{await ze(e)});R.command("workflow").argument("<action>","what to do: check").argument("[name]","workflow name, or a path to a .json file").description("Check a workflow file without running it (shape, actions, selectors, params)").option("--json","emit the findings as JSON").action(async(e,r,o)=>{await wr(e,r,o)});R.command("agent").description("Print a compact reference (commands, .verirun/ layout, logs.json schema) for an AI coding agent").option("--json","emit JSON instead of Markdown").option("--skill","emit a Claude Code skill file instead of the plain reference").option("--install","with --skill: write it to .claude/skills/verirun/SKILL.md").action(async e=>{await _e(R,e)});R.command("log").argument("[source]","log source to connect: vercel, supabase or railway (omit for an overview)").description("Connect a log source and check its configuration").option("--test","query the last 5 minutes and report what comes back").option("--drain","vercel: set up the old push-based log drain instead of the API").option("--listen","vercel: run the drain listener until Ctrl+C (drain mode only)").option("--reconnect","re-run the connect step and replace what was saved").action(async(e,r)=>{await Ke(e,r)});async function Tn(){Nn()||(process.stderr.write(`verirun: this installation looks modified. Reinstall it:
32
+ ${W}/
33
+ `,"utf8"),"added"}function O(e){return`'${e.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(/\n/g,"\\n")}'`}function U(e){if(e&&typeof e=="object"&&"source"in e){let r=e;return`/${r.source??""}/${r.flags??""}`}return O(String(e))}function tn(e){let r=e.options??{},o=e.body;switch(e.kind){case"role":{let t=[];r.name!==void 0&&t.push(`name: ${U(r.name)}`),r.exact===!0&&t.push("exact: true");for(let i of r.attrs??[])t.push(`${i.name}: ${JSON.stringify(i.value)}`);return t.length?`getByRole(${O(o)}, { ${t.join(", ")} })`:`getByRole(${O(o)})`}case"test-id":return`getByTestId(${O(o)})`;case"text":case"label":case"placeholder":case"alt":case"title":{let t={text:"getByText",label:"getByLabel",placeholder:"getByPlaceholder",alt:"getByAltText",title:"getByTitle"}[e.kind];return r.exact===!0?`${t}(${U(o)}, { exact: true })`:`${t}(${U(o)})`}case"nth":return`nth(${o})`;case"first":return"first()";case"last":return"last()";case"visible":return`filter({ visible: ${o==="true"} })`;case"frame":return"contentFrame()";case"frame-locator":return`frameLocator(${O(o)})`;case"has-text":return`filter({ hasText: ${U(o)} })`;case"has-not-text":return`filter({ hasNotText: ${U(o)} })`;default:return`locator(${O(o)})`}}function nr(e){if(!e)return;let r=[],o=e;for(;o;)r.push(tn(o)),o=o.next;return r.join(".")}var nn=/^[A-Za-z0-9][A-Za-z0-9._-]*$/;var on=/^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i;function _(e){if(!e)throw new Error("Workflow name is required.");if(e.length>64)throw new Error("Workflow name must be 64 characters or fewer.");if(!nn.test(e))throw new Error(`Invalid workflow name "${e}". Use letters, digits, dot, dash or underscore, starting with a letter or digit.`);if(e==="."||e==="..")throw new Error(`Invalid workflow name "${e}".`);if(e.endsWith("."))throw new Error(`Invalid workflow name "${e}". A trailing dot is dropped on Windows, so "${e}" and "${e.replace(/\.+$/,"")}" would be the same file.`);let r=e.split(".")[0]??"";if(on.test(r))throw new Error(`Invalid workflow name "${e}". "${r}" is a reserved device name on Windows and cannot be used as a filename.`)}import{mkdir as sn,readFile as an,writeFile as cn}from"node:fs/promises";import or from"node:path";var D=1;async function ir(e,r){await sn(or.dirname(e),{recursive:!0}),await cn(e,`${JSON.stringify(r,null,2)}
34
+ `,"utf8")}async function re(e){let r=await an(e,"utf8"),o;try{o=JSON.parse(r)}catch(i){throw new Error(`Workflow file is not valid JSON: ${e}`,{cause:i})}let t=o;if(!t||typeof t!="object"||!Array.isArray(t.steps))throw new Error(`Workflow file is malformed (no steps array): ${e}`);if(t.schemaVersion!==D)throw new Error(`Workflow "${t.name??or.basename(e)}" uses schema version ${t.schemaVersion}, but this build expects ${D}. Re-record it.`);return t}function un(e){return!(e.name==="openPage"&&e.url==="about:blank")}function fn(e){let r=e.length;for(;r>0&&e[r-1]?.name==="closePage";)r-=1;return e.slice(0,r)}function pn(e,r){let o={index:r,action:e.name,params:er(e),signals:Array.isArray(e.signals)?e.signals:[]};e.selector&&(o.selector=e.selector),e.locator&&(o.locator=e.locator);let t=nr(e.locator);return t&&(o.description=t),e.pageGuid&&(o.pageGuid=e.pageGuid),o}function mn(e){let r=e.description??e.selector??"";switch(e.action){case"navigate":return`navigate ${String(e.params.url??"")}`;case"fill":return`fill ${r} ${n.dim(`= ${JSON.stringify(e.params.text??"")}`)}`;case"press":return`press ${r} ${n.dim(String(e.params.key??""))}`;default:return`${e.action.padEnd(9)} ${r}`.trimEnd()}}async function ar(e,r){let{assertLicensed:o}=await import("./gate.mjs"),t=await o();t.note&&n.warn(t.note),_(e);let i=w(),s=await A(i.configPath),a=P(i,e);if(ln(a)&&!r.force)throw new Error(`Workflow "${e}" already exists at ${sr.relative(i.repoRoot,a)}. Re-run with --force to overwrite it.`);await dn(i.workflowsDir,{recursive:!0});let c=await tr(i.repoRoot);c==="added"?n.step("Added .verirun/ to .gitignore"):c==="no-gitignore"&&n.warn("No .gitignore at the repo root, so .verirun/ is not ignored. Recorded values and run logs may contain secrets.");let l=r.testIdAttribute??s.testIdAttribute??xe,d=r.browser,p=r.channel;if(r.defaultBrowser){(r.browser||r.channel)&&n.warn("--default-browser overrides -b / --channel.");let u=Ze();u?(d=u.browser,p=u.channel,u.approximated?n.warn(`Your default browser is ${u.label}, which Playwright can't drive directly \u2014 recording in ${p??d}.`):n.info(n.dim(`Recording in your default browser: ${u.label}`))):(n.warn("Couldn't detect your default browser; recording in bundled Chromium."),d="chromium",p=void 0)}n.info(""),n.info(`Recording ${n.bold(e)}. A browser window will open.`),n.info(n.dim("Perform the workflow, then close the browser to save.")),n.info("");let f=await rr({url:r.url,browser:d,channel:p,userDataDir:r.userDataDir,testIdAttribute:l}),m=fn(f.actions.filter(un));if(m.length===0){if(f.exitCode!==0)throw new Error(`Playwright codegen exited with code ${f.exitCode} and recorded nothing. If this persists, the installed Playwright may no longer support the \`jsonl\` codegen target that recording depends on.`);n.warn("No actions were recorded, so nothing was saved.");return}let h=m.map(pn),y=h.find(u=>u.action==="navigate"),g={schemaVersion:D,name:e,createdAt:new Date().toISOString(),startUrl:r.url??y?.params.url,browser:f.header.browserName??d??"chromium",channel:p,testIdAttribute:l,steps:h};await ir(a,g),n.info("");for(let u of h)n.info(` ${n.dim(String(u.index).padStart(2))} ${mn(u)}`);n.info(""),n.success(`Saved ${h.length} step${h.length===1?"":"s"} to ${sr.relative(i.repoRoot,a)}`),h.some(u=>u.action==="fill"&&u.params.text)&&n.warn("Recorded steps include text you typed. Check the workflow file before sharing it.")}import{existsSync as Sn}from"node:fs";import{mkdir as $n,writeFile as kn}from"node:fs/promises";import hr from"node:path";import{chromium as F,firefox as gn,selectors as hn,webkit as wn}from"playwright";var yn={chromium:F,firefox:gn,webkit:wn};async function vn(e,r){let o=!r.headed,t=r.slowMoMs&&r.slowMoMs>0?r.slowMoMs:void 0;if(r.cdpEndpoint){let c=await F.connectOverCDP(r.cdpEndpoint,{slowMo:t}),l=c.contexts()[0]??await c.newContext(),d=l.pages()[0]??await l.newPage();return{context:l,page:d,close:()=>c.close()}}if(r.userDataDir){let c=await F.launchPersistentContext(r.userDataDir,{headless:o,channel:r.channel,slowMo:t}),l=c.pages()[0]??await c.newPage();return{context:c,page:l,close:()=>c.close()}}if(r.channel){let c=await F.launch({headless:o,channel:r.channel,slowMo:t}),l=await c.newContext();return{context:l,page:await l.newPage(),close:()=>c.close()}}let s=await(yn[e.browser]??F).launch({headless:o,slowMo:t}),a=await s.newContext();return{context:a,page:await a.newPage(),close:()=>s.close()}}function cr(e){let r=typeof e=="number"?e:0,o=[];return r&1&&o.push("Alt"),r&2&&o.push("Control"),r&4&&o.push("Meta"),r&8&&o.push("Shift"),o}function te(e){return typeof e=="string"?e:void 0}function lr(e){return Array.isArray(e)?e.filter(r=>typeof r=="string"):[]}async function bn(e,r){let o=()=>{if(!r.selector)throw new Error(`Step ${r.index} (${r.action}) has no selector to act on.`);return e.locator(r.selector)};switch(r.action){case"navigate":{let t=te(r.params.url);if(!t)throw new Error(`Step ${r.index} (navigate) has no url.`);await e.goto(t);return}case"openPage":return;case"closePage":await e.close();return;case"click":case"dblclick":{await o().click({button:te(r.params.button)??"left",clickCount:typeof r.params.clickCount=="number"?r.params.clickCount:r.action==="dblclick"?2:1,modifiers:cr(r.params.modifiers)});return}case"fill":await o().fill(te(r.params.text)??"");return;case"press":{let t=te(r.params.key);if(!t)throw new Error(`Step ${r.index} (press) has no key.`);await o().press([...cr(r.params.modifiers),t].join("+"));return}case"check":await o().check();return;case"uncheck":await o().uncheck();return;case"select":await o().selectOption(lr(r.params.options));return;case"setInputFiles":await o().setInputFiles(lr(r.params.files));return;default:if(r.action.startsWith("assert")){n.warn(`Step ${r.index}: skipping ${r.action} (assertions are not replayed).`);return}throw new Error(`Step ${r.index}: don't know how to replay a "${r.action}" action.`)}}async function dr(e,r={}){e.testIdAttribute&&hn.setTestIdAttribute(e.testIdAttribute);let o={...r,channel:r.channel??e.channel},t=await vn(e,o),i=0;try{let{context:s}=t;r.timeoutMs!==void 0&&s.setDefaultTimeout(r.timeoutMs);let a=t.page;s.on("page",c=>{a=c});for(let c of e.steps){n.step(`${String(c.index).padStart(2)} ${c.action}`+(c.description?` ${n.dim(c.description)}`:""));try{await bn(a,c)}catch(l){return{stepsTotal:e.steps.length,stepsReplayed:i,error:l instanceof Error?l:new Error(String(l)),failedStepIndex:c.index}}if(i+=1,a.isClosed()){let l=s.pages().at(-1);l&&(a=l)}}return{stepsTotal:e.steps.length,stepsReplayed:i}}finally{await t.close()}}function ur(e,r){let o=r.toLowerCase();if(!o||typeof e.message=="string"&&e.message.toLowerCase().includes(o))return!0;if(e.raw!==void 0)try{return JSON.stringify(e.raw).toLowerCase().includes(o)}catch{return!1}return!1}var fr=[];function ne(e){fr.push(e)}function pr(e){return fr.map(r=>r(e)).filter(r=>!!r)}var mr=!1;function gr(){mr||(mr=!0,ne(Me),ne(Ke),ne(Ue))}var Rn=1,Cn=500;function En(e){if(e.slowMo!==void 0){let r=Number(e.slowMo);if(!Number.isFinite(r)||r<0)throw new Error(`--slow-mo needs a number of milliseconds, got "${e.slowMo}".`);return r}return e.headed?Cn:0}function M(e){return e instanceof Error?e.message:String(e)}function In(e){return e.replace(/\x1b\[[0-9;]*m/g,"")}async function wr(e){for(let r of[...e].reverse())try{await r.dispose()}catch(o){n.warn(`${r.name}: dispose failed: ${M(o)}`)}}async function yr(e,r){let{assertLicensed:o}=await import("./gate.mjs"),t=await o();t.note&&n.warn(t.note),_(e);let i=w(),s=await A(i.configPath),a=P(i,e);if(!Sn(a))throw new Error(`No workflow named "${e}". Record it first with: verirun record ${e}`);let c=await re(a),l;if(r.timeout!==void 0&&(l=Number(r.timeout),!Number.isFinite(l)||l<0))throw new Error(`--timeout must be a non-negative number of milliseconds, got "${r.timeout}".`);let d=(r.user??s.userFilter)?.trim()||void 0;gr();let p=pr(s),f=Ne(),m=Te(i,e,f);await $n(m,{recursive:!0});let h={config:s,runDir:m,workflowName:e,userFilter:d};n.info(""),n.info(`Running ${n.bold(e)} ${n.dim(`${c.steps.length} steps \xB7 ${c.browser}`)}`),p.length===0?n.warn("No log sources configured. Add a supabase or vercel block to .verirun/config.json."):n.info(n.dim(`Log sources: ${p.map(g=>g.name).join(", ")}`)),d&&n.info(n.dim(`User filter: entries mentioning "${d}"`)),n.info("");let y=[];try{for(let g of p)await g.start(h),y.push(g)}catch(g){let u=p[y.length];throw await wr(y),new Error(`Log source "${u?.name??"?"}" failed to start: ${M(g)}`)}try{let g=new Date().toISOString(),u=await dr(c,{headed:r.headed,slowMoMs:En(r),timeoutMs:l,channel:r.channel,userDataDir:r.userDataDir,cdpEndpoint:r.cdp}),v=new Date().toISOString(),S={startedAt:g,endedAt:v};u.error?n.error(`Replay failed at step ${u.failedStepIndex}: ${M(u.error)}`):n.success(`Replayed ${u.stepsReplayed} step${u.stepsReplayed===1?"":"s"}`);let $=[],j=[],x=0;for(let k of y)try{let I=await k.collect(h,S);x+=I.length,d&&(I=I.filter(Rr=>ur(Rr,d))),j.push(...I),$.push({id:k.id,name:k.name,entries:I.length})}catch(I){n.warn(`${k.name}: log collection failed: ${M(I)}`),$.push({id:k.id,name:k.name,entries:0})}d&&j.length===0&&x>0&&n.warn(`${x} log entr${x===1?"y":"ies"} collected, none mention "${d}".`),j.sort((k,I)=>(k.timestamp??"").localeCompare(I.timestamp??""));let kr={schemaVersion:Rn,workflow:e,status:u.error?"failed":"ok",window:S,steps:{total:u.stepsTotal,replayed:u.stepsReplayed,...u.failedStepIndex!==void 0?{failedAt:u.failedStepIndex}:{}},...u.error?{error:In(M(u.error))}:{},...d?{filter:{user:d}}:{},sources:$,entries:j},ke=hr.join(m,"logs.json");await kn(ke,`${JSON.stringify(kr,null,2)}
35
+ `,"utf8"),n.info("");for(let k of $)n.info(` ${k.name.padEnd(10)} ${k.entries} entr${k.entries===1?"y":"ies"}`);n.info(""),n.success(`Logs written to ${hr.relative(i.repoRoot,ke)}`),u.error&&(process.exitCode=1)}finally{await wr(y)}}import{existsSync as jn}from"node:fs";import xn from"node:path";var An=new Set(["navigate","click","dblclick","fill","press","check","uncheck","select","setInputFiles","openPage","closePage"]),Ln=/^assert/,Nn=new Set(["click","dblclick","fill","press","check","uncheck","select","setInputFiles"]),Tn={navigate:["url"],fill:["text"],press:["key"],select:["values"],setInputFiles:["files"]};function Pn(e){let r=[],o=(i,s,a)=>{r.push({step:i,level:s,message:a})};e.length===0&&r.push({step:0,level:"error",message:"no steps"}),e.forEach((i,s)=>{let a=s+1;if(typeof i.action!="string"||i.action===""){o(a,"error",'missing "action"');return}if(Ln.test(i.action)){o(a,"warning",`"${i.action}" is skipped at replay \u2014 it asserts nothing`);return}if(!An.has(i.action)){o(a,"error",`unknown action "${i.action}" \u2014 a run stops here`);return}Nn.has(i.action)&&!i.selector&&o(a,"error",`"${i.action}" needs a "selector"`);for(let c of Tn[i.action]??[])i.params?.[c]===void 0&&o(a,"error",`"${i.action}" needs params.${c}`);if(i.action==="navigate"){let c=i.params?.url;typeof c=="string"&&!/^https?:\/\//.test(c)&&o(a,"error",`params.url must be absolute, got "${c}"`)}i.selector?.startsWith("role=")&&!/\[name=/.test(i.selector)&&o(a,"warning",`"${i.selector}" matches every such element on the page`),typeof i.index!="number"&&o(a,"warning",`missing "index" \u2014 set it to the step's position`)}),e.length>0&&e[0]?.action!=="navigate"&&r.push({step:1,level:"warning",message:'first step is not "navigate" \u2014 replay opens a blank page, so start with one'});let t=e.map((i,s)=>({step:i,n:s+1})).filter(({step:i,n:s})=>s>1&&i.action==="navigate");for(let{n:i}of t)r.push({step:i,level:"warning",message:"navigating by URL skips the UI \u2014 click the link or button that goes there instead (`verirun map --bfs <route>` names it). Fine only for a deep link with no path to it."});return r}async function vr(e,r,o){if(e!=="check")throw new Error(`Unknown workflow action "${e}". Only "check" exists.`);if(!r)throw new Error("workflow check needs a workflow name or a path to a .json file.");let t=w(),i;if(r.endsWith(".json")?i=xn.resolve(r):(_(r),i=P(t,r)),!jn(i))throw new Error(`No such workflow file: ${i}`);let s=await re(i),a=Pn(s.steps),c=a.filter(l=>l.level==="error");if(o.json){process.stdout.write(`${JSON.stringify({file:i,name:s.name,steps:s.steps.length,ok:c.length===0,findings:a},null,2)}
36
+ `),c.length>0&&(process.exitCode=1);return}n.info(""),n.info(`${n.bold(s.name)} ${n.dim(`\u2014 ${s.steps.length} step(s), schemaVersion ${s.schemaVersion}`)}`),n.info(n.dim(` ${i}`)),n.info("");for(let l of a){let d=`step ${l.step}`.padEnd(8);l.level==="error"?n.error(`${d} ${l.message}`):n.warn(`${d} ${l.message}`)}a.length===0?n.success(` Looks runnable. Try it: verirun run ${s.name}`):c.length===0?(n.info(""),n.success(` No errors. Try it: verirun run ${s.name}`)):(n.info(""),n.error(` ${c.length} error(s) \u2014 a run would fail. Fix them and check again.`),process.exitCode=1),n.info(""),n.info(n.dim(` Static checks only: selectors are not resolved against a page. Schema version ${D}.`))}var Sr="maxex4IKUNrxtTOrel4kbxHVS6xCB67iCHdrJjYp1fz84mMMMqSj5OVHRCJ45wwL0N/zVy0my3fcNQtyPibhCA==",$r="MCowBQYDK2VwAyEATFTl78zmb+BITZuy9mdPMtujnz1tAeVidJT3dccuhLg=";function Fn(){if(Sr.startsWith("@@")||$r.startsWith("@@"))return!0;try{let e=br.dirname(Vn(import.meta.url)),r=Dn(br.join(e,"gate.mjs")),o=On({key:Buffer.from($r,"base64"),format:"der",type:"spki"});return _n(null,r,o,Buffer.from(Sr,"base64"))}catch{return!1}}var R=new Un;R.name("verirun").description("Record and replay app workflows, and capture backend logs for each run.").version(N);R.command("record").argument("<name>","name for the workflow").description("Record a workflow in a headed browser and save it to .verirun/workflows").option("-u, --url <url>","URL to open the browser at").option("-b, --browser <browser>","browser to record in: chromium, firefox or webkit").option("--channel <channel>","use an installed browser: chrome, msedge, chrome-beta, ...").option("--default-browser","record in your OS default browser (falls back to bundled Chromium)").option("--user-data-dir <dir>","record in a persistent profile directory (keeps you logged in)").option("--test-id-attribute <attribute>","attribute to prefer for getByTestId selectors").option("-f, --force","overwrite an existing workflow with this name").action(async(e,r)=>{await ar(e,r)});R.command("run").argument("<name>","name of the workflow to replay").description("Replay a recorded workflow and capture Supabase / Vercel / Railway logs for the run window").option("--headed","run with a visible browser window instead of headless (paced so you can watch)").option("--slow-mo <ms>","pause before each action; default 500 when --headed, 0 otherwise").option("--timeout <ms>","per-action timeout in milliseconds (default: Playwright 30000)").option("--channel <channel>","replay in an installed browser: chrome, msedge, ...").option("--user-data-dir <dir>","replay in a persistent profile directory (keeps you logged in)").option("--cdp <url>","attach to a browser already running with --remote-debugging-port, e.g. http://localhost:9222").option("--user <id>","keep only log entries mentioning this string, e.g. an email (overrides config.userFilter)").action(async(e,r)=>{await yr(e,r)});R.command("login").description("Connect this machine to your Verirun account").option("-f, --force","connect even if this machine is already linked").option("--server <url>","account server base URL (default: https://get-verirun.duely.in)").action(async e=>{await Ce(e)});R.command("logout").description("Disconnect this machine from your Verirun account").action(async()=>{await Ee()});R.command("whoami").description("Show the connected account and subscription status").option("--server <url>","account server base URL").action(async e=>{await Ie(e)});R.command("map").description("Build an interaction graph of this repo: pages, the elements on them, and the backend calls they make").option("-d, --dir <dir>","directory to analyze (default: the repo root)").option("--json","print the full interaction graph as JSON").option("--report","write interaction-tree.json + coverage.md (default: .verirun/map)").option("--out <dir>","output directory for --report").option("--reach","per-route table of reachable vs attached elements").option("--bfs <node>","walk the graph from a node: a route path, page id or component name").option("--depth <n>","steps to follow for --bfs (default: 2)").option("--kind <kind>","--bfs: follow only nav or only effect edges").option("--alias <prefix=dir...>","extra import alias, e.g. @/=src (tsconfig paths are read automatically)").option("--no-follow-children","do not follow child components out of a page file").option("--app-file <file>","file declaring <Routes> (react-router apps; auto-detected by default)").action(async e=>{await Xe(e)});R.command("workflow").argument("<action>","what to do: check").argument("[name]","workflow name, or a path to a .json file").description("Check a workflow file without running it (shape, actions, selectors, params)").option("--json","emit the findings as JSON").action(async(e,r,o)=>{await vr(e,r,o)});R.command("agent").description("Print a compact reference (commands, .verirun/ layout, logs.json schema) for an AI coding agent").option("--json","emit JSON instead of Markdown").option("--skill","emit a Claude Code skill file instead of the plain reference").option("--install","with --skill: write it to .claude/skills/verirun/SKILL.md").action(async e=>{await De(R,e)});R.command("log").argument("[source]","log source to connect: vercel, supabase or railway (omit for an overview)").description("Connect a log source and check its configuration").option("--test","query the last 5 minutes and report what comes back").option("--drain","vercel: set up the old push-based log drain instead of the API").option("--listen","vercel: run the drain listener until Ctrl+C (drain mode only)").option("--reconnect","re-run the connect step and replace what was saved").action(async(e,r)=>{await He(e,r)});async function Mn(){Fn()||(process.stderr.write(`verirun: this installation looks modified. Reinstall it:
37
37
 
38
38
  npm install -g @verirun/cli
39
- `),process.exit(1));try{await R.parseAsync(process.argv)}catch(e){n.error(e instanceof Error?e.message:String(e)),process.exitCode=1}}Tn();
39
+ `),process.exit(1));try{await R.parseAsync(process.argv)}catch(e){n.error(e instanceof Error?e.message:String(e)),process.exitCode=1}}Mn();
package/dist/gate.mjs CHANGED
@@ -1 +1 @@
1
- const aK=i;(function(n,o){const aE=i,r=n();while(!![]){try{const s=-parseInt(aE(0x364))/(0x1d*-0x1+0x1982*0x1+-0x1964)*(parseInt(aE(0x2d4))/(0x2388+0x1722+-0x3aa8))+-parseInt(aE(0x329))/(0x1fdd*-0x1+0x441+0x1b9f)+parseInt(aE(0x1f2))/(-0x1*-0x985+0x9*0x153+-0x156c)+parseInt(aE(0x20a))/(-0x17*0x167+-0x6d1+0x2717)*(parseInt(aE(0x264))/(-0xd3f+-0x2607+-0x19a6*-0x2))+-parseInt(aE(0x232))/(-0x2e1*0x1+-0x35*0xa4+-0xe*-0x2a2)*(-parseInt(aE(0x2c3))/(0x250d*-0x1+0xc23*-0x1+-0x8*-0x627))+parseInt(aE(0x267))/(-0x1837*-0x1+-0x1*-0x26ae+-0x3edc)*(-parseInt(aE(0x2d1))/(0x1*0x2469+-0x228e*0x1+-0x1d1))+-parseInt(aE(0x298))/(0x1adb+-0xfb8+-0xb18)*(parseInt(aE(0x221))/(-0x1854+-0x664+0x2c*0xb3));if(s===o)break;else r['push'](r['shift']());}catch(t){r['push'](r['shift']());}}}(e,0x81f2e+-0xb3*-0x74f+-0x3d6d4));const c=(function(){let n=!![];return function(o,r){const s=n?function(){const aF=i;if(r){const t=r[aF(0x24d)](o,arguments);return r=null,t;}}:function(){};return n=![],s;};}()),a=c(this,function(){const aG=i,n={'mJtzJ':function(o,r){return o!==r;},'apkPn':aG(0x265)+aG(0x291)};if(n[aG(0x2e1)](a[aG(0x324)]()[aG(0x239)]()[aG(0x222)]('\x0a'),-(-0x3a*0x1+-0x9*0x3ad+0x2150)))return;return a[aG(0x239)]()[aG(0x284)](n[aG(0x379)])[aG(0x239)]()[aG(0x238)+aG(0x34e)](a)[aG(0x284)](aG(0x265)+aG(0x291));});a();import{randomBytes as ap}from'node:crypto';import aq from'node:os';function e(){const b5=['zxnWB25Zzs4','AguGCMvHBca','mty5ntq5mNfUsgrhyq','yITcsvrADxK','zsbVBMuGyxq','tu5LrLm','r0H4yvu','x0LorKLosvq','B25Uzwn0ihq','BNrLCMzHy2u','zerOENq','igeGyNjVD3m','vgHPCYbHy2m','qwnguLy','ww91CIbwzxi','sgrLsuS','DxiGC3vIC2m','AxrFzxHJzwu','l2fWAs9SAwm','EgLTDw0GBNu','CMLWDgLVBIa','zgvK','s3jutui','AxnbCNjHEq','BMrLza','ihrVihjLCxu','mte0ntvqu21JzM0','zxjPCNvUige','uw5mqxm','y2SGzMfPBgu','wMHwufC','Dw5RBM93BL8','CgfYC2vjBNq','BwfJ','rxPJsu4','zw5Zzs92ywW','DLrZAMu','qKzXD2m','zePum2rJy3u','l2fJy291BNq','CxDLB08','mNHmmhbsnge','DxbKyxrL','quP6Bg0','DgHLigXPy2u','AxjLza','Dg9TyxrPy2e','B3vYigjPBgW','D0Lwu2i','otqWotj4DuDevNm','Aw5KzxHpzG','ig9MzMXPBMu','ywjVCNq','B2DPBGOkvgG','lIbszwXLyxm','oJaWoJaWoJa','CgrjvgC','AeXNpq','u2HOuwy','zLzZuxC','zxiGyxqG','y2XVy2TsB2W','ANfTugK','CNvUihDOB2e','A2vK','DhjPywWGB24','nJGWmZGZowHhBNHYzq','A1zYu08','BwfJAgLUzxm','tLbeC0W','AgrXs1a','BM93','y29UC3rYDwm','Dg9tDhjPBMC','BI9JBgLaBge','q2X0rum','Axj1BIb0CMK','AwrHDgu','sZjwD0f5rue','suXKr1O','igfSCMvHzhK','B3vUDcbPCYa','ue9tva','Aw5Nigf0ia','AuDsBNm','BM8TBwfJ','Aw4UieeGnYa','C1biCKi','tLnfx1nfuLy','ywrK','BgvUz3rO','v1zMvM0','BgvHC2vFAw4','yxbWBhK','y2fuwM4','BIbSB2DPBG','wfDnseu','tunVD0jrwuq','ihrYAwfSihm','Dw46cGOGihy','CNvUlMr1zwW','BwPOB1i','Awf0','vNPKDxO','zhbevLK','q25kzgm','BNnLihnLCNy','CMvHy2HHyMW','CNra','C2LN','y2vPBa','C29YDa','lIbdB25Uzwm','BIb0AguGBwe','ieLMihLVDsa','zgTct2K','mtG0mKHzz1zgCG','kcGOlISPkYK','CMvZDwX0','ndmYotLdvLrQwwy','y2SGB24Uiem','C2PzAvy','uMn1Cxa','A1Howva','DgLVBL9Jyw4','B2XK','igzHBgWGyMe','C2HHmJu2','vezuBdC4EM0','BM9Uy2u','B3jRAw5NigK','AefiEfu','zwqGzM9Yihq','Cwf1rgK','DguGAxq6cGO','sMvluLe','C2XPy2u','BYb0AguGAw4','DfvktLO','igLUDgvYBMu','v1fxwLa','AwWGC3vWCg8','C2LNBMvKihi','idmWigrHExm','igrPzcbUB3q','Bsb5B3vYify','A2LUza','ihLVDxiGvMu','C2vHCMnO','CxL3zMO','A3zeC1m','DNi5x3m3uwu','s050tu4','ow1Kue10DwO','C2vYDMvYlG','C3bSAxq','B3uGyxjLig4','zMXVB3i','Cgf5Bg9Hza','sfDduLi','DgfYDhmGyxu','kYKRja','wJfTsZHKvZm','DgvYBMv0ihq','AgfZig5VDca','y3PIDeq','mda6mda6mda','zwz2r1a','nta2wK95uwfT','rNH4uMm','ExfRq24','zgnir3C','C0vqzLm','AgvYihrYAwe','Dg8GC2LNBIa','DgLVBIbJAgu','zNjVBq','AguGzNjLzsa','Awjyze4','D25hBgu','vgHLigXPy2u','A1PSEwK','rernsgW','zxj2zxi','zxiGAw4G','lYnWCMLJAw4','z2v0lxzLCMK','DMXrB0C','AxmGDg9Vig8','CMvHC29U','CNvUigXPy2u','q1DHrwS','ihjLDhvYBIa','ieb2zxjPCNu','CMLYDw4Gywm','BgvHC2u','qK9REKO','A0vwtNa','yMfZzty0','vgHPCYb2zxi','BgDhr3q','CK1rsg0','q291BgqGBM8','sM16se4','Cer2EwS','DMfSDwu','yNnJCMLIzsa','AK5urva','DgHLifzLCMK','DxnLCKLUzM8','Dw4GBg9NAw4','ogzjDw5WAW','zwrNwNu','BIb3yxmGy2e','seTHsfG','Aur1BfK','zM9Yig92zxi','BgqGDg8GA2u','DMLJzv9SAw0','uM1Iyum','we52Dei','BwfW','tLryvwS','BgX5igLMihK','icbUCg0GAw4','mtm4mfjZBK5tvG','Aw50','rKTOsw0','nta4ndyWBgzQzxjh','uhzbyMq','BcWGB3iGC3u','su9kwwm','zMLUz2vYChi','Axj1BIbZDwi','BLfdzfm','zxiGka','DgvZDa','y291BNqUifi','r0HSwvy','wgvXzvq','DgLVBL9Wyxm','BuP0EKO','C2HHCgu','C2nYAxb0Aw8','C2LNBMf0Dxi','icb2zxjPCNu','B2jQzwn0','yxnL','C2LNBMfS','A2PruNO','Agv4','yM9VBgvHBG','zwzvBve','lIbhzw5LCMe','AgLUzsbPCYa','CIbJB25Uzwm','yNnJCMLIztO','BNOXDefLvMK','CNnPB24','yxqGB3bLBNm','ig9UzsbMCM8','AwjLigf0ia','CMvWBgfJzq','Dg8GA2vLCca','wwnPu2m','A2v5x3jLDM8','C2v0ifzfuKK','DcbYzwfJAca','zgf0zs4Gsxq','Dcb0BYb0Agu','ksbHBMqGDgG','BM90zq','CgXHDgzVCM0','DgvYBMv0ige','vgfRs0q','igrHEq','BLLurfu','BNrZigf0ihq','BMCUifvWzge','DxnLCM5HBwu','igLZig5VDca','BgvKqMfJAW','C29U','Dw5RBM93BG','DcbHBMqGCNu','zMTRq3G','ue9tsvrjvKu','B3vYifzLCMK','DxnPBMCGAxq','mc4YlJa','zgf5igzYzwu','Bfnzq0O','z2Hpuwi','igXVz2LU','ugj6v3u','BKi2DfK1AeO','C3rYAw5N','zgLNzxn0','BwvZC2fNzq','CwT1sge','C2L6zq','Dg9Rzw4','rgrmtfC','y2HLy2TWB2K','DhjPywXFzw4','y2nVDw50lG','BNrZlIbfBwe','y3jLzgvUDgK','yMLUza','AKTXt0i','CgfYC2u','CMvJB2DUAxm','DhjPywXFzgu','nJe0mZm0swjPB0Xx','BwLUq2XPvMu','Dw50lIbsDw4','BwfJAgLUzuK','zw5Zzsb3yxm','BJOGihzLCMK','ywn0AxzLig8','BYb2ywXPzca','C2vHDf9SAw0','zxHW','ChjVyMXLBq','ywWGAgfZigu','ru9wyKC','ihn0B3bZihC','ChPxv20','BgLJzw5ZzuS','igrHExmUiem','A2v5CW','A2v5','s3b5Dvi','zwqUifj1BJO','C3rHDhvZ','zxiGBgLUAYa','BM8GBg9Uz2u','wLbrqKO','sezWzeO','CNvUigfJy28','zxn0igfUB3q','Es5PBG','DvveyNu','Dxbiy2G','y29UzMLNlMO','CgvYAw9Kx2u','DgvKihrVihK','igjLzw4GDxm','yLrzvMi','vgHPCYbSAwm','Dg9Y','Bg5tBgO','zw50CMLLCW','ihzHBgLKicG','BMv0D29YA0K','uKPzBxG','rM9uvfe','yxjJAa','rurKtxu','BNvTyMvY','vMvYAxj1BIa','wM9jCve','Bwf4','BMrLzc4Gu3u','Ag9ZDg5HBwu','A2LK','rhfRy2q','AgLUzsbOyxm','BYbYzxzHBgK','rKD6v2m','C3rHDguUANm','C3bRAq','mxPzEfndtW','zxaGCNvUBMK','ysb2ywXPzca','Aw9Ul2PZB24','ywXYzwfKEsa','oIaGDMvYAxi','CMvSzwfZzq','lNzLCMLYDw4','zLD1rNq','zxjLigLZig4','y2vSzwq','sxPfsum','zgvY','ihjLDM9Rzwq','ufHMuMG','Df9KDwu','BgvHC2uGDg8','r252yvq','Ahr0Chm6lY8','DgLVBL9LEha','CMvHy2HLzca','yxbRug4','C3rHBgWGlwC','uw9juvO','AhnntMC','uMvZDwjZy3i','ihzLCMLYDw4','vgHPCYbTywm','DxnLCG','Dfn4zNa','Ag9TzwrPCG','zxjPCNvUigW','C0XbtuS','zxiGywnJB3u','AYbPDcbWB2K','ienOzwnRihK','ANnVBG','zw5ZzsbRzxK','BgLJzw5Zzvm','vgHHDcbSAwm','DguGysbUzxC','y2XPx3rVB18','rxLUAhe','zwn0zwqGDg8','Dg9mB3DLCKm','C3rYAw5NAwy','rviSignOzwm','vLzZzKe','uNHXBg0','C2vYDMvY','AwrHDguGEw8','z1LzsMm','y2f0y2G','igfJDgL2zs4','Aw9PqMW','D29dC3u','zxCU','BM90ignVBM4','BMqGCNvUoIa','DMfSAwq','zu5QDuq','Aw50zxjUywW','BIbPCYbUB3q','DxrMoa','AMLzuu4','BMnLBgvKlIa','AM9PBG','ALfntg0','uLvox0Xjq0u','AhDF','BwjLCIbVzIa','ihr3BYbVDgG','yxbWBgLJyxq','yvr1reO','q3HYsgq','DhjPBq','C3vIC2nYAxa','B3nOtxO','yMvLBIbHyMW','C2LVBIbVzIa','zsb0BYb2ywW','yvjKrwm','Du9xBgO','ywDnAhe'];e=function(){return b5;};return e();}import{createHmac as ar}from'node:crypto';import{existsSync as as}from'node:fs';import{mkdir as at,readFile as au,rm as av,writeFile as aw}from'node:fs/promises';import ax from'node:os';import ay from'node:path';import{createHash as az}from'node:crypto';import aA from'node:os';var J=/^(lo|docker|veth|br-|virbr|vmnet|vboxnet|vnic|tun|tap|utun|llw|awdl|ap\d|zt|wg|nordlynx|tailscale|ham|anpi|bridge)/i;function W(){const aH=i,s={'ibXdN':function(a1,a2){return a1===a2;},'Rxqlm':aH(0x296)+aH(0x227)+'0','KpyuR':function(a1,a2){return a1>a2;}};let K=new Set(),a0=new Set();for(let [a1,a2]of Object[aH(0x350)](aA[aH(0x352)+aH(0x1f9)+'s']()))for(let a3 of a2??[]){if(a3[aH(0x1d9)]||!a3[aH(0x211)]||s[aH(0x2a2)](a3[aH(0x211)],s[aH(0x394)]))continue;let a4=a3[aH(0x211)][aH(0x390)+aH(0x2e7)]();a0[aH(0x249)](a4),J[aH(0x2dc)](a1)||K[aH(0x249)](a4);}return[...s[aH(0x33c)](K[aH(0x31c)],-0x1fff+-0x3*-0x2cd+0x1798)?K:a0][aH(0x25f)]();}function H(){const aI=i,n={'PXfRh':aI(0x380)};try{return aA[aI(0x2c1)]()[aI(0x307)];}catch{return process.env.USER??process.env.USERNAME??n[aI(0x372)];}}function g(){const aJ=i,n={'NPDsL':function(r){return r();},'qauDi':function(r,s){return r(s);},'kEVNp':aJ(0x26f),'JmzHN':aJ(0x2ea)};let o=[W()[aJ(0x1de)](',')||aJ(0x245),aA[aJ(0x35c)](),aA[aJ(0x300)](),aA[aJ(0x355)](),n[aJ(0x235)](H)];return aJ(0x1e1)+n[aJ(0x275)](az,n[aJ(0x2b5)])[aJ(0x21a)](o[aJ(0x1de)]('|'))[aJ(0x319)](n[aJ(0x2bb)])[aJ(0x278)](-0x1baf+-0x15*0x54+0x2293,0x267+-0x2*-0x13a+-0x4b3);}var b=ay[aK(0x1de)](ax[aK(0x382)](),aK(0x36b)),C=ay[aK(0x1de)](b,aK(0x348)+aK(0x30a)),k=ay[aK(0x1de)](b,aK(0x362)+'on'),R=aK(0x287)+aK(0x219)+aK(0x292)+aK(0x317);async function T(){await at(b,{'recursive':!(0x6*0x56d+-0x25ff+0x571),'mode':0x1c0});}async function I(n){const aL=aK,o={'XeqeT':function(r,s){return r(s);},'sjYiV':aL(0x1db),'dDhzt':aL(0x2de),'efUmQ':aL(0x347)};if(o[aL(0x2df)](as,n))try{return JSON[aL(0x326)](await au(n,o[aL(0x269)]));}catch{if(o[aL(0x1fa)]===o[aL(0x2ec)])o=!(-0x101f*0x2+-0x1de4+0x3e23);else return;}}async function f(){return await I(C)??{};}async function V(o){const aM=aK,r={'oshMz':function(t){return t();},'fWuFt':function(t){return t();}};await r[aM(0x1e9)](T);let s={...await r[aM(0x36c)](f),...o};return await aw(C,JSON[aM(0x391)+'y'](s,null,0x323+-0x1*0x2167+-0x1f*-0xfa)+'\x0a',{'mode':0x180}),s;}async function l(){const aN=aK,n={'HFpdJ':function(r){return r();}};let o=n[aN(0x342)](g);return(await n[aN(0x342)](f))[aN(0x32c)+'d']!==o&&await V({'machineId':o}),o;}function v(n){const aO=aK,o={'dpDVY':function(r,s,t){return r(s,t);},'qywfj':aO(0x2ea)};return o[aO(0x258)](ar,aO(0x26f),R)[aO(0x21a)](n)[aO(0x319)](o[aO(0x285)])[aO(0x278)](-0x4*0x89e+-0x267+0x24df*0x1,0x1*-0x26c6+0x1536*0x1+-0x18*-0xbc);}function h(n){const aP=aK;return n===null||typeof n!=aP(0x2e6)?JSON[aP(0x391)+'y'](n):Array[aP(0x207)](n)?'['+n[aP(0x2cd)](h)[aP(0x1de)](',')+']':'{'+Object[aP(0x33a)](n)[aP(0x25f)]()[aP(0x2cd)](o=>JSON[aP(0x391)+'y'](o)+':'+h(n[o]))[aP(0x1de)](',')+'}';}function A(n){const aQ=aK,o={'BFqwc':function(r,s,t){return r(s,t);},'WQWZP':function(r){return r();},'Dqkcd':function(r,s){return r(s);},'ZPQBJ':aQ(0x2ea)};return o[aQ(0x215)](ar,aQ(0x26f),R+':'+o[aQ(0x27c)](g))[aQ(0x21a)](o[aQ(0x35e)](h,n))[aQ(0x319)](o[aQ(0x341)]);}async function S(){const aR=aK,o={'WVfVm':function(a0,a1){return a0(a1);},'kjQRz':function(a0,a1){return a0!=a1;},'caTZn':aR(0x318),'AcFRV':aR(0x357),'ghOQb':function(a0,a1){return a0!=a1;}};let r=await o[aR(0x24b)](I,k);if(!r||o[aR(0x2e9)](typeof r[aR(0x25d)],o[aR(0x24e)])||o[aR(0x2e9)](typeof r[aR(0x323)+'al'],o[aR(0x24e)])||typeof r[aR(0x31f)+'nt']!=o[aR(0x1fd)]||!r[aR(0x2b3)]||o[aR(0x314)](typeof r[aR(0x2b3)]['p'],o[aR(0x24e)]))return;let {sig:s,...K}=r;if(A(K)===s)return K;}async function P(o){const aS=aK;await T();let r={...o,'sig':A(o)};await aw(k,JSON[aS(0x391)+'y'](r,null,0x1dc5+0x34e+-0x69d*0x5)+'\x0a',{'mode':0x180});}async function ee(){const aT=aK,n={'iGRns':function(o,r,s){return o(r,s);}};await n[aT(0x244)](av,k,{'force':!(0x1*0x27b+0x176f+-0x19ea*0x1)});}import{createPublicKey as aB,verify as aC}from'node:crypto';var N={'k1':aK(0x251)+aK(0x23e)+aK(0x270)+aK(0x1f3)+aK(0x289)+aK(0x2f1)+aK(0x216)+aK(0x229)},d=aK(0x311);function O(n){const aU=aK,o={'IOJYc':aU(0x2b6)};return Buffer[aU(0x2a0)](n[aU(0x2f6)](/-/g,'+')[aU(0x2f6)](/_/g,'/'),o[aU(0x2d7)]);}function L(s,K){const aV=aK,a0={'VVsfA':aV(0x2e2),'GnvaT':function(a3,a4){return a3<a4;},'HKaHX':aV(0x316),'bTYVb':function(a3,a4){return a3!==a4;}};let a1=s[aV(0x28b)]('.')[aV(0x2cd)](a3=>Number[aV(0x210)](a3,-0x2509+-0x10c4+-0x35d7*-0x1)||-0x10a2+0x1573*-0x1+-0x2615*-0x1),a2=K[aV(0x28b)]('.')[aV(0x2cd)](a3=>Number[aV(0x210)](a3,0xa58+-0x38f+-0x6bf)||-0x12ed+-0xc9b+0x4*0x7e2);for(let a3=-0x5*0x342+-0x2056+0x30a0;a0[aV(0x375)](a3,Math[aV(0x35a)](a1[aV(0x24a)],a2[aV(0x24a)]));a3+=-0xd*0x1fc+0x5*-0x3a9+0x2c1a){if(aV(0x1ef)!==a0[aV(0x2c6)]){let a4=(a1[a3]??-0x23cd+0x3e5*0x3+-0x1b9*-0xe)-(a2[a3]??-0x1af6+-0x1da+0x1cd0);if(a0[aV(0x34c)](a4,-0x11c*-0x1c+-0x5d7+-0x1*0x1939))return a0[aV(0x375)](a4,-0x24fa*-0x1+-0x1*-0x10e7+-0x35e1*0x1)?-(0x19*-0xd+-0x1b5*-0x15+-0x2293):0x21*-0x115+-0xec2*-0x1+0x53d*0x4;}else return{'problem':a0[aV(0x393)]};}return-0x1d*0x16+0x3b*0x19+-0x345;}function i(a,b){a=a-(-0x1b*-0x13e+0x76b*0x2+-0x2e8b);const c=e();let d=c[a];if(i['pEkDan']===undefined){var f=function(j){const l='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let m='',n='',o=m+f,p=(''+function(){return-0x23bc+0x2f*0x7e+0x64d*0x2;})['indexOf']('\x0a')!==-(-0x10c6+-0x2410+-0x1*-0x34d7);for(let q=0x262a+-0x205*0xa+0x47e*-0x4,r,s,t=-0xf67*0x2+0x907*0x1+0x15c7;s=j['charAt'](t++);~s&&(r=q%(-0xf18+0xaec+0x43*0x10)?r*(0x2*-0x8df+0x37e*0x7+-0xec*0x7)+s:s,q++%(-0x373*-0xa+-0x182b+-0xa4f))?m+=p||o['charCodeAt'](t+(-0x1df4+0x1328+-0xad6*-0x1))-(-0x111+-0x18a*-0x16+-0x20c1)!==0x9*0x446+-0x25b8+-0xbe?String['fromCharCode'](-0x13bf+-0x201*-0x2+0x10bc&r>>(-(-0x22b+-0x1a07+0x1c34)*q&-0x159b*0x1+-0x1378+-0x3f*-0xa7)):q:-0xc19*-0x1+-0x1*0xdeb+-0xe9*-0x2){s=l['indexOf'](s);}for(let u=-0x70c+0x4*0x123+0x280*0x1,v=m['length'];u<v;u++){n+='%'+('00'+m['charCodeAt'](u)['toString'](0x250e+0x1798+-0x3c96))['slice'](-(-0x896*0x4+-0x7c5*0x5+-0xa75*-0x7));}return decodeURIComponent(n);};i['kYbMYi']=f,i['QuhkvK']={},i['pEkDan']=!![];}const g=c[0x254f*-0x1+-0x268c+0x4bdb];i['CHLSvb']!==g&&(i['QuhkvK']={},i['CHLSvb']=g);const h=i['QuhkvK'][a];if(h===undefined){const j=function(k){this['hKELDx']=k,this['QjADyp']=[-0x1*0x9f3+-0x503+-0x1*-0xef7,-0x18*0x122+-0x1*0x1f51+-0x11*-0x371,0xfe*0x1d+0x1317+-0x2fdd],this['UCSIwp']=function(){return'newState';},this['bvwYHR']='\x5c\x77\x2b\x20\x2a\x5c\x28\x5c\x29\x20\x2a\x7b\x5c\x77\x2b\x20\x2a',this['hbComL']='\x5b\x27\x7c\x22\x5d\x2e\x2b\x5b\x27\x7c\x22\x5d\x3b\x3f\x20\x2a\x7d';};j['prototype']['CBjyYI']=function(){const k=new RegExp(this['bvwYHR']+this['hbComL']),l=k['test'](this['UCSIwp']['toString']())?--this['QjADyp'][-0x46*-0x22+0x2398+-0x2ce3*0x1]:--this['QjADyp'][0xb97+-0x1540+0x9a9*0x1];return this['yjOjBn'](l);},j['prototype']['yjOjBn']=function(k){if(!Boolean(~k))return k;return this['DGkrDG'](this['hKELDx']);},j['prototype']['DGkrDG']=function(k){for(let l=0x758+0xc3f*0x1+0x127*-0x11,m=this['QjADyp']['length'];l<m;l++){this['QjADyp']['push'](Math['round'](Math['random']())),m=this['QjADyp']['length'];}return k(this['QjADyp'][0x116f*0x1+0xcd4+-0x3d*0x7f]);},(''+function(){return-0x1*0x11b+-0x1416+0x1f*0xaf;})['indexOf']('\x0a')===-(0xafe+0xbe9+-0x7a2*0x3)&&new j(i)['CBjyYI'](),d=i['kYbMYi'](d),i['QuhkvK'][a]=d;}else d=h;return d;}function m(a0,a1,a2={}){const aW=aK,a3={'qweoO':function(aa,ab){return aa!=ab;},'Eynhq':aW(0x2e6),'Rcuqp':aW(0x320)+aW(0x205),'YciSc':aW(0x328)+aW(0x2ca)+'it','jiYQN':aW(0x349)+aW(0x208),'CxrHd':aW(0x1e8)+aW(0x2e0)+aW(0x373),'wnGle':aW(0x34d)+aW(0x32d)+aW(0x371)+aW(0x2ed)+aW(0x38c)+aW(0x2f4)+aW(0x281)+aW(0x20b)+aW(0x321),'BOkzJ':aW(0x20f)+aW(0x31d),'ShhQf':aW(0x37f)+aW(0x2ee)+aW(0x340)+aW(0x2ef)+aW(0x34a)+aW(0x30f)+aW(0x343)+aW(0x32b)+aW(0x369)+aW(0x2c2),'dkBOi':aW(0x38b)+aW(0x389)+aW(0x308)+aW(0x327)+aW(0x33d)+aW(0x2e5)+aW(0x24f),'pDvyk':aW(0x24c)+aW(0x1d7),'mjhoR':aW(0x30b),'sPHrB':function(aa,ab){return aa!=ab;},'lgGGt':aW(0x318),'EDdMu':aW(0x2e2),'HWCRR':aW(0x2e4)+'e','hAHxU':function(aa,ab){return aa(ab);},'KNtMN':aW(0x370),'jNTEP':aW(0x363),'MNeFS':function(aa,ab,ac,ad,af){return aa(ab,ac,ad,af);},'efvGP':function(aa,ab){return aa!==ab;},'sLAMK':aW(0x34f),'rMQHm':aW(0x359),'yqkCn':function(aa,ab){return aa(ab);},'jQMLm':aW(0x286),'ZhVPW':function(aa,ab){return aa!==ab;},'uUDbu':function(aa,ab){return aa!==ab;},'hsMNg':function(aa,ab){return aa!==ab;},'lSYCJ':function(aa,ab){return aa<ab;},'edgZu':aW(0x38d)+aW(0x26d)};if(!a0||typeof a0!=a3[aW(0x38e)]||a3[aW(0x247)](typeof a0['p'],aW(0x318))||typeof a0['s']!=a3[aW(0x2b8)]||a3[aW(0x218)](typeof a0[aW(0x35d)],a3[aW(0x2b8)]))return{'problem':a3[aW(0x356)]};let {p:a4,s:a5,kid:a6}=a0,a7=N[a6];if(!a7)return{'problem':a3[aW(0x28f)]};let a8=!(0xa57*0x3+0x27*0x43+-0x2939);try{if(aW(0x21b)===aW(0x259))try{return a0[aW(0x2c1)]()[aW(0x307)];}catch{return a3.env.USER??a4.env.USERNAME??aW(0x380);}else{let ab=a3[aW(0x273)](aB,{'key':Buffer[aW(0x2a0)](a7,aW(0x2b6)),'format':a3[aW(0x288)],'type':a3[aW(0x2bf)]});a8=a3[aW(0x1f5)](aC,null,Buffer[aW(0x2a0)](a4,aW(0x1db)),ab,O(a5));}}catch{a8=!(-0x1dcf+0xcfc+0x2*0x86a);}if(!a8)return{'problem':a3[aW(0x28f)]};let a9;try{if(a3[aW(0x297)](a3[aW(0x384)],a3[aW(0x2b9)]))a9=JSON[aW(0x326)](a3[aW(0x29a)](O,a4)[aW(0x239)](aW(0x1db)));else return a7===null||VHIole[aW(0x218)](typeof a8,VHIole[aW(0x38e)])?a9[aW(0x391)+'y'](aa):ab[aW(0x207)](ac)?'['+ad[aW(0x2cd)](af)[aW(0x1de)](',')+']':'{'+ag[aW(0x33a)](ah)[aW(0x25f)]()[aW(0x2cd)](aD=>al[aW(0x391)+'y'](aD)+':'+am(an[aD]))[aW(0x1de)](',')+'}';}catch{if(a3[aW(0x297)](aW(0x286),a3[aW(0x1df)])){let af=a2+(aW(0x2a9)+'g'),ai=a3[aW(0x2f6)](/^https?:\/\//,'');switch(a4[aW(0x2ad)]){case a3[aW(0x26a)]:return aW(0x1fe)+aW(0x23c)+aW(0x334)+aW(0x35b)+aW(0x2be)+aW(0x2f7)+aW(0x310)+':\x20'+af;case a3[aW(0x2f8)]:return aW(0x37f)+aW(0x35f)+aW(0x240)+aW(0x34b)+aW(0x274)+aW(0x2a1)+aW(0x231)+aW(0x1e3)+aW(0x385)+aW(0x322)+aW(0x27d)+aW(0x25c)+ai+(aW(0x209)+aW(0x344)+aW(0x29d)+aW(0x2d6)+aW(0x2f0)+'\x20')+af;case a3[aW(0x1dc)]:case a3[aW(0x1e6)]:return aW(0x1fe)+aW(0x2d9)+aW(0x2e3)+aW(0x1da)+aW(0x399)+aW(0x387)+aW(0x21f)+aW(0x243)+aa+aW(0x217);case aW(0x1e8)+aW(0x26c)+aW(0x36e):case aW(0x1e8)+aW(0x377)+aW(0x21d):return aW(0x1fe)+aW(0x2d9)+aW(0x2e3)+aW(0x2c5)+aW(0x1dd)+aW(0x37d)+aW(0x2f5)+af;case aW(0x331)+aW(0x201)+aW(0x205):return aW(0x1fc)+aW(0x241)+aW(0x368)+aW(0x32f)+aW(0x261)+aW(0x203)+aW(0x1e2)+aW(0x234)+aW(0x226)+aW(0x1f4)+'\x20'+ab+aW(0x217);case aW(0x2f9)+aW(0x230):return a3[aW(0x2a3)];case a3[aW(0x2b4)]:return a3[aW(0x22a)];case aW(0x20f)+aW(0x33b):return a3[aW(0x263)];case a3[aW(0x2bc)]:return aW(0x2a4)+aW(0x25a)+aW(0x22c)+ac+(aW(0x280)+aW(0x2b0)+aW(0x366)+aW(0x27e)+aW(0x1f0)+aW(0x262)+aW(0x2fa)+aW(0x1e0)+aW(0x248)+aW(0x392)+aW(0x386)+aW(0x305)+aW(0x1f1)+aW(0x28a));case aW(0x38d)+aW(0x26d):return ad;default:return aW(0x1fe)+aW(0x2d9)+aW(0x2e3)+aW(0x1da)+aW(0x351)+(af[aW(0x33e)]??a3[aW(0x255)])+').';}}else return{'problem':aW(0x2e2)};}return a9['v']!==0x159f+-0x624+-0xf7a||a3[aW(0x20e)](a9[aW(0x35d)],a6)?{'problem':a3[aW(0x356)]}:typeof a9['fp']!=aW(0x318)||a9['fp']!==a1?{'problem':aW(0x2d8)+aW(0x2d2)}:a3[aW(0x346)](a2[aW(0x271)],void(0x4*-0x84e+0x358*0x7+-0x274*-0x4))&&a3[aW(0x37c)](a9[aW(0x271)],a2[aW(0x271)])?{'problem':aW(0x271)}:a9[aW(0x32a)+aW(0x2f2)]&&a3[aW(0x313)](L(d,a9[aW(0x32a)+aW(0x2f2)]),0x1fa3+-0x2614+0x671)?{'payload':a9,'problem':a3[aW(0x2c4)]}:{'payload':a9};}var M=aK(0x376)+aK(0x2aa)+aK(0x254)+aK(0x345),p=(0x561+0x1c9e+-0x975*0x3)*(0x1*0x12cb+0x1b47+-0x1*0x2dd6)*(0x2*0x533+0x1c70+-0x22ee),ie=(-0x1bbe+0xa1f+0x3d*0x4a)*p,oe=(-0x5d*-0x25+-0x5*0x16e+0x1*-0x63c)*p,$=(0x2390+0x1314+-0x2*0x1b43)*p,se=0x5e7+0x2ac9+-0xb0*0xe,ae=(-0x127f+-0x1c93+0x303e)*(-0x1581+0x1*0x263f+-0xcd6);function B(n){const aX=aK;return(process.env.VERIRUN_LICENSE_SERVER??n??M)[aX(0x2f6)](/\/+$/,'');}async function G(){const aY=aK,o={'FGzWc':function(a0){return a0();},'EOVbG':aY(0x33b),'jKqOB':aY(0x31d)};let r=await o[aY(0x361)](f),s=B(r[aY(0x38a)+aY(0x2a7)]),K=process.env.VERIRUN_LICENSE_KEY?.[aY(0x1e7)]();if(K)return{'kind':o[aY(0x335)],'value':K,'server':s};if(r[aY(0x31d)])return{'kind':o[aY(0x325)],'value':r[aY(0x31d)],'server':s};if(r[aY(0x338)+'ey'])return{'kind':o[aY(0x335)],'value':r[aY(0x338)+'ey'],'server':s};}async function j(s){const aZ=aK,K={'DDMHl':function(a3,a4){return a3!==a4;},'XWMHE':aZ(0x265)+aZ(0x291),'kXNYP':function(a3,a4,a5){return a3(a4,a5);},'GHxaU':function(a3,a4){return a3(a4);},'tUJNZ':aZ(0x2ea),'DdLLW':aZ(0x242),'HdeIK':function(a3,a4){return a3!==a4;},'CWaEk':function(a3,a4){return a3!=a4;},'fkkCx':aZ(0x2eb),'vlQoG':function(a3){return a3();},'PvAbd':function(a3,a4){return a3===a4;},'aTuDJ':aZ(0x38d)+aZ(0x26d),'nYTDU':function(a3,a4){return a3<=a4;},'Vzduz':function(a3,a4){return a3*a4;},'hdqKP':aZ(0x1ed),'tSxfp':aZ(0x2cb)};let a0=new AbortController(),a1=K[aZ(0x26b)](setTimeout,()=>a0[aZ(0x224)](),se),a2=K[aZ(0x1f6)](ap,0x943*0x3+-0x2f8*0xb+-0x1*-0x4eb)[aZ(0x239)](K[aZ(0x27a)]);try{let a3=await fetch(s[aZ(0x395)]+(aZ(0x202)+aZ(0x213)+aZ(0x23d)),{'method':K[aZ(0x31e)],'headers':{'Content-Type':aZ(0x1e4)+aZ(0x367)},'signal':a0[aZ(0x2e8)],'body':JSON[aZ(0x391)+'y']({[s[aZ(0x282)]]:s[aZ(0x2bd)],'fingerprint':await l(),'hostname':aq[aZ(0x35c)](),'os':aq[aZ(0x300)]()+'\x20'+aq[aZ(0x36a)](),'cliVersion':d,'nonce':a2})});if(!a3['ok']&&K[aZ(0x1ff)](a3[aZ(0x33e)],-0x102e+-0x25eb*-0x1+-0x6b9*0x3))return{'reachable':!(-0x8d1*0x3+0xa76*0x1+-0x17*-0xb2)};let a4=await a3[aZ(0x388)]()[aZ(0x398)](()=>{});if(!a4||K[aZ(0x2af)](typeof a4[aZ(0x1d7)],K[aZ(0x30d)]))return{'reachable':!(0x1031+0x210a*-0x1+-0x10da*-0x1)};if(!a4[aZ(0x1d7)])return{'reachable':!(-0x1ef7+0x5*-0x6f3+0x41b6),'result':a4};let a5=await K[aZ(0x2ab)](l),a6=m(a4[aZ(0x2b3)],a5,{'nonce':a2});return K[aZ(0x2d5)](a6[aZ(0x333)],K[aZ(0x1e5)])?{'reachable':!(-0x8*0xfc+-0x1*0xcd+0x8ad*0x1),'result':{...a4,'valid':!(-0x8d9+0xf31+-0x657*0x1),'reason':aZ(0x38d)+aZ(0x26d)}}:!a6[aZ(0x28e)]||a6[aZ(0x333)]||K[aZ(0x304)](K[aZ(0x257)](a6[aZ(0x28e)][aZ(0x332)],-0x1100*-0x2+0x2537*0x1+-0x434f),Date[aZ(0x237)]())?{'reachable':!(-0x168f+0x6bb+-0x1*-0xfd4),'result':{...a4,'valid':!(-0x815*0x1+-0xd6d*0x1+-0x1*-0x1583),'reason':aZ(0x24c)+aZ(0x1d7)}}:{'reachable':!(-0x1*-0x1afa+0xe07+-0x2901),'result':a4,'lease':a4[aZ(0x2b3)]};}catch{if(K[aZ(0x236)]!==K[aZ(0x381)])return{'reachable':!(-0x2607+0x1*0x1dd5+0x1*0x833)};else{if(nYvzbo[aZ(0x2a6)](s[aZ(0x324)]()[aZ(0x239)]()[aZ(0x222)]('\x0a'),-(0x1417+-0xbcb+-0x84b)))return;return t[aZ(0x239)]()[aZ(0x284)](aZ(0x265)+aZ(0x291))[aZ(0x239)]()[aZ(0x238)+aZ(0x34e)](K)[aZ(0x284)](nYvzbo[aZ(0x250)]);}}finally{clearTimeout(a1);}}var ce=aK(0x37f)+aK(0x2ee)+aK(0x1d5)+aK(0x38f)+aK(0x283)+aK(0x2b2)+aK(0x2dd)+aK(0x253)+aK(0x383)+aK(0x225)+aK(0x2f3)+aK(0x1fb)+aK(0x33f)+aK(0x29e)+aK(0x246)+aK(0x312)+aK(0x252)+aK(0x290)+aK(0x21e)+aK(0x2cf)+aK(0x28c)+aK(0x39c),_=aK(0x2b7)+aK(0x1eb)+aK(0x358)+aK(0x2ac)+aK(0x2c9)+aK(0x365)+aK(0x306)+aK(0x276)+aK(0x2d0)+aK(0x37a)+aK(0x2b1)+aK(0x23a)+aK(0x2dc);function le(r,s){const b0=aK,K={'ioiBl':b0(0x1e8)+b0(0x26c)+b0(0x36e),'QnLAs':b0(0x331)+b0(0x201)+b0(0x205),'EzcIN':b0(0x34d)+b0(0x32d)+b0(0x371)+b0(0x2ed)+b0(0x38c)+b0(0x2f4)+b0(0x281)+b0(0x20b)+b0(0x321),'XNvtB':b0(0x20f)+b0(0x33b),'qkuHa':b0(0x38b)+b0(0x389)+b0(0x308)+b0(0x327)+b0(0x33d)+b0(0x2e5)+b0(0x24f)};let a0=s+(b0(0x2a9)+'g'),a1=s[b0(0x2f6)](/^https?:\/\//,'');switch(r[b0(0x2ad)]){case b0(0x320)+b0(0x205):return b0(0x1fe)+b0(0x23c)+b0(0x334)+b0(0x35b)+b0(0x2be)+b0(0x2f7)+b0(0x310)+':\x20'+a0;case b0(0x328)+b0(0x2ca)+'it':return b0(0x37f)+b0(0x35f)+b0(0x240)+b0(0x34b)+b0(0x274)+b0(0x2a1)+b0(0x231)+b0(0x1e3)+b0(0x385)+b0(0x322)+b0(0x27d)+b0(0x25c)+a1+(b0(0x209)+b0(0x344)+b0(0x29d)+b0(0x2d6)+b0(0x2f0)+'\x20')+a0;case b0(0x349)+b0(0x208):case b0(0x1e8)+b0(0x2e0)+b0(0x373):return b0(0x1fe)+b0(0x2d9)+b0(0x2e3)+b0(0x1da)+b0(0x399)+b0(0x387)+b0(0x21f)+b0(0x243)+s+b0(0x217);case K[b0(0x39a)]:case b0(0x1e8)+b0(0x377)+b0(0x21d):return b0(0x1fe)+b0(0x2d9)+b0(0x2e3)+b0(0x2c5)+b0(0x1dd)+b0(0x37d)+b0(0x2f5)+a0;case K[b0(0x20c)]:return b0(0x1fc)+b0(0x241)+b0(0x368)+b0(0x32f)+b0(0x261)+b0(0x203)+b0(0x1e2)+b0(0x234)+b0(0x226)+b0(0x1f4)+'\x20'+s+b0(0x217);case b0(0x2f9)+b0(0x230):return K[b0(0x212)];case b0(0x20f)+b0(0x31d):return b0(0x37f)+b0(0x2ee)+b0(0x340)+b0(0x2ef)+b0(0x34a)+b0(0x30f)+b0(0x343)+b0(0x32b)+b0(0x369)+b0(0x2c2);case K[b0(0x2cc)]:return K[b0(0x31b)];case b0(0x24c)+b0(0x1d7):return b0(0x2a4)+b0(0x25a)+b0(0x22c)+s+(b0(0x280)+b0(0x2b0)+b0(0x366)+b0(0x27e)+b0(0x1f0)+b0(0x262)+b0(0x2fa)+b0(0x1e0)+b0(0x248)+b0(0x392)+b0(0x386)+b0(0x305)+b0(0x1f1)+b0(0x28a));case b0(0x38d)+b0(0x26d):return _;default:return b0(0x1fe)+b0(0x2d9)+b0(0x2e3)+b0(0x1da)+b0(0x351)+(r[b0(0x33e)]??b0(0x30b))+').';}}async function D(o,r){const b1=aK,s={'FxxRc':function(K){return K();},'woCsu':function(K,a0){return K(a0);},'uOWlj':function(K,a0){return K(a0);}};try{let K=await s[b1(0x299)](S);await s[b1(0x39b)](P,{'credential':s[b1(0x1ee)](v,o[b1(0x2bd)]),'checkpoint':Math[b1(0x35a)](Date[b1(0x237)](),K?.[b1(0x31f)+'nt']??-0x1e2d+0x2218+-0x3eb*0x1),'lease':r});}catch{}}async function U(r){const b2=aK,s={'dcHGw':function(a3){return a3();},'vTsje':function(a3,a4,a5){return a3(a4,a5);},'ILdGZ':function(a3,a4){return a3<a4;},'gYYJc':function(a3,a4){return a3-a4;}};let K=await s[b2(0x29b)](S);if(!K||K[b2(0x323)+'al']!==v(r[b2(0x2bd)]))return;let a0=await l(),a1=s[b2(0x214)](m,K[b2(0x2b3)],a0);if(!a1[b2(0x28e)])return;let a2=s[b2(0x23f)](Date[b2(0x237)](),s[b2(0x397)](K[b2(0x31f)+'nt'],ae));return{'payload':a1[b2(0x28e)],'clockRolledBack':a2};}async function F(){const b3=aK,K={'NTXUk':function(a6,a7){return a6(a7);},'wIVSb':b3(0x2b6),'JeKRQ':b3(0x370),'RJYmx':b3(0x363),'FoTTQ':b3(0x1db),'nQCdS':function(a6,a7){return a6*a7;},'sEPfS':function(a6,a7){return a6<a7;},'kZlyi':function(a6,a7){return a6*a7;},'FKhIm':function(a6,a7){return a6<a7;},'jqmPi':function(a6){return a6();},'pzWWm':function(a6,a7,a8){return a6(a7,a8);},'IzEIC':function(a6,a7){return a6-a7;},'QoIQZ':function(a6,a7){return a6*a7;},'TakKD':function(a6,a7){return a6<a7;},'pdITg':function(a6,a7){return a6<a7;},'CltEC':b3(0x22b),'iDulY':function(a6,a7){return a6/a7;},'czbtD':function(a6,a7){return a6-a7;},'kVrSO':b3(0x358)+b3(0x294)+b3(0x1ea)+b3(0x1ec)+b3(0x396)+b3(0x200)+b3(0x204)+b3(0x2c8)+b3(0x27f)+b3(0x223)+b3(0x260)+b3(0x2fd)+b3(0x27b)+b3(0x30c)+b3(0x32e)+b3(0x22f)+'mi'};let a0=await G();if(!a0)return{'ok':!(0x221*0x9+-0x1770+0x448),'message':ce};let a1=await U(a0),a2=Date[b3(0x237)](),a3=a1?a2-K[b3(0x2da)](a1[b3(0x28e)][b3(0x256)],0x17b6*-0x1+-0x10ec+0x2c8a):Number[b3(0x30e)+b3(0x1f7)+'Y'],a4=a1!==void(0x2e*0x1e+0x874+0x4*-0x376)&&!a1[b3(0x22d)+b3(0x309)]&&K[b3(0x29c)](a2,K[b3(0x2a5)](a1[b3(0x28e)][b3(0x332)],-0x5*-0x46c+0x1cd*-0xb+0x1*0x19b));if(a1&&K[b3(0x2d3)](L(d,a1[b3(0x28e)][b3(0x32a)+b3(0x2f2)]),0x2274+0x1e*0xd9+-0x3be2))return{'ok':!(0x1a1c+0x10d2+-0x2aed),'message':_};if(a4&&a3<ie)return{'ok':!(-0x25*-0xb3+-0x35a+-0x1685)};let a5=await K[b3(0x2ce)](j,a0);if(a5[b3(0x25b)+'e']&&a5[b3(0x2b3)])return await D(a0,a5[b3(0x2b3)]),m(a5[b3(0x2b3)],await K[b3(0x22e)](l))[b3(0x333)]===b3(0x38d)+b3(0x26d)?{'ok':!(0x2*-0xe8a+0x84b*-0x1+0x2560),'message':_}:{'ok':!(0x1f41+-0x207*-0x2+-0x3*0xbc5)};if(a5[b3(0x25b)+'e']&&a5[b3(0x266)]&&!a5[b3(0x266)][b3(0x1d7)])return{'ok':!(0xba5+-0x5*-0x755+-0x304d),'message':K[b3(0x337)](le,a5[b3(0x266)],a0[b3(0x395)])};if(a1&&!a1[b3(0x22d)+b3(0x309)]){let a6=K[b3(0x36f)](a2,K[b3(0x37b)](a1[b3(0x28e)][b3(0x256)],0x25f9+0x15f9+0x63a*-0x9));if(K[b3(0x302)](a6,oe))return{'ok':!(0x1f73+0x1606+-0x3579)};if(K[b3(0x228)](a6,$)){if(K[b3(0x23b)]!==b3(0x206)){let a7=Math[b3(0x28d)](K[b3(0x2c7)](a6,p)),a8=Math[b3(0x35a)](0xd+-0x15b5*0x1+-0x1*-0x15a9,Math[b3(0x25e)](K[b3(0x295)]($,a6)/p));return{'ok':!(0x1711+0x4e*0x5d+-0x3367),'note':b3(0x358)+b3(0x294)+b3(0x378)+b3(0x21c)+b3(0x25a)+b3(0x2a8)+a7+(b3(0x339)+b3(0x1f8)+b3(0x279)+b3(0x293)+b3(0x360)+b3(0x2fc)+b3(0x336)+b3(0x272)+'n\x20')+a8+b3(0x303)+(a8===-0x1*-0x17ef+-0x32a*-0x3+-0x2c9*0xc?'':'s')+'.'};}else{let aa=bExmEH[b3(0x2ce)](a3,{'key':a4[b3(0x2a0)](a5,bExmEH[b3(0x220)]),'format':bExmEH[b3(0x277)],'type':bExmEH[b3(0x353)]});a6=a7(null,a8[b3(0x2a0)](a9,bExmEH[b3(0x354)]),aa,bExmEH[b3(0x2ce)](aa,ab));}}return{'ok':!(0x283+-0x13f3*0x1+0x5f*0x2f),'message':K[b3(0x233)]};}return{'ok':!(0x45*0x7b+-0x1499*-0x1+-0x35bf*0x1),'message':b3(0x2ba)+b3(0x2fb)+b3(0x2c0)+b3(0x2ae)+b3(0x25a)+b3(0x2db)+a0[b3(0x395)]+(b3(0x2fe)+b3(0x36d)+b3(0x330)+b3(0x374)+b3(0x26e)+b3(0x268)+b3(0x1f8)+b3(0x279)+b3(0x301)+b3(0x1d6)+b3(0x37e)+b3(0x315))};}async function ue(){const b4=aK,n={'eNjuD':function(r){return r();}};let o=await n[b4(0x1d8)](F);if(!o['ok'])throw new Error(o[b4(0x31a)]??b4(0x358)+b4(0x1e8)+b4(0x29f)+b4(0x20d)+'d.');return{'note':o[b4(0x2ff)]};}export{M as DEFAULT_LICENSE_SERVER,ue as assertLicensed,j as checkWithServer,ee as clearLicenseState,F as evaluateLicense,l as getMachineId,f as loadGlobalConfig,D as persistLease,U as readStoredLease,G as resolveCredential,B as resolveServer,V as saveGlobalConfig};
1
+ const aS=i;(function(n,o){const aH=i,r=n();while(!![]){try{const s=-parseInt(aH(0x109))/(-0xeff*0x2+-0xe4c+0x2c4b)+parseInt(aH(0x1e0))/(-0x2*-0x1de+0x3*0x106+-0x6cc)*(-parseInt(aH(0x124))/(0x1*-0x20b5+0x1087*-0x1+0x313f*0x1))+-parseInt(aH(0x28b))/(-0x1*0x1a84+-0x20f3+0x3b7b*0x1)*(-parseInt(aH(0x17a))/(0x7de*0x1+-0x244e+0x1c75))+-parseInt(aH(0x11c))/(0x45*-0x6f+0x22d6+-0x4e5)*(parseInt(aH(0x202))/(0x119*-0x8+0xe7d+-0x1*0x5ae))+parseInt(aH(0x1dd))/(-0x4*0x4a3+0xb77+0x71d)*(-parseInt(aH(0xe5))/(-0x103a+0x1ccb+0xc88*-0x1))+-parseInt(aH(0x15d))/(0x206d*-0x1+0x1a56*-0x1+0x3acd)*(-parseInt(aH(0x24f))/(0x1*-0x752+0xd1*0x2e+-0x1e31))+-parseInt(aH(0x1b7))/(-0x1078+-0x2*-0x1345+-0x1606)*(-parseInt(aH(0x19c))/(0xfe0+0xfa3*0x1+-0x1f76));if(s===o)break;else r['push'](r['shift']());}catch(t){r['push'](r['shift']());}}}(e,0x116eff+0x1*0x117be7+0x1*-0x13d834));const c=(function(){const aI=i,n={'aqayc':aI(0x1b4)};let o=!![];return function(r,s){const aJ=aI;if(aJ(0x1b4)!==n[aJ(0xec)])return;else{const Y=o?function(){const aK=aJ;if(s){const a0=s[aK(0x201)](r,arguments);return s=null,a0;}}:function(){};return o=![],Y;}};}()),a=c(this,function(){const aL=i,n={'ecGhp':aL(0x197),'CGsVN':function(o,r){return o!==r;},'LZqiN':function(o,r){return o===r;},'pXxCj':aL(0x25d),'YWPZP':aL(0x235)+aL(0x298)};if(n[aL(0x191)](a[aL(0x1c3)]()[aL(0x22b)]()[aL(0x222)]('\x0a'),-(0xd*0x61+-0x2*-0x715+-0x1316))){if(n[aL(0x1eb)](n[aL(0x20f)],aL(0x25d)))return;else return s(aL(0x1db),t)[aL(0x10b)](Y)[aL(0x125)](n[aL(0x25b)])[aL(0x247)](0x2410+-0x3*0x48b+-0x166f,-0x699*-0x2+-0x1f3*-0x8+-0x1cba);}return a[aL(0x22b)]()[aL(0x2a5)](aL(0x235)+aL(0x298))[aL(0x22b)]()[aL(0x147)+aL(0x1cd)](a)[aL(0x2a5)](n[aL(0x10d)]);});a();import{randomBytes as ap}from'node:crypto';import aq from'node:os';import{createHmac as ar}from'node:crypto';import{existsSync as as}from'node:fs';import{mkdir as at,readFile as au,rm as av,writeFile as aw}from'node:fs/promises';import ax from'node:os';function e(){const bf=['D3HPtNC','Aw9Ul2PZB24','DLzytvq','CKXjz0y','DxnPBMCGAxq','CMvHy2HLzca','zKTxC0q','yMLUza','lIbhzw5LCMe','DcbYzwfJAca','qK5uuMe','ywjVCNq','BwfJ','Dw4GBg9NAw4','C3bRAq','CMvHy2HHyMW','C1jXtK4','Dg9Y','BwvZC2fNzq','BgPnwuC','Dw5RBM93BL8','DgLVBL9LEha','yNnJCMLIztO','BMrLza','igeGyNjVD3m','DvD2v3i','Ag9cvxm','CLjTDvy','r0fJvNe','CIbJB25Uzwm','Cgf5Bg9Hza','C2HHmJu2','zxiGyxqG','nty5otq5nKPtr3rOCG','CNvUigfJy28','BI9JBgLaBge','mZqXnti5ofjUr0P1Aq','BIbPCYbUB3q','Aurose8','BYbYzxzHBgK','BJOGihzLCMK','Df9KDwu','BM9Uy2u','BMrLzc4Gu3u','ksbHBMqGDgG','zxjPCNvUige','BwfW','tfPXAu4','BfPet3C','C2LVBIbVzIa','CNvUlMr1zwW','rM5iqKC','y2XPx3rVB18','C2LNBMf0Dxi','EgLTDw0GBNu','y2XVy2TsB2W','DgHLifzLCMK','B3vUDcbPCYa','rviSignOzwm','CfLby3C','wLvftLK','q291BgqGBM8','qLvJu1i','BgvHC2vFAw4','ue9tva','AgLUzsbPCYa','CK5srue','B3vYifzLCMK','yMLhvMO','yxbWBhK','mty5mdvNAMPQyKu','BM90zq','uLvox0Xjq0u','zM9csvi','uNfPD1q','yMfZzty0','DxL0A3u','Eg5Iwwi','qMjLtLu','A2v5','C3rHDhvZ','Aw5Nigf0ia','AYbPDcbWB2K','CfH4q2O','AwnHy2XZ','DePvsfu','C3rYAw5N','D09ItK0','BgLJzw5ZzuS','run5wLK','rxz2vKO','yK9iue8','zxHW','z0P5vfe','CNLhEKS','C2nYAxb0Aw8','twfVquy','zw1rvfG','v3j3uw8','BIb3yxmGy2e','ihzHBgLKicG','A1zkvxG','Aw5KzxHpzG','AxrFzxHJzwu','ww9tCuW','Ag9ZDg5HBwu','z1n5u08','DgLVBIbJAgu','y2XNALm','CgXHDgzVCM0','yITcsvrADxK','Dg9tDhjPBMC','qMLKzKm','uxbbDuK','CgfYC2u','DufPAgi','igjLzw4GDxm','Dg8GC2LNBIa','z1zyq0m','Dez3twu','CMvJB2DUAxm','kcGOlISPkYK','ugzlEeS','uM5Zq0W','DNi5x3m3uwu','vgHPCYbTywm','uuX4yKu','tunVD0jrwuq','vvH0zgC','BgvHC2uGDg8','DxiGC3vIC2m','z1nnCKy','C2vYDMvYlG','DhjPBq','Dg9TyxrPy2e','DMfSDwu','Dg9mB3DLCKm','Ag9TzwrPCG','lIbszwXLyxm','C2XPy2u','uNrgugC','AhDF','B3jRAw5NigK','CMLYDw4Gywm','C2LNBMfS','Awf0','B25Uzwn0ihq','mtfUzKHLt04','rvbnrLm','B0P6yLm','zw5Zzs92ywW','uMvZDwjZy3i','zxiGBgLUAYa','sgDMvg8','zeXRtK8','Ahr0Chm6lY8','igrHEq','txP3rfG','wgrjz2e','zwnhAha','zen2Bg0','zvH3uNK','Dcb0BYb0Agu','mc4YlJe','C2L6zq','qNb3ufm','DMfSAwq','DxnLCKLUzM8','BIbSB2DPBG','zxjPCNvUigW','y291BNqUifi','s2rjwvC','s1fqr28','BNnLihnLCNy','CNvUigXPy2u','tu1lvK4','l2fJy291BNq','BM8TBwfJ','Efroufy','sNnpsLq','l2DYyw50oNi','vw9lv3q','CNnPB24','tfPVA3q','igrPzcbUB3q','DgLVBL9Jyw4','ieb2zxjPCNu','zw50CMLLCW','igLUDgvYBMu','AwjLigf0ia','C2LN','BMnLBgvKlIa','ienOzwnRihK','zw5ZzsbRzxK','vgHPCYbHy2m','vgHPCYbSAwm','wgnAsu4','ExfzBMS','quTNDLC','yxjJAa','ow1Kue10DwO','BNvTyMvY','zgLY','tvLZwfa','ChjVyMXLBq','lNzLCMLYDw4','zNDzBMC','ngfsq1vArG','yxnL','wJfTsZHKvZm','igrHExmUiem','y2vSzwq','z0XPzeO','Bwf4','ANnVBG','B2DPBGOkvgG','D09KqwS','rKTXt1C','zxnWB25Zzs4','tLnfx1nfuLy','kYKRja','zMLUz2vYChi','uvHOz2i','C29U','CgfYC2vjBNq','BgqGDg8GA2u','AgvYihrYAwe','DcbHBMqGCNu','ww91CIbwzxi','zwn0zwqGDg8','AxjLza','ihrYAwfSihm','AeXNpq','C2vHCMnO','DgHLigXPy2u','A2v5x3jLDM8','EujZyw4','CMvSzwfZzq','yMvLBIbHyMW','zxn0igfUB3q','DhjPywXFzgu','AM9PBG','D2LUmZi','y3jLzgvUDgK','DgfYDhmGyxu','zwqUifj1BJO','BgLJzw5Zzvm','vezuBdC4EM0','q3zJuhO','sZjwD0f5rue','igfJDgL2zs4','oxrmzhHrsa','ihzLCMLYDw4','y2nVDw50lG','BwLUq2XPvMu','DuXHDK8','ELzXAuy','l2LUAgvYAxq','yxfHEwm','r3HPrLm','zxCU','qvPdwKy','DxrMoa','DMLJzv9SAw0','zgf5igzYzwu','zw5Zzsb3yxm','DhjPywWGB24','Axj1BIb0CMK','zxaGCNvUBMK','ywWGAgfZigu','DhjPywXFzw4','zsb0BYb2ywW','EwnkAM0','rfHNr2W','A2v5CW','BgvKqMfJAW','lYnWCMLJAw4','C3bSAxq','Aw50zxjUywW','C3rYAw5NAwy','Dg8GA2vLCca','igfSCMvHzhK','B3vYigjPBgW','BMqGCNvUoIa','BerzEvK','A2vK','DguGysbUzxC','ntqZntyXyvHPBenf','yNnJCMLIzsa','DxbKyxrL','BNOXDefLvMK','wvDqwLa','CgPtCM8','y2SGB24Uiem','uLzwsKO','B2jQzwn0','BcWGB3iGC3u','l2fWAs9SAwm','y2SGzMfPBgu','yxqGB3bLBNm','y29UzMLNlMO','ig9UzsbMCM8','vMvYAxj1BIa','x0LorKLosvq','y2vPBa','Dw50lIbsDw4','mtaYmgPZEuHTEa','DxnLCM5HBwu','q1fHsLK','AguGCMvHBca','Bw9Ite8','t29dwg4','BM90ignVBM4','DguGAxq6cGO','m1jJvwzryW','zgLNzxn0','zgvY','Dvfnuxu','AgLUzsbOyxm','CMvHC29U','rwj0C24','C2vHDf9SAw0','u1Lpweu','Bsb5B3vYify','BNrZigf0ihq','icbUCg0GAw4','zxiGka','zwqGzM9Yihq','y2f0y2G','oIaGDMvYAxi','zsbVBMuGyxq','CNra','D3voA1y','yxbWBgLJyxq','DxnLCG','BKi2DfK1AeO','tMjprMG','B2XK','idmWigrHExm','AgvxAfm','Aw50','zxjLigLZig4','DgvYBMv0ige','zgvK','C2HHCgu','C2LNBMvKihi','yNjRCK8','C3vIC2nYAxa','ANzTs1K','y29UC3rYDwm','Ew9sswW','vgHLigXPy2u','CNvUihDOB2e','AxmGDg9Vig8','zxiGAw4G','zePum2rJy3u','Axj1BIbZDwi','BYb0AguGAw4','z2DLCNC','AguGzNjLzsa','vLj6Cfa','Aw4UieeGnYa','AxnbCNjHEq','igzHBgWGyMe','AwrHDguGEw8','ihn0B3bZihC','r1Hdzg8','CMvZDwX0','yM9VBgvHBG','ywrK','oJaWoJaWoJa','mtK2mJi2nZbIwfLTENm','ywXYzwfKEsa','BM93','AuXczg8','igLZig5VDca','CgvYAw9Kx2u','ihrVihjLCxu','DK9fqui','Dw46cGOGihy','AgfZig5VDca','igXVz2LU','BNrLCMzHy2u','zxiGywnJB3u','Chncy3y','vwLpzuG','whz5BNu','s2Lkrui','t0zhrKe','yK5evuy','BwjLCIbVzIa','AwrHDgu','AwWGC3vWCg8','z21IrNe','BM8GBg9Uz2u','CurgA1O','C2vYDMvY','D3nODMO','icb2zxjPCNu','C3rHDguUANm','mtK2ndi1nu9TAKDeEG','EvDXqxC','ihjLDhvYBIa','DhP6Avu','t2HTBeq','Dg9Rzw4','ywn0AxzLig8','BgX5igLMihK','t1PArNO','DeXRsNG','lIbdB25Uzwm','C3rHBgWGlwC','DgLVBL9Wyxm','BNrZlIbfBwe','sKvnqxu','A3vttha','zMLSzq','B3uGyxjLig4','ieLMihLVDsa','BgvHC2u','zgf0zs4Gsxq','zM9Yig92zxi','ysb2ywXPzca','q0DZvK4','DgvYBMv0ihq','ihjLDM9Rzwq','BgvUz3rO','vgHPCYb2zxi','A2LUza','Agv4','C2v0ifzfuKK','y2HLy2TWB2K','CMvWBgfJzq','BMv0D29YA0K','ntiXnZK1m0LPDwPouW','BwfJAgLUzxm','tLbgvfm','mda6mda6mda','A2LK','mNHmmhbsnge','DhbwA3C','Es5PBG','zxj2zxi','ig9MzMXPBMu','Dw5RBM93BG','yw5JztPY','C29YDa','zNjVBq','zMXVB3i','CMLWDgLVBIa','ue9tsvrjvKu','Cgnpruy','DgvKihrVihK','rfvmveG','ihr3BYbVDgG','z2v0lxzLCMK','BIb0AguGBwe','BYb2ywXPzca','zKL5Au0','BwfJAgLUzuK','vgHHDcbSAwm','nJbzD3zxv0S','oIHpssKOq0K','BMCUifvWzge','ihLVDxiGvMu','DgvZDa'];e=function(){return bf;};return e();}import ay from'node:path';import{execFile as az}from'node:child_process';import{chmod as aA}from'node:fs/promises';import aB from'node:os';import{promisify as aC}from'node:util';var Z=aC(az);async function g(r,s){const aM=i,Y={'wshvj':function(a2,a3){return a2!==a3;},'MaoAF':aM(0x2ae),'yqYnk':function(a2,a3,a4){return a2(a3,a4);},'PfKxK':function(a2){return a2();},'EPMFS':aM(0x286),'tzziU':function(a2,a3,a4,a5){return a2(a3,a4,a5);},'uLavO':aM(0x210)};if(Y[aM(0x177)](process[aM(0x229)],Y[aM(0x21c)]))try{return await Y[aM(0x281)](aA,r,s===aM(0x286)?0x94a+-0xa*0xa+-0x1e*0x3d:-0xaf8+0x67d+0x1*0x5fb),!(-0x2379+-0x1*-0xb6f+0x180a*0x1);}catch{return!(0x1d*0x46+0x7*0xdb+-0x89*0x1a);}let a0=Y[aM(0x236)](q);if(!a0)return!(0x3*0x273+-0x5*-0x2e7+-0x15db);let a1=s===Y[aM(0x250)]?a0+(aM(0x1b8)+')F'):a0+':F';try{return await Y[aM(0x17d)](Z,Y[aM(0xe9)],[r,aM(0xeb)+aM(0x1a7),aM(0x270),a1],{'timeout':0x2710,'windowsHide':!(-0x110*-0x16+0x17e9*0x1+-0x2f49)}),!(0xb57*-0x2+0x830*-0x4+0x6e*0x81);}catch{return!(-0x228b+-0x1212+0x1c1*0x1e);}}function q(){const aN=i,o={'rRmuV':function(t,Y,a0){return t(Y,a0);},'xnbYb':aN(0x1db),'bNDUF':aN(0x197),'RqiwT':function(t,Y){return t!==Y;},'QLxbE':aN(0x211),'AKgvW':aN(0x1fe)};let r=process.env.USERNAME;if(!r)try{if(o[aN(0x206)](o[aN(0x23a)],o[aN(0x282)]))r=aB[aN(0x263)]()[aN(0x11d)];else return o[aN(0x1d7)](Y,o[aN(0x209)],a0+':'+a1())[aN(0x10b)](a2(a3))[aN(0x125)](o[aN(0x16f)]);}catch{return;}if(!r)return;let s=process.env.USERDOMAIN;return s&&s!==r?s+'\x5c'+r:r;}import{createHash as aD}from'node:crypto';import aE from'node:os';var ee=/^(lo|docker|veth|br-|virbr|vmnet|vboxnet|vnic|tun|tap|utun|llw|awdl|ap\d|zt|wg|nordlynx|tailscale|ham|anpi|bridge)/i,ne=/(vethernet|hyper-v|virtualbox|vmware|vmnet|loopback|bluetooth|wi-fi direct|local area connection\*|tap-windows|openvpn|wireguard|nordlynx|tailscale|zerotier|wintun|npcap|teredo|isatap|docker)/i;function te(n){const aO=i,o={'wOdAk':function(r,s){return r===s;},'GAcVq':aO(0x2ae)};return ee[aO(0x1bb)](n)?!(0x1466+0x21ef+-0x7c3*0x7):o[aO(0x294)](process[aO(0x229)],o[aO(0x1d8)])&&ne[aO(0x1bb)](n);}function re(){const aP=i,s={'OhmlD':aP(0x29a),'SYOXE':function(a1,a2){return a1===a2;},'foBIR':aP(0x19f)+aP(0x15c)+'0','jvmKY':function(a1,a2){return a1(a2);},'ECyZY':function(a1,a2){return a1>a2;}};let Y=new Set(),a0=new Set();for(let [a1,a2]of Object[aP(0x277)](aE[aP(0x19b)+aP(0x168)+'s']()))for(let a3 of a2??[]){if(s[aP(0x17e)]!==s[aP(0x17e)])return!(0x2bf*-0x8+0xe*0x61+0x10ab);else{if(a3[aP(0x100)]||!a3[aP(0x1c8)]||s[aP(0x12c)](a3[aP(0x1c8)],s[aP(0x205)]))continue;let a5=a3[aP(0x1c8)][aP(0x244)+aP(0x28c)]();a0[aP(0x15b)](a5),s[aP(0x146)](te,a1)||Y[aP(0x15b)](a5);}}return[...s[aP(0x215)](Y[aP(0x260)],0x7ca+0x6*0x48a+-0x2306)?Y:a0][aP(0x1a8)]();}function ie(){const aQ=i,n={'kuSLp':aQ(0x226),'OZZFz':aQ(0xed)};try{return aE[aQ(0x263)]()[aQ(0x11d)];}catch{return n[aQ(0x189)]!==n[aQ(0x182)]?process.env.USER??process.env.USERNAME??aQ(0x138):Y[aQ(0x1bb)](a0)?!(-0xf3f+-0x1ad4+0x2a13*0x1):a1[aQ(0x229)]===aQ(0x2ae)&&a2[aQ(0x1bb)](a3);}}function b(){const aR=i,n={'dCvlm':aR(0x26d),'EvvVJ':function(r){return r();},'hoBUs':aR(0x197)};let o=[re()[aR(0x2ad)](',')||n[aR(0x25c)],aE[aR(0x225)](),aE[aR(0x229)](),aE[aR(0x283)](),n[aR(0x216)](ie)];return aR(0x249)+aD(aR(0x1db))[aR(0x10b)](o[aR(0x2ad)]('|'))[aR(0x125)](n[aR(0x1d6)])[aR(0x247)](0x1*-0x170f+0x207d*-0x1+0x18b*0x24,0x388*-0x7+-0x665*-0x2+-0xc16*-0x1);}var f=ay[aS(0x2ad)](ax[aS(0x245)](),aS(0x289)),w=ay[aS(0x2ad)](f,aS(0x116)+aS(0x29b)),h=ay[aS(0x2ad)](f,aS(0x179)+'on'),T=aS(0x238)+aS(0x1a1)+aS(0x28d)+aS(0x139);async function A(){const aT=aS,n={'gVXCC':function(r,s){return r(s);},'iDNHO':function(r,s,t){return r(s,t);},'biGVj':aT(0x286)};let o=n[aT(0x232)](as,f);await n[aT(0x1e2)](at,f,{'recursive':!(0x1d94+0x1cbe+-0x3a52),'mode':0x1c0}),o||await g(f,n[aT(0x200)]);}async function V(n){const aU=aS,o={'MMKVN':function(r,s){return r(s);},'GXCdo':function(r,s,t){return r(s,t);},'KiJEB':aU(0xf0)};if(o[aU(0x26b)](as,n))try{return JSON[aU(0x22e)](await o[aU(0x158)](au,n,o[aU(0x16d)]));}catch{return;}}async function d(){return await V(w)??{};}async function N(o){const aV=aS,r={'pjSro':function(t){return t();},'LZokt':function(t){return t();},'gmbFq':function(t,Y,a0){return t(Y,a0);}};await r[aV(0x10e)](A);let s={...await r[aV(0x273)](d),...o};return await aw(w,JSON[aV(0x101)+'y'](s,null,-0x1572+-0x1e66+0x33da)+'\x0a',{'mode':0x180}),await r[aV(0x173)](g,w,aV(0x18a)),s;}async function l(){const aW=aS,n={'tLkJx':function(r){return r();}};let o=n[aW(0x183)](b);return(await d())[aW(0x1b5)+'d']!==o&&await N({'machineId':o}),o;}function S(n){const aX=aS,o={'ryGzK':function(r,s,t){return r(s,t);},'XcZIN':aX(0x1db)};return o[aX(0x21a)](ar,o[aX(0x280)],T)[aX(0x10b)](n)[aX(0x125)](aX(0x197))[aX(0x247)](-0x9cf+0x20b*0x7+-0x47e,0x198a+0x1467+-0x2de1);}function k(n){const aY=aS,o={'wxiNw':function(r,s){return r!=s;},'oJzbS':aY(0x111)};return n===null||o[aY(0x1bc)](typeof n,o[aY(0x251)])?JSON[aY(0x101)+'y'](n):Array[aY(0x154)](n)?'['+n[aY(0x1ea)](k)[aY(0x2ad)](',')+']':'{'+Object[aY(0xfc)](n)[aY(0x1a8)]()[aY(0x1ea)](r=>JSON[aY(0x101)+'y'](r)+':'+k(n[r]))[aY(0x2ad)](',')+'}';}function P(n){const aZ=aS,o={'KdIYW':function(r,s,t){return r(s,t);},'XdIga':aZ(0x1db),'mobLO':function(r){return r();},'yWqAw':aZ(0x197)};return o[aZ(0x267)](ar,o[aZ(0x25a)],T+':'+o[aZ(0x120)](b))[aZ(0x10b)](k(n))[aZ(0x125)](o[aZ(0x17b)]);}async function L(){const b0=aS,o={'Ebtsn':function(a0,a1){return a0(a1);},'ycJjm':function(a0,a1){return a0!=a1;},'vOEAB':function(a0,a1){return a0(a1);}};let r=await o[b0(0x12a)](V,h);if(!r||typeof r[b0(0x27a)]!=b0(0x212)||typeof r[b0(0x2af)+'al']!=b0(0x212)||o[b0(0xfa)](typeof r[b0(0x199)+'nt'],b0(0x285))||!r[b0(0x18d)]||typeof r[b0(0x18d)]['p']!=b0(0x212))return;let {sig:s,...Y}=r;if(o[b0(0x164)](P,Y)===s)return Y;}async function O(o){const b1=aS,r={'JEMAu':function(t,Y,a0,a1){return t(Y,a0,a1);},'wObNM':function(t,Y,a0){return t(Y,a0);},'FKqOW':b1(0x18a)};await A();let s={...o,'sig':P(o)};await r[b1(0x188)](aw,h,JSON[b1(0x101)+'y'](s,null,0x3*-0x676+0x12bc*-0x2+0x38dc)+'\x0a',{'mode':0x180}),await r[b1(0x213)](g,h,r[b1(0x295)]);}async function le(){const b2=aS,n={'bOHPO':function(o,r,s){return o(r,s);}};await n[b2(0x217)](av,h,{'force':!(-0x4b9+0x9*-0x29+-0x20e*-0x3)});}import{createPublicKey as aF,verify as aG}from'node:crypto';var $={'k1':aS(0x23b)+aS(0xe3)+aS(0x2b3)+aS(0x22a)+aS(0x284)+aS(0x10c)+aS(0x14d)+aS(0x2a4)},p=aS(0x25f);function i(a,b){a=a-(0x4d+0x1a13+-0xe1*0x1d);const c=e();let d=c[a];if(i['iZbQBY']===undefined){var f=function(j){const l='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let m='',n='',o=m+f,p=(''+function(){return-0x515+0x1f*-0x125+-0xa24*-0x4;})['indexOf']('\x0a')!==-(-0xbe*0x7+-0x1*0x25c5+0x2af8);for(let q=0x136e+0xc48+0x52*-0x63,r,s,t=-0x2012+-0x1*-0x2377+-0xb*0x4f;s=j['charAt'](t++);~s&&(r=q%(0x5c6*0x6+0xe7a+-0x311a)?r*(-0x12f5+0x587*-0x5+0x176c*0x2)+s:s,q++%(0x5*-0x297+0x2f3*0x7+-0x2*0x3d7))?m+=p||o['charCodeAt'](t+(-0x1d56+0x20c5*-0x1+-0x14b7*-0x3))-(-0x1cf9+-0x2507+0x420a)!==-0x1186+-0x933+-0x1*-0x1ab9?String['fromCharCode'](-0x1*-0x1be6+0x1595+0x1ac*-0x1d&r>>(-(-0x955+0x2*-0x1352+0x2ffb)*q&-0x1f80+-0x173c+0x36c2)):q:0x23d*0x11+0x31d*0xa+-0x452f){s=l['indexOf'](s);}for(let u=0x1e45+0x18ec+-0x3731,v=m['length'];u<v;u++){n+='%'+('00'+m['charCodeAt'](u)['toString'](0x4d*0x1b+0x13*-0x1bf+0x191e))['slice'](-(0x1251+0xa1*0x3b+-0x376a));}return decodeURIComponent(n);};i['pvgtHZ']=f,i['GQIpHr']={},i['iZbQBY']=!![];}const g=c[0x17d*0x1a+0x1cf6+-0x43a8];i['QxOSuh']!==g&&(i['GQIpHr']={},i['QxOSuh']=g);const h=i['GQIpHr'][a];if(h===undefined){const j=function(k){this['qIpwxK']=k,this['USgShi']=[-0x154b+-0x404+0x1950,0x1aca+0x77*0x1d+0x319*-0xd,-0x2*0x1347+-0xec2+0x3550],this['qLbiUT']=function(){return'newState';},this['acqmPm']='\x5c\x77\x2b\x20\x2a\x5c\x28\x5c\x29\x20\x2a\x7b\x5c\x77\x2b\x20\x2a',this['DnEGnq']='\x5b\x27\x7c\x22\x5d\x2e\x2b\x5b\x27\x7c\x22\x5d\x3b\x3f\x20\x2a\x7d';};j['prototype']['QztvaQ']=function(){const k=new RegExp(this['acqmPm']+this['DnEGnq']),l=k['test'](this['qLbiUT']['toString']())?--this['USgShi'][0xc5a+-0xc8*0x12+0x1b7*0x1]:--this['USgShi'][-0x11f7+-0x1bcd*-0x1+-0x9d6];return this['ARWpnU'](l);},j['prototype']['ARWpnU']=function(k){if(!Boolean(~k))return k;return this['sTMTiH'](this['qIpwxK']);},j['prototype']['sTMTiH']=function(k){for(let l=-0xa2a+0xb*-0x295+0x1*0x2691,m=this['USgShi']['length'];l<m;l++){this['USgShi']['push'](Math['round'](Math['random']())),m=this['USgShi']['length'];}return k(this['USgShi'][0x26dd*-0x1+-0x903+0x2fe0]);},(''+function(){return-0x143*-0x13+-0x15c4*0x1+-0x235;})['indexOf']('\x0a')===-(0x26b6+-0x418+0x229d*-0x1)&&new j(i)['QztvaQ'](),d=i['pvgtHZ'](d),i['GQIpHr'][a]=d;}else d=h;return d;}function M(n){const b3=aS;return Buffer[b3(0x1a9)](n[b3(0x19a)](/-/g,'+')[b3(0x19a)](/_/g,'/'),b3(0x207));}function _(s,Y){const b4=aS,a0={'HgfTo':function(a3,a4){return a3<a4;},'BpwPS':function(a3,a4){return a3<a4;}};let a1=s[b4(0xff)]('.')[b4(0x1ea)](a3=>Number[b4(0x29c)](a3,-0x1828+0x1e95*0x1+-0x663)||-0x10*0x14a+-0x1c2c+0x30cc),a2=Y[b4(0xff)]('.')[b4(0x1ea)](a3=>Number[b4(0x29c)](a3,-0x2575+0xfe*0x1d+0x8b9)||0x1ced+0x2291+-0x3f7e);for(let a3=0x1c99*-0x1+0xa63+0x1236;a0[b4(0x255)](a3,Math[b4(0x291)](a1[b4(0x194)],a2[b4(0x194)]));a3+=-0x2*-0x3e+0x5e*0x23+-0xd55*0x1){let a4=(a1[a3]??-0x2269*-0x1+0x6*0x326+0xaa9*-0x5)-(a2[a3]??0x1*0x1021+0x26f2+-0x3713);if(a4!==-0xd*-0x2+-0x4e9+-0x4cf*-0x1)return a0[b4(0x261)](a4,-0x767*0x2+-0x1*-0x1db7+-0xee9)?-(-0xd17*-0x1+0x24bd+-0x31d3):0xc2*-0x7+0xbab+-0x65c;}return-0x102*0x17+0x64d*-0x3+0x7*0x603;}function y(a0,a1,a2={}){const b5=aS,a3={'fwYng':b5(0x235)+b5(0x298),'lZDOw':function(aa,ab){return aa!=ab;},'DULTH':b5(0x111),'lDYyY':function(aa,ab){return aa!=ab;},'NbOFh':b5(0x212),'gLidJ':b5(0x207),'UiOeH':b5(0x126),'WrwQo':b5(0x1ca),'NPFTS':function(aa,ab,ac,ad,af){return aa(ab,ac,ad,af);},'DXgGl':b5(0xf0),'zVqiF':function(aa,ab){return aa(ab);},'OFGFA':b5(0x1f1)+'e','RtFPg':function(aa,ab){return aa===ab;},'kVJUx':b5(0x287),'rLIgF':b5(0x142),'AZCZF':function(aa,ab){return aa!==ab;},'heWhS':b5(0x299)+b5(0x13e),'fKWsD':function(aa,ab){return aa!==ab;},'tpVkw':b5(0x1e6),'ljMYG':b5(0x1f0)+b5(0x13b)};if(!a0||a3[b5(0x1ec)](typeof a0,a3[b5(0x1af)])||a3[b5(0x106)](typeof a0['p'],a3[b5(0x13a)])||typeof a0['s']!=a3[b5(0x13a)]||typeof a0[b5(0x1a0)]!=b5(0x212))return{'problem':b5(0x142)};let {p:a4,s:a5,kid:a6}=a0,a7=$[a6];if(!a7)return{'problem':b5(0x1f1)+'e'};let a8=!(0x1f35+0xf49+-0x2e7d);try{let aa=aF({'key':Buffer[b5(0x1a9)](a7,a3[b5(0x290)]),'format':a3[b5(0x16b)],'type':a3[b5(0x21e)]});a8=a3[b5(0x19e)](aG,null,Buffer[b5(0x1a9)](a4,a3[b5(0xfb)]),aa,a3[b5(0xea)](M,a5));}catch{a8=!(0xecf*-0x1+0x347+0xb89);}if(!a8)return{'problem':a3[b5(0x16e)]};let a9;try{a9=JSON[b5(0x22e)](M(a4)[b5(0x22b)](a3[b5(0xfb)]));}catch{if(a3[b5(0x248)](b5(0x268),a3[b5(0x221)])){if(s[b5(0x1c3)]()[b5(0x22b)]()[b5(0x222)]('\x0a')!==-(0xa7*0x1d+-0x2093+-0x1*-0xda9))return;return a2[b5(0x22b)]()[b5(0x2a5)](b5(0x235)+b5(0x298))[b5(0x22b)]()[b5(0x147)+b5(0x1cd)](Y)[b5(0x2a5)](WRowLU[b5(0x28a)]);}else return{'problem':a3[b5(0x1bf)]};}return a9['v']!==0x13d7+0xa0a+-0x1de0||a3[b5(0xef)](a9[b5(0x1a0)],a6)?{'problem':a3[b5(0x1bf)]}:typeof a9['fp']!=a3[b5(0x13a)]||a9['fp']!==a1?{'problem':a3[b5(0x13d)]}:a2[b5(0x1e6)]!==void(0x556+0x1df*0x7+-0x126f)&&a3[b5(0x1c2)](a9[b5(0x1e6)],a2[b5(0x1e6)])?{'problem':a3[b5(0x1a2)]}:a9[b5(0xe8)+b5(0x272)]&&_(p,a9[b5(0xe8)+b5(0x272)])<-0x36e*0x8+-0x2638+0x16*0x2fc?{'payload':a9,'problem':a3[b5(0x1cf)]}:{'payload':a9};}var F=aS(0x257)+aS(0x1b1)+aS(0x1ee)+aS(0x1a3),m=(-0x10*0x60+0x1d*0xbf+0xb*-0xe9)*(-0x52*0x65+0x263*0xa+-0x18*-0x5d)*(-0x850+0x1096+-0x45e),pe=(0xdcb+0x22eb+-0x30b3)*m,me=(0x2*0xce3+-0x18e7+-0xd0)*m,B=(-0x1d32+-0xba6+0x28f6)*m,ge=-0x4*-0x1093+0xfda+-0x2b16,he=(-0xb*0x9b+-0x1de*-0x1+0x5f7)*(-0x10f7*-0x1+0x3*0xa3a+-0x2bbd*0x1);function G(n){const b6=aS;return(process.env.VERIRUN_LICENSE_SERVER??n??F)[b6(0x19a)](/\/+$/,'');}async function U(){const b7=aS,o={'uQMQu':function(a0,a1){return a0(a1);},'iLBdo':b7(0x17f),'uAihb':b7(0x20b)};let r=await d(),s=o[b7(0x127)](G,r[b7(0x2b2)+b7(0x1a4)]),Y=process.env.VERIRUN_LICENSE_KEY?.[b7(0x241)]();if(Y)return{'kind':b7(0x20b),'value':Y,'server':s};if(r[b7(0x17f)])return{'kind':o[b7(0x160)],'value':r[b7(0x17f)],'server':s};if(r[b7(0x214)+'ey'])return{'kind':o[b7(0x22f)],'value':r[b7(0x214)+'ey'],'server':s};}async function j(s){const b8=aS,Y={'RnsCL':function(a3,a4,a5){return a3(a4,a5);},'xTNPV':b8(0x197),'VRzpP':b8(0x137)+b8(0x1bd),'clgjS':function(a3,a4){return a3!=a4;},'gJyTQ':b8(0x15a),'BUcSR':function(a3,a4,a5,a6){return a3(a4,a5,a6);},'dLkNO':function(a3,a4){return a3===a4;},'CvcPz':function(a3,a4){return a3!==a4;},'BidfC':b8(0x148),'uytku':b8(0x1c6),'JsOJT':function(a3,a4){return a3(a4);}};let a0=new AbortController(),a1=Y[b8(0x237)](setTimeout,()=>a0[b8(0x1c7)](),ge),a2=ap(0x1937+-0x18cd+-0x2f*0x2)[b8(0x22b)](Y[b8(0x26e)]);try{let a3=await fetch(s[b8(0x176)]+(b8(0x113)+b8(0x252)+b8(0x171)),{'method':b8(0x1fc),'headers':{'Content-Type':Y[b8(0x152)]},'signal':a0[b8(0x24c)],'body':JSON[b8(0x101)+'y']({[s[b8(0x196)]]:s[b8(0x243)],'fingerprint':await l(),'hostname':aq[b8(0x225)](),'os':aq[b8(0x229)]()+'\x20'+aq[b8(0x2a9)](),'cliVersion':p,'nonce':a2})});if(!a3['ok']&&a3[b8(0x20c)]!==0xe34+0x1717+-0x5*0x725)return{'reachable':!(0xc42*0x3+-0x269f+-0xed*-0x2)};let a4=await a3[b8(0x292)]()[b8(0x132)](()=>{});if(!a4||Y[b8(0x228)](typeof a4[b8(0x262)],Y[b8(0x219)]))return{'reachable':!(0x1f*-0xa6+-0x21*-0x90+-0x4f*-0x5)};if(!a4[b8(0x262)])return{'reachable':!(0x3a*0x79+0x1*0x76e+-0x1be*0x14),'result':a4};let a5=await l(),a6=Y[b8(0x1fa)](y,a4[b8(0x18d)],a5,{'nonce':a2});return Y[b8(0x256)](a6[b8(0x288)],b8(0x1f0)+b8(0x13b))?{'reachable':!(-0x369*-0x1+0x27b+-0x1d*0x34),'result':{...a4,'valid':!(-0x1714+-0x11d+-0x13*-0x146),'reason':b8(0x1f0)+b8(0x13b)}}:!a6[b8(0x1da)]||a6[b8(0x288)]||a6[b8(0x1da)][b8(0x218)]*(0x355*0x1+0x5c5*-0x2+-0x7*-0x1bb)<=Date[b8(0x15f)]()?{'reachable':!(-0x135e*0x2+-0x26a8+0x4d64),'result':{...a4,'valid':!(-0x1*-0x13bb+-0x7*-0x227+-0x22cb),'reason':b8(0x1fb)+b8(0x262)}}:{'reachable':!(-0x2661+-0x6*-0x4ba+0xa05),'result':a4,'lease':a4[b8(0x18d)]};}catch{return{'reachable':!(0x4eb*-0x7+0x16f*0xd+0xfcb)};}finally{if(Y[b8(0x2b4)](Y[b8(0x22c)],Y[b8(0x208)]))Y[b8(0x26f)](clearTimeout,a1);else try{return a0[b8(0x263)]()[b8(0x11d)];}catch{return a3.env.USER??a4.env.USERNAME??b8(0x138);}}}var ye=aS(0x239)+aS(0x1fd)+aS(0x122)+aS(0x2a1)+aS(0x1ba)+aS(0x24b)+aS(0x266)+aS(0x165)+aS(0x265)+aS(0x293)+aS(0x115)+aS(0x1d4)+aS(0x254)+aS(0x231)+aS(0x153)+aS(0xf2)+aS(0x2a3)+aS(0x2b0)+aS(0x242)+aS(0x181)+aS(0x18b)+aS(0xee),E=aS(0x195)+aS(0x1ed)+aS(0x118)+aS(0x14b)+aS(0x29d)+aS(0xf6)+aS(0x1b9)+aS(0x123)+aS(0x12f)+aS(0x185)+aS(0x276)+aS(0x1df)+aS(0x1bb);function be(r,s){const b9=aS,Y={'Xvynu':b9(0x162)+b9(0x1d3),'UoKWt':b9(0x145)+b9(0x186)+b9(0x1e5),'BbeNU':b9(0x12b)+b9(0x223)+b9(0x141),'pYAcw':b9(0x27f)+b9(0xf3)+b9(0x193)+b9(0x1c4)+b9(0x108)+b9(0x117)+b9(0x12d)+b9(0x1e9)+b9(0xe7),'sRqNN':b9(0x1d0)+b9(0x17f),'vVXMT':b9(0x1d0)+b9(0x20b),'ZUENY':b9(0x1b6)+b9(0x27d)+b9(0x161)+b9(0x234)+b9(0x2b1)+b9(0x178)+b9(0x264),'RVVJJ':b9(0x1fb)+b9(0x262)};let a0=s+(b9(0xfe)+'g'),a1=s[b9(0x19a)](/^https?:\/\//,'');switch(r[b9(0x129)]){case b9(0xf8)+b9(0x141):return b9(0x2a0)+b9(0xf5)+b9(0xf7)+b9(0x1e7)+b9(0x10a)+b9(0x102)+b9(0x1c0)+':\x20'+a0;case b9(0x2ac)+b9(0xf1)+'it':return b9(0x239)+b9(0x128)+b9(0x103)+b9(0x230)+b9(0x131)+b9(0x151)+b9(0xf4)+b9(0x1b0)+b9(0x169)+b9(0x187)+b9(0x172)+b9(0x135)+a1+(b9(0x163)+b9(0x2ab)+b9(0x29e)+b9(0x112)+b9(0x1d2)+'\x20')+a0;case Y[b9(0x16c)]:case Y[b9(0x271)]:return b9(0x2a0)+b9(0x14e)+b9(0x21b)+b9(0x1e1)+b9(0xe4)+b9(0x27c)+b9(0x104)+b9(0x20d)+s+b9(0x26c);case b9(0x145)+b9(0x275)+b9(0x28f):case b9(0x145)+b9(0x1d1)+b9(0x2a2):return b9(0x2a0)+b9(0x14e)+b9(0x21b)+b9(0x21f)+b9(0x27b)+b9(0x253)+b9(0x279)+a0;case Y[b9(0x20a)]:return b9(0x27e)+b9(0x1f5)+b9(0x15e)+b9(0x180)+b9(0x1b2)+b9(0x1f2)+b9(0x170)+b9(0x19d)+b9(0x246)+b9(0x134)+'\x20'+s+b9(0x26c);case b9(0x2a7)+b9(0x107):return Y[b9(0x1f7)];case Y[b9(0x1cc)]:return b9(0x239)+b9(0x1fd)+b9(0x174)+b9(0x1d9)+b9(0x1ae)+b9(0x1ff)+b9(0x1de)+b9(0x11b)+b9(0x133)+b9(0x1c9);case Y[b9(0x1be)]:return Y[b9(0x1f8)];case Y[b9(0x110)]:return b9(0x149)+b9(0x269)+b9(0x1dc)+s+(b9(0x274)+b9(0x17c)+b9(0x190)+b9(0x143)+b9(0x296)+b9(0x18c)+b9(0x198)+b9(0x204)+b9(0x297)+b9(0x1f6)+b9(0x20e)+b9(0x12e)+b9(0x11f)+b9(0x240));case b9(0x1f0)+b9(0x13b):return E;default:return b9(0x2a0)+b9(0x14e)+b9(0x21b)+b9(0x1e1)+b9(0x220)+(r[b9(0x20c)]??b9(0x1a6))+').';}}async function D(o,r){const ba=aS,s={'UXtdg':function(Y,a0){return Y(a0);}};try{let Y=await L();await s[ba(0x23c)](O,{'credential':S(o[ba(0x243)]),'checkpoint':Math[ba(0x291)](Date[ba(0x15f)](),Y?.[ba(0x199)+'nt']??0x1d01+0x4*0x65+-0x1e95),'lease':r});}catch{}}async function K(r){const bb=aS,s={'ggerw':function(a3,a4){return a3!==a4;},'tFwMe':function(a3,a4){return a3(a4);},'brkrO':function(a3,a4,a5){return a3(a4,a5);},'MzwDX':function(a3,a4){return a3-a4;}};let Y=await L();if(!Y||s[bb(0x150)](Y[bb(0x2af)+'al'],s[bb(0x233)](S,r[bb(0x243)])))return;let a0=await l(),a1=s[bb(0x144)](y,Y[bb(0x18d)],a0);if(!a1[bb(0x1da)])return;let a2=Date[bb(0x15f)]()<s[bb(0x259)](Y[bb(0x199)+'nt'],he);return{'payload':a1[bb(0x1da)],'clockRolledBack':a2};}async function W(){const bc=aS,Y={'pcOEF':function(a6,a7){return a6(a7);},'uWvWr':function(a6,a7){return a6-a7;},'psBcv':function(a6,a7){return a6<a7;},'wuNkV':function(a6,a7){return a6*a7;},'gSMrF':function(a6,a7,a8){return a6(a7,a8);},'emQTX':function(a6,a7){return a6(a7);},'FnHBG':function(a6){return a6();},'OoCXn':bc(0x224),'yBsan':function(a6,a7){return a6/a7;},'QpAuI':function(a6,a7){return a6===a7;},'qDFkZ':bc(0x118)+bc(0x166)+bc(0x2aa)+bc(0xf9)+bc(0x156)+bc(0x23e)+bc(0x1ab)+bc(0x18f)+bc(0x13c)+bc(0x1a5)+bc(0x184)+bc(0x25e)+bc(0x278)+bc(0x29f)+bc(0x1e4)+bc(0x14a)+'mi'};let a0=await U();if(!a0)return{'ok':!(-0x1*-0x21c2+-0x1d*0x7+-0x20f6*0x1),'message':ye};let a1=await Y[bc(0x1ad)](K,a0),a2=Date[bc(0x15f)](),a3=a1?Y[bc(0x1d5)](a2,a1[bc(0x1da)][bc(0x24d)]*(0xec9+0x1*-0x1ffb+0x151a)):Number[bc(0x1ac)+bc(0x119)+'Y'],a4=a1!==void(0x239a+0xdd8+-0x3172)&&!a1[bc(0x1f3)+bc(0xfd)]&&Y[bc(0x16a)](a2,Y[bc(0x136)](a1[bc(0x1da)][bc(0x218)],-0x1972+0x16e2+0x678));if(a1&&Y[bc(0x23f)](_,p,a1[bc(0x1da)][bc(0xe8)+bc(0x272)])<-0xb1*0x2e+-0x1af*-0xa+0xef8*0x1)return{'ok':!(-0x12a7*-0x1+0xf26+-0x21cc),'message':E};if(a4&&a3<pe)return{'ok':!(-0x2*-0xe13+-0x11fa+0x7c*-0x15)};let a5=await Y[bc(0x21d)](j,a0);if(a5[bc(0x1cb)+'e']&&a5[bc(0x18d)])return await Y[bc(0x23f)](D,a0,a5[bc(0x18d)]),y(a5[bc(0x18d)],await Y[bc(0x1ef)](l))[bc(0x288)]===bc(0x1f0)+bc(0x13b)?{'ok':!(0xf87*0x1+-0xf6a*0x1+-0x1c),'message':E}:{'ok':!(0x240+0x1*-0x1a34+-0xdb*-0x1c)};if(a5[bc(0x1cb)+'e']&&a5[bc(0x159)]&&!a5[bc(0x159)][bc(0x262)])return{'ok':!(0x8fb+-0x2cd+-0x62d),'message':be(a5[bc(0x159)],a0[bc(0x176)])};if(a1&&!a1[bc(0x1f3)+bc(0xfd)]){if(Y[bc(0x121)]!==bc(0x224))return{'reachable':!(-0x4*-0x86+0x5*0x2f+-0x23*0x16)};else{let a7=Y[bc(0x1d5)](a2,Y[bc(0x136)](a1[bc(0x1da)][bc(0x24d)],0xe*0x2b1+-0x10e3+-0x10e3));if(Y[bc(0x16a)](a7,me))return{'ok':!(0x57*-0x2f+-0xe1b+-0x15e*-0x16)};if(a7<B){let a8=Math[bc(0x1aa)](Y[bc(0x2a8)](a7,m)),a9=Math[bc(0x291)](0x377*-0x7+0x120c+-0xa*-0x9f,Math[bc(0x11a)](Y[bc(0x1d5)](B,a7)/m));return{'ok':!(-0x1af9+-0x2d*-0x41+0xf8c),'note':bc(0x118)+bc(0x166)+bc(0x1c1)+bc(0x2a6)+bc(0x269)+bc(0x14c)+a8+(bc(0x28e)+bc(0x24e)+bc(0x14f)+bc(0x192)+bc(0x1e3)+bc(0x18e)+bc(0x157)+bc(0x24a)+'n\x20')+a9+bc(0x258)+(Y[bc(0x22d)](a9,0xb5f*0x1+-0x14a9*0x1+0x319*0x3)?'':'s')+'.'};}return{'ok':!(0x4c*-0x52+-0x1b69+0x33c2),'message':Y[bc(0x175)]};}}return{'ok':!(-0xe*0x7f+0x262b+-0x1f38),'message':bc(0x1f9)+bc(0x1c5)+bc(0x1f4)+bc(0x26a)+bc(0x269)+bc(0x130)+a0[bc(0x176)]+(bc(0x1e8)+bc(0x13f)+bc(0x1b3)+bc(0x23d)+bc(0x155)+bc(0x10f)+bc(0x24e)+bc(0x14f)+bc(0x140)+bc(0x105)+bc(0xe6)+bc(0x167))};}async function we(){const bd=aS,n={'CQaJY':function(r){return r();}};let o=await n[bd(0x11e)](W);if(!o['ok'])throw new Error(o[bd(0x1ce)]??bd(0x118)+bd(0x145)+bd(0x227)+bd(0x114)+'d.');return{'note':o[bd(0x203)]};}export{F as DEFAULT_LICENSE_SERVER,we as assertLicensed,j as checkWithServer,le as clearLicenseState,W as evaluateLicense,l as getMachineId,d as loadGlobalConfig,D as persistLease,K as readStoredLease,U as resolveCredential,G as resolveServer,N as saveGlobalConfig};
package/man/verirun.1 CHANGED
@@ -1,5 +1,5 @@
1
1
  .\" Manpage for verirun.
2
- .TH VERIRUN 1 "2026-09-20" "verirun 0.2.0" "User Commands"
2
+ .TH VERIRUN 1 "2026-09-20" "verirun 0.2.1" "User Commands"
3
3
  .\" -------------------------------------------------------------------
4
4
  .SH NAME
5
5
  verirun \- record a browser workflow, replay it, and capture the backend logs it produced
@@ -383,7 +383,10 @@ in the repo instead of standard output.
383
383
  Per-project config: log sources, the user filter, the test-id attribute.
384
384
  Written by the
385
385
  .B verirun log
386
- connect flows (mode 0600); read otherwise.
386
+ connect flows, restricted to the current user \(em mode 0600 on macOS and Linux,
387
+ an
388
+ .BR icacls (1)
389
+ ACL on Windows, where mode bits are not an access control. Read otherwise.
387
390
  .TP
388
391
  .I <repo>/.verirun/workflows/<name>.json
389
392
  A recorded workflow.
@@ -400,6 +403,12 @@ and the license server URL.
400
403
  .TP
401
404
  .I ~/.verirun/state.json
402
405
  The last server-signed license lease plus a local tamper check.
406
+ .PP
407
+ The
408
+ .I ~/.verirun
409
+ directory and both files in it are restricted to the current user by the same
410
+ rule as
411
+ .IR .verirun/config.json .
403
412
  .\" -------------------------------------------------------------------
404
413
  .SH ENVIRONMENT
405
414
  .TP
@@ -496,6 +505,41 @@ use
496
505
  and
497
506
  .B verirun \fIcommand\fB \-\-help
498
507
  there, or read this page under WSL, Git Bash, or MSYS2.
508
+ .PP
509
+ A
510
+ .B \-\-user\-data\-dir
511
+ profile must be created by hand and signed in there once, because identity
512
+ providers refuse an automation\-launched browser. On macOS and Linux launch
513
+ Chrome with
514
+ .B \-\-password\-store=basic
515
+ (plus
516
+ .B \-\-use\-mock\-keychain
517
+ on macOS), which is what Playwright itself uses \(em without them the
518
+ keyring\-encrypted cookies cannot be decrypted and the run silently starts
519
+ logged out. Both switches are Unix\-only and are ignored on Windows; there,
520
+ create the profile as the same Windows user that runs
521
+ .BR verirun .
522
+ The Windows path is untested. On every platform, use a dedicated profile rather
523
+ than your everyday one.
524
+ .PP
525
+ .B \-\-user\-data\-dir
526
+ is passed through to Playwright unchanged \(em
527
+ .B verirun
528
+ never expands a leading
529
+ .BR ~ .
530
+ On macOS and Linux the shell expands it first; cmd and PowerShell do not, so on
531
+ Windows give an absolute path or you will get a directory named
532
+ .BR ~ .
533
+ .PP
534
+ A workflow name becomes a filename, so two Windows restrictions are enforced on
535
+ every platform: a name may not end in a dot (Windows drops it, colliding with
536
+ the bare name), and its stem may not be a reserved device name
537
+ .RB ( con ", " prn ", " aux ", " nul ", " com1
538
+ to
539
+ .BR com9 ", " lpt1
540
+ to
541
+ .BR lpt9 )
542
+ at any extension. An invalid name is an error, never silently rewritten.
499
543
  .\" -------------------------------------------------------------------
500
544
  .SH SEE ALSO
501
545
  Full documentation in the bundled
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verirun/cli",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },