@zibby/cli 0.1.29 → 0.1.30

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,9 +1,9 @@
1
- import{existsSync as f,readFileSync as I}from"fs";import{join as o,dirname as b}from"path";import{fileURLToPath as x}from"url";import{invokeAgent as j}from"@zibby/core";import{fetchExecutionContext as D}from"../utils/execution-context.js";import{reportProgress as S,reportFinalStatus as O}from"../utils/progress-reporter.js";const L=x(import.meta.url),K=b(L);async function B(t){const{EXECUTION_ID:i,TICKET_KEY:l,PROJECT_ID:n,REPOS:e,_PRIMARY_REPO:s,_GITHUB_TOKEN:y,MODEL:k}=process.env;(!i||!l||!n)&&(console.error("\u274C Missing required environment variables:"),console.error(" EXECUTION_ID, TICKET_KEY, PROJECT_ID"),process.exit(1));const a=await D(i,n),g=a.ticketContext,m=e?JSON.parse(e):a.repos,R=m.find(_=>_.isPrimary)||m[0],h=process.cwd(),p={status:"running",steps:[]};try{await w("Start Environment",async()=>{}),await w("Clone Repositories",async()=>{const r=process.env.GITHUB_TOKEN,c=process.env.GITLAB_TOKEN||"",u=process.env.GITLAB_URL||"";for(const d of m){const T=o(h,d.name);let E=d.url;const P=d.provider==="gitlab"||u&&d.url.includes(new URL(u).host);if((d.provider==="github"||d.url.includes("github.com"))&&r)E=d.url.replace("https://github.com",`https://${r}@github.com`);else if(P&&c&&u)try{const v=new URL(u).host;E=d.url.replace(`https://${v}`,`https://oauth2:${c}@${v}`)}catch(v){console.warn(`\u26A0\uFE0F Failed to parse GITLAB_URL: ${v.message}`)}if(C(["git","clone",E,T],h),C(["git","checkout",d.branch],T),d.isPrimary){const v=`feature/${l.toLowerCase()}`;C(["git","checkout","-b",v],T)}}p.steps.push({name:"clone",status:"success",repoCount:m.length})});const _=await w("Load Ticket Context",async()=>(p.steps.push({name:"load_ticket",status:"success"}),g));await w("Install Dependencies",async()=>{for(const r of m){const c=o(h,r.name),u=U(c);try{C(u.installCommand,c)}catch{}}p.steps.push({name:"install_deps",status:"success"})});const A=await w("Detect Dev Command",async()=>{const r=o(h,R.name),c=["docker-compose.yml","docker-compose.yaml","compose.yml","compose.yaml"];for(const P of c)if(f(o(r,P)))return p.steps.push({name:"detect_dev",status:"success",command:"docker-compose up",type:"docker-compose"}),{command:"docker-compose up",type:"docker-compose",configFile:P};const u=o(r,"package.json");if(!f(u))return console.log(" \u26A0\uFE0F No package.json or docker-compose found"),p.steps.push({name:"detect_dev",status:"skipped"}),null;const T=JSON.parse(I(u,"utf-8")).scripts||{};let E=null;return T.dev?E="npm run dev":T.start?E="npm start":T["dev:local"]&&(E="npm run dev:local"),E?(p.steps.push({name:"detect_dev",status:"success",command:E,type:"npm"}),{command:E,type:"npm"}):(p.steps.push({name:"detect_dev",status:"skipped"}),null)});await w("Start Dev Server",async()=>{const r=o(h,R.name),c="docker-compose.test.yml";return f(o(r,c))?(C(["docker","compose","-f",c,"up","-d"],r),await new Promise(u=>setTimeout(u,1e4)),p.steps.push({name:"start_server",status:"success"}),!0):(console.log(` \u26A0\uFE0F No ${c} found, skipping server startup`),p.steps.push({name:"start_server",status:"skipped"}),null)}),await w("Run AI Agent Implementation",async()=>{const r=m.map(d=>{const T=o(h,d.name);return{...d,...U(T)}}),c=F(_,r,A),u=o(h,".cursor-prompt.md");require("fs").writeFileSync(u,c),await j(c,{state:{model:k,workspace:h}},{print:!0}),p.steps.push({name:"ai_agent",status:"success"})});const G=await w("Run E2E Tests",async()=>{const r=o(h,R.name);if(!f(o(r,"playwright.config.js"))&&!f(o(r,"playwright.config.ts")))return p.steps.push({name:"e2e_tests",status:"skipped"}),null;try{return C("npx playwright test --reporter=json",r),p.steps.push({name:"e2e_tests",status:"success"}),{passed:!0}}catch(c){throw C("docker compose -f docker-compose.test.yml down",r,{allowFailure:!0}),new Error(`E2E tests failed: ${c.message}`,{cause:c})}});try{C("docker compose -f docker-compose.test.yml down",o(h,R.name),{allowFailure:!0})}catch{}const $=await w("Create Pull Request",async()=>{const r=o(h,R.name),c=`feature/${l.toLowerCase()}`;return C(["git","add","."],r),C(["git","commit","-m",`feat(${l}): ${_.summary}`],r),C(["git","push","origin",c],r),console.log(" \u26A0\uFE0F PR creation via API removed (using SQS flow)"),p.steps.push({name:"create_pr",status:"skipped"}),null});await w("Report Results",async()=>{const r=o(h,R.name),c=o(r,"test-results"),u=[];f(c),p.status="completed",p.prUrl=$,p.videoUrls=u,await O(N(),{status:"completed",artifacts:{prUrl:$,videoUrls:u}})}),process.exit(0)}catch(_){console.error(""),console.error("\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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"),console.error("\u2551 \u274C FAILED! \u2551"),console.error("\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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"),console.error(""),console.error("Error:",_.message),console.error("Stack:",_.stack);try{await O(N(),{status:"failed",error:_.message})}catch(A){console.error("Failed to report error:",A.message)}process.exit(1)}}function N(){return{EXECUTION_ID:process.env.EXECUTION_ID,PROGRESS_API_URL:process.env.PROGRESS_API_URL,PROGRESS_QUEUE_URL:process.env.PROGRESS_QUEUE_URL,SQS_AUTH_TOKEN:process.env.SQS_AUTH_TOKEN,PROJECT_API_TOKEN:process.env.PROJECT_API_TOKEN}}async function w(t,i){const l=Date.now(),n=[];let e="";const s=console.log;console.log=(...a)=>{const g=a.join(" ");n.push(g),s(...a)};const y=N(),k=setInterval(()=>{const a=n.join(`
1
+ import{existsSync as f,readFileSync as I,writeFileSync as b}from"fs";import{join as o,dirname as x}from"path";import{fileURLToPath as j}from"url";import{invokeAgent as D}from"@zibby/core";import{fetchExecutionContext as L}from"../utils/execution-context.js";import{reportProgress as S,reportFinalStatus as O}from"../utils/progress-reporter.js";const K=j(import.meta.url),F=x(K);async function z(t){const{EXECUTION_ID:i,TICKET_KEY:l,PROJECT_ID:n,REPOS:e,_PRIMARY_REPO:s,_GITHUB_TOKEN:y,MODEL:k}=process.env;(!i||!l||!n)&&(console.error("\u274C Missing required environment variables:"),console.error(" EXECUTION_ID, TICKET_KEY, PROJECT_ID"),process.exit(1));const a=await L(i,n),g=a.ticketContext,m=e?JSON.parse(e):a.repos,R=m.find(_=>_.isPrimary)||m[0],h=process.cwd(),p={status:"running",steps:[]};try{await w("Start Environment",async()=>{}),await w("Clone Repositories",async()=>{const r=process.env.GITHUB_TOKEN,c=process.env.GITLAB_TOKEN||"",u=process.env.GITLAB_URL||"";for(const d of m){const T=o(h,d.name);let E=d.url;const P=d.provider==="gitlab"||u&&d.url.includes(new URL(u).host);if((d.provider==="github"||d.url.includes("github.com"))&&r)E=d.url.replace("https://github.com",`https://${r}@github.com`);else if(P&&c&&u)try{const v=new URL(u).host;E=d.url.replace(`https://${v}`,`https://oauth2:${c}@${v}`)}catch(v){console.warn(`\u26A0\uFE0F Failed to parse GITLAB_URL: ${v.message}`)}if(C(["git","clone",E,T],h),C(["git","checkout",d.branch],T),d.isPrimary){const v=`feature/${l.toLowerCase()}`;C(["git","checkout","-b",v],T)}}p.steps.push({name:"clone",status:"success",repoCount:m.length})});const _=await w("Load Ticket Context",async()=>(p.steps.push({name:"load_ticket",status:"success"}),g));await w("Install Dependencies",async()=>{for(const r of m){const c=o(h,r.name),u=U(c);try{C(u.installCommand,c)}catch{}}p.steps.push({name:"install_deps",status:"success"})});const A=await w("Detect Dev Command",async()=>{const r=o(h,R.name),c=["docker-compose.yml","docker-compose.yaml","compose.yml","compose.yaml"];for(const P of c)if(f(o(r,P)))return p.steps.push({name:"detect_dev",status:"success",command:"docker-compose up",type:"docker-compose"}),{command:"docker-compose up",type:"docker-compose",configFile:P};const u=o(r,"package.json");if(!f(u))return console.log(" \u26A0\uFE0F No package.json or docker-compose found"),p.steps.push({name:"detect_dev",status:"skipped"}),null;const T=JSON.parse(I(u,"utf-8")).scripts||{};let E=null;return T.dev?E="npm run dev":T.start?E="npm start":T["dev:local"]&&(E="npm run dev:local"),E?(p.steps.push({name:"detect_dev",status:"success",command:E,type:"npm"}),{command:E,type:"npm"}):(p.steps.push({name:"detect_dev",status:"skipped"}),null)});await w("Start Dev Server",async()=>{const r=o(h,R.name),c="docker-compose.test.yml";return f(o(r,c))?(C(["docker","compose","-f",c,"up","-d"],r),await new Promise(u=>setTimeout(u,1e4)),p.steps.push({name:"start_server",status:"success"}),!0):(console.log(` \u26A0\uFE0F No ${c} found, skipping server startup`),p.steps.push({name:"start_server",status:"skipped"}),null)}),await w("Run AI Agent Implementation",async()=>{const r=m.map(d=>{const T=o(h,d.name);return{...d,...U(T)}}),c=G(_,r,A),u=o(h,".cursor-prompt.md");b(u,c),await D(c,{state:{model:k,workspace:h}},{print:!0}),p.steps.push({name:"ai_agent",status:"success"})});const J=await w("Run E2E Tests",async()=>{const r=o(h,R.name);if(!f(o(r,"playwright.config.js"))&&!f(o(r,"playwright.config.ts")))return p.steps.push({name:"e2e_tests",status:"skipped"}),null;try{return C("npx playwright test --reporter=json",r),p.steps.push({name:"e2e_tests",status:"success"}),{passed:!0}}catch(c){throw C("docker compose -f docker-compose.test.yml down",r,{allowFailure:!0}),new Error(`E2E tests failed: ${c.message}`,{cause:c})}});try{C("docker compose -f docker-compose.test.yml down",o(h,R.name),{allowFailure:!0})}catch{}const $=await w("Create Pull Request",async()=>{const r=o(h,R.name),c=`feature/${l.toLowerCase()}`;return C(["git","add","."],r),C(["git","commit","-m",`feat(${l}): ${_.summary}`],r),C(["git","push","origin",c],r),console.log(" \u26A0\uFE0F PR creation via API removed (using SQS flow)"),p.steps.push({name:"create_pr",status:"skipped"}),null});await w("Report Results",async()=>{const r=o(h,R.name),c=o(r,"test-results"),u=[];f(c),p.status="completed",p.prUrl=$,p.videoUrls=u,await O(N(),{status:"completed",artifacts:{prUrl:$,videoUrls:u}})}),process.exit(0)}catch(_){console.error(""),console.error("\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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"),console.error("\u2551 \u274C FAILED! \u2551"),console.error("\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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"),console.error(""),console.error("Error:",_.message),console.error("Stack:",_.stack);try{await O(N(),{status:"failed",error:_.message})}catch(A){console.error("Failed to report error:",A.message)}process.exit(1)}}function N(){return{EXECUTION_ID:process.env.EXECUTION_ID,PROGRESS_API_URL:process.env.PROGRESS_API_URL,PROGRESS_QUEUE_URL:process.env.PROGRESS_QUEUE_URL,SQS_AUTH_TOKEN:process.env.SQS_AUTH_TOKEN,PROJECT_API_TOKEN:process.env.PROJECT_API_TOKEN}}async function w(t,i){const l=Date.now(),n=[];let e="";const s=console.log;console.log=(...a)=>{const g=a.join(" ");n.push(g),s(...a)};const y=N(),k=setInterval(()=>{const a=n.join(`
2
2
  `);a!==e&&a.length>0&&(e=a,S(t,"running",a,y).catch(()=>{}))},2e3);try{await S(t,"running","",y);const a=await i(),g=`${((Date.now()-l)/1e3).toFixed(1)}s`;clearInterval(k),console.log=s;const m=n.join(`
3
3
  `);return await S(t,"success",m||`Completed in ${g}`,y),a}catch(a){clearInterval(k),console.log=s;const g=n.join(`
4
4
  `);throw await S(t,"failed",`${g}
5
5
 
6
- Error: ${a.message}`,y),a}}function C(t,i,l={}){try{const{spawnSync:n}=require("child_process");let e;if(Array.isArray(t)){const[s,...y]=t;e=n(s,y,{cwd:i,encoding:"utf-8",stdio:["pipe","pipe","pipe"]})}else e=n(t,{cwd:i,shell:!0,encoding:"utf-8",stdio:["pipe","pipe","pipe"]});if(e.stdout&&console.log(e.stdout),e.stderr&&console.log(e.stderr),e.status!==0&&!l.allowFailure){const s=Array.isArray(t)?t.join(" "):t;throw new Error(`Command failed with exit code ${e.status}: ${s}`)}return e.stdout||e.stderr}catch(n){if(l.allowFailure)return null;throw n}}function U(t){const i=o(t,".zibby.yml");if(f(i))try{const e=require("js-yaml").load(I(i,"utf-8"));return{name:e.name||"Custom Project",framework:e.framework||"Custom",language:e.language||"Custom",testCommand:e.test||"make test",installCommand:e.install||"make install",custom:!0}}catch{console.warn("Invalid .zibby.yml, falling back to auto-detection")}const l=o(t,"package.json");if(f(l)){const n=JSON.parse(I(l,"utf-8")),e={...n.dependencies,...n.devDependencies};let s="Node.js";return e.next?s="Next.js":e["react-scripts"]?s="Create React App":e.vite&&e.react?s="React + Vite":e["@angular/core"]?s="Angular":e.vue?s="Vue.js":e.express&&(s="Express.js"),{name:n.name||"Unknown Project",framework:s,language:"JavaScript/TypeScript",testCommand:n.scripts?.test||"npm test",installCommand:"npm install"}}return f(o(t,"requirements.txt"))||f(o(t,"pyproject.toml"))?{name:"Python Project",framework:f(o(t,"manage.py"))?"Django":f(o(t,"app.py"))?"Flask":"Python",language:"Python",testCommand:"pytest",installCommand:"pip install -r requirements.txt"}:f(o(t,"Gemfile"))?{name:"Ruby Project",framework:"Rails",language:"Ruby",testCommand:"bundle exec rspec",installCommand:"bundle install"}:f(o(t,"go.mod"))?{name:"Go Project",framework:"Go",language:"Go",testCommand:"go test ./...",installCommand:"go mod download"}:f(o(t,"pom.xml"))?{name:"Java Project",framework:"Spring Boot",language:"Java",testCommand:"./mvnw test",installCommand:"./mvnw install"}:{name:"Unknown Project",framework:"Unknown",language:"Unknown",testCommand:"make test",installCommand:"make install"}}function F(t,i,l){const n=o(K,"../../prompts/implement-ticket.md");let e;try{e=I(n,"utf-8")}catch{e=`
6
+ Error: ${a.message}`,y),a}}function C(t,i,l={}){try{const{spawnSync:n}=require("child_process");let e;if(Array.isArray(t)){const[s,...y]=t;e=n(s,y,{cwd:i,encoding:"utf-8",stdio:["pipe","pipe","pipe"]})}else e=n(t,{cwd:i,shell:!0,encoding:"utf-8",stdio:["pipe","pipe","pipe"]});if(e.stdout&&console.log(e.stdout),e.stderr&&console.log(e.stderr),e.status!==0&&!l.allowFailure){const s=Array.isArray(t)?t.join(" "):t;throw new Error(`Command failed with exit code ${e.status}: ${s}`)}return e.stdout||e.stderr}catch(n){if(l.allowFailure)return null;throw n}}function U(t){const i=o(t,".zibby.yml");if(f(i))try{const e=require("js-yaml").load(I(i,"utf-8"));return{name:e.name||"Custom Project",framework:e.framework||"Custom",language:e.language||"Custom",testCommand:e.test||"make test",installCommand:e.install||"make install",custom:!0}}catch{console.warn("Invalid .zibby.yml, falling back to auto-detection")}const l=o(t,"package.json");if(f(l)){const n=JSON.parse(I(l,"utf-8")),e={...n.dependencies,...n.devDependencies};let s="Node.js";return e.next?s="Next.js":e["react-scripts"]?s="Create React App":e.vite&&e.react?s="React + Vite":e["@angular/core"]?s="Angular":e.vue?s="Vue.js":e.express&&(s="Express.js"),{name:n.name||"Unknown Project",framework:s,language:"JavaScript/TypeScript",testCommand:n.scripts?.test||"npm test",installCommand:"npm install"}}return f(o(t,"requirements.txt"))||f(o(t,"pyproject.toml"))?{name:"Python Project",framework:f(o(t,"manage.py"))?"Django":f(o(t,"app.py"))?"Flask":"Python",language:"Python",testCommand:"pytest",installCommand:"pip install -r requirements.txt"}:f(o(t,"Gemfile"))?{name:"Ruby Project",framework:"Rails",language:"Ruby",testCommand:"bundle exec rspec",installCommand:"bundle install"}:f(o(t,"go.mod"))?{name:"Go Project",framework:"Go",language:"Go",testCommand:"go test ./...",installCommand:"go mod download"}:f(o(t,"pom.xml"))?{name:"Java Project",framework:"Spring Boot",language:"Java",testCommand:"./mvnw test",installCommand:"./mvnw install"}:{name:"Unknown Project",framework:"Unknown",language:"Unknown",testCommand:"make test",installCommand:"make install"}}function G(t,i,l){const n=o(F,"../../prompts/implement-ticket.md");let e;try{e=I(n,"utf-8")}catch{e=`
7
7
  # Implement Ticket: {{TICKET_KEY}}
8
8
 
9
9
  ## Project Context
@@ -62,4 +62,4 @@ ${i.filter(m=>!m.isPrimary).map(m=>`- **${m.name}**: You can read code from here
62
62
  `.trim()}let a=e.replace(/\{\{TICKET_KEY\}\}/g,t.ticketKey||t.key||"UNKNOWN").replace(/\{\{PROJECT_CONTEXT\}\}/g,k).replace(/\{\{TICKET_SUMMARY\}\}/g,t.summary||"No summary").replace(/\{\{TICKET_DESCRIPTION\}\}/g,t.description||"No description provided").replace(/\{\{ACCEPTANCE_CRITERIA\}\}/g,t.acceptanceCriteria||"Not specified");if(t.additionalContext){const g=`## Additional Context from User
63
63
  ${t.additionalContext}
64
64
 
65
- `;a=a.replace(/\{\{#if ADDITIONAL_CONTEXT\}\}[\s\S]*?\{\{\/if\}\}/g,g)}else a=a.replace(/\{\{#if ADDITIONAL_CONTEXT\}\}[\s\S]*?\{\{\/if\}\}/g,"");return a}export{B as implementCommand};
65
+ `;a=a.replace(/\{\{#if ADDITIONAL_CONTEXT\}\}[\s\S]*?\{\{\/if\}\}/g,g)}else a=a.replace(/\{\{#if ADDITIONAL_CONTEXT\}\}[\s\S]*?\{\{\/if\}\}/g,"");return a}export{z as implementCommand};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zibby/cli",
3
- "version": "0.1.29",
3
+ "version": "0.1.30",
4
4
  "description": "Zibby CLI - Test automation generator and runner",
5
5
  "type": "module",
6
6
  "bin": {
@@ -44,7 +44,7 @@
44
44
  "glob": "^13.0.0",
45
45
  "handlebars": "^4.7.9",
46
46
  "inquirer": "^13.4.1",
47
- "mem0ai": "^2.4.6",
47
+ "mem0ai": "npm:@zibby/mem0ai@^2.4.7",
48
48
  "open": "^10.2.0",
49
49
  "ora": "^8.0.1",
50
50
  "tar": "^7.5.2",
@@ -59,10 +59,6 @@
59
59
  "engines": {
60
60
  "node": ">=18.0.0"
61
61
  },
62
- "overrides": {
63
- "axios": "^1.15.0",
64
- "undici": "^7.24.0"
65
- },
66
62
  "devDependencies": {
67
63
  "esbuild": "^0.28.0",
68
64
  "vitest": "^4.1.4"