@zibby/cli 0.1.76 → 0.1.78
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,18 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{dirname as G,join as L,resolve as J}from"path";import{fileURLToPath as b}from"url";import{readFileSync as j,existsSync as B}from"fs";import{compileGraph as Q,validateGraphConfig as z}from"@zibby/
|
|
2
|
+
import{dirname as G,join as L,resolve as J}from"path";import{fileURLToPath as b}from"url";import{readFileSync as j,existsSync as B}from"fs";import{compileGraph as Q,validateGraphConfig as z,WorkflowGraph as W}from"@zibby/workflow";import{invokeAgent as q}from"@zibby/core";import{buildAnalysisGraph as H}from"@zibby/core/templates/code-analysis/graph.js";import{analysisStateSchema as X}from"@zibby/core/templates/code-analysis/state.js";import"@zibby/core/templates/register-nodes.js";async function k(r,t){let a=process.env.CONTEXT_PRESIGNED_URL;if(!a)throw new Error("CONTEXT_PRESIGNED_URL env var is required");console.log("\u{1F4E6} Fetching execution context via pre-signed URL");let e=await fetch(a);if(!e.ok)throw new Error(`Failed to fetch execution context: ${e.status}`);let o=await e.json();return console.log(` \u2705 Got ticketContext (${JSON.stringify(o.ticketContext||{}).length} chars)`),o.nodeConfigs&&Object.keys(o.nodeConfigs).length>0&&console.log(` \u2705 Got nodeConfigs (${Object.keys(o.nodeConfigs).length} nodes configured)`),{ticketContext:o.ticketContext||{},nodeConfigs:o.nodeConfigs||{},graphConfig:o.graphConfig||null,repos:o.repos||[]}}import{SQSClient as M,SendMessageCommand as D}from"@aws-sdk/client-sqs";var I=null;function F(){return I||(I=new M({region:process.env.AWS_REGION||"ap-southeast-2"})),I}async function A(r,t,a,e){let{EXECUTION_ID:o,SQS_AUTH_TOKEN:s,PROGRESS_API_URL:d,PROGRESS_QUEUE_URL:l,PROJECT_API_TOKEN:u}=e;if(!o)return;let f={executionId:o,...s&&{sqsAuthToken:s},step:{name:r,status:t,logs:a,timestamp:new Date().toISOString(),...t==="success"&&{completedAt:new Date().toISOString()}},status:t==="failed"?"failed":"running"};try{d?await v(d,o,f,u):l&&await U(l,o,f)}catch(m){console.error(`\u26A0\uFE0F Failed to send progress: ${m.message}`)}}async function N(r,t,a){let{EXECUTION_ID:e,SQS_AUTH_TOKEN:o,PROGRESS_API_URL:s,PROGRESS_QUEUE_URL:d,PROJECT_API_TOKEN:l}=r;if(!e||!a)return;let u=JSON.stringify(a).length;console.log(`Sending artifact: ${t} (${(u/1024).toFixed(1)}KB)`);let f={executionId:e,...o&&{sqsAuthToken:o},artifacts:{[t]:a},timestamp:new Date().toISOString()},m=s?"HTTP":d?"SQS":"NONE",i=JSON.stringify(f).length;try{if(s)await v(s,e,f,l);else if(d)await U(d,e,f);else{console.warn(`\u26A0\uFE0F No transport configured for artifact ${t} \u2014 neither PROGRESS_API_URL nor PROGRESS_QUEUE_URL set`);return}console.log(`Artifact ${t} sent via ${m} (payload=${(i/1024).toFixed(1)}KB, value=${(u/1024).toFixed(1)}KB)`)}catch(_){console.error(`Failed to send artifact ${t} via ${m}:`),console.error(` Payload size: ${(i/1024).toFixed(1)}KB, Value size: ${(u/1024).toFixed(1)}KB`),console.error(` Error: ${_.message}`),_.name&&console.error(` Error type: ${_.name}`),_.code&&console.error(` Error code: ${_.code}`),i>256*1024&&console.error(" \u26A0\uFE0F Message exceeds SQS 256KB limit! Consider splitting or compressing.")}}async function P(r,{status:t,error:a}){let{EXECUTION_ID:e,SQS_AUTH_TOKEN:o,PROGRESS_API_URL:s,PROGRESS_QUEUE_URL:d,PROJECT_API_TOKEN:l}=r;if(!e)return;let u={executionId:e,...o&&{sqsAuthToken:o},status:t,...a&&{error:a},timestamp:new Date().toISOString()},f=s?"HTTP":d?"SQS":"NONE",m=JSON.stringify(u).length;console.log(`Sending final status: ${t} via ${f} (${(m/1024).toFixed(1)}KB)`);try{if(s)await v(s,e,u,l);else if(d){let i=["completed","failed","insufficient_context","blocked"].includes(t)?"execution_completed":"progress_update";await U(d,e,u,i)}else{console.warn("No transport configured for final status \u2014 neither PROGRESS_API_URL nor PROGRESS_QUEUE_URL set");return}console.log(`Final status ${t} sent via ${f}`)}catch(i){console.error(`Failed to send final status (${t}) via ${f}:`),console.error(` Payload: ${(m/1024).toFixed(1)}KB`),console.error(` Error: ${i.message}`),i.name&&console.error(` Error type: ${i.name}`),i.code&&console.error(` Error code: ${i.code}`)}}async function v(r,t,a,e){let o=`${r}/${t}/progress`,s={"Content-Type":"application/json"};e&&(s.Authorization=`Bearer ${e}`);let d=await fetch(o,{method:"POST",headers:s,body:JSON.stringify(a)});if(!d.ok){let l=await d.text();throw new Error(`HTTP ${d.status}: ${l}`)}}async function U(r,t,a,e="progress_update"){let o=JSON.stringify(a),s=(o.length/1024).toFixed(1);o.length>256*1024&&console.error(`\u274C SQS message too large: ${s}KB (limit 256KB) for ${t} [${e}]`),await F().send(new D({QueueUrl:r,MessageBody:o,MessageGroupId:t,MessageAttributes:{executionId:{DataType:"String",StringValue:t},messageType:{DataType:"String",StringValue:e}}}))}import{writeMcpConfig as V}from"@zibby/core/utils/mcp-config-writer.js";var Y=b(import.meta.url),Z=G(Y),ee=JSON.parse(j(L(Z,"../../package.json"),"utf-8")),oe={analyze_ticket:r=>({key:"analysis",value:{raw:r.raw,structured:r.output}}),generate_code:r=>({key:"codeImplementation",value:r.output?.codeImplementation}),generate_test_cases:r=>({key:"tests",value:r.output?.tests}),finalize:r=>({key:"report",value:r.output?.report})};function te(r,t){return async function(e,o,s){let d=Date.now(),l=[],u="",f=console.log,m=process.stdout.write.bind(process.stdout),i=process.stderr.write.bind(process.stderr),_=!1;console.log=(...n)=>{let h=n.map(w=>typeof w=="string"?w:JSON.stringify(w)).join(" ");l.push(h),_=!0,f(...n),_=!1};let S="";process.stdout.write=(n,h,w)=>{if(!_){let g=typeof n=="string"?n:n.toString();S+=g;let $=S.split(`
|
|
3
3
|
`);S=$.pop()||"";for(let y of $){let O=y.trim();O&&l.push(O)}}return m(n,h,w)},f(`[Middleware] Started capturing logs for ${e}`);let R=!1,T=setInterval(()=>{if(R)return;let n=l.join(`
|
|
4
4
|
`);n!==u&&n.length>0&&(u=n,i(`\u{1F4E1} [Middleware] Sending live update for ${e}: ${n.length} chars, ${l.length} lines
|
|
5
5
|
`),r(e,"in_progress",n,s).catch(h=>{i(`\u26A0\uFE0F [Middleware] Failed to send live update: ${h.message}
|
|
6
6
|
`)}))},500);try{await r(e,"in_progress","",s);let n=await o(),h=((Date.now()-d)/1e3).toFixed(1);R=!0,clearInterval(T),await new Promise(g=>setImmediate(g)),console.log=f,process.stdout.write=m,S.trim()&&(l.push(S.trim()),S="");let w=l.join(`
|
|
7
7
|
`);if(i(`\u{1F4E1} [Middleware] Sending final update for ${e}: ${w.length} chars, ${l.length} total lines captured
|
|
8
|
-
`),n.success){await r(e,"success",w||`Completed in ${h}s`,s);let g=
|
|
8
|
+
`),n.success){await r(e,"success",w||`Completed in ${h}s`,s);let g=oe[e];if(g){let{key:$,value:y}=g(n);y&&await t(s,$,y)}}else await r(e,"failed",`${w}
|
|
9
9
|
|
|
10
10
|
Error: ${n.error}`,s);return n}catch(n){R=!0,clearInterval(T),await new Promise(w=>setImmediate(w)),console.log=f,process.stdout.write=m;let h=`${l.join(`
|
|
11
11
|
`)}
|
|
12
12
|
|
|
13
|
-
Error: ${n.message}`;throw await r(e,"failed",h,s),n}}}async function
|
|
14
|
-
\u{1F680} Zibby Analysis (Graph Mode)`),console.log(`@zibby/cli v${
|
|
13
|
+
Error: ${n.message}`;throw await r(e,"failed",h,s),n}}}async function re(r){let{EXECUTION_ID:t,TICKET_KEY:a,PROJECT_ID:e,REPOS:o,PROGRESS_QUEUE_URL:s,PROGRESS_API_URL:d,SQS_AUTH_TOKEN:l,PROJECT_API_TOKEN:u,GITHUB_TOKEN:f,MODEL:m}=process.env;(!t||!a||!e)&&(console.error("\u274C Missing required environment variables"),console.error(" Required: EXECUTION_ID, TICKET_KEY, PROJECT_ID"),process.exit(1));let i=await k(t,e),_=i.ticketContext,S=i.nodeConfigs||{},R=o?JSON.parse(o):i.repos,T=process.env.WORKSPACE||"/workspace",n=b(import.meta.resolve("@zibby/core/package.json")),h=L(G(n),"templates","code-analysis","prompts");console.log(`
|
|
14
|
+
\u{1F680} Zibby Analysis (Graph Mode)`),console.log(`@zibby/cli v${ee.version} | Node.js ${process.version}`),console.log("\u2500".repeat(60)),console.log(`Ticket: ${a}`),console.log(`Repositories: ${R.length}`),console.log(`Workspace: ${T}`),console.log(`AI Model: ${m||"auto"}`),console.log("\u2500".repeat(60));let w=te(A,N),g,$,y=null;if(r?.workflow){let c=J(process.cwd(),r.workflow);if(B(c)||(console.error(`\u274C Workflow file not found: ${c}`),process.exit(1)),c.endsWith(".js")||c.endsWith(".mjs"))try{let{pathToFileURL:p}=await import("url");y=await import(p(c).href),$=`local JS module (${c})`}catch(p){console.error(`\u274C Failed to load workflow JS module: ${p.message}`),process.exit(1)}else{try{let E=JSON.parse(j(c,"utf-8")),{_meta:C,...K}=E;g=K,$=`local file (${c})`}catch(E){console.error(`\u274C Failed to parse workflow file: ${E.message}`),process.exit(1)}let p=z(g);p.valid||(console.error("\u274C Invalid workflow file:"),p.errors.forEach(E=>console.error(` - ${E}`)),process.exit(1))}}else if(i.graphConfig)g=i.graphConfig,$="custom (from project workflow)";else{let c=new W;H(c),g=c.serialize(),$="default"}let O;if(y){let p={...y.nodeConfigs||{},...S};O=y.buildGraph({nodeMiddleware:w}),console.log(`\u{1F4D0} Graph source: ${$}`),console.log(` Nodes: ${O.nodes.size}`),S=p}else{if(S&&Object.keys(S).length>0){let c=g.nodeConfigs||{},p={...c};for(let[E,C]of Object.entries(S))p[E]={...c[E],...C};g.nodeConfigs=p}console.log(`\u{1F4D0} Graph source: ${$}`),console.log(` Nodes: ${g.nodes?.length||0}`),console.log(` Edges: ${g.edges?.length||0}`),O=Q(g,{nodeMiddleware:w,stateSchema:X,invokeAgent:q})}V(S);let x={EXECUTION_ID:t,PROGRESS_QUEUE_URL:s,PROGRESS_API_URL:d,SQS_AUTH_TOKEN:l,PROJECT_API_TOKEN:u,workspace:T,repos:R,ticketContext:_,promptsDir:h,githubToken:f,model:m,nodeConfigs:S};try{let p=(await O.run(null,x)).state,E=p.analyze_ticket_output?.validation||p.analyze_ticket_output?.analysis?.structured?.validation,C="completed";E&&!E.canProceed&&(C=E.status==="insufficient_context"?"insufficient_context":"blocked"),console.log(`
|
|
15
15
|
\u{1F4CB} Validation: canProceed=${E?.canProceed}, status=${E?.status}, finalStatus=${C}`),console.log(`
|
|
16
16
|
\u{1F4CA} Sending final status: ${C}`),await P(x,{status:C}),console.log(`
|
|
17
17
|
\u2705 Analysis completed successfully`),process.exit(0)}catch(c){if(console.error(`
|
|
18
|
-
\u274C Analysis failed:`,c.message),t)try{console.log("\u{1F4E1} Reporting failure..."),await P(x,{status:"failed",error:c.message})}catch{console.error("\u26A0\uFE0F Failed to report error")}process.exit(1)}}import.meta.url===`file://${process.argv[1]}`&&
|
|
18
|
+
\u274C Analysis failed:`,c.message),t)try{console.log("\u{1F4E1} Reporting failure..."),await P(x,{status:"failed",error:c.message})}catch{console.error("\u26A0\uFE0F Failed to report error")}process.exit(1)}}import.meta.url===`file://${process.argv[1]}`&&re();export{re as analyzeCommand};
|
|
@@ -1,4 +1,4 @@
|
|
|
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
|
|
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,generateWorkflowCode as S,generateNodeConfigsJson as F}from"@zibby/workflow";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
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
|
|
@@ -8,7 +8,7 @@ import{readFileSync as N,writeFileSync as b,existsSync as B,mkdirSync as D}from"
|
|
|
8
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
9
|
`)),process.exit(1)),!U.includes(e)&&!O.test(e)&&(console.log(o.red(`
|
|
10
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
|
|
11
|
+
`)),process.exit(1)),e}async function eo(t){let e=j(),{apiKey:l,projectId:c}=x(t),n=P(t);console.log(o.bold.cyan(`
|
|
12
12
|
Zibby Workflow Download
|
|
13
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
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(`
|
|
@@ -21,7 +21,7 @@ import{readFileSync as N,writeFileSync as b,existsSync as B,mkdirSync as D}from"
|
|
|
21
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
22
|
`)),console.log(o.white(" To run locally:")),console.log(o.cyan(` zibby analyze --workflow ${r}
|
|
23
23
|
`)),console.log(o.white(" To upload changes back:")),console.log(o.cyan(` zibby workflow upload --project ${e.projectId} --type ${t}
|
|
24
|
-
`))}async function
|
|
24
|
+
`))}async function no(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
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
27
|
File not found: ${s}`)),console.log(o.gray(` Download a workflow first: zibby workflow download --project <id> --type <type>
|
|
@@ -39,9 +39,9 @@ import{readFileSync as N,writeFileSync as b,existsSync as B,mkdirSync as D}from"
|
|
|
39
39
|
Workflow "${n}" updated to version ${h.version}`)),console.log(o.gray(` Project: ${c}
|
|
40
40
|
`))}catch(p){I.fail(" Upload failed"),console.log(o.red(`
|
|
41
41
|
${p.message}
|
|
42
|
-
`)),process.exit(1)}}var J=["analysis","implementation","run_test"];async function
|
|
42
|
+
`)),process.exit(1)}}var J=["analysis","implementation","run_test"];async function to(t){let e=j(),{apiKey:l,projectId:c}=x(t);console.log(o.bold.cyan(`
|
|
43
43
|
Zibby Workflows
|
|
44
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
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
46
|
${i.message}
|
|
47
|
-
`)),process.exit(1)}}export{
|
|
47
|
+
`)),process.exit(1)}}export{eo as workflowDownloadCommand,to as workflowListCommand,no as workflowUploadCommand};
|
|
@@ -1,44 +1,46 @@
|
|
|
1
|
-
import e from"chalk";import{readFileSync as
|
|
1
|
+
import e from"chalk";import{readFileSync as R,existsSync as C}from"fs";import{homedir as _}from"os";import{join as j}from"path";var I="https://logs.workflows.zibby.app",A="https://logs-stream.zibby.app/",S=null;async function O(s){return S||(process.env.ZIBBY_SSE_ENDPOINT?(S=process.env.ZIBBY_SSE_ENDPOINT,S):(S=A,S))}function J(s){let n=j(_(),".zibby","config.json");C(n)||(console.log(e.red(`
|
|
2
2
|
Not authenticated`)),console.log(e.gray(` Run: zibby login
|
|
3
|
-
`)),process.exit(1));let t;try{t=JSON.parse(
|
|
3
|
+
`)),process.exit(1));let t;try{t=JSON.parse(R(n,"utf-8"))}catch{console.log(e.red(`
|
|
4
4
|
Config file corrupt`)),console.log(e.gray(` Run: zibby login
|
|
5
|
-
`)),process.exit(1)}let
|
|
5
|
+
`)),process.exit(1)}let c=t.sessionToken;c||(console.log(e.red(`
|
|
6
6
|
Not authenticated`)),console.log(e.gray(` Run: zibby login
|
|
7
|
-
`)),process.exit(1));let f=s.project;return{token:
|
|
7
|
+
`)),process.exit(1));let f=s.project;return{token:c,projectId:f}}function k(s){return new Date(s).toISOString().replace("T"," ").replace("Z","")}async function P(s,n){let t=await fetch(s,{headers:{Authorization:`Bearer ${n}`}});if(!t.ok){let c=await t.text();throw new Error(`API ${t.status}: ${c}`)}return t.json()}async function z(s,n,t,c){return s||(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)),s}async function T({token:s,executionId:n,sseEndpoint:t,stopped:
|
|
10
|
-
`);y=d.pop()||"";for(let o of d)if(o.trim()){if(o.startsWith("id:"))f=o.slice(3).trim();else if(o.startsWith("event:")){let l=o.slice(6).trim();if(l==="log")continue;if(l==="status"){let u=d[d.indexOf(o)+1];if(u&&u.startsWith("data:"))try{let m=JSON.parse(u.slice(5).trim());if(m.status==="new_execution"){let i=m.executionId,b=`${i.slice(0,8)}...${i.slice(-4)}`,
|
|
11
|
-
\u250C\u2500 Execution: ${b} (task: ${
|
|
9
|
+
`)),process.exit(1)),s}async function T({token:s,executionId:n,sseEndpoint:t,stopped:c}){let f=null;try{let a=new URL(t);a.searchParams.set("jobId",n),f&&a.searchParams.set("lastEventId",f);let g=await fetch(a.toString(),{headers:{Authorization:`Bearer ${s}`,Accept:"text/event-stream"}});if(!g.ok)throw new Error(`SSE connection failed: ${g.status} ${g.statusText}`);let r=g.body.getReader(),p=new TextDecoder,y="",w=!1;for(;!c.value;){let{done:$,value:h}=await r.read();if($)break;y+=p.decode(h,{stream:!0});let d=y.split(`
|
|
10
|
+
`);y=d.pop()||"";for(let o of d)if(o.trim()){if(o.startsWith("id:"))f=o.slice(3).trim();else if(o.startsWith("event:")){let l=o.slice(6).trim();if(l==="log")continue;if(l==="status"){let u=d[d.indexOf(o)+1];if(u&&u.startsWith("data:"))try{let m=JSON.parse(u.slice(5).trim());if(m.status==="new_execution"){let i=m.executionId,b=`${i.slice(0,8)}...${i.slice(-4)}`,x=m.taskId?m.taskId.slice(-8):"pending";console.log(e.cyan(`
|
|
11
|
+
\u250C\u2500 Execution: ${b} (task: ${x})`)),console.log(e.cyan(` \u2514\u2500 Streaming logs...
|
|
12
12
|
`))}else m.status==="waiting"&&console.log(e.gray(`
|
|
13
|
-
Waiting for next execution...`))}catch{}continue}if(l==="complete"){w=!0;continue}if(l==="error"){let u=d[d.indexOf(o)+1];if(u&&u.startsWith("data:"))try{if(JSON.parse(u.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 u=JSON.parse(l);if(u.timestamp&&u.message){let m=e.gray(k(u.timestamp)),i=u.taskId?e.gray(`(${u.taskId.slice(-8)}) `):"";console.log(`${m} ${i}${u.message.replace(/\n$/,"")}`)}}catch{}}}}return{completed:w}}catch(
|
|
14
|
-
`):"");let f=await
|
|
15
|
-
`)),
|
|
13
|
+
Waiting for next execution...`))}catch{}continue}if(l==="complete"){w=!0;continue}if(l==="error"){let u=d[d.indexOf(o)+1];if(u&&u.startsWith("data:"))try{if(JSON.parse(u.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 u=JSON.parse(l);if(u.timestamp&&u.message){let m=e.gray(k(u.timestamp)),i=u.taskId?e.gray(`(${u.taskId.slice(-8)}) `):"";console.log(`${m} ${i}${u.message.replace(/\n$/,"")}`)}}catch{}}}}return{completed:w}}catch(a){if(a.name==="AbortError")return{aborted:!0};throw a}}async function E({token:s,jobId:n,follow:t,projectId:c}){console.log(e.gray(` Streaming logs for workflow ${e.cyan(n)}...`)),console.log(t?e.gray(` Press Ctrl+C to stop.
|
|
14
|
+
`):"");let f=await O(s);if(!f)return console.log(e.yellow(` SSE endpoint not configured, using CloudWatch polling...
|
|
15
|
+
`)),v({token:s,projectId:null,jobId:n,follow:t,limit:1e5});let a={value:!1},g=()=>{a.value=!0,console.log(e.gray(`
|
|
16
16
|
Stopped streaming.
|
|
17
|
-
`)),process.exit(0)};process.on("SIGINT",g),process.on("SIGTERM",g);try{let r=await T({token:s,executionId:n,sseEndpoint:f,stopped:
|
|
18
|
-
`));!
|
|
17
|
+
`)),process.exit(0)};process.on("SIGINT",g),process.on("SIGTERM",g);try{let r=await T({token:s,executionId:n,sseEndpoint:f,stopped:a});if(r.aborted||a.value)return;if(r.notFound)if(t)for(console.log(e.yellow(" No executions found yet. Waiting for workflow to be triggered...")),console.log(e.gray(` Press Ctrl+C to stop.
|
|
18
|
+
`));!a.value;){if(await new Promise(p=>setTimeout(p,5e3)),a.value)return;try{if(!(await T({token:s,executionId:n,sseEndpoint:f,stopped:a})).notFound)return}catch{}}else console.log(e.yellow(`
|
|
19
19
|
No executions found for this workflow. Trigger the workflow first.
|
|
20
20
|
`)),process.exit(1);if(r.failed){console.log(e.red(`
|
|
21
|
-
Execution failed.`)),t||process.exit(1);return}
|
|
22
|
-
|
|
23
|
-
`)),
|
|
21
|
+
Execution failed.`)),t||process.exit(1);return}if(r.completed&&process.exit(0),t&&!a.value)return console.log(e.gray(`
|
|
22
|
+
Connection ended, reconnecting...
|
|
23
|
+
`)),E({token:s,jobId:n,follow:t,projectId:null})}catch(r){if(r.name==="AbortError"||a.value)return;if(console.error(e.red(` SSE Error: ${r.message}`)),t&&!a.value)return console.log(e.gray(`
|
|
24
|
+
Reconnecting...
|
|
25
|
+
`)),E({token:s,jobId:n,follow:t,projectId:null})}}async function v({token:s,projectId:n,jobId:t,follow:c,limit:f}){let a=n?`${I}/logs/${n}/${t}`:`${I}/job/${t}`,g=null,r=0,p=new Set,y=!1,w=0,$=5,h=()=>{y=!0,console.log(e.gray(`
|
|
24
26
|
Stopped tailing.
|
|
25
|
-
`)),process.exit(0)};for(process.on("SIGINT",h),process.on("SIGTERM",h),console.log(e.gray(` Fetching logs for workflow ${e.cyan(t)}...`)),console.log(
|
|
26
|
-
`):"");!y;)try{let d=new URLSearchParams({limit:String(f)});g&&d.set("nextToken",g);let o=await P(`${
|
|
27
|
-
Job ${o.status}.`)),process.exit(o.status==="completed"?0:1)}if(!
|
|
27
|
+
`)),process.exit(0)};for(process.on("SIGINT",h),process.on("SIGTERM",h),console.log(e.gray(` Fetching logs for workflow ${e.cyan(t)}...`)),console.log(c?e.gray(` Press Ctrl+C to stop.
|
|
28
|
+
`):"");!y;)try{let d=new URLSearchParams({limit:String(f)});g&&d.set("nextToken",g);let o=await P(`${a}?${d}`,s);w=0,o.message&&o.lines?.length===0&&r===0&&console.log(e.gray(` ${o.message}`)),o.status==="starting"&&o.lines?.length===0&&r===0&&console.log(e.gray(" Container starting..."));for(let i of o.lines||[]){let b=`${i.timestamp}:${i.message}`;if(p.has(b))continue;p.add(b);let x=e.gray(k(i.timestamp)),N=o.taskId?e.gray(`(${o.taskId.slice(-8)}) `):"";console.log(`${x} ${N}${i.message.replace(/\n$/,"")}`)}if(r=o.lines?.length>0?0:r+1,g=o.nextForwardToken||null,o.status==="completed"||o.status==="failed"){let i=o.status==="completed"?e.green:e.red;console.log(i(`
|
|
29
|
+
Job ${o.status}.`)),process.exit(o.status==="completed"?0:1)}if(!c){o.status&&console.log(e.gray(`
|
|
28
30
|
Status: ${o.status}`));break}let m=o.lines?.length>0?500:r>5?5e3:2e3;await new Promise(i=>setTimeout(i,m))}catch(d){if(d.name==="AbortError")break;d.message.match(/API (400|401|403|404):/)&&(console.error(e.red(`
|
|
29
31
|
${d.message}
|
|
30
32
|
`)),process.exit(1)),w++,console.error(e.red(` Error: ${d.message}`)),w>=$&&(console.error(e.red(`
|
|
31
33
|
Too many consecutive errors (${$}). Stopping.
|
|
32
|
-
`)),process.exit(1)),
|
|
34
|
+
`)),process.exit(1)),c||process.exit(1),await new Promise(l=>setTimeout(l,3e3))}}async function L({token:s,projectId:n,workflow:t,follow:c,limit:f}){let a=`${I}/all/${n}`,g=null,r=0,p=new Set,y=null,w=!1,$=0,h=5,d=()=>{w=!0,console.log(e.gray(`
|
|
33
35
|
Stopped tailing.
|
|
34
36
|
`)),process.exit(0)};for(process.on("SIGINT",d),process.on("SIGTERM",d),console.log(e.gray(`
|
|
35
|
-
Tailing all runs for ${e.cyan(t)}...`)),console.log(
|
|
36
|
-
`):"");!w;)try{let o=new URLSearchParams({workflow:t,limit:String(f)});g&&o.set("nextToken",g);let l=await P(`${
|
|
37
|
+
Tailing all runs for ${e.cyan(t)}...`)),console.log(c?e.gray(` Press Ctrl+C to stop.
|
|
38
|
+
`):"");!w;)try{let o=new URLSearchParams({workflow:t,limit:String(f)});g&&o.set("nextToken",g);let l=await P(`${a}?${o}`,s);$=0,l.message&&l.lines?.length===0&&r===0&&console.log(e.gray(` ${l.message}`));for(let i of l.lines||[]){let b=`${i.timestamp}:${i.jobId}:${i.message}`;if(p.has(b))continue;p.add(b),i.jobId!==y&&(y!==null&&console.log(""),console.log(e.dim(` \u2500\u2500 ${i.jobId} \u2500\u2500`)),y=i.jobId);let x=e.gray(k(i.timestamp));console.log(`${x} ${i.message.replace(/\n$/,"")}`)}if(r=l.lines?.length>0?0:r+1,g=l.nextToken||null,!c){g&&console.log(e.gray(`
|
|
37
39
|
... 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&&!g&&r>2){console.log(e.gray(`
|
|
38
40
|
No running jobs. All caught up.`));break}let m=l.lines?.length>0?500:r>5?5e3:2e3;await new Promise(i=>setTimeout(i,m))}catch(o){if(o.name==="AbortError")break;o.message.match(/API (400|401|403|404):/)&&(console.error(e.red(`
|
|
39
41
|
${o.message}
|
|
40
42
|
`)),process.exit(1)),$++,console.error(e.red(` Error: ${o.message}`)),$>=h&&(console.error(e.red(`
|
|
41
43
|
Too many consecutive errors (${h}). Stopping.
|
|
42
|
-
`)),process.exit(1)),
|
|
44
|
+
`)),process.exit(1)),c||process.exit(1),await new Promise(u=>setTimeout(u,3e3))}}async function F(s,n){let{token:t,projectId:c}=J(n),f=n.follow===!0,a=n.lines?parseInt(n.lines,10):1e5;if(n.all){let r=n.workflow;return r||(console.log(e.red(`
|
|
43
45
|
--workflow is required with --all`)),console.log(e.gray(` Example: zibby logs --workflow ticket-triage --all --project <id>
|
|
44
|
-
`)),process.exit(1)),L({token:t,projectId:
|
|
46
|
+
`)),process.exit(1)),L({token:t,projectId:c,workflow:r,follow:f,limit:a})}let g=await z(s,n,t,c);return f?E({token:t,jobId:g,follow:f,projectId:c}):v({token:t,projectId:c,jobId:g,follow:!1,limit:a})}export{F as logsCommand};
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zibby/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.78",
|
|
4
4
|
"description": "Zibby CLI - Test automation generator and runner",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@aws-sdk/client-sqs": "^3.1038.0",
|
|
36
|
+
"@zibby/workflow": "^0.1.0",
|
|
36
37
|
"@zibby/core": "^0.1.30",
|
|
37
38
|
"@zibby/memory": "^0.1.5",
|
|
38
39
|
"@zibby/skills": "^0.1.6",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zibby/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.78",
|
|
4
4
|
"description": "Zibby CLI - Test automation generator and runner",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@aws-sdk/client-sqs": "^3.1038.0",
|
|
36
|
+
"@zibby/workflow": "^0.1.0",
|
|
36
37
|
"@zibby/core": "^0.1.30",
|
|
37
38
|
"@zibby/memory": "^0.1.5",
|
|
38
39
|
"@zibby/skills": "^0.1.6",
|