@inkly-org/cli 0.7.3 → 0.7.4

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.
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import En from"mri";import{spawn as zt,execFile as or}from"child_process";import{createHash as lr,randomUUID as cr}from"crypto";import{mkdir as Y,mkdtemp as dr,open as pr,readFile as Q,readdir as fr,rm as Gt,writeFile as V}from"fs/promises";import{existsSync as Fe}from"fs";import{dirname as He,isAbsolute as gr,join as _,resolve as Kt,sep as wr}from"path";import{tmpdir as br,homedir as Jt}from"os";import{fileURLToPath as Zt}from"url";import{unzipSync as Sr,zipSync as Pr}from"fflate";import Xt from"ws";import xr from"sharp";import Er from"subset-font";import{zipSync as Ln}from"fflate";import{JSDOM as Lr}from"jsdom";import{randomUUID as Qe}from"crypto";import{mkdir as et,readFile as tt,writeFile as nt}from"fs/promises";import{dirname as rt,join as it}from"path";import{homedir as st}from"os";import{PostHog as ot}from"posthog-node";var be=process.env.NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN??process.env.POSTHOG_PROJECT_TOKEN??"phc_Dmh4w8YFNosi3YHD4Sv7ShHX7ccS8kmtRcm8XSVmB5jT",at=process.env.NEXT_PUBLIC_POSTHOG_HOST??process.env.POSTHOG_HOST??"https://us.i.posthog.com",lt="@inkly-org/cli@0.5.1",se=it(st(),".inkly","analytics.json"),ye=null,z=null,ve=null;function ct(){return!!be&&process.env.INKLY_TELEMETRY_DISABLED!=="1"}function ut(){return ct()?(ye??=new ot(be,{host:at,flushAt:1,flushInterval:0}),ye):null}async function dt(){try{let e=await tt(se,"utf8");return JSON.parse(e)}catch{return{}}}async function pt(e){await et(rt(se),{recursive:!0}),await nt(se,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384})}async function ft(){return z||(z=(async()=>{let e=await dt();if(typeof e.platformUserId=="string"&&e.platformUserId&&(ve=e.platformUserId),typeof e.distinctId=="string"&&e.distinctId)return e.distinctId;let t=`cli_${Qe()}`;return await pt({...e,distinctId:t}),t})(),z)}async function mt(){let e=await ft();return ve??e}function ht(){return{surface:"cli",release:process.env.POSTHOG_RELEASE??lt,node_version:process.versions.node,platform:process.platform,arch:process.arch,ci:!!process.env.CI}}async function ke(e,t={}){let n=ut();if(n)try{n.capture({distinctId:await mt(),event:e,properties:{...ht(),...t}})}catch{}}import{mkdir as gt,rename as wt,writeFile as yt}from"fs/promises";import{dirname as bt}from"path";async function Se(e,t,n){await gt(bt(e),{recursive:!0});let r=`${e}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;await yt(r,t,n?.mode!=null?{mode:n.mode}:void 0),await wt(r,e)}import{Stagehand as $t}from"@browserbasehq/stagehand";import{NodeHtmlMarkdown as Ut}from"node-html-markdown";function Pe(){return{urlMap:{},xpathMap:{}}}function vt(e){if(e.startsWith("@")){let t=e.slice(1);return t.startsWith("[")&&t.endsWith("]")?t.slice(1,-1):t}return e.startsWith("[")&&e.endsWith("]")&&/^\[\d+-\d+]$/.test(e)?e.slice(1,-1):e.startsWith("ref=")?e.slice(4):/^\d+-\d+$/.test(e)?e:null}function I(e,t){let n=vt(e);if(!n)return e;let r=t.xpathMap[n];if(!r)throw new Error(`Unknown ref "${n}" - run \`inkly capture nav snapshot\` first to populate refs (have ${Object.keys(t.xpathMap).length} refs).`);return r}function oe(e,t={}){let n=e.split(`
4
- `);return t.maxDepth!==void 0&&(n=n.filter(r=>B(r)<=t.maxDepth)),t.filter&&(n=Pt(n,t.filter)),t.trim?n=Nt(n):t.compact&&(n=xe(n)),(t.trim||t.compact)&&(n=St(n)),n.join(`
5
- `).trim()}function Ce(e){let t=e.match(/^\s*(?:\[[\w-]+]\s*)?([A-Za-z]+)/);return t?t[1].toLowerCase():null}function kt(e){let t=e.match(/^\s*(?:\[[\w-]+]\s*)?[A-Za-z]+(?:,[^:]*)?:\s*(.*)$/);return t?t[1].trim():""}function St(e){let r=[],i=0;for(;i<e.length;){let s=B(e[i]),o=Ce(e[i]),u=i+1;if(o)for(;u<e.length&&B(e[u])===s&&Ce(e[u])===o;)u+=1;let d=u-i,g=new Set;for(let p=i;p<u;p+=1)g.add(kt(e[p]));let y=g.size<=d/2;if(o&&d>=14&&y){for(let w=i;w<i+6;w+=1)r.push(e[w]);let p=" ".repeat(s*2);r.push(`${p}\u2026 (+${d-6} more ${o}, repeated)`),i=u}else r.push(e[i]),i+=1}return r}function Pt(e,t){let n=Ct(t);return ae(e,n)}function ae(e,t){let n=new Set;for(let r=0;r<e.length;r+=1){if(!t(e[r]??""))continue;n.add(r);let i=B(e[r]??"");for(let s=r-1;s>=0;s-=1){let o=B(e[s]??"");if(o<i&&(n.add(s),i=o,o===0))break}}return e.filter((r,i)=>n.has(i))}function Ct(e){let t=At(e);if(t)return r=>t.test(r);let n=e.toLowerCase();return r=>r.toLowerCase().includes(n)}function At(e){let t=e.match(/^\/(.+)\/([a-z]*)$/i);if(!t)return null;try{return new RegExp(t[1]??"",t[2]??"")}catch{return null}}function xe(e){let t=ae(e,xt);return t.length>0?t:e}function xt(e){return/\[\d+-\d+]/.test(e)||e.includes(": ")||/\b(button|link|textbox|checkbox|radio|combobox)\b/i.test(e)}var _t=["button","link","textbox","searchbox","checkbox","radio","combobox","listbox","option","switch","slider","spinbutton","tab","menuitem","menuitemcheckbox","menuitemradio","treeitem"],Et=["navigation","main","banner","contentinfo","complementary","search","form","dialog","alertdialog","menu","menubar","tablist","region"],W="^\\s*(?:\\[[\\w-]+]\\s*)?",Tt=new RegExp(`${W}(?:${_t.join("|")})\\b`,"i"),Mt=new RegExp(`${W}(?:${Et.join("|")})\\b`,"i"),It=new RegExp(`${W}heading\\b`,"i"),Lt=new RegExp(`${W}StaticText\\b`,"i");function Ae(e){return Lt.test(e)?!1:Tt.test(e)||It.test(e)||Mt.test(e)}var Rt=new RegExp(`${W}[\\w-]+(?:,[^:]*)?:\\s`,"i");function Dt(e){return Rt.test(e)}function Nt(e){let n=ae(e,Ae).filter(r=>Ae(r)||Dt(r));return n.length>0?n:xe(e)}function B(e){let t=e.match(/^\s*/);return Math.floor((t?.[0].length??0)/2)}var Ot={trim:!0},G=90,Ft=110,Te=1600,_e=2600,Ht=1800,Ee={width:1440,height:900},K=class{constructor(t,n){this.browserWsUrl=t;this.targetId=n;this.stagehand=null;this.context=null;this.refMaps=Pe()}async init(){if(this.stagehand)return;let t=new $t({disablePino:!0,env:"LOCAL",localBrowserLaunchOptions:{cdpUrl:this.browserWsUrl},verbose:0});try{await t.init()}catch(n){throw await t.close().catch(()=>{}),n}this.stagehand=t,this.context=t.context,this.selectRecorderPage()}selectRecorderPage(){if(!this.context)throw new Error("nav driver not initialized");let t=this.context.pages(),r=t.find(i=>{try{return i.targetId()===this.targetId}catch{return!1}})??this.activePageIfPresent()??t[0];if(!r)throw new Error("nav driver found no page in the attached browser");return this.context.setActivePage(r),r}activePageIfPresent(){try{return this.context?.activePage()??void 0}catch{return}}activePage(){return this.selectRecorderPage()}async snapshot(t){let n=this.activePage(),r=await n.snapshot();this.refMaps={urlMap:r.urlMap??{},xpathMap:r.xpathMap??{}};let i=oe(r.formattedTree,t);return t.includeMaps?{tree:i,url:n.url(),urlMap:r.urlMap,xpathMap:r.xpathMap}:{tree:i,url:n.url()}}async agentSnapshot(){let t=this.activePage(),n=await t.snapshot();return this.refMaps={urlMap:n.urlMap??{},xpathMap:n.xpathMap??{}},{tree:oe(n.formattedTree,Ot),url:t.url()}}url(){return this.activePage().url()}resolveRef(t){return I(t,this.refMaps)}async click(t){if(!this.stagehand)throw new Error("nav driver not initialized");this.activePage();let n=I(t,this.refMaps);return await this.stagehand.act({arguments:[],description:"click element",method:"click",selector:n}),{clicked:!0,selector:n}}async fill(t,n,r){if(!this.stagehand)throw new Error("nav driver not initialized");let i=this.activePage(),s=I(t,this.refMaps);return await this.stagehand.act({arguments:[n],description:"fill element",method:"fill",selector:s}),r&&await i.keyPress("Enter"),{filled:!0,pressedEnter:r,selector:s}}async type(t,n){return await this.activePage().type(t,{delay:n}),{typed:!0}}async key(t){return await this.activePage().keyPress(t),{pressed:t}}async select(t,n){let r=this.activePage(),i=I(t,this.refMaps);return{selected:await r.deepLocator(i).selectOption(n),selector:i}}async upload(t,n){let r=this.activePage(),i=I(t,this.refMaps);return await r.deepLocator(i).setInputFiles(n.length===1?n[0]:n),{uploaded:!0,files:n,selector:i}}async get(t,n){let r=this.activePage();if(t==="url")return{url:r.url()};if(t==="title")return{title:await r.title()};let i=I(n??"body",this.refMaps),s=r.deepLocator(i);if(t==="text")return{text:await s.textContent()};if(t==="html")return{html:await s.innerHtml()};if(t==="value")return{value:await s.inputValue()};if(t==="visible")return{visible:await s.isVisible()};if(t==="checked")return{checked:await s.isChecked()};if(t==="markdown")return{markdown:Ut.translate(await s.innerHtml())};if(t==="box"){let{x:o,y:u}=await s.centroid();return{x:Math.round(o),y:Math.round(u)}}throw new Error(`unknown get target "${t}" \u2014 expected url|title|text|html|value|visible|checked|markdown|box`)}async is(t,n){let i=this.activePage().deepLocator(I(n,this.refMaps));if(t==="visible")return{visible:await i.isVisible()};if(t==="checked")return{checked:await i.isChecked()};throw new Error(`unknown is check "${t}" \u2014 expected visible|checked`)}async wait(t){let n=this.activePage();if(t.type==="load")await n.waitForLoadState(t.arg??"load",t.timeoutMs);else if(t.type==="selector"){if(!t.arg)throw new Error("nav wait selector requires a <selector> argument");await n.waitForSelector(I(t.arg,this.refMaps),{state:t.state??"visible",timeout:t.timeoutMs??3e4})}else if(t.type==="timeout"){let r=Number(t.arg);if(!Number.isInteger(r)||r<0)throw new Error("nav wait timeout requires a non-negative integer <ms>");await n.waitForTimeout(r)}else throw new Error(`unknown wait type "${t.type}" \u2014 expected load|selector|timeout`);return{waited:!0}}async back(t){let n=this.activePage();return await n.goBack(t),{navigated:!0,url:n.url()}}async forward(t){let n=this.activePage();return await n.goForward(t),{navigated:!0,url:n.url()}}async reload(t){let n=this.activePage();return await n.reload(t),{reloaded:!0,url:n.url()}}refs(){return{count:Object.keys(this.refMaps.xpathMap).length,urlMap:this.refMaps.urlMap,xpathMap:this.refMaps.xpathMap}}async mouseClick(t,n,r={}){return await this.activePage().click(t,n,r),{clicked:!0}}async mouseHover(t,n){return await this.activePage().hover(t,n),{hovered:!0}}async mouseScroll(t,n,r,i){return await this.activePage().scroll(t,n,r,i),{scrolled:!0}}async scroll(t,n){let r=this.activePage(),i=Math.round(Ee.width/2),s=Math.round(Ee.height/2),o=Math.max(G,Math.round(Math.abs(n))),u=t==="up"?-1:1,d=Math.ceil(o/G),g=Math.max(1,d-1),y=Math.min(Math.round(_e/g),Math.max(Ft,Math.round(Ht/g))),p=Date.now(),w=o;for(let v=0;v<d&&!(Date.now()-p>_e);v+=1){let S=Math.min(G,w)*u;w-=G,await r.scroll(i,s,0,S),v<d-1&&await new Promise(P=>setTimeout(P,y))}return{scrolled:!0,direction:t,amount:o}}async close(){let t=this.stagehand;this.stagehand=null,this.context=null,t&&await t.close().catch(()=>{})}};import jt from"net";import Bt from"readline";import{rm as Me}from"fs/promises";import{join as le}from"path";import{homedir as Wt}from"os";function Vt(){return le(process.env.INKLY_CAPTURE_AGENT_HOME||le(Wt(),".inkly"),"capture-agent","sessions")}function Le(e){if(!/^[a-zA-Z0-9._:-]+$/.test(e))throw new Error(`invalid session id: ${e}`);return le(Vt(),`${e}.nav.sock`)}async function Re(e,t){let n=jt.createServer(r=>{let i=Bt.createInterface({input:r});r.once("error",()=>{i.close(),r.destroy()}),i.once("line",s=>{qt(s,t).then(o=>Ie(r,o)).catch(o=>Ie(r,{type:"error",error:o instanceof Error?o.message:String(o)})).finally(()=>{i.close(),r.end()})})});return await Me(e,{force:!0}).catch(()=>{}),await new Promise((r,i)=>{let s=o=>i(o);n.once("error",s),n.listen(e,()=>{n.off("error",s),r()})}),{close(){return new Promise(r=>{n.close(()=>{Me(e,{force:!0}).catch(()=>{}).finally(()=>r())})})}}}async function qt(e,t){let n;try{n=JSON.parse(e)}catch(r){return{type:"error",error:r instanceof Error?r.message:String(r)}}if(n.type!=="command"||typeof n.command!="string")return{id:n.id,type:"error",error:"invalid nav request"};try{let r=await t(n);return{id:n.id,type:"success",data:r}}catch(r){return{id:n.id,type:"error",error:r instanceof Error?r.message:String(r)}}}function Ie(e,t){e.write(`${JSON.stringify(t)}
2
+ import Mn from"mri";import{spawn as Kt,execFile as Ir}from"child_process";import{createHash as Rr,randomUUID as Dr}from"crypto";import{mkdir as Y,mkdtemp as $r,open as Ur,readFile as Q,readdir as Or,rm as Jt,writeFile as V}from"fs/promises";import{existsSync as Fe}from"fs";import{dirname as He,isAbsolute as jr,join as E,resolve as Zt,sep as Br}from"path";import{tmpdir as Vr,homedir as Xt}from"os";import{fileURLToPath as Yt}from"url";import{unzipSync as Gr,zipSync as Kr}from"fflate";import Qt from"ws";import Xr from"sharp";import Qr from"subset-font";import{zipSync as Dn}from"fflate";import{JSDOM as ri}from"jsdom";import{randomUUID as Qe}from"crypto";import{mkdir as et,readFile as tt,writeFile as nt}from"fs/promises";import{dirname as rt,join as it}from"path";import{homedir as st}from"os";import{PostHog as ot}from"posthog-node";var be=process.env.NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN??process.env.POSTHOG_PROJECT_TOKEN??"phc_Dmh4w8YFNosi3YHD4Sv7ShHX7ccS8kmtRcm8XSVmB5jT",at=process.env.NEXT_PUBLIC_POSTHOG_HOST??process.env.POSTHOG_HOST??"https://us.i.posthog.com",lt="@inkly-org/cli@0.5.1",se=it(st(),".inkly","analytics.json"),ye=null,z=null,ve=null;function ct(){return!!be&&process.env.INKLY_TELEMETRY_DISABLED!=="1"}function ut(){return ct()?(ye??=new ot(be,{host:at,flushAt:1,flushInterval:0}),ye):null}async function dt(){try{let e=await tt(se,"utf8");return JSON.parse(e)}catch{return{}}}async function pt(e){await et(rt(se),{recursive:!0}),await nt(se,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384})}async function ft(){return z||(z=(async()=>{let e=await dt();if(typeof e.platformUserId=="string"&&e.platformUserId&&(ve=e.platformUserId),typeof e.distinctId=="string"&&e.distinctId)return e.distinctId;let t=`cli_${Qe()}`;return await pt({...e,distinctId:t}),t})(),z)}async function mt(){let e=await ft();return ve??e}function ht(){return{surface:"cli",release:process.env.POSTHOG_RELEASE??lt,node_version:process.versions.node,platform:process.platform,arch:process.arch,ci:!!process.env.CI}}async function ke(e,t={}){let n=ut();if(n)try{n.capture({distinctId:await mt(),event:e,properties:{...ht(),...t}})}catch{}}import{mkdir as gt,rename as wt,writeFile as yt}from"fs/promises";import{dirname as bt}from"path";async function Se(e,t,n){await gt(bt(e),{recursive:!0});let r=`${e}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;await yt(r,t,n?.mode!=null?{mode:n.mode}:void 0),await wt(r,e)}import{mkdir as rr,readFile as ir,writeFile as sr}from"fs/promises";import{homedir as vt}from"os";import{dirname as lr,join as kt}from"path";import{readFile as zn}from"fs/promises";import{existsSync as Kn}from"fs";import{dirname as Zn,join as Xn}from"path";import{fileURLToPath as Qn}from"url";var ur=kt(vt(),".inkly","update-check.json"),dr=360*60*1e3;import{Stagehand as Ot}from"@browserbasehq/stagehand";import{NodeHtmlMarkdown as Ft}from"node-html-markdown";function Pe(){return{urlMap:{},xpathMap:{}}}function St(e){if(e.startsWith("@")){let t=e.slice(1);return t.startsWith("[")&&t.endsWith("]")?t.slice(1,-1):t}return e.startsWith("[")&&e.endsWith("]")&&/^\[\d+-\d+]$/.test(e)?e.slice(1,-1):e.startsWith("ref=")?e.slice(4):/^\d+-\d+$/.test(e)?e:null}function I(e,t){let n=St(e);if(!n)return e;let r=t.xpathMap[n];if(!r)throw new Error(`Unknown ref "${n}" - run \`inkly capture nav snapshot\` first to populate refs (have ${Object.keys(t.xpathMap).length} refs).`);return r}function oe(e,t={}){let n=e.split(`
4
+ `);return t.maxDepth!==void 0&&(n=n.filter(r=>B(r)<=t.maxDepth)),t.filter&&(n=At(n,t.filter)),t.trim?n=Ut(n):t.compact&&(n=xe(n)),(t.trim||t.compact)&&(n=Ct(n)),n.join(`
5
+ `).trim()}function Ce(e){let t=e.match(/^\s*(?:\[[\w-]+]\s*)?([A-Za-z]+)/);return t?t[1].toLowerCase():null}function Pt(e){let t=e.match(/^\s*(?:\[[\w-]+]\s*)?[A-Za-z]+(?:,[^:]*)?:\s*(.*)$/);return t?t[1].trim():""}function Ct(e){let r=[],i=0;for(;i<e.length;){let s=B(e[i]),o=Ce(e[i]),u=i+1;if(o)for(;u<e.length&&B(e[u])===s&&Ce(e[u])===o;)u+=1;let d=u-i,g=new Set;for(let p=i;p<u;p+=1)g.add(Pt(e[p]));let y=g.size<=d/2;if(o&&d>=14&&y){for(let w=i;w<i+6;w+=1)r.push(e[w]);let p=" ".repeat(s*2);r.push(`${p}\u2026 (+${d-6} more ${o}, repeated)`),i=u}else r.push(e[i]),i+=1}return r}function At(e,t){let n=xt(t);return ae(e,n)}function ae(e,t){let n=new Set;for(let r=0;r<e.length;r+=1){if(!t(e[r]??""))continue;n.add(r);let i=B(e[r]??"");for(let s=r-1;s>=0;s-=1){let o=B(e[s]??"");if(o<i&&(n.add(s),i=o,o===0))break}}return e.filter((r,i)=>n.has(i))}function xt(e){let t=_t(e);if(t)return r=>t.test(r);let n=e.toLowerCase();return r=>r.toLowerCase().includes(n)}function _t(e){let t=e.match(/^\/(.+)\/([a-z]*)$/i);if(!t)return null;try{return new RegExp(t[1]??"",t[2]??"")}catch{return null}}function xe(e){let t=ae(e,Et);return t.length>0?t:e}function Et(e){return/\[\d+-\d+]/.test(e)||e.includes(": ")||/\b(button|link|textbox|checkbox|radio|combobox)\b/i.test(e)}var Tt=["button","link","textbox","searchbox","checkbox","radio","combobox","listbox","option","switch","slider","spinbutton","tab","menuitem","menuitemcheckbox","menuitemradio","treeitem"],Mt=["navigation","main","banner","contentinfo","complementary","search","form","dialog","alertdialog","menu","menubar","tablist","region"],W="^\\s*(?:\\[[\\w-]+]\\s*)?",It=new RegExp(`${W}(?:${Tt.join("|")})\\b`,"i"),Lt=new RegExp(`${W}(?:${Mt.join("|")})\\b`,"i"),Rt=new RegExp(`${W}heading\\b`,"i"),Dt=new RegExp(`${W}StaticText\\b`,"i");function Ae(e){return Dt.test(e)?!1:It.test(e)||Rt.test(e)||Lt.test(e)}var Nt=new RegExp(`${W}[\\w-]+(?:,[^:]*)?:\\s`,"i");function $t(e){return Nt.test(e)}function Ut(e){let n=ae(e,Ae).filter(r=>Ae(r)||$t(r));return n.length>0?n:xe(e)}function B(e){let t=e.match(/^\s*/);return Math.floor((t?.[0].length??0)/2)}var Ht={trim:!0},G=90,jt=110,Te=1600,_e=2600,Bt=1800,Ee={width:1440,height:900},K=class{constructor(t,n){this.browserWsUrl=t;this.targetId=n;this.stagehand=null;this.context=null;this.refMaps=Pe()}async init(){if(this.stagehand)return;let t=new Ot({disablePino:!0,env:"LOCAL",localBrowserLaunchOptions:{cdpUrl:this.browserWsUrl},verbose:0});try{await t.init()}catch(n){throw await t.close().catch(()=>{}),n}this.stagehand=t,this.context=t.context,this.selectRecorderPage()}selectRecorderPage(){if(!this.context)throw new Error("nav driver not initialized");let t=this.context.pages(),r=t.find(i=>{try{return i.targetId()===this.targetId}catch{return!1}})??this.activePageIfPresent()??t[0];if(!r)throw new Error("nav driver found no page in the attached browser");return this.context.setActivePage(r),r}activePageIfPresent(){try{return this.context?.activePage()??void 0}catch{return}}activePage(){return this.selectRecorderPage()}async snapshot(t){let n=this.activePage(),r=await n.snapshot();this.refMaps={urlMap:r.urlMap??{},xpathMap:r.xpathMap??{}};let i=oe(r.formattedTree,t);return t.includeMaps?{tree:i,url:n.url(),urlMap:r.urlMap,xpathMap:r.xpathMap}:{tree:i,url:n.url()}}async agentSnapshot(){let t=this.activePage(),n=await t.snapshot();return this.refMaps={urlMap:n.urlMap??{},xpathMap:n.xpathMap??{}},{tree:oe(n.formattedTree,Ht),url:t.url()}}url(){return this.activePage().url()}resolveRef(t){return I(t,this.refMaps)}async click(t){if(!this.stagehand)throw new Error("nav driver not initialized");this.activePage();let n=I(t,this.refMaps);return await this.stagehand.act({arguments:[],description:"click element",method:"click",selector:n}),{clicked:!0,selector:n}}async fill(t,n,r){if(!this.stagehand)throw new Error("nav driver not initialized");let i=this.activePage(),s=I(t,this.refMaps);return await this.stagehand.act({arguments:[n],description:"fill element",method:"fill",selector:s}),r&&await i.keyPress("Enter"),{filled:!0,pressedEnter:r,selector:s}}async type(t,n){return await this.activePage().type(t,{delay:n}),{typed:!0}}async key(t){return await this.activePage().keyPress(t),{pressed:t}}async select(t,n){let r=this.activePage(),i=I(t,this.refMaps);return{selected:await r.deepLocator(i).selectOption(n),selector:i}}async upload(t,n){let r=this.activePage(),i=I(t,this.refMaps);return await r.deepLocator(i).setInputFiles(n.length===1?n[0]:n),{uploaded:!0,files:n,selector:i}}async get(t,n){let r=this.activePage();if(t==="url")return{url:r.url()};if(t==="title")return{title:await r.title()};let i=I(n??"body",this.refMaps),s=r.deepLocator(i);if(t==="text")return{text:await s.textContent()};if(t==="html")return{html:await s.innerHtml()};if(t==="value")return{value:await s.inputValue()};if(t==="visible")return{visible:await s.isVisible()};if(t==="checked")return{checked:await s.isChecked()};if(t==="markdown")return{markdown:Ft.translate(await s.innerHtml())};if(t==="box"){let{x:o,y:u}=await s.centroid();return{x:Math.round(o),y:Math.round(u)}}throw new Error(`unknown get target "${t}" \u2014 expected url|title|text|html|value|visible|checked|markdown|box`)}async is(t,n){let i=this.activePage().deepLocator(I(n,this.refMaps));if(t==="visible")return{visible:await i.isVisible()};if(t==="checked")return{checked:await i.isChecked()};throw new Error(`unknown is check "${t}" \u2014 expected visible|checked`)}async wait(t){let n=this.activePage();if(t.type==="load")await n.waitForLoadState(t.arg??"load",t.timeoutMs);else if(t.type==="selector"){if(!t.arg)throw new Error("nav wait selector requires a <selector> argument");await n.waitForSelector(I(t.arg,this.refMaps),{state:t.state??"visible",timeout:t.timeoutMs??3e4})}else if(t.type==="timeout"){let r=Number(t.arg);if(!Number.isInteger(r)||r<0)throw new Error("nav wait timeout requires a non-negative integer <ms>");await n.waitForTimeout(r)}else throw new Error(`unknown wait type "${t.type}" \u2014 expected load|selector|timeout`);return{waited:!0}}async back(t){let n=this.activePage();return await n.goBack(t),{navigated:!0,url:n.url()}}async forward(t){let n=this.activePage();return await n.goForward(t),{navigated:!0,url:n.url()}}async reload(t){let n=this.activePage();return await n.reload(t),{reloaded:!0,url:n.url()}}refs(){return{count:Object.keys(this.refMaps.xpathMap).length,urlMap:this.refMaps.urlMap,xpathMap:this.refMaps.xpathMap}}async mouseClick(t,n,r={}){return await this.activePage().click(t,n,r),{clicked:!0}}async mouseHover(t,n){return await this.activePage().hover(t,n),{hovered:!0}}async mouseScroll(t,n,r,i){return await this.activePage().scroll(t,n,r,i),{scrolled:!0}}async scroll(t,n){let r=this.activePage(),i=Math.round(Ee.width/2),s=Math.round(Ee.height/2),o=Math.max(G,Math.round(Math.abs(n))),u=t==="up"?-1:1,d=Math.ceil(o/G),g=Math.max(1,d-1),y=Math.min(Math.round(_e/g),Math.max(jt,Math.round(Bt/g))),p=Date.now(),w=o;for(let v=0;v<d&&!(Date.now()-p>_e);v+=1){let S=Math.min(G,w)*u;w-=G,await r.scroll(i,s,0,S),v<d-1&&await new Promise(P=>setTimeout(P,y))}return{scrolled:!0,direction:t,amount:o}}async close(){let t=this.stagehand;this.stagehand=null,this.context=null,t&&await t.close().catch(()=>{})}};import Wt from"net";import Vt from"readline";import{rm as Me}from"fs/promises";import{join as le}from"path";import{homedir as qt}from"os";function zt(){return le(process.env.INKLY_CAPTURE_AGENT_HOME||le(qt(),".inkly"),"capture-agent","sessions")}function Le(e){if(!/^[a-zA-Z0-9._:-]+$/.test(e))throw new Error(`invalid session id: ${e}`);return le(zt(),`${e}.nav.sock`)}async function Re(e,t){let n=Wt.createServer(r=>{let i=Vt.createInterface({input:r});r.once("error",()=>{i.close(),r.destroy()}),i.once("line",s=>{Gt(s,t).then(o=>Ie(r,o)).catch(o=>Ie(r,{type:"error",error:o instanceof Error?o.message:String(o)})).finally(()=>{i.close(),r.end()})})});return await Me(e,{force:!0}).catch(()=>{}),await new Promise((r,i)=>{let s=o=>i(o);n.once("error",s),n.listen(e,()=>{n.off("error",s),r()})}),{close(){return new Promise(r=>{n.close(()=>{Me(e,{force:!0}).catch(()=>{}).finally(()=>r())})})}}}async function Gt(e,t){let n;try{n=JSON.parse(e)}catch(r){return{type:"error",error:r instanceof Error?r.message:String(r)}}if(n.type!=="command"||typeof n.command!="string")return{id:n.id,type:"error",error:"invalid nav request"};try{let r=await t(n);return{id:n.id,type:"success",data:r}}catch(r){return{id:n.id,type:"error",error:r instanceof Error?r.message:String(r)}}}function Ie(e,t){e.write(`${JSON.stringify(t)}
6
6
  `)}var je=`Options:
7
7
  --url <url> URL to open and arm for recording.
8
8
  --name <name> Demo name written into the exported ZIP.
@@ -23,7 +23,7 @@ import En from"mri";import{spawn as zt,execFile as or}from"child_process";import
23
23
  done once in this profile survives, so later captures of the same site need
24
24
  no re-login. Implies --keep-profile. Run --headed the first time so the user
25
25
  can sign in; reuse can run headless.
26
- --no-unpack On stop, write only the ZIP.`,Yt=`inkly capture - capture an image/video walkthrough for an external browser agent
26
+ --no-unpack On stop, write only the ZIP.`,en=`inkly capture - capture an image/video walkthrough for an external browser agent
27
27
 
28
28
  Usage:
29
29
  inkly capture start --url <url> --name <name>
@@ -44,7 +44,7 @@ ${je}
44
44
  Output:
45
45
  Every subcommand prints JSON. This command does not accept prompts and does not plan or drive the page.
46
46
  For self-contained HTML snapshot capture, use \`inkly capture-html\`.
47
- `,Ur=`inkly capture-html - capture a self-contained HTML walkthrough for an external browser agent
47
+ `,ci=`inkly capture-html - capture a self-contained HTML walkthrough for an external browser agent
48
48
 
49
49
  Usage:
50
50
  inkly capture-html start --url <url> --name <name>
@@ -61,14 +61,14 @@ ${je}
61
61
 
62
62
  Output:
63
63
  Every subcommand prints JSON. This command does not accept prompts and does not plan or drive the page.
64
- `,De=He(Zt(import.meta.url));var Be=1440,We=900;var Ve=3e4,Qt=30,J=720,en=3e4,tn=350,nn=10,rn=1200,sn=1500,on=1e3,an=720,qe=60,ln=Math.round(an/qe);function $(e){return new Promise(t=>setTimeout(t,e))}function cn(e,t){if(!Object.prototype.hasOwnProperty.call(e,t))return;let n=e[t];return typeof n=="string"?n:""}function un(e){return{click_tag:e?.tag??null,has_click_label:!!e?.label,has_click_selector:!!e?.selector,has_click_alpha_id:!!e?.alphaId}}async function Z(e){await ke("inkly_cli_capture_step_captured",{runtime:e.session.runtime??"cli",capture_kind:e.session.cliCaptureKind??e.stepKind,step_kind:e.stepKind,action:e.action,step_count:e.session.cliScreens?.length??null,window_width:e.session.width,window_height:e.session.height,record_video:e.session.cliRecordVideo===!0,auto_apply_zoom:e.session.autoApplyZoom!==!1,...un(e.click)})}function Ne(e){let t=e.cliScreens??[],n=t[t.length-1]?.kind;return n==="video"||n==="html"?n:"image"}function dn(e,t,n){let r=cn(e,t);if(!r)throw new Error(`missing --${t} <value>
64
+ `,De=He(Yt(import.meta.url));var Be=1440,We=900;var Ve=3e4,tn=30,J=720,nn=3e4,rn=350,sn=10,on=1200,an=1500,ln=500,cn=720,qe=60,un=Math.round(cn/qe);function $(e){return new Promise(t=>setTimeout(t,e))}function dn(e,t){if(!Object.prototype.hasOwnProperty.call(e,t))return;let n=e[t];return typeof n=="string"?n:""}function pn(e){return{click_tag:e?.tag??null,has_click_label:!!e?.label,has_click_selector:!!e?.selector,has_click_alpha_id:!!e?.alphaId}}async function Z(e){await ke("inkly_cli_capture_step_captured",{runtime:e.session.runtime??"cli",capture_kind:e.session.cliCaptureKind??e.stepKind,step_kind:e.stepKind,action:e.action,step_count:e.session.cliScreens?.length??null,window_width:e.session.width,window_height:e.session.height,record_video:e.session.cliRecordVideo===!0,auto_apply_zoom:e.session.autoApplyZoom!==!1,...pn(e.click)})}function Ne(e){let t=e.cliScreens??[],n=t[t.length-1]?.kind;return n==="video"||n==="html"?n:"image"}function fn(e,t,n){let r=dn(e,t);if(!r)throw new Error(`missing --${t} <value>
65
65
 
66
- ${n}`);return r}function $e(e,t){let n=Kt(e);for(;;){let r=_(n,t);if(Fe(r))return r;let i=He(n);if(i===n)return null;n=i}}var O=class{constructor(t){this.nextId=1;this.pending=new Map;this.listeners=new Map;this.ws=new Xt(t,{perMessageDeflate:!1,maxPayload:512*1024*1024}),this.ready=new Promise((n,r)=>{this.ws.once("open",()=>n()),this.ws.once("error",i=>r(i))}),this.ws.on("message",n=>{let r=JSON.parse(n.toString());if(typeof r.id=="number"&&this.pending.has(r.id)){let s=this.pending.get(r.id);if(this.pending.delete(r.id),!s)return;r.error?s.reject(new Error(`${r.error.message??"CDP error"}: ${JSON.stringify(r.error.data??"")}`)):s.resolve(r.result??{});return}if(!r.method)return;let i=this.listeners.get(r.method);if(i)for(let s of i)s(r.params,r.sessionId)})}async send(t,n={},r){await this.ready;let i=this.nextId;this.nextId+=1;let s={id:i,method:t,params:n};return r&&(s.sessionId=r),new Promise((o,u)=>{this.pending.set(i,{resolve:o,reject:u}),this.ws.send(JSON.stringify(s),d=>{d&&(this.pending.delete(i),u(d))})})}on(t,n){let r=this.listeners.get(t)??new Set;return r.add(n),this.listeners.set(t,r),()=>r.delete(n)}close(){try{this.ws.close()}catch{}}};async function L(e,t,n,r=3e4){let i=await e.send("Runtime.evaluate",{expression:n,awaitPromise:!0,returnByValue:!0,timeout:r,userGesture:!0},t);if(i.exceptionDetails)throw new Error(`Runtime.evaluate failed: ${JSON.stringify(i.exceptionDetails)}`);return i.result?.value}async function ee(e,t){let r=(await e.send("Target.attachToTarget",{targetId:t,flatten:!0})).sessionId;if(typeof r!="string")throw new Error("Target.attachToTarget returned no sessionId");return r}async function Ue(e){return((await e.send("Target.getTargets",{filter:[{type:"page"}]})).targetInfos??[]).filter(r=>r.type==="page")}async function pn(e,t){let n=await L(e,t,`JSON.stringify({
66
+ ${n}`);return r}function $e(e,t){let n=Zt(e);for(;;){let r=E(n,t);if(Fe(r))return r;let i=He(n);if(i===n)return null;n=i}}var O=class{constructor(t){this.nextId=1;this.pending=new Map;this.listeners=new Map;this.ws=new Qt(t,{perMessageDeflate:!1,maxPayload:512*1024*1024}),this.ready=new Promise((n,r)=>{this.ws.once("open",()=>n()),this.ws.once("error",i=>r(i))}),this.ws.on("message",n=>{let r=JSON.parse(n.toString());if(typeof r.id=="number"&&this.pending.has(r.id)){let s=this.pending.get(r.id);if(this.pending.delete(r.id),!s)return;r.error?s.reject(new Error(`${r.error.message??"CDP error"}: ${JSON.stringify(r.error.data??"")}`)):s.resolve(r.result??{});return}if(!r.method)return;let i=this.listeners.get(r.method);if(i)for(let s of i)s(r.params,r.sessionId)})}async send(t,n={},r){await this.ready;let i=this.nextId;this.nextId+=1;let s={id:i,method:t,params:n};return r&&(s.sessionId=r),new Promise((o,u)=>{this.pending.set(i,{resolve:o,reject:u}),this.ws.send(JSON.stringify(s),d=>{d&&(this.pending.delete(i),u(d))})})}on(t,n){let r=this.listeners.get(t)??new Set;return r.add(n),this.listeners.set(t,r),()=>r.delete(n)}close(){try{this.ws.close()}catch{}}};async function L(e,t,n,r=3e4){let i=await e.send("Runtime.evaluate",{expression:n,awaitPromise:!0,returnByValue:!0,timeout:r,userGesture:!0},t);if(i.exceptionDetails)throw new Error(`Runtime.evaluate failed: ${JSON.stringify(i.exceptionDetails)}`);return i.result?.value}async function ee(e,t){let r=(await e.send("Target.attachToTarget",{targetId:t,flatten:!0})).sessionId;if(typeof r!="string")throw new Error("Target.attachToTarget returned no sessionId");return r}async function Ue(e){return((await e.send("Target.getTargets",{filter:[{type:"page"}]})).targetInfos??[]).filter(r=>r.type==="page")}async function mn(e,t){let n=await L(e,t,`JSON.stringify({
67
67
  innerWidth: window.innerWidth,
68
68
  innerHeight: window.innerHeight,
69
69
  outerWidth: window.outerWidth,
70
70
  outerHeight: window.outerHeight
71
- })`,5e3),r=JSON.parse(String(n)),i={innerWidth:Number(r.innerWidth),innerHeight:Number(r.innerHeight),outerWidth:Number(r.outerWidth),outerHeight:Number(r.outerHeight)};if(!Number.isFinite(i.innerWidth)||!Number.isFinite(i.innerHeight)||!Number.isFinite(i.outerWidth)||!Number.isFinite(i.outerHeight))throw new Error(`could not measure Chrome viewport: ${JSON.stringify(r)}`);return i}async function te(e,t,n,r,i){try{let o=(await e.send("Browser.getWindowForTarget",{targetId:n})).windowId;if(typeof o!="number")throw new Error("Browser.getWindowForTarget returned no windowId");for(let u=0;u<4;u+=1){let d=await pn(e,t),g=Math.max(0,d.outerWidth-d.innerWidth),y=Math.max(0,d.outerHeight-d.innerHeight),p=r+g,w=i+y;if(Math.abs(d.innerWidth-r)<=1&&Math.abs(d.innerHeight-i)<=1)return;await e.send("Browser.setWindowBounds",{windowId:o,bounds:{windowState:"normal",width:p,height:w}}),await $(250)}}catch{}await e.send("Emulation.setDeviceMetricsOverride",{width:r,height:i,deviceScaleFactor:1,mobile:!1},t).catch(()=>{}),await $(100)}function pe(e){if(e.length<24)return null;let t=[137,80,78,71,13,10,26,10];for(let o=0;o<t.length;o+=1)if(e[o]!==t[o])return null;if(String.fromCharCode(e[12],e[13],e[14],e[15])!=="IHDR")return null;let r=new DataView(e.buffer,e.byteOffset,e.byteLength),i=r.getUint32(16,!1),s=r.getUint32(20,!1);return i>0&&s>0?{width:i,height:s}:null}var ue=`(() => {
71
+ })`,5e3),r=JSON.parse(String(n)),i={innerWidth:Number(r.innerWidth),innerHeight:Number(r.innerHeight),outerWidth:Number(r.outerWidth),outerHeight:Number(r.outerHeight)};if(!Number.isFinite(i.innerWidth)||!Number.isFinite(i.innerHeight)||!Number.isFinite(i.outerWidth)||!Number.isFinite(i.outerHeight))throw new Error(`could not measure Chrome viewport: ${JSON.stringify(r)}`);return i}async function te(e,t,n,r,i){try{let o=(await e.send("Browser.getWindowForTarget",{targetId:n})).windowId;if(typeof o!="number")throw new Error("Browser.getWindowForTarget returned no windowId");for(let u=0;u<4;u+=1){let d=await mn(e,t),g=Math.max(0,d.outerWidth-d.innerWidth),y=Math.max(0,d.outerHeight-d.innerHeight),p=r+g,w=i+y;if(Math.abs(d.innerWidth-r)<=1&&Math.abs(d.innerHeight-i)<=1)return;await e.send("Browser.setWindowBounds",{windowId:o,bounds:{windowState:"normal",width:p,height:w}}),await $(250)}}catch{}await e.send("Emulation.setDeviceMetricsOverride",{width:r,height:i,deviceScaleFactor:1,mobile:!1},t).catch(()=>{}),await $(100)}function pe(e){if(e.length<24)return null;let t=[137,80,78,71,13,10,26,10];for(let o=0;o<t.length;o+=1)if(e[o]!==t[o])return null;if(String.fromCharCode(e[12],e[13],e[14],e[15])!=="IHDR")return null;let r=new DataView(e.buffer,e.byteOffset,e.byteLength),i=r.getUint32(16,!1),s=r.getUint32(20,!1);return i>0&&s>0?{width:i,height:s}:null}var ue=`(() => {
72
72
  if (window.__inklyCliRecorderInstalled) return;
73
73
  window.__inklyCliRecorderInstalled = true;
74
74
  window.__inklyCliLastClick = null;
@@ -263,7 +263,7 @@ function selectorFor(el) {
263
263
  maxX: Math.max(0, document.documentElement.scrollWidth - window.innerWidth),
264
264
  maxY: Math.max(0, document.documentElement.scrollHeight - window.innerHeight)
265
265
  }
266
- })`,5e3),r=JSON.parse(String(n));return{viewport:{width:Number(r.viewport?.width)||Be,height:Number(r.viewport?.height)||We},sourceUrl:typeof r.sourceUrl=="string"?r.sourceUrl:"",title:typeof r.title=="string"?r.title:"Captured screen",click:r.click??null,scroll:{x:Number(r.scroll?.x)||0,y:Number(r.scroll?.y)||0,maxX:Number(r.scroll?.maxX)||0,maxY:Number(r.scroll?.maxY)||0}}}function fn(){let e=_(De,"singlefile-injected.js");if(Fe(e))return e;let t=$e(process.cwd(),"packages/capture-extension/dist/singlefile-injected.js"),n=$e(De,"packages/capture-extension/dist/singlefile-injected.js"),r=t??n;if(!r)throw new Error("SingleFile bundle not found. Run `npm run extension:build` before --html capture.");return r}var mn={removeFrames:!0,blockScripts:!0,compressHTML:!1,compressCSS:!1,saveRawPage:!1,loadDeferredImages:!1,loadDeferredImagesMaxIdleTime:1500,loadDeferredImagesKeepZoomLevel:!1,loadDeferredImagesBlockCookies:!1,loadDeferredImagesBlockStorage:!1,blockMixedContent:!1,insertMetaCSP:!0,insertMetaNoIndex:!1,insertSingleFileComment:!1,removeAlternativeFonts:!0,removeAlternativeImages:!0,removeAlternativeMedias:!0,removeUnusedFonts:!0,backgroundSave:!1,removeUnusedStyles:!0,removeHiddenElements:!0,compressContent:!1,groupDuplicateImages:!0,groupDuplicateStylesheets:!0},de="__inklySingleFileFetch",hn=`(() => {
266
+ })`,5e3),r=JSON.parse(String(n));return{viewport:{width:Number(r.viewport?.width)||Be,height:Number(r.viewport?.height)||We},sourceUrl:typeof r.sourceUrl=="string"?r.sourceUrl:"",title:typeof r.title=="string"?r.title:"Captured screen",click:r.click??null,scroll:{x:Number(r.scroll?.x)||0,y:Number(r.scroll?.y)||0,maxX:Number(r.scroll?.maxX)||0,maxY:Number(r.scroll?.maxY)||0}}}function hn(){let e=E(De,"singlefile-injected.js");if(Fe(e))return e;let t=$e(process.cwd(),"packages/capture-extension/dist/singlefile-injected.js"),n=$e(De,"packages/capture-extension/dist/singlefile-injected.js"),r=t??n;if(!r)throw new Error("SingleFile bundle not found. Run `npm run extension:build` before --html capture.");return r}var gn={removeFrames:!0,blockScripts:!0,compressHTML:!1,compressCSS:!1,saveRawPage:!1,loadDeferredImages:!1,loadDeferredImagesMaxIdleTime:1500,loadDeferredImagesKeepZoomLevel:!1,loadDeferredImagesBlockCookies:!1,loadDeferredImagesBlockStorage:!1,blockMixedContent:!1,insertMetaCSP:!0,insertMetaNoIndex:!1,insertSingleFileComment:!1,removeAlternativeFonts:!0,removeAlternativeImages:!0,removeAlternativeMedias:!0,removeUnusedFonts:!0,backgroundSave:!1,removeUnusedStyles:!0,removeHiddenElements:!0,compressContent:!1,groupDuplicateImages:!0,groupDuplicateStylesheets:!0},de="__inklySingleFileFetch",wn=`(() => {
267
267
  if (globalThis.__inklyFetchInstalled) return;
268
268
  globalThis.__inklyFetchInstalled = true;
269
269
  const pending = new Map();
@@ -306,7 +306,7 @@ function selectorFor(el) {
306
306
  return viaNode(url, options);
307
307
  }
308
308
  };
309
- })();`;function gn(e,t){let n,r,i;try{let s=new URL(e);n=s.hostname,r=s.pathname||"/",i=s.protocol==="https:"}catch{return""}return t.filter(s=>{let o=s.domain.replace(/^\./,""),u=n===o||n.endsWith(`.${o}`),d=r.startsWith(s.path||"/"),g=!s.secure||i;return u&&d&&g}).map(s=>`${s.name}=${s.value}`).join("; ")}async function wn(e,t,n,r){let i;try{let s=JSON.parse(n);i=s.id;let o={...s.options?.headers??{}},u=gn(s.url,r);u&&(o.cookie=u),s.options?.referrer&&(o.referer=s.options.referrer);let d=await fetch(s.url,{headers:o,redirect:"follow"}),g=Buffer.from(await d.arrayBuffer()),y={};d.headers.forEach((w,v)=>{y[v]=w});let p={status:d.status,headers:y,data:g.toString("base64")};await L(e,t,`globalThis.__inklyResolveFetch(${i}, ${JSON.stringify(p)})`,2e4)}catch(s){if(i===void 0)return;await L(e,t,`globalThis.__inklyRejectFetch(${i}, ${JSON.stringify({error:String(s)})})`,2e4).catch(()=>{})}}var ce=Math.max(6e4,Number(process.env.INKLY_CAPTURE_TIMEOUT_MS)||24e4);async function yn(e,t,n=!1){let r=await Q(fn(),"utf8");await e.send("Network.enable",{},t).catch(()=>{}),await e.send("Runtime.addBinding",{name:de},t).catch(()=>{});let i=[];try{i=(await e.send("Network.getAllCookies",{},t)).cookies??[]}catch{}let s=e.on("Runtime.bindingCalled",(o,u)=>{if(u!==t)return;let d=o;d.name!==de||typeof d.payload!="string"||wn(e,t,d.payload,i)});try{await L(e,t,r,3e4),await L(e,t,hn,1e4);let o=await L(e,t,`(async () => {
309
+ })();`;function yn(e,t){let n,r,i;try{let s=new URL(e);n=s.hostname,r=s.pathname||"/",i=s.protocol==="https:"}catch{return""}return t.filter(s=>{let o=s.domain.replace(/^\./,""),u=n===o||n.endsWith(`.${o}`),d=r.startsWith(s.path||"/"),g=!s.secure||i;return u&&d&&g}).map(s=>`${s.name}=${s.value}`).join("; ")}async function bn(e,t,n,r){let i;try{let s=JSON.parse(n);i=s.id;let o={...s.options?.headers??{}},u=yn(s.url,r);u&&(o.cookie=u),s.options?.referrer&&(o.referer=s.options.referrer);let d=await fetch(s.url,{headers:o,redirect:"follow"}),g=Buffer.from(await d.arrayBuffer()),y={};d.headers.forEach((w,v)=>{y[v]=w});let p={status:d.status,headers:y,data:g.toString("base64")};await L(e,t,`globalThis.__inklyResolveFetch(${i}, ${JSON.stringify(p)})`,2e4)}catch(s){if(i===void 0)return;await L(e,t,`globalThis.__inklyRejectFetch(${i}, ${JSON.stringify({error:String(s)})})`,2e4).catch(()=>{})}}var ce=Math.max(6e4,Number(process.env.INKLY_CAPTURE_TIMEOUT_MS)||24e4);async function vn(e,t,n=!1){let r=await Q(hn(),"utf8");await e.send("Network.enable",{},t).catch(()=>{}),await e.send("Runtime.addBinding",{name:de},t).catch(()=>{});let i=[];try{i=(await e.send("Network.getAllCookies",{},t)).cookies??[]}catch{}let s=e.on("Runtime.bindingCalled",(o,u)=>{if(u!==t)return;let d=o;d.name!==de||typeof d.payload!="string"||bn(e,t,d.payload,i)});try{await L(e,t,r,3e4),await L(e,t,wn,1e4);let o=await L(e,t,`(async () => {
310
310
  const sf = globalThis.__inklySingleFile;
311
311
  if (!sf || typeof sf.getPageData !== "function") throw new Error("SingleFile not loaded");
312
312
  // initOptions (2nd arg) is forwarded to single-file-core/core/util.js
@@ -317,22 +317,22 @@ function selectorFor(el) {
317
317
  frameFetch: globalThis.__inklyPrivilegedFetch,
318
318
  };
319
319
  const data = await Promise.race([
320
- sf.getPageData(${JSON.stringify({...mn,blockVideos:n})}, initOptions),
320
+ sf.getPageData(${JSON.stringify({...gn,blockVideos:n})}, initOptions),
321
321
  new Promise((_, reject) => setTimeout(() => reject(new Error("SingleFile getPageData exceeded ${ce}ms")), ${ce}))
322
322
  ]);
323
323
  if (typeof data.content === "string") return data.content;
324
324
  return new TextDecoder().decode(new Uint8Array(data.content));
325
- })()`,ce+15e3);return String(o)}finally{s()}}async function bn(e,t){if(e.runtime!=="cli")throw new Error("HTML capture is only available for --runtime cli sessions");if(!e.captureDir)throw new Error("CLI capture session has no captureDir");let n=new O(e.browserWsUrl);try{let r=await ee(n,e.targetId);await n.send("Page.enable",{},r).catch(()=>{}),await n.send("Runtime.enable",{},r).catch(()=>{}),await ne(n,r),await te(n,r,e.targetId,e.width,e.height);let i=await re(n,r),s=await yn(n,r,e.cliBlockVideos===!0),o=(e.cliScreens?.length??0)+1,u=_(e.captureDir,`html-${String(o).padStart(3,"0")}`),d=_(u,"index.html");await Y(u,{recursive:!0}),await V(d,s,"utf8");let g={...e,cliScreens:[...e.cliScreens??[],{kind:"html",pngPath:null,htmlPath:d,viewport:i.viewport,naturalSize:i.viewport,sourceUrl:i.sourceUrl,title:i.title,click:t??i.click,scroll:i.scroll,capturedAt:new Date().toISOString()}],tabUrl:i.sourceUrl};return await n.send("Target.detachFromTarget",{sessionId:r}).catch(()=>{}),await F(g),g}finally{n.close()}}function vn(e,t){if(!e.length)return null;if(t==null)return e[e.length-1].data;for(let n=e.length-1;n>=0;n-=1)if(e[n].receivedAt<t)return e[n].data;return e[0].data}async function kn(e){await new Promise((t,n)=>{let r=zt("ffmpeg",e,{stdio:["ignore","ignore","pipe"]}),i=[];r.stderr.on("data",s=>i.push(s)),r.on("error",n),r.on("close",s=>{if(s===0){t();return}n(new Error(`ffmpeg exited ${s}: ${Buffer.concat(i).toString("utf8").slice(-2e3)}`))})})}function Sn(e){if(e.length<=2)return e;let t=[],n=0;for(let s=1;s<e.length;s++)e[s].receivedAt-e[s-1].receivedAt>tn&&(t.push({start:n,end:s-1}),n=s);t.push({start:n,end:e.length-1});let r=t[0],i=e[r.end].receivedAt-e[r.start].receivedAt;for(let s of t){let o=e[s.end].receivedAt-e[s.start].receivedAt;o>=i&&(r=s,i=o)}return e.slice(r.start,r.end+1)}async function Pn(e){let t=e.fps,n=[...e.frames].sort((C,x)=>C.receivedAt-x.receivedAt),r=[],i=n[0]?.receivedAt;if(i!==void 0){let C=1e3/t,x=i;for(let A of n)A.receivedAt<x&&A!==n[n.length-1]||(r.push(A),x=A.receivedAt+C)}let s=r.slice(-Math.ceil(Ve/1e3*t)-2);if(process.env.INKLY_NAV_DEBUG){let C=s.map((x,A)=>A===0?0:x.receivedAt-s[A-1].receivedAt);process.stderr.write(`[navdbg] writeVideo: raw=${n.length} sampled=${r.length} preTrim=${s.length} gaps=${JSON.stringify(C)}
326
- `)}let o=Sn(s),u=o[0]?.receivedAt,d=o[o.length-1]?.receivedAt,g=u!==void 0&&d!==void 0?d-u:0;if(o.length<nn||g<rn)return process.env.INKLY_NAV_DEBUG&&process.stderr.write(`[navdbg] video reject: frames=${o.length} durationMs=${g}
325
+ })()`,ce+15e3);return String(o)}finally{s()}}async function kn(e,t){if(e.runtime!=="cli")throw new Error("HTML capture is only available for --runtime cli sessions");if(!e.captureDir)throw new Error("CLI capture session has no captureDir");let n=new O(e.browserWsUrl);try{let r=await ee(n,e.targetId);await n.send("Page.enable",{},r).catch(()=>{}),await n.send("Runtime.enable",{},r).catch(()=>{}),await ne(n,r),await te(n,r,e.targetId,e.width,e.height);let i=await re(n,r),s=await vn(n,r,e.cliBlockVideos===!0),o=(e.cliScreens?.length??0)+1,u=E(e.captureDir,`html-${String(o).padStart(3,"0")}`),d=E(u,"index.html");await Y(u,{recursive:!0}),await V(d,s,"utf8");let g={...e,cliScreens:[...e.cliScreens??[],{kind:"html",pngPath:null,htmlPath:d,viewport:i.viewport,naturalSize:i.viewport,sourceUrl:i.sourceUrl,title:i.title,click:t??i.click,scroll:i.scroll,capturedAt:new Date().toISOString()}],tabUrl:i.sourceUrl};return await n.send("Target.detachFromTarget",{sessionId:r}).catch(()=>{}),await F(g),g}finally{n.close()}}function Sn(e,t){if(!e.length)return null;if(t==null)return e[e.length-1].data;for(let n=e.length-1;n>=0;n-=1)if(e[n].receivedAt<t)return e[n].data;return e[0].data}async function Pn(e){await new Promise((t,n)=>{let r=Kt("ffmpeg",e,{stdio:["ignore","ignore","pipe"]}),i=[];r.stderr.on("data",s=>i.push(s)),r.on("error",n),r.on("close",s=>{if(s===0){t();return}n(new Error(`ffmpeg exited ${s}: ${Buffer.concat(i).toString("utf8").slice(-2e3)}`))})})}function Cn(e){if(e.length<=2)return e;let t=[],n=0;for(let s=1;s<e.length;s++)e[s].receivedAt-e[s-1].receivedAt>rn&&(t.push({start:n,end:s-1}),n=s);t.push({start:n,end:e.length-1});let r=t[0],i=e[r.end].receivedAt-e[r.start].receivedAt;for(let s of t){let o=e[s.end].receivedAt-e[s.start].receivedAt;o>=i&&(r=s,i=o)}return e.slice(r.start,r.end+1)}async function An(e){let t=e.fps,n=[...e.frames].sort((C,_)=>C.receivedAt-_.receivedAt),r=[],i=n[0]?.receivedAt;if(i!==void 0){let C=1e3/t,_=i;for(let A of n)A.receivedAt<_&&A!==n[n.length-1]||(r.push(A),_=A.receivedAt+C)}let s=r.slice(-Math.ceil(Ve/1e3*t)-2);if(process.env.INKLY_NAV_DEBUG){let C=s.map((_,A)=>A===0?0:_.receivedAt-s[A-1].receivedAt);process.stderr.write(`[navdbg] writeVideo: raw=${n.length} sampled=${r.length} preTrim=${s.length} gaps=${JSON.stringify(C)}
326
+ `)}let o=Cn(s),u=o[0]?.receivedAt,d=o[o.length-1]?.receivedAt,g=u!==void 0&&d!==void 0?d-u:0;if(o.length<sn||g<on)return process.env.INKLY_NAV_DEBUG&&process.stderr.write(`[navdbg] video reject: frames=${o.length} durationMs=${g}
327
327
  `),null;if(new Set(o.map(C=>C.data)).size<=1)return process.env.INKLY_NAV_DEBUG&&process.stderr.write(`[navdbg] video reject: frozen (all ${o.length} frames identical)
328
- `),null;let y=Math.round(on/1e3*t),p=Array.from({length:y},()=>o[0]).concat(o),w=Math.ceil(sn/1e3*t),v=p.length>=w?p:p.concat(Array.from({length:w-p.length},()=>p[p.length-1])),S=_(e.captureDir,`video-${String(e.index).padStart(3,"0")}`);await Gt(S,{recursive:!0,force:!0}).catch(()=>{}),await Y(S,{recursive:!0});for(let[C,x]of v.entries())await V(_(S,`frame-${String(C+1).padStart(5,"0")}.png`),Buffer.from(x.data,"base64"));let P=_(S,"poster.png");await V(P,Buffer.from(o[0].data,"base64"));let R=_(e.captureDir,`video-${String(e.index).padStart(3,"0")}.webm`);await kn(["-y","-framerate",String(t),"-i",_(S,"frame-%05d.png"),"-c:v","libvpx-vp9","-pix_fmt","yuv420p","-deadline","realtime","-cpu-used","6",R]);let b=new Uint8Array(await Q(P));return{videoPath:R,posterPngPath:P,naturalSize:pe(b)??{width:Be,height:We}}}async function ze(e,t,n,r){if(!e.captureDir)throw new Error("CLI capture session has no captureDir");let i=Buffer.from(t,"base64"),s=(e.cliScreens?.length??0)+1,o=_(e.captureDir,`screen-${String(s).padStart(3,"0")}.png`);await Y(e.captureDir,{recursive:!0}),await V(o,i);let u=pe(i)??n.viewport,d={...e,cliScreens:[...e.cliScreens??[],{kind:"image",pngPath:o,viewport:n.viewport,naturalSize:u,sourceUrl:n.sourceUrl,title:n.title,click:r,scroll:n.scroll,capturedAt:new Date().toISOString()}],tabUrl:n.sourceUrl};return await F(d),d}async function Cn(e,t,n,r,i){if(e.runtime!=="cli")throw new Error("video capture is only available for --runtime cli sessions");if(!e.captureDir)throw new Error("CLI capture session has no captureDir");let s=r??null,o=null;try{if(!s){o=new O(e.browserWsUrl);let p=await ee(o,e.targetId);await o.send("Page.enable",{},p).catch(()=>{}),await o.send("Runtime.enable",{},p).catch(()=>{}),await ne(o,p),await te(o,p,e.targetId,e.width,e.height),s=await re(o,p),await o.send("Target.detachFromTarget",{sessionId:p}).catch(()=>{})}let u=(e.cliScreens?.length??0)+1,d=e.cliHeadless?qe:Qt,g=await Pn({frames:t,captureDir:e.captureDir,index:u,fps:d});if(!g)return i&&r?ze(e,i,r,n??null):Ge(e,void 0,n,"click");let y={...e,cliScreens:[...e.cliScreens??[],{kind:"video",pngPath:g.posterPngPath,videoPath:g.videoPath,posterPngPath:g.posterPngPath,viewport:s.viewport,naturalSize:g.naturalSize,sourceUrl:s.sourceUrl,title:s.title,click:n??s.click,scroll:s.scroll,capturedAt:new Date().toISOString()}],tabUrl:s.sourceUrl};return await F(y),y}finally{o?.close()}}async function Ge(e,t,n,r="click"){if(e.runtime!=="cli")throw new Error("capture is only available for --runtime cli sessions");if(!e.captureDir)throw new Error("CLI capture session has no captureDir");let i=new O(e.browserWsUrl);try{let s=await ee(i,e.targetId);await i.send("Page.enable",{},s).catch(()=>{}),await i.send("Runtime.enable",{},s).catch(()=>{}),await ne(i,s),await te(i,s,e.targetId,e.width,e.height);let o=await re(i,s),d=(await i.send("Page.captureScreenshot",{format:"png",fromSurface:!0,captureBeyondViewport:!1},s)).data;if(typeof d!="string")throw new Error("Page.captureScreenshot returned no data");let g=Buffer.from(d,"base64"),y=(e.cliScreens?.length??0)+1,p=_(e.captureDir,`screen-${String(y).padStart(3,"0")}.png`);await Y(e.captureDir,{recursive:!0}),await V(p,g);let w=pe(g)??o.viewport,v=r==="click"?n??o.click:null,S=t&&r==="click"?{...v??{x:.5,y:.5},label:t}:v,P={...e,cliScreens:[...e.cliScreens??[],{kind:"image",pngPath:p,viewport:o.viewport,naturalSize:w,sourceUrl:o.sourceUrl,title:o.title,click:S,scroll:o.scroll,capturedAt:new Date().toISOString()}],tabUrl:o.sourceUrl};return await i.send("Target.detachFromTarget",{sessionId:s}).catch(()=>{}),await F(P),P}finally{i.close()}}function Ke(){return _(process.env.INKLY_CAPTURE_AGENT_HOME||_(Jt(),".inkly"),"capture-agent","sessions")}function Je(e){if(!/^[a-zA-Z0-9._:-]+$/.test(e))throw new Error(`invalid session id: ${e}`);return _(Ke(),`${e}.json`)}function An(e){return _(Ke(),`${e}.listener.json`)}async function xn(e){try{let t=await Q(An(e),"utf8");return JSON.parse(t)}catch{return null}}async function F(e){await Se(Je(e.id),`${JSON.stringify(e,null,2)}
329
- `)}async function N(e){let t=await Q(Je(e),"utf8");return JSON.parse(t)}async function Ze(e){let t=dn(e,"session",Yt),n=await N(t);if(n.runtime!=="cli")throw new Error("listen subcommand is only available for cli runtime sessions");let r=await xn(t);process.stderr.write(`capture listener: session ${t} connecting to ${n.browserWsUrl}
330
- `);let i=new O(n.browserWsUrl),s=null,o=n.targetId,u=Promise.resolve(),d=Promise.resolve(),g=0,y=new Set,p=[],w=null,v=!1,S=null,P=null,R=!1,b=null,C=null;async function x(m){s&&(await i.send("Page.stopScreencast",{},s).catch(()=>{}),await i.send("Target.detachFromTarget",{sessionId:s}).catch(()=>{})),p=[],w=null,v=!1,S=null,P=null,o=m,s=await ee(i,m),await i.send("Page.enable",{},s).catch(()=>{}),await i.send("Runtime.enable",{},s).catch(()=>{});let h=await N(t).catch(()=>n);await te(i,s,m,h.width,h.height),await ne(i,s,!0),p=[],v=!1,S=null,P=null;let a=await N(t).catch(()=>h);a.cliRecordVideo&&a.cliCaptureKind!=="html"&&await i.send("Page.startScreencast",{format:"png",quality:90,maxWidth:a.width,maxHeight:a.height,everyNthFrame:1},s).catch(l=>{process.stderr.write(`capture video start failed: ${l.message}
331
- `)});let f=await N(t).catch(()=>n);await F({...f,targetId:m,cliListenerPid:f.cliListenerPid??r?.cliListenerPid??null,cliListenerLogPath:f.cliListenerLogPath??r?.cliListenerLogPath??null,cliListenerReadyAt:f.cliListenerReadyAt??new Date().toISOString()})}async function A(m){R||(R=!0,C&&(await C.close().catch(()=>{}),C=null),b&&(await b.close().catch(()=>{}),b=null),s&&(await i.send("Page.stopScreencast",{},s).catch(()=>{}),await i.send("Target.detachFromTarget",{sessionId:s}).catch(()=>{})),i.close(),process.exit(m))}process.once("SIGTERM",()=>{A(0)}),process.once("SIGINT",()=>{A(0)}),await i.send("Target.setDiscoverTargets",{discover:!0}).catch(()=>{});for(let m of await Ue(i).catch(()=>[]))y.add(m.targetId);await x(n.targetId);{let m=await N(t).catch(()=>n);await F({...m,targetId:o,cliListenerPid:m.cliListenerPid??r?.cliListenerPid??null,cliListenerLogPath:m.cliListenerLogPath??r?.cliListenerLogPath??null,cliListenerReadyAt:m.cliListenerReadyAt??new Date().toISOString()})}process.stderr.write(`capture listener: session ${t} armed and recording
332
- `);let q=async m=>{let h=await i.send("Page.captureScreenshot",{format:"png"},m).catch(()=>null),a=h&&h.data;typeof a=="string"&&(p.push({data:a,receivedAt:Date.now()}),p.length>J&&(p=p.slice(-J)))};try{b=new K(n.browserWsUrl,o),await b.init(),C=await Re(Le(t),async m=>{if(!b)throw new Error("nav driver unavailable");let h=b,a=m.params??{},f=async l=>{if(a.noSnapshot===!0)return l;try{await h.wait({type:"load",arg:"load",timeoutMs:5e3}).catch(()=>{});let c=await h.agentSnapshot();return{...l,snapshot:c}}catch{return l}};switch(m.command){case"snapshot":return b.snapshot({trim:a.full!==!0,filter:typeof a.filter=="string"?a.filter:void 0,maxDepth:typeof a.maxDepth=="number"?a.maxDepth:void 0,includeMaps:a.json===!0});case"click":{let l=a.selector;if(typeof l!="string"||!l)throw new Error("nav click requires a selector");let c=(await X(t)).steps??0;if(s){let T=s,U=n.cliHeadless?()=>q(T):void 0;await _n(i,T,h.resolveRef(l),{width:n.width,height:n.height},U).catch(()=>{})}if(s){let T=await i.send("Page.captureScreenshot",{format:"png",fromSurface:!0,captureBeyondViewport:!1},s).catch(()=>null),U=T&&T.data;w=typeof U=="string"?U:w}let k=await h.click(l),E=await Oe(t,c);return f({...k,steps:E.steps,lastLabel:E.lastLabel})}case"fill":{let l=a.selector,c=a.value;if(typeof l!="string"||!l)throw new Error("nav fill requires a selector");if(typeof c!="string")throw new Error("nav fill requires a value");return f(await h.fill(l,c,a.pressEnter===!0))}case"type":{let l=a.text;if(typeof l!="string")throw new Error("nav type requires text");return f(await h.type(l,typeof a.delay=="number"?a.delay:void 0))}case"key":{let l=a.key;if(typeof l!="string"||!l)throw new Error("nav press requires a key");return f(await h.key(l))}case"select":{let l=a.selector,c=a.values;if(typeof l!="string"||!l)throw new Error("nav select requires a selector");if(!Array.isArray(c)||c.some(k=>typeof k!="string"))throw new Error("nav select requires one or more string values");return f(await h.select(l,c))}case"upload":{let l=a.selector,c=a.files;if(typeof l!="string"||!l)throw new Error("nav upload requires a selector");if(!Array.isArray(c)||c.length===0||c.some(k=>typeof k!="string"))throw new Error("nav upload requires one or more file paths");return b.upload(l,c)}case"get":{let l=a.what;if(typeof l!="string"||!l)throw new Error("nav get requires a target");return b.get(l,typeof a.selector=="string"?a.selector:void 0)}case"is":{let l=a.check,c=a.selector;if(typeof l!="string"||!l)throw new Error("nav is requires a check");if(typeof c!="string"||!c)throw new Error("nav is requires a selector");return b.is(l,c)}case"wait":{let l=a.type;if(typeof l!="string"||!l)throw new Error("nav wait requires a type");return b.wait({type:l,arg:typeof a.arg=="string"?a.arg:void 0,state:typeof a.state=="string"?a.state:void 0,timeoutMs:typeof a.timeoutMs=="number"?a.timeoutMs:void 0})}case"back":return f(await h.back({waitUntil:typeof a.waitUntil=="string"?a.waitUntil:void 0,timeoutMs:typeof a.timeoutMs=="number"?a.timeoutMs:void 0}));case"forward":return f(await h.forward({waitUntil:typeof a.waitUntil=="string"?a.waitUntil:void 0,timeoutMs:typeof a.timeoutMs=="number"?a.timeoutMs:void 0}));case"reload":return f(await h.reload({waitUntil:typeof a.waitUntil=="string"?a.waitUntil:void 0,timeoutMs:typeof a.timeoutMs=="number"?a.timeoutMs:void 0}));case"scroll":{let l=a.direction==="up"?"up":"down",c=typeof a.amount=="number"&&a.amount>0?a.amount:Te;if(s){let k=s,E=n.cliHeadless?()=>q(k):void 0;await Xe(i,k,l,c,{width:n.width,height:n.height},E)}else await h.scroll(l,c);return f({scrolled:!0,direction:l,amount:c})}case"refs":return b.refs();case"mouse.click":{let l=a.x,c=a.y;if(typeof l!="number"||typeof c!="number")throw new Error("nav mouse click requires numeric x and y");let k=(await X(t)).steps??0,E=await h.mouseClick(l,c,{button:typeof a.button=="string"?a.button:void 0,clickCount:typeof a.clickCount=="number"?a.clickCount:void 0}),T=await Oe(t,k);return f({...E,steps:T.steps,lastLabel:T.lastLabel})}case"mouse.hover":{let l=a.x,c=a.y;if(typeof l!="number"||typeof c!="number")throw new Error("nav mouse hover requires numeric x and y");return b.mouseHover(l,c)}case"mouse.scroll":{let l=a.x,c=a.y,k=a.deltaX,E=a.deltaY;if(typeof l!="number"||typeof c!="number"||typeof k!="number"||typeof E!="number")throw new Error("nav mouse scroll requires numeric x, y, deltaX, deltaY");return f(await h.mouseScroll(l,c,k,E))}default:throw new Error(`unknown nav command: ${m.command}`)}})}catch(m){process.stderr.write(`capture nav driver init failed: ${m.message}
333
- `),b&&(await b.close().catch(()=>{}),b=null)}i.on("Target.targetCreated",m=>{let a=m.targetInfo;!a||a.type!=="page"||!(a.openerId===o||Date.now()<g)||(d=d.then(async()=>{await $(250),await x(a.targetId),y.add(a.targetId)}).catch(l=>{process.stderr.write(`capture target follow failed: ${l.message}
334
- `)}))}),i.on("Page.screencastFrame",(m,h)=>{if(h!==s)return;let a=m;typeof a.sessionId=="number"&&i.send("Page.screencastFrameAck",{sessionId:a.sessionId},h).catch(()=>{}),typeof a.data=="string"&&(p.push({data:a.data,receivedAt:Date.now()}),p.length>J&&(p=p.slice(-J)))});async function fe(){let m=await Ue(i).catch(()=>[]),h=m.find(a=>a.openerId===o)??m.find(a=>a.targetId!==o&&!y.has(a.targetId));for(let a of m)y.add(a.targetId);!h||h.targetId===o||await x(h.targetId)}async function me(m){!m||!s||await i.send("Page.navigate",{url:m},s).catch(h=>{process.stderr.write(`capture post-click navigation failed: ${h.message}
335
- `)})}i.on("Runtime.bindingCalled",(m,h)=>{if(h!==s)return;let a=m;if(a.name!=="__inklyCliCaptureEvent"&&a.name!=="__inklyCliCaptureClick"||typeof a.payload!="string")return;let f=null;try{let c=JSON.parse(a.payload);a.name==="__inklyCliCaptureClick"?f={type:"click",click:c,page:null}:f={type:c.type==="input"||c.type==="scroll"?c.type:"click",click:typeof c.click=="object"&&c.click?c.click:null,page:typeof c.page=="object"&&c.page?c.page:null}}catch{f=null}if(!f)return;let l=f.type==="click"?Date.now():null;if(f.type==="click")g=Date.now()+3e3;else{let c=Date.now();S=S??c,P=c,v=!0}u=u.then(async()=>{if(f.type!=="click")return;let c=Date.now(),k=S,E=P,T=v&&k!==null&&E!==null&&c-E<=en;v=!1,S=null,P=null;let U=Math.max(k?k-250:0,c-Ve),he=k?p.filter(M=>M.receivedAt>=U):[...p],ie=f.page?.navigationUrl??null;process.env.INKLY_NAV_DEBUG&&process.stderr.write(`[navdbg] click: attachVideo=${T} hadMotion=${v} motionStart=${k} bufFrames=${p.length} segFrames=${he.length} sinceMotion=${E?c-E:"n/a"}
336
- `);let H=w??vn(p,l);w=null;let j=f.page?{viewport:f.page.viewport,sourceUrl:f.page.url,title:f.page.title,click:f.click,scroll:f.page.scroll}:null;if(s&&(j||(j=await re(i,s).catch(()=>null)),!H)){let M=await i.send("Page.captureScreenshot",{format:"png",fromSurface:!0,captureBeyondViewport:!1},s).catch(()=>null),we=M&&M.data;H=typeof we=="string"?we:null}p=[];let D=await N(t).catch(()=>null);if(!D||D.runtime!=="cli"){await A(0);return}if(D.cliCaptureKind==="html"){await $(ie?500:2e3);let M=await bn(D,f.click);await Z({session:M,stepKind:"html",action:f.type,click:f.click}),await me(ie),await $(2e3),await d,await fe();return}if(await me(ie),await $(2e3),await d,await fe(),D.cliRecordVideo&&T){let M=await Cn(D,he,f.click,j??void 0,H);await Z({session:M,stepKind:Ne(M),action:f.type,click:f.click});return}if(H&&j){let M=await ze(D,H,j,f.click??null);await Z({session:M,stepKind:"image",action:f.type,click:f.click});return}let ge=await Ge(D,void 0,f.click,"click");await Z({session:ge,stepKind:Ne(ge),action:f.type,click:f.click})}).catch(c=>{process.stderr.write(`capture listener failed: ${c.message}
337
- `)})});let Ye=setInterval(()=>{N(t).catch(()=>{clearInterval(Ye),A(0)})},1e3);return await new Promise(()=>{}),0}async function X(e){let n=(await N(e).catch(()=>null))?.cliScreens??[],r=n[n.length-1];return{steps:n.length,lastLabel:r&&(r.click?.label||r.title)||null,lastKind:r?.kind??null}}async function Xe(e,t,n,r,i,s){let o=!!s,u=o?ln:90,d=1800,g=o?6e3:5e3,y=110,p=Math.round(i.width/2),w=Math.round(i.height/2),v=Math.max(u,Math.round(Math.abs(r))),S=n==="up"?-1:1,P=Math.ceil(v/u),R=Math.max(1,P-1),b=Math.min(Math.round(g/R),Math.max(y,Math.round(d/R)));await e.send("Input.dispatchMouseEvent",{type:"mouseMoved",x:p,y:w,button:"none"},t).catch(()=>{});let C=Date.now(),x=v;for(let A=0;A<P&&!(Date.now()-C>g);A+=1){let q=Math.min(u,x)*S;x-=u,await e.send("Input.dispatchMouseEvent",{type:"mouseWheel",x:p,y:w,deltaX:0,deltaY:q,button:"none"},t).catch(()=>{}),s&&await s(),!o&&A<P-1&&await $(b)}}async function _n(e,t,n,r,i){if(!n.startsWith("/"))return!1;let s=`(()=>{try{const el=document.evaluate(${JSON.stringify(n)},document,null,9,null).singleNodeValue;if(!el)return null;const r=el.getBoundingClientRect();const vh=window.innerHeight||${r.height};if(r.width<=0&&r.height<=0)return null;if(r.top>=0&&r.bottom<=vh)return 0;return Math.round(r.top-vh*0.2);}catch{return null;}})()`,o=await e.send("Runtime.evaluate",{expression:s,returnByValue:!0},t).catch(()=>null),u=o&&o.result?.value;return typeof u!="number"||Math.abs(u)<48?!1:(await Xe(e,t,u>0?"down":"up",Math.abs(u),r,i),!0)}async function Oe(e,t,n=7e3){let r=Date.now()+n,i=await X(e);for(;(i.steps??0)<=t&&Date.now()<r;)await $(200),i=await X(e);return i}var Or=20*6e4;async function Tn(){let e=En(process.argv.slice(2));process.exit(await Ze(e))}Tn().catch(e=>{process.stderr.write(`capture listener failed: ${e.message}
328
+ `),null;let y=Math.round(ln/1e3*t),p=Array.from({length:y},()=>o[0]).concat(o),w=Math.ceil(an/1e3*t),v=p.length>=w?p:p.concat(Array.from({length:w-p.length},()=>p[p.length-1])),S=E(e.captureDir,`video-${String(e.index).padStart(3,"0")}`);await Jt(S,{recursive:!0,force:!0}).catch(()=>{}),await Y(S,{recursive:!0});for(let[C,_]of v.entries())await V(E(S,`frame-${String(C+1).padStart(5,"0")}.png`),Buffer.from(_.data,"base64"));let P=E(S,"poster.png");await V(P,Buffer.from(o[0].data,"base64"));let R=E(e.captureDir,`video-${String(e.index).padStart(3,"0")}.webm`);await Pn(["-y","-framerate",String(t),"-i",E(S,"frame-%05d.png"),"-c:v","libvpx-vp9","-pix_fmt","yuv420p","-deadline","realtime","-cpu-used","6",R]);let b=new Uint8Array(await Q(P));return{videoPath:R,posterPngPath:P,naturalSize:pe(b)??{width:Be,height:We}}}async function ze(e,t,n,r){if(!e.captureDir)throw new Error("CLI capture session has no captureDir");let i=Buffer.from(t,"base64"),s=(e.cliScreens?.length??0)+1,o=E(e.captureDir,`screen-${String(s).padStart(3,"0")}.png`);await Y(e.captureDir,{recursive:!0}),await V(o,i);let u=pe(i)??n.viewport,d={...e,cliScreens:[...e.cliScreens??[],{kind:"image",pngPath:o,viewport:n.viewport,naturalSize:u,sourceUrl:n.sourceUrl,title:n.title,click:r,scroll:n.scroll,capturedAt:new Date().toISOString()}],tabUrl:n.sourceUrl};return await F(d),d}async function xn(e,t,n,r,i){if(e.runtime!=="cli")throw new Error("video capture is only available for --runtime cli sessions");if(!e.captureDir)throw new Error("CLI capture session has no captureDir");let s=r??null,o=null;try{if(!s){o=new O(e.browserWsUrl);let p=await ee(o,e.targetId);await o.send("Page.enable",{},p).catch(()=>{}),await o.send("Runtime.enable",{},p).catch(()=>{}),await ne(o,p),await te(o,p,e.targetId,e.width,e.height),s=await re(o,p),await o.send("Target.detachFromTarget",{sessionId:p}).catch(()=>{})}let u=(e.cliScreens?.length??0)+1,d=e.cliHeadless?qe:tn,g=await An({frames:t,captureDir:e.captureDir,index:u,fps:d});if(!g)return i&&r?ze(e,i,r,n??null):Ge(e,void 0,n,"click");let y={...e,cliScreens:[...e.cliScreens??[],{kind:"video",pngPath:g.posterPngPath,videoPath:g.videoPath,posterPngPath:g.posterPngPath,viewport:s.viewport,naturalSize:g.naturalSize,sourceUrl:s.sourceUrl,title:s.title,click:n??s.click,scroll:s.scroll,capturedAt:new Date().toISOString()}],tabUrl:s.sourceUrl};return await F(y),y}finally{o?.close()}}async function Ge(e,t,n,r="click"){if(e.runtime!=="cli")throw new Error("capture is only available for --runtime cli sessions");if(!e.captureDir)throw new Error("CLI capture session has no captureDir");let i=new O(e.browserWsUrl);try{let s=await ee(i,e.targetId);await i.send("Page.enable",{},s).catch(()=>{}),await i.send("Runtime.enable",{},s).catch(()=>{}),await ne(i,s),await te(i,s,e.targetId,e.width,e.height);let o=await re(i,s),d=(await i.send("Page.captureScreenshot",{format:"png",fromSurface:!0,captureBeyondViewport:!1},s)).data;if(typeof d!="string")throw new Error("Page.captureScreenshot returned no data");let g=Buffer.from(d,"base64"),y=(e.cliScreens?.length??0)+1,p=E(e.captureDir,`screen-${String(y).padStart(3,"0")}.png`);await Y(e.captureDir,{recursive:!0}),await V(p,g);let w=pe(g)??o.viewport,v=r==="click"?n??o.click:null,S=t&&r==="click"?{...v??{x:.5,y:.5},label:t}:v,P={...e,cliScreens:[...e.cliScreens??[],{kind:"image",pngPath:p,viewport:o.viewport,naturalSize:w,sourceUrl:o.sourceUrl,title:o.title,click:S,scroll:o.scroll,capturedAt:new Date().toISOString()}],tabUrl:o.sourceUrl};return await i.send("Target.detachFromTarget",{sessionId:s}).catch(()=>{}),await F(P),P}finally{i.close()}}function Ke(){return E(process.env.INKLY_CAPTURE_AGENT_HOME||E(Xt(),".inkly"),"capture-agent","sessions")}function Je(e){if(!/^[a-zA-Z0-9._:-]+$/.test(e))throw new Error(`invalid session id: ${e}`);return E(Ke(),`${e}.json`)}function _n(e){return E(Ke(),`${e}.listener.json`)}async function En(e){try{let t=await Q(_n(e),"utf8");return JSON.parse(t)}catch{return null}}async function F(e){await Se(Je(e.id),`${JSON.stringify(e,null,2)}
329
+ `)}async function N(e){let t=await Q(Je(e),"utf8");return JSON.parse(t)}async function Ze(e){let t=fn(e,"session",en),n=await N(t);if(n.runtime!=="cli")throw new Error("listen subcommand is only available for cli runtime sessions");let r=await En(t);process.stderr.write(`capture listener: session ${t} connecting to ${n.browserWsUrl}
330
+ `);let i=new O(n.browserWsUrl),s=null,o=n.targetId,u=Promise.resolve(),d=Promise.resolve(),g=0,y=new Set,p=[],w=null,v=!1,S=null,P=null,R=!1,b=null,C=null;async function _(m){s&&(await i.send("Page.stopScreencast",{},s).catch(()=>{}),await i.send("Target.detachFromTarget",{sessionId:s}).catch(()=>{})),p=[],w=null,v=!1,S=null,P=null,o=m,s=await ee(i,m),await i.send("Page.enable",{},s).catch(()=>{}),await i.send("Runtime.enable",{},s).catch(()=>{});let h=await N(t).catch(()=>n);await te(i,s,m,h.width,h.height),await ne(i,s,!0),p=[],v=!1,S=null,P=null;let a=await N(t).catch(()=>h);a.cliRecordVideo&&a.cliCaptureKind!=="html"&&await i.send("Page.startScreencast",{format:"png",quality:90,maxWidth:a.width,maxHeight:a.height,everyNthFrame:1},s).catch(l=>{process.stderr.write(`capture video start failed: ${l.message}
331
+ `)});let f=await N(t).catch(()=>n);await F({...f,targetId:m,cliListenerPid:f.cliListenerPid??r?.cliListenerPid??null,cliListenerLogPath:f.cliListenerLogPath??r?.cliListenerLogPath??null,cliListenerReadyAt:f.cliListenerReadyAt??new Date().toISOString()})}async function A(m){R||(R=!0,C&&(await C.close().catch(()=>{}),C=null),b&&(await b.close().catch(()=>{}),b=null),s&&(await i.send("Page.stopScreencast",{},s).catch(()=>{}),await i.send("Target.detachFromTarget",{sessionId:s}).catch(()=>{})),i.close(),process.exit(m))}process.once("SIGTERM",()=>{A(0)}),process.once("SIGINT",()=>{A(0)}),await i.send("Target.setDiscoverTargets",{discover:!0}).catch(()=>{});for(let m of await Ue(i).catch(()=>[]))y.add(m.targetId);await _(n.targetId);{let m=await N(t).catch(()=>n);await F({...m,targetId:o,cliListenerPid:m.cliListenerPid??r?.cliListenerPid??null,cliListenerLogPath:m.cliListenerLogPath??r?.cliListenerLogPath??null,cliListenerReadyAt:m.cliListenerReadyAt??new Date().toISOString()})}process.stderr.write(`capture listener: session ${t} armed and recording
332
+ `);let q=async m=>{let h=await i.send("Page.captureScreenshot",{format:"png"},m).catch(()=>null),a=h&&h.data;typeof a=="string"&&(p.push({data:a,receivedAt:Date.now()}),p.length>J&&(p=p.slice(-J)))};try{b=new K(n.browserWsUrl,o),await b.init(),C=await Re(Le(t),async m=>{if(!b)throw new Error("nav driver unavailable");let h=b,a=m.params??{},f=async l=>{if(a.noSnapshot===!0)return l;try{await h.wait({type:"load",arg:"load",timeoutMs:5e3}).catch(()=>{});let c=await h.agentSnapshot();return{...l,snapshot:c}}catch{return l}};switch(m.command){case"snapshot":return b.snapshot({trim:a.full!==!0,filter:typeof a.filter=="string"?a.filter:void 0,maxDepth:typeof a.maxDepth=="number"?a.maxDepth:void 0,includeMaps:a.json===!0});case"click":{let l=a.selector;if(typeof l!="string"||!l)throw new Error("nav click requires a selector");let c=(await X(t)).steps??0;if(s){let T=s,U=n.cliHeadless?()=>q(T):void 0;await Tn(i,T,h.resolveRef(l),{width:n.width,height:n.height},U).catch(()=>{})}if(s){let T=await i.send("Page.captureScreenshot",{format:"png",fromSurface:!0,captureBeyondViewport:!1},s).catch(()=>null),U=T&&T.data;w=typeof U=="string"?U:w}let k=await h.click(l),x=await Oe(t,c);return f({...k,steps:x.committed?x.steps:null,lastLabel:x.committed?x.lastLabel:"(step still committing)"})}case"fill":{let l=a.selector,c=a.value;if(typeof l!="string"||!l)throw new Error("nav fill requires a selector");if(typeof c!="string")throw new Error("nav fill requires a value");return f(await h.fill(l,c,a.pressEnter===!0))}case"type":{let l=a.text;if(typeof l!="string")throw new Error("nav type requires text");return f(await h.type(l,typeof a.delay=="number"?a.delay:void 0))}case"key":{let l=a.key;if(typeof l!="string"||!l)throw new Error("nav press requires a key");return f(await h.key(l))}case"select":{let l=a.selector,c=a.values;if(typeof l!="string"||!l)throw new Error("nav select requires a selector");if(!Array.isArray(c)||c.some(k=>typeof k!="string"))throw new Error("nav select requires one or more string values");return f(await h.select(l,c))}case"upload":{let l=a.selector,c=a.files;if(typeof l!="string"||!l)throw new Error("nav upload requires a selector");if(!Array.isArray(c)||c.length===0||c.some(k=>typeof k!="string"))throw new Error("nav upload requires one or more file paths");return b.upload(l,c)}case"get":{let l=a.what;if(typeof l!="string"||!l)throw new Error("nav get requires a target");return b.get(l,typeof a.selector=="string"?a.selector:void 0)}case"is":{let l=a.check,c=a.selector;if(typeof l!="string"||!l)throw new Error("nav is requires a check");if(typeof c!="string"||!c)throw new Error("nav is requires a selector");return b.is(l,c)}case"wait":{let l=a.type;if(typeof l!="string"||!l)throw new Error("nav wait requires a type");return b.wait({type:l,arg:typeof a.arg=="string"?a.arg:void 0,state:typeof a.state=="string"?a.state:void 0,timeoutMs:typeof a.timeoutMs=="number"?a.timeoutMs:void 0})}case"back":return f(await h.back({waitUntil:typeof a.waitUntil=="string"?a.waitUntil:void 0,timeoutMs:typeof a.timeoutMs=="number"?a.timeoutMs:void 0}));case"forward":return f(await h.forward({waitUntil:typeof a.waitUntil=="string"?a.waitUntil:void 0,timeoutMs:typeof a.timeoutMs=="number"?a.timeoutMs:void 0}));case"reload":return f(await h.reload({waitUntil:typeof a.waitUntil=="string"?a.waitUntil:void 0,timeoutMs:typeof a.timeoutMs=="number"?a.timeoutMs:void 0}));case"scroll":{let l=a.direction==="up"?"up":"down",c=typeof a.amount=="number"&&a.amount>0?a.amount:Te;if(s){let k=s,x=n.cliHeadless?()=>q(k):void 0;await Xe(i,k,l,c,{width:n.width,height:n.height},x)}else await h.scroll(l,c);return f({scrolled:!0,direction:l,amount:c})}case"refs":return b.refs();case"mouse.click":{let l=a.x,c=a.y;if(typeof l!="number"||typeof c!="number")throw new Error("nav mouse click requires numeric x and y");let k=(await X(t)).steps??0,x=await h.mouseClick(l,c,{button:typeof a.button=="string"?a.button:void 0,clickCount:typeof a.clickCount=="number"?a.clickCount:void 0}),T=await Oe(t,k);return f({...x,steps:T.committed?T.steps:null,lastLabel:T.committed?T.lastLabel:"(step still committing)"})}case"mouse.hover":{let l=a.x,c=a.y;if(typeof l!="number"||typeof c!="number")throw new Error("nav mouse hover requires numeric x and y");return b.mouseHover(l,c)}case"mouse.scroll":{let l=a.x,c=a.y,k=a.deltaX,x=a.deltaY;if(typeof l!="number"||typeof c!="number"||typeof k!="number"||typeof x!="number")throw new Error("nav mouse scroll requires numeric x, y, deltaX, deltaY");return f(await h.mouseScroll(l,c,k,x))}default:throw new Error(`unknown nav command: ${m.command}`)}})}catch(m){process.stderr.write(`capture nav driver init failed: ${m.message}
333
+ `),b&&(await b.close().catch(()=>{}),b=null)}i.on("Target.targetCreated",m=>{let a=m.targetInfo;!a||a.type!=="page"||!(a.openerId===o||Date.now()<g)||(d=d.then(async()=>{await $(250),await _(a.targetId),y.add(a.targetId)}).catch(l=>{process.stderr.write(`capture target follow failed: ${l.message}
334
+ `)}))}),i.on("Page.screencastFrame",(m,h)=>{if(h!==s)return;let a=m;typeof a.sessionId=="number"&&i.send("Page.screencastFrameAck",{sessionId:a.sessionId},h).catch(()=>{}),typeof a.data=="string"&&(p.push({data:a.data,receivedAt:Date.now()}),p.length>J&&(p=p.slice(-J)))});async function fe(){let m=await Ue(i).catch(()=>[]),h=m.find(a=>a.openerId===o)??m.find(a=>a.targetId!==o&&!y.has(a.targetId));for(let a of m)y.add(a.targetId);!h||h.targetId===o||await _(h.targetId)}async function me(m){!m||!s||await i.send("Page.navigate",{url:m},s).catch(h=>{process.stderr.write(`capture post-click navigation failed: ${h.message}
335
+ `)})}i.on("Runtime.bindingCalled",(m,h)=>{if(h!==s)return;let a=m;if(a.name!=="__inklyCliCaptureEvent"&&a.name!=="__inklyCliCaptureClick"||typeof a.payload!="string")return;let f=null;try{let c=JSON.parse(a.payload);a.name==="__inklyCliCaptureClick"?f={type:"click",click:c,page:null}:f={type:c.type==="input"||c.type==="scroll"?c.type:"click",click:typeof c.click=="object"&&c.click?c.click:null,page:typeof c.page=="object"&&c.page?c.page:null}}catch{f=null}if(!f)return;let l=f.type==="click"?Date.now():null;if(f.type==="click")g=Date.now()+3e3;else{let c=Date.now();S=S??c,P=c,v=!0}u=u.then(async()=>{if(f.type!=="click")return;let c=Date.now(),k=S,x=P,T=v&&k!==null&&x!==null&&c-x<=nn;v=!1,S=null,P=null;let U=Math.max(k?k-250:0,c-Ve),he=k?p.filter(M=>M.receivedAt>=U):[...p],ie=f.page?.navigationUrl??null;process.env.INKLY_NAV_DEBUG&&process.stderr.write(`[navdbg] click: attachVideo=${T} hadMotion=${v} motionStart=${k} bufFrames=${p.length} segFrames=${he.length} sinceMotion=${x?c-x:"n/a"}
336
+ `);let H=w??Sn(p,l);w=null;let j=f.page?{viewport:f.page.viewport,sourceUrl:f.page.url,title:f.page.title,click:f.click,scroll:f.page.scroll}:null;if(s&&(j||(j=await re(i,s).catch(()=>null)),!H)){let M=await i.send("Page.captureScreenshot",{format:"png",fromSurface:!0,captureBeyondViewport:!1},s).catch(()=>null),we=M&&M.data;H=typeof we=="string"?we:null}p=[];let D=await N(t).catch(()=>null);if(!D||D.runtime!=="cli"){await A(0);return}if(D.cliCaptureKind==="html"){await $(ie?500:2e3);let M=await kn(D,f.click);await Z({session:M,stepKind:"html",action:f.type,click:f.click}),await me(ie),await $(2e3),await d,await fe();return}if(await me(ie),await $(2e3),await d,await fe(),D.cliRecordVideo&&T){let M=await xn(D,he,f.click,j??void 0,H);await Z({session:M,stepKind:Ne(M),action:f.type,click:f.click});return}if(H&&j){let M=await ze(D,H,j,f.click??null);await Z({session:M,stepKind:"image",action:f.type,click:f.click});return}let ge=await Ge(D,void 0,f.click,"click");await Z({session:ge,stepKind:Ne(ge),action:f.type,click:f.click})}).catch(c=>{process.stderr.write(`capture listener failed: ${c.message}
337
+ `)})});let Ye=setInterval(()=>{N(t).catch(()=>{clearInterval(Ye),A(0)})},1e3);return await new Promise(()=>{}),0}async function X(e){let n=(await N(e).catch(()=>null))?.cliScreens??[],r=n[n.length-1];return{steps:n.length,lastLabel:r&&(r.click?.label||r.title)||null,lastKind:r?.kind??null}}async function Xe(e,t,n,r,i,s){let o=!!s,u=o?un:90,d=1800,g=o?6e3:5e3,y=110,p=Math.round(i.width/2),w=Math.round(i.height/2),v=Math.max(u,Math.round(Math.abs(r))),S=n==="up"?-1:1,P=Math.ceil(v/u),R=Math.max(1,P-1),b=Math.min(Math.round(g/R),Math.max(y,Math.round(d/R)));await e.send("Input.dispatchMouseEvent",{type:"mouseMoved",x:p,y:w,button:"none"},t).catch(()=>{});let C=Date.now(),_=v;for(let A=0;A<P&&!(Date.now()-C>g);A+=1){let q=Math.min(u,_)*S;_-=u,await e.send("Input.dispatchMouseEvent",{type:"mouseWheel",x:p,y:w,deltaX:0,deltaY:q,button:"none"},t).catch(()=>{}),s&&await s(),!o&&A<P-1&&await $(b)}}async function Tn(e,t,n,r,i){if(!n.startsWith("/"))return!1;let s=`(()=>{try{const el=document.evaluate(${JSON.stringify(n)},document,null,9,null).singleNodeValue;if(!el)return null;const r=el.getBoundingClientRect();const vh=window.innerHeight||${r.height};if(r.width<=0&&r.height<=0)return null;if(r.top>=0&&r.bottom<=vh)return 0;return Math.round(r.top-vh*0.2);}catch{return null;}})()`,o=await e.send("Runtime.evaluate",{expression:s,returnByValue:!0},t).catch(()=>null),u=o&&o.result?.value;return typeof u!="number"||Math.abs(u)<48?!1:(await Xe(e,t,u>0?"down":"up",Math.abs(u),r,i),!0)}async function Oe(e,t,n=7e3){let r=Date.now()+n,i=await X(e);for(;(i.steps??0)<=t&&Date.now()<r;)await $(200),i=await X(e);return{...i,committed:(i.steps??0)>t}}var ui=20*6e4;async function In(){let e=Mn(process.argv.slice(2));process.exit(await Ze(e))}In().catch(e=>{process.stderr.write(`capture listener failed: ${e.message}
338
338
  `),process.exit(1)});