@fasttest-ai/qa-agent 1.0.1 → 1.0.3

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.
package/dist/install.js CHANGED
@@ -1,18 +1,18 @@
1
- import{execFileSync as y}from"node:child_process";import{createInterface as M}from"node:readline";import{existsSync as a,mkdirSync as b,readFileSync as u,writeFileSync as f,unlinkSync as N,copyFileSync as _}from"node:fs";import{homedir as g,platform as j}from"node:os";import{join as i,dirname as O}from"node:path";import{fileURLToPath as T}from"node:url";var C=j()==="win32",D=j()==="darwin",l="fasttest",F=C?"npx.cmd":"npx",$="npx",I=["-y","@fasttest-ai/qa-agent@latest"],v=[{id:"claude-code",label:"Claude Code",globalConfigPath:"",format:"cli",hasPermissions:!0},{id:"cursor",label:"Cursor",globalConfigPath:i(g(),".cursor","mcp.json"),format:"json-mcpServers",hasPermissions:!1},{id:"windsurf",label:"Windsurf",globalConfigPath:i(g(),".codeium","windsurf","mcp_config.json"),format:"json-mcpServers",hasPermissions:!1},{id:"vscode",label:"VS Code / Copilot",globalConfigPath:D?i(g(),"Library","Application Support","Code","User","mcp.json"):C?i(process.env.APPDATA??i(g(),"AppData","Roaming"),"Code","User","mcp.json"):i(g(),".config","Code","User","mcp.json"),format:"json-servers",hasPermissions:!1},{id:"codex",label:"Codex",globalConfigPath:i(g(),".codex","config.toml"),format:"toml",hasPermissions:!1},{id:"antigravity",label:"Antigravity",globalConfigPath:i(g(),".gemini","antigravity","mcp_config.json"),format:"json-mcpServers",hasPermissions:!1}];function J(){let e=process.argv[2],o=process.argv.slice(3),s=null,n="user",r=!1;for(let t=0;t<o.length;t++)o[t]==="--ide"&&o[t+1]?s=o[++t]:o[t]==="--scope"&&o[t+1]?n=o[++t]:o[t]==="--skip-permissions"&&(r=!0);return{action:e,ide:s,scope:n,skipPermissions:r}}function L(e){let o=M({input:process.stdin,output:process.stdout});return new Promise(s=>{o.question(e,n=>{o.close(),s(n.trim())})})}async function R(){console.log(` Which IDE do you use?
2
- `),v.forEach((n,r)=>{console.log(` ${r+1}. ${n.label}`)}),console.log();let e=await L(" > "),o=parseInt(e,10)-1;if(o>=0&&o<v.length)return v[o].id;let s=v.find(n=>n.id===e.toLowerCase()||n.label.toLowerCase()===e.toLowerCase());return s?s.id:(console.log(` Invalid selection, defaulting to Claude Code.
3
- `),"claude-code")}function U(){try{return y("claude",["--version"],{stdio:"pipe",shell:C}),!0}catch{return!1}}function W(e){let o=["mcp","add","--scope",e,l,"--",$,...I];try{return y("claude",o,{stdio:"inherit",shell:C}),!0}catch{try{return y("claude",["mcp","remove","--scope",e,l],{stdio:"pipe",shell:C}),y("claude",o,{stdio:"inherit",shell:C}),!0}catch{return!1}}}function G(e){try{return y("claude",["mcp","remove","--scope",e,l],{stdio:"inherit",shell:C}),!0}catch{return!1}}var P=i(g(),".claude"),d=i(P,"settings.json"),h="mcp__fasttest";function q(){a(P)||b(P,{recursive:!0});let e={};if(a(d))try{e=JSON.parse(u(d,"utf-8"))}catch{let o=d+".bak";f(o,u(d)),console.log(` Warning: ${d} was corrupted. Backed up to ${o}`),e={}}return e.permissions||(e.permissions={}),Array.isArray(e.permissions.allow)||(e.permissions.allow=[]),e.permissions.allow.includes(h)?{added:!1,alreadyExists:!0}:(e.permissions.allow.push(h),f(d,JSON.stringify(e,null,2)+`
4
- `),{added:!0,alreadyExists:!1})}function H(){if(!a(d))return!1;try{let e=JSON.parse(u(d,"utf-8")),o=e.permissions?.allow;if(!Array.isArray(o))return!1;let s=o.indexOf(h);return s===-1?!1:(o.splice(s,1),f(d,JSON.stringify(e,null,2)+`
5
- `),!0)}catch{return!1}}var B=O(T(import.meta.url)),w=i(process.cwd(),".claude","commands"),E=["ftest.md","qa.md"];function V(){let e=0,o=0;for(let s of E){let n=i(B,"..","commands",s),r=i(w,s);a(n)&&(a(r)?(_(n,r),o++):(b(w,{recursive:!0}),_(n,r),e++))}return{installed:e,updated:o}}function Y(){let e=0;for(let o of E){let s=i(w,o);if(a(s))try{N(s),e++}catch{}}return e}function K(e){let o=i(e,"..");a(o)||b(o,{recursive:!0});let s={};if(a(e))try{s=JSON.parse(u(e,"utf-8"))}catch{let n=e+".bak";f(n,u(e)),console.log(` Warning: ${e} was corrupted. Backed up to ${n}`),s={}}return(!s.mcpServers||typeof s.mcpServers!="object")&&(s.mcpServers={}),s.mcpServers[l]={command:$,args:[...I]},f(e,JSON.stringify(s,null,2)+`
6
- `),!0}function Q(e){let o=i(e,"..");a(o)||b(o,{recursive:!0});let s={};if(a(e))try{s=JSON.parse(u(e,"utf-8"))}catch{let n=e+".bak";f(n,u(e)),console.log(` Warning: ${e} was corrupted. Backed up to ${n}`),s={}}return(!s.servers||typeof s.servers!="object")&&(s.servers={}),s.servers[l]={type:"stdio",command:$,args:[...I]},f(e,JSON.stringify(s,null,2)+`
7
- `),!0}function X(e){let o=i(e,"..");a(o)||b(o,{recursive:!0});let s="";a(e)&&(s=u(e,"utf-8"));let n=`[mcp_servers.${l}]`;if(s.includes(n)){let r=new RegExp(`\\[mcp_servers\\.${l}\\][\\s\\S]*?(?=\\n\\[|$)`);s=s.replace(r,k())}else s.length>0&&!s.endsWith(`
8
- `)&&(s+=`
9
- `),s+=`
10
- `+k()+`
11
- `;return f(e,s),!0}function k(){return`[mcp_servers.${l}]
1
+ import{execFileSync as y}from"node:child_process";import{createInterface as M}from"node:readline";import{existsSync as c,mkdirSync as h,readFileSync as m,writeFileSync as f,unlinkSync as N,copyFileSync as _}from"node:fs";import{homedir as g,platform as j}from"node:os";import{join as l,dirname as O}from"node:path";import{fileURLToPath as T}from"node:url";var C=j()==="win32",D=j()==="darwin",a="fasttest",F=C?"npx.cmd":"npx",$="npx",I=["-y","@fasttest-ai/qa-agent@latest"],v=[{id:"claude-code",label:"Claude Code",globalConfigPath:"",format:"cli",hasPermissions:!0},{id:"cursor",label:"Cursor",globalConfigPath:l(g(),".cursor","mcp.json"),format:"json-mcpServers",hasPermissions:!1},{id:"windsurf",label:"Windsurf",globalConfigPath:l(g(),".codeium","windsurf","mcp_config.json"),format:"json-mcpServers",hasPermissions:!1},{id:"vscode",label:"VS Code / Copilot",globalConfigPath:D?l(g(),"Library","Application Support","Code","User","mcp.json"):C?l(process.env.APPDATA??l(g(),"AppData","Roaming"),"Code","User","mcp.json"):l(g(),".config","Code","User","mcp.json"),format:"json-servers",hasPermissions:!1},{id:"codex",label:"Codex",globalConfigPath:l(g(),".codex","config.toml"),format:"toml",hasPermissions:!1},{id:"antigravity",label:"Antigravity",globalConfigPath:l(g(),".gemini","antigravity","mcp_config.json"),format:"json-mcpServers",hasPermissions:!1}];function J(){let e=process.argv[2],s=process.argv.slice(3),n=null,o="user",r=!1,i=null;for(let t=0;t<s.length;t++)s[t]==="--ide"&&s[t+1]?n=s[++t]:s[t]==="--scope"&&s[t+1]?o=s[++t]:s[t]==="--api-key"&&s[t+1]?i=s[++t]:s[t]==="--skip-permissions"&&(r=!0);return{action:e,ide:n,scope:o,skipPermissions:r,apiKey:i}}function L(e){let s=M({input:process.stdin,output:process.stdout});return new Promise(n=>{s.question(e,o=>{s.close(),n(o.trim())})})}async function R(){console.log(` Which IDE do you use?
2
+ `),v.forEach((o,r)=>{console.log(` ${r+1}. ${o.label}`)}),console.log();let e=await L(" > "),s=parseInt(e,10)-1;if(s>=0&&s<v.length)return v[s].id;let n=v.find(o=>o.id===e.toLowerCase()||o.label.toLowerCase()===e.toLowerCase());return n?n.id:(console.log(` Invalid selection, defaulting to Claude Code.
3
+ `),"claude-code")}function U(){try{return y("claude",["--version"],{stdio:"pipe",shell:C}),!0}catch{return!1}}function W(e,s=[]){let n=["mcp","add","--scope",e,a,"--",$,...I,...s];try{return y("claude",n,{stdio:"inherit",shell:C}),!0}catch{try{return y("claude",["mcp","remove","--scope",e,a],{stdio:"pipe",shell:C}),y("claude",n,{stdio:"inherit",shell:C}),!0}catch{return!1}}}function G(e){try{return y("claude",["mcp","remove","--scope",e,a],{stdio:"inherit",shell:C}),!0}catch{return!1}}var P=l(g(),".claude"),u=l(P,"settings.json"),b="mcp__fasttest";function q(){c(P)||h(P,{recursive:!0});let e={};if(c(u))try{e=JSON.parse(m(u,"utf-8"))}catch{let s=u+".bak";f(s,m(u)),console.log(` Warning: ${u} was corrupted. Backed up to ${s}`),e={}}return e.permissions||(e.permissions={}),Array.isArray(e.permissions.allow)||(e.permissions.allow=[]),e.permissions.allow.includes(b)?{added:!1,alreadyExists:!0}:(e.permissions.allow.push(b),f(u,JSON.stringify(e,null,2)+`
4
+ `),{added:!0,alreadyExists:!1})}function H(){if(!c(u))return!1;try{let e=JSON.parse(m(u,"utf-8")),s=e.permissions?.allow;if(!Array.isArray(s))return!1;let n=s.indexOf(b);return n===-1?!1:(s.splice(n,1),f(u,JSON.stringify(e,null,2)+`
5
+ `),!0)}catch{return!1}}var B=O(T(import.meta.url)),w=l(g(),".claude","commands"),E=["ftest.md","qa.md"];function K(){let e=0,s=0;for(let n of E){let o=l(B,"..","commands",n),r=l(w,n);c(o)&&(c(r)?(_(o,r),s++):(h(w,{recursive:!0}),_(o,r),e++))}return{installed:e,updated:s}}function V(){let e=0;for(let s of E){let n=l(w,s);if(c(n))try{N(n),e++}catch{}}return e}function Y(e,s=[]){let n=l(e,"..");c(n)||h(n,{recursive:!0});let o={};if(c(e))try{o=JSON.parse(m(e,"utf-8"))}catch{let r=e+".bak";f(r,m(e)),console.log(` Warning: ${e} was corrupted. Backed up to ${r}`),o={}}return(!o.mcpServers||typeof o.mcpServers!="object")&&(o.mcpServers={}),o.mcpServers[a]={command:$,args:[...I,...s]},f(e,JSON.stringify(o,null,2)+`
6
+ `),!0}function Q(e,s=[]){let n=l(e,"..");c(n)||h(n,{recursive:!0});let o={};if(c(e))try{o=JSON.parse(m(e,"utf-8"))}catch{let r=e+".bak";f(r,m(e)),console.log(` Warning: ${e} was corrupted. Backed up to ${r}`),o={}}return(!o.servers||typeof o.servers!="object")&&(o.servers={}),o.servers[a]={type:"stdio",command:$,args:[...I,...s]},f(e,JSON.stringify(o,null,2)+`
7
+ `),!0}function X(e,s=[]){let n=l(e,"..");c(n)||h(n,{recursive:!0});let o="";c(e)&&(o=m(e,"utf-8"));let r=`[mcp_servers.${a}]`;if(o.includes(r)){let i=new RegExp(`\\[mcp_servers\\.${a}\\][\\s\\S]*?(?=\\n\\[|$)`);o=o.replace(i,x(s))}else o.length>0&&!o.endsWith(`
8
+ `)&&(o+=`
9
+ `),o+=`
10
+ `+x(s)+`
11
+ `;return f(e,o),!0}function x(e=[]){return`[mcp_servers.${a}]
12
12
  command = "${$}"
13
- args = [${I.map(e=>`"${e}"`).join(", ")}]`}function z(e){if(!a(e))return!1;try{let o=JSON.parse(u(e,"utf-8")),s=o.mcpServers;return!s||!(l in s)?!1:(delete s[l],f(e,JSON.stringify(o,null,2)+`
14
- `),!0)}catch{return!1}}function Z(e){if(!a(e))return!1;try{let o=JSON.parse(u(e,"utf-8")),s=o.servers;return!s||!(l in s)?!1:(delete s[l],f(e,JSON.stringify(o,null,2)+`
15
- `),!0)}catch{return!1}}function ee(e){if(!a(e))return!1;try{let o=u(e,"utf-8"),s=`[mcp_servers.${l}]`;if(!o.includes(s))return!1;let n=new RegExp(`\\n?\\[mcp_servers\\.${l}\\][\\s\\S]*?(?=\\n\\[|$)`);return o=o.replace(n,""),f(e,o),!0}catch{return!1}}function se(){if(process.env.FASTTEST_SKIP_PLAYWRIGHT==="1"){console.log(" Skipping Playwright install (FASTTEST_SKIP_PLAYWRIGHT=1)");return}try{y(F,["playwright","install","--with-deps","chromium"],{stdio:"inherit"}),console.log(" Chromium installed")}catch{console.log(" Warning: Could not install Playwright browsers automatically."),console.log(" Run manually: npx playwright install --with-deps chromium")}}function oe(e,o){switch(e.format){case"cli":return U()?W(o):(console.log(`
13
+ args = [${[...I,...e].map(s=>`"${s}"`).join(", ")}]`}function z(e){if(!c(e))return!1;try{let s=JSON.parse(m(e,"utf-8")),n=s.mcpServers;return!n||!(a in n)?!1:(delete n[a],f(e,JSON.stringify(s,null,2)+`
14
+ `),!0)}catch{return!1}}function Z(e){if(!c(e))return!1;try{let s=JSON.parse(m(e,"utf-8")),n=s.servers;return!n||!(a in n)?!1:(delete n[a],f(e,JSON.stringify(s,null,2)+`
15
+ `),!0)}catch{return!1}}function ee(e){if(!c(e))return!1;try{let s=m(e,"utf-8"),n=`[mcp_servers.${a}]`;if(!s.includes(n))return!1;let o=new RegExp(`\\n?\\[mcp_servers\\.${a}\\][\\s\\S]*?(?=\\n\\[|$)`);return s=s.replace(o,""),f(e,s),!0}catch{return!1}}function se(){if(process.env.FASTTEST_SKIP_PLAYWRIGHT==="1"){console.log(" Skipping Playwright install (FASTTEST_SKIP_PLAYWRIGHT=1)");return}try{y(F,["playwright","install","--with-deps","chromium"],{stdio:"inherit"}),console.log(" Chromium installed")}catch{console.log(" Warning: Could not install Playwright browsers automatically."),console.log(" Run manually: npx playwright install --with-deps chromium")}}function ne(e,s,n){let o=n?["--api-key",n]:[];switch(e.format){case"cli":return U()?W(s,o):(console.log(`
16
16
  Claude Code CLI not found in PATH.
17
17
 
18
18
  Install Claude Code first:
@@ -27,33 +27,31 @@ args = [${I.map(e=>`"${e}"`).join(", ")}]`}function z(e){if(!a(e))return!1;try{l
27
27
  }
28
28
  }
29
29
  }
30
- `),!1);case"json-mcpServers":return K(e.globalConfigPath);case"json-servers":return Q(e.globalConfigPath);case"toml":return X(e.globalConfigPath)}}function ne(e,o){switch(e.format){case"cli":return G(o);case"json-mcpServers":return z(e.globalConfigPath);case"json-servers":return Z(e.globalConfigPath);case"toml":return ee(e.globalConfigPath)}}async function te(e){console.log(`
30
+ `),!1);case"json-mcpServers":return Y(e.globalConfigPath,o);case"json-servers":return Q(e.globalConfigPath,o);case"toml":return X(e.globalConfigPath,o)}}function oe(e,s){switch(e.format){case"cli":return G(s);case"json-mcpServers":return z(e.globalConfigPath);case"json-servers":return Z(e.globalConfigPath);case"toml":return ee(e.globalConfigPath)}}async function re(e){console.log(`
31
31
  FastTest Agent Installer
32
- `);let o=e.ide??await R(),s=v.find(c=>c.id===o);s||(console.log(` Unknown IDE: ${o}`),console.log(` Supported: ${v.map(c=>c.id).join(", ")}`),process.exit(1)),console.log(`
33
- Installing for ${s.label}...
34
- `);let n=s.id==="claude-code",r=s.hasPermissions&&!e.skipPermissions,t=2;r&&t++,n&&t++;let m=1;if(console.log(` [${m}/${t}] Registering MCP server...`),oe(s,e.scope)){let c=s.format==="cli"?`(scope: ${e.scope})`:s.globalConfigPath;console.log(` MCP server "${l}" registered ${c}`)}else s.format==="cli"&&process.exit(1),console.log(" Warning: Could not register MCP server.");if(m++,r){console.log(` [${m}/${t}] Pre-approving tools...`);let{added:c,alreadyExists:S}=q();c?console.log(` Added ${h} to ${d}`):S&&console.log(` Already configured (${h})`),m++}if(n){console.log(` [${m}/${t}] Installing /ftest and /qa commands...`);let{installed:c,updated:S}=V();c>0&&console.log(` Added ${c} command(s) to ${w}`),S>0&&console.log(` Updated ${S} command(s)`),c===0&&S===0&&console.log(" Warning: Could not install commands (source files missing)"),m++}console.log(` [${m}/${t}] Installing Playwright browsers...`),se();let x=` Optional: Add this to your project's ${{"claude-code":"CLAUDE.md",cursor:".cursor/rules",windsurf:".windsurfrules",vscode:".github/copilot-instructions.md",codex:"AGENTS.md",antigravity:"GEMINI.md"}[s.id]} to auto-test after building features:
32
+ `);let s=e.ide??await R(),n=v.find(d=>d.id===s);n||(console.log(` Unknown IDE: ${s}`),console.log(` Supported: ${v.map(d=>d.id).join(", ")}`),process.exit(1)),console.log(`
33
+ Installing for ${n.label}...
34
+ `);let o=n.id==="claude-code",r=n.hasPermissions&&!e.skipPermissions,i=2;r&&i++,o&&i++;let t=1;if(console.log(` [${t}/${i}] Registering MCP server...`),ne(n,e.scope,e.apiKey)){let d=n.format==="cli"?`(scope: ${e.scope})`:n.globalConfigPath;console.log(` MCP server "${a}" registered ${d}`)}else n.format==="cli"&&process.exit(1),console.log(" Warning: Could not register MCP server.");if(t++,r){console.log(` [${t}/${i}] Pre-approving tools...`);let{added:d,alreadyExists:S}=q();d?console.log(` Added ${b} to ${u}`):S&&console.log(` Already configured (${b})`),t++}if(o){console.log(` [${t}/${i}] Installing /ftest and /qa commands...`);let{installed:d,updated:S}=K();d>0&&console.log(` Added ${d} command(s) to ${w}`),S>0&&console.log(` Updated ${S} command(s)`),d===0&&S===0&&console.log(" Warning: Could not install commands (source files missing)"),t++}console.log(` [${t}/${i}] Installing Playwright browsers...`),se();let k=` Optional: Add this to your project's ${{"claude-code":"CLAUDE.md",cursor:".cursor/rules",windsurf:".windsurfrules",vscode:".github/copilot-instructions.md",codex:"AGENTS.md",antigravity:"GEMINI.md"}[n.id]} to auto-test after building features:
35
35
 
36
36
  ## Testing
37
37
  After implementing a feature, verify it works by running:
38
38
  \`ftest <app-url> <what to test>\`
39
- or use \`vibe shield <app-url>\` to generate a full regression suite.`;console.log(n?`
40
- Done! Open ${s.label} and try:
39
+ or use \`vibe shield <app-url>\` to generate a full regression suite.`;console.log(o?`
40
+ Done! Open ${n.label} and try:
41
41
 
42
- /ftest http://localhost:3000 login flow
42
+ "break my app"
43
43
 
44
- ${x}
44
+ ${k}
45
45
  `:`
46
- Done! Open ${s.label} and try:
46
+ Done! Open ${n.label} and try:
47
47
 
48
- "ftest my app at http://localhost:3000"
49
- "ftest explore http://localhost:3000"
50
- "ftest chaos http://localhost:3000"
48
+ "break my app"
51
49
 
52
- ${x}
53
- `)}async function re(e){console.log(`
50
+ ${k}
51
+ `)}async function te(e){console.log(`
54
52
  FastTest Agent Uninstaller
55
- `);let o=e.ide??await R(),s=v.find(p=>p.id===o);s||(console.log(` Unknown IDE: ${o}`),process.exit(1)),console.log(`
56
- Uninstalling from ${s.label}...
57
- `);let n=s.id==="claude-code",r=1;s.hasPermissions&&r++,n&&r++;let t=1;console.log(` [${t}/${r}] Removing MCP server...`);let m=ne(s,e.scope);if(console.log(m?` MCP server "${l}" removed`:" MCP server was not registered (nothing to remove)"),t++,s.hasPermissions){console.log(` [${t}/${r}] Removing tool permissions...`);let p=H();console.log(p?` Removed ${h} from ${d}`:" Permission was not present (nothing to remove)"),t++}if(n){console.log(` [${t}/${r}] Removing /ftest and /qa commands...`);let p=Y();p>0?console.log(` Removed ${p} command(s)`):console.log(" Commands were not installed (nothing to remove)")}console.log(`
58
- FastTest has been uninstalled from ${s.label}.
59
- `)}var A=J();A.action==="uninstall"?await re(A):await te(A);
53
+ `);let s=e.ide??await R(),n=v.find(p=>p.id===s);n||(console.log(` Unknown IDE: ${s}`),process.exit(1)),console.log(`
54
+ Uninstalling from ${n.label}...
55
+ `);let o=n.id==="claude-code",r=1;n.hasPermissions&&r++,o&&r++;let i=1;console.log(` [${i}/${r}] Removing MCP server...`);let t=oe(n,e.scope);if(console.log(t?` MCP server "${a}" removed`:" MCP server was not registered (nothing to remove)"),i++,n.hasPermissions){console.log(` [${i}/${r}] Removing tool permissions...`);let p=H();console.log(p?` Removed ${b} from ${u}`:" Permission was not present (nothing to remove)"),i++}if(o){console.log(` [${i}/${r}] Removing /ftest and /qa commands...`);let p=V();p>0?console.log(` Removed ${p} command(s)`):console.log(" Commands were not installed (nothing to remove)")}console.log(`
56
+ FastTest has been uninstalled from ${n.label}.
57
+ `)}var A=J();A.action==="uninstall"?await te(A):await re(A);
package/package.json CHANGED
@@ -1,15 +1,11 @@
1
1
  {
2
2
  "name": "@fasttest-ai/qa-agent",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "FastTest Agent — MCP server that turns your coding agent into a QA engineer. Test, explore, and break web apps using Playwright.",
5
5
  "type": "module",
6
- "repository": {
7
- "type": "git",
8
- "url": "https://github.com/fasttest-ai/agent.git"
9
- },
10
6
  "homepage": "https://fasttest.ai",
11
7
  "bugs": {
12
- "url": "https://github.com/fasttest-ai/agent/issues"
8
+ "url": "https://fasttest.ai"
13
9
  },
14
10
  "author": "FastTest AI <hello@fasttest.ai>",
15
11
  "keywords": [
@@ -38,11 +34,13 @@
38
34
  "dev": "tsc --watch",
39
35
  "typecheck": "tsc --noEmit",
40
36
  "start": "node dist/index.js",
41
- "ci": "node dist/cli.js"
37
+ "ci": "node dist/cli.js",
38
+ "prepublishOnly": "npm run build"
42
39
  },
43
40
  "dependencies": {
44
41
  "@modelcontextprotocol/sdk": "^1.12.0",
45
- "playwright": "^1.52.0"
42
+ "playwright": "^1.52.0",
43
+ "zod": "^3.25.0"
46
44
  },
47
45
  "devDependencies": {
48
46
  "@types/node": "^22.0.0",