@fasttest-ai/qa-agent 1.0.4-staging.2 → 1.0.4-staging.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 b}from"node:child_process";import{createInterface as O}from"node:readline";import{existsSync as c,mkdirSync as w,readFileSync as d,writeFileSync as f,unlinkSync as T,copyFileSync as _}from"node:fs";import{homedir as g,platform as j}from"node:os";import{join as i,dirname as D}from"node:path";import{fileURLToPath as J}from"node:url";var C=j()==="win32",F=j()==="darwin",a="fasttest",L=C?"npx.cmd":"npx",$="npx",R=D(J(import.meta.url)),U=(()=>{try{return JSON.parse(d(i(R,"..","package.json"),"utf-8")).version??""}catch{return""}})(),E=U.includes("-staging")?"staging":"latest",I=["-y",`@fasttest-ai/qa-agent@${E}`],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:F?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 W(){let e=process.argv[2],s=process.argv.slice(3),n=null,o="user",r=!1,l=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]?l=s[++t]:s[t]==="--skip-permissions"&&(r=!0);return{action:e,ide:n,scope:o,skipPermissions:r,apiKey:l}}function G(e){let s=O({input:process.stdin,output:process.stdout});return new Promise(n=>{s.question(e,o=>{s.close(),n(o.trim())})})}async function N(){console.log(` Which IDE do you use?
2
- `),v.forEach((o,r)=>{console.log(` ${r+1}. ${o.label}`)}),console.log();let e=await G(" > "),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 q(){try{return b("claude",["--version"],{stdio:"pipe",shell:C}),!0}catch{return!1}}function H(e,s=[]){try{b("claude",["mcp","remove","--scope",e,a],{stdio:"pipe",shell:C})}catch{}let n=["mcp","add","--scope",e,a,"--",$,...I,...s];try{return b("claude",n,{stdio:"inherit",shell:C}),!0}catch{return!1}}function K(e){try{return b("claude",["mcp","remove","--scope",e,a],{stdio:"inherit",shell:C}),!0}catch{return!1}}var A=i(g(),".claude"),m=i(A,"settings.json"),y="mcp__fasttest";function V(){c(A)||w(A,{recursive:!0});let e={};if(c(m))try{e=JSON.parse(d(m,"utf-8"))}catch{let s=m+".bak";f(s,d(m)),console.log(` Warning: ${m} was corrupted. Backed up to ${s}`),e={}}return e.permissions||(e.permissions={}),Array.isArray(e.permissions.allow)||(e.permissions.allow=[]),e.permissions.allow.includes(y)?{added:!1,alreadyExists:!0}:(e.permissions.allow.push(y),f(m,JSON.stringify(e,null,2)+`
4
- `),{added:!0,alreadyExists:!1})}function B(){if(!c(m))return!1;try{let e=JSON.parse(d(m,"utf-8")),s=e.permissions?.allow;if(!Array.isArray(s))return!1;let n=s.indexOf(y);return n===-1?!1:(s.splice(n,1),f(m,JSON.stringify(e,null,2)+`
5
- `),!0)}catch{return!1}}var h=i(g(),".claude","commands"),M=["ftest.md","qa.md"];function Y(){let e=0,s=0;for(let n of M){let o=i(R,"..","commands",n),r=i(h,n);c(o)&&(c(r)?(_(o,r),s++):(w(h,{recursive:!0}),_(o,r),e++))}return{installed:e,updated:s}}function Q(){let e=0;for(let s of M){let n=i(h,s);if(c(n))try{T(n),e++}catch{}}return e}function X(e,s=[]){let n=i(e,"..");c(n)||w(n,{recursive:!0});let o={};if(c(e))try{o=JSON.parse(d(e,"utf-8"))}catch{let r=e+".bak";f(r,d(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 z(e,s=[]){let n=i(e,"..");c(n)||w(n,{recursive:!0});let o={};if(c(e))try{o=JSON.parse(d(e,"utf-8"))}catch{let r=e+".bak";f(r,d(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 Z(e,s=[]){let n=i(e,"..");c(n)||w(n,{recursive:!0});let o="";c(e)&&(o=d(e,"utf-8"));let r=`[mcp_servers.${a}]`;if(o.includes(r)){let l=new RegExp(`\\[mcp_servers\\.${a}\\][\\s\\S]*?(?=\\n\\[|$)`);o=o.replace(l,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}]
1
+ import{execFileSync as b}from"node:child_process";import{createInterface as j}from"node:readline";import{existsSync as c,mkdirSync as h,readFileSync as d,writeFileSync as f,unlinkSync as O,copyFileSync as x}from"node:fs";import{homedir as g,platform as _}from"node:os";import{join as l,dirname as D}from"node:path";import{fileURLToPath as F}from"node:url";var C=_()==="win32",J=_()==="darwin",a="fasttest",L=C?"npx.cmd":"npx",$="npx",M=D(F(import.meta.url)),U=(()=>{try{return JSON.parse(d(l(M,"..","package.json"),"utf-8")).version??""}catch{return""}})(),T=U.includes("-staging")?"staging":"latest",I=["-y",`@fasttest-ai/qa-agent@${T}`],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:"vscode",label:"VS Code / Copilot",globalConfigPath:J?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}];function W(){let e=process.argv[2],s=process.argv.slice(3),o=null,n="user",t=!1,i=null;for(let r=0;r<s.length;r++)s[r]==="--ide"&&s[r+1]?o=s[++r]:s[r]==="--scope"&&s[r+1]?n=s[++r]:s[r]==="--api-key"&&s[r+1]?i=s[++r]:s[r]==="--skip-permissions"&&(t=!0);return{action:e,ide:o,scope:n,skipPermissions:t,apiKey:i}}function G(e){let s=j({input:process.stdin,output:process.stdout});return new Promise(o=>{s.question(e,n=>{s.close(),o(n.trim())})})}async function E(){console.log(` Which IDE do you use?
2
+ `),v.forEach((n,t)=>{console.log(` ${t+1}. ${n.label}`)}),console.log();let e=await G(" > "),s=parseInt(e,10)-1;if(s>=0&&s<v.length)return v[s].id;let o=v.find(n=>n.id===e.toLowerCase()||n.label.toLowerCase()===e.toLowerCase());return o?o.id:(console.log(` Invalid selection, defaulting to Claude Code.
3
+ `),"claude-code")}function q(){try{return b("claude",["--version"],{stdio:"pipe",shell:C}),!0}catch{return!1}}function H(e,s=[]){try{b("claude",["mcp","remove","--scope",e,a],{stdio:"pipe",shell:C})}catch{}let o=["mcp","add","--scope",e,a,"--",$,...I,...s];try{return b("claude",o,{stdio:"inherit",shell:C}),!0}catch{return!1}}function K(e){try{return b("claude",["mcp","remove","--scope",e,a],{stdio:"inherit",shell:C}),!0}catch{return!1}}var P=l(g(),".claude"),m=l(P,"settings.json"),y="mcp__fasttest";function V(){c(P)||h(P,{recursive:!0});let e={};if(c(m))try{e=JSON.parse(d(m,"utf-8"))}catch{let s=m+".bak";f(s,d(m)),console.log(` Warning: ${m} was corrupted. Backed up to ${s}`),e={}}return e.permissions||(e.permissions={}),Array.isArray(e.permissions.allow)||(e.permissions.allow=[]),e.permissions.allow.includes(y)?{added:!1,alreadyExists:!0}:(e.permissions.allow.push(y),f(m,JSON.stringify(e,null,2)+`
4
+ `),{added:!0,alreadyExists:!1})}function B(){if(!c(m))return!1;try{let e=JSON.parse(d(m,"utf-8")),s=e.permissions?.allow;if(!Array.isArray(s))return!1;let o=s.indexOf(y);return o===-1?!1:(s.splice(o,1),f(m,JSON.stringify(e,null,2)+`
5
+ `),!0)}catch{return!1}}var w=l(g(),".claude","commands"),N=["ftest.md","qa.md"];function Y(){let e=0,s=0;for(let o of N){let n=l(M,"..","commands",o),t=l(w,o);c(n)&&(c(t)?(x(n,t),s++):(h(w,{recursive:!0}),x(n,t),e++))}return{installed:e,updated:s}}function Q(){let e=0;for(let s of N){let o=l(w,s);if(c(o))try{O(o),e++}catch{}}return e}function X(e,s=[]){let o=l(e,"..");c(o)||h(o,{recursive:!0});let n={};if(c(e))try{n=JSON.parse(d(e,"utf-8"))}catch{let t=e+".bak";f(t,d(e)),console.log(` Warning: ${e} was corrupted. Backed up to ${t}`),n={}}return(!n.mcpServers||typeof n.mcpServers!="object")&&(n.mcpServers={}),n.mcpServers[a]={command:$,args:[...I,...s]},f(e,JSON.stringify(n,null,2)+`
6
+ `),!0}function z(e,s=[]){let o=l(e,"..");c(o)||h(o,{recursive:!0});let n={};if(c(e))try{n=JSON.parse(d(e,"utf-8"))}catch{let t=e+".bak";f(t,d(e)),console.log(` Warning: ${e} was corrupted. Backed up to ${t}`),n={}}return(!n.servers||typeof n.servers!="object")&&(n.servers={}),n.servers[a]={type:"stdio",command:$,args:[...I,...s]},f(e,JSON.stringify(n,null,2)+`
7
+ `),!0}function Z(e,s=[]){let o=l(e,"..");c(o)||h(o,{recursive:!0});let n="";c(e)&&(n=d(e,"utf-8"));let t=`[mcp_servers.${a}]`;if(n.includes(t)){let i=new RegExp(`\\[mcp_servers\\.${a}\\][\\s\\S]*?(?=\\n\\[|$)`);n=n.replace(i,R(s))}else n.length>0&&!n.endsWith(`
8
+ `)&&(n+=`
9
+ `),n+=`
10
+ `+R(s)+`
11
+ `;return f(e,n),!0}function R(e=[]){return`[mcp_servers.${a}]
12
12
  command = "${$}"
13
- args = [${[...I,...e].map(s=>`"${s}"`).join(", ")}]`}function ee(e){if(!c(e))return!1;try{let s=JSON.parse(d(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 se(e){if(!c(e))return!1;try{let s=JSON.parse(d(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 ne(e){if(!c(e))return!1;try{let s=d(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 oe(){if(process.env.FASTTEST_SKIP_PLAYWRIGHT==="1"){console.log(" Skipping Playwright install (FASTTEST_SKIP_PLAYWRIGHT=1)");return}try{b(L,["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 re(e,s,n){let o=n?["--api-key",n]:[];switch(e.format){case"cli":return q()?H(s,o):(console.log(`
13
+ args = [${[...I,...e].map(s=>`"${s}"`).join(", ")}]`}function ee(e){if(!c(e))return!1;try{let s=JSON.parse(d(e,"utf-8")),o=s.mcpServers;return!o||!(a in o)?!1:(delete o[a],f(e,JSON.stringify(s,null,2)+`
14
+ `),!0)}catch{return!1}}function se(e){if(!c(e))return!1;try{let s=JSON.parse(d(e,"utf-8")),o=s.servers;return!o||!(a in o)?!1:(delete o[a],f(e,JSON.stringify(s,null,2)+`
15
+ `),!0)}catch{return!1}}function oe(e){if(!c(e))return!1;try{let s=d(e,"utf-8"),o=`[mcp_servers.${a}]`;if(!s.includes(o))return!1;let n=new RegExp(`\\n?\\[mcp_servers\\.${a}\\][\\s\\S]*?(?=\\n\\[|$)`);return s=s.replace(n,""),f(e,s),!0}catch{return!1}}function ne(){if(process.env.FASTTEST_SKIP_PLAYWRIGHT==="1"){console.log(" Skipping Playwright install (FASTTEST_SKIP_PLAYWRIGHT=1)");return}try{b(L,["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 te(e,s,o){let n=o?["--api-key",o]:[];switch(e.format){case"cli":return q()?H(s,n):(console.log(`
16
16
  Claude Code CLI not found in PATH.
17
17
 
18
18
  Install Claude Code first:
@@ -23,35 +23,50 @@ args = [${[...I,...e].map(s=>`"${s}"`).join(", ")}]`}function ee(e){if(!c(e))ret
23
23
  "mcpServers": {
24
24
  "fasttest": {
25
25
  "command": "npx",
26
- "args": ["-y", "@fasttest-ai/qa-agent@${E}"]
26
+ "args": ["-y", "@fasttest-ai/qa-agent@${T}"]
27
27
  }
28
28
  }
29
29
  }
30
- `),!1);case"json-mcpServers":return X(e.globalConfigPath,o);case"json-servers":return z(e.globalConfigPath,o);case"toml":return Z(e.globalConfigPath,o)}}function te(e,s){switch(e.format){case"cli":return K(s);case"json-mcpServers":return ee(e.globalConfigPath);case"json-servers":return se(e.globalConfigPath);case"toml":return ne(e.globalConfigPath)}}async function ie(e){console.log(`
30
+ `),!1);case"json-mcpServers":return X(e.globalConfigPath,n);case"json-servers":return z(e.globalConfigPath,n);case"toml":return Z(e.globalConfigPath,n)}}function re(e,s){switch(e.format){case"cli":return K(s);case"json-mcpServers":return ee(e.globalConfigPath);case"json-servers":return se(e.globalConfigPath);case"toml":return oe(e.globalConfigPath)}}async function ie(e){console.log(`
31
31
  FastTest Agent Installer
32
- `);let s=e.ide??await N(),n=v.find(u=>u.id===s);n||(console.log(` Unknown IDE: ${s}`),console.log(` Supported: ${v.map(u=>u.id).join(", ")}`),process.exit(1)),console.log(`
33
- Installing for ${n.label}...
34
- `);let o=n.id==="claude-code",r=n.hasPermissions&&!e.skipPermissions,l=2;r&&l++,o&&l++;let t=1;if(console.log(` [${t}/${l}] Registering MCP server...`),re(n,e.scope,e.apiKey)){let u=n.format==="cli"?`(scope: ${e.scope})`:n.globalConfigPath;console.log(` MCP server "${a}" registered ${u}`)}else n.format==="cli"&&process.exit(1),console.log(" Warning: Could not register MCP server.");if(t++,r){console.log(` [${t}/${l}] Pre-approving tools...`);let{added:u,alreadyExists:S}=V();u?console.log(` Added ${y} to ${m}`):S&&console.log(` Already configured (${y})`),t++}if(o){console.log(` [${t}/${l}] Installing /ftest and /qa commands...`);let{installed:u,updated:S}=Y();u>0&&console.log(` Added ${u} command(s) to ${h}`),S>0&&console.log(` Updated ${S} command(s)`),u===0&&S===0&&console.log(" Warning: Could not install commands (source files missing)"),t++}console.log(` [${t}/${l}] Installing Playwright browsers...`),oe();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:
32
+ `);let s=e.ide??await E(),o=v.find(u=>u.id===s);o||(console.log(` Unknown IDE: ${s}`),console.log(` Supported: ${v.map(u=>u.id).join(", ")}`),process.exit(1)),console.log(`
33
+ Installing for ${o.label}...
34
+ `);let n=o.id==="claude-code",t=o.hasPermissions&&!e.skipPermissions,i=2;t&&i++,n&&i++;let r=1;if(console.log(` [${r}/${i}] Registering MCP server...`),te(o,e.scope,e.apiKey)){let u=o.format==="cli"?`(scope: ${e.scope})`:o.globalConfigPath;console.log(` MCP server "${a}" registered ${u}`)}else o.format==="cli"&&process.exit(1),console.log(" Warning: Could not register MCP server.");if(r++,t){console.log(` [${r}/${i}] Pre-approving tools...`);let{added:u,alreadyExists:S}=V();u?console.log(` Added ${y} to ${m}`):S&&console.log(` Already configured (${y})`),r++}if(n){console.log(` [${r}/${i}] Installing /ftest and /qa commands...`);let{installed:u,updated:S}=Y();u>0&&console.log(` Added ${u} command(s) to ${w}`),S>0&&console.log(` Updated ${S} command(s)`),u===0&&S===0&&console.log(" Warning: Could not install commands (source files missing)"),r++}console.log(` [${r}/${i}] Installing Playwright browsers...`),ne();let k={"claude-code":"CLAUDE.md",cursor:".cursor/rules",vscode:".github/copilot-instructions.md",codex:"AGENTS.md"};console.log(n?`
35
+ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
36
+ FastTest installed! Try it now \u2014 paste into ${o.label}:
37
+ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
35
38
 
36
- ## Testing
37
- After implementing a feature, verify it works by running:
38
- \`ftest <app-url> <what to test>\`
39
- or use \`vibe shield <app-url>\` to generate a full regression suite.`;console.log(o?`
40
- Done! Open ${n.label} and try:
39
+ /ftest test the login flow
41
40
 
42
- "break my app"
41
+ More things to try:
42
+ /ftest explore my app Map out pages and flows
43
+ /ftest break my app Adversarial security testing
44
+ /ftest shield my app Generate a full regression suite
43
45
 
44
- ${k}
46
+ Set up an environment so you never have to pass a URL:
47
+ /ftest setup environment "dev" for my project
48
+
49
+ Tip: Add testing rules to ${k[o.id]} \u2014 https://docs.fasttest.ai
45
50
  `:`
46
- Done! Open ${n.label} and try:
51
+ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
52
+ FastTest installed! Try it now \u2014 paste into ${o.label}:
53
+ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
54
+
55
+ test the login flow
56
+
57
+ More things to try:
58
+ explore my app Map out pages and flows
59
+ break my app Adversarial security testing
60
+ vibe shield my app Generate a full regression suite
47
61
 
48
- "break my app"
62
+ Set up an environment so you never have to pass a URL:
63
+ setup a "dev" environment for my project
49
64
 
50
- ${k}
65
+ Tip: Add testing rules to ${k[o.id]} \u2014 https://docs.fasttest.ai
51
66
  `)}async function le(e){console.log(`
52
67
  FastTest Agent Uninstaller
53
- `);let s=e.ide??await N(),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 l=1;console.log(` [${l}/${r}] Removing MCP server...`);let t=te(n,e.scope);if(console.log(t?` MCP server "${a}" removed`:" MCP server was not registered (nothing to remove)"),l++,n.hasPermissions){console.log(` [${l}/${r}] Removing tool permissions...`);let p=B();console.log(p?` Removed ${y} from ${m}`:" Permission was not present (nothing to remove)"),l++}if(o){console.log(` [${l}/${r}] Removing /ftest and /qa commands...`);let p=Q();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 P=W();P.action==="uninstall"?await le(P):await ie(P);
68
+ `);let s=e.ide??await E(),o=v.find(p=>p.id===s);o||(console.log(` Unknown IDE: ${s}`),process.exit(1)),console.log(`
69
+ Uninstalling from ${o.label}...
70
+ `);let n=o.id==="claude-code",t=1;o.hasPermissions&&t++,n&&t++;let i=1;console.log(` [${i}/${t}] Removing MCP server...`);let r=re(o,e.scope);if(console.log(r?` MCP server "${a}" removed`:" MCP server was not registered (nothing to remove)"),i++,o.hasPermissions){console.log(` [${i}/${t}] Removing tool permissions...`);let p=B();console.log(p?` Removed ${y} from ${m}`:" Permission was not present (nothing to remove)"),i++}if(n){console.log(` [${i}/${t}] Removing /ftest and /qa commands...`);let p=Q();p>0?console.log(` Removed ${p} command(s)`):console.log(" Commands were not installed (nothing to remove)")}console.log(`
71
+ FastTest has been uninstalled from ${o.label}.
72
+ `)}var A=W();A.action==="uninstall"?await le(A):await ie(A);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fasttest-ai/qa-agent",
3
- "version": "1.0.4-staging.2",
3
+ "version": "1.0.4-staging.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
6
  "homepage": "https://fasttest.ai",