@zibby/cli 0.1.49 → 0.1.51

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,10 +1,10 @@
1
- import{mkdir as S,writeFile as p,readFile as w}from"fs/promises";import{existsSync as h,readdirSync as G}from"fs";import{join as a,resolve as O,dirname as H}from"path";import{homedir as P}from"os";import Y from"inquirer";import e from"chalk";import I from"ora";import{spawn as K,execSync as R}from"child_process";import{fileURLToPath as V}from"url";import{createRequire as Z}from"module";import{AGENT_KEY_MAP as D,saveAgentApiKey as F,readGlobalConfig as W}from"../utils/agent-credentials.js";const U=V(import.meta.url),q=H(U),N=Z(import.meta.url);async function X(){try{const d=process.platform==="win32",o=R("npm config get prefix",{encoding:"utf-8"}).trim(),y=d?o:`${o}/bin`,m=y.replace(/^~/,P()),l=d?";":":";if(process.env.PATH.split(l).some(f=>{const x=f.replace(/^~/,P());return x===m||x===y}))return;if(process.env.CI||process.env.ZIBBY_CI||!process.stdin.isTTY){console.log(e.yellow("\u26A0\uFE0F npm global bin not in PATH")),console.log(e.gray(` Location: ${m}`)),console.log(e.gray(` Add it manually: export PATH="${m}:$PATH"
1
+ import{mkdir as S,writeFile as p,readFile as w}from"fs/promises";import{existsSync as h,readdirSync as G}from"fs";import{join as a,resolve as O,dirname as H}from"path";import{homedir as P}from"os";import Y from"inquirer";import e from"chalk";import I from"ora";import{spawn as K,execSync as R}from"child_process";import{fileURLToPath as V}from"url";import{createRequire as Z}from"module";import{AGENT_KEY_MAP as D,saveAgentApiKey as F,readGlobalConfig as W}from"../utils/agent-credentials.js";const U=V(import.meta.url),q=H(U),N=Z(import.meta.url);async function X(){try{const d=process.platform==="win32",o=R("npm config get prefix",{encoding:"utf-8"}).trim(),f=d?o:`${o}/bin`,m=f.replace(/^~/,P()),l=d?";":":";if(process.env.PATH.split(l).some(y=>{const x=y.replace(/^~/,P());return x===m||x===f}))return;if(process.env.CI||process.env.ZIBBY_CI||!process.stdin.isTTY){console.log(e.yellow("\u26A0\uFE0F npm global bin not in PATH")),console.log(e.gray(` Location: ${m}`)),console.log(e.gray(` Add it manually: export PATH="${m}:$PATH"
2
2
  `));return}console.log(e.yellow("\u26A0\uFE0F npm global bin not in PATH")),console.log(e.gray(` Location: ${m}`)),console.log();const{shouldAddPath:s}=await Y.prompt([{type:"confirm",name:"shouldAddPath",message:"Add npm global bin to your shell PATH automatically?",default:!0}]);if(!s){d?(console.log(e.gray(`
3
3
  \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: ${m}
4
4
  `))):(console.log(e.gray(`
5
5
  \u{1F4A1} To add manually, run:`)),console.log(e.gray(` echo 'export PATH="${m}:$PATH"' >> ~/.zshrc`)),console.log(e.gray(` source ~/.zshrc
6
6
  `)));return}if(d){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: ${m}
7
- `));return}const A=process.env.SHELL||"";let g="";if(A.includes("zsh"))g=a(P(),".zshrc");else if(A.includes("bash"))g=h(a(P(),".bashrc"))?a(P(),".bashrc"):a(P(),".bash_profile");else{console.log(e.yellow(`\u26A0\uFE0F Unknown shell: ${A}`)),console.log(e.gray(" Please add manually:")),console.log(e.gray(` export PATH="${m}:$PATH"`));return}if(h(g)){const f=await w(g,"utf-8");if(f.includes(m)||f.includes("npm")&&f.includes("global")&&f.includes("bin")){console.log(e.yellow(`\u26A0\uFE0F PATH entry found in ${g} but not active`)),console.log(e.gray(` Run: source ${g}
7
+ `));return}const C=process.env.SHELL||"";let g="";if(C.includes("zsh"))g=a(P(),".zshrc");else if(C.includes("bash"))g=h(a(P(),".bashrc"))?a(P(),".bashrc"):a(P(),".bash_profile");else{console.log(e.yellow(`\u26A0\uFE0F Unknown shell: ${C}`)),console.log(e.gray(" Please add manually:")),console.log(e.gray(` export PATH="${m}:$PATH"`));return}if(h(g)){const y=await w(g,"utf-8");if(y.includes(m)||y.includes("npm")&&y.includes("global")&&y.includes("bin")){console.log(e.yellow(`\u26A0\uFE0F PATH entry found in ${g} but not active`)),console.log(e.gray(` Run: source ${g}
8
8
  `));return}}const v=`
9
9
  # npm global bin (added by zibby)
10
10
  export PATH="${m}:$PATH"
@@ -12,7 +12,7 @@ export PATH="${m}:$PATH"
12
12
  \u{1F4A1} Run this to activate in current session:`)),console.log(e.gray(` source ${g}
13
13
  `))}catch{}}async function be(d,o){console.log(e.bold.cyan(`
14
14
  \u{1F3AD} Welcome to Zibby Test Automation!
15
- `));const y=!o.skipMemory,m=["dolt","mem0"].includes(String(o.memoryBackend||"").toLowerCase())?String(o.memoryBackend).toLowerCase():"dolt";await X();const l=d?O(process.cwd(),d):process.cwd(),$=d||"zibby-tests",b=!!d;b&&h(l)&&(console.log(e.red(`
15
+ `));const f=!o.skipMemory,m=["dolt","mem0"].includes(String(o.memoryBackend||"").toLowerCase())?String(o.memoryBackend).toLowerCase():"dolt";await X();const l=d?O(process.cwd(),d):process.cwd(),$=d||"zibby-tests",b=!!d;b&&h(l)&&(console.log(e.red(`
16
16
  \u274C Directory "${d}" already exists!
17
17
  `)),process.exit(1)),!b&&h(a(l,".zibby.config.mjs"))&&!o.force&&(console.log(e.yellow(`
18
18
  \u26A0\uFE0F Zibby is already initialized in this directory!
@@ -20,7 +20,7 @@ export PATH="${m}:$PATH"
20
20
  `)),process.exit(0)),o.force&&!b&&console.log(e.cyan(`
21
21
  Reinitializing Zibby configuration...
22
22
  `));let s;if(o.agent&&(o.headed||o.headless))console.log(e.cyan(`Setting up with provided options...
23
- `)),s={agent:o.agent,browserMode:o.headless?"headless":"headed",apiKey:o.apiKey||null,cloudSync:!!(o.cloudSync||o.apiKey)};else{if(o.agent)s={agent:o.agent};else{const{agent:C}=await Y.prompt([{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"}]);s={agent:C}}const f=D[s.agent];if(f&&!o.agentKey&&!(process.env.CI||process.env.ZIBBY_CI||!process.stdin.isTTY)){const C=process.env[f.envVar]||W().agentApiKey,B=C?`***${C.slice(-4)}`:null,E=B?`${f.label} found (${B}). Press Enter to keep, or paste a new key:`:`Enter ${f.label} (from ${f.url}, or press Enter to skip):`,{agentKey:t}=await Y.prompt([{type:"password",name:"agentKey",message:E,mask:"*"}]);t&&t.trim()&&(s.agentKey=t.trim())}const x=[];if(!o.headed&&!o.headless&&x.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||x.push({type:"input",name:"apiKey",message:"Enable cloud sync? Enter project ZIBBY_API_KEY (or press Enter to skip):"}),x.length>0){const C=await Y.prompt(x);Object.assign(s,C)}s.browserMode=o.headless?"headless":o.headed?"headed":s.browserMode,s.apiKey=o.apiKey||s.apiKey,s.cloudSync=!!(o.cloudSync||o.apiKey||s.apiKey&&s.apiKey.trim())}o.agentKey&&(s.agentKey=o.agentKey);const g=D[s.agent];s.agentKey&&(F(s.agentKey),console.log(e.gray(" \u2713 Agent API key saved to ~/.zibby/config.json"))),s.mcp="playwright",s.setupMcp=s.agent==="cursor";const v=I("Setting up Zibby...").start();try{if(b&&await S(l,{recursive:!0}),await S(a(l,"test-specs/examples"),{recursive:!0}),await S(a(l,"tests"),{recursive:!0}),await S(a(l,".zibby/output"),{recursive:!0}),await S(a(l,".zibby/commands"),{recursive:!0}),y&&m==="dolt")try{const{initMemory:t,DoltDB:i}=await import("@zibby/memory");if(i.isAvailable()){const{created:n}=t(l);n&&(v.text="Initialized test memory database (Dolt)...")}else v.text="Dolt not found \u2014 skipping memory database (brew install dolt)"}catch{}v.text="Scaffolding workflow graph...";const{TemplateFactory:f}=await import("@zibby/core/templates"),x=o.template||"browser-test-automation";try{const{graphPath:t,nodesPath:i,readmePath:n,resultHandlerPath:c,template:r}=f.getTemplateFiles(x),u=a(l,".zibby"),M=await w(t,"utf-8");if(await p(a(u,"graph.mjs"),M),c){const k=await w(c,"utf-8");await p(a(u,"result-handler.mjs"),k)}const z=await w(n,"utf-8");await p(a(u,"README.md"),z),await S(a(u,"nodes"),{recursive:!0});const{readdirSync:_}=await import("fs"),T=_(i);for(const k of T){let j=await w(a(i,k),"utf-8");!y&&k==="execute-live.mjs"&&(j=j.replace("skills: [SKILLS.BROWSER, SKILLS.MEMORY],","skills: [SKILLS.BROWSER],")),await p(a(u,"nodes",k),j)}const L=a(r.path,"chat.mjs");if(h(L)){const k=await w(L,"utf-8");await p(a(u,"chat.mjs"),k)}}catch(t){throw v.fail(`Failed to scaffold template: ${t.message}`),t}v.text="Generating configuration files...";const C=J(s,o,{memoryBackend:m});if(await p(a(l,".zibby.config.mjs"),C),await p(a(l,".env.example"),Q(s,m)),s.apiKey&&s.apiKey.trim()){const t=a(l,".env"),i=s.apiKey.trim();if(h(t)){let n=await w(t,"utf8");/^ZIBBY_API_KEY=/m.test(n)?n=n.replace(/^ZIBBY_API_KEY=.*/m,`ZIBBY_API_KEY=${i}`):/^#\s*ZIBBY_API_KEY=/m.test(n)?n=n.replace(/^#\s*ZIBBY_API_KEY=.*/m,`ZIBBY_API_KEY=${i}`):n=`${n.trimEnd()}
23
+ `)),s={agent:o.agent,browserMode:o.headless?"headless":"headed",apiKey:o.apiKey||null,cloudSync:!!(o.cloudSync||o.apiKey)};else{if(o.agent)s={agent:o.agent};else{const{agent:E}=await Y.prompt([{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"}]);s={agent:E}}const y=D[s.agent];if(y&&!o.agentKey&&!(process.env.CI||process.env.ZIBBY_CI||!process.stdin.isTTY)){const E=W(),B=process.env[y.envVar]||E.agentKeys?.[y.envVar],A=B?`***${B.slice(-4)}`:null,t=A?`${y.label} found (${A}). Press Enter to keep, or paste a new key:`:`Enter ${y.label} (from ${y.url}, or press Enter to skip):`,{agentKey:i}=await Y.prompt([{type:"password",name:"agentKey",message:t,mask:"*"}]);i&&i.trim()&&(s.agentKey=i.trim())}const x=[];if(!o.headed&&!o.headless&&x.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||x.push({type:"input",name:"apiKey",message:"Enable cloud sync? Enter project ZIBBY_API_KEY (or press Enter to skip):"}),x.length>0){const E=await Y.prompt(x);Object.assign(s,E)}s.browserMode=o.headless?"headless":o.headed?"headed":s.browserMode,s.apiKey=o.apiKey||s.apiKey,s.cloudSync=!!(o.cloudSync||o.apiKey||s.apiKey&&s.apiKey.trim())}o.agentKey&&(s.agentKey=o.agentKey);const g=D[s.agent];s.agentKey&&(F(s.agentKey,s.agent),console.log(e.gray(" \u2713 Agent API key saved to ~/.zibby/config.json"))),s.mcp="playwright",s.setupMcp=s.agent==="cursor";const v=I("Setting up Zibby...").start();try{if(b&&await S(l,{recursive:!0}),await S(a(l,"test-specs/examples"),{recursive:!0}),await S(a(l,"tests"),{recursive:!0}),await S(a(l,".zibby/output"),{recursive:!0}),await S(a(l,".zibby/commands"),{recursive:!0}),f&&m==="dolt")try{const{initMemory:t,DoltDB:i}=await import("@zibby/memory");if(i.isAvailable()){const{created:n}=t(l);n&&(v.text="Initialized test memory database (Dolt)...")}else v.text="Dolt not found \u2014 skipping memory database (brew install dolt)"}catch{}v.text="Scaffolding workflow graph...";const{TemplateFactory:y}=await import("@zibby/core/templates"),x=o.template||"browser-test-automation";try{const{graphPath:t,nodesPath:i,readmePath:n,resultHandlerPath:c,template:r}=y.getTemplateFiles(x),u=a(l,".zibby"),M=await w(t,"utf-8");if(await p(a(u,"graph.mjs"),M),c){const k=await w(c,"utf-8");await p(a(u,"result-handler.mjs"),k)}const z=await w(n,"utf-8");await p(a(u,"README.md"),z),await S(a(u,"nodes"),{recursive:!0});const{readdirSync:_}=await import("fs"),T=_(i);for(const k of T){let j=await w(a(i,k),"utf-8");!f&&k==="execute-live.mjs"&&(j=j.replace("skills: [SKILLS.BROWSER, SKILLS.MEMORY],","skills: [SKILLS.BROWSER],")),await p(a(u,"nodes",k),j)}const L=a(r.path,"chat.mjs");if(h(L)){const k=await w(L,"utf-8");await p(a(u,"chat.mjs"),k)}}catch(t){throw v.fail(`Failed to scaffold template: ${t.message}`),t}v.text="Generating configuration files...";const E=J(s,o,{memoryBackend:m});if(await p(a(l,".zibby.config.mjs"),E),await p(a(l,".env.example"),Q(s,m)),s.apiKey&&s.apiKey.trim()){const t=a(l,".env"),i=s.apiKey.trim();if(h(t)){let n=await w(t,"utf8");/^ZIBBY_API_KEY=/m.test(n)?n=n.replace(/^ZIBBY_API_KEY=.*/m,`ZIBBY_API_KEY=${i}`):/^#\s*ZIBBY_API_KEY=/m.test(n)?n=n.replace(/^#\s*ZIBBY_API_KEY=.*/m,`ZIBBY_API_KEY=${i}`):n=`${n.trimEnd()}
24
24
 
25
25
  # Zibby Cloud Sync
26
26
  ZIBBY_API_KEY=${i}
@@ -31,7 +31,7 @@ ${g.envVar}=${i}
31
31
  `,await p(t,n)}}if(b){const t=te($,s,{memoryBackend:m});await p(a(l,"package.json"),t)}if(!h(a(l,".gitignore"))){const t=ne();await p(a(l,".gitignore"),t)}if(!h(a(l,"playwright.config.js"))){const t=oe("on");await p(a(l,"playwright.config.js"),t)}if(!h(a(l,"test-specs/examples/example-domain.txt"))){const t=se();await p(a(l,"test-specs/examples/example-domain.txt"),t)}const B=O(q,"../../../../examples/.zibby/commands");if(h(B)){const t=G(B).filter(i=>i.toLowerCase().endsWith(".md"));for(const i of t){const n=a(l,".zibby/commands",i);if(o.force||!h(n)){const c=await w(a(B,i),"utf-8");await p(n,c)}}}if(!h(a(l,".zibby/commands/example.md"))){const t=ie();await p(a(l,".zibby/commands/example.md"),t)}if(b){const t=ae($,s);await p(a(l,"README.md"),t)}if(v.succeed(b?"Project created!":"Zibby initialized!"),b&&!o.skipInstall){const t=I("Installing dependencies...").start();await new Promise((i,n)=>{K("npm",["install"],{cwd:l,stdio:"pipe"}).on("close",r=>{r===0?(t.succeed("Dependencies installed!"),i()):(t.fail("Failed to install dependencies"),n(new Error("npm install failed")))})})}else if(!b){const t=["@zibby/cli","@zibby/core"],i=[];for(const n of t)try{Z(a(l,"package.json")).resolve(`${n}/package.json`)}catch{i.push(n)}if(i.length>0){const n=N("../../package.json"),c=i.map(r=>r==="@zibby/cli"?`${r}@latest`:r==="@zibby/core"?`${r}@${n.dependencies?.["@zibby/core"]||"^0.1.29"}`:r);if(o.skipInstall)console.log(e.yellow(`
32
32
  Missing required Zibby dependencies in this project:`)),console.log(e.white(` ${i.join(", ")}`)),console.log(e.gray("Install them manually to avoid runtime errors:")),console.log(e.white(` npm install --save-dev ${c.join(" ")}
33
33
  `));else{const r=I(`Installing ${c.join(", ")}...`).start();await new Promise(M=>{K("npm",["install","--save-dev",...c],{cwd:l,stdio:"pipe"}).on("close",_=>M(_??1))})===0?r.succeed("Installed missing Zibby dependencies"):(r.warn("Could not auto-install Zibby dependencies"),console.log(e.gray("Run this manually:")),console.log(e.white(` npm install --save-dev ${c.join(" ")}
34
- `)))}}}if(!b&&y&&m==="mem0"&&(console.log(e.yellow(`
34
+ `)))}}}if(!b&&f&&m==="mem0"&&(console.log(e.yellow(`
35
35
  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
36
36
  `))),!o.skipInstall){const t=I("Installing Playwright browsers...").start();await new Promise(i=>{const n=K("npx",["playwright","install","chromium"],{cwd:l,stdio:"pipe"});let c="";n.stdout.on("data",r=>{c+=r.toString()}),n.stderr.on("data",r=>{c+=r.toString()}),n.on("close",r=>{r===0?(c.includes("already installed")||c.includes("up to date")?t.succeed("Playwright browsers already installed"):t.succeed("Playwright browsers installed!"),i()):(t.warn("Could not verify Playwright browsers"),console.log(e.yellow(`
37
37
  \u26A0\uFE0F If tests fail, run: npx playwright install
@@ -48,10 +48,10 @@ Using mem0 backend requires mem0ai in your project dependencies.`)),console.log(
48
48
  \u{1F389} All set!
49
49
  `)),console.log(e.cyan("Start the Zibby Chat Agent:")),b&&console.log(e.white(` cd ${d}`)),console.log(e.white(` zibby
50
50
  `)),console.log(e.cyan("Or run a test directly:")),console.log(e.white(` zibby run test-specs/examples/example-domain.txt
51
- `)),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")}`)),y&&console.log(e.white(` ${E++}. Set ${e.bold("ZIBBY_MEMORY_BACKEND")} in .env ${e.gray(`# currently: ${m}`)}`)),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>
52
- `))}catch(f){v.fail("Failed to create project"),console.error(e.red(`
53
- \u274C Error: ${f.message}
54
- `)),process.exit(1)}}function J(d,o={},y={}){const m=["dolt","mem0"].includes(String(y.memoryBackend||"").toLowerCase())?String(y.memoryBackend).toLowerCase():"dolt",l={claude:`
51
+ `)),console.log(e.cyan("Next steps:"));let A=1;console.log(e.white(` ${A++}. cp .env.example .env ${e.gray("# then add your API keys")}`)),f&&console.log(e.white(` ${A++}. Set ${e.bold("ZIBBY_MEMORY_BACKEND")} in .env ${e.gray(`# currently: ${m}`)}`)),console.log(e.white(` ${A++}. Type ${e.bold("zibby")} to chat with the AI testing assistant`)),console.log(e.white(` ${A++}. Write test specs in test-specs/`)),console.log(e.white(` ${A++}. Run: npx zibby run <spec-file>
52
+ `))}catch(y){v.fail("Failed to create project"),console.error(e.red(`
53
+ \u274C Error: ${y.message}
54
+ `)),process.exit(1)}}function J(d,o={},f={}){const m=["dolt","mem0"].includes(String(f.memoryBackend||"").toLowerCase())?String(f.memoryBackend).toLowerCase():"dolt",l={claude:`
55
55
  claude: {
56
56
  model: 'auto', // Options: 'auto', 'sonnet-4.6', 'opus-4.6', 'sonnet-4.5', 'opus-4.5'
57
57
  maxTokens: 4096,
@@ -65,7 +65,7 @@ Using mem0 backend requires mem0ai in your project dependencies.`)),console.log(
65
65
  gemini: {
66
66
  model: 'gemini-2.5-pro', // Options: 'auto', 'gemini-2.5-pro', 'gemini-2.5-flash'
67
67
  },`},$=d.agent,b=Object.entries(l).filter(([s])=>s!==$).map(([,s])=>s.split(`
68
- `).map(A=>A.trim()?` // ${A.trimStart()}`:A).join(`
68
+ `).map(C=>C.trim()?` // ${C.trimStart()}`:C).join(`
69
69
  `)).join(`
70
70
  `);return`export default {
71
71
  // AI agent settings
@@ -150,7 +150,7 @@ ${{claude:"ANTHROPIC_API_KEY=sk-ant-your_key_here",cursor:`# Cursor Agent uses c
150
150
 
151
151
  # Chat memory backend
152
152
  ZIBBY_MEMORY_BACKEND=${o}
153
- `}function ee(d,o,y="dolt"){return`# Zibby Test Automation - Environment Variables
153
+ `}function ee(d,o,f="dolt"){return`# Zibby Test Automation - Environment Variables
154
154
 
155
155
  # AI Provider Keys
156
156
  ${{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"}[d.agent]||""}
@@ -164,8 +164,8 @@ ZIBBY_API_KEY=${o}
164
164
  # ZIBBY_MEMORY_COMPACT_EVERY=1500 # Auto-compact every N runs (0 to disable)
165
165
 
166
166
  # Chat memory backend
167
- ZIBBY_MEMORY_BACKEND=${y}
168
- `}function te(d,o,y={}){const l={"@zibby/cli":"latest","@zibby/core":N("../../package.json").dependencies?.["@zibby/core"]||"^0.1.29"};return y.memoryBackend==="mem0"&&(l.mem0ai="^2.4.6"),JSON.stringify({name:d,version:"1.0.0",type:"module",private:!0,scripts:{"test:spec":"zibby run",test:"playwright test","test:headed":"playwright test --headed"},dependencies:l,devDependencies:{"@playwright/test":"^1.49.0",dotenv:"^17.2.3"}},null,2)}function ne(){return`# Dependencies
167
+ ZIBBY_MEMORY_BACKEND=${f}
168
+ `}function te(d,o,f={}){const l={"@zibby/cli":"latest","@zibby/core":N("../../package.json").dependencies?.["@zibby/core"]||"^0.1.29"};return f.memoryBackend==="mem0"&&(l.mem0ai="^2.4.6"),JSON.stringify({name:d,version:"1.0.0",type:"module",private:!0,scripts:{"test:spec":"zibby run",test:"playwright test","test:headed":"playwright test --headed"},dependencies:l,devDependencies:{"@playwright/test":"^1.49.0",dotenv:"^17.2.3"}},null,2)}function ne(){return`# Dependencies
169
169
  node_modules/
170
170
 
171
171
  # Test artifacts
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zibby/cli",
3
- "version": "0.1.49",
3
+ "version": "0.1.51",
4
4
  "description": "Zibby CLI - Test automation generator and runner",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,2 +1,3 @@
1
- import{existsSync as s,readFileSync as a,writeFileSync as u,mkdirSync as g}from"fs";import{join as o}from"path";import{homedir as i}from"os";const l={cursor:{envVar:"CURSOR_API_KEY",label:"Cursor API Key",url:"https://cursor.com/settings"},claude:{envVar:"ANTHROPIC_API_KEY",label:"Anthropic API Key",url:"https://console.anthropic.com/settings/keys"},codex:{envVar:"OPENAI_API_KEY",label:"OpenAI API Key",url:"https://platform.openai.com/api-keys"},gemini:{envVar:"GEMINI_API_KEY",label:"Gemini API Key",url:"https://aistudio.google.com/app/apikey"}};function p(){return o(i(),".zibby","config.json")}function f(){try{const t=p();return s(t)?JSON.parse(a(t,"utf-8")):{}}catch{return{}}}function I(t){const r=o(i(),".zibby");g(r,{recursive:!0});const e=p(),n=f();n.agentApiKey=String(t).trim(),u(e,`${JSON.stringify(n,null,2)}
2
- `,"utf-8")}function y(t){const r=[o(t,".zibby.config.mjs"),o(i(),".zibby.config.mjs")];for(const e of r)if(s(e))try{const n=a(e,"utf-8");for(const c of["cursor","claude","codex","gemini"])if(new RegExp(`agent\\s*:\\s*\\{[^}]*${c}\\s*:`,"s").test(n))return c}catch{}return null}function K(t){const r=y(t||process.cwd());if(!r)return;const e=l[r];if(!e||process.env[e.envVar])return;const n=f();n.agentApiKey&&(process.env[e.envVar]=n.agentApiKey)}export{l as AGENT_KEY_MAP,K as bootstrapAgentEnv,y as detectAgentType,f as readGlobalConfig,I as saveAgentApiKey};
1
+ import{existsSync as a,readFileSync as f,writeFileSync as b,mkdirSync as h}from"fs";import{join as i}from"path";import{homedir as u}from"os";const m={cursor:{envVar:"CURSOR_API_KEY",label:"Cursor API Key",url:"https://cursor.com/settings"},claude:{envVar:"ANTHROPIC_API_KEY",label:"Anthropic API Key",url:"https://console.anthropic.com/settings/keys"},codex:{envVar:"OPENAI_API_KEY",label:"OpenAI API Key",url:"https://platform.openai.com/api-keys"},gemini:{envVar:"GEMINI_API_KEY",label:"Gemini API Key",url:"https://aistudio.google.com/app/apikey"}};function v(){return i(u(),".zibby","config.json")}function A(){try{const n=v();return a(n)?JSON.parse(f(n,"utf-8")):{}}catch{return{}}}function V(n,r){const o=i(u(),".zibby");h(o,{recursive:!0});const t=v(),e=A(),s=r?m[r]:null;s&&((!e.agentKeys||typeof e.agentKeys!="object")&&(e.agentKeys={}),e.agentKeys[s.envVar]=String(n).trim()),delete e.agentApiKey,b(t,`${JSON.stringify(e,null,2)}
2
+ `,"utf-8")}function I(n){const r=[i(n,".zibby.config.mjs"),i(u(),".zibby.config.mjs")];for(const o of r)if(a(o))try{const t=f(o,"utf-8");for(const e of["cursor","claude","codex","gemini"])if(new RegExp(`agent\\s*:\\s*\\{[^}]*${e}\\s*:`,"s").test(t))return e}catch{}return null}function _(n){const r=n||process.cwd(),o=I(r);if(!o)return;const t=m[o];if(!t||process.env[t.envVar])return;const e=[i(r,".env.local"),i(r,".env")];for(const l of e)if(a(l))try{for(const d of f(l,"utf-8").split(`
3
+ `)){const c=d.trim();if(c.startsWith("#")||!c.includes("="))continue;const y=c.indexOf("="),K=c.slice(0,y).trim(),g=c.slice(y+1).trim();if(K===t.envVar&&g){process.env[t.envVar]=g;return}}}catch{}const p=A().agentKeys?.[t.envVar];p&&(process.env[t.envVar]=p)}export{m as AGENT_KEY_MAP,_ as bootstrapAgentEnv,I as detectAgentType,A as readGlobalConfig,V as saveAgentApiKey};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zibby/cli",
3
- "version": "0.1.49",
3
+ "version": "0.1.51",
4
4
  "description": "Zibby CLI - Test automation generator and runner",
5
5
  "type": "module",
6
6
  "bin": {