@zibby/cli 0.1.32 → 0.1.34

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.
@@ -5,7 +5,7 @@ import It from"express";import{createServer as Jt}from"http";import{WebSocketSer
5
5
  \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
6
6
  \u2551 Zibby Studio \u2551
7
7
  \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
8
- `),ie({projectRoot:I}),setTimeout(()=>{y.close(),process.exit(0)},1e3)}function rt(){const s=a(I,".zibby.config.mjs");return u(s)?s:a(v,".zibby.config.mjs")}function x(){rt();const s=a(I,".zibby","output","sessions");return u(s)?s:a(v,".zibby","output","sessions")}function q(s,t){let e=null,o=null,n=null;const c=a(s,"codegen");if(u(c)){const r=a(c,"test.spec.ts"),i=a(c,"generated-test.spec.js");e=u(r)?r:u(i)?i:null;const d=a(c,"test.selenium.py"),p=a(c,"generated-test-selenium.js");o=u(d)?d:u(p)?p:null;const m=a(c,"trace.zip");n=u(m)?m:null}const l=a(s,"generate_script","result.json");if(!e&&u(l))try{const i=JSON.parse(_(l,"utf8"))?.scriptPath;if(typeof i=="string"&&i.trim()){const d=i.trim(),p=d.startsWith("/")||process.platform==="win32"&&/^[A-Za-z]:[\\/]/.test(d)?d:a(t,d);u(p)&&(e=p)}}catch(r){console.warn("[Studio API] generate_script result.json:",r.message)}return!e&&!o&&!n?null:{playwrightFile:e,seleniumFile:o,tracePath:n}}function Rt(s,t,e){try{H(a(s,U),JSON.stringify({sessionId:t,pid:e??null,startedAt:Date.now()},null,2),"utf8")}catch(o){console.error("[Studio API] writeStudioRunMeta:",o.message)}}function z(s){try{const t=a(s,U);u(t)&&qt(t)}catch{}}function Ct(s){const t=Number(s);if(!Number.isFinite(t)||t<=0)return[];try{const e=Y(`pgrep -P ${t}`,{encoding:"utf8",stdio:["ignore","pipe","ignore"],maxBuffer:524288}).trim();return e?e.split(/\n/).map(o=>parseInt(o.trim(),10)).filter(o=>Number.isFinite(o)&&o>0):[]}catch{return[]}}function W(s,t){const e=Number(s);if(!Number.isFinite(e)||e<=0)return;const o=new Set;function n(c){if(!o.has(c)){o.add(c);for(const l of Ct(c))n(l);try{process.kill(c,t)}catch{}}}n(e)}function it(s){const t=Number(s);if(!(!Number.isFinite(t)||t<=0))try{Y(`taskkill /PID ${t} /T /F`,{stdio:"ignore",windowsHide:!0})}catch{}}function ct(s){if(!Number.isFinite(s)||s<=0)return;if(process.platform==="win32"){it(s);return}W(s,"SIGTERM");const t=setTimeout(()=>{W(s,"SIGKILL")},800);typeof t.unref=="function"&&t.unref()}function Ft(s,t){const o=C(s)||a(x(),s);try{bt(o,{recursive:!0}),H(a(o,Et),JSON.stringify({requestedAt:Date.now()}),"utf8")}catch(r){console.error("[Studio API] write studio stop request:",r.message)}const n=R.get(s);if(n){const r=n.pid;if(process.platform==="win32")it(r);else{W(r,"SIGTERM");const i=setTimeout(()=>{W(r,"SIGKILL")},800);typeof i.unref=="function"&&i.unref()}return R.delete(s),z(o),!0}const c=a(o,U);if(u(c)){let r=null;try{const i=JSON.parse(_(c,"utf8"));r=Number(i.pid)}catch(i){console.error("[Studio API] studio-run.json read:",i.message)}if(z(o),Number.isFinite(r)&&r>0)return ct(r),!0}const l=Number(t);return Number.isFinite(l)&&l>0?(ct(l),z(o),!0):!1}function J(s){try{const t=s?.query?.sessionsRoot;if(typeof t!="string")return"";const e=t.trim();if(!e)return"";const o=decodeURIComponent(e),n=O(o);return u(n)?n:""}catch{return""}}function C(s,t=""){const e=typeof s=="string"?decodeURIComponent(s).trim():String(s||"").trim();if(!e)return null;const o=[e],n=e.split("_")[0]?.trim()||"";n&&n!==e&&o.push(n);const c=new Set,l=[],r=new Set,i=[],d=h=>{if(!h)return;const f=O(h);r.has(f)||(r.add(f),i.push(f))},p=h=>{if(h){d(h);for(const f of o){const S=a(h,f);c.has(S)||(c.add(S),l.push(S))}}};p(t),p(x()),p(a(v,".zibby","output","sessions"));let m;try{m=$(I)}catch{m=[]}for(const h of m){if(h.startsWith("."))continue;const f=a(I,h);try{if(!L(f).isDirectory())continue}catch{continue}p(a(f,".zibby","output","sessions"));let S;try{S=$(f,{withFileTypes:!0})}catch{S=[]}for(const T of S)T?.isDirectory?.()&&String(T.name||"").startsWith(".zibby")&&p(a(f,T.name,"output","sessions"))}const w=l.filter(h=>u(h));if(w.length===0)for(const h of i){if(!u(h))continue;let f;try{f=$(h,{withFileTypes:!0})}catch{f=[]}for(const S of f){if(!S?.isDirectory?.())continue;const T=String(S.name||"");if(T===e||T===n||T.startsWith(`${e}_`)||n&&T.startsWith(`${n}_`)){const F=a(h,T);if(c.has(F))continue;c.add(F),w.push(F)}}}if(w.length===0)return null;if(w.length===1)return w[0];const M=h=>{let f=0;u(a(h,"execute_live"))&&(f+=20),Pt(h)&&(f+=15),u(a(h,"execute_live","events.json"))&&(f+=8),u(a(h,"execute_live","result.json"))&&(f+=6),u(a(h,U))&&(f+=4),u(a(h,".session-info.json"))&&(f+=2);try{const S=a(h,"execute_live");u(S)&&(f+=Math.min(L(S).mtimeMs/1e12,3))}catch{}return f};return w.sort((h,f)=>M(f)-M(h)),w[0]}function Lt(s,t){try{const e=typeof s=="string"?decodeURIComponent(s).trim():String(s||"").trim();if(!e||!t)return null;const o=(e.split("_")[0]||"").trim(),n=jt(t);if(!o||!n||!u(n))return null;let c=[];try{c=$(n,{withFileTypes:!0})}catch{c=[]}let l=null;for(const r of c){if(!r?.isDirectory?.())continue;const i=String(r.name||"");if(!(i===e||i===o||i.startsWith(`${e}_`)||i.startsWith(`${o}_`)))continue;const d=a(n,i),p=vt(d);p&&(!l||Number(p.mtime||0)>Number(l.mtime||0))&&(l=p)}return l}catch{return null}}g.get("/api/config/check",(s,t)=>{const e=rt();t.json({exists:u(e),path:e,isProjectLevel:e.startsWith(I)})}),g.get("/api/projects",(s,t)=>{try{const e=a(v,".zibby","config.json");if(!u(e))return t.json({projects:[]});const o=JSON.parse(_(e,"utf8")),n=typeof o.sessionToken=="string"&&o.sessionToken.trim()!==""?o.sessionToken.trim():"",c=Array.isArray(o.projects)?o.projects:[];if(!n)return t.json({projects:c});const l=String(wt()).replace(/\/$/,"");fetch(`${l}/projects`,{headers:{Authorization:`Bearer ${n}`}}).then(r=>r.json().catch(()=>({})).then(i=>({ok:r.ok,status:r.status,body:i}))).then(({ok:r,body:i})=>{if(!r)return t.json({projects:c});const p=(Array.isArray(i?.projects)?i.projects:[]).map(m=>({name:m?.name,projectId:m?.projectId,apiToken:m?.apiToken||null,createdAt:m?.createdAt||null,updatedAt:m?.updatedAt||null}));o.projects=p;try{H(e,`${JSON.stringify(o,null,2)}
8
+ `),await ie({projectRoot:I}),setTimeout(()=>{y.close(),process.exit(0)},1e3)}function rt(){const s=a(I,".zibby.config.mjs");return u(s)?s:a(v,".zibby.config.mjs")}function x(){rt();const s=a(I,".zibby","output","sessions");return u(s)?s:a(v,".zibby","output","sessions")}function q(s,t){let e=null,o=null,n=null;const c=a(s,"codegen");if(u(c)){const r=a(c,"test.spec.ts"),i=a(c,"generated-test.spec.js");e=u(r)?r:u(i)?i:null;const d=a(c,"test.selenium.py"),p=a(c,"generated-test-selenium.js");o=u(d)?d:u(p)?p:null;const m=a(c,"trace.zip");n=u(m)?m:null}const l=a(s,"generate_script","result.json");if(!e&&u(l))try{const i=JSON.parse(_(l,"utf8"))?.scriptPath;if(typeof i=="string"&&i.trim()){const d=i.trim(),p=d.startsWith("/")||process.platform==="win32"&&/^[A-Za-z]:[\\/]/.test(d)?d:a(t,d);u(p)&&(e=p)}}catch(r){console.warn("[Studio API] generate_script result.json:",r.message)}return!e&&!o&&!n?null:{playwrightFile:e,seleniumFile:o,tracePath:n}}function Rt(s,t,e){try{H(a(s,U),JSON.stringify({sessionId:t,pid:e??null,startedAt:Date.now()},null,2),"utf8")}catch(o){console.error("[Studio API] writeStudioRunMeta:",o.message)}}function z(s){try{const t=a(s,U);u(t)&&qt(t)}catch{}}function Ct(s){const t=Number(s);if(!Number.isFinite(t)||t<=0)return[];try{const e=Y(`pgrep -P ${t}`,{encoding:"utf8",stdio:["ignore","pipe","ignore"],maxBuffer:524288}).trim();return e?e.split(/\n/).map(o=>parseInt(o.trim(),10)).filter(o=>Number.isFinite(o)&&o>0):[]}catch{return[]}}function W(s,t){const e=Number(s);if(!Number.isFinite(e)||e<=0)return;const o=new Set;function n(c){if(!o.has(c)){o.add(c);for(const l of Ct(c))n(l);try{process.kill(c,t)}catch{}}}n(e)}function it(s){const t=Number(s);if(!(!Number.isFinite(t)||t<=0))try{Y(`taskkill /PID ${t} /T /F`,{stdio:"ignore",windowsHide:!0})}catch{}}function ct(s){if(!Number.isFinite(s)||s<=0)return;if(process.platform==="win32"){it(s);return}W(s,"SIGTERM");const t=setTimeout(()=>{W(s,"SIGKILL")},800);typeof t.unref=="function"&&t.unref()}function Ft(s,t){const o=C(s)||a(x(),s);try{bt(o,{recursive:!0}),H(a(o,Et),JSON.stringify({requestedAt:Date.now()}),"utf8")}catch(r){console.error("[Studio API] write studio stop request:",r.message)}const n=R.get(s);if(n){const r=n.pid;if(process.platform==="win32")it(r);else{W(r,"SIGTERM");const i=setTimeout(()=>{W(r,"SIGKILL")},800);typeof i.unref=="function"&&i.unref()}return R.delete(s),z(o),!0}const c=a(o,U);if(u(c)){let r=null;try{const i=JSON.parse(_(c,"utf8"));r=Number(i.pid)}catch(i){console.error("[Studio API] studio-run.json read:",i.message)}if(z(o),Number.isFinite(r)&&r>0)return ct(r),!0}const l=Number(t);return Number.isFinite(l)&&l>0?(ct(l),z(o),!0):!1}function J(s){try{const t=s?.query?.sessionsRoot;if(typeof t!="string")return"";const e=t.trim();if(!e)return"";const o=decodeURIComponent(e),n=O(o);return u(n)?n:""}catch{return""}}function C(s,t=""){const e=typeof s=="string"?decodeURIComponent(s).trim():String(s||"").trim();if(!e)return null;const o=[e],n=e.split("_")[0]?.trim()||"";n&&n!==e&&o.push(n);const c=new Set,l=[],r=new Set,i=[],d=h=>{if(!h)return;const f=O(h);r.has(f)||(r.add(f),i.push(f))},p=h=>{if(h){d(h);for(const f of o){const S=a(h,f);c.has(S)||(c.add(S),l.push(S))}}};p(t),p(x()),p(a(v,".zibby","output","sessions"));let m;try{m=$(I)}catch{m=[]}for(const h of m){if(h.startsWith("."))continue;const f=a(I,h);try{if(!L(f).isDirectory())continue}catch{continue}p(a(f,".zibby","output","sessions"));let S;try{S=$(f,{withFileTypes:!0})}catch{S=[]}for(const T of S)T?.isDirectory?.()&&String(T.name||"").startsWith(".zibby")&&p(a(f,T.name,"output","sessions"))}const w=l.filter(h=>u(h));if(w.length===0)for(const h of i){if(!u(h))continue;let f;try{f=$(h,{withFileTypes:!0})}catch{f=[]}for(const S of f){if(!S?.isDirectory?.())continue;const T=String(S.name||"");if(T===e||T===n||T.startsWith(`${e}_`)||n&&T.startsWith(`${n}_`)){const F=a(h,T);if(c.has(F))continue;c.add(F),w.push(F)}}}if(w.length===0)return null;if(w.length===1)return w[0];const M=h=>{let f=0;u(a(h,"execute_live"))&&(f+=20),Pt(h)&&(f+=15),u(a(h,"execute_live","events.json"))&&(f+=8),u(a(h,"execute_live","result.json"))&&(f+=6),u(a(h,U))&&(f+=4),u(a(h,".session-info.json"))&&(f+=2);try{const S=a(h,"execute_live");u(S)&&(f+=Math.min(L(S).mtimeMs/1e12,3))}catch{}return f};return w.sort((h,f)=>M(f)-M(h)),w[0]}function Lt(s,t){try{const e=typeof s=="string"?decodeURIComponent(s).trim():String(s||"").trim();if(!e||!t)return null;const o=(e.split("_")[0]||"").trim(),n=jt(t);if(!o||!n||!u(n))return null;let c=[];try{c=$(n,{withFileTypes:!0})}catch{c=[]}let l=null;for(const r of c){if(!r?.isDirectory?.())continue;const i=String(r.name||"");if(!(i===e||i===o||i.startsWith(`${e}_`)||i.startsWith(`${o}_`)))continue;const d=a(n,i),p=vt(d);p&&(!l||Number(p.mtime||0)>Number(l.mtime||0))&&(l=p)}return l}catch{return null}}g.get("/api/config/check",(s,t)=>{const e=rt();t.json({exists:u(e),path:e,isProjectLevel:e.startsWith(I)})}),g.get("/api/projects",(s,t)=>{try{const e=a(v,".zibby","config.json");if(!u(e))return t.json({projects:[]});const o=JSON.parse(_(e,"utf8")),n=typeof o.sessionToken=="string"&&o.sessionToken.trim()!==""?o.sessionToken.trim():"",c=Array.isArray(o.projects)?o.projects:[];if(!n)return t.json({projects:c});const l=String(wt()).replace(/\/$/,"");fetch(`${l}/projects`,{headers:{Authorization:`Bearer ${n}`}}).then(r=>r.json().catch(()=>({})).then(i=>({ok:r.ok,status:r.status,body:i}))).then(({ok:r,body:i})=>{if(!r)return t.json({projects:c});const p=(Array.isArray(i?.projects)?i.projects:[]).map(m=>({name:m?.name,projectId:m?.projectId,apiToken:m?.apiToken||null,createdAt:m?.createdAt||null,updatedAt:m?.updatedAt||null}));o.projects=p;try{H(e,`${JSON.stringify(o,null,2)}
9
9
  `,"utf8")}catch{}return t.json({projects:p})}).catch(()=>t.json({projects:c}))}catch(e){t.status(500).json({error:e.message})}}),g.post("/api/projects/create",async(s,t)=>{try{const e=typeof s.body?.name=="string"?s.body.name.trim():"";if(!e)return t.status(400).json({error:"Project name is required"});const o=a(v,".zibby","config.json");if(!u(o))return t.status(401).json({error:"Not logged in"});const n=JSON.parse(_(o,"utf8")),c=typeof n.sessionToken=="string"&&n.sessionToken.trim()!==""?n.sessionToken.trim():"";if(!c)return t.status(401).json({error:"Not logged in"});const l=String(wt()).replace(/\/$/,""),r=await fetch(`${l}/projects`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${c}`},body:JSON.stringify({name:e})}),i=await r.json().catch(()=>({}));if(!r.ok)return t.status(r.status).json({error:i.error||i.message||`HTTP ${r.status}`});const d=i?.project&&typeof i.project=="object"?i.project:null;if(d?.projectId){const m=(Array.isArray(n.projects)?n.projects:[]).filter(w=>String(w?.projectId||"")!==String(d.projectId));m.push({name:d.name||e,projectId:d.projectId,apiToken:d.apiToken||i?.apiToken||null,createdAt:d.createdAt||null,updatedAt:d.updatedAt||null}),n.projects=m;try{H(o,`${JSON.stringify(n,null,2)}
10
10
  `,"utf8")}catch{}}return t.json(i)}catch(e){return t.status(500).json({error:e.message||String(e)})}});function $t(s,t){const e=Array.isArray(t)?t.filter(d=>typeof d=="string"):[],o=process.argv[1]?O(process.argv[1]):"",n=o?Qt(o):"";let c;try{c=!!o&&u(o)&&L(o).isFile()&&!/\.(cmd|ps1|bat)$/i.test(o)&&(/\.(m|c)?js$/i.test(o)||n==="zibby")}catch{c=!1}if(c){const d=[o,"test",s,...e],p=[process.execPath,...d].map(m=>/\s/.test(String(m))?`"${String(m).replace(/"/g,'\\"')}"`:m).join(" ");return{useShell:!1,cmd:process.execPath,args:d,display:p}}const l=s.replace(/"/g,'\\"'),r=e.join(" "),i=`zibby test "${l}" ${r}`.trim();return{useShell:!0,cmd:i,args:[],display:i}}g.get("/api/run/result/:sessionId",(s,t)=>{const{sessionId:e}=s.params,o=D.get(e);if(!o)return t.status(404).json({pending:!0,error:"unknown_session"});t.json(o)}),g.post("/api/run",async(s,t)=>{const{task:e,args:o=[],sessionId:n,studioTestCaseId:c}=s.body;if(!e||!n)return t.status(400).json({success:!1,error:"task and sessionId are required"});const l=x(),r=a(l,n),i=O(r),d=c!=null&&String(c).trim()!==""?String(c).trim():String(n);D.set(n,{pending:!0});let p=!1,m=null;const w=()=>{if(m&&!m.destroyed)try{m.end()}catch{}m=null},M=(f,S)=>{D.delete(n),w(),p||t.status(f).json(S)},h=()=>{const f=[];return k.clients.forEach(S=>{S.sessionId===n&&f.push(S)}),f};try{const f=$t(e,o);console.log("[Studio API] Running:",f.display),f.useShell?console.warn('[Studio API] Falling back to shell "zibby" from PATH \u2014 if runs do nothing, run Studio from this repo or ensure `zibby` points to the same install.'):console.log("[Studio API] Using same CLI as this server (argv[1]):",process.argv[1]),bt(r,{recursive:!0}),m=Yt(a(r,nt),{flags:"w"}),B(i,{sessionId:String(n),studioTestCaseId:d,status:"running",runSource:"studio",activeStageIndex:0,activeNode:"preflight",cwd:I,outputBase:".zibby/output",sessionPathAbs:i});const S=st(f.cmd,f.args,{cwd:I,shell:f.useShell,env:{...process.env,ZIBBY_SESSION_ID:n,ZIBBY_SESSION_PATH:O(r)}});R.set(n,S),Rt(r,n,S.pid),B(i,{sessionId:String(n),studioTestCaseId:d,status:"running",runSource:"studio",activeStageIndex:0,activeNode:"preflight",cwd:I,outputBase:".zibby/output",sessionPathAbs:i,pid:S.pid??null});let T="",F="",dt=!1,ft=0;const pt=setInterval(()=>{try{const b=Pt(r);if(!b||b.mtime<=ft)return;ft=b.mtime;const j=_(b.p).toString("base64"),P=b.p.toLowerCase().endsWith(".png")?"image/png":"image/jpeg";h().forEach(K=>{try{K.send(JSON.stringify({type:"video-frame",sessionId:n,frame:j,mime:P}))}catch{}})}catch{}},320),mt=b=>{if(dt)return;dt=!0,w();const j={pending:!1,...b};typeof j.stdout=="string"&&j.stdout.length>G&&(j.stdout=`\u2026(truncated)
11
11
  ${j.stdout.slice(-G)}`),typeof j.stderr=="string"&&j.stderr.length>G&&(j.stderr=`\u2026(truncated)
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zibby/cli",
3
- "version": "0.1.32",
3
+ "version": "0.1.34",
4
4
  "description": "Zibby CLI - Test automation generator and runner",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,7 +1,7 @@
1
- import i from"os";import a from"path";import{existsSync as m,readFileSync as y,readdirSync as S,createWriteStream as h,mkdirSync as g,rmSync as x,unlinkSync as I}from"fs";import{execFileSync as Z}from"child_process";import{createInterface as v}from"readline";import l from"chalk";const A=process.env.ZIBBY_STUDIO_CDN||"https://dl.zibby.app",n=a.join(i.homedir(),".zibby","studio");function b(){const t=i.platform(),o=i.arch();if(t==="darwin"&&o==="arm64")return{archive:"Zibby Studio-mac-arm64.zip",label:"macOS (Apple Silicon)"};if(t==="darwin")return{archive:"Zibby Studio-mac-x64.zip",label:"macOS (Intel)"};if(t==="win32"&&o==="arm64")return{archive:"Zibby Studio-win-arm64.zip",label:"Windows (ARM)"};if(t==="win32")return{archive:"Zibby Studio-win-x64.zip",label:"Windows (x64)"};if(t==="linux"&&o==="arm64")return{archive:"Zibby Studio-arm64.AppImage",label:"Linux (ARM64)"};if(t==="linux")return{archive:"Zibby Studio-1.0.0.AppImage",label:"Linux (x64)"};throw new Error(`Unsupported platform: ${t} ${o}`)}function $(){const{archive:t}=b();return`${A}/download/latest/${encodeURIComponent(t)}`}function z(t){const o=v({input:process.stdin,output:process.stdout});return new Promise(e=>{o.question(t,u=>{o.close(),e(u.trim().toLowerCase())})})}async function C(){const{label:t}=b();console.log(""),console.log(l.cyan(" Zibby Studio is not installed.")),console.log(l.gray(` Platform: ${t}`)),console.log("");const o=await z(l.white(" Download and install Zibby Studio? (Y/n): "));return o&&o!=="y"&&o!=="yes"?(console.log(l.yellow(`
1
+ import i from"os";import a from"path";import{existsSync as m,readFileSync as S,readdirSync as h,createWriteStream as g,mkdirSync as x,rmSync as I,unlinkSync as Z}from"fs";import{execFileSync as b}from"child_process";import{createInterface as v}from"readline";import l from"chalk";const A=process.env.ZIBBY_STUDIO_CDN||"https://dl.zibby.app",n=a.join(i.homedir(),".zibby","studio");function w(){const t=i.platform(),o=i.arch();if(t==="darwin"&&o==="arm64")return{archive:"Zibby Studio-mac-arm64.zip",label:"macOS (Apple Silicon)"};if(t==="darwin")return{archive:"Zibby Studio-mac-x64.zip",label:"macOS (Intel)"};if(t==="win32"&&o==="arm64")return{archive:"Zibby Studio-win-arm64.zip",label:"Windows (ARM)"};if(t==="win32")return{archive:"Zibby Studio-win-x64.zip",label:"Windows (x64)"};if(t==="linux"&&o==="arm64")return{archive:"Zibby Studio-arm64.AppImage",label:"Linux (ARM64)"};if(t==="linux")return{archive:"Zibby Studio-1.0.0.AppImage",label:"Linux (x64)"};throw new Error(`Unsupported platform: ${t} ${o}`)}function $(){const{archive:t}=w();return`${A}/download/latest/${encodeURIComponent(t)}`}function z(t){const o=v({input:process.stdin,output:process.stdout});return new Promise(e=>{o.question(t,u=>{o.close(),e(u.trim().toLowerCase())})})}async function C(){const{label:t}=w();console.log(""),console.log(l.cyan(" Zibby Studio is not installed.")),console.log(l.gray(` Platform: ${t}`)),console.log("");const o=await z(l.white(" Download and install Zibby Studio? (Y/n): "));return o&&o!=="y"&&o!=="yes"?(console.log(l.yellow(`
2
2
  Skipped.
3
3
  `)),!1):(await D(),!0)}async function D(){const t=$(),o=decodeURIComponent(a.basename(t));console.log(l.cyan(`
4
- \u{1F4E6} Downloading Zibby Studio...`));try{const e=await fetch(t);if(!e.ok)throw new Error(`Download failed: ${e.status} ${e.statusText}`);const u=parseInt(e.headers.get("content-length")||"0",10),s=a.join(i.tmpdir(),o);let f=0;const d=h(s);for await(const r of e.body)if(f+=r.length,d.write(r),u>0){const c=(f/u*100).toFixed(1),p=(f/1024/1024).toFixed(1),w=(u/1024/1024).toFixed(1);process.stdout.write(`\r \u{1F4E5} ${c}% (${p}MB / ${w}MB)`)}if(await new Promise((r,c)=>{d.on("finish",r),d.on("error",c),d.end()}),console.log(""),m(n)&&x(n,{recursive:!0,force:!0}),g(n,{recursive:!0}),console.log(l.cyan(" \u{1F4C2} Installing...")),s.endsWith(".zip"))if(i.platform()==="darwin"||i.platform()==="linux")Z("unzip",["-oq",s,"-d",n]);else{const r=(await import("adm-zip")).default;new r(s).extractAllTo(n,!0)}else if(s.endsWith(".AppImage")){const{copyFileSync:r,chmodSync:c}=await import("fs"),p=a.join(n,o);r(s,p),c(p,493)}try{I(s)}catch{}return console.log(l.green(` \u2705 Zibby Studio installed!
4
+ \u{1F4E6} Downloading Zibby Studio...`));try{const e=await fetch(t);if(!e.ok)throw new Error(`Download failed: ${e.status} ${e.statusText}`);const u=parseInt(e.headers.get("content-length")||"0",10),c=a.join(i.tmpdir(),o);let f=0;const p=g(c);for await(const r of e.body)if(f+=r.length,p.write(r),u>0){const s=(f/u*100).toFixed(1),d=(f/1024/1024).toFixed(1),y=(u/1024/1024).toFixed(1);process.stdout.write(`\r \u{1F4E5} ${s}% (${d}MB / ${y}MB)`)}if(await new Promise((r,s)=>{p.on("finish",r),p.on("error",s),p.end()}),console.log(""),m(n)&&I(n,{recursive:!0,force:!0}),x(n,{recursive:!0}),console.log(l.cyan(" \u{1F4C2} Installing...")),c.endsWith(".zip"))if(i.platform()==="darwin"||i.platform()==="linux"){if(b("unzip",["-oq",c,"-d",n]),i.platform()==="darwin")try{b("xattr",["-rd","com.apple.quarantine",n])}catch{}}else{const r=(await import("adm-zip")).default;new r(c).extractAllTo(n,!0)}else if(c.endsWith(".AppImage")){const{copyFileSync:r,chmodSync:s}=await import("fs"),d=a.join(n,o);r(c,d),s(d,493)}try{Z(c)}catch{}return console.log(l.green(` \u2705 Zibby Studio installed!
5
5
  `)),!0}catch(e){throw console.log(l.red(`
6
6
  \u274C Installation failed: ${e.message}
7
- `)),e}}function M(){const t=k();return!!(t&&m(t))}function k(){if(i.platform()==="darwin")return a.join(n,"Zibby Studio.app");if(i.platform()==="win32")return a.join(n,"Zibby Studio.exe");if(i.platform()==="linux"){if(!m(n))return null;const t=S(n).find(o=>o.endsWith(".AppImage"));return t?a.join(n,t):null}return null}function O(){const t=a.join(n,"version.txt");return m(t)?y(t,"utf-8").trim():"unknown"}export{k as getStudioAppPath,O as getStudioVersion,D as installStudio,M as isStudioInstalled,C as promptAndInstallStudio};
7
+ `)),e}}function M(){const t=k();return!!(t&&m(t))}function k(){if(i.platform()==="darwin")return a.join(n,"Zibby Studio.app");if(i.platform()==="win32")return a.join(n,"Zibby Studio.exe");if(i.platform()==="linux"){if(!m(n))return null;const t=h(n).find(o=>o.endsWith(".AppImage"));return t?a.join(n,t):null}return null}function O(){const t=a.join(n,"version.txt");return m(t)?S(t,"utf-8").trim():"unknown"}export{k as getStudioAppPath,O as getStudioVersion,D as installStudio,M as isStudioInstalled,C as promptAndInstallStudio};
@@ -1 +1 @@
1
- import{spawn as n}from"child_process";import p from"os";import c from"path";import{existsSync as d,mkdirSync as a,writeFileSync as f}from"fs";import{getStudioAppPath as u}from"./studio-installer.js";const s=c.join(p.homedir(),".zibby","studio-launch.json");function l(r){const o={};r.projectRoot&&(o.projectRoot=r.projectRoot),r.port&&(o.port=r.port),o.launchedAt=Date.now();const t=c.dirname(s);a(t,{recursive:!0}),f(s,JSON.stringify(o,null,2))}function g(r={}){const o=u();if(!o)throw new Error("Studio not installed");if(!d(o))throw new Error(`Studio app not found at ${o}`);l(r);let t;p.platform()==="darwin"?t=n("open",["-a",o,"--env",`ZIBBY_STUDIO_PROJECT_ROOT=${r.projectRoot||process.cwd()}`],{stdio:["ignore","pipe","pipe"]}):(t=n(o,[],{detached:!0,stdio:["ignore","pipe","pipe"],env:{...process.env,ZIBBY_STUDIO_PROJECT_ROOT:r.projectRoot||process.cwd()}}),t.unref()),t.stderr?.on("data",e=>{const i=e.toString().trim();i&&console.error(`[Studio Desktop] ${i}`)}),t.on("error",e=>{console.error(`Failed to open Zibby Studio: ${e.message}`)}),t.on("close",e=>{e&&e!==0&&console.error(`Zibby Studio exited with code ${e}`)})}export{g as launchStudio};
1
+ import{spawn as d,execFileSync as u}from"child_process";import c from"os";import a from"path";import{existsSync as f,mkdirSync as l,writeFileSync as m}from"fs";import{getStudioAppPath as S}from"./studio-installer.js";const s=a.join(c.homedir(),".zibby","studio-launch.json");function h(t){const o={};t.projectRoot&&(o.projectRoot=t.projectRoot),t.port&&(o.port=t.port),o.launchedAt=Date.now();const i=a.dirname(s);l(i,{recursive:!0}),m(s,JSON.stringify(o,null,2))}function w(t){if(c.platform()==="darwin")try{u("xattr",["-rd","com.apple.quarantine",t])}catch{}}function p(t,o){return new Promise(i=>{const r=d("open",["-a",t,"--env",`ZIBBY_STUDIO_PROJECT_ROOT=${o.projectRoot}`],{stdio:["ignore","pipe","pipe"]});let e="";r.stderr?.on("data",n=>{e+=n.toString()}),r.on("close",n=>i({code:n,stderr:e})),r.on("error",n=>i({code:1,stderr:n.message}))})}async function _(t={}){const o=S();if(!o)throw new Error("Studio not installed");if(!f(o))throw new Error(`Studio app not found at ${o}`);h(t);const i=t.projectRoot||process.cwd();if(c.platform()==="darwin"){let r=await p(o,{projectRoot:i});if(r.code!==0&&r.stderr.includes("Launch failed")&&(w(a.dirname(o)),r=await p(o,{projectRoot:i})),r.code!==0){const e=r.stderr.trim();e&&console.error(`[Studio Desktop] ${e}`),console.error(`Zibby Studio exited with code ${r.code}`)}}else{const r=d(o,[],{detached:!0,stdio:["ignore","pipe","pipe"],env:{...process.env,ZIBBY_STUDIO_PROJECT_ROOT:i}});r.unref(),r.stderr?.on("data",e=>{const n=e.toString().trim();n&&console.error(`[Studio Desktop] ${n}`)}),r.on("error",e=>{console.error(`Failed to open Zibby Studio: ${e.message}`)})}}export{_ as launchStudio};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zibby/cli",
3
- "version": "0.1.32",
3
+ "version": "0.1.34",
4
4
  "description": "Zibby CLI - Test automation generator and runner",
5
5
  "type": "module",
6
6
  "bin": {