@zibby/cli 0.1.33 → 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.33",
3
+ "version": "0.1.34",
4
4
  "description": "Zibby CLI - Test automation generator and runner",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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.33",
3
+ "version": "0.1.34",
4
4
  "description": "Zibby CLI - Test automation generator and runner",
5
5
  "type": "module",
6
6
  "bin": {