agenqa 1.1.6 → 1.1.7
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/dist/cli.cjs +2 -2
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -39,5 +39,5 @@ Expecting one of '${r.join("', '")}'`);let s=`${e}Help`;return this.on(s,i=>{let
|
|
|
39
39
|
`:"")+this.retryErrorContext,this.retryErrorContext=null);let l=a?.cacheEnabled?await this._buildStepCacheKey(e,t,r,s,c,o):null;if(l){let f=await ze(l);if(f)return a.usedCache=!0,{playwrightCode:f.playwrightCode,description:f.description,isFinalStep:f.isFinalStep,forceFailure:f.forceFailure,forceFailureReason:f.forceFailureReason,userExperienceRate:f.userExperienceRate,userExperienceAdvices:f.userExperienceAdvices,fromCache:!0,cacheKey:l,cacheMeta:{projectId:e.projectId,testId:e.testId||e.sourceTestId||e.id,sessionId:e.sessionId,timing:"step",level:"test",actionId:null,testFolderId:e.testFolderId||null}}}let u=new FormData;u.append("test_name",e.testName||"Untitled Test"),u.append("test_description",e.testDescription||""),u.append("html_code",r||"");let d=new Blob([s],{type:"image/jpeg"});u.append("screenshot",d,"screenshot.jpeg"),c&&u.append("previous_steps",c),Array.isArray(e.files)&&e.files.length>0&&e.files.forEach((f,g)=>{u.append(`files[${g}][name]`,f.name||""),u.append(`files[${g}][description]`,f.description||"")});let h=await Ue(this.apiConfig.runTestUrl,{formData:u,headers:this.apiConfig.headers});return{playwrightCode:h.playwright_code,description:h.description,isFinalStep:h.is_final_step,forceFailure:h.force_failure,forceFailureReason:h.force_failure_reason,userExperienceRate:h.user_experience_rate,userExperienceAdvices:h.user_experience_advices,fromCache:!1,cacheKey:l,cacheMeta:{projectId:e.projectId,testId:e.testId||e.sourceTestId||e.id,sessionId:e.sessionId,timing:"step",level:"test",actionId:null,testFolderId:e.testFolderId||null}}}async _executePlaywrightCode(e,t,r,s,i=!1){try{let o=await this._prepareTestFiles(e);return await q.executePlaywrightCode(e.sessionId,e.url,r.playwrightCode,null,e.actionTimeout*1e3,r.isFinalStep,o,s,e.testFolderId,e.projectId,i)}catch(o){throw o.isLogged||(this.logger.addLog(e.id,"error",`Step ${t} execution error`,o.message),o.isLogged=!0),o}}async _prepareTestFiles(e){let t=[];if(Array.isArray(e.files))for(let r=0;r<e.files.length;r++){let s=e.files[r];s?.path&&s?.name?t[r]={name:s.name,description:s.description||"",path:s.path}:t[r]=null}return t}async _handleExecutionFailure(e,t,r,s,i,o,a,c,l){let u=`Step ${t} failed`,d=r.error;if(r.isExpectFailure){u=typeof a=="string"&&a.trim().length>0?`Step ${t} failed - ${a.trim()}`:`Step ${t} assertion failed`,this.logger.addLog(e.id,"error",u,d);let m=new Error(`${u}: ${d}`);return m.isLogged=!0,m.shouldRetryWithoutCache=l?.usedCache||!1,m.cacheUsed=l?.usedCache||!1,{shouldRetry:!1,error:m}}if(this.isRetryableError(r.error)&&s<i)return this.logger.addLog(e.id,"warning",`Step ${t} failed (attempt ${s+1}/${i}): ${r.error}`,d),this.retryErrorContext=`Step ${t} (attempt ${s+1}): Failed with error: ${r.error}`,{shouldRetry:!0};r.errorType==="execution"?u=`Step ${t} code execution failed`:r.errorType==="browser"&&(u=`Step ${t} browser error`),this.logger.addLog(e.id,"error",u,d);let f=new Error(`${u}: ${d}`);return f.isLogged=!0,f.shouldRetryWithoutCache=l?.usedCache||!1,f.cacheUsed=l?.usedCache||!1,{shouldRetry:!1,error:f}}_logStepDetails(e,t,r,s,i,o,a=!1){let c=r||"No description provided",l=a?" (cache)":"",u={};typeof i<"u"&&(u.user_experience_rate=i),typeof o<"u"&&(u.user_experience_advices=o),a&&(u.from_cache=!0),this.logger.addLog(e,"info",`Step ${t}${l}: ${c}`,null,u)}async _buildStepCacheKey(e,t,r,s,i,o){let a="v1",c=e.testId||e.sourceTestId||e.id||"unknown-test",l=e.projectId||"unknown-project",u=await this._hashString(i||""),d=this._buildFilesSignature(e.files),h=e.testFolderId||"",f=JSON.stringify({cacheVersion:a,projectId:l,sourceTestId:c,url:e.url||"",resetStateOption:o||"",maxSteps:e.maxSteps,actionTimeout:e.actionTimeout,environment:e.environment||"",role:e.role||"",previousStepsHash:u,filesSignature:d,testFolderId:h,stepNumber:t}),g=await this._hashString(f);return`step:${a}:${l}:${c}:${t}:${g}`}_buildFilesSignature(e){if(!Array.isArray(e)||e.length===0)return"no-files";let t=e.map(r=>({name:r?.name||"",description:r?.description||"",id:r?.id||""}));return this._simpleHash(JSON.stringify(t))}async _hashString(e){if(typeof e!="string")return"no-string";try{if(typeof crypto<"u"&&crypto.subtle?.digest){let r=new TextEncoder().encode(e),s=await crypto.subtle.digest("SHA-256",r);return Array.from(new Uint8Array(s)).map(i=>i.toString(16).padStart(2,"0")).join("")}}catch{}return this._simpleHash(e)}_simpleHash(e){let t=0,r=String(e);for(let s=0;s<r.length;s++)t=(t<<5)-t+r.charCodeAt(s),t|=0;return Math.abs(t).toString(16)}async _capturePageState(e,t){try{let r=await q.getCurrentState(e);if(r&&r.success)return{html:r.html,screenshot:r.screenshot}}catch(r){this.logger.addLog(t,"warning","Failed to capture page state",r.message)}return null}_sleep(e){return new Promise(t=>setTimeout(t,e))}_isNetworkError(e){if(!e||e.code==="ERR_CANCELED")return!1;if(e.isAxiosError&&!e.response)return!0;let t=typeof e.message=="string"?e.message.toLowerCase():"",r=typeof e.code=="string"?e.code.toLowerCase():"",s=["network error","net::err_","failed to fetch","getaddrinfo","socket hang up","econnreset","econnrefused","timed out","etimedout","ehostunreach","enotfound","network is unreachable"];return!!(s.some(i=>t.includes(i))||r&&s.some(i=>r.includes(i)))}isRetryableError(e){if(!e||typeof e!="string")return!1;let t=e.toLowerCase();return t.includes("strict mode violation")?!0:!(t.includes("assertion failed")||t.includes("expect(")&&!t.includes("timed out")||t.includes("expected")&&t.includes("received")&&!t.includes("timed out")||t.includes("assertionerror")||t.includes("expectation failed"))}};var Ze=class{constructor(e,t,r=()=>!1,s=()=>{}){this.logger=e,this.apiConfig=t,this.retryErrorContext=null,this.isStopRequested=r,this.executedProjectBeforeActions=new Map,this.recordActionCode=typeof s=="function"?s:()=>{}}async executeActions(e,t,r,s,i="test",o=null,a=null,c={}){let l=c?.enableCache!==!1,u=r.filter(m=>s==="before"&&!m.executeAfter||s==="after"&&m.executeAfter);if(this.isStopRequested())return this.logger.addLog(t,"warning",`${s} actions cancelled by user request`),{success:!1,message:`${s} actions cancelled by user`,cancelled:!0,usedCache:!1};if(u.length===0)return this.logger.addLog(t,"info",`No ${s} actions to execute`),{success:!0,message:`No ${s} actions to execute`,usedCache:!1};this.logger.addLog(t,"info",`Executing ${u.length} ${s} action(s) in inheritance order (Project->Test Folder->Test)`);let d=0,h=0,f=!1;for(let m=0;m<u.length;m++){if(this.isStopRequested())return this.logger.addLog(t,"warning",`Cancelled remaining ${s} actions after user stop request`),{success:!1,message:`${s} actions cancelled by user`,cancelled:!0,usedCache:f};let w=u[m];if(this._shouldSkipProjectBeforeAction(e,w,s,i)){this.logger.addLog(t,"info",`Skipping project-level ${s} action "${w.name}" for persistent session`);continue}try{let y=this._resolveActionUrl(w);this.logger.addLog(t,"info",`[${m+1}/${u.length}] Executing ${s} action: "${w.name}" (${w.level} level) - URL: ${y}`);let C=this._resolveActionStorage(w),k=(C?.cookies?.length||0)>0||Object.keys(C?.localStorage||{}).length>0||Object.keys(C?.sessionStorage||{}).length>0,p=null;if(k?p=await this._navigateWithBrowserState(e,w,y,t,i,o,a):p=await q.navigateToUrl(e,y,null,i,o,a),p?.cancelled)return this.logger.addLog(t,"warning",`${s} action "${w.name}" cancelled during navigation`),{success:!1,cancelled:!0,usedCache:f};if(p&&p.success===!1){let D=this._formatDetails(p.error,"Navigation failed");this.logger.addLog(t,"warning",`\u2717 ${s} action "${w.name}" navigation failed`,D),h++;continue}if(this.isStopRequested())return this.logger.addLog(t,"warning",`Cancelled ${s} action "${w.name}" due to user stop request`),{success:!1,message:`${s} actions cancelled by user`,cancelled:!0,usedCache:f};let b=typeof w.description=="string"?w.description.trim():"";if(!b){this._recordProjectBeforeActionSuccess(e,w,s,i);let v=!!w.storageOnly?`\u2713 ${s} action "${w.name}" storage configuration applied (no AI instructions)`:`\u2713 ${s} action "${w.name}" navigation completed (no description to execute)`;this.logger.addLog(t,"success",v),d++;continue}let E=await this._executeActionWithAI(e,{...w,description:b},y,t,s,i,o,a,m+1,{enableCache:l,testId:c?.testId,projectId:c?.projectId});if(E?.cacheUsed&&(f=!0),!E||E.cancelled)return{success:!1,cancelled:!0,usedCache:f};E.success?(d++,this._recordProjectBeforeActionSuccess(e,w,s,i)):h++}catch(y){let C=this._formatDetails(y);this.logger.addLog(t,"warning",`\u2717 ${s} action "${w.name}" failed with unexpected error`,C),h++}}let g=h===0;return{success:g,message:g?`${s} actions completed`:`${s} actions failed`,usedCache:f}}async _navigateWithBrowserState(e,t,r,s,i,o,a){let c=this._resolveActionStorage(t);this.logger.addLog(s,"info",`Action "${t.name}" includes browser state: ${t.cookies?.length||0} cookies, ${Object.keys(t.localStorage||{}).length} localStorage items, ${Object.keys(t.sessionStorage||{}).length} sessionStorage items`);let l=JSON.parse(JSON.stringify(c));return await q.navigateToUrlWithState(e,r,l,i,o,a)}async _executeActionWithAI(e,t,r,s,i,o,a,c,l=1,u={}){let d=u?.enableCache!==!1,h=!1,f=u?.testId||s,g=u?.projectId||c;if(this.isStopRequested())return this.logger.addLog(s,"warning",`${i} action "${t.name}" cancelled before execution`),{success:!1,cancelled:!0};let m=typeof t.actionTimeout=="number"?t.actionTimeout*1e3:6e4,w=typeof t.maxSteps=="number"?t.maxSteps:10,y=await q.getCurrentState(e);if(!y||!y.success){let O=this._formatDetails(y?.error);return this.logger.addLog(s,"warning",`\u2717 ${i} action "${t.name}" failed to capture page state: ${O}`,O),{success:!1}}let C=1,k="",p=!1,b=0,E=3,D=[5e3,15e3],v=0;for(;(!p||b>0)&&C<=w;){if(this.isStopRequested())return this.logger.addLog(s,"warning",`${i} action "${t.name}" cancelled by user`),{success:!1,cancelled:!0};try{let O=(t.description||"").trim(),T=k;this.retryErrorContext&&(T+=(T?`
|
|
40
40
|
`:"")+this.retryErrorContext,this.retryErrorContext=null);let ae=d?await this._buildActionCacheKey({action:t,timing:i,stepNumber:C,pageStateResult:y,previousStepsContext:T,resetStateOption:o,projectId:g,testId:f,sessionId:e,actionTimeoutMs:m,maxSteps:w,testFolderId:a}):null,K,L,he,fe,S,$,I,j=!1;if(ae){let A=await ze(ae);A&&(h=!0,j=!0,{playwrightCode:K,description:L,isFinalStep:he,forceFailure:fe,forceFailureReason:S,userExperienceRate:$,userExperienceAdvices:I}=A)}if(!j){let A=new FormData;A.append("test_name",`${i} action: ${t.name}`),A.append("test_description",O),A.append("html_code",y.html);let F=new Blob([y.screenshot],{type:"image/jpeg"});A.append("screenshot",F,"screenshot.jpeg"),T&&A.append("previous_steps",T),{playwright_code:K,description:L,is_final_step:he,forceFailure:fe,forceFailureReason:S,user_experience_rate:$,user_experience_advices:I}=await Ue(this.apiConfig.runTestUrl,{formData:A,headers:this.apiConfig.headers})}if(fe){let A=S||L;if(j&&v<D.length&&!this.isStopRequested()){let F=D[v];v++,this.logger.addLog(s,"warning",`Cache retry ${v}/2 after failure - waiting ${Math.round(F/1e3)}s before retrying ${i} action "${t.name}" step ${C} from cache`),await new Promise(_=>setTimeout(_,F));let B=await this._capturePageState(e,s);B&&(y=B),b=0;continue}return this._logActionDetails(s,t.name,L,y.screenshot,$,I,j),this.logger.addLog(s,"warning",`\u2717 ${i} action "${t.name}" failed: ${A}`,A),{success:!1,cacheUsed:h}}if(p=!!he,K){if(this.isStopRequested())return this.logger.addLog(s,"warning",`${i} action "${t.name}" cancelled before executing Playwright code`),{success:!1,cancelled:!0,cacheUsed:h};let A=j&&v<D.length&&!this.isStopRequested(),F=await q.executePlaywrightCode(e,r,K,null,m,p,[],o,a,c,A),B=F.cancelled?"cancelled":F.success?"success":"failed";if(this.recordActionCode({executionId:s,timing:i,actionName:t.name,actionLevel:t.level,actionOrder:l,stepNumber:C,attempt:b+1,description:L,code:K,status:B}),F.cancelled)return{success:!1,cancelled:!0};if(F.success){let z=await this._capturePageState(e,s);if(z&&(y=z),!j&&ae&&Ye(ae,{playwrightCode:K,description:L,isFinalStep:he,forceFailure:fe,forceFailureReason:S,userExperienceRate:$,userExperienceAdvices:I},{projectId:g,testId:f,sessionId:e,timing:i,level:t.level,actionId:t.id||null,testFolderId:a||null}),j&&(h=!0),this._logActionDetails(s,t.name,L,y.screenshot,$,I,j),k+=`Step ${C}: ${L}
|
|
41
41
|
`,!p){C++,b=0,v=0;continue}return this.logger.addLog(s,"success",`\u2713 ${i} action "${t.name}" executed successfully`),{success:!0,cacheUsed:h}}let _=!!F.isExpectFailure,ce=!_&&this.isRetryableError(F.error),M=this._formatDetails(F.error);if(ce&&b<E){b++,this.logger.addLog(s,"warning",`${i} action "${t.name}" step ${C} failed (attempt ${b}/${E}): ${F.error}`,M),this.retryErrorContext=`Step ${C} (attempt ${b}): Failed with error: ${F.error}`;let z=await this._capturePageState(e,s);z&&(y=z);continue}if(j&&v<D.length&&!this.isStopRequested()){let z=D[v];v++,this.logger.addLog(s,"warning",`Cache retry ${v}/2 after failure - waiting ${Math.round(z/1e3)}s before retrying ${i} action "${t.name}" step ${C} from cache`),await new Promise(Ce=>setTimeout(Ce,z));let be=await this._capturePageState(e,s);be&&(y=be),b=0;continue}let pe=_?"assertion failed":"execution failed";return this.logger.addLog(s,"warning",`\u2717 ${i} action "${t.name}" step ${C} ${pe}: ${F.error}`,M),{success:!1,cacheUsed:h}}let Z=await this._capturePageState(e,s);if(Z&&(y=Z),this._logActionDetails(s,t.name,L,y.screenshot,$,I,j),k+=`Step ${C}: ${L}
|
|
42
|
-
`,!p){C++,b=0,v=0;continue}return this.logger.addLog(s,"success",`\u2713 ${i} action "${t.name}" completed`),{success:!0,cacheUsed:h}}catch(O){let T=this._formatDetails(O);return this.logger.addLog(s,"warning",`\u2717 ${i} action "${t.name}" API failed: ${O.message}`,T),{success:!1,cacheUsed:h}}}let R=`Maximum of ${w} steps reached without completing action "${t.name}"`;return this.logger.addLog(s,"warning",`\u2717 ${i} action "${t.name}" reached maximum steps limit (${w}) without completing`,R),{success:!1,cacheUsed:h}}async _capturePageState(e,t){try{let r=await q.getCurrentState(e);if(r&&r.success)return r}catch(r){let s=this._formatDetails(r);this.logger.addLog(t,"warning","Failed to capture page state for action logging",s)}return null}_logActionDetails(e,t,r,s,i,o,a=!1){let c=a?" (cache)":"",l={};typeof i<"u"&&(l.user_experience_rate=i),typeof o<"u"&&(l.user_experience_advices=o),a&&(l.from_cache=!0),this.logger.addLog(e,"info",`${t}${c}: ${r||"No description provided"}`,null,l)}_formatDetails(e,t="Unknown error"){if(e instanceof Error)return e.stack||e.message||t;if(typeof e=="string")return e||t;if(e==null)return t;if(typeof e=="object")try{return JSON.stringify(e,null,2)}catch{return String(e)}return String(e)}async _buildActionCacheKey({action:e,timing:t,stepNumber:r,pageStateResult:s,previousStepsContext:i,resetStateOption:o,projectId:a,testId:c,sessionId:l,actionTimeoutMs:u,maxSteps:d,testFolderId:h}){let f="v1",g=await this._hashString(i||""),m=JSON.stringify({cacheVersion:f,actionId:e.id||"",actionName:e.name||"",actionUrl:e.url||"",actionLevel:e.level||"",timing:t,stepNumber:r,resetStateOption:o,actionTimeoutMs:u,maxSteps:d,projectId:a||"unknown-project",testId:c||"unknown-test",description:(e.description||"").trim(),storageOnly:!!e.storageOnly,testFolderId:h||e.testFolderId||"",cookies:e.cookies||[],localStorage:e.localStorage||{},sessionStorage:e.sessionStorage||{},previousStepsHash:g}),w=await this._hashString(m);return`action:${f}:${a||"project"}:${c||"test"}:${t}:${e.id||e.name||"unnamed"}:${w}`}async _hashString(e){if(typeof e!="string")return"no-string";try{if(typeof crypto<"u"&&crypto.subtle?.digest){let r=new TextEncoder().encode(e),s=await crypto.subtle.digest("SHA-256",r);return Array.from(new Uint8Array(s)).map(i=>i.toString(16).padStart(2,"0")).join("")}}catch{}return this._simpleHash(e)}_simpleHash(e){let t=0,r=String(e);for(let s=0;s<r.length;s++)t=(t<<5)-t+r.charCodeAt(s),t|=0;return Math.abs(t).toString(16)}_shouldSkipProjectBeforeAction(e,t,r,s){if(!e||r!=="before"||t.level!=="project"||!t.id||s==="test")return!1;let i=this.executedProjectBeforeActions.get(e);return i?i.has(t.id):!1}_recordProjectBeforeActionSuccess(e,t,r,s){!e||r!=="before"||t.level!=="project"||!t.id||s!=="test"&&(this.executedProjectBeforeActions.has(e)||this.executedProjectBeforeActions.set(e,new Set),this.executedProjectBeforeActions.get(e).add(t.id))}_resolveActionUrl(e){let t=typeof e?.cloudReplaceUrl=="string"?e.cloudReplaceUrl.trim():"";return e?.cloudUseLocalUrl===!1&&t?t:typeof e?.url=="string"?e.url.trim():""}_resolveActionStorage(e){return e?.cloudUseLocalStorage===!1&&e.cloudStorage?e.cloudStorage:{cookies:e.cookies||[],localStorage:e.localStorage||{},sessionStorage:e.sessionStorage||{}}}isRetryableError(e){if(!e||typeof e!="string")return!1;let t=e.toLowerCase();return t.includes("strict mode violation")?!0:!(t.includes("assertion failed")||t.includes("expect(")&&!t.includes("timed out")||t.includes("expected")&&t.includes("received")&&!t.includes("timed out")||t.includes("assertionerror")||t.includes("expectation failed"))}};Se();var ke=U(require("node:path"),1);Se();async function jr(n){let e=await V(ke.default.join(n,"structure.json"),{}),t=await V(ke.default.join(n,"project.json"),{}),r=await V(ke.default.join(n,"files.json"),{files:{}}),s=await V(ke.default.join(n,"cache.json"),{entries:[]});return{structure:e,projectMeta:t,filesIndex:r,cacheData:s}}function de(n){return typeof n!="string"?"":n.trim()}function Gn(n,e){let t=de(n),r=de(e);if(!r)return t;let s=t.replace(/\/+$/,""),i=r.replace(/^\/+/,"");return s?`${s}/${i}`:`/${i}`}function Jn(n,e,t){let r=de(n?.replaceUrl);if(r)return r;let s=de(n?.url);if(s)return s;let i=de(t?.replaceUrl);return i||Gn(e?.baseUrl||"",t?.path||"")}function Kn(n,e,t){let r=de(n?.cloudReplaceUrl);if(n?.cloudUseLocalUrl===!1&&r)return r;let s=de(t?.cloudReplaceUrl);if(t?.cloudUseLocalUrl===!1&&s)return s;let i=de(e?.cloudReplaceUrl);return e?.cloudUseLocalUrl===!1&&i?i:Jn(n,e,t)}function Ft(n=[],e){return n.map(t=>({...t,level:e}))}function zn(n,e,t){let r=[];return Array.isArray(n.actions)&&r.push(...Ft(n.actions,"project")),e&&Array.isArray(e.actions)&&r.push(...Ft(e.actions,"testFolder")),Array.isArray(t.actions)&&r.push(...Ft(t.actions,"test")),r}function Yn(n){return Array.isArray(n)?n.map(e=>({id:e?.id||"",name:e?.name||"",description:e?.description||""})):[]}function Pr(n){return Array.isArray(n)?n.map(e=>({id:e?.id||"",name:e?.name||"",description:e?.description||"",executeAfter:!!e?.executeAfter})):[]}function Qn(n,e,t,r){let s=Yn(n?.files),i=Pr(n?.actions),o=Pr(t?.actions),a={name:n?.name,description:n?.description,url:n?.url,maxSteps:n?.maxSteps,actionTimeout:n?.actionTimeout,resetStateOption:r,projectReset:e?.resetStateForEachTest,projectBaseUrl:e?.baseUrl,environment:n?.environment||"",role:n?.role||"",testFolderId:n?.testFolderId||"",testFolderReplaceUrl:t?.replaceUrl||"",testFolderActions:o,files:s,actions:i};try{return JSON.stringify(a)}catch{return`${n?.name||"test"}-${r}-${s.length}-${i.length}`}}function Xn(n,e,t){return Array.isArray(n.files)?n.files.map(r=>{if(!r?.id)return null;let s=e.files?.[r.id];if(!s?.path)throw new Error(`Missing stored file path for ${r.name||r.id}`);let i=et.default.join(t,s.path);return{id:r.id,name:r.name||s?.name||"",description:r.description||"",path:i}}).filter(Boolean):[]}function Zn(n){let e=[],t=Array.isArray(n.documents)?n.documents:[];for(let s of t)e.push({...s,testFolder:null});let r=Array.isArray(n.testFolders)?n.testFolders:[];for(let s of r){let i=Array.isArray(s.documents)?s.documents:[];for(let o of i)e.push({...o,testFolder:s})}return e}function es(n,e,t){let r=Zn(n);return e==="project"?r:e==="folder"?r.filter(s=>s.testFolder?.cloudId===t):e==="test"?r.filter(s=>s.cloudId===t):[]}async function kr({projectId:n,targetType:e,targetId:t,apiConfig:r,cacheEnabled:s,silent:i=!1}){let o=new qe({silent:i}),a=se(n),{structure:c,filesIndex:l,cacheData:u}=await jr(a),d=c||{},h=d.id||n,f=es(c,e,t),g=et.default.join(a,"cache-signatures.json"),m={},w=!1,y=!1,C=!1,k=Array.isArray(u.entries)&&u.entries.length>0;if(s)try{if(await _e(g)){let S=await V(g,{});S&&typeof S=="object"&&(m=S),y=!0}}catch{m={},y=!1}if(!f.length)throw new Error("No tests found for the selected target.");let p=et.default.join(a,"cache.json");$r(u.entries||{},s,{cachePath:p,cacheVersion:u.version||null});let b=new Ze(o,r),E=new Xe(o,r),D=Q.startExecutionGroup(),v=d?.queueFailureBehavior==="continueQueue"?"continueQueue":"stopQueue",R=[],O=new Map,T=0,ae=0;for(let S of f){let $=S.testFolder,I=S.resetStateOption||d?.resetStateForEachTest||"test";if(!(S.executeOnCloud!==!1)){ae++,o.addLog(S.cloudId||S.id||"unknown-test","info",`Skipping "${S.name||"Untitled Test"}" (set to run in app only).`);continue}let Z=Q.generateSessionId({...S,projectId:h,testFolderId:$?.id||null},I,D),A=S.id||S.testId||S.cloudId,F=S.name||"Untitled Test",B=Kn(S,d,$);if(!F.trim()||!S.description?.trim()||!B||!B.trim()){T++,o.addLog(A||"unknown-test","warning","Skipping test missing required name, description, or URL.");continue}if(s&&A){let _={...S,url:B,testFolderId:$?.id||S.testFolderId||null},ce=Qn(_,d,$,I),M=m[A];!y&&k&&!C?(Qe(h,A),C=!0):M&&M!==ce&&Qe(h,A),M!==ce&&(m[A]=ce,w=!0)}R.push({testEntry:S,testFolder:$,resetStateOption:I,sessionId:Z,testId:A,testName:F,testUrl:B}),O.set(Z,(O.get(Z)||0)+1)}if(!R.length)throw new Error("No valid tests found for the selected target.");T>0&&o.addLog("system","warning",`Skipping ${T} test(s) without required name, description, or URL.`),ae>0&&o.addLog("system","info",`Skipping ${ae} test(s) marked for app-only execution.`);let K=0,L=0,he=S=>{if(!S)return;let $=O.get(S);if(!$)return;let I=$-1;I<=0?O.delete(S):O.set(S,I)},fe=async(S,$,I=!1)=>{let j=$||S.resetStateOption||"test";if(j!=="never"){if(j==="testFolder"){if(I){await Q.cleanupSession();return}if((O.get(S.sessionId)||0)>1)return}await Q.cleanupSession()}};try{for(let S of R){let{testEntry:$,testFolder:I,resetStateOption:j,sessionId:Z,testId:A,testName:F,testUrl:B}=S,_={id:A,testId:A,sessionId:Z,testName:F,testDescription:$.description||"",projectId:h,testFolderId:I?.id||null,testFolderName:I?.name||null,url:B,actionTimeout:$.actionTimeout||60,testTimeout:$.testTimeout||300,maxSteps:$.maxSteps||50,actions:Array.isArray($.actions)?[...$.actions]:[],files:Xn($,l,a),environment:$.environment||"",role:$.role||"",resetStateOption:j,startedAt:new Date};o.addLog(_.id,"info",`Started executing test "${_.testName}"`);let ce=zn(d,I,_);try{let M=0,pe=!1,z=4,be=!1,Ce=!1;for(;M<z;){Q.shouldResetSession(_,j)&&await Q.cleanupSession(),Q.updateSessionTracking(_.sessionId,_.testFolderId);try{let me=await b.executeActions(_.sessionId,_.id,ce,"before",j,_.testFolderId,_.projectId,{enableCache:!pe,projectId:h,testId:A});if(!me?.success){let ge=new Error(`Before actions failed: ${me?.message||"Unknown error"}`);throw ge.shouldRetryWithoutCache=!0,me?.usedCache&&(ge.cacheUsed=!0),ge}let De=await q.getPageState(_.sessionId,_.url,null,j,_.testFolderId,_.projectId);if(!De?.success)throw new Error(De?.error||"Failed to capture initial page state");await E.executeTestSteps(_,De,j,{enableCache:!pe});let tt=await b.executeActions(_.sessionId,_.id,ce,"after",j,_.testFolderId,_.projectId,{enableCache:!pe,projectId:h,testId:A});if(!tt?.success){let ge=new Error(`After actions failed: ${tt?.message||"Unknown error"}`);throw ge.shouldRetryWithoutCache=!0,tt?.usedCache&&(ge.cacheUsed=!0),ge}o.addLog(_.id,"success",`Test "${_.testName}" completed successfully`),be=!0;break}catch(me){if(!pe&&!!me?.shouldRetryWithoutCache){pe=!0,Qe(_.projectId,A||null),Or(_.sessionId),o.addLog(_.id,"warning",`Cache invalidated after failure - retrying test "${_.testName}" without cache`),await Q.cleanupSession(),_.startedAt=new Date,M++;continue}o.addLog(_.id,"error",`Test "${_.testName}" failed`,me.message||String(me)),Ce=!0;break}}be?K++:Ce&&L++,await fe(_,j,Ce&&v==="stopQueue"),he(_.sessionId)}catch(M){o.addLog(_.id,"error",`Test "${_.testName}" failed`,M.message||String(M)),L++,await fe(_,j,v==="stopQueue"),he(_.sessionId)}if(L>0&&v==="stopQueue")break}}finally{await Q.cleanupSession()}if(s&&w)try{await Y(g,m)}catch{}return L>0?{success:!1,passed:K,failed:L,total:R.length}:{success:!0,passed:K,failed:L,total:R.length}}var J=new Yt,ts="1.1.6";J.name("agenqa").description("Agenqa CLI for cloud projects").version(ts);process.on("SIGINT",()=>{console.log(`
|
|
43
|
-
Interrupted. Exiting.`),process.exit(130)});function Dr(n,e,t){let r=Ct(t||$e(n,e));if(!r)throw new Error("API base URL is not configured in this build.");return r}function Dt(n,e){if(n===void 0)return null;let t=String(n).trim().toLowerCase();if(["y","yes"].includes(t))return!0;if(["n","no"].includes(t))return!1;console.error(`Invalid value for ${e}. Use "yes" or "no".`),process.exit(1)}function It(n){console.log(`Synced project ${n.project?.name||n.project?.id}`),console.log(`Files: ${n.files.downloaded} downloaded, ${n.files.skipped} skipped, ${n.files.removed} removed.`),n.cache&&(n.cacheDisabledGlobally?console.log("Cache disabled globally for this project."):console.log("Cache synced."))}function rs(n){return typeof n?.cacheCloudEnabled=="boolean"?n.cacheCloudEnabled:!!n?.cacheEnabled}function ns(n){return typeof n?.cacheLocalEnabled=="boolean"?n.cacheLocalEnabled:!!n?.cacheEnabled}async function Fe(n){throw ar(n)&&(console.error("Cloud key is invalid or expired. Please re-import the project."),process.exit(2)),n}J.command("import").description("Import a cloud project using project id and secret key").requiredOption("-p, --project <projectId>","Cloud project id").requiredOption("-s, --key-secret <secret>","Cloud key secret").option("--trust <yes|no>","Skip trust prompt by answering yes or no").option("--cache-local <yes|no>","Skip local cache prompt by answering yes or no").option("--cache-cloud <yes|no>","Skip cloud cache prompt by answering yes or no").action(async n=>{let e=await ne(),t=n.project.trim(),r=n.keySecret.trim(),s=Dr(e,t),i=Dt(n.trust,"--trust"),o=Dt(n.cacheLocal,"--cache-local"),a=Dt(n.cacheCloud,"--cache-cloud");(i??await ye("Importing projects from unknown sources can expose you to risks. Do you confirm you trust this project? (yes/no)",{required:!0}))!==!0&&(console.error("Import cancelled."),process.exit(1));let u=(o??await ye("Enable local cache on this machine? (required for cloud cache) (yes/no)"))===!0,d=!1;u?d=(a??await ye("Enable cloud cache? (warning: reuses collaborators' cached steps; only enable if you trust them to avoid security risks) (yes/no)"))===!0:a===!0&&(console.error("Cloud cache requires local cache. Re-run with --cache-local yes or omit --cache-cloud."),process.exit(1));let h={keyToken:r,cacheCloudEnabled:d,cacheLocalEnabled:u,baseUrl:s,importedAt:new Date().toISOString()};e.projects[t]=h,await Ae(e),await Te(t);try{let f=await He(e,t);It(f),console.log("Import completed.")}catch(f){await Fe(f),console.error(f.message||String(f)),process.exit(1)}});J.command("list").description("List stored projects").action(async()=>{let n=await ne(),e=Object.entries(n.projects||{});if(e.length===0){console.log("No projects imported.");return}let t=[];for(let[a,c]of e){let l=null;try{l=await V(Fr.default.join(se(a),"project.json"),null)}catch(f){console.error(`Warning: failed to read metadata for project ${a}: ${f.message||f}`)}let u=rs(c)?"enabled":"disabled",d=c.importedAt||"import time unknown",h=$e(n,a)||"base URL not set";t.push([a,l?.name||"",h,u,d])}let r=["Project ID","Name","Base URL","Cache","Imported At"],s=r.map((a,c)=>Math.max(a.length,...t.map(l=>(l[c]||"").length))),i=s.map(a=>"-".repeat(a)).join("-+-"),o=a=>a.map((c,l)=>String(c||"").padEnd(s[l]," ")).join(" | ");console.log("Stored projects:"),console.log(o(r)),console.log(i),t.forEach(a=>console.log(o(a)))});J.command("sync").description("Sync a cloud project locally").requiredOption("-p, --project <projectId>","Cloud project id").action(async n=>{let e=await ne(),t=n.project.trim();try{let r=await He(e,t);It(r)}catch(r){await Fe(r),console.error(r.message||String(r)),process.exit(1)}});J.command("remove-project").description("Remove an imported project and local data").requiredOption("-p, --project <projectId>","Cloud project id").action(async n=>{let e=n.project.trim(),t=await ne();t.projects?.[e]||(console.error(`Project ${e} is not imported. Run
|
|
42
|
+
`,!p){C++,b=0,v=0;continue}return this.logger.addLog(s,"success",`\u2713 ${i} action "${t.name}" completed`),{success:!0,cacheUsed:h}}catch(O){let T=this._formatDetails(O);return this.logger.addLog(s,"warning",`\u2717 ${i} action "${t.name}" API failed: ${O.message}`,T),{success:!1,cacheUsed:h}}}let R=`Maximum of ${w} steps reached without completing action "${t.name}"`;return this.logger.addLog(s,"warning",`\u2717 ${i} action "${t.name}" reached maximum steps limit (${w}) without completing`,R),{success:!1,cacheUsed:h}}async _capturePageState(e,t){try{let r=await q.getCurrentState(e);if(r&&r.success)return r}catch(r){let s=this._formatDetails(r);this.logger.addLog(t,"warning","Failed to capture page state for action logging",s)}return null}_logActionDetails(e,t,r,s,i,o,a=!1){let c=a?" (cache)":"",l={};typeof i<"u"&&(l.user_experience_rate=i),typeof o<"u"&&(l.user_experience_advices=o),a&&(l.from_cache=!0),this.logger.addLog(e,"info",`${t}${c}: ${r||"No description provided"}`,null,l)}_formatDetails(e,t="Unknown error"){if(e instanceof Error)return e.stack||e.message||t;if(typeof e=="string")return e||t;if(e==null)return t;if(typeof e=="object")try{return JSON.stringify(e,null,2)}catch{return String(e)}return String(e)}async _buildActionCacheKey({action:e,timing:t,stepNumber:r,pageStateResult:s,previousStepsContext:i,resetStateOption:o,projectId:a,testId:c,sessionId:l,actionTimeoutMs:u,maxSteps:d,testFolderId:h}){let f="v1",g=await this._hashString(i||""),m=JSON.stringify({cacheVersion:f,actionId:e.id||"",actionName:e.name||"",actionUrl:e.url||"",actionLevel:e.level||"",timing:t,stepNumber:r,resetStateOption:o,actionTimeoutMs:u,maxSteps:d,projectId:a||"unknown-project",testId:c||"unknown-test",description:(e.description||"").trim(),storageOnly:!!e.storageOnly,testFolderId:h||e.testFolderId||"",cookies:e.cookies||[],localStorage:e.localStorage||{},sessionStorage:e.sessionStorage||{},previousStepsHash:g}),w=await this._hashString(m);return`action:${f}:${a||"project"}:${c||"test"}:${t}:${e.id||e.name||"unnamed"}:${w}`}async _hashString(e){if(typeof e!="string")return"no-string";try{if(typeof crypto<"u"&&crypto.subtle?.digest){let r=new TextEncoder().encode(e),s=await crypto.subtle.digest("SHA-256",r);return Array.from(new Uint8Array(s)).map(i=>i.toString(16).padStart(2,"0")).join("")}}catch{}return this._simpleHash(e)}_simpleHash(e){let t=0,r=String(e);for(let s=0;s<r.length;s++)t=(t<<5)-t+r.charCodeAt(s),t|=0;return Math.abs(t).toString(16)}_shouldSkipProjectBeforeAction(e,t,r,s){if(!e||r!=="before"||t.level!=="project"||!t.id||s==="test")return!1;let i=this.executedProjectBeforeActions.get(e);return i?i.has(t.id):!1}_recordProjectBeforeActionSuccess(e,t,r,s){!e||r!=="before"||t.level!=="project"||!t.id||s!=="test"&&(this.executedProjectBeforeActions.has(e)||this.executedProjectBeforeActions.set(e,new Set),this.executedProjectBeforeActions.get(e).add(t.id))}_resolveActionUrl(e){let t=typeof e?.cloudReplaceUrl=="string"?e.cloudReplaceUrl.trim():"";return e?.cloudUseLocalUrl===!1&&t?t:typeof e?.url=="string"?e.url.trim():""}_resolveActionStorage(e){return e?.cloudUseLocalStorage===!1&&e.cloudStorage?e.cloudStorage:{cookies:e.cookies||[],localStorage:e.localStorage||{},sessionStorage:e.sessionStorage||{}}}isRetryableError(e){if(!e||typeof e!="string")return!1;let t=e.toLowerCase();return t.includes("strict mode violation")?!0:!(t.includes("assertion failed")||t.includes("expect(")&&!t.includes("timed out")||t.includes("expected")&&t.includes("received")&&!t.includes("timed out")||t.includes("assertionerror")||t.includes("expectation failed"))}};Se();var ke=U(require("node:path"),1);Se();async function jr(n){let e=await V(ke.default.join(n,"structure.json"),{}),t=await V(ke.default.join(n,"project.json"),{}),r=await V(ke.default.join(n,"files.json"),{files:{}}),s=await V(ke.default.join(n,"cache.json"),{entries:[]});return{structure:e,projectMeta:t,filesIndex:r,cacheData:s}}function de(n){return typeof n!="string"?"":n.trim()}function Gn(n,e){let t=de(n),r=de(e);if(!r)return t;let s=t.replace(/\/+$/,""),i=r.replace(/^\/+/,"");return s?`${s}/${i}`:`/${i}`}function Jn(n,e,t){let r=de(n?.replaceUrl);if(r)return r;let s=de(n?.url);if(s)return s;let i=de(t?.replaceUrl);return i||Gn(e?.baseUrl||"",t?.path||"")}function Kn(n,e,t){let r=de(n?.cloudReplaceUrl);if(n?.cloudUseLocalUrl===!1&&r)return r;let s=de(t?.cloudReplaceUrl);if(t?.cloudUseLocalUrl===!1&&s)return s;let i=de(e?.cloudReplaceUrl);return e?.cloudUseLocalUrl===!1&&i?i:Jn(n,e,t)}function Ft(n=[],e){return n.map(t=>({...t,level:e}))}function zn(n,e,t){let r=[];return Array.isArray(n.actions)&&r.push(...Ft(n.actions,"project")),e&&Array.isArray(e.actions)&&r.push(...Ft(e.actions,"testFolder")),Array.isArray(t.actions)&&r.push(...Ft(t.actions,"test")),r}function Yn(n){return Array.isArray(n)?n.map(e=>({id:e?.id||"",name:e?.name||"",description:e?.description||""})):[]}function Pr(n){return Array.isArray(n)?n.map(e=>({id:e?.id||"",name:e?.name||"",description:e?.description||"",executeAfter:!!e?.executeAfter})):[]}function Qn(n,e,t,r){let s=Yn(n?.files),i=Pr(n?.actions),o=Pr(t?.actions),a={name:n?.name,description:n?.description,url:n?.url,maxSteps:n?.maxSteps,actionTimeout:n?.actionTimeout,resetStateOption:r,projectReset:e?.resetStateForEachTest,projectBaseUrl:e?.baseUrl,environment:n?.environment||"",role:n?.role||"",testFolderId:n?.testFolderId||"",testFolderReplaceUrl:t?.replaceUrl||"",testFolderActions:o,files:s,actions:i};try{return JSON.stringify(a)}catch{return`${n?.name||"test"}-${r}-${s.length}-${i.length}`}}function Xn(n,e,t){return Array.isArray(n.files)?n.files.map(r=>{if(!r?.id)return null;let s=e.files?.[r.id];if(!s?.path)throw new Error(`Missing stored file path for ${r.name||r.id}`);let i=et.default.join(t,s.path);return{id:r.id,name:r.name||s?.name||"",description:r.description||"",path:i}}).filter(Boolean):[]}function Zn(n){let e=[],t=Array.isArray(n.documents)?n.documents:[];for(let s of t)e.push({...s,testFolder:null});let r=Array.isArray(n.testFolders)?n.testFolders:[];for(let s of r){let i=Array.isArray(s.documents)?s.documents:[];for(let o of i)e.push({...o,testFolder:s})}return e}function es(n,e,t){let r=Zn(n);return e==="project"?r:e==="folder"?r.filter(s=>s.testFolder?.cloudId===t):e==="test"?r.filter(s=>s.cloudId===t):[]}async function kr({projectId:n,targetType:e,targetId:t,apiConfig:r,cacheEnabled:s,silent:i=!1}){let o=new qe({silent:i}),a=se(n),{structure:c,filesIndex:l,cacheData:u}=await jr(a),d=c||{},h=d.id||n,f=es(c,e,t),g=et.default.join(a,"cache-signatures.json"),m={},w=!1,y=!1,C=!1,k=Array.isArray(u.entries)&&u.entries.length>0;if(s)try{if(await _e(g)){let S=await V(g,{});S&&typeof S=="object"&&(m=S),y=!0}}catch{m={},y=!1}if(!f.length)throw new Error("No tests found for the selected target.");let p=et.default.join(a,"cache.json");$r(u.entries||{},s,{cachePath:p,cacheVersion:u.version||null});let b=new Ze(o,r),E=new Xe(o,r),D=Q.startExecutionGroup(),v=d?.queueFailureBehavior==="continueQueue"?"continueQueue":"stopQueue",R=[],O=new Map,T=0,ae=0;for(let S of f){let $=S.testFolder,I=S.resetStateOption||d?.resetStateForEachTest||"test";if(!(S.executeOnCloud!==!1)){ae++,o.addLog(S.cloudId||S.id||"unknown-test","info",`Skipping "${S.name||"Untitled Test"}" (set to run in app only).`);continue}let Z=Q.generateSessionId({...S,projectId:h,testFolderId:$?.id||null},I,D),A=S.id||S.testId||S.cloudId,F=S.name||"Untitled Test",B=Kn(S,d,$);if(!F.trim()||!S.description?.trim()||!B||!B.trim()){T++,o.addLog(A||"unknown-test","warning","Skipping test missing required name, description, or URL.");continue}if(s&&A){let _={...S,url:B,testFolderId:$?.id||S.testFolderId||null},ce=Qn(_,d,$,I),M=m[A];!y&&k&&!C?(Qe(h,A),C=!0):M&&M!==ce&&Qe(h,A),M!==ce&&(m[A]=ce,w=!0)}R.push({testEntry:S,testFolder:$,resetStateOption:I,sessionId:Z,testId:A,testName:F,testUrl:B}),O.set(Z,(O.get(Z)||0)+1)}if(!R.length)throw new Error("No valid tests found for the selected target.");T>0&&o.addLog("system","warning",`Skipping ${T} test(s) without required name, description, or URL.`),ae>0&&o.addLog("system","info",`Skipping ${ae} test(s) marked for app-only execution.`);let K=0,L=0,he=S=>{if(!S)return;let $=O.get(S);if(!$)return;let I=$-1;I<=0?O.delete(S):O.set(S,I)},fe=async(S,$,I=!1)=>{let j=$||S.resetStateOption||"test";if(j!=="never"){if(j==="testFolder"){if(I){await Q.cleanupSession();return}if((O.get(S.sessionId)||0)>1)return}await Q.cleanupSession()}};try{for(let S of R){let{testEntry:$,testFolder:I,resetStateOption:j,sessionId:Z,testId:A,testName:F,testUrl:B}=S,_={id:A,testId:A,sessionId:Z,testName:F,testDescription:$.description||"",projectId:h,testFolderId:I?.id||null,testFolderName:I?.name||null,url:B,actionTimeout:$.actionTimeout||60,testTimeout:$.testTimeout||300,maxSteps:$.maxSteps||50,actions:Array.isArray($.actions)?[...$.actions]:[],files:Xn($,l,a),environment:$.environment||"",role:$.role||"",resetStateOption:j,startedAt:new Date};o.addLog(_.id,"info",`Started executing test "${_.testName}"`);let ce=zn(d,I,_);try{let M=0,pe=!1,z=4,be=!1,Ce=!1;for(;M<z;){Q.shouldResetSession(_,j)&&await Q.cleanupSession(),Q.updateSessionTracking(_.sessionId,_.testFolderId);try{let me=await b.executeActions(_.sessionId,_.id,ce,"before",j,_.testFolderId,_.projectId,{enableCache:!pe,projectId:h,testId:A});if(!me?.success){let ge=new Error(`Before actions failed: ${me?.message||"Unknown error"}`);throw ge.shouldRetryWithoutCache=!0,me?.usedCache&&(ge.cacheUsed=!0),ge}let De=await q.getPageState(_.sessionId,_.url,null,j,_.testFolderId,_.projectId);if(!De?.success)throw new Error(De?.error||"Failed to capture initial page state");await E.executeTestSteps(_,De,j,{enableCache:!pe});let tt=await b.executeActions(_.sessionId,_.id,ce,"after",j,_.testFolderId,_.projectId,{enableCache:!pe,projectId:h,testId:A});if(!tt?.success){let ge=new Error(`After actions failed: ${tt?.message||"Unknown error"}`);throw ge.shouldRetryWithoutCache=!0,tt?.usedCache&&(ge.cacheUsed=!0),ge}o.addLog(_.id,"success",`Test "${_.testName}" completed successfully`),be=!0;break}catch(me){if(!pe&&!!me?.shouldRetryWithoutCache){pe=!0,Qe(_.projectId,A||null),Or(_.sessionId),o.addLog(_.id,"warning",`Cache invalidated after failure - retrying test "${_.testName}" without cache`),await Q.cleanupSession(),_.startedAt=new Date,M++;continue}o.addLog(_.id,"error",`Test "${_.testName}" failed`,me.message||String(me)),Ce=!0;break}}be?K++:Ce&&L++,await fe(_,j,Ce&&v==="stopQueue"),he(_.sessionId)}catch(M){o.addLog(_.id,"error",`Test "${_.testName}" failed`,M.message||String(M)),L++,await fe(_,j,v==="stopQueue"),he(_.sessionId)}if(L>0&&v==="stopQueue")break}}finally{await Q.cleanupSession()}if(s&&w)try{await Y(g,m)}catch{}return L>0?{success:!1,passed:K,failed:L,total:R.length}:{success:!0,passed:K,failed:L,total:R.length}}var J=new Yt,ts="1.1.7";J.name("agenqa").description("Agenqa CLI for cloud projects").version(ts);process.on("SIGINT",()=>{console.log(`
|
|
43
|
+
Interrupted. Exiting.`),process.exit(130)});function Dr(n,e,t){let r=Ct(t||$e(n,e));if(!r)throw new Error("API base URL is not configured in this build.");return r}function Dt(n,e){if(n===void 0)return null;let t=String(n).trim().toLowerCase();if(["y","yes"].includes(t))return!0;if(["n","no"].includes(t))return!1;console.error(`Invalid value for ${e}. Use "yes" or "no".`),process.exit(1)}function It(n){console.log(`Synced project ${n.project?.name||n.project?.id}`),console.log(`Files: ${n.files.downloaded} downloaded, ${n.files.skipped} skipped, ${n.files.removed} removed.`),n.cache&&(n.cacheDisabledGlobally?console.log("Cache disabled globally for this project."):console.log("Cache synced."))}function rs(n){return typeof n?.cacheCloudEnabled=="boolean"?n.cacheCloudEnabled:!!n?.cacheEnabled}function ns(n){return typeof n?.cacheLocalEnabled=="boolean"?n.cacheLocalEnabled:!!n?.cacheEnabled}async function Fe(n){throw ar(n)&&(console.error("Cloud key is invalid or expired. Please re-import the project."),process.exit(2)),n}J.command("import").description("Import a cloud project using project id and secret key").requiredOption("-p, --project <projectId>","Cloud project id").requiredOption("-s, --key-secret <secret>","Cloud key secret").option("--trust <yes|no>","Skip trust prompt by answering yes or no").option("--cache-local <yes|no>","Skip local cache prompt by answering yes or no").option("--cache-cloud <yes|no>","Skip cloud cache prompt by answering yes or no").action(async n=>{let e=await ne(),t=n.project.trim(),r=n.keySecret.trim(),s=Dr(e,t),i=Dt(n.trust,"--trust"),o=Dt(n.cacheLocal,"--cache-local"),a=Dt(n.cacheCloud,"--cache-cloud");(i??await ye("Importing projects from unknown sources can expose you to risks. Do you confirm you trust this project? (yes/no)",{required:!0}))!==!0&&(console.error("Import cancelled."),process.exit(1));let u=(o??await ye("Enable local cache on this machine? (required for cloud cache) (yes/no)"))===!0,d=!1;u?d=(a??await ye("Enable cloud cache? (warning: reuses collaborators' cached steps; only enable if you trust them to avoid security risks) (yes/no)"))===!0:a===!0&&(console.error("Cloud cache requires local cache. Re-run with --cache-local yes or omit --cache-cloud."),process.exit(1));let h={keyToken:r,cacheCloudEnabled:d,cacheLocalEnabled:u,baseUrl:s,importedAt:new Date().toISOString()};e.projects[t]=h,await Ae(e),await Te(t);try{let f=await He(e,t);It(f),console.log("Import completed.")}catch(f){await Fe(f),console.error(f.message||String(f)),process.exit(1)}});J.command("list").description("List stored projects").action(async()=>{let n=await ne(),e=Object.entries(n.projects||{});if(e.length===0){console.log("No projects imported.");return}let t=[];for(let[a,c]of e){let l=null;try{l=await V(Fr.default.join(se(a),"project.json"),null)}catch(f){console.error(`Warning: failed to read metadata for project ${a}: ${f.message||f}`)}let u=rs(c)?"enabled":"disabled",d=c.importedAt||"import time unknown",h=$e(n,a)||"base URL not set";t.push([a,l?.name||"",h,u,d])}let r=["Project ID","Name","Base URL","Cache","Imported At"],s=r.map((a,c)=>Math.max(a.length,...t.map(l=>(l[c]||"").length))),i=s.map(a=>"-".repeat(a)).join("-+-"),o=a=>a.map((c,l)=>String(c||"").padEnd(s[l]," ")).join(" | ");console.log("Stored projects:"),console.log(o(r)),console.log(i),t.forEach(a=>console.log(o(a)))});J.command("sync").description("Sync a cloud project locally").requiredOption("-p, --project <projectId>","Cloud project id").action(async n=>{let e=await ne(),t=n.project.trim();try{let r=await He(e,t);It(r)}catch(r){await Fe(r),console.error(r.message||String(r)),process.exit(1)}});J.command("remove-project").description("Remove an imported project and local data").requiredOption("-p, --project <projectId>","Cloud project id").action(async n=>{let e=n.project.trim(),t=await ne();t.projects?.[e]||(console.error(`Project ${e} is not imported. Run agenqa import first.`),process.exit(1)),await ye(`Remove local data for project ${e}? This does not delete the cloud project. (yes/no)`,{required:!0})||(console.error("Remove cancelled."),process.exit(1)),delete t.projects[e],await Ae(t),await bt(e),console.log(`Removed local data for project ${e}.`)});J.command("cache").description("Enable or disable cloud cache for a project").requiredOption("-p, --project <projectId>","Project id").option("--enable","Enable cache").option("--disable","Disable cache").action(async n=>{let e=n.project.trim(),t=n.enable===!0?!0:n.disable===!0?!1:null;t===null&&(console.error("Choose either --enable or --disable."),process.exit(1));let r=await ne(),s=r.projects?.[e];s||(console.error(`Project ${e} is not imported. Run "agenqa import" first.`),process.exit(1)),t&&(console.log("Warning: cache reuses generated steps from collaborators. Enable only if you trust the project sources."),await ye("Do you want to enable cache? (yes/no)",{required:!0})||(console.error("Cache enable cancelled."),process.exit(1))),s.cacheCloudEnabled=t,s.cacheEnabled!==void 0&&(s.cacheEnabled=t),await Ae(r),console.log(`Cache ${t?"enabled":"disabled"} for project ${e}.`)});J.command("reset-cache").description("Clear local cache (cloud cache downloads and local-only cache)").requiredOption("-p, --project <projectId>","Project id").action(async n=>{let e=n.project.trim();(await ne()).projects?.[e]||(console.error(`Project ${e} is not imported. Run "agenqa import" first.`),process.exit(1)),await ye(`Reset local cache for project ${e}? (yes/no)`,{required:!0})||(console.error("Reset cache cancelled."),process.exit(1)),await Te(e),console.log(`Local cache cleared for project ${e}.`)});async function Nt({projectId:n,targetType:e,targetId:t,cacheOverride:r,silent:s}){let i=await ne(),o=i.projects?.[n];if(!o)throw new Error(`Project ${n} is not imported. Run "agenqa import" first.`);let a=Dr(i,n,o.baseUrl),c=await He(i,n,{cacheOverride:r}),l=!!c?.cacheDisabledGlobally;if(c?.project?.readOnly)throw new Error("This cloud project is read-only on your current plan. Convert to local-only to run tests.");s||It(c);let u=l?!1:r!==null?r:ns(o),d=Ve(o,n),h=await kr({projectId:n,targetType:e,targetId:t,cacheEnabled:u,silent:s,apiConfig:{runTestUrl:`${a}/cloud/cli/run-test`,headers:d}});s||console.log(`Summary: ${h.passed}/${h.total} passed, ${h.failed} failed.`),h.success||process.exit(1)}function Lt(n){return n.cache===void 0?null:!!n.cache}J.command("run-project").description("Execute a cloud project").requiredOption("-p, --project <projectId>","Cloud project id").option("--cache","Enable cache").option("--no-cache","Disable cache").option("--silent","Suppress non-error logs").action(async n=>{try{await Nt({projectId:n.project.trim(),targetType:"project",targetId:null,cacheOverride:Lt(n),silent:!!n.silent})}catch(e){await Fe(e),console.error(e.message||String(e)),process.exit(1)}});J.command("run-folder").description("Execute a cloud test folder").requiredOption("-p, --project <projectId>","Cloud project id").requiredOption("-f, --folder <folderId>","Cloud test folder id").option("--cache","Enable cache").option("--no-cache","Disable cache").option("--silent","Suppress non-error logs").action(async n=>{try{await Nt({projectId:n.project.trim(),targetType:"folder",targetId:n.folder.trim(),cacheOverride:Lt(n),silent:!!n.silent})}catch(e){await Fe(e),console.error(e.message||String(e)),process.exit(1)}});J.command("run-test").description("Execute a single cloud test case").requiredOption("-p, --project <projectId>","Cloud project id").requiredOption("-t, --test <testId>","Cloud test case id").option("--cache","Enable cache").option("--no-cache","Disable cache").option("--silent","Suppress non-error logs").action(async n=>{try{await Nt({projectId:n.project.trim(),targetType:"test",targetId:n.test.trim(),cacheOverride:Lt(n),silent:!!n.silent})}catch(e){await Fe(e),console.error(e.message||String(e)),process.exit(1)}});J.parseAsync(process.argv);
|