@zibby/cli 0.1.69 → 0.1.70

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.
@@ -1,14 +1,16 @@
1
- import{existsSync as f,readFileSync as E}from"fs";import{join as i}from"path";import a from"chalk";import R from"ora";import F from"dotenv";import{select as C}from"@inquirer/prompts";import{existsSync as Z}from"fs";import{join as O}from"path";import{pathToFileURL as T}from"url";async function x(e){let t=O(e,".zibby.config.mjs");if(!Z(t))throw new Error(".zibby.config.mjs not found");try{let n=await import(T(t).href);return n.default||n}catch(n){throw new Error(`Failed to load .zibby.config.mjs: ${n.message}`,{cause:n})}}var U={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 B(){let e;if(process.env.ZIBBY_API_URL)e=process.env.ZIBBY_API_URL;else{let t=process.env.ZIBBY_ENV||"prod";U[t]?e=U[t].apiUrl:e=U.prod.apiUrl}try{let t=new URL(e);return t.protocol!=="http:"&&t.protocol!=="https:"?(console.error(`\u26A0\uFE0F Invalid API URL protocol: ${t.protocol} (only http/https allowed)`),U.prod.apiUrl):e}catch{return console.error(`\u26A0\uFE0F Invalid API URL: ${e}`),U.prod.apiUrl}}F.config();async function V(e){let t=B(),n=R("Fetching projects...").start();try{let g=await fetch(`${t}/projects`,{method:"GET",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`}});g.ok||(n.fail("Failed to fetch projects"),process.exit(1));let o=await g.json();Array.isArray(o)||(o.projects&&Array.isArray(o.projects)?o=o.projects:o.data&&Array.isArray(o.data)?o=o.data:(n.fail("Unexpected response format"),process.exit(1))),(!o||o.length===0)&&(n.fail("No projects found"),process.exit(1)),n.succeed(`Found ${o.length} project${o.length===1?"":"s"}`),console.log("");let j=o.map(p=>{let k=p.projectId||p.id||p._id||"unknown";return{name:`${p.name||p.projectName||"Unnamed"} (${k})`,value:k}});return await C({message:"Select a project to deploy to:",choices:j})}catch(g){n.fail(`Error: ${g.message}`),process.exit(1)}}async function so(e,t={}){let n=process.cwd(),g=t.apiKey||process.env.ZIBBY_API_KEY;g||(console.log(`
1
+ import{existsSync as f,readFileSync as T}from"fs";import{join as i}from"path";import l from"chalk";import N from"ora";import H from"dotenv";import{select as O}from"@inquirer/prompts";import{existsSync as J}from"fs";import{join as K}from"path";import{pathToFileURL as M}from"url";async function D(t){let s=K(t,".zibby.config.mjs");if(!J(s))throw new Error(".zibby.config.mjs not found");try{let n=await import(M(s).href);return n.default||n}catch(n){throw new Error(`Failed to load .zibby.config.mjs: ${n.message}`,{cause:n})}}var U={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 x(){let t;if(process.env.ZIBBY_API_URL)t=process.env.ZIBBY_API_URL;else{let s=process.env.ZIBBY_ENV||"prod";U[s]?t=U[s].apiUrl:t=U.prod.apiUrl}try{let s=new URL(t);return s.protocol!=="http:"&&s.protocol!=="https:"?(console.error(`\u26A0\uFE0F Invalid API URL protocol: ${s.protocol} (only http/https allowed)`),U.prod.apiUrl):t}catch{return console.error(`\u26A0\uFE0F Invalid API URL: ${t}`),U.prod.apiUrl}}H.config();async function q(t){let s=x(),n=N("Fetching projects...").start();try{let d=await fetch(`${s}/projects`,{method:"GET",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`}});d.ok||(n.fail("Failed to fetch projects"),process.exit(1));let o=await d.json();Array.isArray(o)||(o.projects&&Array.isArray(o.projects)?o=o.projects:o.data&&Array.isArray(o.data)?o=o.data:(n.fail("Unexpected response format"),process.exit(1))),(!o||o.length===0)&&(n.fail("No projects found"),process.exit(1)),n.succeed(`Found ${o.length} project${o.length===1?"":"s"}`),console.log("");let y=o.map(p=>{let k=p.projectId||p.id||p._id||"unknown";return{name:`${p.name||p.projectName||"Unnamed"} (${k})`,value:k}});return await O({message:"Select a project to deploy to:",choices:y})}catch(d){n.fail(`Error: ${d.message}`),process.exit(1)}}async function go(t,s={}){let n=process.cwd(),d=s.apiKey||process.env.ZIBBY_API_KEY;d||(console.log(`
2
2
  Error: ZIBBY_API_KEY not set`),console.log(` Add to .env or use --api-key flag
3
- `),process.exit(1));let o=".zibby/workflows";try{o=(await x(n))?.paths?.workflows||".zibby/workflows"}catch{}if(!e){let c=i(n,o);f(c)||(console.log(`
3
+ `),process.exit(1));let o=".zibby/workflows";try{o=(await D(n))?.paths?.workflows||".zibby/workflows"}catch{}if(!t){let c=i(n,o);f(c)||(console.log(`
4
4
  Error: No workflows found in ${o}/`),console.log(` Create one with: zibby g workflow <name>
5
- `),process.exit(1));let{readdir:l,stat:y}=await import("fs/promises"),A=await l(c),w=[];for(let m of A){let d=i(c,m);if(!(await y(d)).isDirectory())continue;(f(i(d,"graph.mjs"))||f(i(d,"graph.js")))&&w.push(m)}w.length===0&&(console.log(`
5
+ `),process.exit(1));let{readdir:a,stat:w}=await import("fs/promises"),A=await a(c),m=[];for(let b of A){let g=i(c,b);if(!(await w(g)).isDirectory())continue;(f(i(g,"graph.mjs"))||f(i(g,"graph.js")))&&m.push(b)}m.length===0&&(console.log(`
6
6
  Error: No workflows found in ${o}/`),console.log(` Create one with: zibby g workflow <name>
7
- `),process.exit(1)),console.log(""),e=await C({message:"Select a workflow to deploy:",choices:w.map(m=>({name:m,value:m}))})}let j=t.project||process.env.ZIBBY_PROJECT_ID;j||(console.log(""),j=await V(g));let u=i(n,o,e);f(u)||(console.log(`
8
- Error: Workflow not found: ${o}/${e}`),console.log(` Run: zibby workflow list
7
+ `),process.exit(1)),console.log(""),t=await O({message:"Select a workflow to deploy:",choices:m.map(b=>({name:b,value:b}))})}let y=s.project||process.env.ZIBBY_PROJECT_ID;y||(console.log(""),y=await q(d));let u=i(n,o,t);f(u)||(console.log(`
8
+ Error: Workflow not found: ${o}/${t}`),console.log(` Run: zibby workflow list
9
9
  `),process.exit(1));let p=i(u,"graph.mjs"),k=i(u,"workflow.json");f(p)||(console.log(`
10
- Error: graph.mjs not found in ${o}/${e}/`),process.exit(1)),console.log(`
10
+ Error: graph.mjs not found in ${o}/${t}/`),process.exit(1)),console.log(`
11
11
  Deploying Workflow
12
- `),console.log(" ".padEnd(60,"-")),console.log(` Workflow: ${e}`),console.log(` Project: ${j}`),console.log(" ".padEnd(60,"-")),console.log("");let r=R("Validating workflow...").start(),I=E(p,"utf-8");if(I.includes("@zibby/core")||I.includes("@zibby/skills")){let c=i(u,"package.json");f(c)||(r.fail("Missing package.json"),console.log(""),console.log(a.red(" \u2717 graph.mjs imports @zibby packages but no package.json found")),console.log(""),console.log(a.yellow(" Create package.json with:")),console.log(""),console.log(a.gray(" {")),console.log(a.gray(' "type": "module",')),console.log(a.gray(' "dependencies": {')),console.log(a.gray(' "@zibby/core": "workspace:*"')),console.log(a.gray(" }")),console.log(a.gray(" }")),console.log(""),process.exit(1));let l=JSON.parse(E(c,"utf-8"));!{...l.dependencies,...l.devDependencies}["@zibby/core"]&&I.includes("@zibby/core")&&(r.fail("Missing @zibby/core dependency"),console.log(""),console.log(a.red(" \u2717 graph.mjs imports @zibby/core but it's not in package.json")),console.log(""),console.log(a.yellow(" Add to package.json dependencies:")),console.log(a.gray(' "@zibby/core": "workspace:*"')),console.log(""),process.exit(1))}r.text="Loading workflow graph...";try{let{pathToFileURL:c}=await import("url"),l=await import(c(p).href),y;if(l.default)if(typeof l.default=="function"){let s=l.default.prototype;s&&s.buildGraph?y=new l.default:y=l.default()}else r.fail("graph.mjs must export a class or factory function"),process.exit(1);else{let s=Object.values(l).find(b=>b.prototype&&b.prototype.buildGraph);s?y=new s:(r.fail("graph.mjs must export a WorkflowAgent class or factory function"),process.exit(1))}let w=y.buildGraph().serialize(),{readdir:m,readFile:d}=await import("fs/promises"),h={};r.text="Packaging workflow sources...";let $=await d(p,"utf-8");if(h["graph.mjs"]=$,f(k)){let s=await d(k,"utf-8");h["workflow.json"]=s}let v=i(u,"nodes");if(f(v)){let s=await m(v);for(let b of s)if(b.endsWith(".mjs")||b.endsWith(".js")){let N=i(v,b),Y=await d(N,"utf-8");h[`nodes/${b}`]=Y}}let P=i(u,"package.json");if(f(P)){let s=await d(P,"utf-8");h["package.json"]=s,r.text="Including package.json for dependencies..."}let z=i(u,"package-lock.json");if(f(z)){let s=await d(z,"utf-8");h["package-lock.json"]=s}r.text=`Uploading to cloud (${w.nodes.size||Object.keys(w.nodes||{}).length} nodes, ${Object.keys(h).length} files)...`;let L=B(),_=await fetch(`${L}/projects/${j}/workflows/${e}`,{method:"PUT",headers:{"Content-Type":"application/json",Authorization:`Bearer ${g}`},body:JSON.stringify({graph:w,sources:h,isDefault:!1})});if(!_.ok){let s=await _.json().catch(()=>({}));r.fail("Deploy failed"),console.log(` Error: ${s.message||_.statusText}
13
- `),process.exit(1)}let D=await _.json();r.succeed(`Deployed successfully (v${D.version||1})`),console.log(""),console.log(" Next steps:"),console.log(` zibby start ${e} Run locally`),console.log(" zibby workflow list View all workflows"),console.log("")}catch(c){r.fail("Deploy failed"),console.log(` Error: ${c.message}
14
- `),process.exit(1)}}export{so as deployWorkflowCommand};
12
+ `),console.log(" ".padEnd(60,"-")),console.log(` Workflow: ${t}`),console.log(` Project: ${y}`),console.log(" ".padEnd(60,"-")),console.log("");let r=N("Validating workflow...").start(),$=T(p,"utf-8");if($.includes("@zibby/core")||$.includes("@zibby/skills")){let c=i(u,"package.json");f(c)||(r.fail("Missing package.json"),console.log(""),console.log(l.red(" \u2717 graph.mjs imports @zibby packages but no package.json found")),console.log(""),console.log(l.yellow(" Create package.json with:")),console.log(""),console.log(l.gray(" {")),console.log(l.gray(' "type": "module",')),console.log(l.gray(' "dependencies": {')),console.log(l.gray(' "@zibby/core": "workspace:*"')),console.log(l.gray(" }")),console.log(l.gray(" }")),console.log(""),process.exit(1));let a=JSON.parse(T(c,"utf-8"));!{...a.dependencies,...a.devDependencies}["@zibby/core"]&&$.includes("@zibby/core")&&(r.fail("Missing @zibby/core dependency"),console.log(""),console.log(l.red(" \u2717 graph.mjs imports @zibby/core but it's not in package.json")),console.log(""),console.log(l.yellow(" Add to package.json dependencies:")),console.log(l.gray(' "@zibby/core": "workspace:*"')),console.log(""),process.exit(1))}r.text="Loading workflow graph...";try{let{pathToFileURL:c}=await import("url"),a=await import(c(p).href),w;if(a.default)if(typeof a.default=="function"){let e=a.default.prototype;e&&e.buildGraph?w=new a.default:w=a.default()}else r.fail("graph.mjs must export a class or factory function"),process.exit(1);else{let e=Object.values(a).find(j=>j.prototype&&j.prototype.buildGraph);e?w=new e:(r.fail("graph.mjs must export a WorkflowAgent class or factory function"),process.exit(1))}let m=w.buildGraph().serialize(),{readdir:b,readFile:g}=await import("fs/promises"),h={};r.text="Packaging workflow sources...";let P=await g(p,"utf-8");if(h["graph.mjs"]=P,f(k)){let e=await g(k,"utf-8");h["workflow.json"]=e}let v=i(u,"nodes");if(f(v)){let e=await b(v);for(let j of e)if(j.endsWith(".mjs")||j.endsWith(".js")){let W=i(v,j),G=await g(W,"utf-8");h[`nodes/${j}`]=G}}let z=i(u,"package.json");if(f(z)){let e=await g(z,"utf-8");h["package.json"]=e,r.text="Including package.json for dependencies..."}let E=i(u,"package-lock.json");if(f(E)){let e=await g(E,"utf-8");h["package-lock.json"]=e}r.text=`Uploading to cloud (${m.nodes.size||Object.keys(m.nodes||{}).length} nodes, ${Object.keys(h).length} files)...`;let R=x(),C=JSON.stringify({format:1,sources:h}),L=Buffer.byteLength(C,"utf8"),_=await fetch(`${R}/projects/${y}/workflows/${t}/sources/presign`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${d}`},body:JSON.stringify({contentLength:L})});if(!_.ok){let e=await _.json().catch(()=>({}));r.fail("Deploy failed (presign)"),console.log(` Error: ${e.error||e.message||_.statusText}
13
+ `),process.exit(1)}let Y=await _.json(),{uploadUrl:Z,key:S,headers:F}=Y,B=await fetch(Z,{method:"PUT",headers:{...F||{},"Content-Length":String(L)},body:C});if(!B.ok){let e=await B.text().catch(()=>"");r.fail("Deploy failed (S3 upload)"),console.log(` S3 PUT failed: ${B.status} ${e.slice(0,200)}
14
+ `),process.exit(1)}r.text="Saving workflow definition...";let I=await fetch(`${R}/projects/${y}/workflows/${t}`,{method:"PUT",headers:{"Content-Type":"application/json",Authorization:`Bearer ${d}`},body:JSON.stringify({graph:m,sourcesStagingKey:S,isDefault:!1})});if(!I.ok){let e=await I.json().catch(()=>({}));r.fail("Deploy failed"),console.log(` Error: ${e.message||e.error||I.statusText}
15
+ `),process.exit(1)}let V=await I.json();r.succeed(`Deployed successfully (v${V.version||1})`),console.log(""),console.log(" Next steps:"),console.log(` zibby start ${t} Run locally`),console.log(" zibby workflow list View all workflows"),console.log("")}catch(c){r.fail("Deploy failed"),console.log(` Error: ${c.message}
16
+ `),process.exit(1)}}export{go as deployWorkflowCommand};
@@ -1,38 +1,44 @@
1
- import e from"chalk";import{readFileSync as N,existsSync as R}from"fs";import{homedir as v}from"os";import{join as P}from"path";var E="https://logs.workflows.zibby.app",j="https://logs-stream.zibby.app/",h=null;async function C(i){return h||(process.env.ZIBBY_SSE_ENDPOINT?(h=process.env.ZIBBY_SSE_ENDPOINT,h):(h=j,h))}function A(i){let s=P(v(),".zibby","config.json");R(s)||(console.log(e.red(`
1
+ import e from"chalk";import{readFileSync as P,existsSync as v}from"fs";import{homedir as N}from"os";import{join as R}from"path";var I="https://logs.workflows.zibby.app",j="https://logs-stream.zibby.app/",$=null;async function C(r){return $||(process.env.ZIBBY_SSE_ENDPOINT?($=process.env.ZIBBY_SSE_ENDPOINT,$):($=j,$))}function _(r){let t=R(N(),".zibby","config.json");v(t)||(console.log(e.red(`
2
2
  Not authenticated`)),console.log(e.gray(` Run: zibby login
3
- `)),process.exit(1));let n;try{n=JSON.parse(N(s,"utf-8"))}catch{console.log(e.red(`
3
+ `)),process.exit(1));let n;try{n=JSON.parse(P(t,"utf-8"))}catch{console.log(e.red(`
4
4
  Config file corrupt`)),console.log(e.gray(` Run: zibby login
5
- `)),process.exit(1)}let a=n.sessionToken;a||(console.log(e.red(`
5
+ `)),process.exit(1)}let i=n.sessionToken;i||(console.log(e.red(`
6
6
  Not authenticated`)),console.log(e.gray(` Run: zibby login
7
- `)),process.exit(1));let f=i.project;return{token:a,projectId:f}}function k(i){return new Date(i).toISOString().replace("T"," ").replace("Z","")}async function T(i,s){let n=await fetch(i,{headers:{Authorization:`Bearer ${s}`}});if(!n.ok){let a=await n.text();throw new Error(`API ${n.status}: ${a}`)}return n.json()}async function _(i,s,n,a){return i||(console.log(e.red(`
7
+ `)),process.exit(1));let m=r.project;return{token:i,projectId:m}}function k(r){return new Date(r).toISOString().replace("T"," ").replace("Z","")}async function T(r,t){let n=await fetch(r,{headers:{Authorization:`Bearer ${t}`}});if(!n.ok){let i=await n.text();throw new Error(`API ${n.status}: ${i}`)}return n.json()}async function A(r,t,n,i){return r||(console.log(e.red(`
8
8
  Workflow UUID is required`)),console.log(e.gray(" Usage: zibby logs <workflow-uuid>")),console.log(e.gray(` zibby logs <workflow-uuid> -t
9
- `)),process.exit(1)),i}async function J({token:i,jobId:s,follow:n}){console.log(e.gray(` Streaming logs for workflow ${e.cyan(s)}...`)),console.log(n?e.gray(` Press Ctrl+C to stop.
10
- `):"");let a=await C(i);if(!a)return console.log(e.yellow(` SSE endpoint not configured, using CloudWatch polling...
11
- `)),I({token:i,projectId:null,jobId:s,follow:n,limit:1e3});let f=!1,u=null,c=()=>{f=!0,console.log(e.gray(`
9
+ `)),process.exit(1)),r}async function O({token:r,executionId:t,sseEndpoint:n,stopped:i}){let m=null;try{let g=new URL(n);g.searchParams.set("jobId",t),m&&g.searchParams.set("lastEventId",m);let a=await fetch(g.toString(),{headers:{Authorization:`Bearer ${r}`,Accept:"text/event-stream"}});if(!a.ok)throw new Error(`SSE connection failed: ${a.status} ${a.statusText}`);let s=a.body.getReader(),h=new TextDecoder,d="",y=!1;for(;!i.value;){let{done:w,value:b}=await s.read();if(w)break;d+=h.decode(b,{stream:!0});let u=d.split(`
10
+ `);d=u.pop()||"";for(let o of u)if(o.trim()){if(o.startsWith("id:"))m=o.slice(3).trim();else if(o.startsWith("event:")){let l=o.slice(6).trim();if(l==="log")continue;if(l==="status"){let f=u[u.indexOf(o)+1];if(f&&f.startsWith("data:"))try{let p=JSON.parse(f.slice(5).trim());p.status==="new_execution"?console.log(e.gray(`
11
+ New execution detected: ${p.executionId}
12
+ `)):p.status==="waiting"&&console.log(e.gray(`
13
+ Waiting for next execution...`))}catch{}continue}if(l==="complete"){console.log(e.green(`
14
+ Execution completed.`)),y=!0;continue}if(l==="error"){let f=u[u.indexOf(o)+1];if(f&&f.startsWith("data:"))try{if(JSON.parse(f.slice(5).trim()).error==="No executions found for workflow")return{notFound:!0}}catch{}return{failed:!0}}}else if(o.startsWith("data:")){let l=o.slice(5).trim();if(!l)continue;try{let f=JSON.parse(l);if(f.timestamp&&f.message){let p=e.gray(k(f.timestamp));console.log(`${p} ${f.message.replace(/\n$/,"")}`)}}catch{}}}}return{completed:y}}catch(g){if(g.name==="AbortError")return{aborted:!0};throw g}}async function J({token:r,jobId:t,follow:n,projectId:i}){console.log(e.gray(` Streaming logs for workflow ${e.cyan(t)}...`)),console.log(n?e.gray(` Press Ctrl+C to stop.
15
+ `):"");let m=await C(r);if(!m)return console.log(e.yellow(` SSE endpoint not configured, using CloudWatch polling...
16
+ `)),x({token:r,projectId:null,jobId:t,follow:n,limit:1e5});let g={value:!1},a=()=>{g.value=!0,console.log(e.gray(`
12
17
  Stopped streaming.
13
- `)),process.exit(0)};process.on("SIGINT",c),process.on("SIGTERM",c);try{let l=new URL(a);l.searchParams.set("jobId",s),u&&l.searchParams.set("lastEventId",u);let p=await fetch(l.toString(),{headers:{Authorization:`Bearer ${i}`,Accept:"text/event-stream"}});if(!p.ok)throw new Error(`SSE connection failed: ${p.status} ${p.statusText}`);let w=p.body.getReader(),b=new TextDecoder,d="";for(;!f;){let{done:$,value:m}=await w.read();if($)break;d+=b.decode(m,{stream:!0});let o=d.split(`
14
- `);d=o.pop()||"";for(let r of o)if(r.trim()){if(r.startsWith("id:"))u=r.slice(3).trim();else if(r.startsWith("event:")){let y=r.slice(6).trim();if(y==="status"||y==="log")continue;if(y==="complete"){console.log(e.green(`
15
- Job completed.`)),n||process.exit(0);return}if(y==="error"){let g=o[o.indexOf(r)+1];if(g&&g.startsWith("data:"))try{let t=JSON.parse(g.slice(5).trim());if(t.error==="No executions found for workflow"){console.log(e.yellow(`
18
+ `)),process.exit(0)};process.on("SIGINT",a),process.on("SIGTERM",a);try{let s=await O({token:r,executionId:t,sseEndpoint:m,stopped:g});if(s.aborted||g.value)return;if(s.notFound&&(console.log(e.yellow(`
16
19
  No executions found for this workflow. Trigger the workflow first.
17
- `)),process.exit(1);return}if(t.error==="Task not started yet"){console.log(e.yellow(`
18
- Task not started yet. Try again in a few seconds.
19
- `)),process.exit(1);return}}catch{}console.log(e.red(`
20
- Job failed.`)),n||process.exit(1);return}}else if(r.startsWith("data:")){let y=r.slice(5).trim();if(!y)continue;try{let g=JSON.parse(y);if(g.timestamp&&g.message){let t=e.gray(k(g.timestamp));console.log(`${t} ${g.message.replace(/\n$/,"")}`)}}catch{}}}}}catch(l){return l.name==="AbortError"?void 0:(console.error(e.red(` SSE Error: ${l.message}`)),console.log(e.yellow(` Falling back to polling mode...
21
- `)),I({token:i,projectId:null,jobId:s,follow:n,limit:1e3}))}}async function I({token:i,projectId:s,jobId:n,follow:a,limit:f}){let u=s?`${E}/logs/${s}/${n}`:`${E}/job/${n}`,c=null,l=0,p=new Set,w=!1,b=0,d=5,$=()=>{w=!0,console.log(e.gray(`
20
+ `)),process.exit(1)),s.failed){console.log(e.red(`
21
+ Execution failed.`)),n||process.exit(1);return}return s.completed&&process.exit(0),console.log(e.yellow(` Connection ended unexpectedly, falling back to polling...
22
+ `)),x({token:r,projectId:null,jobId:t,follow:n,limit:1e3})}catch(s){return s.name==="AbortError"||g.value?void 0:(console.error(e.red(` SSE Error: ${s.message}`)),console.log(e.yellow(` Falling back to polling mode...
23
+ `)),x({token:r,projectId:null,jobId:t,follow:n,limit:1e3}))}}async function x({token:r,projectId:t,jobId:n,follow:i,limit:m}){let g=t?`${I}/logs/${t}/${n}`:`${I}/job/${n}`,a=null,s=0,h=new Set,d=!1,y=0,w=5,b=()=>{d=!0,console.log(e.gray(`
22
24
  Stopped tailing.
23
- `)),process.exit(0)};for(process.on("SIGINT",$),process.on("SIGTERM",$),console.log(e.gray(` Fetching logs for workflow ${e.cyan(n)}...`)),console.log(a?e.gray(` Press Ctrl+C to stop.
24
- `):"");!w;)try{let m=new URLSearchParams({limit:String(f)});c&&m.set("nextToken",c);let o=await T(`${u}?${m}`,i);b=0,o.message&&o.lines?.length===0&&l===0&&console.log(e.gray(` ${o.message}`)),o.status==="starting"&&o.lines?.length===0&&l===0&&console.log(e.gray(" Container starting..."));for(let t of o.lines||[]){let S=`${t.timestamp}:${t.message}`;if(p.has(S))continue;p.add(S);let x=e.gray(k(t.timestamp));console.log(`${x} ${t.message.replace(/\n$/,"")}`)}if(l=o.lines?.length>0?0:l+1,c=o.nextForwardToken||null,o.status==="completed"||o.status==="failed"){let t=o.status==="completed"?e.green:e.red;console.log(t(`
25
- Job ${o.status}.`)),process.exit(o.status==="completed"?0:1)}if(!a){o.status&&console.log(e.gray(`
26
- Status: ${o.status}`));break}let g=o.lines?.length>0?500:l>5?5e3:2e3;await new Promise(t=>setTimeout(t,g))}catch(m){if(m.name==="AbortError")break;b++,console.error(e.red(` Error: ${m.message}`)),b>=d&&(console.error(e.red(`
27
- Too many consecutive errors (${d}). Stopping.
28
- `)),process.exit(1)),a||process.exit(1),await new Promise(o=>setTimeout(o,3e3))}}async function O({token:i,projectId:s,workflow:n,follow:a,limit:f}){let u=`${E}/all/${s}`,c=null,l=0,p=new Set,w=null,b=!1,d=0,$=5,m=()=>{b=!0,console.log(e.gray(`
25
+ `)),process.exit(0)};for(process.on("SIGINT",b),process.on("SIGTERM",b),console.log(e.gray(` Fetching logs for workflow ${e.cyan(n)}...`)),console.log(i?e.gray(` Press Ctrl+C to stop.
26
+ `):"");!d;)try{let u=new URLSearchParams({limit:String(m)});a&&u.set("nextToken",a);let o=await T(`${g}?${u}`,r);y=0,o.message&&o.lines?.length===0&&s===0&&console.log(e.gray(` ${o.message}`)),o.status==="starting"&&o.lines?.length===0&&s===0&&console.log(e.gray(" Container starting..."));for(let c of o.lines||[]){let S=`${c.timestamp}:${c.message}`;if(h.has(S))continue;h.add(S);let E=e.gray(k(c.timestamp));console.log(`${E} ${c.message.replace(/\n$/,"")}`)}if(s=o.lines?.length>0?0:s+1,a=o.nextForwardToken||null,o.status==="completed"||o.status==="failed"){let c=o.status==="completed"?e.green:e.red;console.log(c(`
27
+ Job ${o.status}.`)),process.exit(o.status==="completed"?0:1)}if(!i){o.status&&console.log(e.gray(`
28
+ Status: ${o.status}`));break}let p=o.lines?.length>0?500:s>5?5e3:2e3;await new Promise(c=>setTimeout(c,p))}catch(u){if(u.name==="AbortError")break;u.message.match(/API (400|401|403|404):/)&&(console.error(e.red(`
29
+ ${u.message}
30
+ `)),process.exit(1)),y++,console.error(e.red(` Error: ${u.message}`)),y>=w&&(console.error(e.red(`
31
+ Too many consecutive errors (${w}). Stopping.
32
+ `)),process.exit(1)),i||process.exit(1),await new Promise(l=>setTimeout(l,3e3))}}async function z({token:r,projectId:t,workflow:n,follow:i,limit:m}){let g=`${I}/all/${t}`,a=null,s=0,h=new Set,d=null,y=!1,w=0,b=5,u=()=>{y=!0,console.log(e.gray(`
29
33
  Stopped tailing.
30
- `)),process.exit(0)};for(process.on("SIGINT",m),process.on("SIGTERM",m),console.log(e.gray(`
31
- Tailing all runs for ${e.cyan(n)}...`)),console.log(a?e.gray(` Press Ctrl+C to stop.
32
- `):"");!b;)try{let o=new URLSearchParams({workflow:n,limit:String(f)});c&&o.set("nextToken",c);let r=await T(`${u}?${o}`,i);d=0,r.message&&r.lines?.length===0&&l===0&&console.log(e.gray(` ${r.message}`));for(let t of r.lines||[]){let S=`${t.timestamp}:${t.jobId}:${t.message}`;if(p.has(S))continue;p.add(S),t.jobId!==w&&(w!==null&&console.log(""),console.log(e.dim(` \u2500\u2500 ${t.jobId} \u2500\u2500`)),w=t.jobId);let x=e.gray(k(t.timestamp));console.log(`${x} ${t.message.replace(/\n$/,"")}`)}if(l=r.lines?.length>0?0:l+1,c=r.nextToken||null,!a){c&&console.log(e.gray(`
33
- ... more logs available. Run again or use --follow to stream.`)),r.jobCount&&console.log(e.gray(` ${r.jobCount} job(s) found.`));break}if(!r.hasRunning&&!c&&l>2){console.log(e.gray(`
34
- No running jobs. All caught up.`));break}let g=r.lines?.length>0?500:l>5?5e3:2e3;await new Promise(t=>setTimeout(t,g))}catch(o){if(o.name==="AbortError")break;d++,console.error(e.red(` Error: ${o.message}`)),d>=$&&(console.error(e.red(`
35
- Too many consecutive errors (${$}). Stopping.
36
- `)),process.exit(1)),a||process.exit(1),await new Promise(r=>setTimeout(r,3e3))}}async function B(i,s){let{token:n,projectId:a}=A(s),f=s.follow===!0,u=s.lines?parseInt(s.lines,10):1e3;if(s.all){let l=s.workflow;return l||(console.log(e.red(`
34
+ `)),process.exit(0)};for(process.on("SIGINT",u),process.on("SIGTERM",u),console.log(e.gray(`
35
+ Tailing all runs for ${e.cyan(n)}...`)),console.log(i?e.gray(` Press Ctrl+C to stop.
36
+ `):"");!y;)try{let o=new URLSearchParams({workflow:n,limit:String(m)});a&&o.set("nextToken",a);let l=await T(`${g}?${o}`,r);w=0,l.message&&l.lines?.length===0&&s===0&&console.log(e.gray(` ${l.message}`));for(let c of l.lines||[]){let S=`${c.timestamp}:${c.jobId}:${c.message}`;if(h.has(S))continue;h.add(S),c.jobId!==d&&(d!==null&&console.log(""),console.log(e.dim(` \u2500\u2500 ${c.jobId} \u2500\u2500`)),d=c.jobId);let E=e.gray(k(c.timestamp));console.log(`${E} ${c.message.replace(/\n$/,"")}`)}if(s=l.lines?.length>0?0:s+1,a=l.nextToken||null,!i){a&&console.log(e.gray(`
37
+ ... more logs available. Run again or use --follow to stream.`)),l.jobCount&&console.log(e.gray(` ${l.jobCount} job(s) found.`));break}if(!l.hasRunning&&!a&&s>2){console.log(e.gray(`
38
+ No running jobs. All caught up.`));break}let p=l.lines?.length>0?500:s>5?5e3:2e3;await new Promise(c=>setTimeout(c,p))}catch(o){if(o.name==="AbortError")break;o.message.match(/API (400|401|403|404):/)&&(console.error(e.red(`
39
+ ${o.message}
40
+ `)),process.exit(1)),w++,console.error(e.red(` Error: ${o.message}`)),w>=b&&(console.error(e.red(`
41
+ Too many consecutive errors (${b}). Stopping.
42
+ `)),process.exit(1)),i||process.exit(1),await new Promise(f=>setTimeout(f,3e3))}}async function W(r,t){let{token:n,projectId:i}=_(t),m=t.follow===!0,g=t.lines?parseInt(t.lines,10):1e5;if(t.all){let s=t.workflow;return s||(console.log(e.red(`
37
43
  --workflow is required with --all`)),console.log(e.gray(` Example: zibby logs --workflow ticket-triage --all --project <id>
38
- `)),process.exit(1)),O({token:n,projectId:a,workflow:l,follow:f,limit:u})}let c=await _(i,s,n,a);return f?J({token:n,jobId:c,follow:f}):I({token:n,projectId:a,jobId:c,follow:!1,limit:u})}export{B as logsCommand};
44
+ `)),process.exit(1)),z({token:n,projectId:i,workflow:s,follow:m,limit:g})}let a=await A(r,t,n,i);return m?J({token:n,jobId:a,follow:m,projectId:i}):x({token:n,projectId:i,jobId:a,follow:!1,limit:g})}export{W as logsCommand};
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import{mkdirSync as F,writeFileSync as L,existsSync as U}from"fs";import{join as E,dirname as W,resolve as y}from"path";import{pathToFileURL as D}from"url";import{SQSClient as k,SendMessageCommand as C}from"@aws-sdk/client-sqs";var S=null;function N(){return S||(S=new k({region:process.env.AWS_REGION||"ap-southeast-2"})),S}async function h(s,{status:e,error:o}){let{EXECUTION_ID:t,SQS_AUTH_TOKEN:r,PROGRESS_API_URL:i,PROGRESS_QUEUE_URL:n,PROJECT_API_TOKEN:d}=s;if(!t)return;let l={executionId:t,...r&&{sqsAuthToken:r},status:e,...o&&{error:o},timestamp:new Date().toISOString()},p=i?"HTTP":n?"SQS":"NONE",f=JSON.stringify(l).length;console.log(`Sending final status: ${e} via ${p} (${(f/1024).toFixed(1)}KB)`);try{if(i)await v(i,t,l,d);else if(n){let c=["completed","failed","insufficient_context","blocked"].includes(e)?"execution_completed":"progress_update";await x(n,t,l,c)}else{console.warn("No transport configured for final status \u2014 neither PROGRESS_API_URL nor PROGRESS_QUEUE_URL set");return}console.log(`Final status ${e} sent via ${p}`)}catch(c){console.error(`Failed to send final status (${e}) via ${p}:`),console.error(` Payload: ${(f/1024).toFixed(1)}KB`),console.error(` Error: ${c.message}`),c.name&&console.error(` Error type: ${c.name}`),c.code&&console.error(` Error code: ${c.code}`)}}async function v(s,e,o,t){let r=`${s}/${e}/progress`,i={"Content-Type":"application/json"};t&&(i.Authorization=`Bearer ${t}`);let n=await fetch(r,{method:"POST",headers:i,body:JSON.stringify(o)});if(!n.ok){let d=await n.text();throw new Error(`HTTP ${n.status}: ${d}`)}}async function x(s,e,o,t="progress_update"){let r=JSON.stringify(o),i=(r.length/1024).toFixed(1);r.length>256*1024&&console.error(`\u274C SQS message too large: ${i}KB (limit 256KB) for ${e} [${t}]`),await N().send(new C({QueueUrl:s,MessageBody:r,MessageGroupId:e,MessageAttributes:{executionId:{DataType:"String",StringValue:e},messageType:{DataType:"String",StringValue:t}}}))}var P=process.env.WORKSPACE||"/workspace";async function K(){let s=process.env.WORKFLOW_SOURCES_URL;if(!s)throw new Error("WORKFLOW_SOURCES_URL env var is required");console.log("Fetching workflow sources via pre-signed URL...");let e=await fetch(s);if(!e.ok)throw new Error(`Failed to fetch sources: ${e.status} ${e.statusText}`);let o=await e.json();if(!o.sources||typeof o.sources!="object")throw new Error('Invalid sources payload \u2014 missing "sources" map');return o}function b(s,e){let o=y(e),t=0;for(let[r,i]of Object.entries(s)){let n=y(e,r);if(!n.startsWith(`${o}/`)&&n!==o){console.error(` \u26D4 Skipping unsafe path: ${r}`);continue}F(W(n),{recursive:!0}),L(n,i,"utf-8"),t++}return t}async function G(s,e){let o=E(s,"graph.mjs");if(!U(o))throw new Error(`graph.mjs not found at ${o}`);let t=await import(D(o).href),r=e?.entryClass,i=r&&t[r]||t.default||Object.values(t).find(n=>typeof n=="function"&&n.prototype?.buildGraph);if(!i)throw new Error("No WorkflowAgent class found in graph.mjs");return i}async function z(){if(!process.env.NODE_PATH){process.env.NODE_PATH="/opt/zibby/packages";let a=await import("module");a.default._initPaths&&a.default._initPaths()}let{WORKFLOW_JOB_ID:s,WORKFLOW_TYPE:e,PROJECT_ID:o,AGENT_TYPE:t,MODEL:r}=process.env;e||(console.error("Missing WORKFLOW_TYPE env var"),process.exit(1)),console.log(`
3
- Zibby Custom Workflow Runner`),console.log(` Job: ${s||"local"}`),console.log(` Workflow: ${e}`),console.log(` Project: ${o||"none"}`),console.log(` Agent: ${t||"default"}`),console.log(` Model: ${r||"auto"}`),console.log("\u2500".repeat(60));let i=await K(),{sources:n,input:d,workflowType:l,version:p}=i;console.log(` Workflow v${p||"?"} \u2014 ${Object.keys(n).length} source files`);let f=E(P,".zibby","workflows",l||e),c=b(n,f);console.log(` Wrote ${c} files to ${f}`),console.log(" Installing dependencies...");let{execSync:T}=await import("child_process");try{T("npm install --silent --no-audit --no-fund",{cwd:f,stdio:"inherit"}),console.log(" Dependencies installed")}catch(a){console.warn(` npm install failed: ${a.message}`)}let m={},O=E(f,"workflow.json");if(U(O)){let{readFileSync:a}=await import("fs");m=JSON.parse(a(O,"utf-8"))}let _=await G(f,m);console.log(` Loaded ${_.name}`);let I=Date.now(),u=new _({workflow:l||e}),R=u.buildGraph(),A={input:d||{},cwd:P,runId:s||`run-${Date.now()}`};console.log(`
2
+ import{mkdirSync as F,writeFileSync as L,existsSync as T}from"fs";import{join as w,dirname as W,resolve as h}from"path";import{pathToFileURL as K}from"url";import{SQSClient as C,SendMessageCommand as N}from"@aws-sdk/client-sqs";var S=null;function k(){return S||(S=new C({region:process.env.AWS_REGION||"ap-southeast-2"})),S}async function P(s,{status:e,error:o}){let{EXECUTION_ID:t,SQS_AUTH_TOKEN:r,PROGRESS_API_URL:i,PROGRESS_QUEUE_URL:n,PROJECT_API_TOKEN:d}=s;if(!t)return;let l={executionId:t,...r&&{sqsAuthToken:r},status:e,...o&&{error:o},timestamp:new Date().toISOString()},p=i?"HTTP":n?"SQS":"NONE",f=JSON.stringify(l).length;console.log(`Sending final status: ${e} via ${p} (${(f/1024).toFixed(1)}KB)`);try{if(i)await v(i,t,l,d);else if(n){let c=["completed","failed","insufficient_context","blocked"].includes(e)?"execution_completed":"progress_update";await x(n,t,l,c)}else{console.warn("No transport configured for final status \u2014 neither PROGRESS_API_URL nor PROGRESS_QUEUE_URL set");return}console.log(`Final status ${e} sent via ${p}`)}catch(c){console.error(`Failed to send final status (${e}) via ${p}:`),console.error(` Payload: ${(f/1024).toFixed(1)}KB`),console.error(` Error: ${c.message}`),c.name&&console.error(` Error type: ${c.name}`),c.code&&console.error(` Error code: ${c.code}`)}}async function v(s,e,o,t){let r=`${s}/${e}/progress`,i={"Content-Type":"application/json"};t&&(i.Authorization=`Bearer ${t}`);let n=await fetch(r,{method:"POST",headers:i,body:JSON.stringify(o)});if(!n.ok){let d=await n.text();throw new Error(`HTTP ${n.status}: ${d}`)}}async function x(s,e,o,t="progress_update"){let r=JSON.stringify(o),i=(r.length/1024).toFixed(1);r.length>256*1024&&console.error(`\u274C SQS message too large: ${i}KB (limit 256KB) for ${e} [${t}]`),await k().send(new N({QueueUrl:s,MessageBody:r,MessageGroupId:e,MessageAttributes:{executionId:{DataType:"String",StringValue:e},messageType:{DataType:"String",StringValue:t}}}))}var y=process.env.WORKSPACE||"/workspace";async function D(){let s=process.env.WORKFLOW_SOURCES_URL;if(!s)throw new Error("WORKFLOW_SOURCES_URL env var is required");console.log("Fetching workflow sources via pre-signed URL...");let e=await fetch(s);if(!e.ok)throw new Error(`Failed to fetch sources: ${e.status} ${e.statusText}`);let o=await e.json();if(!o.sources||typeof o.sources!="object")throw new Error('Invalid sources payload \u2014 missing "sources" map');return o}function b(s,e){let o=h(e),t=0;for(let[r,i]of Object.entries(s)){let n=h(e,r);if(!n.startsWith(`${o}/`)&&n!==o){console.error(` \u26D4 Skipping unsafe path: ${r}`);continue}F(W(n),{recursive:!0}),L(n,i,"utf-8"),t++}return t}async function G(s,e){let o=w(s,"graph.mjs");if(!T(o))throw new Error(`graph.mjs not found at ${o}`);let t=await import(K(o).href),r=e?.entryClass,i=r&&t[r]||t.default||Object.values(t).find(n=>typeof n=="function"&&n.prototype?.buildGraph);if(!i)throw new Error("No WorkflowAgent class found in graph.mjs");return i}async function z(){if(!process.env.NODE_PATH){process.env.NODE_PATH="/opt/zibby/packages";let a=await import("module");a.default._initPaths&&a.default._initPaths()}let{WORKFLOW_JOB_ID:s,WORKFLOW_TYPE:e,PROJECT_ID:o,AGENT_TYPE:t,MODEL:r}=process.env;e||(console.error("Missing WORKFLOW_TYPE env var"),process.exit(1)),console.log(`
3
+ Zibby Custom Workflow Runner`),console.log(` Job: ${s||"local"}`),console.log(` Workflow: ${e}`),console.log(` Project: ${o||"none"}`),console.log(` Agent: ${t||"default"}`),console.log(` Model: ${r||"auto"}`),console.log("\u2500".repeat(60));let i=await D(),{sources:n,input:d,workflowType:l,version:p}=i;console.log(` Workflow v${p||"?"} \u2014 ${Object.keys(n).length} source files`);let f=w(y,".zibby","workflows",l||e),c=b(n,f);console.log(` Wrote ${c} files to ${f}`),console.log(" Installing dependencies...");let{execSync:U}=await import("child_process");try{U("npm install --silent --no-audit --no-fund",{cwd:f,stdio:"inherit"}),console.log(" Dependencies installed")}catch(a){console.warn(` npm install failed: ${a.message}`)}let O={},_=w(f,"workflow.json");if(T(_)){let{readFileSync:a}=await import("fs");O=JSON.parse(a(_,"utf-8"))}let m=await G(f,O);console.log(` Loaded ${m.name}`);let I=Date.now(),u=new m({workflow:l||e}),R=u.buildGraph(),A={input:d||{},cwd:y,runId:s||`run-${Date.now()}`};console.log(`
4
4
  Running graph (${R.nodes?.size||"?"} nodes)...
5
5
  `);let g;try{g=await R.run(u,A)}catch(a){console.error(`
6
- Workflow execution failed: ${a.message}`),console.error(a.stack),await w("failed",a.message),process.exit(1)}let $=((Date.now()-I)/1e3).toFixed(1);g?.success!==!1?(console.log(`
7
- Workflow "${l||e}" completed in ${$}s`),await w("completed")):(console.error(`
8
- Workflow "${l||e}" failed after ${$}s`),await w("failed",g?.error||"Workflow execution failed"),process.exit(1)),u.onComplete&&await u.onComplete(g)}async function w(s,e=null){let o={EXECUTION_ID:process.env.WORKFLOW_JOB_ID,PROGRESS_API_URL:process.env.PROGRESS_API_URL,PROGRESS_QUEUE_URL:process.env.PROGRESS_QUEUE_URL};if(o.EXECUTION_ID)try{await h(o,{status:s,...e&&{error:e}})}catch(t){console.error(`\u26A0\uFE0F Failed to report status: ${t.message}`)}}export{z as runWorkflowCommand};
6
+ Workflow execution failed: ${a.message}`),console.error(a.stack),await E("failed",a.message),process.exit(1)}let $=((Date.now()-I)/1e3).toFixed(1);g?.success!==!1?(console.log(`
7
+ Workflow "${l||e}" completed in ${$}s`),await E("completed")):(console.error(`
8
+ Workflow "${l||e}" failed after ${$}s`),await E("failed",g?.error||"Workflow execution failed"),process.exit(1)),u.onComplete&&await u.onComplete(g)}async function E(s,e=null){let o={EXECUTION_ID:process.env.WORKFLOW_JOB_ID,PROGRESS_API_URL:process.env.PROGRESS_API_URL,PROGRESS_QUEUE_URL:process.env.PROGRESS_QUEUE_URL,PROJECT_API_TOKEN:process.env.PROJECT_API_TOKEN};if(o.EXECUTION_ID)try{await P(o,{status:s,...e&&{error:e}})}catch(t){console.error(`\u26A0\uFE0F Failed to report status: ${t.message}`)}}export{z as runWorkflowCommand};
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zibby/cli",
3
- "version": "0.1.69",
3
+ "version": "0.1.70",
4
4
  "description": "Zibby CLI - Test automation generator and runner",
5
5
  "type": "module",
6
6
  "bin": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zibby/cli",
3
- "version": "0.1.69",
3
+ "version": "0.1.70",
4
4
  "description": "Zibby CLI - Test automation generator and runner",
5
5
  "type": "module",
6
6
  "bin": {