@zibby/cli 0.1.37 → 0.1.39

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,46 +1,50 @@
1
- import{mkdir as A,writeFile as g,readFile as w}from"fs/promises";import{existsSync as h,readdirSync as j}from"fs";import{join as i,resolve as Y,dirname as N}from"path";import{homedir as I}from"os";import K from"inquirer";import e from"chalk";import P from"ora";import{spawn as T,execSync as O}from"child_process";import{fileURLToPath as Z}from"url";const G=Z(import.meta.url),H=N(G);async function F(){try{const r=process.platform==="win32",t=O("npm config get prefix",{encoding:"utf-8"}).trim(),u=r?t:`${t}/bin`,d=u.replace(/^~/,I()),s=r?";":":";if(process.env.PATH.split(s).some(v=>{const M=v.replace(/^~/,I());return M===d||M===u}))return;console.log(e.yellow("\u26A0\uFE0F npm global bin not in PATH")),console.log(e.gray(` Location: ${d}`)),console.log();const{shouldAddPath:n}=await K.prompt([{type:"confirm",name:"shouldAddPath",message:"Add npm global bin to your shell PATH automatically?",default:!0}]);if(!n){r?(console.log(e.gray(`
1
+ import{mkdir as C,writeFile as u,readFile as w}from"fs/promises";import{existsSync as y,readdirSync as L}from"fs";import{join as s,resolve as D,dirname as Z}from"path";import{homedir as A}from"os";import O from"inquirer";import e from"chalk";import P from"ora";import{spawn as Y,execSync as K}from"child_process";import{fileURLToPath as j}from"url";const N=j(import.meta.url),G=Z(N);async function H(){try{const l=process.platform==="win32",o=K("npm config get prefix",{encoding:"utf-8"}).trim(),g=l?o:`${o}/bin`,d=g.replace(/^~/,A()),a=l?";":":";if(process.env.PATH.split(a).some(v=>{const M=v.replace(/^~/,A());return M===d||M===g}))return;console.log(e.yellow("\u26A0\uFE0F npm global bin not in PATH")),console.log(e.gray(` Location: ${d}`)),console.log();const{shouldAddPath:n}=await O.prompt([{type:"confirm",name:"shouldAddPath",message:"Add npm global bin to your shell PATH automatically?",default:!0}]);if(!n){l?(console.log(e.gray(`
2
2
  \u{1F4A1} To add manually on Windows:`)),console.log(e.gray(' 1. Search "Environment Variables" in Start menu')),console.log(e.gray(' 2. Edit "Path" in User variables')),console.log(e.gray(` 3. Add: ${d}
3
3
  `))):(console.log(e.gray(`
4
4
  \u{1F4A1} To add manually, run:`)),console.log(e.gray(` echo 'export PATH="${d}:$PATH"' >> ~/.zshrc`)),console.log(e.gray(` source ~/.zshrc
5
- `)));return}if(r){console.log(e.yellow("\u26A0\uFE0F Cannot auto-add PATH on Windows")),console.log(e.gray(" Please add manually:")),console.log(e.gray(' 1. Search "Environment Variables" in Start menu')),console.log(e.gray(' 2. Edit "Path" in User variables')),console.log(e.gray(` 3. Add: ${d}
6
- `));return}const x=process.env.SHELL||"";let p="";if(x.includes("zsh"))p=i(I(),".zshrc");else if(x.includes("bash"))p=h(i(I(),".bashrc"))?i(I(),".bashrc"):i(I(),".bash_profile");else{console.log(e.yellow(`\u26A0\uFE0F Unknown shell: ${x}`)),console.log(e.gray(" Please add manually:")),console.log(e.gray(` export PATH="${d}:$PATH"`));return}if(h(p)){const v=await w(p,"utf-8");if(v.includes(d)||v.includes("npm")&&v.includes("global")&&v.includes("bin")){console.log(e.yellow(`\u26A0\uFE0F PATH entry found in ${p} but not active`)),console.log(e.gray(` Run: source ${p}
5
+ `)));return}if(l){console.log(e.yellow("\u26A0\uFE0F Cannot auto-add PATH on Windows")),console.log(e.gray(" Please add manually:")),console.log(e.gray(' 1. Search "Environment Variables" in Start menu')),console.log(e.gray(' 2. Edit "Path" in User variables')),console.log(e.gray(` 3. Add: ${d}
6
+ `));return}const x=process.env.SHELL||"";let p="";if(x.includes("zsh"))p=s(A(),".zshrc");else if(x.includes("bash"))p=y(s(A(),".bashrc"))?s(A(),".bashrc"):s(A(),".bash_profile");else{console.log(e.yellow(`\u26A0\uFE0F Unknown shell: ${x}`)),console.log(e.gray(" Please add manually:")),console.log(e.gray(` export PATH="${d}:$PATH"`));return}if(y(p)){const v=await w(p,"utf-8");if(v.includes(d)||v.includes("npm")&&v.includes("global")&&v.includes("bin")){console.log(e.yellow(`\u26A0\uFE0F PATH entry found in ${p} but not active`)),console.log(e.gray(` Run: source ${p}
7
7
  `));return}}const b=`
8
8
  # npm global bin (added by zibby)
9
9
  export PATH="${d}:$PATH"
10
- `;await g(p,(h(p)?await w(p,"utf-8"):"")+b),console.log(e.green(`\u2705 Added to ${p}`)),console.log(e.yellow(`
10
+ `;await u(p,(y(p)?await w(p,"utf-8"):"")+b),console.log(e.green(`\u2705 Added to ${p}`)),console.log(e.yellow(`
11
11
  \u{1F4A1} Run this to activate in current session:`)),console.log(e.gray(` source ${p}
12
- `))}catch{}}async function me(r,t){console.log(e.bold.cyan(`
12
+ `))}catch{}}async function de(l,o){console.log(e.bold.cyan(`
13
13
  \u{1F3AD} Welcome to Zibby Test Automation!
14
- `));const u=!t.skipMemory,d=["dolt","mem0"].includes(String(t.memoryBackend||"").toLowerCase())?String(t.memoryBackend).toLowerCase():"dolt";await F();const s=r?Y(process.cwd(),r):process.cwd(),E=r||"zibby-tests",y=!!r;y&&h(s)&&(console.log(e.red(`
15
- \u274C Directory "${r}" already exists!
16
- `)),process.exit(1)),!y&&h(i(s,".zibby.config.mjs"))&&!t.force&&(console.log(e.yellow(`
14
+ `));const g=!o.skipMemory,d=["dolt","mem0"].includes(String(o.memoryBackend||"").toLowerCase())?String(o.memoryBackend).toLowerCase():"dolt";await H();const a=l?D(process.cwd(),l):process.cwd(),_=l||"zibby-tests",f=!!l;f&&y(a)&&(console.log(e.red(`
15
+ \u274C Directory "${l}" already exists!
16
+ `)),process.exit(1)),!f&&y(s(a,".zibby.config.mjs"))&&!o.force&&(console.log(e.yellow(`
17
17
  \u26A0\uFE0F Zibby is already initialized in this directory!
18
18
  `)),console.log(e.white("Config file found: .zibby.config.mjs")),console.log(e.gray(`Use --force or -f to reinitialize
19
- `)),process.exit(0)),t.force&&!y&&console.log(e.cyan(`
19
+ `)),process.exit(0)),o.force&&!f&&console.log(e.cyan(`
20
20
  Reinitializing Zibby configuration...
21
- `));let n;if(t.agent&&(t.headed||t.headless))console.log(e.cyan(`Setting up with provided options...
22
- `)),n={agent:t.agent,browserMode:t.headless?"headless":"headed",apiKey:t.apiKey||null,cloudSync:!!(t.cloudSync||t.apiKey)};else{const b=[];t.agent||b.push({type:"select",name:"agent",message:"Which AI agent do you prefer?",choices:[{name:"Cursor",value:"cursor"},{name:"Claude (Anthropic)",value:"claude"},{name:"Codex (OpenAI)",value:"codex"},{name:"Gemini (Google)",value:"gemini"}],default:"cursor"}),!t.headed&&!t.headless&&b.push({type:"select",name:"browserMode",message:"Browser mode during live AI execution?",choices:[{name:"Headed - Visible browser (recommended for development)",value:"headed"},{name:"Headless - Hidden browser (for CI/CD)",value:"headless"}],default:"headed"}),t.apiKey||b.push({type:"input",name:"apiKey",message:"Enable cloud sync? Enter project ZIBBY_API_KEY (or press Enter to skip):"}),n=b.length>0?await K.prompt(b):{},n.agent=t.agent||n.agent,n.browserMode=t.headless?"headless":t.headed?"headed":n.browserMode,n.apiKey=t.apiKey||n.apiKey,n.cloudSync=!!(t.cloudSync||t.apiKey||n.apiKey&&n.apiKey.trim())}n.mcp="playwright",n.setupMcp=n.agent==="cursor";const p=P("Setting up Zibby...").start();try{if(y&&await A(s,{recursive:!0}),await A(i(s,"test-specs/examples"),{recursive:!0}),await A(i(s,"tests"),{recursive:!0}),await A(i(s,".zibby/output"),{recursive:!0}),await A(i(s,".zibby/commands"),{recursive:!0}),u&&d==="dolt")try{const{initMemory:o,DoltDB:l}=await import("@zibby/memory");if(l.isAvailable()){const{created:a}=o(s);a&&(p.text="Initialized test memory database (Dolt)...")}else p.text="Dolt not found \u2014 skipping memory database (brew install dolt)"}catch{}p.text="Scaffolding workflow graph...";const{TemplateFactory:b}=await import("@zibby/core/templates"),v=t.template||"browser-test-automation";try{const{graphPath:o,nodesPath:l,readmePath:a,resultHandlerPath:m,template:c}=b.getTemplateFiles(v),f=i(s,".zibby"),z=await w(o,"utf-8");if(await g(i(f,"graph.mjs"),z),m){const C=await w(m,"utf-8");await g(i(f,"result-handler.mjs"),C)}const B=await w(a,"utf-8");await g(i(f,"README.md"),B),await A(i(f,"nodes"),{recursive:!0});const{readdirSync:k}=await import("fs"),S=k(l);for(const C of S){let D=await w(i(l,C),"utf-8");!u&&C==="execute-live.mjs"&&(D=D.replace("skills: [SKILLS.BROWSER, SKILLS.MEMORY],","skills: [SKILLS.BROWSER],")),await g(i(f,"nodes",C),D)}const $=i(c.path,"chat.mjs");if(h($)){const C=await w($,"utf-8");await g(i(f,"chat.mjs"),C)}}catch(o){throw p.fail(`Failed to scaffold template: ${o.message}`),o}p.text="Generating configuration files...";const M=W(n,t,{memoryBackend:d});await g(i(s,".zibby.config.mjs"),M);const L=n.apiKey&&n.apiKey.trim()?V(n,n.apiKey.trim(),d):U(n,d);if(await g(i(s,".env.example"),L),y){const o=q(E,n,{memoryBackend:d});await g(i(s,"package.json"),o)}if(!h(i(s,".gitignore"))){const o=X();await g(i(s,".gitignore"),o)}if(!h(i(s,"playwright.config.js"))){const o=J("on");await g(i(s,"playwright.config.js"),o)}if(!h(i(s,"test-specs/examples/example-domain.txt"))){const o=Q();await g(i(s,"test-specs/examples/example-domain.txt"),o)}const R=Y(H,"../../../../examples/.zibby/commands");if(h(R)){const o=j(R).filter(l=>l.toLowerCase().endsWith(".md"));for(const l of o){const a=i(s,".zibby/commands",l);if(t.force||!h(a)){const m=await w(i(R,l),"utf-8");await g(a,m)}}}if(!h(i(s,".zibby/commands/example.md"))){const o=ee();await g(i(s,".zibby/commands/example.md"),o)}if(y){const o=te(E,n);await g(i(s,"README.md"),o)}if(p.succeed(y?"Project created!":"Zibby initialized!"),y&&!t.skipInstall){const o=P("Installing dependencies...").start();await new Promise((l,a)=>{T("npm",["install"],{cwd:s,stdio:"pipe"}).on("close",c=>{c===0?(o.succeed("Dependencies installed!"),l()):(o.fail("Failed to install dependencies"),a(new Error("npm install failed")))})})}else y||console.log(e.gray(`
21
+ `));let n;if(o.agent&&(o.headed||o.headless))console.log(e.cyan(`Setting up with provided options...
22
+ `)),n={agent:o.agent,browserMode:o.headless?"headless":"headed",apiKey:o.apiKey||null,cloudSync:!!(o.cloudSync||o.apiKey)};else{const b=[];o.agent||b.push({type:"select",name:"agent",message:"Which AI agent do you prefer?",choices:[{name:"Cursor",value:"cursor"},{name:"Claude (Anthropic)",value:"claude"},{name:"Codex (OpenAI)",value:"codex"},{name:"Gemini (Google)",value:"gemini"}],default:"cursor"}),!o.headed&&!o.headless&&b.push({type:"select",name:"browserMode",message:"Browser mode during live AI execution?",choices:[{name:"Headed - Visible browser (recommended for development)",value:"headed"},{name:"Headless - Hidden browser (for CI/CD)",value:"headless"}],default:"headed"}),o.apiKey||b.push({type:"input",name:"apiKey",message:"Enable cloud sync? Enter project ZIBBY_API_KEY (or press Enter to skip):"}),n=b.length>0?await O.prompt(b):{},n.agent=o.agent||n.agent,n.browserMode=o.headless?"headless":o.headed?"headed":n.browserMode,n.apiKey=o.apiKey||n.apiKey,n.cloudSync=!!(o.cloudSync||o.apiKey||n.apiKey&&n.apiKey.trim())}n.mcp="playwright",n.setupMcp=n.agent==="cursor";const p=P("Setting up Zibby...").start();try{if(f&&await C(a,{recursive:!0}),await C(s(a,"test-specs/examples"),{recursive:!0}),await C(s(a,"tests"),{recursive:!0}),await C(s(a,".zibby/output"),{recursive:!0}),await C(s(a,".zibby/commands"),{recursive:!0}),g&&d==="dolt")try{const{initMemory:t,DoltDB:r}=await import("@zibby/memory");if(r.isAvailable()){const{created:i}=t(a);i&&(p.text="Initialized test memory database (Dolt)...")}else p.text="Dolt not found \u2014 skipping memory database (brew install dolt)"}catch{}p.text="Scaffolding workflow graph...";const{TemplateFactory:b}=await import("@zibby/core/templates"),v=o.template||"browser-test-automation";try{const{graphPath:t,nodesPath:r,readmePath:i,resultHandlerPath:m,template:c}=b.getTemplateFiles(v),h=s(a,".zibby"),B=await w(t,"utf-8");if(await u(s(h,"graph.mjs"),B),m){const I=await w(m,"utf-8");await u(s(h,"result-handler.mjs"),I)}const z=await w(i,"utf-8");await u(s(h,"README.md"),z),await C(s(h,"nodes"),{recursive:!0});const{readdirSync:k}=await import("fs"),S=k(r);for(const I of S){let R=await w(s(r,I),"utf-8");!g&&I==="execute-live.mjs"&&(R=R.replace("skills: [SKILLS.BROWSER, SKILLS.MEMORY],","skills: [SKILLS.BROWSER],")),await u(s(h,"nodes",I),R)}const T=s(c.path,"chat.mjs");if(y(T)){const I=await w(T,"utf-8");await u(s(h,"chat.mjs"),I)}}catch(t){throw p.fail(`Failed to scaffold template: ${t.message}`),t}p.text="Generating configuration files...";const M=F(n,o,{memoryBackend:d});if(await u(s(a,".zibby.config.mjs"),M),await u(s(a,".env.example"),W(n,d)),n.apiKey&&n.apiKey.trim()){const t=s(a,".env"),r=n.apiKey.trim();if(y(t)){let i=await w(t,"utf8");/^ZIBBY_API_KEY=/m.test(i)?i=i.replace(/^ZIBBY_API_KEY=.*/m,`ZIBBY_API_KEY=${r}`):/^#\s*ZIBBY_API_KEY=/m.test(i)?i=i.replace(/^#\s*ZIBBY_API_KEY=.*/m,`ZIBBY_API_KEY=${r}`):i=i.trimEnd()+`
23
+
24
+ # Zibby Cloud Sync
25
+ ZIBBY_API_KEY=${r}
26
+ `,await u(t,i)}else await u(t,U(n,r,d))}if(f){const t=V(_,n,{memoryBackend:d});await u(s(a,"package.json"),t)}if(!y(s(a,".gitignore"))){const t=q();await u(s(a,".gitignore"),t)}if(!y(s(a,"playwright.config.js"))){const t=X("on");await u(s(a,"playwright.config.js"),t)}if(!y(s(a,"test-specs/examples/example-domain.txt"))){const t=J();await u(s(a,"test-specs/examples/example-domain.txt"),t)}const $=D(G,"../../../../examples/.zibby/commands");if(y($)){const t=L($).filter(r=>r.toLowerCase().endsWith(".md"));for(const r of t){const i=s(a,".zibby/commands",r);if(o.force||!y(i)){const m=await w(s($,r),"utf-8");await u(i,m)}}}if(!y(s(a,".zibby/commands/example.md"))){const t=Q();await u(s(a,".zibby/commands/example.md"),t)}if(f){const t=ee(_,n);await u(s(a,"README.md"),t)}if(p.succeed(f?"Project created!":"Zibby initialized!"),f&&!o.skipInstall){const t=P("Installing dependencies...").start();await new Promise((r,i)=>{Y("npm",["install"],{cwd:a,stdio:"pipe"}).on("close",c=>{c===0?(t.succeed("Dependencies installed!"),r()):(t.fail("Failed to install dependencies"),i(new Error("npm install failed")))})})}else f||console.log(e.gray(`
23
27
  Make sure @zibby/cli is installed in your package.json
24
- `));if(!y&&u&&d==="mem0"&&(console.log(e.yellow(`
28
+ `));if(!f&&g&&d==="mem0"&&(console.log(e.yellow(`
25
29
  Using mem0 backend requires mem0ai in your project dependencies.`)),console.log(e.gray("Run this manually in your project when ready:")),console.log(e.white(` npm install mem0ai
26
- `))),!t.skipInstall){const o=P("Installing Playwright browsers...").start();await new Promise(l=>{const a=T("npx",["playwright","install","chromium"],{cwd:s,stdio:"pipe"});let m="";a.stdout.on("data",c=>{m+=c.toString()}),a.stderr.on("data",c=>{m+=c.toString()}),a.on("close",c=>{c===0?(m.includes("already installed")||m.includes("up to date")?o.succeed("Playwright browsers already installed"):o.succeed("Playwright browsers installed!"),l()):(o.warn("Could not verify Playwright browsers"),console.log(e.yellow(`
30
+ `))),!o.skipInstall){const t=P("Installing Playwright browsers...").start();await new Promise(r=>{const i=Y("npx",["playwright","install","chromium"],{cwd:a,stdio:"pipe"});let m="";i.stdout.on("data",c=>{m+=c.toString()}),i.stderr.on("data",c=>{m+=c.toString()}),i.on("close",c=>{c===0?(m.includes("already installed")||m.includes("up to date")?t.succeed("Playwright browsers already installed"):t.succeed("Playwright browsers installed!"),r()):(t.warn("Could not verify Playwright browsers"),console.log(e.yellow(`
27
31
  \u26A0\uFE0F If tests fail, run: npx playwright install
28
- `)),l())})})}if(n.agent==="codex"&&!t.skipInstall){const o=P("Checking Codex CLI...").start();try{O("codex --version",{encoding:"utf-8",timeout:5e3,stdio:"pipe"}),o.succeed("Codex CLI already installed")}catch{o.text="Installing Codex CLI...";try{await new Promise((l,a)=>{T("npm",["install","-g","@openai/codex"],{stdio:"pipe"}).on("close",c=>{c===0?(o.succeed("Codex CLI installed!"),l()):a(new Error("npm install -g @openai/codex failed"))})})}catch{o.fail("Could not install Codex CLI"),console.log(e.yellow(` Install manually: npm install -g @openai/codex
29
- `))}}}if(n.agent==="gemini"&&!t.skipInstall){const o=P("Checking Gemini CLI...").start();try{O("gemini --version",{encoding:"utf-8",timeout:5e3,stdio:"pipe"}),o.succeed("Gemini CLI already installed")}catch{o.text="Installing Gemini CLI...";try{await new Promise((a,m)=>{T("npm",["install","-g","@google/gemini-cli"],{stdio:"pipe"}).on("close",f=>{f===0?(o.succeed("Gemini CLI installed!"),a()):m(new Error("npm install -g @google/gemini-cli failed"))})})}catch{o.fail("Could not install Gemini CLI"),console.log(e.yellow(` Install manually: npm install -g @google/gemini-cli
30
- `))}}const l=P("Configuring Gemini MCP servers...").start();try{const a=i(I(),".gemini"),m=i(a,"settings.json");h(a)||await A(a,{recursive:!0});let c={mcpServers:{}};if(h(m))try{const S=await w(m,"utf-8");c=JSON.parse(S),c.mcpServers||(c.mcpServers={})}catch{}let f;try{const{createRequire:S}=await import("module");f=S(import.meta.url).resolve("@zibby/mcp-browser/bin/mcp-browser-zibby.js")}catch{f="@playwright/mcp"}const z=n.browserMode!=="headless",B=f==="@playwright/mcp"?["-y","@playwright/mcp","--isolated","--save-video=1280x720","--viewport-size=1280x720","--output-dir","test-results"]:[f,"--isolated","--save-video=1280x720","--viewport-size=1280x720","--output-dir=test-results"];z||B.push("--headless"),c.mcpServers["playwright-official"]={command:f==="@playwright/mcp"?"npx":"node",args:B},await g(m,`${JSON.stringify(c,null,2)}
31
- `,"utf-8");let k="Gemini MCP configured";z?k+=" (headed mode - visible browser)":k+=" (headless mode - hidden browser)",l.succeed(k)}catch(a){l.fail("MCP setup failed"),console.log(e.yellow(" You may need to configure ~/.gemini/settings.json manually")),console.log(e.gray(` Error: ${a.message}
32
- `))}}if(n.agent==="cursor"&&n.setupMcp){const o=P("Setting up Playwright MCP...").start();try{const{setupPlaywrightMcpCommand:l}=await import("./setup-scripts.js"),a=n.cloudSync||!1,m=n.browserMode!=="headless";await l({headed:m,cloudSync:a,video:"on",viewport:{width:1280,height:720}});let c="Playwright MCP configured";m?c+=" (headed mode - visible browser)":c+=" (headless mode - hidden browser)",a&&(c+=" + Zibby MCP (cloud sync)"),o.succeed(c),a&&console.log(e.gray(`
32
+ `)),r())})})}if(n.agent==="codex"&&!o.skipInstall){const t=P("Checking Codex CLI...").start();try{K("codex --version",{encoding:"utf-8",timeout:5e3,stdio:"pipe"}),t.succeed("Codex CLI already installed")}catch{t.text="Installing Codex CLI...";try{await new Promise((r,i)=>{Y("npm",["install","-g","@openai/codex"],{stdio:"pipe"}).on("close",c=>{c===0?(t.succeed("Codex CLI installed!"),r()):i(new Error("npm install -g @openai/codex failed"))})})}catch{t.fail("Could not install Codex CLI"),console.log(e.yellow(` Install manually: npm install -g @openai/codex
33
+ `))}}}if(n.agent==="gemini"&&!o.skipInstall){const t=P("Checking Gemini CLI...").start();try{K("gemini --version",{encoding:"utf-8",timeout:5e3,stdio:"pipe"}),t.succeed("Gemini CLI already installed")}catch{t.text="Installing Gemini CLI...";try{await new Promise((i,m)=>{Y("npm",["install","-g","@google/gemini-cli"],{stdio:"pipe"}).on("close",h=>{h===0?(t.succeed("Gemini CLI installed!"),i()):m(new Error("npm install -g @google/gemini-cli failed"))})})}catch{t.fail("Could not install Gemini CLI"),console.log(e.yellow(` Install manually: npm install -g @google/gemini-cli
34
+ `))}}const r=P("Configuring Gemini MCP servers...").start();try{const i=s(A(),".gemini"),m=s(i,"settings.json");y(i)||await C(i,{recursive:!0});let c={mcpServers:{}};if(y(m))try{const S=await w(m,"utf-8");c=JSON.parse(S),c.mcpServers||(c.mcpServers={})}catch{}let h;try{const{createRequire:S}=await import("module");h=S(import.meta.url).resolve("@zibby/mcp-browser/bin/mcp-browser-zibby.js")}catch{h="@playwright/mcp"}const B=n.browserMode!=="headless",z=h==="@playwright/mcp"?["-y","@playwright/mcp","--isolated","--save-video=1280x720","--viewport-size=1280x720","--output-dir","test-results"]:[h,"--isolated","--save-video=1280x720","--viewport-size=1280x720","--output-dir=test-results"];B||z.push("--headless"),c.mcpServers["playwright-official"]={command:h==="@playwright/mcp"?"npx":"node",args:z},await u(m,`${JSON.stringify(c,null,2)}
35
+ `,"utf-8");let k="Gemini MCP configured";B?k+=" (headed mode - visible browser)":k+=" (headless mode - hidden browser)",r.succeed(k)}catch(i){r.fail("MCP setup failed"),console.log(e.yellow(" You may need to configure ~/.gemini/settings.json manually")),console.log(e.gray(` Error: ${i.message}
36
+ `))}}if(n.agent==="cursor"&&n.setupMcp){const t=P("Setting up Playwright MCP...").start();try{const{setupPlaywrightMcpCommand:r}=await import("./setup-scripts.js"),i=n.cloudSync||!1,m=n.browserMode!=="headless";await r({headed:m,cloudSync:i,video:"on",viewport:{width:1280,height:720}});let c="Playwright MCP configured";m?c+=" (headed mode - visible browser)":c+=" (headless mode - hidden browser)",i&&(c+=" + Zibby MCP (cloud sync)"),t.succeed(c),i&&!(n.apiKey&&n.apiKey.trim())&&console.log(e.gray(`
33
37
  Copy .env.example to .env and set ZIBBY_API_KEY to enable uploads
34
- `))}catch(l){o.fail("MCP setup script failed"),console.log(e.yellow(" Check if MCP is already configured:")),console.log(e.gray(' \u2022 Open Cursor settings \u2192 Check "playwright-official" MCP')),console.log(e.gray(" \u2022 Run: cursor-agent mcp list")),console.log(e.gray(` \u2022 Or run manually: zibby setup-playwright
35
- `)),console.log(e.gray(` Error: ${l.message}
38
+ `))}catch(r){t.fail("MCP setup script failed"),console.log(e.yellow(" Check if MCP is already configured:")),console.log(e.gray(' \u2022 Open Cursor settings \u2192 Check "playwright-official" MCP')),console.log(e.gray(" \u2022 Run: cursor-agent mcp list")),console.log(e.gray(` \u2022 Or run manually: zibby setup-playwright
39
+ `)),console.log(e.gray(` Error: ${r.message}
36
40
  `))}}console.log(e.bold.green(`
37
41
  \u{1F389} All set!
38
- `)),console.log(e.cyan("Start the Zibby Chat Agent:")),y&&console.log(e.white(` cd ${r}`)),console.log(e.white(` zibby
42
+ `)),console.log(e.cyan("Start the Zibby Chat Agent:")),f&&console.log(e.white(` cd ${l}`)),console.log(e.white(` zibby
39
43
  `)),console.log(e.cyan("Or run a test directly:")),console.log(e.white(` zibby run test-specs/examples/example-domain.txt
40
- `)),console.log(e.cyan("Next steps:"));let _=1;console.log(e.white(` ${_++}. cp .env.example .env ${e.gray("# then add your API keys")}`)),u&&console.log(e.white(` ${_++}. Set ${e.bold("ZIBBY_MEMORY_BACKEND")} in .env ${e.gray(`# currently: ${d}`)}`)),console.log(e.white(` ${_++}. Type ${e.bold("zibby")} to chat with the AI testing assistant`)),console.log(e.white(` ${_++}. Write test specs in test-specs/`)),console.log(e.white(` ${_++}. Run: npx zibby run <spec-file>
44
+ `)),console.log(e.cyan("Next steps:"));let E=1;console.log(e.white(` ${E++}. cp .env.example .env ${e.gray("# then add your API keys")}`)),g&&console.log(e.white(` ${E++}. Set ${e.bold("ZIBBY_MEMORY_BACKEND")} in .env ${e.gray(`# currently: ${d}`)}`)),console.log(e.white(` ${E++}. Type ${e.bold("zibby")} to chat with the AI testing assistant`)),console.log(e.white(` ${E++}. Write test specs in test-specs/`)),console.log(e.white(` ${E++}. Run: npx zibby run <spec-file>
41
45
  `))}catch(b){p.fail("Failed to create project"),console.error(e.red(`
42
46
  \u274C Error: ${b.message}
43
- `)),process.exit(1)}}function W(r,t={},u={}){const d=["dolt","mem0"].includes(String(u.memoryBackend||"").toLowerCase())?String(u.memoryBackend).toLowerCase():"dolt",s={claude:`
47
+ `)),process.exit(1)}}function F(l,o={},g={}){const d=["dolt","mem0"].includes(String(g.memoryBackend||"").toLowerCase())?String(g.memoryBackend).toLowerCase():"dolt",a={claude:`
44
48
  claude: {
45
49
  model: 'auto', // Options: 'auto', 'sonnet-4.6', 'opus-4.6', 'sonnet-4.5', 'opus-4.5'
46
50
  maxTokens: 4096,
@@ -53,13 +57,13 @@ Using mem0 backend requires mem0ai in your project dependencies.`)),console.log(
53
57
  },`,gemini:`
54
58
  gemini: {
55
59
  model: 'gemini-2.5-pro', // Options: 'auto', 'gemini-2.5-pro', 'gemini-2.5-flash'
56
- },`},E=r.agent,y=Object.entries(s).filter(([n])=>n!==E).map(([,n])=>n.split(`
60
+ },`},_=l.agent,f=Object.entries(a).filter(([n])=>n!==_).map(([,n])=>n.split(`
57
61
  `).map(x=>x.trim()?` // ${x.trimStart()}`:x).join(`
58
62
  `)).join(`
59
63
  `);return`export default {
60
64
  // AI agent settings
61
- agent: {${s[E]}
62
- ${y}
65
+ agent: {${a[_]}
66
+ ${f}
63
67
  strictMode: false,
64
68
  },
65
69
 
@@ -67,7 +71,7 @@ ${y}
67
71
  // and workflow config. Runtime strategies attach MCP per run (no global Gemini settings mutation).
68
72
  browser: {
69
73
  mcp: 'playwright',
70
- headless: ${r.browserMode==="headless"},
74
+ headless: ${l.browserMode==="headless"},
71
75
  },
72
76
 
73
77
  // Chat memory backend adapter (dolt | mem0)
@@ -120,13 +124,13 @@ ${y}
120
124
  },
121
125
 
122
126
  // Cloud sync - auto-upload test results & videos (requires ZIBBY_API_KEY in .env)
123
- cloudSync: ${r.cloudSync||!1}
127
+ cloudSync: ${l.cloudSync||!1}
124
128
  };
125
- `}function U(r,t="dolt"){return`# Zibby Test Automation - Environment Variables
129
+ `}function W(l,o="dolt"){return`# Zibby Test Automation - Environment Variables
126
130
 
127
131
  # AI Provider Keys
128
132
  ${{claude:"ANTHROPIC_API_KEY=sk-ant-your_key_here",cursor:`# Cursor Agent uses cursor-agent CLI \u2014 no API key needed
129
- # Install: curl https://cursor.com/install -fsS | bash`,codex:"OPENAI_API_KEY=sk-your_key_here",gemini:"GEMINI_API_KEY=your_key_here"}[r.agent]||""}
133
+ # Install: curl https://cursor.com/install -fsS | bash`,codex:"OPENAI_API_KEY=sk-your_key_here",gemini:"GEMINI_API_KEY=your_key_here"}[l.agent]||""}
130
134
 
131
135
  # Zibby Cloud Sync (for uploading test results & videos)
132
136
  # Get your API key from: https://zibby.app/settings/tokens
@@ -138,14 +142,14 @@ ${{claude:"ANTHROPIC_API_KEY=sk-ant-your_key_here",cursor:`# Cursor Agent uses c
138
142
  # ZIBBY_MEMORY_COMPACT_EVERY=1500 # Auto-compact every N runs (0 to disable)
139
143
 
140
144
  # Chat memory backend
141
- ZIBBY_MEMORY_BACKEND=${t}
142
- `}function V(r,t,u="dolt"){return`# Zibby Test Automation - Environment Variables
145
+ ZIBBY_MEMORY_BACKEND=${o}
146
+ `}function U(l,o,g="dolt"){return`# Zibby Test Automation - Environment Variables
143
147
 
144
148
  # AI Provider Keys
145
- ${{claude:"ANTHROPIC_API_KEY=sk-ant-your_key_here",cursor:"# Cursor Agent uses cursor-agent CLI \u2014 no API key needed",codex:"OPENAI_API_KEY=sk-your_key_here",gemini:"GEMINI_API_KEY=your_key_here"}[r.agent]||""}
149
+ ${{claude:"ANTHROPIC_API_KEY=sk-ant-your_key_here",cursor:"# Cursor Agent uses cursor-agent CLI \u2014 no API key needed",codex:"OPENAI_API_KEY=sk-your_key_here",gemini:"GEMINI_API_KEY=your_key_here"}[l.agent]||""}
146
150
 
147
151
  # Zibby Cloud Sync
148
- ZIBBY_API_KEY=${t}
152
+ ZIBBY_API_KEY=${o}
149
153
 
150
154
  # Test Memory (Dolt DB) - Auto-compaction settings
151
155
  # ZIBBY_MEMORY_MAX_RUNS=3000 # Max test runs to keep per spec
@@ -153,8 +157,8 @@ ZIBBY_API_KEY=${t}
153
157
  # ZIBBY_MEMORY_COMPACT_EVERY=1500 # Auto-compact every N runs (0 to disable)
154
158
 
155
159
  # Chat memory backend
156
- ZIBBY_MEMORY_BACKEND=${u}
157
- `}function q(r,t,u={}){const d={"@zibby/cli":"^0.1.25","@zibby/core":"^0.1.20"};return u.memoryBackend==="mem0"&&(d.mem0ai="^2.4.6"),JSON.stringify({name:r,version:"1.0.0",type:"module",private:!0,scripts:{"test:spec":"zibby run",test:"playwright test","test:headed":"playwright test --headed"},dependencies:d,devDependencies:{"@playwright/test":"^1.49.0",dotenv:"^17.2.3"}},null,2)}function X(){return`# Dependencies
160
+ ZIBBY_MEMORY_BACKEND=${g}
161
+ `}function V(l,o,g={}){const d={"@zibby/cli":"^0.1.25","@zibby/core":"^0.1.20"};return g.memoryBackend==="mem0"&&(d.mem0ai="^2.4.6"),JSON.stringify({name:l,version:"1.0.0",type:"module",private:!0,scripts:{"test:spec":"zibby run",test:"playwright test","test:headed":"playwright test --headed"},dependencies:d,devDependencies:{"@playwright/test":"^1.49.0",dotenv:"^17.2.3"}},null,2)}function q(){return`# Dependencies
158
162
  node_modules/
159
163
 
160
164
  # Test artifacts
@@ -182,11 +186,11 @@ Thumbs.db
182
186
  # Zibby memory (Dolt DB synced separately via dolt remote, not git)
183
187
  .zibby/memory/
184
188
  .zibby/memory-context.md
185
- `}function J(r="off",t=null){return`import { defineConfig} from '@playwright/test';
189
+ `}function X(l="off",o=null){return`import { defineConfig} from '@playwright/test';
186
190
 
187
191
  export default defineConfig({
188
192
  testDir: './tests',
189
- ${t?` outputDir: '${t}',
193
+ ${o?` outputDir: '${o}',
190
194
  `:` outputDir: 'test-results/playwright', // Keep Playwright artifacts separate from Zibby workflow output
191
195
  `} timeout: 30000,
192
196
  retries: 0,
@@ -204,7 +208,7 @@ ${t?` outputDir: '${t}',
204
208
  ['list']
205
209
  ],
206
210
  });
207
- `}function Q(){return`Test Specification: Example Domain Navigation
211
+ `}function J(){return`Test Specification: Example Domain Navigation
208
212
  ==============================================
209
213
 
210
214
  Application: Example Domain
@@ -241,7 +245,7 @@ Notes:
241
245
  - Uses a stable, public domain (example.com) maintained by IANA
242
246
  - No authentication required
243
247
  - Suitable for CI/CD smoke testing
244
- `}function ee(){return`# Example command template
248
+ `}function Q(){return`# Example command template
245
249
 
246
250
  Use this command when the user asks for a concise testing task breakdown.
247
251
 
@@ -252,7 +256,7 @@ Required output format:
252
256
  4. Expected result
253
257
 
254
258
  Keep the response actionable and short.
255
- `}function te(r,t){return`# ${r}
259
+ `}function ee(l,o){return`# ${l}
256
260
 
257
261
  AI-powered test automation with Zibby.
258
262
 
@@ -266,7 +270,7 @@ npm install
266
270
  2. Configure environment:
267
271
  \`\`\`bash
268
272
  cp .env.example .env
269
- # Edit .env and add your ${{claude:"ANTHROPIC_API_KEY",codex:"OPENAI_API_KEY",gemini:"GEMINI_API_KEY",cursor:"CURSOR_API_KEY (optional)"}[t.agent]}
273
+ # Edit .env and add your ${{claude:"ANTHROPIC_API_KEY",codex:"OPENAI_API_KEY",gemini:"GEMINI_API_KEY",cursor:"CURSOR_API_KEY (optional)"}[o.agent]}
270
274
  \`\`\`
271
275
 
272
276
  3. Run example test:
@@ -317,13 +321,13 @@ npx playwright test --ui
317
321
  Edit \`.zibby.config.mjs\` to customize:
318
322
  - Agent settings (model, temperature)
319
323
  - Browser settings (headless, viewport)
320
- - Cloud sync${t.cloudSync?" (enabled)":" (disabled)"}
324
+ - Cloud sync${o.cloudSync?" (enabled)":" (disabled)"}
321
325
  - Self-healing behavior
322
326
 
323
327
  ## Project Structure
324
328
 
325
329
  \`\`\`
326
- ${r}/
330
+ ${l}/
327
331
  \u251C\u2500\u2500 .zibby/
328
332
  \u2502 \u251C\u2500\u2500 graph.mjs # Workflow definition
329
333
  \u2502 \u251C\u2500\u2500 nodes/ # Custom nodes
@@ -341,4 +345,4 @@ ${r}/
341
345
 
342
346
  - Documentation: https://docs.zibby.dev
343
347
  - Examples: https://github.com/zibby/examples
344
- `}export{me as initCommand};
348
+ `}export{de as initCommand};
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zibby/cli",
3
- "version": "0.1.37",
3
+ "version": "0.1.39",
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.37",
3
+ "version": "0.1.39",
4
4
  "description": "Zibby CLI - Test automation generator and runner",
5
5
  "type": "module",
6
6
  "bin": {