@taqwright/lime-cli 0.7.9 → 0.7.10
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/index.js +9 -9
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";var R=(e,t)=>()=>{try{return t||e((t={exports:{}}).exports,t),t.exports}catch(r){throw t=0,r}};var Pe=R((ds,Ir)=>{Ir.exports={name:"@taqwright/lime-cli",version:"0.7.9",description:"Thin CLI client for the LIME server \u2014 fire a natural-language QA Agent goal against a connected device and write back a taqwright spec.",license:"SEE LICENSE IN LICENSE",author:"Taqwright",homepage:"https://www.taqwright.ai",bugs:{url:"https://www.taqwright.ai/contact"},keywords:["appium","mobile-testing","e2e","qa","test-automation","taqwright","lime","cli"],bin:{"lime-cli":"dist/index.js"},main:"dist/index.js",files:["dist"],publishConfig:{access:"public"},scripts:{"lime-cli":"node src/index.js",start:"node src/index.js",test:"node --test test/*.test.js",bundle:"esbuild src/index.js --bundle --platform=node --target=node18 --minify --outfile=dist/index.js",prepack:"npm run bundle",prepublishOnly:"npm test"},engines:{node:">=18"},devDependencies:{esbuild:"^0.28.1"}}});var D=R((ps,De)=>{"use strict";var _r="https://www.taqwright.ai";De.exports={POLL_INTERVAL_MS:1e3,POLL_TIMEOUT_MS:18e5,BOOT_POLL_INTERVAL_MS:5e3,BOOT_TIMEOUT_MS:3e5,CONNECT_POLL_INTERVAL_MS:2e3,CONNECT_TIMEOUT_MS:3e5,DEFAULT_SERVER:_r,HTTP_TIMEOUT_MS:3e5,MAX_RESPONSE_BYTES:52428800}});var z=R((hs,Fe)=>{"use strict";var{URL:kr}=require("url"),{HTTP_TIMEOUT_MS:qe,MAX_RESPONSE_BYTES:Me}=D();function Ue(e){let t=String(e||"").replace(/^\[|\]$/g,"").toLowerCase();return t==="localhost"||t==="127.0.0.1"||t==="::1"||t.endsWith(".localhost")}var Rr=["just a moment","attention required! | cloudflare","checking your browser","/cdn-cgi/challenge-platform","cf-error-details","cf-browser-verification","_incapsula_resource"];function Be(e,t){if(!t||typeof t!="string")return null;let r=t.slice(0,4e3).toLowerCase();return Rr.some(n=>r.includes(n))?`the LIME server is behind a bot challenge that blocked this request (HTTP ${e}). The request never reached LIME \u2014 it was stopped at the edge, so your token and arguments are probably fine. CI runners use datacenter IPs, which Cloudflare's Bot Fight Mode challenges by default; it cannot be excepted with a WAF skip rule, so the server's operator has to turn it off or move to Super Bot Fight Mode (which supports skip rules) for the /api/ paths.`:null}var de=class{constructor(t,r){this.server=t,this.token=r}_url(t){return/^https?:\/\//i.test(t)?t:`${this.server}${t}`}json(t,r,n,i={}){let s=n?JSON.stringify(n):null,o={...i};return s&&(o["Content-Type"]="application/json",o["Content-Length"]=Buffer.byteLength(s)),this._send(t,this._url(r),o,s)}raw(t,r,n,i={}){let s={...i,"Content-Type":"application/octet-stream","Content-Length":n.length};return this._send(t,this._url(r),s,n)}_send(t,r,n,i){let s=new kr(r);if(s.protocol==="http:"&&!Ue(s.hostname))return Promise.reject(new Error(`refusing to send your LIME_CI_TOKEN over cleartext http to ${s.hostname} \u2014 use https (http is allowed only for localhost).`));let o=s.protocol==="https:"?require("https"):require("http"),a={method:t,hostname:s.hostname,port:s.port||(s.protocol==="https:"?443:80),path:s.pathname+(s.search||""),headers:{...n,Authorization:`Bearer ${this.token}`,Origin:`${s.protocol}//${s.host}`}};return new Promise((l,p)=>{let c=o.request(a,u=>{let d="",g=0;u.setEncoding("utf8"),u.on("data",f=>{if(g+=Buffer.byteLength(f),g>Me){c.destroy(new Error(`Server response exceeded ${Me} bytes`));return}d+=f}),u.on("end",()=>{let f;try{f=d?JSON.parse(d):{}}catch{let w=Be(u.statusCode,d);return p(new Error(w||`Server returned non-JSON (${u.statusCode}): ${d.substring(0,200)}`))}l({status:u.statusCode,body:f})})});c.setTimeout(qe,()=>{c.destroy(new Error(`request timed out after ${qe/1e3}s`))}),c.on("error",p),i&&c.write(i),c.end()})}};function $r(e,t){if(!e.body||!e.body.success)throw new Error(`${t} \u2014 ${e.body&&e.body.error||"unknown"}`);return e.body}Fe.exports={isLoopbackHost:Ue,HttpClient:de,expectSuccess:$r,describeEdgeBlock:Be}});var q=R((fs,Ke)=>{"use strict";var Or={browserstack:{label:"BrowserStack",envUsername:"BROWSERSTACK_USERNAME",envAccessKey:"BROWSERSTACK_ACCESS_KEY",hubHost:"hub.browserstack.com"},lambdatest:{label:"LambdaTest",envUsername:"LT_USERNAME",envAccessKey:"LT_ACCESS_KEY",hubHost:"mobile-hub.lambdatest.com"}};function Lr({provider:e,platform:t,device:r,os:n,appUrl:i,username:s,accessKey:o,capabilities:a}){let l={connectionMode:"cloud",cloudProvider:e||"browserstack",cloudUsername:s,cloudAccessKey:o,platform:t,deviceName:r,deviceOsVersion:n,cloudAppUrl:i,automationName:t==="ios"?"XCUITest":"UiAutomator2"};return a&&(l.cloudCapabilities=a),l}Ke.exports={CLOUD_PROVIDERS:Or,buildCloudSettingsPayload:Lr}});var fe=R((ms,He)=>{"use strict";var Z=require("fs"),pe=require("path"),Cr=["taqwright","webdriverio-js","appium-java-junit5","appium-python-pytest","appium-ruby-rspec","appium-csharp-nunit"],xr={taqwright:"deterministic","webdriverio-js":"gemini","appium-java-junit5":"gemini","appium-python-pytest":"gemini","appium-ruby-rspec":"gemini","appium-csharp-nunit":"gemini"},j={taqwright:"taqwright (native)","webdriverio-js":"WebdriverIO (JavaScript)","appium-java-junit5":"Appium Java (JUnit 5)","appium-python-pytest":"Appium Python (pytest)","appium-ruby-rspec":"Appium Ruby (RSpec)","appium-csharp-nunit":"Appium C# (NUnit)"},Nr=5*1024*1024,he={exists:e=>Z.existsSync(e),readText:e=>{try{return Z.statSync(e).size>Nr?null:Z.readFileSync(e,"utf8")}catch{return null}},list:e=>{try{return Z.readdirSync(e)}catch{return[]}}};function jr(e,t){let r=e.readText(pe.join(t,"package.json"));if(!r)return{};try{let n=JSON.parse(r);return{...n.dependencies||{},...n.devDependencies||{}}}catch{return{}}}var Pr=new Set(["node_modules","dist","build","target","bin","obj","vendor","out","coverage"]);function Dr(e,t){let r=new Set([""]),n=[];try{n=e.list(t)}catch{n=[]}for(let i of n)i.startsWith(".")||Pr.has(i)||r.add(i);return[...r]}function qr(e,t,r){let n=r?pe.join(t,r):t,i=u=>pe.join(n,u),s=u=>r?`${r}/${u}`:u,o=[],a=jr(e,n),l=[];try{l=e.list(n)}catch{l=[]}(a["@taqwright/taqwright"]||a.taqwright||e.exists(i("taqwright.config.ts"))||e.exists(i("taqwright.config.js")))&&o.push({id:"taqwright",label:j.taqwright,reason:"taqwright dependency/config found",manifest:s("package.json")});let p=l.some(u=>/^wdio\.conf\.(js|ts|mjs|cjs)$/.test(u));(a.webdriverio||a["@wdio/cli"]||p)&&o.push({id:"webdriverio-js",label:j["webdriverio-js"],reason:p?"wdio.conf.* found":"webdriverio dependency found",manifest:s("package.json")});for(let u of["pom.xml","build.gradle","build.gradle.kts"]){let d=e.readText(i(u));if(d&&/io\.appium|java-client/.test(d)){o.push({id:"appium-java-junit5",label:j["appium-java-junit5"],reason:`io.appium:java-client in ${s(u)}`,manifest:s(u)});break}}for(let u of["requirements.txt","pyproject.toml"]){let d=e.readText(i(u));if(d&&/appium-python-client/i.test(d)){o.push({id:"appium-python-pytest",label:j["appium-python-pytest"],reason:`Appium-Python-Client in ${s(u)}`,manifest:s(u)});break}}let c=e.readText(i("Gemfile"));c&&/appium_lib(_core)?/.test(c)&&o.push({id:"appium-ruby-rspec",label:j["appium-ruby-rspec"],reason:"appium_lib in Gemfile",manifest:s("Gemfile")});for(let u of l){if(!/\.csproj$/i.test(u))continue;let d=e.readText(i(u));if(d&&/Appium\.WebDriver/i.test(d)){o.push({id:"appium-csharp-nunit",label:j["appium-csharp-nunit"],reason:`Appium.WebDriver in ${s(u)}`,manifest:s(u)});break}}return o}function Ye(e,t=he){let r=new Map;for(let n of Dr(t,e))for(let i of qr(t,e,n))r.has(i.id)||r.set(i.id,i);return[...r.values()]}function Mr(e,t=he){let r=Ye(e,t);return r.some(n=>n.id==="taqwright")||r.push({id:"taqwright",label:j.taqwright,reason:"default output"}),r}function Ur(e){let{requested:t,configured:r,remembered:n,offeredIds:i,detectedRealIds:s,taqwrightDetected:o,javaSignal:a}=e,l=p=>!!p&&i.includes(p);return l(t)?t:l(r)?r:l(n)&&(s.includes(n)||n==="taqwright"&&o)?n:s.length?s[0]:o?"taqwright":a?"appium-java-junit5":"taqwright"}He.exports={FRAMEWORK_IDS:Cr,FRAMEWORK_ENGINES:xr,FRAMEWORK_LABELS:j,nodeFs:he,detectFrameworks:Ye,rankFrameworks:Mr,pickDefaultFramework:Ur}});var ve=R((gs,Xe)=>{"use strict";var me=require("path"),{nodeFs:Br}=fe(),Ve={taqwright:"tests","webdriverio-js":"test/specs","appium-java-junit5":"src/test/java","appium-python-pytest":"tests","appium-ruby-rspec":"spec","appium-csharp-nunit":"Tests"},Fr="tests",Kr={taqwright:".spec.ts","webdriverio-js":".spec.ts","appium-java-junit5":".java","appium-python-pytest":".py","appium-ruby-rspec":"_spec.rb","appium-csharp-nunit":".cs"},Yr=new Set(["appium-python-pytest","appium-ruby-rspec"]);function ge(e){return Ve[e]||Fr}function we(e){let t=(e||"").split(/[^A-Za-z0-9]+/).filter(Boolean);return t.length?t.map(r=>/^[A-Z0-9]+$/.test(r)?r[0]+r.slice(1).toLowerCase():r[0].toUpperCase()+r.slice(1)).join(""):""}function ye(e){return(e||"").replace(/([a-z0-9])([A-Z])/g,"$1_$2").split(/[^A-Za-z0-9]+/).filter(Boolean).join("_").toLowerCase()}function Hr(e){return ye(e).split("_").filter(Boolean).join("-")}var Vr=6,Wr=new Set(["and","or","the","a","an","to","of","in","on","at","as","with","for","then","into","from","by","that","is"]),Gr=/@|\d{6,}/;function Jr(e){let t=String(e||"").trim().split(/\s+/).filter(Boolean).filter(r=>!Gr.test(r)).slice(0,Vr);for(;t.length>1&&Wr.has(t[t.length-1].toLowerCase());)t.pop();return we(t.join(" "))||"RecordedTest"}function Xr(e){let t=String(e||"").trim();return t?/[A-Za-z]/.test(t)?t.length>80?"Keep the name under 80 characters.":/[/\\]/.test(t)?"Use the destination field for the folder.":null:"Use at least one letter.":"Enter a test name."}function Qr(e){if(e==null||e==="")return null;let t=String(e);return t!==t.trim()?"must not have leading or trailing spaces.":t.length>120?"is longer than any key LIME mints (120 characters).":/^[a-z0-9][a-z0-9._/:-]*$/.test(t)?t.includes("..")?'must not contain "..".':null:"is not a scenario key \u2014 expected lower-case letters, digits and . _ - / : only."}function We(e,t){let r;return Yr.has(e)?r=ye(t):r=we(t),`${r}${Kr[e]||""}`}function K(e){return String(e||"").split(/[/\\]+/).filter(t=>t&&t!=="."&&t!=="..").join("/")}function zr(e){if(e==null)return null;let t=String(e);return t.trim()===""?null:/^([A-Za-z]:)?[/\\]/.test(t)?"must be a path inside the project, not an absolute path.":t.split(/[/\\]+/).includes("..")?'must not contain ".." \u2014 the test belongs inside the project.':null}function be(e){let t=K(e).split("/");return t.pop(),t.join("/")}function Ge(e){let t=/(?:^|\/)src\/(?:test|main)\/java\/(.+)$/.exec(K(e));return t&&t[1].split("/").filter(Boolean).join(".")||void 0}function Zr(e){let t=K(e),r=t.search(/\/src\/(?:test|main)\/java(?:\/|$)/);return r>0?t.slice(0,r):""}function en(e){let t=new Map;for(let n of e){let i=be(n);t.set(i,(t.get(i)||0)+1)}if(!t.size)return null;let r=[...t.entries()].sort((n,i)=>i[1]-n[1]||n[0].localeCompare(i[0]));return{dir:r[0][0],count:r[0][1]}}var Je={taqwright:{segment:"tests",file:/\.spec\.(ts|js)$/},"webdriverio-js":{segment:"test/specs",file:/\.(ts|js)$/},"appium-java-junit5":{segment:"src/test/java",file:/\.java$/},"appium-python-pytest":{segment:"tests",file:/^(test_.+|.+_test)\.py$/},"appium-ruby-rspec":{segment:"spec",file:/_spec\.rb$/},"appium-csharp-nunit":{segment:"",file:/Tests\.cs$/}},tn=new Set(["node_modules","dist","build","target","bin","obj","vendor","out","coverage",".git"]),rn=2e4;function nn(e,t,r=Br){let n=Je[t];if(!n)return[];let i=[],s=rn,o=a=>{if(s<=0)return;let l=a?me.join(e,a):e,p=[];try{p=r.list(l)}catch{return}for(let c of p){if(s--<=0)return;if(c.startsWith(".")||tn.has(c))continue;let u=a?`${a}/${c}`:c;if(r.isDir?r.isDir(me.join(e,u)):r.list(me.join(e,u)).length>0){o(u);continue}n.file.test(c)&&(n.segment&&!`/${be(u)}/`.includes(`/${n.segment}/`)||i.push(u))}};return o(""),i.sort()}function sn(e){let{framework:t,testName:r}=e,n=We(t,r),i=(a,l,p=0)=>{let c=K(a),u=t==="appium-java-junit5"?Ge(c):void 0;return{dir:c,fileName:n,...u?{packageName:u}:{},source:l,neighbourCount:p}};if(e.remembered!=null)return i(e.remembered,"remembered");let s=en(e.existingTests||[]);if(s&&s.dir)return i(s.dir,"existing",s.count);let o=e.detection&&e.detection.manifest?be(e.detection.manifest):"";return o?i(`${o}/${ge(t)}`,"module"):i(ge(t),"convention")}Xe.exports={CONVENTIONAL_DIRS:Ve,TEST_PATTERNS:Je,conventionalDir:ge,pascalCase:we,snakeCase:ye,kebabCase:Hr,testNameFromGoal:Jr,validateTestName:Xr,validateDest:zr,validateScenarioKey:Qr,fileNameFor:We,normalizeDir:K,javaPackageOf:Ge,moduleRootOf:Zr,findExistingTests:nn,resolveExportTarget:sn}});var et=R((ws,Ze)=>{"use strict";var{CLOUD_PROVIDERS:ee}=q(),{validateScenarioKey:on}=ve();function an(e){let t=Object.create(null);for(let r=0;r<e.length;r++){let n=e[r];if(!n.startsWith("--"))continue;let i=n.slice(2),s=e[r+1];s===void 0||s.startsWith("--")?t[i]=!0:(t[i]=s,r++)}return t}var ze=["export","adapt","verify","check-locators","disconnect","report"];function cn(e){let t=Array.isArray(e)?e:[],r=[];for(let n=0;n<t.length;n+=1){let i=String(t[n]==null?"":t[n]);!i||i.startsWith("-")||(n>0?String(t[n-1]||""):"").startsWith("--")||r.push(i)}return r}function ln(e){let t=e[0];return t&&ze.includes(t)?{command:t,rest:e.slice(1)}:{command:"run",rest:e}}function un(e="taqwright"){return e==="json"?"recorded-steps.json":"RecordedTest.spec.ts"}function dn(e,t=process.env){let r=[],n=!!e["list-devices"],i=!!e["keep-session"],s=!!e["no-boot"],o=e["lime-dir"]===!0?".lime":typeof e["lime-dir"]=="string"&&e["lime-dir"].trim()?e["lime-dir"].trim():void 0,a=e.format?String(e.format).toLowerCase():"taqwright";if(["taqwright","json"].includes(a)||r.push(`--format must be taqwright or json (got "${e.format}")`),n)return{errors:r,listDevices:n,keepSession:i,noBoot:s,format:a,limeDir:o};(!e.goal||typeof e.goal!="string"||!e.goal.trim())&&r.push("--goal is required");let l;e.project!==void 0&&(typeof e.project!="string"||!e.project.trim()?r.push("--project requires a project name"):l=e.project.trim());let p;if(e.scenario!==void 0){let h=typeof e.scenario=="string"?e.scenario.trim():"",T=h?on(h):"requires a scenario key";T?r.push(`--scenario ${T}`):p=h}let c,u;e["gemini-key"]!==void 0&&(typeof e["gemini-key"]!="string"||!e["gemini-key"].trim()?r.push("--gemini-key requires a value (or set GEMINI_API_KEY)"):(c=e["gemini-key"].trim(),u="flag")),!c&&typeof t.GEMINI_API_KEY=="string"&&t.GEMINI_API_KEY.trim()&&(c=t.GEMINI_API_KEY.trim(),u="env");let d,g;if(e["qwen-key"]!==void 0&&(typeof e["qwen-key"]!="string"||!e["qwen-key"].trim()?r.push("--qwen-key requires a value (or set QWEN_API_KEY)"):(d=e["qwen-key"].trim(),g="flag")),!d&&typeof t.QWEN_API_KEY=="string"&&t.QWEN_API_KEY.trim()&&(d=t.QWEN_API_KEY.trim(),g="env"),e["max-steps"]!==void 0){let h=Number(e["max-steps"]);(!Number.isFinite(h)||h<1||h>200)&&r.push("--max-steps must be a number between 1 and 200")}let f;e.platform&&(f=String(e.platform).toLowerCase(),["android","ios"].includes(f)||r.push(`--platform must be android or ios (got "${e.platform}")`));let v=!!e.cloud,w=typeof e.os=="string"?e.os:void 0,y=typeof e["app-url"]=="string"?e["app-url"]:void 0,I=typeof e.app=="string"?e.app:void 0,b=typeof e.caps=="string"&&e.caps.trim()?e.caps.trim():void 0,E,A,S;if(v&&(E=e.cloud===!0?"browserstack":String(e.cloud).toLowerCase(),ee[E]||r.push(`--cloud must be ${Object.keys(ee).join(" or ")} (got "${e.cloud}")`)),v){(!e.device||typeof e.device!="string")&&r.push('--cloud requires --device (the cloud device name, e.g. "Google Pixel 8")'),f||r.push("--cloud requires --platform (android or ios)"),w||r.push("--cloud requires --os (the device OS version, e.g. 14.0)"),I?r.push("--app is not supported for cloud runs. Upload the build to your provider \u2014 LambdaTest: POST https://manual-api.lambdatest.com/app/upload/realDevice (-F appFile=@<file>), BrowserStack: POST https://api-cloud.browserstack.com/app-automate/upload (-F file=@<file>) \u2014 then pass the returned id with --app-url. (--app is still supported for local runs, where it clean-reinstalls on the agent device.)"):y||r.push("--cloud requires --app-url <bs://\u2026 | lt://\u2026> (the id from your provider\u2019s app upload API)"),e["app-url"]!==void 0&&(typeof e["app-url"]!="string"||!e["app-url"].trim())&&r.push("--app-url requires a bs:// or lt:// app id"),y&&ee[E]&&(E==="browserstack"&&y.startsWith("lt://")?r.push(`--app-url "${y}" is a LambdaTest app id, but the provider is browserstack`):E==="lambdatest"&&y.startsWith("bs://")&&r.push(`--app-url "${y}" is a BrowserStack app id, but the provider is lambdatest`)),e["cloud-username"]!==void 0&&(typeof e["cloud-username"]!="string"||!e["cloud-username"].trim())&&r.push("--cloud-username requires a value"),e["cloud-access-key"]!==void 0&&(typeof e["cloud-access-key"]!="string"||!e["cloud-access-key"].trim())&&r.push("--cloud-access-key requires a value"),e.caps!==void 0&&(typeof e.caps!="string"||!e.caps.trim())&&r.push("--caps requires a path to a JSON file");let h=ee[E];h&&(A=typeof e["cloud-username"]=="string"&&e["cloud-username"].trim()||t[h.envUsername]||void 0,S=typeof e["cloud-access-key"]=="string"&&e["cloud-access-key"].trim()||t[h.envAccessKey]||void 0,A||r.push(`cloud runs require a username \u2014 pass --cloud-username or set ${h.envUsername} (credentials are never read from your LIME account for CLI runs)`),S||r.push(`cloud runs require an access key \u2014 pass --cloud-access-key or set ${h.envAccessKey}`))}else e.app!==void 0&&(typeof e.app!="string"||!e.app.trim()?r.push("--app requires a path to an APK"):e.device?f&&f!=="android"&&r.push("--app is Android only"):r.push("--app requires --device (lime-cli must connect to a device to reinstall the app)")),e["app-url"]!==void 0&&r.push("--app-url requires --cloud"),e.os!==void 0&&r.push("--os requires --cloud"),e["cloud-username"]!==void 0&&r.push("--cloud-username requires --cloud"),e["cloud-access-key"]!==void 0&&r.push("--cloud-access-key requires --cloud"),e.caps!==void 0&&r.push("--caps requires --cloud");return{errors:r,listDevices:n,keepSession:i,noBoot:s,limeDir:o,device:e.device,platform:f,projectName:l,scenarioKey:p,geminiKey:c,geminiKeySource:u,qwenKey:d,qwenKeySource:g,app:I,cloud:v,cloudProvider:E,cloudUsername:A,cloudAccessKey:S,os:w,appUrl:y,capsPath:b,format:a}}var Qe=["browserstack","lambdatest","appium"];function pn(e){let t=[],r=[];for(let[n,i]of Object.entries(e||{}))!i||typeof i!="object"||Array.isArray(i)?t.push(`--caps block "${n}" must be a JSON object, e.g. { "${n}": { "someCap": true } }`):Qe.includes(n)||r.push(`--caps block "${n}" is not one of ${Qe.join("/")} \u2014 it will be ignored (typo?)`);return{errors:t,warnings:r}}Ze.exports={parseArgs:an,parseCommand:ln,positionalPaths:cn,validateArgs:dn,extToFilename:un,validateCapsObject:pn,COMMANDS:ze}});var nt=R((ys,rt)=>{"use strict";var{DEFAULT_SERVER:hn}=D(),tt={export:`lime-cli export \u2014 work out what this repo is, and where the test belongs.
|
|
2
|
+
"use strict";var R=(e,t)=>()=>{try{return t||e((t={exports:{}}).exports,t),t.exports}catch(r){throw t=0,r}};var Pe=R((ds,Ir)=>{Ir.exports={name:"@taqwright/lime-cli",version:"0.7.10",description:"Thin CLI client for the LIME server \u2014 fire a natural-language QA Agent goal against a connected device and write back a taqwright spec.",license:"SEE LICENSE IN LICENSE",author:"Taqwright",homepage:"https://www.taqwright.ai",bugs:{url:"https://www.taqwright.ai/contact"},keywords:["appium","mobile-testing","e2e","qa","test-automation","taqwright","lime","cli"],bin:{"lime-cli":"dist/index.js"},main:"dist/index.js",files:["dist"],publishConfig:{access:"public"},scripts:{"lime-cli":"node src/index.js",start:"node src/index.js",test:"node --test test/*.test.js",bundle:"esbuild src/index.js --bundle --platform=node --target=node18 --minify --outfile=dist/index.js",prepack:"npm run bundle",prepublishOnly:"npm test"},engines:{node:">=18"},devDependencies:{esbuild:"^0.28.1"}}});var D=R((ps,De)=>{"use strict";var _r="https://www.taqwright.ai";De.exports={POLL_INTERVAL_MS:1e3,POLL_TIMEOUT_MS:18e5,BOOT_POLL_INTERVAL_MS:5e3,BOOT_TIMEOUT_MS:3e5,CONNECT_POLL_INTERVAL_MS:2e3,CONNECT_TIMEOUT_MS:3e5,DEFAULT_SERVER:_r,HTTP_TIMEOUT_MS:3e5,MAX_RESPONSE_BYTES:52428800}});var z=R((hs,Fe)=>{"use strict";var{URL:kr}=require("url"),{HTTP_TIMEOUT_MS:qe,MAX_RESPONSE_BYTES:Me}=D();function Ue(e){let t=String(e||"").replace(/^\[|\]$/g,"").toLowerCase();return t==="localhost"||t==="127.0.0.1"||t==="::1"||t.endsWith(".localhost")}var Rr=["just a moment","attention required! | cloudflare","checking your browser","/cdn-cgi/challenge-platform","cf-error-details","cf-browser-verification","_incapsula_resource"];function Be(e,t){if(!t||typeof t!="string")return null;let r=t.slice(0,4e3).toLowerCase();return Rr.some(n=>r.includes(n))?`the LIME server is behind a bot challenge that blocked this request (HTTP ${e}). The request never reached LIME \u2014 it was stopped at the edge, so your token and arguments are probably fine. CI runners use datacenter IPs, which Cloudflare's Bot Fight Mode challenges by default; it cannot be excepted with a WAF skip rule, so the server's operator has to turn it off or move to Super Bot Fight Mode (which supports skip rules) for the /api/ paths.`:null}var de=class{constructor(t,r){this.server=t,this.token=r}_url(t){return/^https?:\/\//i.test(t)?t:`${this.server}${t}`}json(t,r,n,i={}){let s=n?JSON.stringify(n):null,o={...i};return s&&(o["Content-Type"]="application/json",o["Content-Length"]=Buffer.byteLength(s)),this._send(t,this._url(r),o,s)}raw(t,r,n,i={}){let s={...i,"Content-Type":"application/octet-stream","Content-Length":n.length};return this._send(t,this._url(r),s,n)}_send(t,r,n,i){let s=new kr(r);if(s.protocol==="http:"&&!Ue(s.hostname))return Promise.reject(new Error(`refusing to send your LIME_CI_TOKEN over cleartext http to ${s.hostname} \u2014 use https (http is allowed only for localhost).`));let o=s.protocol==="https:"?require("https"):require("http"),a={method:t,hostname:s.hostname,port:s.port||(s.protocol==="https:"?443:80),path:s.pathname+(s.search||""),headers:{...n,Authorization:`Bearer ${this.token}`,Origin:`${s.protocol}//${s.host}`}};return new Promise((l,p)=>{let c=o.request(a,u=>{let d="",g=0;u.setEncoding("utf8"),u.on("data",f=>{if(g+=Buffer.byteLength(f),g>Me){c.destroy(new Error(`Server response exceeded ${Me} bytes`));return}d+=f}),u.on("end",()=>{let f;try{f=d?JSON.parse(d):{}}catch{let w=Be(u.statusCode,d);return p(new Error(w||`Server returned non-JSON (${u.statusCode}): ${d.substring(0,200)}`))}l({status:u.statusCode,body:f})})});c.setTimeout(qe,()=>{c.destroy(new Error(`request timed out after ${qe/1e3}s`))}),c.on("error",p),i&&c.write(i),c.end()})}};function $r(e,t){if(!e.body||!e.body.success)throw new Error(`${t} \u2014 ${e.body&&e.body.error||"unknown"}`);return e.body}Fe.exports={isLoopbackHost:Ue,HttpClient:de,expectSuccess:$r,describeEdgeBlock:Be}});var q=R((fs,Ke)=>{"use strict";var Or={browserstack:{label:"BrowserStack",envUsername:"BROWSERSTACK_USERNAME",envAccessKey:"BROWSERSTACK_ACCESS_KEY",hubHost:"hub.browserstack.com"},lambdatest:{label:"LambdaTest",envUsername:"LT_USERNAME",envAccessKey:"LT_ACCESS_KEY",hubHost:"mobile-hub.lambdatest.com"}};function Lr({provider:e,platform:t,device:r,os:n,appUrl:i,username:s,accessKey:o,capabilities:a}){let l={connectionMode:"cloud",cloudProvider:e||"browserstack",cloudUsername:s,cloudAccessKey:o,platform:t,deviceName:r,deviceOsVersion:n,cloudAppUrl:i,automationName:t==="ios"?"XCUITest":"UiAutomator2"};return a&&(l.cloudCapabilities=a),l}Ke.exports={CLOUD_PROVIDERS:Or,buildCloudSettingsPayload:Lr}});var fe=R((ms,He)=>{"use strict";var Z=require("fs"),pe=require("path"),Cr=["taqwright","webdriverio-js","appium-java-junit5","appium-python-pytest","appium-ruby-rspec","appium-csharp-nunit"],xr={taqwright:"deterministic","webdriverio-js":"gemini","appium-java-junit5":"gemini","appium-python-pytest":"gemini","appium-ruby-rspec":"gemini","appium-csharp-nunit":"gemini"},j={taqwright:"taqwright (native)","webdriverio-js":"WebdriverIO (JavaScript)","appium-java-junit5":"Appium Java (JUnit 5)","appium-python-pytest":"Appium Python (pytest)","appium-ruby-rspec":"Appium Ruby (RSpec)","appium-csharp-nunit":"Appium C# (NUnit)"},Nr=5*1024*1024,he={exists:e=>Z.existsSync(e),readText:e=>{try{return Z.statSync(e).size>Nr?null:Z.readFileSync(e,"utf8")}catch{return null}},list:e=>{try{return Z.readdirSync(e)}catch{return[]}}};function jr(e,t){let r=e.readText(pe.join(t,"package.json"));if(!r)return{};try{let n=JSON.parse(r);return{...n.dependencies||{},...n.devDependencies||{}}}catch{return{}}}var Pr=new Set(["node_modules","dist","build","target","bin","obj","vendor","out","coverage"]);function Dr(e,t){let r=new Set([""]),n=[];try{n=e.list(t)}catch{n=[]}for(let i of n)i.startsWith(".")||Pr.has(i)||r.add(i);return[...r]}function qr(e,t,r){let n=r?pe.join(t,r):t,i=u=>pe.join(n,u),s=u=>r?`${r}/${u}`:u,o=[],a=jr(e,n),l=[];try{l=e.list(n)}catch{l=[]}(a["@taqwright/taqwright"]||a.taqwright||e.exists(i("taqwright.config.ts"))||e.exists(i("taqwright.config.js")))&&o.push({id:"taqwright",label:j.taqwright,reason:"taqwright dependency/config found",manifest:s("package.json")});let p=l.some(u=>/^wdio\.conf\.(js|ts|mjs|cjs)$/.test(u));(a.webdriverio||a["@wdio/cli"]||p)&&o.push({id:"webdriverio-js",label:j["webdriverio-js"],reason:p?"wdio.conf.* found":"webdriverio dependency found",manifest:s("package.json")});for(let u of["pom.xml","build.gradle","build.gradle.kts"]){let d=e.readText(i(u));if(d&&/io\.appium|java-client/.test(d)){o.push({id:"appium-java-junit5",label:j["appium-java-junit5"],reason:`io.appium:java-client in ${s(u)}`,manifest:s(u)});break}}for(let u of["requirements.txt","pyproject.toml"]){let d=e.readText(i(u));if(d&&/appium-python-client/i.test(d)){o.push({id:"appium-python-pytest",label:j["appium-python-pytest"],reason:`Appium-Python-Client in ${s(u)}`,manifest:s(u)});break}}let c=e.readText(i("Gemfile"));c&&/appium_lib(_core)?/.test(c)&&o.push({id:"appium-ruby-rspec",label:j["appium-ruby-rspec"],reason:"appium_lib in Gemfile",manifest:s("Gemfile")});for(let u of l){if(!/\.csproj$/i.test(u))continue;let d=e.readText(i(u));if(d&&/Appium\.WebDriver/i.test(d)){o.push({id:"appium-csharp-nunit",label:j["appium-csharp-nunit"],reason:`Appium.WebDriver in ${s(u)}`,manifest:s(u)});break}}return o}function Ye(e,t=he){let r=new Map;for(let n of Dr(t,e))for(let i of qr(t,e,n))r.has(i.id)||r.set(i.id,i);return[...r.values()]}function Mr(e,t=he){let r=Ye(e,t);return r.some(n=>n.id==="taqwright")||r.push({id:"taqwright",label:j.taqwright,reason:"default output"}),r}function Ur(e){let{requested:t,configured:r,remembered:n,offeredIds:i,detectedRealIds:s,taqwrightDetected:o,javaSignal:a}=e,l=p=>!!p&&i.includes(p);return l(t)?t:l(r)?r:l(n)&&(s.includes(n)||n==="taqwright"&&o)?n:s.length?s[0]:o?"taqwright":a?"appium-java-junit5":"taqwright"}He.exports={FRAMEWORK_IDS:Cr,FRAMEWORK_ENGINES:xr,FRAMEWORK_LABELS:j,nodeFs:he,detectFrameworks:Ye,rankFrameworks:Mr,pickDefaultFramework:Ur}});var ve=R((gs,Xe)=>{"use strict";var me=require("path"),{nodeFs:Br}=fe(),Ve={taqwright:"tests","webdriverio-js":"test/specs","appium-java-junit5":"src/test/java","appium-python-pytest":"tests","appium-ruby-rspec":"spec","appium-csharp-nunit":"Tests"},Fr="tests",Kr={taqwright:".spec.ts","webdriverio-js":".spec.ts","appium-java-junit5":".java","appium-python-pytest":".py","appium-ruby-rspec":"_spec.rb","appium-csharp-nunit":".cs"},Yr=new Set(["appium-python-pytest","appium-ruby-rspec"]);function ge(e){return Ve[e]||Fr}function we(e){let t=(e||"").split(/[^A-Za-z0-9]+/).filter(Boolean);return t.length?t.map(r=>/^[A-Z0-9]+$/.test(r)?r[0]+r.slice(1).toLowerCase():r[0].toUpperCase()+r.slice(1)).join(""):""}function ye(e){return(e||"").replace(/([a-z0-9])([A-Z])/g,"$1_$2").split(/[^A-Za-z0-9]+/).filter(Boolean).join("_").toLowerCase()}function Hr(e){return ye(e).split("_").filter(Boolean).join("-")}var Vr=6,Wr=new Set(["and","or","the","a","an","to","of","in","on","at","as","with","for","then","into","from","by","that","is"]),Gr=/@|\d{6,}/;function Jr(e){let t=String(e||"").trim().split(/\s+/).filter(Boolean).filter(r=>!Gr.test(r)).slice(0,Vr);for(;t.length>1&&Wr.has(t[t.length-1].toLowerCase());)t.pop();return we(t.join(" "))||"RecordedTest"}function Xr(e){let t=String(e||"").trim();return t?/[A-Za-z]/.test(t)?t.length>80?"Keep the name under 80 characters.":/[/\\]/.test(t)?"Use the destination field for the folder.":null:"Use at least one letter.":"Enter a test name."}function Qr(e){if(e==null||e==="")return null;let t=String(e);return t!==t.trim()?"must not have leading or trailing spaces.":t.length>120?"is longer than any key LIME mints (120 characters).":/^[a-z0-9][a-z0-9._/:-]*$/.test(t)?t.includes("..")?'must not contain "..".':null:"is not a scenario key \u2014 expected lower-case letters, digits and . _ - / : only."}function We(e,t){let r;return Yr.has(e)?r=ye(t):r=we(t),`${r}${Kr[e]||""}`}function K(e){return String(e||"").split(/[/\\]+/).filter(t=>t&&t!=="."&&t!=="..").join("/")}function zr(e){if(e==null)return null;let t=String(e);return t.trim()===""?null:/^([A-Za-z]:)?[/\\]/.test(t)?"must be a path inside the project, not an absolute path.":t.split(/[/\\]+/).includes("..")?'must not contain ".." \u2014 the test belongs inside the project.':null}function be(e){let t=K(e).split("/");return t.pop(),t.join("/")}function Ge(e){let t=/(?:^|\/)src\/(?:test|main)\/java\/(.+)$/.exec(K(e));return t&&t[1].split("/").filter(Boolean).join(".")||void 0}function Zr(e){let t=K(e),r=t.search(/\/src\/(?:test|main)\/java(?:\/|$)/);return r>0?t.slice(0,r):""}function en(e){let t=new Map;for(let n of e){let i=be(n);t.set(i,(t.get(i)||0)+1)}if(!t.size)return null;let r=[...t.entries()].sort((n,i)=>i[1]-n[1]||n[0].localeCompare(i[0]));return{dir:r[0][0],count:r[0][1]}}var Je={taqwright:{segment:"tests",file:/\.spec\.(ts|js)$/},"webdriverio-js":{segment:"test/specs",file:/\.(ts|js)$/},"appium-java-junit5":{segment:"src/test/java",file:/\.java$/},"appium-python-pytest":{segment:"tests",file:/^(test_.+|.+_test)\.py$/},"appium-ruby-rspec":{segment:"spec",file:/_spec\.rb$/},"appium-csharp-nunit":{segment:"",file:/Tests\.cs$/}},tn=new Set(["node_modules","dist","build","target","bin","obj","vendor","out","coverage",".git"]),rn=2e4;function nn(e,t,r=Br){let n=Je[t];if(!n)return[];let i=[],s=rn,o=a=>{if(s<=0)return;let l=a?me.join(e,a):e,p=[];try{p=r.list(l)}catch{return}for(let c of p){if(s--<=0)return;if(c.startsWith(".")||tn.has(c))continue;let u=a?`${a}/${c}`:c;if(r.isDir?r.isDir(me.join(e,u)):r.list(me.join(e,u)).length>0){o(u);continue}n.file.test(c)&&(n.segment&&!`/${be(u)}/`.includes(`/${n.segment}/`)||i.push(u))}};return o(""),i.sort()}function sn(e){let{framework:t,testName:r}=e,n=We(t,r),i=(a,l,p=0)=>{let c=K(a),u=t==="appium-java-junit5"?Ge(c):void 0;return{dir:c,fileName:n,...u?{packageName:u}:{},source:l,neighbourCount:p}};if(e.remembered!=null)return i(e.remembered,"remembered");let s=en(e.existingTests||[]);if(s&&s.dir)return i(s.dir,"existing",s.count);let o=e.detection&&e.detection.manifest?be(e.detection.manifest):"";return o?i(`${o}/${ge(t)}`,"module"):i(ge(t),"convention")}Xe.exports={CONVENTIONAL_DIRS:Ve,TEST_PATTERNS:Je,conventionalDir:ge,pascalCase:we,snakeCase:ye,kebabCase:Hr,testNameFromGoal:Jr,validateTestName:Xr,validateDest:zr,validateScenarioKey:Qr,fileNameFor:We,normalizeDir:K,javaPackageOf:Ge,moduleRootOf:Zr,findExistingTests:nn,resolveExportTarget:sn}});var et=R((ws,Ze)=>{"use strict";var{CLOUD_PROVIDERS:ee}=q(),{validateScenarioKey:on}=ve();function an(e){let t=Object.create(null);for(let r=0;r<e.length;r++){let n=e[r];if(!n.startsWith("--"))continue;let i=n.slice(2),s=e[r+1];s===void 0||s.startsWith("--")?t[i]=!0:(t[i]=s,r++)}return t}var ze=["export","adapt","verify","check-locators","disconnect","report"];function cn(e){let t=Array.isArray(e)?e:[],r=[];for(let n=0;n<t.length;n+=1){let i=String(t[n]==null?"":t[n]);!i||i.startsWith("-")||(n>0?String(t[n-1]||""):"").startsWith("--")||r.push(i)}return r}function ln(e){let t=e[0];return t&&ze.includes(t)?{command:t,rest:e.slice(1)}:{command:"run",rest:e}}function un(e="taqwright"){return e==="json"?"recorded-steps.json":"RecordedTest.spec.ts"}function dn(e,t=process.env){let r=[],n=!!e["list-devices"],i=!!e["keep-session"],s=!!e["no-boot"],o=e["lime-dir"]===!0?".lime":typeof e["lime-dir"]=="string"&&e["lime-dir"].trim()?e["lime-dir"].trim():void 0,a=e.format?String(e.format).toLowerCase():"taqwright";if(["taqwright","json"].includes(a)||r.push(`--format must be taqwright or json (got "${e.format}")`),n)return{errors:r,listDevices:n,keepSession:i,noBoot:s,format:a,limeDir:o};(!e.goal||typeof e.goal!="string"||!e.goal.trim())&&r.push("--goal is required");let l;e.project!==void 0&&(typeof e.project!="string"||!e.project.trim()?r.push("--project requires a project name"):l=e.project.trim());let p;if(e.scenario!==void 0){let h=typeof e.scenario=="string"?e.scenario.trim():"",T=h?on(h):"requires a scenario key";T?r.push(`--scenario ${T}`):p=h}let c,u;e["gemini-key"]!==void 0&&(typeof e["gemini-key"]!="string"||!e["gemini-key"].trim()?r.push("--gemini-key requires a value (or set GEMINI_API_KEY)"):(c=e["gemini-key"].trim(),u="flag")),!c&&typeof t.GEMINI_API_KEY=="string"&&t.GEMINI_API_KEY.trim()&&(c=t.GEMINI_API_KEY.trim(),u="env");let d,g;if(e["qwen-key"]!==void 0&&(typeof e["qwen-key"]!="string"||!e["qwen-key"].trim()?r.push("--qwen-key requires a value (or set QWEN_API_KEY)"):(d=e["qwen-key"].trim(),g="flag")),!d&&typeof t.QWEN_API_KEY=="string"&&t.QWEN_API_KEY.trim()&&(d=t.QWEN_API_KEY.trim(),g="env"),e["max-steps"]!==void 0){let h=Number(e["max-steps"]);(!Number.isFinite(h)||h<1||h>200)&&r.push("--max-steps must be a number between 1 and 200")}let f;e.platform&&(f=String(e.platform).toLowerCase(),["android","ios"].includes(f)||r.push(`--platform must be android or ios (got "${e.platform}")`));let v=!!e.cloud,w=typeof e.os=="string"?e.os:void 0,y=typeof e["app-url"]=="string"?e["app-url"]:void 0,I=typeof e.app=="string"?e.app:void 0,b=typeof e.caps=="string"&&e.caps.trim()?e.caps.trim():void 0,E,A,S;if(v&&(E=e.cloud===!0?"browserstack":String(e.cloud).toLowerCase(),ee[E]||r.push(`--cloud must be ${Object.keys(ee).join(" or ")} (got "${e.cloud}")`)),v){(!e.device||typeof e.device!="string")&&r.push('--cloud requires --device (the cloud device name, e.g. "Google Pixel 8")'),f||r.push("--cloud requires --platform (android or ios)"),w||r.push("--cloud requires --os (the device OS version, e.g. 14.0)"),I?r.push("--app is not supported for cloud runs. Upload the build to your provider \u2014 LambdaTest: POST https://manual-api.lambdatest.com/app/upload/realDevice (-F appFile=@<file>), BrowserStack: POST https://api-cloud.browserstack.com/app-automate/upload (-F file=@<file>) \u2014 then pass the returned id with --app-url. (--app is still supported for local runs, where it clean-reinstalls on the agent device.)"):y||r.push("--cloud requires --app-url <bs://\u2026 | lt://\u2026> (the id from your provider\u2019s app upload API)"),e["app-url"]!==void 0&&(typeof e["app-url"]!="string"||!e["app-url"].trim())&&r.push("--app-url requires a bs:// or lt:// app id"),y&&ee[E]&&(E==="browserstack"&&y.startsWith("lt://")?r.push(`--app-url "${y}" is a LambdaTest app id, but the provider is browserstack`):E==="lambdatest"&&y.startsWith("bs://")&&r.push(`--app-url "${y}" is a BrowserStack app id, but the provider is lambdatest`)),e["cloud-username"]!==void 0&&(typeof e["cloud-username"]!="string"||!e["cloud-username"].trim())&&r.push("--cloud-username requires a value"),e["cloud-access-key"]!==void 0&&(typeof e["cloud-access-key"]!="string"||!e["cloud-access-key"].trim())&&r.push("--cloud-access-key requires a value"),e.caps!==void 0&&(typeof e.caps!="string"||!e.caps.trim())&&r.push("--caps requires a path to a JSON file");let h=ee[E];h&&(A=typeof e["cloud-username"]=="string"&&e["cloud-username"].trim()||t[h.envUsername]||void 0,S=typeof e["cloud-access-key"]=="string"&&e["cloud-access-key"].trim()||t[h.envAccessKey]||void 0,A||r.push(`cloud runs require a username \u2014 pass --cloud-username or set ${h.envUsername} (credentials are never read from your LIME account for CLI runs)`),S||r.push(`cloud runs require an access key \u2014 pass --cloud-access-key or set ${h.envAccessKey}`))}else e.app!==void 0&&(typeof e.app!="string"||!e.app.trim()?r.push("--app requires a path to an APK"):e.device?f&&f!=="android"&&r.push("--app is Android only"):r.push("--app requires --device (lime-cli must connect to a device to reinstall the app)")),e["app-url"]!==void 0&&r.push("--app-url requires --cloud"),e.os!==void 0&&r.push("--os requires --cloud"),e["cloud-username"]!==void 0&&r.push("--cloud-username requires --cloud"),e["cloud-access-key"]!==void 0&&r.push("--cloud-access-key requires --cloud"),e.caps!==void 0&&r.push("--caps requires --cloud");return{errors:r,listDevices:n,keepSession:i,noBoot:s,limeDir:o,device:e.device,platform:f,projectName:l,scenarioKey:p,geminiKey:c,geminiKeySource:u,qwenKey:d,qwenKeySource:g,app:I,cloud:v,cloudProvider:E,cloudUsername:A,cloudAccessKey:S,os:w,appUrl:y,capsPath:b,format:a}}var Qe=["browserstack","lambdatest","appium"];function pn(e){let t=[],r=[];for(let[n,i]of Object.entries(e||{}))!i||typeof i!="object"||Array.isArray(i)?t.push(`--caps block "${n}" must be a JSON object, e.g. { "${n}": { "someCap": true } }`):Qe.includes(n)||r.push(`--caps block "${n}" is not one of ${Qe.join("/")} \u2014 it will be ignored (typo?)`);return{errors:t,warnings:r}}Ze.exports={parseArgs:an,parseCommand:ln,positionalPaths:cn,validateArgs:dn,extToFilename:un,validateCapsObject:pn,COMMANDS:ze}});var nt=R((ys,rt)=>{"use strict";var{DEFAULT_SERVER:hn}=D(),tt={export:`lime-cli export \u2014 work out what this repo is, and where the test belongs.
|
|
3
3
|
|
|
4
4
|
Detects the test framework from the project's own manifests (pytest, JUnit, RSpec, WebdriverIO,
|
|
5
5
|
C#, taqwright), picks the directory its existing tests live in, and writes the adaptation brief.
|
|
@@ -358,14 +358,14 @@ ${at(e)}`);if(r&&o.platform!==r)throw new Error(`Device "${t}" matched on ${o.pl
|
|
|
358
358
|
`),1):(h&&h.unused.length&&process.stdout.write(`lime-cli: ${h.unused.length} recorded locator${h.unused.length===1?"":"s"} the generated test does not use.
|
|
359
359
|
`),ae(r,{...c,adaptedFiles:S.files,adaptSummary:S.summary||null,conservation:h}),process.stdout.write(`${H}: adapted
|
|
360
360
|
`),0)}async function yi(e={}){let{cwd:t=process.cwd(),limeDir:r=k.join(t,".lime"),files:n=[],diff:i}=e,s=k.join(r,x(M)),o=Xt(s);if(!o)return process.stderr.write(`lime-cli: no readable ${x(M)} in ${r} \u2014 nothing to check the generated test against.
|
|
361
|
-
`),2;let l=(V(r)||{}).framework||"taqwright",p;if(i){let
|
|
362
|
-
`),2}let
|
|
363
|
-
`),0;p=Bt({steps:o,framework:l,files:
|
|
364
|
-
`),2;p=Qt(t,
|
|
365
|
-
`),
|
|
366
|
-
`),
|
|
367
|
-
`),
|
|
368
|
-
`),
|
|
361
|
+
`),2;let l=(V(r)||{}).framework||"taqwright",p;if(i){let c;try{c=$.readFileSync(k.resolve(t,i),"utf8")}catch{return process.stderr.write(`lime-cli: could not read the diff at ${i}.
|
|
362
|
+
`),2}let u=di(c);if(!u.length)return process.stdout.write(`lime-cli: the change adds no lines, so there is no new locator to check.
|
|
363
|
+
`),0;p=Bt({steps:o,framework:l,files:u})}else{let c=n.filter(Boolean);if(!c.length)return process.stderr.write(`lime-cli: name at least one generated file to check, or pass --diff.
|
|
364
|
+
`),2;p=Qt(t,c,{steps:o,framework:l})}return p?p.ok?p.abstained?(process.stdout.write(`lime-cli: ${p.reason}.
|
|
365
|
+
`),0):(process.stdout.write(`lime-cli: every locator in this change was recorded on the device.
|
|
366
|
+
`),0):(process.stderr.write(`${Ft(p)}
|
|
367
|
+
`),1):(process.stderr.write(`lime-cli: none of the named files could be read, so nothing was checked.
|
|
368
|
+
`),2)}function Xt(e){try{return JSON.parse($.readFileSync(e,"utf8"))}catch{return null}}function Qt(e,t,{steps:r,framework:n}){let i=[];for(let s of Array.isArray(t)?t:[])try{i.push({path:s,source:$.readFileSync(k.resolve(e,s),"utf8")})}catch{}return i.length?Bt({steps:r,framework:n,files:i}):null}async function bi(e={}){let{cwd:t=process.cwd(),limeDir:r=k.join(t,".lime"),agent:n="auto",spec:i,testId:s,appDir:o,env:a=process.env,runAgent:l=Mt,resolveBin:p=Ut}=e,c=V(r)||{},u=c.target==="cloud"?"cloud":"local",d=c.framework||"taqwright",g=Wt(c.adaptedFiles),f=i?[i]:g.length?g:[c.output||"RecordedTest.spec.ts"],v={};if(u==="cloud"){let S=c.cloud||{},h=jt[S.provider]||jt.browserstack,T=(a[h.envUsername]||"").trim(),L=(a[h.envAccessKey]||"").trim();if(!T||!L)return process.stderr.write(`lime-cli: verifying on ${h.label} needs ${h.envUsername} and ${h.envAccessKey} in the environment.
|
|
369
369
|
`),2;$.mkdirSync(r,{recursive:!0}),$.writeFileSync(k.join(r,x(oi)),JSON.stringify({provider:S.provider||"browserstack",hubHost:S.hubHost||h.hubHost,appUrl:S.appUrl||null,device:S.device||null,os:S.os||null,platform:c.platform||null,region:S.region||null},null,2)+`
|
|
370
370
|
`,"utf8"),v={LIME_CLOUD_USER:T,LIME_CLOUD_KEY:L}}let w=ci({frameworkLabel:c.frameworkLabel||d,framework:d,testPaths:f,testId:s||c.testId||null,target:u,recordedPlatform:c.platform||null}),y=k.join(r,x(si));$.writeFileSync(y,w,"utf8"),process.stdout.write(`lime-cli: wrote ${k.relative(t,y)||y}
|
|
371
371
|
`);let I=Gt(n,p);if(I.error)return process.stderr.write(`lime-cli: ${I.error}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taqwright/lime-cli",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.10",
|
|
4
4
|
"description": "Thin CLI client for the LIME server — fire a natural-language QA Agent goal against a connected device and write back a taqwright spec.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"author": "Taqwright",
|