@zibby/cli 0.1.60 → 0.1.62
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/auth/cli-login.js +12 -12
- package/dist/bin/zibby.js +2 -2
- package/dist/commands/agent-reliability.js +4 -4
- package/dist/commands/analyze-graph.js +14 -14
- package/dist/commands/chat-session-store.js +1 -1
- package/dist/commands/chat.js +71 -62
- package/dist/commands/ci-setup.js +3 -3
- package/dist/commands/generate.js +60 -21
- package/dist/commands/implement.js +15 -15
- package/dist/commands/init.js +88 -67
- package/dist/commands/list-projects.js +9 -9
- package/dist/commands/memory.js +13 -13
- package/dist/commands/project.js +8 -8
- package/dist/commands/run-capacity-queue-cli.js +2 -2
- package/dist/commands/run.js +52 -50
- package/dist/commands/setup-scripts.js +6 -6
- package/dist/commands/studio.js +21 -15
- package/dist/commands/uninstall.js +10 -10
- package/dist/commands/upload.js +15 -15
- package/dist/commands/video.js +1 -1
- package/dist/commands/workflow.js +35 -35
- package/dist/commands/workflows/delete.js +8 -0
- package/dist/commands/workflows/deploy.js +10 -10
- package/dist/commands/workflows/generate.js +17 -17
- package/dist/commands/workflows/list.js +15 -15
- package/dist/commands/workflows/logs.js +13 -13
- package/dist/commands/workflows/run.js +7 -7
- package/dist/commands/workflows/start.js +6 -6
- package/dist/commands/workflows/trigger.js +14 -8
- package/dist/config/config-loader.js +1 -1
- package/dist/config/config.js +1 -1
- package/dist/config/environments.js +1 -1
- package/dist/package.json +2 -2
- package/dist/utils/agent-credentials.js +3 -3
- package/dist/utils/chat-run-lifecycle.js +3 -3
- package/dist/utils/execution-context.js +1 -1
- package/dist/utils/progress-reporter.js +1 -1
- package/dist/utils/studio-cli-log-mirror.js +1 -1
- package/dist/utils/studio-installer.js +5 -5
- package/dist/utils/studio-launcher.js +1 -1
- package/package.json +2 -2
package/dist/commands/studio.js
CHANGED
|
@@ -1,27 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
`)
|
|
2
|
+
var fe=Object.defineProperty;var me=(a,r)=>()=>(a&&(r=a(a=0)),r);var ge=(a,r)=>{for(var p in r)fe(a,p,{get:r[p],enumerable:!0})};var Ct={};ge(Ct,{getStudioAppPath:()=>ot,getStudioVersion:()=>Ae,installStudio:()=>Lt,isStudioInstalled:()=>et,promptAndInstallStudio:()=>ft});import U from"os";import $ from"path";import{existsSync as tt,readFileSync as he,readdirSync as ye,createWriteStream as Se,mkdirSync as be,rmSync as Ie,unlinkSync as we}from"fs";import{execFileSync as Ut}from"child_process";import{createInterface as ve}from"readline";import C from"chalk";function Bt(){let a=U.platform(),r=U.arch();if(a==="darwin"&&r==="arm64")return{archive:"Zibby Studio-mac-arm64.zip",label:"macOS (Apple Silicon)"};if(a==="darwin")return{archive:"Zibby Studio-mac-x64.zip",label:"macOS (Intel)"};if(a==="win32"&&r==="arm64")return{archive:"Zibby Studio-win-arm64.zip",label:"Windows (ARM)"};if(a==="win32")return{archive:"Zibby Studio-win-x64.zip",label:"Windows (x64)"};if(a==="linux"&&r==="arm64")return{archive:"Zibby Studio-arm64.AppImage",label:"Linux (ARM64)"};if(a==="linux")return{archive:"Zibby Studio-1.0.0.AppImage",label:"Linux (x64)"};throw new Error(`Unsupported platform: ${a} ${r}`)}function je(){let{archive:a}=Bt();return`${Pe}/download/latest/${encodeURIComponent(a)}`}function _e(a){let r=ve({input:process.stdin,output:process.stdout});return new Promise(p=>{r.question(a,S=>{r.close(),p(S.trim().toLowerCase())})})}async function ft(){let{label:a}=Bt();console.log(""),console.log(C.cyan(" Zibby Studio is not installed.")),console.log(C.gray(` Platform: ${a}`)),console.log("");let r=await _e(C.white(" Download and install Zibby Studio? (Y/n): "));return r&&r!=="y"&&r!=="yes"?(console.log(C.yellow(`
|
|
3
|
+
Skipped.
|
|
4
|
+
`)),!1):(await Lt(),!0)}async function Lt(){let a=je(),r=decodeURIComponent($.basename(a));console.log(C.cyan(`
|
|
5
|
+
\u{1F4E6} Downloading Zibby Studio...`));try{let p=await fetch(a);if(!p.ok)throw new Error(`Download failed: ${p.status} ${p.statusText}`);let S=parseInt(p.headers.get("content-length")||"0",10),w=$.join(U.tmpdir(),r),h=0,_=Se(w);for await(let E of p.body)if(h+=E.length,_.write(E),S>0){let F=(h/S*100).toFixed(1),k=(h/1024/1024).toFixed(1),Y=(S/1024/1024).toFixed(1);process.stdout.write(`\r \u{1F4E5} ${F}% (${k}MB / ${Y}MB)`)}if(await new Promise((E,F)=>{_.on("finish",E),_.on("error",F),_.end()}),console.log(""),tt(O)&&Ie(O,{recursive:!0,force:!0}),be(O,{recursive:!0}),console.log(C.cyan(" \u{1F4C2} Installing...")),w.endsWith(".zip"))if(U.platform()==="darwin"||U.platform()==="linux"){if(Ut("unzip",["-oq",w,"-d",O]),U.platform()==="darwin")try{Ut("xattr",["-cr",O])}catch{}}else{let E=(await import("adm-zip")).default;new E(w).extractAllTo(O,!0)}else if(w.endsWith(".AppImage")){let{copyFileSync:E,chmodSync:F}=await import("fs"),k=$.join(O,r);E(w,k),F(k,493)}try{we(w)}catch{}return console.log(C.green(` \u2705 Zibby Studio installed!
|
|
6
|
+
`)),!0}catch(p){throw console.log(C.red(`
|
|
7
|
+
\u274C Installation failed: ${p.message}
|
|
8
|
+
`)),p}}function et(){let a=ot();return!!(a&&tt(a))}function ot(){if(U.platform()==="darwin")return $.join(O,"Zibby Studio.app");if(U.platform()==="win32")return $.join(O,"Zibby Studio.exe");if(U.platform()==="linux"){if(!tt(O))return null;let a=ye(O).find(r=>r.endsWith(".AppImage"));return a?$.join(O,a):null}return null}function Ae(){let a=$.join(O,"version.txt");return tt(a)?he(a,"utf-8").trim():"unknown"}var Pe,O,nt=me(()=>{Pe=process.env.ZIBBY_STUDIO_CDN||"https://dl.zibby.app",O=$.join(U.homedir(),".zibby","studio")});nt();import Gt from"express";import{createServer as ke}from"http";import{WebSocketServer as Ee}from"ws";import{spawn as ht,execSync as rt}from"child_process";import{readFileSync as x,existsSync as f,readdirSync as W,statSync as Z,createReadStream as Ue,createWriteStream as Be,mkdirSync as Wt,openSync as Le,readSync as Ce,closeSync as $e,writeFileSync as st,unlinkSync as Fe}from"fs";import{join as u,resolve as B,dirname as yt,basename as ze}from"path";import{homedir as De}from"os";import{inspect as Ze}from"util";import{fileURLToPath as Ye,pathToFileURL as Mt}from"url";import Ge from"dotenv";nt();import{spawn as Dt,execFileSync as $t}from"child_process";import mt from"os";import Zt from"path";import{existsSync as Ne,mkdirSync as Te,writeFileSync as Re}from"fs";var Ft=Zt.join(mt.homedir(),".zibby","studio-launch.json");function Oe(a){let r={};a.projectRoot&&(r.projectRoot=a.projectRoot),a.port&&(r.port=a.port),r.launchedAt=Date.now();let p=Zt.dirname(Ft);Te(p,{recursive:!0}),Re(Ft,JSON.stringify(r,null,2))}function xe(a){if(mt.platform()==="darwin"){try{$t("xattr",["-cr",a])}catch{}try{$t("spctl",["--add","--label","ZibbyStudio",a])}catch{}}}function zt(a,r){return new Promise(p=>{let S=Dt("open",["-a",a,"--env",`ZIBBY_STUDIO_PROJECT_ROOT=${r.projectRoot}`],{stdio:["ignore","pipe","pipe"]}),w="";S.stderr?.on("data",h=>{w+=h.toString()}),S.on("close",h=>p({code:h,stderr:w})),S.on("error",h=>p({code:1,stderr:h.message}))})}async function Yt(a={}){let r=ot();if(!r)throw new Error("Studio not installed");if(!Ne(r))throw new Error(`Studio app not found at ${r}`);Oe(a);let p=a.projectRoot||process.cwd();if(mt.platform()==="darwin"){let S=await zt(r,{projectRoot:p});if(S.code!==0&&S.stderr.includes("Launch failed")&&(xe(r),S=await zt(r,{projectRoot:p})),S.code!==0){let w=S.stderr.trim();w&&console.error(`[Studio Desktop] ${w}`),console.error(`Zibby Studio exited with code ${S.code}`)}}else{let S=Dt(r,[],{detached:!0,stdio:["ignore","pipe","pipe"],env:{...process.env,ZIBBY_STUDIO_PROJECT_ROOT:p}});S.unref(),S.stderr?.on("data",w=>{let h=w.toString().trim();h&&console.error(`[Studio Desktop] ${h}`)}),S.on("error",w=>{console.error(`Failed to open Zibby Studio: ${w.message}`)})}}import{mergeSessionRunState as K,listRunningSessionStatesFromSessionsRoot as We}from"@zibby/core/utils/run-state-session.js";import{liveRunsFromSessionStateRows as Me}from"@zibby/core/utils/session-state-live-runs.js";import{findLatestLiveFrameFileSync as Jt,readLatestLiveFramePayloadSync as Kt}from"@zibby/core/utils/live-frame-discovery.js";var J={local:{name:"Local Development",apiUrl:"http://localhost:3001",accountApiUrl:"http://localhost:3001",frontendUrl:"http://localhost:3000",description:"Local backend running on port 3001"},prod:{name:"Production",apiUrl:process.env.ZIBBY_PROD_API_URL||"https://api-prod.zibby.app",accountApiUrl:process.env.ZIBBY_PROD_ACCOUNT_API_URL||"https://account-api-prod.zibby.app",frontendUrl:process.env.ZIBBY_PROD_FRONTEND_URL||"https://studio.zibby.app",description:"Production environment"}};function gt(){let a;if(process.env.ZIBBY_API_URL)a=process.env.ZIBBY_API_URL;else{let r=process.env.ZIBBY_ENV||"prod";J[r]?a=J[r].apiUrl:a=J.prod.apiUrl}try{let r=new URL(a);return r.protocol!=="http:"&&r.protocol!=="https:"?(console.error(`\u26A0\uFE0F Invalid API URL protocol: ${r.protocol} (only http/https allowed)`),J.prod.apiUrl):a}catch{return console.error(`\u26A0\uFE0F Invalid API URL: ${a}`),J.prod.apiUrl}}var Je=Ye(import.meta.url),Ke=yt(Je);function Ht(a){let r=u(a,"video.webm");if(f(r))return r;let p=u(a,"execute_live");if(!f(p))return null;try{let S=W(p).filter(h=>h.endsWith(".webm"));return S.length===0?null:S.map(h=>{let _=u(p,h);try{return{p:_,mtime:Z(_).mtimeMs}}catch{return{p:_,mtime:0}}}).sort((h,_)=>_.mtime-h.mtime)[0].p}catch{return null}}function Vt(a){if(process.platform==="win32")try{let r=rt("netstat -ano",{encoding:"utf8"}),p=new Set;for(let S of r.split(`
|
|
9
|
+
`)){if(!S.includes("LISTENING"))continue;let w=S.trim().split(/\s+/);if(!(w[1]||"").endsWith(`:${a}`))continue;let _=w[w.length-1];/^\d+$/.test(_)&&p.add(parseInt(_,10))}return[...p].filter(S=>S!==process.pid)}catch{return[]}try{let r=rt(`lsof -tiTCP:${a} -sTCP:LISTEN`,{encoding:"utf8"}).trim();return[...new Set(r.split(`
|
|
10
|
+
`).filter(Boolean))].map(p=>parseInt(p,10)).filter(p=>!Number.isNaN(p)&&p!==process.pid)}catch{return[]}}async function qt(a){let r=Vt(a);if(r.length!==0){console.log(`[Studio] Port ${a} in use \u2014 stopping previous Studio listener(s): ${r.join(", ")}`);for(let p of r)try{process.kill(p,"SIGTERM")}catch{}await new Promise(p=>setTimeout(p,450)),r=Vt(a);for(let p of r)try{process.kill(p,"SIGKILL")}catch{}await new Promise(p=>setTimeout(p,200))}}async function No(a={}){let r=Gt(),p=ke(r),S=new Ee({server:p}),w=a.port||3847,h=process.cwd(),_=De();process.env.DOTENV_CONFIG_QUIET="true";let E=process.env.NODE_ENV||"development";[B(h,".env.local"),B(h,`.env.${E}`),B(h,".env")].forEach(o=>{f(o)&&Ge.config({path:o,override:!1})});let k=new Map,Y=new Map,Qt=null,H=96e3,St="studio-cli.log",V="studio-run.json",Xt=".zibby-studio-stop",it=512*1024;r.use(Gt.json()),r.get("/api/session-run-states",(o,t)=>{try{let e=L();try{let i=new URL(o.url,"http://zibby.studio").searchParams.get("sessionsRoot");if(i&&String(i).trim()){let l=B(decodeURIComponent(String(i).trim()));f(l)&&Z(l).isDirectory()&&(e=l)}}catch{}let s=We(e),{liveIdList:n,progressByKey:c}=Me(s);t.json({rows:s,liveIdList:n,progressByKey:c,sessionsRoot:e,unavailable:!1})}catch(e){t.status(500).json({error:e.message,rows:[],liveIdList:[],progressByKey:{},unavailable:!0})}}),r.get("/api/workflow/graph",async(o,t)=>{try{let e=null,s=u(h,".zibby","graph.mjs");if(f(s))try{let n=await import(Mt(s).href),c=n.BrowserTestAutomationAgent||n.default;if(c&&typeof c=="function"){let i=new c().buildGraph();i&&typeof i.serialize=="function"&&(e=i.serialize())}}catch{}if(!e)try{let{createRequire:n}=await import("module"),c=n(import.meta.url),d=u(yt(c.resolve("@zibby/core/package.json")),"templates","browser-test-automation","run_test.json");f(d)&&(e=JSON.parse(x(d,"utf-8")))}catch{}t.json({graph:e})}catch{t.json({graph:null})}}),r.use((o,t,e)=>(t.header("Access-Control-Allow-Origin","*"),t.header("Access-Control-Allow-Methods","GET, POST, PUT, DELETE"),t.header("Access-Control-Allow-Headers","Content-Type"),e()));let ct=u(Ke,"../../../../studio"),bt=f(u(ct,"package.json"));function te(){let o=u(ct,"node_modules",".bin",process.platform==="win32"?"electron.cmd":"electron"),t=f(o),n=ht(t?o:"npx",t?["."]:["electron","."],{cwd:ct,detached:!0,stdio:"ignore",shell:!1,env:{...process.env,ZIBBY_STUDIO_PROJECT_ROOT:h,ZIBBY_STUDIO_API_BASE:`http://localhost:${w}/api`}});n.unref(),Qt=n}async function ee(){if(bt){te();return}if(a.update||!et()){if(a.update&&et()){console.log(`
|
|
5
11
|
Updating Zibby Studio...
|
|
6
|
-
`);
|
|
12
|
+
`);let{installStudio:o}=await Promise.resolve().then(()=>(nt(),Ct));await o()}else if(!await ft()){p.close(),process.exit(0);return}}console.log(`
|
|
7
13
|
\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
|
|
8
14
|
\u2551 Zibby Studio \u2551
|
|
9
15
|
\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
|
|
10
|
-
`),await
|
|
11
|
-
`,"utf8")}catch{}return t.json({projects:
|
|
12
|
-
`,"utf8")}catch{}}return t.json(
|
|
13
|
-
${j.stdout.slice(-
|
|
14
|
-
${j.stderr.slice(-
|
|
15
|
-
${
|
|
16
|
+
`),await Yt({projectRoot:h}),setTimeout(()=>{p.close(),process.exit(0)},1e3)}function It(){let o=u(h,".zibby.config.mjs");return f(o)?o:u(_,".zibby.config.mjs")}function L(){It();let o=u(h,".zibby","output","sessions");return f(o)?o:u(_,".zibby","output","sessions")}function at(o,t){let e=null,s=null,n=null,c=u(o,"codegen");if(f(c)){let i=u(c,"test.spec.ts"),l=u(c,"generated-test.spec.js");e=f(i)?i:f(l)?l:null;let g=u(c,"test.selenium.py"),I=u(c,"generated-test-selenium.js");s=f(g)?g:f(I)?I:null;let m=u(c,"trace.zip");n=f(m)?m:null}let d=u(o,"generate_script","result.json");if(!e&&f(d))try{let l=JSON.parse(x(d,"utf8"))?.scriptPath;if(typeof l=="string"&&l.trim()){let g=l.trim(),I=g.startsWith("/")||process.platform==="win32"&&/^[A-Za-z]:[\\/]/.test(g)?g:u(t,g);f(I)&&(e=I)}}catch(i){console.warn("[Studio API] generate_script result.json:",i.message)}return!e&&!s&&!n?null:{playwrightFile:e,seleniumFile:s,tracePath:n}}function oe(o,t,e){try{st(u(o,V),JSON.stringify({sessionId:t,pid:e??null,startedAt:Date.now()},null,2),"utf8")}catch(s){console.error("[Studio API] writeStudioRunMeta:",s.message)}}function M(o){try{let t=u(o,V);f(t)&&Fe(t)}catch{}}function ne(o){let t=Number(o);if(!Number.isFinite(t)||t<=0)return[];try{let e=rt(`pgrep -P ${t}`,{encoding:"utf8",stdio:["ignore","pipe","ignore"],maxBuffer:524288}).trim();return e?e.split(/\n/).map(s=>parseInt(s.trim(),10)).filter(s=>Number.isFinite(s)&&s>0):[]}catch{return[]}}function q(o,t){let e=Number(o);if(!Number.isFinite(e)||e<=0)return;let s=new Set;function n(c){if(!s.has(c)){s.add(c);for(let d of ne(c))n(d);try{process.kill(c,t)}catch{}}}n(e)}function wt(o){let t=Number(o);if(!(!Number.isFinite(t)||t<=0))try{rt(`taskkill /PID ${t} /T /F`,{stdio:"ignore",windowsHide:!0})}catch{}}function vt(o){if(!Number.isFinite(o)||o<=0)return;if(process.platform==="win32"){wt(o);return}q(o,"SIGTERM");let t=setTimeout(()=>{q(o,"SIGKILL")},800);typeof t.unref=="function"&&t.unref()}function se(o,t){let s=z(o)||u(L(),o);try{Wt(s,{recursive:!0}),st(u(s,Xt),JSON.stringify({requestedAt:Date.now()}),"utf8")}catch(i){console.error("[Studio API] write studio stop request:",i.message)}let n=k.get(o);if(n){let i=n.pid;if(process.platform==="win32")wt(i);else{q(i,"SIGTERM");let l=setTimeout(()=>{q(i,"SIGKILL")},800);typeof l.unref=="function"&&l.unref()}return k.delete(o),M(s),!0}let c=u(s,V);if(f(c)){let i=null;try{let l=JSON.parse(x(c,"utf8"));i=Number(l.pid)}catch(l){console.error("[Studio API] studio-run.json read:",l.message)}if(M(s),Number.isFinite(i)&&i>0)return vt(i),!0}let d=Number(t);return Number.isFinite(d)&&d>0?(vt(d),M(s),!0):!1}function Q(o){try{let t=o?.query?.sessionsRoot;if(typeof t!="string")return"";let e=t.trim();if(!e)return"";let s=decodeURIComponent(e),n=B(s);return f(n)?n:""}catch{return""}}function z(o,t=""){let e=typeof o=="string"?decodeURIComponent(o).trim():String(o||"").trim();if(!e)return null;let s=[e],n=e.split("_")[0]?.trim()||"";n&&n!==e&&s.push(n);let c=new Set,d=[],i=new Set,l=[],g=b=>{if(!b)return;let y=B(b);i.has(y)||(i.add(y),l.push(y))},I=b=>{if(b){g(b);for(let y of s){let v=u(b,y);c.has(v)||(c.add(v),d.push(v))}}};I(t),I(L()),I(u(_,".zibby","output","sessions"));let m;try{m=W(h)}catch{m=[]}for(let b of m){if(b.startsWith("."))continue;let y=u(h,b);try{if(!Z(y).isDirectory())continue}catch{continue}I(u(y,".zibby","output","sessions"));let v;try{v=W(y,{withFileTypes:!0})}catch{v=[]}for(let T of v)T?.isDirectory?.()&&String(T.name||"").startsWith(".zibby")&&I(u(y,T.name,"output","sessions"))}let N=d.filter(b=>f(b));if(N.length===0)for(let b of l){if(!f(b))continue;let y;try{y=W(b,{withFileTypes:!0})}catch{y=[]}for(let v of y){if(!v?.isDirectory?.())continue;let T=String(v.name||"");if(T===e||T===n||T.startsWith(`${e}_`)||n&&T.startsWith(`${n}_`)){let D=u(b,T);if(c.has(D))continue;c.add(D),N.push(D)}}}if(N.length===0)return null;if(N.length===1)return N[0];let G=b=>{let y=0;f(u(b,"execute_live"))&&(y+=20),Jt(b)&&(y+=15),f(u(b,"execute_live","events.json"))&&(y+=8),f(u(b,"execute_live","result.json"))&&(y+=6),f(u(b,V))&&(y+=4),f(u(b,".session-info.json"))&&(y+=2);try{let v=u(b,"execute_live");f(v)&&(y+=Math.min(Z(v).mtimeMs/1e12,3))}catch{}return y};return N.sort((b,y)=>G(y)-G(b)),N[0]}function re(o,t){try{let e=typeof o=="string"?decodeURIComponent(o).trim():String(o||"").trim();if(!e||!t)return null;let s=(e.split("_")[0]||"").trim(),n=yt(t);if(!s||!n||!f(n))return null;let c=[];try{c=W(n,{withFileTypes:!0})}catch{c=[]}let d=null;for(let i of c){if(!i?.isDirectory?.())continue;let l=String(i.name||"");if(!(l===e||l===s||l.startsWith(`${e}_`)||l.startsWith(`${s}_`)))continue;let g=u(n,l),I=Kt(g);I&&(!d||Number(I.mtime||0)>Number(d.mtime||0))&&(d=I)}return d}catch{return null}}r.get("/api/config/check",(o,t)=>{let e=It();t.json({exists:f(e),path:e,isProjectLevel:e.startsWith(h)})}),r.get("/api/projects",(o,t)=>{try{let e=u(_,".zibby","config.json");if(!f(e))return t.json({projects:[]});let s=JSON.parse(x(e,"utf8")),n=typeof s.sessionToken=="string"&&s.sessionToken.trim()!==""?s.sessionToken.trim():"",c=Array.isArray(s.projects)?s.projects:[];if(!n)return t.json({projects:c});let d=String(gt()).replace(/\/$/,"");fetch(`${d}/projects`,{headers:{Authorization:`Bearer ${n}`}}).then(i=>i.json().catch(()=>({})).then(l=>({ok:i.ok,status:i.status,body:l}))).then(({ok:i,body:l})=>{if(!i)return t.json({projects:c});let I=(Array.isArray(l?.projects)?l.projects:[]).map(m=>({name:m?.name,projectId:m?.projectId,apiToken:m?.apiToken||null,createdAt:m?.createdAt||null,updatedAt:m?.updatedAt||null}));s.projects=I;try{st(e,`${JSON.stringify(s,null,2)}
|
|
17
|
+
`,"utf8")}catch{}return t.json({projects:I})}).catch(()=>t.json({projects:c}))}catch(e){t.status(500).json({error:e.message})}}),r.post("/api/projects/create",async(o,t)=>{try{let e=typeof o.body?.name=="string"?o.body.name.trim():"";if(!e)return t.status(400).json({error:"Project name is required"});let s=u(_,".zibby","config.json");if(!f(s))return t.status(401).json({error:"Not logged in"});let n=JSON.parse(x(s,"utf8")),c=typeof n.sessionToken=="string"&&n.sessionToken.trim()!==""?n.sessionToken.trim():"";if(!c)return t.status(401).json({error:"Not logged in"});let d=String(gt()).replace(/\/$/,""),i=await fetch(`${d}/projects`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${c}`},body:JSON.stringify({name:e})}),l=await i.json().catch(()=>({}));if(!i.ok)return t.status(i.status).json({error:l.error||l.message||`HTTP ${i.status}`});let g=l?.project&&typeof l.project=="object"?l.project:null;if(g?.projectId){let m=(Array.isArray(n.projects)?n.projects:[]).filter(N=>String(N?.projectId||"")!==String(g.projectId));m.push({name:g.name||e,projectId:g.projectId,apiToken:g.apiToken||l?.apiToken||null,createdAt:g.createdAt||null,updatedAt:g.updatedAt||null}),n.projects=m;try{st(s,`${JSON.stringify(n,null,2)}
|
|
18
|
+
`,"utf8")}catch{}}return t.json(l)}catch(e){return t.status(500).json({error:e.message||String(e)})}});function ie(o,t){let e=Array.isArray(t)?t.filter(g=>typeof g=="string"):[],s=process.argv[1]?B(process.argv[1]):"",n=s?ze(s):"",c;try{c=!!s&&f(s)&&Z(s).isFile()&&!/\.(cmd|ps1|bat)$/i.test(s)&&(/\.(m|c)?js$/i.test(s)||n==="zibby")}catch{c=!1}if(c){let g=[s,"test",o,...e],I=[process.execPath,...g].map(m=>/\s/.test(String(m))?`"${String(m).replace(/"/g,'\\"')}"`:m).join(" ");return{useShell:!1,cmd:process.execPath,args:g,display:I}}let d=o.replace(/"/g,'\\"'),i=e.join(" "),l=`zibby test "${d}" ${i}`.trim();return{useShell:!0,cmd:l,args:[],display:l}}r.get("/api/run/result/:sessionId",(o,t)=>{let{sessionId:e}=o.params,s=Y.get(e);if(!s)return t.status(404).json({pending:!0,error:"unknown_session"});t.json(s)}),r.post("/api/run",async(o,t)=>{let{task:e,args:s=[],sessionId:n,studioTestCaseId:c}=o.body;if(!e||!n)return t.status(400).json({success:!1,error:"task and sessionId are required"});let d=L(),i=u(d,n),l=B(i),g=c!=null&&String(c).trim()!==""?String(c).trim():String(n);Y.set(n,{pending:!0});let I=!1,m=null,N=()=>{if(m&&!m.destroyed)try{m.end()}catch{}m=null},G=(y,v)=>{Y.delete(n),N(),I||t.status(y).json(v)},b=()=>{let y=[];return S.clients.forEach(v=>{v.sessionId===n&&y.push(v)}),y};try{let y=ie(e,s);console.log("[Studio API] Running:",y.display),y.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]),Wt(i,{recursive:!0}),m=Be(u(i,St),{flags:"w"}),K(l,{sessionId:String(n),studioTestCaseId:g,status:"running",runSource:"studio",activeStageIndex:0,activeNode:"preflight",cwd:h,outputBase:".zibby/output",sessionPathAbs:l});let v=ht(y.cmd,y.args,{cwd:h,shell:y.useShell,env:{...process.env,ZIBBY_SESSION_ID:n,ZIBBY_SESSION_PATH:B(i)}});k.set(n,v),oe(i,n,v.pid),K(l,{sessionId:String(n),studioTestCaseId:g,status:"running",runSource:"studio",activeStageIndex:0,activeNode:"preflight",cwd:h,outputBase:".zibby/output",sessionPathAbs:l,pid:v.pid??null});let T="",D="",At=!1,Nt=0,Tt=setInterval(()=>{try{let P=Jt(i);if(!P||P.mtime<=Nt)return;Nt=P.mtime;let j=x(P.p).toString("base64"),A=P.p.toLowerCase().endsWith(".png")?"image/png":"image/jpeg";b().forEach(X=>{try{X.send(JSON.stringify({type:"video-frame",sessionId:n,frame:j,mime:A}))}catch{}})}catch{}},320),Rt=P=>{if(At)return;At=!0,N();let j={pending:!1,...P};typeof j.stdout=="string"&&j.stdout.length>H&&(j.stdout=`\u2026(truncated)
|
|
19
|
+
${j.stdout.slice(-H)}`),typeof j.stderr=="string"&&j.stderr.length>H&&(j.stderr=`\u2026(truncated)
|
|
20
|
+
${j.stderr.slice(-H)}`),Y.set(n,j),b().forEach(A=>{try{A.send(JSON.stringify({type:"run-complete",sessionId:n,result:P}))}catch{}})};v.stdout.on("data",P=>{let j=P.toString();if(T+=j,m&&!m.destroyed)try{m.write(j)}catch(A){console.error("[Studio API] studio-cli.log write failed:",A.message)}b().forEach(A=>{try{A.send(JSON.stringify({type:"stdout",data:j}))}catch{}})}),v.stderr.on("data",P=>{let j=P.toString();if(D+=j,m&&!m.destroyed)try{m.write(`[stderr] ${j}`)}catch(A){console.error("[Studio API] studio-cli.log write failed:",A.message)}b().forEach(A=>{try{A.send(JSON.stringify({type:"stderr",data:j}))}catch{}})}),v.on("error",P=>{clearInterval(Tt),k.delete(n),K(l,{sessionId:String(n),studioTestCaseId:g,status:"failed",runSource:"studio",activeNode:null,activeStageIndex:null,errorMessage:P.message,cwd:h,outputBase:".zibby/output",sessionPathAbs:l}),console.error("[Studio API] Spawn error:",P.message),Rt({heldUntilExit:!0,success:!1,exitCode:null,error:P.message,stderr:D,stdout:T,runName:null,videoPath:null,eventsPath:null,codegenFiles:null,metadata:{sessionId:n,task:e}})}),v.on("close",P=>{clearInterval(Tt),k.delete(n),K(l,{sessionId:String(n),studioTestCaseId:g,status:P===0?"completed":P===130||P===143?"interrupted":"failed",runSource:"studio",activeNode:null,activeStageIndex:null,exitCode:P,cwd:h,outputBase:".zibby/output",sessionPathAbs:l}),M(i),b().forEach(R=>{try{R.send(JSON.stringify({type:"exit",code:P}))}catch{}});let j=P===0,A=null,X=u(i,".session-info.json"),Ot=u(i,"result.json");if(f(X))try{let R=JSON.parse(x(X,"utf8"));A=R.name||R.task}catch(R){console.error("[Studio API] Failed to read session info:",R.message)}else if(f(Ot))try{let R=JSON.parse(x(Ot,"utf8"));A=R.name||R.task}catch(R){console.error("[Studio API] Failed to read result:",R.message)}let de=[/\[SessionRecorder\] Run name set: (.+)/,/Run name: (.+)/];if(!A)for(let R of de){let Et=T.match(R);if(Et){A=Et[1].trim();break}}let pe=at(i,h),dt=Ht(i),xt=u(i,"events.json"),kt=u(i,"execute_live","events.json"),pt=f(xt)?xt:f(kt)?kt:null;Rt({heldUntilExit:!0,success:j,exitCode:P,stdout:T,stderr:D,runName:A,videoPath:dt&&f(dt)?dt:null,eventsPath:pt&&f(pt)?pt:null,codegenFiles:pe,metadata:{sessionId:n,task:e}})}),I=!0,t.status(202).json({accepted:!0,sessionId:n,pid:v.pid!=null&&Number.isFinite(Number(v.pid))?Number(v.pid):null,pollPath:`/api/run/result/${n}`,message:"Run started. Poll GET /api/run/result/:sessionId until pending is false."})}catch(y){G(500,{success:!1,error:y.message})}}),r.post("/api/stop/:sessionId",(o,t)=>{let{sessionId:e}=o.params,s=o.body&&o.body.pid!=null?o.body.pid:null;if(se(e,s))return t.json({success:!0});t.status(404).json({success:!1,error:"Session not found"})}),r.get("/api/recordings",(o,t)=>{try{let e=L();if(!f(e))return t.json({recordings:[],path:e});let n=W(e).map(c=>{let d=u(e,c),i=u(d,".session-info.json"),l=u(d,"result.json"),g={};return f(i)?g=JSON.parse(x(i,"utf8")):f(l)&&(g=JSON.parse(x(l,"utf8"))),{sessionId:c,...g,path:d}});t.json({path:e,recordings:n})}catch(e){t.status(500).json({error:e.message})}}),r.get("/api/sessions/:sessionId/cli-log",(o,t)=>{try{let{sessionId:e}=o.params,s=parseInt(String(o.query.offset||"0"),10);(Number.isNaN(s)||s<0)&&(s=0);let n=Q(o),c=z(e,n),d=u(c||u(L(),e),St);if(!f(d))return t.json({exists:!1,content:"",size:0,fromByte:0,nextOffset:0});let i=Z(d).size;s>i&&(s=i);let l=s,g=i-l;g>it&&(l=i-it,g=it);let I=Buffer.alloc(g),m=Le(d,"r");try{Ce(m,I,0,g,l)}finally{$e(m)}t.json({exists:!0,content:I.toString("utf8"),size:i,fromByte:l,nextOffset:i})}catch(e){t.status(500).json({error:e.message})}}),r.get("/api/sessions/:sessionId/events",(o,t)=>{try{let{sessionId:e}=o.params,s=Q(o),n=z(e,s);if(!n)return t.json({events:[]});let c=u(n,"events.json");if(!f(c)){let i=u(n,"execute_live","events.json");if(f(i))c=i;else return t.json({events:[]})}let d=JSON.parse(x(c,"utf8"));t.json({events:d})}catch(e){t.status(500).json({error:e.message})}}),r.get("/api/sessions/:sessionId/live-preview",(o,t)=>{try{let{sessionId:e}=o.params,s=Q(o),n=z(e,s);if(!n)return t.json({ok:!1,error:"session_not_found"});let d=Kt(n)||re(e,n);if(!d)return t.json({ok:!1,error:"no_frame",sessionId:e,sessionPath:n});t.json({ok:!0,frame:d.base64,mime:d.mime,mtime:d.mtime,path:d.path})}catch(e){t.status(500).json({ok:!1,error:e.message})}}),r.get("/api/sessions/:sessionId/video",(o,t)=>{try{let{sessionId:e}=o.params,s=Q(o),n=z(e,s);if(!n)return t.status(404).json({error:"Session not found"});let c=Ht(n);if(!c||!f(c))return t.status(404).json({error:"Video not found"});let d=Z(c);t.writeHead(200,{"Content-Type":"video/webm","Content-Length":d.size}),Ue(c).pipe(t)}catch(e){t.status(500).json({error:e.message})}}),r.get("/api/sessions/:sessionId/codegen/playwright",(o,t)=>{try{let{sessionId:e}=o.params,s=z(e)||u(L(),e);if(!f(s))return t.status(404).type("text/plain").send("Session not found");let n=at(s,h);if(!n?.playwrightFile||!f(n.playwrightFile))return t.status(404).type("text/plain").send("No Playwright artifact");t.type("text/plain; charset=utf-8").send(x(n.playwrightFile,"utf8"))}catch(e){t.status(500).type("text/plain").send(e.message)}}),r.get("/api/sessions/:sessionId/codegen/selenium",(o,t)=>{try{let{sessionId:e}=o.params,s=z(e)||u(L(),e);if(!f(s))return t.status(404).type("text/plain").send("Session not found");let n=at(s,h);if(!n?.seleniumFile||!f(n.seleniumFile))return t.status(404).type("text/plain").send("No Selenium artifact");t.type("text/plain; charset=utf-8").send(x(n.seleniumFile,"utf8"))}catch(e){t.status(500).type("text/plain").send(e.message)}}),r.post("/api/init",async(o,t)=>{let{agentType:e,apiKey:s}=o.body;try{let n=`zibby init --agent ${e} --headed`,c=ht(n,[],{cwd:h,env:{...process.env,CURSOR_API_KEY:e==="cursor"?s:process.env.CURSOR_API_KEY,ANTHROPIC_API_KEY:e==="claude"?s:process.env.ANTHROPIC_API_KEY,OPENAI_API_KEY:e==="codex"?s:process.env.OPENAI_API_KEY,GEMINI_API_KEY:e==="gemini"?s:process.env.GEMINI_API_KEY,GOOGLE_API_KEY:e==="gemini"?s:process.env.GOOGLE_API_KEY,CI:"true",ZIBBY_CI:"true"},shell:!0}),d="",i="";c.stdout.on("data",m=>{d+=m.toString()}),c.stderr.on("data",m=>{i+=m.toString()});let l=!1,g=(m,N)=>{if(!l)if(l=!0,m===0)t.json({success:!0,stdout:d});else{let G=N||i||"zibby init failed";t.status(500).json({success:!1,error:G,stdout:d})}},I=setTimeout(()=>{try{c.kill()}catch{}g(1,`zibby init timed out after 3 minutes. stdout so far:
|
|
21
|
+
${d}
|
|
16
22
|
stderr:
|
|
17
|
-
${
|
|
23
|
+
${i}`)},18e4);c.on("close",m=>{clearTimeout(I),g(m)}),c.on("error",m=>{clearTimeout(I),g(1,m.message)})}catch(n){t.status(500).json({success:!1,error:n.message})}});let lt=(o,t)=>{let e={type:o,message:t,time:new Date().toLocaleTimeString()};S.clients.forEach(s=>{if(s.listenType==="console")try{s.send(JSON.stringify(e))}catch{}})},ce=console.log,ae=console.error,le=console.warn,ut=o=>o.map(t=>{if(t==null)return String(t);if(typeof t=="object")try{return Ze(t,{depth:4,colors:!1,breakLength:100})}catch{return String(t)}return String(t)}).join(" ");console.log=(...o)=>{ce(...o),lt("info",ut(o))},console.error=(...o)=>{ae(...o),lt("error",ut(o))},console.warn=(...o)=>{le(...o),lt("warn",ut(o))},S.on("connection",(o,t)=>{let e=t.url;if(e.includes("/console"))o.listenType="console",console.log("[WebSocket] Console listener connected"),o.send(JSON.stringify({type:"success",message:"\u{1F3AD} Connected to Studio server logs",time:new Date().toLocaleTimeString()}));else{let s=e.split("/").pop()||"";try{s=decodeURIComponent(s)}catch{}o.sessionId=s,o.listenType="session",console.log(`[WebSocket] Session listener connected: ${s}`)}o.on("close",()=>{o.listenType==="console"?console.log("[WebSocket] Console listener disconnected"):console.log(`[WebSocket] Session listener disconnected: ${o.sessionId}`)})}),r.get("/api/workflow/graph",async(o,t)=>{try{let e=u(h,".zibby","graph.mjs");if(!f(e))return console.warn("[Workflow Graph API] Graph file not found at",e),t.json({graph:null,error:"No graph.mjs found in .zibby folder"});let s=await import(`${Mt(e).href}?t=${Date.now()}`),n=s.default||Object.values(s)[0];if(!n||typeof n!="function")return console.error("[Workflow Graph API] Invalid graph module, got:",typeof n),t.json({graph:null,error:"Invalid graph module"});let d=new n().buildGraph(),i=d.toJSON?d.toJSON():d.serialize();console.log(`[Workflow Graph API] graph OK nodes=${i.nodes?.length??0} edges=${i.edges?.length??0} (${e})`),t.json({graph:i})}catch(e){console.error("[Workflow Graph API] Failed to load workflow graph:",e),t.status(500).json({graph:null,error:e.message})}});let ue=()=>{bt&&console.log(`
|
|
18
24
|
\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
|
|
19
25
|
\u2551 Zibby Studio \u2551
|
|
20
26
|
\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
|
|
21
27
|
|
|
22
|
-
API: http://localhost:${
|
|
23
|
-
Project: ${
|
|
28
|
+
API: http://localhost:${w}/api
|
|
29
|
+
Project: ${h}
|
|
24
30
|
|
|
25
31
|
Press Ctrl+C to stop
|
|
26
|
-
`),
|
|
27
|
-
Stopping Studio...`);
|
|
32
|
+
`),a.open!==!1&&ee().catch(o=>{console.error(`Failed to launch Zibby Studio: ${o.message}`)})},Pt=!1;function jt(){let o=async t=>{if(p.removeListener("error",o),t.code==="EADDRINUSE"&&!Pt){Pt=!0,console.log(`[Studio] Port ${w} still busy \u2014 forcing cleanup and retrying...`),await qt(w),jt();return}console.error("[Studio] Server error:",t.message),process.exit(1)};p.once("error",o),p.listen(w,()=>{p.removeListener("error",o),p.on("error",t=>{console.error("[Studio] Runtime error:",t.message)}),ue()})}await qt(w),jt();let _t=()=>{console.log(`
|
|
33
|
+
Stopping Studio...`);let o=L();for(let t of k.keys()){let e=B(u(o,t));try{K(e,{status:"interrupted",runSource:"studio",activeNode:null,activeStageIndex:null,exitReason:"studio-shutdown"})}catch{}try{M(u(o,t))}catch{}}k.forEach(t=>t.kill()),p.close(()=>{console.log("Studio stopped"),process.exit(0)})};process.on("SIGINT",_t),process.on("SIGTERM",_t)}export{No as studioCommand};
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import{spawnSync as C}from"child_process";import{existsSync as i,readFileSync as z,writeFileSync as S,readdirSync as m,cpSync as R,rmSync as p,mkdirSync as x}from"fs";import{join as r}from"path";import{homedir as f}from"os";import o from"chalk";
|
|
1
|
+
import{spawnSync as C}from"child_process";import{existsSync as i,readFileSync as z,writeFileSync as S,readdirSync as m,cpSync as R,rmSync as p,mkdirSync as x}from"fs";import{join as r}from"path";import{homedir as f}from"os";import o from"chalk";var h=r(f(),".zibby-cleanup-backups",new Date().toISOString().replace(/[:.]/g,"-").slice(0,19));function u(s){x(h,{recursive:!0});try{R(s,r(h,s.replace(/\//g,"_")),{recursive:!0})}catch{}}function j(s,l){i(s)&&(u(s),p(s,{recursive:!0,force:!0}),console.log(o.gray(` \u2713 Removed ${l||s}`)))}async function A(s={}){let l=s.dryRun||!1,y=process.cwd();if(console.log(o.cyan(`
|
|
2
2
|
\u{1F9F9} Zibby Uninstall
|
|
3
3
|
`)),l&&console.log(o.yellow(` (dry-run mode \u2014 nothing will be deleted)
|
|
4
|
-
`)),console.log(o.white("Global CLI:")),l)console.log(o.gray(" [dry-run] npm uninstall -g @zibby/cli"));else try{C("npm",["uninstall","-g","@zibby/cli"],{stdio:"pipe",timeout:3e4}),console.log(o.gray(" \u2713 npm uninstall -g @zibby/cli"))}catch{console.log(o.yellow(" \u26A0 Could not uninstall global CLI"))}
|
|
5
|
-
Global config (~/.zibby):`)),i(b)?l?console.log(o.gray(` [dry-run] rm -rf ${b}`)):j(b,"~/.zibby"):console.log(o.gray(" (not found)"));
|
|
6
|
-
Cursor MCP config:`)),i(g))try{
|
|
7
|
-
`),console.log(o.gray(" \u2713 Removed playwright-official from ~/.cursor/mcp.json"))):console.log(o.gray(" (no playwright-official entry)"))}catch{console.log(o.yellow(" \u26A0 Could not parse ~/.cursor/mcp.json"))}else console.log(o.gray(" (not found)"));
|
|
8
|
-
Cursor MCP approvals:`)),i(d)){let n=0;for(
|
|
9
|
-
Zibby Studio:`));let v=!1;for(
|
|
10
|
-
Current project (${y}):`));
|
|
11
|
-
`),console.log(o.gray(" \u2713 Stripped @zibby/* from package.json"))))}catch{}}if(s.deep){
|
|
12
|
-
npx cache (--deep):`)),i(n)){let t=0;for(
|
|
4
|
+
`)),console.log(o.white("Global CLI:")),l)console.log(o.gray(" [dry-run] npm uninstall -g @zibby/cli"));else try{C("npm",["uninstall","-g","@zibby/cli"],{stdio:"pipe",timeout:3e4}),console.log(o.gray(" \u2713 npm uninstall -g @zibby/cli"))}catch{console.log(o.yellow(" \u26A0 Could not uninstall global CLI"))}let b=r(f(),".zibby");console.log(o.white(`
|
|
5
|
+
Global config (~/.zibby):`)),i(b)?l?console.log(o.gray(` [dry-run] rm -rf ${b}`)):j(b,"~/.zibby"):console.log(o.gray(" (not found)"));let g=r(f(),".cursor","mcp.json");if(console.log(o.white(`
|
|
6
|
+
Cursor MCP config:`)),i(g))try{let n=JSON.parse(z(g,"utf-8"));n.mcpServers?.["playwright-official"]?l?console.log(o.gray(" [dry-run] Remove playwright-official from ~/.cursor/mcp.json")):(u(g),delete n.mcpServers["playwright-official"],S(g,`${JSON.stringify(n,null,2)}
|
|
7
|
+
`),console.log(o.gray(" \u2713 Removed playwright-official from ~/.cursor/mcp.json"))):console.log(o.gray(" (no playwright-official entry)"))}catch{console.log(o.yellow(" \u26A0 Could not parse ~/.cursor/mcp.json"))}else console.log(o.gray(" (not found)"));let d=r(f(),".cursor","projects");if(console.log(o.white(`
|
|
8
|
+
Cursor MCP approvals:`)),i(d)){let n=0;for(let t of m(d)){let e=r(d,t,"mcp-approvals.json");i(e)&&(l?console.log(o.gray(` [dry-run] rm ${e}`)):j(e,`${t}/mcp-approvals.json`),n++)}n===0&&console.log(o.gray(" (none found)"))}else console.log(o.gray(" (not found)"));let k="/Applications/Zibby Studio.app",$=r(f(),"Library","Application Support","@zibby");console.log(o.white(`
|
|
9
|
+
Zibby Studio:`));let v=!1;for(let n of[k,$])i(n)&&(v=!0,l?console.log(o.gray(` [dry-run] rm -rf "${n}"`)):(p(n,{recursive:!0,force:!0}),console.log(o.gray(` \u2713 Removed ${n}`))));if(v||console.log(o.gray(" (not found)")),i(r(y,".zibby"))||i(r(y,".zibby.config.mjs"))){console.log(o.white(`
|
|
10
|
+
Current project (${y}):`));let n=[".zibby",".zibby.config.mjs",".env.example","node_modules","package-lock.json","test-results","playwright-report"];for(let e of n){let c=r(y,e);i(c)&&(l?console.log(o.gray(` [dry-run] rm -rf ${e}`)):([".zibby",".zibby.config.mjs",".env.example"].includes(e)&&u(c),p(c,{recursive:!0,force:!0}),console.log(o.gray(` \u2713 Removed ${e}`))))}let t=r(y,"package.json");if(i(t))try{let e=JSON.parse(z(t,"utf-8")),c=!1;for(let a of["dependencies","devDependencies","peerDependencies"])if(e[a]){for(let w of Object.keys(e[a]))w.startsWith("@zibby/")&&(delete e[a][w],c=!0);e[a]&&Object.keys(e[a]).length===0&&delete e[a]}c&&(l?console.log(o.gray(" [dry-run] Strip @zibby/* from package.json")):(u(t),S(t,`${JSON.stringify(e,null,2)}
|
|
11
|
+
`),console.log(o.gray(" \u2713 Stripped @zibby/* from package.json"))))}catch{}}if(s.deep){let n=r(f(),".npm","_npx");if(console.log(o.white(`
|
|
12
|
+
npx cache (--deep):`)),i(n)){let t=0;for(let e of m(n)){let c=r(n,e);try{let a=m(c,{recursive:!0}).join(`
|
|
13
13
|
`);/zibby/i.test(a)&&(l?console.log(o.gray(` [dry-run] rm -rf ${c}`)):(p(c,{recursive:!0,force:!0}),console.log(o.gray(` \u2713 Removed ${c}`))),t++)}catch{}}t===0&&console.log(o.gray(" (no zibby-related npx cache found)"))}else console.log(o.gray(" (no ~/.npm/_npx)"))}console.log(o.green(`
|
|
14
14
|
\u2705 Uninstall complete.`)),l||console.log(o.gray(` Backups: ${h}`)),console.log(o.gray(` To reinstall: npm i -g @zibby/cli && zibby init
|
|
15
15
|
`))}export{A as uninstallCommand};
|
package/dist/commands/upload.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import{readFileSync as
|
|
1
|
+
import{readFileSync as m,existsSync as l,statSync as P}from"fs";import{join as p,basename as j}from"path";import{glob as F}from"glob";import e from"chalk";import k from"ora";import z from"dotenv";var r={local:{name:"Local Development",apiUrl:"http://localhost:3001",accountApiUrl:"http://localhost:3001",frontendUrl:"http://localhost:3000",description:"Local backend running on port 3001"},prod:{name:"Production",apiUrl:process.env.ZIBBY_PROD_API_URL||"https://api-prod.zibby.app",accountApiUrl:process.env.ZIBBY_PROD_ACCOUNT_API_URL||"https://account-api-prod.zibby.app",frontendUrl:process.env.ZIBBY_PROD_FRONTEND_URL||"https://studio.zibby.app",description:"Production environment"}};function A(){let n;if(process.env.ZIBBY_API_URL)n=process.env.ZIBBY_API_URL;else{let o=process.env.ZIBBY_ENV||"prod";r[o]?n=r[o].apiUrl:n=r.prod.apiUrl}try{let o=new URL(n);return o.protocol!=="http:"&&o.protocol!=="https:"?(console.error(`\u26A0\uFE0F Invalid API URL protocol: ${o.protocol} (only http/https allowed)`),r.prod.apiUrl):n}catch{return console.error(`\u26A0\uFE0F Invalid API URL: ${n}`),r.prod.apiUrl}}function R(){let n=process.env.ZIBBY_ENV||"prod";return r[n]||r.prod}function E(){let n;if(process.env.ZIBBY_FRONTEND_URL)n=process.env.ZIBBY_FRONTEND_URL;else{let o=process.env.ZIBBY_ENV||"prod";r[o]?n=r[o].frontendUrl:n=r.prod.frontendUrl}try{let o=new URL(n);if(o.protocol!=="http:"&&o.protocol!=="https:")return console.error(`\u26A0\uFE0F Invalid frontend URL protocol: ${o.protocol} (only http/https allowed)`),r.local.frontendUrl;if(process.env.NODE_ENV==="production"||process.env.ZIBBY_ENV==="prod"){let s=["zibby.app","studio.zibby.app","studio-staging.zibby.app"],i=o.hostname;if(!s.some(u=>i===u||i.endsWith(`.${u}`))&&!i.includes("localhost")&&i!=="127.0.0.1")return console.error(`\u26A0\uFE0F Untrusted frontend URL in production: ${i}`),"https://studio.zibby.app"}return n}catch{return console.error(`\u26A0\uFE0F Invalid frontend URL: ${n}`),r.local.frontendUrl}}import{existsSync as O,mkdirSync as q,readFileSync as D,writeFileSync as J}from"fs";import{homedir as $}from"os";import{join as y}from"path";function Y(){return process.env.ZIBBY_CONFIG_DIR||y($(),".zibby")}function S(){return y(Y(),"config.json")}var Z=y($(),".zibby"),H=y(Z,"config.json");function T(){try{let n=S();if(O(n)){let o=D(n,"utf-8");return JSON.parse(o)}}catch{}return{}}function w(){return T().sessionToken||null}function C(){return T().user||null}z.config();function V(n,o){let d=o?.paths?.specs||"test-specs",s=o?.paths?.generated||"tests";return n.replace(d,s).replace(/\.txt$/,".spec.js")}async function lo(n,o){let d=R();console.log(e.bold.cyan(`
|
|
2
2
|
\u{1F4E4} Zibby Cloud Upload
|
|
3
|
-
`)),console.log(e.gray("\u2501".repeat(50))),console.log(e.white(`Environment: ${e.cyan(
|
|
4
|
-
`));
|
|
3
|
+
`)),console.log(e.gray("\u2501".repeat(50))),console.log(e.white(`Environment: ${e.cyan(d.name)}
|
|
4
|
+
`));let s=process.cwd(),i=o.project||process.env.ZIBBY_API_KEY;i||(console.log(e.red(`\u274C Error: Project API key required
|
|
5
5
|
`)),console.log(e.white("Provide via:")),console.log(e.gray(" --project <token>")),console.log(e.gray(` or ZIBBY_API_KEY in .env
|
|
6
|
-
`)),process.exit(1));
|
|
6
|
+
`)),process.exit(1));let v=process.env.ZIBBY_USER_TOKEN||w(),u=C();v||(console.log(e.red(`
|
|
7
7
|
\u274C Error: User authentication required
|
|
8
8
|
`)),console.log(e.cyan("Option 1 (Local):")),console.log(e.gray(` zibby login
|
|
9
9
|
`)),console.log(e.cyan("Option 2 (CI/CD):")),console.log(e.gray(` export ZIBBY_USER_TOKEN=zby_pat_xxxxx
|
|
10
|
-
`)),process.exit(1)),console.log(
|
|
10
|
+
`)),process.exit(1)),console.log(u?e.gray(`Authenticated: ${u.email}
|
|
11
11
|
`):e.gray(`Authenticated: Using Personal Access Token
|
|
12
|
-
`));
|
|
12
|
+
`));let b=F.sync("test-results/sessions/*",{cwd:s}).filter(t=>P(p(s,t)).isDirectory()&&!/session_/.test(t)).sort((t,g)=>{let a=P(p(s,t));return P(p(s,g)).mtimeMs-a.mtimeMs});b.length===0&&(console.log(e.red(`\u274C No test results found
|
|
13
13
|
`)),console.log(e.white(`Run a test first: zibby run <spec-path>
|
|
14
|
-
`)),process.exit(1));
|
|
15
|
-
`)),process.exit(1));
|
|
16
|
-
`));
|
|
17
|
-
`)),process.exit(1)}
|
|
18
|
-
\u2713 Test uploaded successfully`)),console.log(e.gray(` Execution ID: ${
|
|
19
|
-
View results: ${
|
|
20
|
-
`))}catch(
|
|
21
|
-
${
|
|
22
|
-
`)),process.exit(1)}}export{
|
|
14
|
+
`)),process.exit(1));let I=b[0],f=p(s,I,"execute_live");l(f)||(console.log(e.red(`\u274C No execution data found in ${I}
|
|
15
|
+
`)),process.exit(1));let x=p(f,"recording.webm"),h=p(f,"events.json"),N=p(f,"title.txt"),_=V(n,{});console.log(e.white("Found artifacts:")),console.log(e.gray(` Session: ${j(I)}`)),console.log(e.gray(` Video: ${l(x)?"\u2713":"\u2717"}`)),console.log(e.gray(` Events: ${l(h)?"\u2713":"\u2717"}`)),console.log(e.gray(` Test: ${l(_)?"\u2713":"\u2717"}
|
|
16
|
+
`));let B=k(`Uploading to ${d.name}...`).start();try{let t=new FormData;if(t.append("specPath",n),t.append("agent",o.agent||"cursor"),t.append("agentType",o.agent||"cursor"),o.collection&&t.append("collectionIdOrName",o.collection),o.folder&&t.append("folder",o.folder),l(x)){let c=new Blob([m(x)]);t.append("video",c,"recording.webm")}if(l(h)){let c=m(h,"utf-8");t.append("events",c)}if(l(_)){let c=m(_,"utf-8");t.append("testCode",c)}if(l(N)){let c=m(N,"utf-8").trim();t.append("title",c)}let g=A(),a=await fetch(`${g}/executions/upload`,{method:"POST",headers:{Authorization:`Bearer ${i}`,"X-User-Token":v},body:t});if(!a.ok){let c=await a.text();B.fail(`Upload failed: ${a.status}`),console.log(e.red(`${c}
|
|
17
|
+
`)),process.exit(1)}let U=await a.json();B.succeed("Upload complete!"),console.log(e.green(`
|
|
18
|
+
\u2713 Test uploaded successfully`)),console.log(e.gray(` Execution ID: ${U.executionId}`));let L=`${E()}/projects/${U.projectId}/runs/${U.executionId}`;console.log(e.cyan(`
|
|
19
|
+
View results: ${L}
|
|
20
|
+
`))}catch(t){B.fail("Upload failed"),console.log(e.red(`
|
|
21
|
+
${t.message}
|
|
22
|
+
`)),process.exit(1)}}export{lo as uploadCommand};
|
package/dist/commands/video.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{organizeVideos as s}from"@zibby/core";import{resolve as i}from"path";import r from"chalk";import t from"ora";async function m(n){
|
|
1
|
+
import{organizeVideos as s}from"@zibby/core";import{resolve as i}from"path";import r from"chalk";import t from"ora";async function m(n){let e=t("Organizing test videos...").start();try{let o=await s({projectRoot:i(process.cwd()),verbose:!1});o.success?(e.succeed(`Organized ${o.movedCount} video(s)`),console.log(r.gray(`
|
|
2
2
|
\u{1F4C2} Videos are now next to their test files in tests/
|
|
3
3
|
`))):(e.fail("Failed to organize videos"),o.error&&console.log(r.red(`Error: ${o.error}
|
|
4
4
|
`)))}catch(o){e.fail("Failed to organize videos"),console.log(r.red(`
|
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
import{readFileSync as
|
|
1
|
+
import{readFileSync as N,writeFileSync as b,existsSync as B,mkdirSync as D}from"fs";import{resolve as T,join as m}from"path";import o from"chalk";import $ from"ora";import Y from"dotenv";import R from"inquirer";var w={local:{name:"Local Development",apiUrl:"http://localhost:3001",accountApiUrl:"http://localhost:3001",frontendUrl:"http://localhost:3000",description:"Local backend running on port 3001"},prod:{name:"Production",apiUrl:process.env.ZIBBY_PROD_API_URL||"https://api-prod.zibby.app",accountApiUrl:process.env.ZIBBY_PROD_ACCOUNT_API_URL||"https://account-api-prod.zibby.app",frontendUrl:process.env.ZIBBY_PROD_FRONTEND_URL||"https://studio.zibby.app",description:"Production environment"}};function _(){let t;if(process.env.ZIBBY_API_URL)t=process.env.ZIBBY_API_URL;else{let e=process.env.ZIBBY_ENV||"prod";w[e]?t=w[e].apiUrl:t=w.prod.apiUrl}try{let e=new URL(t);return e.protocol!=="http:"&&e.protocol!=="https:"?(console.error(`\u26A0\uFE0F Invalid API URL protocol: ${e.protocol} (only http/https allowed)`),w.prod.apiUrl):t}catch{return console.error(`\u26A0\uFE0F Invalid API URL: ${t}`),w.prod.apiUrl}}function j(){let t=process.env.ZIBBY_ENV||"prod";return w[t]||w.prod}import{validateGraphConfig as z}from"@zibby/core/framework/graph-compiler.js";import{generateWorkflowCode as S,generateNodeConfigsJson as F}from"@zibby/core/framework/code-generator.js";import"@zibby/core/templates/register-nodes.js";Y.config();async function L(t){let e=_(),l=$("Fetching projects...").start();try{let c=await fetch(`${e}/projects`,{method:"GET",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`}});c.ok||(l.fail("Failed to fetch projects"),process.exit(1));let n=await c.json();Array.isArray(n)||(n.projects&&Array.isArray(n.projects)?n=n.projects:n.data&&Array.isArray(n.data)?n=n.data:(l.fail("Unexpected response format"),process.exit(1))),(!n||n.length===0)&&(l.fail("No projects found"),process.exit(1)),l.stop();let i=n.map(r=>({name:`${r.name||"Unnamed"} (${r.id||"no-id"})`,value:r.id})),{projectId:g}=await R.prompt([{type:"list",name:"projectId",message:"Select a project:",choices:i}]);return g}catch(c){l.fail(`Error: ${c.message}`),process.exit(1)}}function x(t){let e=t.apiKey||process.env.ZIBBY_API_KEY;e||(console.log(o.red(`
|
|
2
2
|
ZIBBY_API_KEY not set`)),console.log(o.gray(` Add to .env: ZIBBY_API_KEY=zby_xxx
|
|
3
|
-
`)),process.exit(1));
|
|
3
|
+
`)),process.exit(1));let l=t.project||process.env.ZIBBY_PROJECT_ID;return l||(console.log(o.red(`
|
|
4
4
|
--project or ZIBBY_PROJECT_ID is required`)),console.log(o.gray(` Example: zibby workflow download --project <id> --type analysis
|
|
5
|
-
`)),process.exit(1)),{apiKey:
|
|
5
|
+
`)),process.exit(1)),{apiKey:e,projectId:l}}async function Z(t){let e=t.apiKey||process.env.ZIBBY_API_KEY;e||(console.log(o.red(`
|
|
6
6
|
ZIBBY_API_KEY not set`)),console.log(o.gray(` Add to .env: ZIBBY_API_KEY=zby_xxx
|
|
7
|
-
`)),process.exit(1));let
|
|
8
|
-
--type is required`)),console.log(o.gray(` Built-in types: ${
|
|
9
|
-
`)),process.exit(1)),!
|
|
10
|
-
Invalid workflow type: "${
|
|
11
|
-
`)),process.exit(1)),
|
|
7
|
+
`)),process.exit(1));let l=t.project||process.env.ZIBBY_PROJECT_ID;return l||(l=await L(e)),{apiKey:e,projectId:l}}var U=["analysis","implementation","run_test"],O=/^[a-z][a-z0-9_-]{0,62}[a-z0-9]$/;function P(t){let e=t.type;return e||(console.log(o.red(`
|
|
8
|
+
--type is required`)),console.log(o.gray(` Built-in types: ${U.join(", ")}`)),console.log(o.gray(` Custom workflows: any lowercase slug (e.g., ticket-triage)
|
|
9
|
+
`)),process.exit(1)),!U.includes(e)&&!O.test(e)&&(console.log(o.red(`
|
|
10
|
+
Invalid workflow type: "${e}"`)),console.log(o.gray(` Built-in: ${U.join(", ")}`)),console.log(o.gray(` Custom: lowercase letters, digits, hyphens (2\u201364 chars)
|
|
11
|
+
`)),process.exit(1)),e}async function no(t){let e=j(),{apiKey:l,projectId:c}=x(t),n=P(t);console.log(o.bold.cyan(`
|
|
12
12
|
Zibby Workflow Download
|
|
13
|
-
`)),console.log(o.gray(" ".padEnd(52,"-"))),console.log(o.white(` Environment: ${o.cyan(
|
|
14
|
-
`)),process.exit(1)}
|
|
13
|
+
`)),console.log(o.gray(" ".padEnd(52,"-"))),console.log(o.white(` Environment: ${o.cyan(e.name)}`)),console.log(o.white(` Project: ${o.cyan(c)}`)),console.log(o.white(` Type: ${o.cyan(n)}`)),console.log(o.gray(" ".padEnd(52,"-")));let i=$(" Fetching workflow from cloud...").start();try{let g=_(),r=await fetch(`${g}/projects/${c}/workflows/${n}`,{method:"GET",headers:{"Content-Type":"application/json",Authorization:`Bearer ${l}`}});if(!r.ok){let a=await r.text();i.fail(` API error: ${r.status}`),console.log(o.red(` ${a}
|
|
14
|
+
`)),process.exit(1)}let s=await r.json();!s.graph&&s.isDefault?i.info(" No custom workflow saved -- downloading default graph"):i.succeed(` Fetched workflow (v${s.version||0})`);let d=s.graph||null;if(!d){console.log(o.yellow(`
|
|
15
15
|
No graph config available for this workflow.`)),console.log(o.gray(" The project is using the built-in default graph.")),console.log(o.gray(` Edit the graph in the UI first, or use --include-default to download the default.
|
|
16
|
-
`)),t.includeDefault||process.exit(0),
|
|
17
|
-
${
|
|
18
|
-
`)),process.exit(1)}}function
|
|
19
|
-
`,"utf-8");
|
|
16
|
+
`)),t.includeDefault||process.exit(0),i.start(" Fetching default graph...");let{getDefaultGraph:a}=await import("@zibby/core/templates/graphs/index.js"),u=a(n);return u||(i.fail(` No default graph found for type "${n}"`),process.exit(1)),k(n,{graph:u,version:0,isDefault:!0,projectId:c,workflowType:n},t)}return k(n,{graph:d,version:s.version||0,isDefault:s.isDefault||!1,projectId:c,workflowType:n},t)}catch(g){i.fail(" Download failed"),console.log(o.red(`
|
|
17
|
+
${g.message}
|
|
18
|
+
`)),process.exit(1)}}function k(t,e,l){let c=process.cwd(),n=l.output||m(c,".zibby");B(n)||D(n,{recursive:!0});let i={projectId:e.projectId,workflowType:e.workflowType,version:e.version,isDefault:e.isDefault},g=`workflow-${t}.js`,r=m(n,g),s=S(e.graph,i);b(r,s,"utf-8");let d=e.graph.nodeConfigs||{},a=F(d),u=`workflow-${t}.config.json`,v=m(n,u);b(v,`${JSON.stringify(a,null,2)}
|
|
19
|
+
`,"utf-8");let I=`workflow-${t}.json`,p=m(n,I),f={_meta:{...i,downloadedAt:new Date().toISOString()},...e.graph};b(p,`${JSON.stringify(f,null,2)}
|
|
20
20
|
`,"utf-8"),console.log(o.green(`
|
|
21
|
-
Generated workflow files:`)),console.log(o.white(` ${o.bold(
|
|
22
|
-
`)),console.log(o.white(" To run locally:")),console.log(o.cyan(` zibby analyze --workflow ${
|
|
23
|
-
`)),console.log(o.white(" To upload changes back:")),console.log(o.cyan(` zibby workflow upload --project ${
|
|
24
|
-
`))}async function
|
|
21
|
+
Generated workflow files:`)),console.log(o.white(` ${o.bold(r)}`)),console.log(o.gray(" Executable graph with inline tool bindings")),console.log(o.white(` ${o.bold(v)}`)),console.log(o.gray(" Extra prompt instructions & runtime config")),console.log(o.white(` ${o.bold(p)}`)),console.log(o.gray(" Raw JSON config (for upload back to cloud)")),console.log(""),console.log(o.gray(` Version: ${e.version}`)),console.log(o.gray(` Nodes: ${e.graph.nodes?.length||0}`)),console.log(o.gray(` Edges: ${e.graph.edges?.length||0}
|
|
22
|
+
`)),console.log(o.white(" To run locally:")),console.log(o.cyan(` zibby analyze --workflow ${r}
|
|
23
|
+
`)),console.log(o.white(" To upload changes back:")),console.log(o.cyan(` zibby workflow upload --project ${e.projectId} --type ${t}
|
|
24
|
+
`))}async function to(t){let e=j(),{apiKey:l,projectId:c}=await Z(t),n=P(t);console.log(o.bold.cyan(`
|
|
25
25
|
Zibby Workflow Upload
|
|
26
|
-
`)),console.log(o.gray(" ".padEnd(52,"-"))),console.log(o.white(` Environment: ${o.cyan(
|
|
27
|
-
File not found: ${
|
|
28
|
-
`)),process.exit(1));
|
|
26
|
+
`)),console.log(o.gray(" ".padEnd(52,"-"))),console.log(o.white(` Environment: ${o.cyan(e.name)}`)),console.log(o.white(` Project: ${o.cyan(c)}`)),console.log(o.white(` Type: ${o.cyan(n)}`)),console.log(o.gray(" ".padEnd(52,"-")));let i=process.cwd(),g=m(i,".zibby",`workflow-${n}.json`),r=m(i,".zibby",`workflow-${n}.js`),s=t.file||(B(r)?r:g);B(s)||(console.log(o.red(`
|
|
27
|
+
File not found: ${s}`)),console.log(o.gray(` Download a workflow first: zibby workflow download --project <id> --type <type>
|
|
28
|
+
`)),process.exit(1));let d=s.endsWith(".js")||s.endsWith(".mjs"),a;if(d){let p=$(" Loading JS workflow module...").start();try{let{pathToFileURL:f}=await import("url"),h=await import(f(T(s)).href),y=h.buildGraph();a=y.serialize();let E=h.nodeConfigs||{};if(Object.keys(E).length>0)for(let[A,C]of Object.entries(E))a.nodeConfigs[A]={...C,...a.nodeConfigs[A]};p.succeed(` Loaded JS module (${y.nodes.size} nodes)`)}catch(f){p.fail(" Failed to load JS module"),console.log(o.red(`
|
|
29
29
|
${f.message}
|
|
30
|
-
`)),process.exit(1)}}else{let
|
|
31
|
-
Failed to parse ${
|
|
32
|
-
`)),process.exit(1)}
|
|
30
|
+
`)),process.exit(1)}}else{let p;try{p=JSON.parse(N(s,"utf-8"))}catch(y){console.log(o.red(`
|
|
31
|
+
Failed to parse ${s}: ${y.message}
|
|
32
|
+
`)),process.exit(1)}let{_meta:f,...h}=p;a=h}(!a.nodes||!a.edges)&&(console.log(o.red(`
|
|
33
33
|
Invalid workflow file: missing nodes or edges`)),console.log(o.gray(` The file should contain { nodes: [...], edges: [...], nodeConfigs: {...} }
|
|
34
34
|
`)),process.exit(1)),console.log(o.gray(`
|
|
35
|
-
File: ${
|
|
35
|
+
File: ${s}`)),console.log(o.gray(` Format: ${d?"JavaScript (serialized via graph.serialize())":"JSON"}`)),console.log(o.gray(` Nodes: ${a.nodes.length}`)),console.log(o.gray(` Edges: ${a.edges.length}`));let u=$(" Validating graph...").start(),v=z(a);if(!v.valid){u.fail(" Graph validation failed"),console.log("");for(let p of v.errors)console.log(o.red(` ${p}`));console.log(o.gray(`
|
|
36
36
|
Fix the errors above and try again.
|
|
37
|
-
`)),process.exit(1)}
|
|
38
|
-
`)),process.exit(1)}
|
|
39
|
-
Workflow "${
|
|
40
|
-
`))}catch(
|
|
41
|
-
${
|
|
42
|
-
`)),process.exit(1)}}
|
|
37
|
+
`)),process.exit(1)}u.succeed(" Graph is valid");let I=$(" Uploading to cloud...").start();try{let p=_(),f=await fetch(`${p}/projects/${c}/workflows/${n}`,{method:"PUT",headers:{"Content-Type":"application/json",Authorization:`Bearer ${l}`},body:JSON.stringify({graph:a})});if(!f.ok){let y=await f.text();I.fail(` API error: ${f.status}`),console.log(o.red(` ${y}
|
|
38
|
+
`)),process.exit(1)}let h=await f.json();I.succeed(` Uploaded successfully (v${h.version})`),console.log(o.green(`
|
|
39
|
+
Workflow "${n}" updated to version ${h.version}`)),console.log(o.gray(` Project: ${c}
|
|
40
|
+
`))}catch(p){I.fail(" Upload failed"),console.log(o.red(`
|
|
41
|
+
${p.message}
|
|
42
|
+
`)),process.exit(1)}}var J=["analysis","implementation","run_test"];async function ro(t){let e=j(),{apiKey:l,projectId:c}=x(t);console.log(o.bold.cyan(`
|
|
43
43
|
Zibby Workflows
|
|
44
|
-
`));
|
|
45
|
-
`),console.log(o.gray(" ".padEnd(70,"-"))),console.log(o.white(" Type".padEnd(20))+o.white("Version".padEnd(10))+o.white("Nodes".padEnd(10))+o.white("Status".padEnd(15))+o.white("Updated")),console.log(o.gray(" ".padEnd(70,"-")));for(
|
|
46
|
-
${
|
|
47
|
-
`)),process.exit(1)}}export{
|
|
44
|
+
`));let n=$(" Fetching workflows...").start();try{let i=_(),g=[];for(let r of J){let s=await fetch(`${i}/projects/${c}/workflows/${r}`,{method:"GET",headers:{"Content-Type":"application/json",Authorization:`Bearer ${l}`}});if(s.ok){let d=await s.json();g.push({type:r,version:d.version||0,isDefault:d.isDefault!==!1&&!d.graph,nodes:d.graph?.nodes?.length||0,updatedAt:d.updatedAt||null})}}n.succeed(` Fetched workflows
|
|
45
|
+
`),console.log(o.gray(" ".padEnd(70,"-"))),console.log(o.white(" Type".padEnd(20))+o.white("Version".padEnd(10))+o.white("Nodes".padEnd(10))+o.white("Status".padEnd(15))+o.white("Updated")),console.log(o.gray(" ".padEnd(70,"-")));for(let r of g){let s=r.isDefault?o.gray("default"):o.green("custom"),d=r.updatedAt?new Date(r.updatedAt).toLocaleDateString():o.gray("-");console.log(` ${o.cyan(r.type.padEnd(18))}${String(r.version).padEnd(10)}${String(r.nodes).padEnd(10)}${s.padEnd(15)}${d}`)}console.log(o.gray(" ".padEnd(70,"-"))),console.log("")}catch(i){n.fail(" Failed to fetch workflows"),console.log(o.red(`
|
|
46
|
+
${i.message}
|
|
47
|
+
`)),process.exit(1)}}export{no as workflowDownloadCommand,ro as workflowListCommand,to as workflowUploadCommand};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import e from"chalk";import h from"ora";import{confirm as y,select as U}from"@inquirer/prompts";import{readFileSync as A,existsSync as $}from"fs";import{homedir as v}from"os";import{join as _}from"path";var d={local:{name:"Local Development",apiUrl:"http://localhost:3001",accountApiUrl:"http://localhost:3001",frontendUrl:"http://localhost:3000",description:"Local backend running on port 3001"},prod:{name:"Production",apiUrl:process.env.ZIBBY_PROD_API_URL||"https://api-prod.zibby.app",accountApiUrl:process.env.ZIBBY_PROD_ACCOUNT_API_URL||"https://account-api-prod.zibby.app",frontendUrl:process.env.ZIBBY_PROD_FRONTEND_URL||"https://studio.zibby.app",description:"Production environment"}};function u(){let r;if(process.env.ZIBBY_API_URL)r=process.env.ZIBBY_API_URL;else{let s=process.env.ZIBBY_ENV||"prod";d[s]?r=d[s].apiUrl:r=d.prod.apiUrl}try{let s=new URL(r);return s.protocol!=="http:"&&s.protocol!=="https:"?(console.error(`\u26A0\uFE0F Invalid API URL protocol: ${s.protocol} (only http/https allowed)`),d.prod.apiUrl):r}catch{return console.error(`\u26A0\uFE0F Invalid API URL: ${r}`),d.prod.apiUrl}}function B(){let r=_(v(),".zibby","config.json");$(r)||(console.log(e.red(`
|
|
2
|
+
Not authenticated`)),console.log(e.gray(` Run: zibby login
|
|
3
|
+
`)),process.exit(1));let s;try{s=JSON.parse(A(r,"utf-8"))}catch{console.log(e.red(`
|
|
4
|
+
Config file corrupt`)),console.log(e.gray(` Run: zibby login
|
|
5
|
+
`)),process.exit(1)}let t=s.sessionToken;return t||(console.log(e.red(`
|
|
6
|
+
Not authenticated`)),console.log(e.gray(` Run: zibby login
|
|
7
|
+
`)),process.exit(1)),t}async function j(r){let s=u(),t=h("Fetching projects...").start();try{let n=await fetch(`${s}/projects`,{method:"GET",headers:{"Content-Type":"application/json",Authorization:`Bearer ${r}`}});n.ok||(t.fail("Failed to fetch projects"),process.exit(1));let o=await n.json();return Array.isArray(o)||(o.projects&&Array.isArray(o.projects)?o=o.projects:o.data&&Array.isArray(o.data)?o=o.data:(t.fail("Unexpected response format"),process.exit(1))),(!o||o.length===0)&&(t.fail("No projects found"),process.exit(1)),t.succeed(`Found ${o.length} project${o.length===1?"":"s"}`),console.log(""),await U({message:"Select a project:",choices:o.map(i=>({name:`${i.name||i.projectId} ${i.description?`(${i.description})`:""}`,value:i.projectId}))})}catch(n){t.fail(`Error: ${n.message}`),process.exit(1)}}async function N(r,s){let t=u();try{let n=await fetch(`${t}/projects/${s}/workflows`,{method:"GET",headers:{"Content-Type":"application/json",Authorization:`Bearer ${r}`}});if(!n.ok){let o=await n.json();throw new Error(o.error||"Failed to fetch workflows")}return await n.json()}catch(n){throw new Error(`Failed to fetch workflows: ${n.message}`,{cause:n})}}async function m(r,s){let t=u();try{let n=await fetch(`${t}/workflows/${s}`,{method:"DELETE",headers:{"Content-Type":"application/json",Authorization:`Bearer ${r}`}});if(!n.ok){let o=await n.json();throw new Error(o.error||"Failed to delete workflow")}return await n.json()}catch(n){throw new Error(`Failed to delete workflow: ${n.message}`,{cause:n})}}async function z(r,s){try{let t=B();if(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(r)){console.log(""),console.log(e.yellow("WARNING: This will permanently delete the workflow:")),console.log(e.white(` UUID: ${r}`)),console.log(""),await y({message:"Are you sure you want to delete this workflow?",default:!1})||(console.log(e.gray("Deletion cancelled")),process.exit(0));let c=h("Deleting workflow...").start();try{await m(t,r),c.succeed(e.green("Workflow deleted successfully"))}catch(I){c.fail(I.message),process.exit(1)}return}let o=r,w=s.project;w||(w=await j(t));let i=h("Fetching workflows...").start(),p;try{let l=await N(t,w);p=l.workflows||l,i.succeed(`Found ${p.length} workflow${p.length===1?"":"s"}`)}catch(l){i.fail(l.message),process.exit(1)}(!p||p.length===0)&&(console.log(e.yellow("No workflows found in this project")),process.exit(0));let k=["analysis","implementation","run_test"],f=p.filter(l=>!k.includes(l.workflowType));f.length===0&&(console.log(e.yellow("No custom workflows found in this project")),process.exit(0));let a;if(o)a=f.find(l=>l.workflowType===o),a||(console.error(e.red(`Workflow "${o}" not found`)),console.log(e.gray(`
|
|
8
|
+
Available workflows:`)),f.forEach(l=>{console.log(e.gray(` - ${l.workflowType}`))}),process.exit(1));else{console.log("");let l=await U({message:"Select workflow to delete:",choices:f.map(c=>({name:`${c.workflowType} ${c.version?`(v${c.version})`:""}`,value:c.workflowType}))});a=f.find(c=>c.workflowType===l)}console.log(""),console.log(e.yellow("WARNING: This will permanently delete the workflow:")),console.log(e.white(` Name: ${a.workflowType}`)),console.log(e.white(` UUID: ${a.uuid}`)),console.log(e.white(` Version: ${a.version||"N/A"}`)),console.log(""),await y({message:"Are you sure you want to delete this workflow?",default:!1})||(console.log(e.gray("Deletion cancelled")),process.exit(0));let g=h("Deleting workflow...").start();try{await m(t,a.uuid),g.succeed(e.green(`Workflow "${a.workflowType}" deleted successfully`))}catch(l){g.fail(l.message),process.exit(1)}}catch(t){console.error(e.red(`Error: ${t.message}`)),process.exit(1)}}export{z as deleteWorkflowCommand};
|