@react-grab/cli 0.1.0-beta.10 → 0.1.0-beta.11

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.
Files changed (3) hide show
  1. package/dist/cli.cjs +118 -80
  2. package/dist/cli.js +118 -80
  3. package/package.json +2 -2
package/dist/cli.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
  'use strict';
3
3
 
4
4
  var commander = require('commander');
5
- var pc = require('picocolors');
5
+ var pc2 = require('picocolors');
6
6
  var prompts3 = require('prompts');
7
7
  var fs = require('fs');
8
8
  var path = require('path');
@@ -18,7 +18,7 @@ var stdio_js = require('@modelcontextprotocol/sdk/server/stdio.js');
18
18
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
19
19
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
20
20
 
21
- var pc__default = /*#__PURE__*/_interopDefault(pc);
21
+ var pc2__default = /*#__PURE__*/_interopDefault(pc2);
22
22
  var prompts3__default = /*#__PURE__*/_interopDefault(prompts3);
23
23
  var ora__default = /*#__PURE__*/_interopDefault(ora);
24
24
 
@@ -1160,11 +1160,11 @@ var previewPackageJsonAgentRemoval = (projectRoot, agent) => {
1160
1160
  }
1161
1161
  };
1162
1162
  var highlighter = {
1163
- error: pc__default.default.red,
1164
- warn: pc__default.default.yellow,
1165
- info: pc__default.default.cyan,
1166
- success: pc__default.default.green,
1167
- dim: pc__default.default.dim
1163
+ error: pc2__default.default.red,
1164
+ warn: pc2__default.default.yellow,
1165
+ info: pc2__default.default.cyan,
1166
+ success: pc2__default.default.green,
1167
+ dim: pc2__default.default.dim
1168
1168
  };
1169
1169
 
1170
1170
  // src/utils/logger.ts
@@ -1262,6 +1262,17 @@ var spinner = (text, options2) => ora__default.default({ text, isSilent: options
1262
1262
  var detectSkillAgents = (cwd) => {
1263
1263
  return SKILL_AGENTS.filter((agent) => fs.existsSync(path.join(cwd, agent.folder)));
1264
1264
  };
1265
+ var getRankedSkillAgents = (cwd) => {
1266
+ const rankedAgents = SKILL_AGENTS.map((agent) => ({
1267
+ ...agent,
1268
+ detected: fs.existsSync(path.join(cwd, agent.folder))
1269
+ }));
1270
+ return rankedAgents.sort((first, second) => {
1271
+ if (first.detected && !second.detected) return -1;
1272
+ if (!first.detected && second.detected) return 1;
1273
+ return 0;
1274
+ });
1275
+ };
1265
1276
  var findSkillAgent = (id) => {
1266
1277
  return SKILL_AGENTS.find((agent) => agent.id === id);
1267
1278
  };
@@ -1715,7 +1726,8 @@ ${BOLD}File: ${filePath}${RESET}`);
1715
1726
  console.log(formatDiff(diff));
1716
1727
  console.log("\u2500".repeat(60));
1717
1728
  };
1718
- var VERSION = "0.1.0-beta.9";
1729
+ var VERSION = "0.1.0-beta.10";
1730
+ var formatInstalledAgentNames2 = (agents) => agents.map((agent) => AGENT_NAMES[agent] || agent).join(", ");
1719
1731
  var configureMcp = (mcpClient, cwd, customPkg) => {
1720
1732
  const mcpCommand = customPkg ? `npx -y ${customPkg} browser mcp` : `npx -y grab browser mcp`;
1721
1733
  const mcpSpinner = spinner(
@@ -1771,17 +1783,15 @@ var add = new commander.Command().name("add").alias("install").description("add
1771
1783
  process.cwd()
1772
1784
  ).action(async (agentArg, opts2) => {
1773
1785
  console.log(
1774
- `${pc__default.default.magenta("\u273F")} ${pc__default.default.bold("React Grab")} ${pc__default.default.gray(VERSION)}`
1786
+ `${pc2__default.default.magenta("\u273F")} ${pc2__default.default.bold("React Grab")} ${pc2__default.default.gray(VERSION)}`
1775
1787
  );
1776
1788
  console.log();
1777
1789
  try {
1778
1790
  const cwd = opts2.cwd;
1779
1791
  const isNonInteractive = opts2.yes;
1780
1792
  if (agentArg === "mcp") {
1781
- let mcpClient = opts2.client;
1782
- if (mcpClient === "claude") {
1783
- mcpClient = "claude-code";
1784
- }
1793
+ const rawClient = opts2.client === "claude" ? "claude-code" : opts2.client;
1794
+ let mcpClient = rawClient;
1785
1795
  if (mcpClient && !MCP_CLIENTS.includes(mcpClient)) {
1786
1796
  logger.break();
1787
1797
  logger.error(`Invalid MCP client: ${mcpClient}`);
@@ -1795,9 +1805,9 @@ var add = new commander.Command().name("add").alias("install").description("add
1795
1805
  type: "select",
1796
1806
  name: "client",
1797
1807
  message: `Which ${highlighter.info("client")} would you like to configure?`,
1798
- choices: MCP_CLIENTS.map((innerClient) => ({
1799
- title: MCP_CLIENT_NAMES[innerClient],
1800
- value: innerClient
1808
+ choices: MCP_CLIENTS.map((mcpClientOption) => ({
1809
+ title: MCP_CLIENT_NAMES[mcpClientOption],
1810
+ value: mcpClientOption
1801
1811
  }))
1802
1812
  });
1803
1813
  if (!client) {
@@ -1818,35 +1828,29 @@ var add = new commander.Command().name("add").alias("install").description("add
1818
1828
  if (agentArg === "skill") {
1819
1829
  const clientArg = opts2.client;
1820
1830
  let selectedAgent = clientArg ? findSkillAgent(clientArg) : void 0;
1821
- const detectedAgents = detectSkillAgents(cwd);
1822
1831
  if (clientArg && !selectedAgent) {
1823
1832
  logger.break();
1824
1833
  logger.error(`Invalid skill agent: ${clientArg}`);
1825
1834
  logger.error(
1826
- `Available agents: ${SKILL_AGENTS.map((a) => a.id).join(", ")}`
1835
+ `Available agents: ${SKILL_AGENTS.map((skillAgent) => skillAgent.id).join(", ")}`
1827
1836
  );
1828
1837
  logger.break();
1829
1838
  process.exit(1);
1830
1839
  }
1831
1840
  if (!selectedAgent && !isNonInteractive) {
1832
- if (detectedAgents.length === 0) {
1833
- logger.break();
1834
- logger.warn("No supported agent folders detected.");
1835
- logger.log(
1836
- "Supported agents: " + SKILL_AGENTS.map((a) => a.id).join(", ")
1837
- );
1838
- logger.break();
1839
- process.exit(0);
1840
- }
1841
+ const rankedAgents = getRankedSkillAgents(cwd);
1842
+ const hasDetectedAgents = rankedAgents.some(
1843
+ (rankedAgent) => rankedAgent.detected
1844
+ );
1841
1845
  logger.break();
1842
1846
  const { agent } = await prompts3__default.default({
1843
1847
  type: "select",
1844
1848
  name: "agent",
1845
1849
  message: `Which ${highlighter.info("agent")} would you like to install the skill for?`,
1846
1850
  choices: [
1847
- ...detectedAgents.map((innerAgent) => ({
1848
- title: innerAgent.name,
1849
- value: innerAgent
1851
+ ...rankedAgents.map((rankedAgent) => ({
1852
+ title: hasDetectedAgents ? `${rankedAgent.name}${rankedAgent.detected ? pc2__default.default.green(" (detected)") : pc2__default.default.dim(" (not detected)")}` : rankedAgent.name,
1853
+ value: rankedAgent
1850
1854
  })),
1851
1855
  { title: "Skip", value: null }
1852
1856
  ]
@@ -1861,7 +1865,7 @@ var add = new commander.Command().name("add").alias("install").description("add
1861
1865
  logger.break();
1862
1866
  logger.error("Please specify an agent with --client");
1863
1867
  logger.error(
1864
- `Available agents: ${SKILL_AGENTS.map((a) => a.id).join(", ")}`
1868
+ `Available agents: ${SKILL_AGENTS.map((skillAgent) => skillAgent.id).join(", ")}`
1865
1869
  );
1866
1870
  logger.break();
1867
1871
  process.exit(1);
@@ -1901,9 +1905,9 @@ var add = new commander.Command().name("add").alias("install").description("add
1901
1905
  type: "select",
1902
1906
  name: "client",
1903
1907
  message: `Which ${highlighter.info("client")} would you like to configure?`,
1904
- choices: MCP_CLIENTS.map((innerClient) => ({
1905
- title: MCP_CLIENT_NAMES[innerClient],
1906
- value: innerClient
1908
+ choices: MCP_CLIENTS.map((mcpClientOption) => ({
1909
+ title: MCP_CLIENT_NAMES[mcpClientOption],
1910
+ value: mcpClientOption
1907
1911
  }))
1908
1912
  });
1909
1913
  if (!client) {
@@ -1917,24 +1921,18 @@ var add = new commander.Command().name("add").alias("install").description("add
1917
1921
  );
1918
1922
  }
1919
1923
  if (addType === "skill") {
1920
- const detectedAgents = detectSkillAgents(cwd);
1921
- if (detectedAgents.length === 0) {
1922
- logger.break();
1923
- logger.warn("No supported agent folders detected.");
1924
- logger.log(
1925
- "Supported agents: " + SKILL_AGENTS.map((a) => a.id).join(", ")
1926
- );
1927
- logger.break();
1928
- process.exit(0);
1929
- }
1924
+ const rankedAgents = getRankedSkillAgents(cwd);
1925
+ const hasDetectedAgents = rankedAgents.some(
1926
+ (rankedAgent) => rankedAgent.detected
1927
+ );
1930
1928
  const { selectedAgent } = await prompts3__default.default({
1931
1929
  type: "select",
1932
1930
  name: "selectedAgent",
1933
1931
  message: `Which ${highlighter.info("agent")} would you like to install the skill for?`,
1934
1932
  choices: [
1935
- ...detectedAgents.map((innerAgent) => ({
1936
- title: innerAgent.name,
1937
- value: innerAgent
1933
+ ...rankedAgents.map((rankedAgent) => ({
1934
+ title: hasDetectedAgents ? `${rankedAgent.name}${rankedAgent.detected ? pc2__default.default.green(" (detected)") : pc2__default.default.dim(" (not detected)")}` : rankedAgent.name,
1935
+ value: rankedAgent
1938
1936
  })),
1939
1937
  { title: "Skip", value: null }
1940
1938
  ]
@@ -1986,7 +1984,7 @@ var add = new commander.Command().name("add").alias("install").description("add
1986
1984
  }
1987
1985
  agentIntegration = validAgent;
1988
1986
  if (projectInfo.installedAgents.length > 0 && !isNonInteractive) {
1989
- const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES[innerAgent] || innerAgent).join(", ");
1987
+ const installedNames = formatInstalledAgentNames2(projectInfo.installedAgents);
1990
1988
  logger.break();
1991
1989
  logger.warn(`${installedNames} is already installed.`);
1992
1990
  const { action } = await prompts3__default.default({
@@ -2017,7 +2015,7 @@ var add = new commander.Command().name("add").alias("install").description("add
2017
2015
  }
2018
2016
  } else if (!isNonInteractive) {
2019
2017
  if (projectInfo.installedAgents.length > 0) {
2020
- const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES[innerAgent] || innerAgent).join(", ");
2018
+ const installedNames = formatInstalledAgentNames2(projectInfo.installedAgents);
2021
2019
  logger.warn(`Currently installed: ${installedNames}`);
2022
2020
  logger.break();
2023
2021
  }
@@ -2025,9 +2023,9 @@ var add = new commander.Command().name("add").alias("install").description("add
2025
2023
  type: "select",
2026
2024
  name: "agent",
2027
2025
  message: `Which ${highlighter.info("agent integration")} would you like to add?`,
2028
- choices: availableAgents.map((innerAgent) => ({
2029
- title: AGENT_NAMES[innerAgent],
2030
- value: innerAgent
2026
+ choices: availableAgents.map((availableAgent) => ({
2027
+ title: AGENT_NAMES[availableAgent],
2028
+ value: availableAgent
2031
2029
  }))
2032
2030
  });
2033
2031
  if (!agent) {
@@ -2036,7 +2034,7 @@ var add = new commander.Command().name("add").alias("install").description("add
2036
2034
  }
2037
2035
  agentIntegration = agent;
2038
2036
  if (projectInfo.installedAgents.length > 0) {
2039
- const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES[innerAgent] || innerAgent).join(", ");
2037
+ const installedNames = formatInstalledAgentNames2(projectInfo.installedAgents);
2040
2038
  const { action } = await prompts3__default.default({
2041
2039
  type: "select",
2042
2040
  name: "action",
@@ -2133,7 +2131,7 @@ var add = new commander.Command().name("add").alias("install").description("add
2133
2131
  }
2134
2132
  }
2135
2133
  projectInfo.installedAgents = projectInfo.installedAgents.filter(
2136
- (innerAgent) => !agentsToRemove.includes(innerAgent)
2134
+ (installedAgent) => !agentsToRemove.includes(installedAgent)
2137
2135
  );
2138
2136
  }
2139
2137
  const addingSpinner = spinner(
@@ -16751,10 +16749,10 @@ PERFORMANCE: Batch multiple actions in one execute call.`,
16751
16749
  };
16752
16750
 
16753
16751
  // src/commands/browser.ts
16754
- var VERSION2 = "0.1.0-beta.9";
16752
+ var VERSION2 = "0.1.0-beta.10";
16755
16753
  var printHeader = () => {
16756
16754
  console.log(
16757
- `${pc__default.default.magenta("\u273F")} ${pc__default.default.bold("React Grab")} ${pc__default.default.gray(VERSION2)}`
16755
+ `${pc2__default.default.magenta("\u273F")} ${pc2__default.default.bold("React Grab")} ${pc2__default.default.gray(VERSION2)}`
16758
16756
  );
16759
16757
  console.log();
16760
16758
  };
@@ -17259,7 +17257,7 @@ browser.addCommand(status);
17259
17257
  browser.addCommand(execute);
17260
17258
  browser.addCommand(pages);
17261
17259
  browser.addCommand(mcp);
17262
- var VERSION3 = "0.1.0-beta.9";
17260
+ var VERSION3 = "0.1.0-beta.10";
17263
17261
  var isMac = process.platform === "darwin";
17264
17262
  var META_LABEL = isMac ? "Cmd" : "Win";
17265
17263
  var ALT_LABEL = isMac ? "Option" : "Alt";
@@ -17469,7 +17467,7 @@ var configure = new commander.Command().name("configure").alias("config").descri
17469
17467
  process.cwd()
17470
17468
  ).action(async (opts2) => {
17471
17469
  console.log(
17472
- `${pc__default.default.magenta("\u273F")} ${pc__default.default.bold("React Grab")} ${pc__default.default.gray(VERSION3)}`
17470
+ `${pc2__default.default.magenta("\u273F")} ${pc2__default.default.bold("React Grab")} ${pc2__default.default.gray(VERSION3)}`
17473
17471
  );
17474
17472
  console.log();
17475
17473
  try {
@@ -17656,7 +17654,7 @@ var configure = new commander.Command().name("configure").alias("config").descri
17656
17654
  `Add this to your ${highlighter.info("init()")} call or ${highlighter.info("data-options")} attribute:`
17657
17655
  );
17658
17656
  logger.break();
17659
- console.log(` ${pc__default.default.cyan(configJson)}`);
17657
+ console.log(` ${pc2__default.default.cyan(configJson)}`);
17660
17658
  logger.break();
17661
17659
  process.exit(1);
17662
17660
  }
@@ -17704,7 +17702,7 @@ var configure = new commander.Command().name("configure").alias("config").descri
17704
17702
  handleError(error48);
17705
17703
  }
17706
17704
  });
17707
- var VERSION4 = "0.1.0-beta.9";
17705
+ var VERSION4 = "0.1.0-beta.10";
17708
17706
  var REPORT_URL = "https://react-grab.com/api/report-cli";
17709
17707
  var DOCS_URL = "https://github.com/aidenybai/react-grab";
17710
17708
  var promptSkillInstall = async (cwd) => {
@@ -17821,7 +17819,7 @@ var init = new commander.Command().name("init").description("initialize React Gr
17821
17819
  process.cwd()
17822
17820
  ).action(async (opts2) => {
17823
17821
  console.log(
17824
- `${pc__default.default.magenta("\u273F")} ${pc__default.default.bold("React Grab")} ${pc__default.default.gray(VERSION4)}`
17822
+ `${pc2__default.default.magenta("\u273F")} ${pc2__default.default.bold("React Grab")} ${pc2__default.default.gray(VERSION4)}`
17825
17823
  );
17826
17824
  console.log();
17827
17825
  try {
@@ -18393,7 +18391,7 @@ var init = new commander.Command().name("init").description("initialize React Gr
18393
18391
  reportToCli("error", void 0, error48);
18394
18392
  }
18395
18393
  });
18396
- var VERSION5 = "0.1.0-beta.9";
18394
+ var VERSION5 = "0.1.0-beta.10";
18397
18395
  var remove = new commander.Command().name("remove").description("remove an agent integration").argument(
18398
18396
  "[agent]",
18399
18397
  "agent to remove (claude-code, cursor, opencode, codex, gemini, amp, ami, visual-edit)"
@@ -18403,7 +18401,7 @@ var remove = new commander.Command().name("remove").description("remove an agent
18403
18401
  process.cwd()
18404
18402
  ).action(async (agentArg, opts2) => {
18405
18403
  console.log(
18406
- `${pc__default.default.magenta("\u273F")} ${pc__default.default.bold("React Grab")} ${pc__default.default.gray(VERSION5)}`
18404
+ `${pc2__default.default.magenta("\u273F")} ${pc2__default.default.bold("React Grab")} ${pc2__default.default.gray(VERSION5)}`
18407
18405
  );
18408
18406
  console.log();
18409
18407
  try {
@@ -18580,7 +18578,7 @@ var uninstall = new commander.Command().name("uninstall").description("uninstall
18580
18578
  process.exit(1);
18581
18579
  }
18582
18580
  });
18583
- var VERSION6 = "0.1.0-beta.9";
18581
+ var VERSION6 = "0.1.0-beta.10";
18584
18582
  var UPDATE_COMMAND = "npm install -g grab@latest";
18585
18583
  var getLatestVersion = () => {
18586
18584
  try {
@@ -18594,7 +18592,7 @@ var getLatestVersion = () => {
18594
18592
  };
18595
18593
  var update = new commander.Command().name("update").alias("upgrade").description("update React Grab CLI to the latest version").option("-y, --yes", "skip confirmation prompts", false).option("--check", "only check for updates, don't install", false).action(async (opts2) => {
18596
18594
  console.log(
18597
- `${pc__default.default.magenta("\u273F")} ${pc__default.default.bold("React Grab")} ${pc__default.default.gray(VERSION6)}`
18595
+ `${pc2__default.default.magenta("\u273F")} ${pc2__default.default.bold("React Grab")} ${pc2__default.default.gray(VERSION6)}`
18598
18596
  );
18599
18597
  console.log();
18600
18598
  const checkSpinner = spinner("Checking for updates").start();
@@ -18660,15 +18658,15 @@ var update = new commander.Command().name("update").alias("upgrade").description
18660
18658
  process.exit(1);
18661
18659
  }
18662
18660
  });
18663
- var isGloballyInstalled = () => {
18661
+ var getGlobalVersion = () => {
18664
18662
  try {
18665
- const result = child_process.execSync("which grab", {
18663
+ const result = child_process.execSync("grab --version", {
18666
18664
  encoding: "utf-8",
18667
18665
  stdio: ["pipe", "pipe", "pipe"]
18668
18666
  }).trim();
18669
- return result.length > 0;
18667
+ return result || null;
18670
18668
  } catch {
18671
- return false;
18669
+ return null;
18672
18670
  }
18673
18671
  };
18674
18672
  var isRunningViaNpx = () => {
@@ -18676,21 +18674,58 @@ var isRunningViaNpx = () => {
18676
18674
  const npmCommand = process.env.npm_command ?? "";
18677
18675
  return npmExecPath.includes("npx") || npmCommand === "exec";
18678
18676
  };
18679
- var installGloballyInBackground = (version2) => {
18680
- if (!isRunningViaNpx() || isGloballyInstalled()) {
18677
+ var promptGlobalInstall = async (version2) => {
18678
+ if (!isRunningViaNpx()) {
18681
18679
  return;
18682
18680
  }
18683
- const packageSpec = `grab@${version2}`;
18684
- const child = child_process.spawn("npm", ["install", "-g", packageSpec], {
18685
- detached: true,
18686
- stdio: "ignore",
18687
- shell: true
18681
+ const globalVersion = getGlobalVersion();
18682
+ const isInstalled = globalVersion !== null;
18683
+ const isOutdated = isInstalled && globalVersion !== version2;
18684
+ if (isInstalled && !isOutdated) {
18685
+ return;
18686
+ }
18687
+ logger.break();
18688
+ const message = isOutdated ? `Update global grab from ${globalVersion} to ${version2}?` : "Install grab globally so you can run it without npx?";
18689
+ const { shouldInstall } = await prompts3__default.default({
18690
+ type: "confirm",
18691
+ name: "shouldInstall",
18692
+ message,
18693
+ initial: true
18688
18694
  });
18689
- child.unref();
18695
+ if (!shouldInstall) {
18696
+ logger.dim(
18697
+ `Skipped. Run ${highlighter.info("npm install -g grab")} to install later.`
18698
+ );
18699
+ logger.break();
18700
+ return;
18701
+ }
18702
+ const packageSpec = `grab@${version2}`;
18703
+ const actionText = isOutdated ? "Updating" : "Installing";
18704
+ const installSpinner = spinner(`${actionText} ${packageSpec} globally`).start();
18705
+ try {
18706
+ child_process.execSync(`npm install -g ${packageSpec}`, {
18707
+ stdio: ["pipe", "pipe", "pipe"]
18708
+ });
18709
+ const successText = isOutdated ? "Updated" : "Installed";
18710
+ installSpinner.succeed(
18711
+ `${successText} globally. Run ${highlighter.info("grab")} to get started.`
18712
+ );
18713
+ } catch {
18714
+ const failText = isOutdated ? "Update" : "Install";
18715
+ installSpinner.fail(`Global ${failText.toLowerCase()} failed`);
18716
+ logger.break();
18717
+ logger.dim(
18718
+ `Try running: ${highlighter.info("sudo npm install -g grab")}`
18719
+ );
18720
+ logger.dim(
18721
+ `Or see: ${highlighter.info("https://docs.npmjs.com/resolving-eacces-permissions-errors")}`
18722
+ );
18723
+ }
18724
+ logger.break();
18690
18725
  };
18691
18726
 
18692
18727
  // src/cli.ts
18693
- var VERSION7 = "0.1.0-beta.9";
18728
+ var VERSION7 = "0.1.0-beta.10";
18694
18729
  var VERSION_API_URL = "https://www.react-grab.com/api/version";
18695
18730
  process.on("SIGINT", () => process.exit(0));
18696
18731
  process.on("SIGTERM", () => process.exit(0));
@@ -18699,7 +18734,6 @@ try {
18699
18734
  });
18700
18735
  } catch {
18701
18736
  }
18702
- installGloballyInBackground(VERSION7);
18703
18737
  var program = new commander.Command().name("grab").description("add React Grab to your project").version(VERSION7, "-v, --version", "display the version number");
18704
18738
  program.addCommand(init);
18705
18739
  program.addCommand(add);
@@ -18708,4 +18742,8 @@ program.addCommand(configure);
18708
18742
  program.addCommand(browser);
18709
18743
  program.addCommand(update);
18710
18744
  program.addCommand(uninstall);
18711
- program.parse();
18745
+ var main = async () => {
18746
+ await promptGlobalInstall(VERSION7);
18747
+ await program.parseAsync();
18748
+ };
18749
+ main();
package/dist/cli.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from 'commander';
3
- import pc from 'picocolors';
3
+ import pc2 from 'picocolors';
4
4
  import prompts3 from 'prompts';
5
5
  import { existsSync, readFileSync, writeFileSync, accessSync, constants, readdirSync } from 'fs';
6
6
  import { join, dirname, basename } from 'path';
7
- import { execSync, spawn } from 'child_process';
7
+ import { execSync } from 'child_process';
8
8
  import ora from 'ora';
9
9
  import { detect } from '@antfu/ni';
10
10
  import { createRequire } from 'module';
@@ -1151,11 +1151,11 @@ var previewPackageJsonAgentRemoval = (projectRoot, agent) => {
1151
1151
  }
1152
1152
  };
1153
1153
  var highlighter = {
1154
- error: pc.red,
1155
- warn: pc.yellow,
1156
- info: pc.cyan,
1157
- success: pc.green,
1158
- dim: pc.dim
1154
+ error: pc2.red,
1155
+ warn: pc2.yellow,
1156
+ info: pc2.cyan,
1157
+ success: pc2.green,
1158
+ dim: pc2.dim
1159
1159
  };
1160
1160
 
1161
1161
  // src/utils/logger.ts
@@ -1253,6 +1253,17 @@ var spinner = (text, options2) => ora({ text, isSilent: options2?.silent });
1253
1253
  var detectSkillAgents = (cwd) => {
1254
1254
  return SKILL_AGENTS.filter((agent) => existsSync(join(cwd, agent.folder)));
1255
1255
  };
1256
+ var getRankedSkillAgents = (cwd) => {
1257
+ const rankedAgents = SKILL_AGENTS.map((agent) => ({
1258
+ ...agent,
1259
+ detected: existsSync(join(cwd, agent.folder))
1260
+ }));
1261
+ return rankedAgents.sort((first, second) => {
1262
+ if (first.detected && !second.detected) return -1;
1263
+ if (!first.detected && second.detected) return 1;
1264
+ return 0;
1265
+ });
1266
+ };
1256
1267
  var findSkillAgent = (id) => {
1257
1268
  return SKILL_AGENTS.find((agent) => agent.id === id);
1258
1269
  };
@@ -1706,7 +1717,8 @@ ${BOLD}File: ${filePath}${RESET}`);
1706
1717
  console.log(formatDiff(diff));
1707
1718
  console.log("\u2500".repeat(60));
1708
1719
  };
1709
- var VERSION = "0.1.0-beta.9";
1720
+ var VERSION = "0.1.0-beta.10";
1721
+ var formatInstalledAgentNames2 = (agents) => agents.map((agent) => AGENT_NAMES[agent] || agent).join(", ");
1710
1722
  var configureMcp = (mcpClient, cwd, customPkg) => {
1711
1723
  const mcpCommand = customPkg ? `npx -y ${customPkg} browser mcp` : `npx -y grab browser mcp`;
1712
1724
  const mcpSpinner = spinner(
@@ -1762,17 +1774,15 @@ var add = new Command().name("add").alias("install").description("add an agent i
1762
1774
  process.cwd()
1763
1775
  ).action(async (agentArg, opts2) => {
1764
1776
  console.log(
1765
- `${pc.magenta("\u273F")} ${pc.bold("React Grab")} ${pc.gray(VERSION)}`
1777
+ `${pc2.magenta("\u273F")} ${pc2.bold("React Grab")} ${pc2.gray(VERSION)}`
1766
1778
  );
1767
1779
  console.log();
1768
1780
  try {
1769
1781
  const cwd = opts2.cwd;
1770
1782
  const isNonInteractive = opts2.yes;
1771
1783
  if (agentArg === "mcp") {
1772
- let mcpClient = opts2.client;
1773
- if (mcpClient === "claude") {
1774
- mcpClient = "claude-code";
1775
- }
1784
+ const rawClient = opts2.client === "claude" ? "claude-code" : opts2.client;
1785
+ let mcpClient = rawClient;
1776
1786
  if (mcpClient && !MCP_CLIENTS.includes(mcpClient)) {
1777
1787
  logger.break();
1778
1788
  logger.error(`Invalid MCP client: ${mcpClient}`);
@@ -1786,9 +1796,9 @@ var add = new Command().name("add").alias("install").description("add an agent i
1786
1796
  type: "select",
1787
1797
  name: "client",
1788
1798
  message: `Which ${highlighter.info("client")} would you like to configure?`,
1789
- choices: MCP_CLIENTS.map((innerClient) => ({
1790
- title: MCP_CLIENT_NAMES[innerClient],
1791
- value: innerClient
1799
+ choices: MCP_CLIENTS.map((mcpClientOption) => ({
1800
+ title: MCP_CLIENT_NAMES[mcpClientOption],
1801
+ value: mcpClientOption
1792
1802
  }))
1793
1803
  });
1794
1804
  if (!client) {
@@ -1809,35 +1819,29 @@ var add = new Command().name("add").alias("install").description("add an agent i
1809
1819
  if (agentArg === "skill") {
1810
1820
  const clientArg = opts2.client;
1811
1821
  let selectedAgent = clientArg ? findSkillAgent(clientArg) : void 0;
1812
- const detectedAgents = detectSkillAgents(cwd);
1813
1822
  if (clientArg && !selectedAgent) {
1814
1823
  logger.break();
1815
1824
  logger.error(`Invalid skill agent: ${clientArg}`);
1816
1825
  logger.error(
1817
- `Available agents: ${SKILL_AGENTS.map((a) => a.id).join(", ")}`
1826
+ `Available agents: ${SKILL_AGENTS.map((skillAgent) => skillAgent.id).join(", ")}`
1818
1827
  );
1819
1828
  logger.break();
1820
1829
  process.exit(1);
1821
1830
  }
1822
1831
  if (!selectedAgent && !isNonInteractive) {
1823
- if (detectedAgents.length === 0) {
1824
- logger.break();
1825
- logger.warn("No supported agent folders detected.");
1826
- logger.log(
1827
- "Supported agents: " + SKILL_AGENTS.map((a) => a.id).join(", ")
1828
- );
1829
- logger.break();
1830
- process.exit(0);
1831
- }
1832
+ const rankedAgents = getRankedSkillAgents(cwd);
1833
+ const hasDetectedAgents = rankedAgents.some(
1834
+ (rankedAgent) => rankedAgent.detected
1835
+ );
1832
1836
  logger.break();
1833
1837
  const { agent } = await prompts3({
1834
1838
  type: "select",
1835
1839
  name: "agent",
1836
1840
  message: `Which ${highlighter.info("agent")} would you like to install the skill for?`,
1837
1841
  choices: [
1838
- ...detectedAgents.map((innerAgent) => ({
1839
- title: innerAgent.name,
1840
- value: innerAgent
1842
+ ...rankedAgents.map((rankedAgent) => ({
1843
+ title: hasDetectedAgents ? `${rankedAgent.name}${rankedAgent.detected ? pc2.green(" (detected)") : pc2.dim(" (not detected)")}` : rankedAgent.name,
1844
+ value: rankedAgent
1841
1845
  })),
1842
1846
  { title: "Skip", value: null }
1843
1847
  ]
@@ -1852,7 +1856,7 @@ var add = new Command().name("add").alias("install").description("add an agent i
1852
1856
  logger.break();
1853
1857
  logger.error("Please specify an agent with --client");
1854
1858
  logger.error(
1855
- `Available agents: ${SKILL_AGENTS.map((a) => a.id).join(", ")}`
1859
+ `Available agents: ${SKILL_AGENTS.map((skillAgent) => skillAgent.id).join(", ")}`
1856
1860
  );
1857
1861
  logger.break();
1858
1862
  process.exit(1);
@@ -1892,9 +1896,9 @@ var add = new Command().name("add").alias("install").description("add an agent i
1892
1896
  type: "select",
1893
1897
  name: "client",
1894
1898
  message: `Which ${highlighter.info("client")} would you like to configure?`,
1895
- choices: MCP_CLIENTS.map((innerClient) => ({
1896
- title: MCP_CLIENT_NAMES[innerClient],
1897
- value: innerClient
1899
+ choices: MCP_CLIENTS.map((mcpClientOption) => ({
1900
+ title: MCP_CLIENT_NAMES[mcpClientOption],
1901
+ value: mcpClientOption
1898
1902
  }))
1899
1903
  });
1900
1904
  if (!client) {
@@ -1908,24 +1912,18 @@ var add = new Command().name("add").alias("install").description("add an agent i
1908
1912
  );
1909
1913
  }
1910
1914
  if (addType === "skill") {
1911
- const detectedAgents = detectSkillAgents(cwd);
1912
- if (detectedAgents.length === 0) {
1913
- logger.break();
1914
- logger.warn("No supported agent folders detected.");
1915
- logger.log(
1916
- "Supported agents: " + SKILL_AGENTS.map((a) => a.id).join(", ")
1917
- );
1918
- logger.break();
1919
- process.exit(0);
1920
- }
1915
+ const rankedAgents = getRankedSkillAgents(cwd);
1916
+ const hasDetectedAgents = rankedAgents.some(
1917
+ (rankedAgent) => rankedAgent.detected
1918
+ );
1921
1919
  const { selectedAgent } = await prompts3({
1922
1920
  type: "select",
1923
1921
  name: "selectedAgent",
1924
1922
  message: `Which ${highlighter.info("agent")} would you like to install the skill for?`,
1925
1923
  choices: [
1926
- ...detectedAgents.map((innerAgent) => ({
1927
- title: innerAgent.name,
1928
- value: innerAgent
1924
+ ...rankedAgents.map((rankedAgent) => ({
1925
+ title: hasDetectedAgents ? `${rankedAgent.name}${rankedAgent.detected ? pc2.green(" (detected)") : pc2.dim(" (not detected)")}` : rankedAgent.name,
1926
+ value: rankedAgent
1929
1927
  })),
1930
1928
  { title: "Skip", value: null }
1931
1929
  ]
@@ -1977,7 +1975,7 @@ var add = new Command().name("add").alias("install").description("add an agent i
1977
1975
  }
1978
1976
  agentIntegration = validAgent;
1979
1977
  if (projectInfo.installedAgents.length > 0 && !isNonInteractive) {
1980
- const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES[innerAgent] || innerAgent).join(", ");
1978
+ const installedNames = formatInstalledAgentNames2(projectInfo.installedAgents);
1981
1979
  logger.break();
1982
1980
  logger.warn(`${installedNames} is already installed.`);
1983
1981
  const { action } = await prompts3({
@@ -2008,7 +2006,7 @@ var add = new Command().name("add").alias("install").description("add an agent i
2008
2006
  }
2009
2007
  } else if (!isNonInteractive) {
2010
2008
  if (projectInfo.installedAgents.length > 0) {
2011
- const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES[innerAgent] || innerAgent).join(", ");
2009
+ const installedNames = formatInstalledAgentNames2(projectInfo.installedAgents);
2012
2010
  logger.warn(`Currently installed: ${installedNames}`);
2013
2011
  logger.break();
2014
2012
  }
@@ -2016,9 +2014,9 @@ var add = new Command().name("add").alias("install").description("add an agent i
2016
2014
  type: "select",
2017
2015
  name: "agent",
2018
2016
  message: `Which ${highlighter.info("agent integration")} would you like to add?`,
2019
- choices: availableAgents.map((innerAgent) => ({
2020
- title: AGENT_NAMES[innerAgent],
2021
- value: innerAgent
2017
+ choices: availableAgents.map((availableAgent) => ({
2018
+ title: AGENT_NAMES[availableAgent],
2019
+ value: availableAgent
2022
2020
  }))
2023
2021
  });
2024
2022
  if (!agent) {
@@ -2027,7 +2025,7 @@ var add = new Command().name("add").alias("install").description("add an agent i
2027
2025
  }
2028
2026
  agentIntegration = agent;
2029
2027
  if (projectInfo.installedAgents.length > 0) {
2030
- const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES[innerAgent] || innerAgent).join(", ");
2028
+ const installedNames = formatInstalledAgentNames2(projectInfo.installedAgents);
2031
2029
  const { action } = await prompts3({
2032
2030
  type: "select",
2033
2031
  name: "action",
@@ -2124,7 +2122,7 @@ var add = new Command().name("add").alias("install").description("add an agent i
2124
2122
  }
2125
2123
  }
2126
2124
  projectInfo.installedAgents = projectInfo.installedAgents.filter(
2127
- (innerAgent) => !agentsToRemove.includes(innerAgent)
2125
+ (installedAgent) => !agentsToRemove.includes(installedAgent)
2128
2126
  );
2129
2127
  }
2130
2128
  const addingSpinner = spinner(
@@ -16742,10 +16740,10 @@ PERFORMANCE: Batch multiple actions in one execute call.`,
16742
16740
  };
16743
16741
 
16744
16742
  // src/commands/browser.ts
16745
- var VERSION2 = "0.1.0-beta.9";
16743
+ var VERSION2 = "0.1.0-beta.10";
16746
16744
  var printHeader = () => {
16747
16745
  console.log(
16748
- `${pc.magenta("\u273F")} ${pc.bold("React Grab")} ${pc.gray(VERSION2)}`
16746
+ `${pc2.magenta("\u273F")} ${pc2.bold("React Grab")} ${pc2.gray(VERSION2)}`
16749
16747
  );
16750
16748
  console.log();
16751
16749
  };
@@ -17250,7 +17248,7 @@ browser.addCommand(status);
17250
17248
  browser.addCommand(execute);
17251
17249
  browser.addCommand(pages);
17252
17250
  browser.addCommand(mcp);
17253
- var VERSION3 = "0.1.0-beta.9";
17251
+ var VERSION3 = "0.1.0-beta.10";
17254
17252
  var isMac = process.platform === "darwin";
17255
17253
  var META_LABEL = isMac ? "Cmd" : "Win";
17256
17254
  var ALT_LABEL = isMac ? "Option" : "Alt";
@@ -17460,7 +17458,7 @@ var configure = new Command().name("configure").alias("config").description("con
17460
17458
  process.cwd()
17461
17459
  ).action(async (opts2) => {
17462
17460
  console.log(
17463
- `${pc.magenta("\u273F")} ${pc.bold("React Grab")} ${pc.gray(VERSION3)}`
17461
+ `${pc2.magenta("\u273F")} ${pc2.bold("React Grab")} ${pc2.gray(VERSION3)}`
17464
17462
  );
17465
17463
  console.log();
17466
17464
  try {
@@ -17647,7 +17645,7 @@ var configure = new Command().name("configure").alias("config").description("con
17647
17645
  `Add this to your ${highlighter.info("init()")} call or ${highlighter.info("data-options")} attribute:`
17648
17646
  );
17649
17647
  logger.break();
17650
- console.log(` ${pc.cyan(configJson)}`);
17648
+ console.log(` ${pc2.cyan(configJson)}`);
17651
17649
  logger.break();
17652
17650
  process.exit(1);
17653
17651
  }
@@ -17695,7 +17693,7 @@ var configure = new Command().name("configure").alias("config").description("con
17695
17693
  handleError(error48);
17696
17694
  }
17697
17695
  });
17698
- var VERSION4 = "0.1.0-beta.9";
17696
+ var VERSION4 = "0.1.0-beta.10";
17699
17697
  var REPORT_URL = "https://react-grab.com/api/report-cli";
17700
17698
  var DOCS_URL = "https://github.com/aidenybai/react-grab";
17701
17699
  var promptSkillInstall = async (cwd) => {
@@ -17812,7 +17810,7 @@ var init = new Command().name("init").description("initialize React Grab in your
17812
17810
  process.cwd()
17813
17811
  ).action(async (opts2) => {
17814
17812
  console.log(
17815
- `${pc.magenta("\u273F")} ${pc.bold("React Grab")} ${pc.gray(VERSION4)}`
17813
+ `${pc2.magenta("\u273F")} ${pc2.bold("React Grab")} ${pc2.gray(VERSION4)}`
17816
17814
  );
17817
17815
  console.log();
17818
17816
  try {
@@ -18384,7 +18382,7 @@ var init = new Command().name("init").description("initialize React Grab in your
18384
18382
  reportToCli("error", void 0, error48);
18385
18383
  }
18386
18384
  });
18387
- var VERSION5 = "0.1.0-beta.9";
18385
+ var VERSION5 = "0.1.0-beta.10";
18388
18386
  var remove = new Command().name("remove").description("remove an agent integration").argument(
18389
18387
  "[agent]",
18390
18388
  "agent to remove (claude-code, cursor, opencode, codex, gemini, amp, ami, visual-edit)"
@@ -18394,7 +18392,7 @@ var remove = new Command().name("remove").description("remove an agent integrati
18394
18392
  process.cwd()
18395
18393
  ).action(async (agentArg, opts2) => {
18396
18394
  console.log(
18397
- `${pc.magenta("\u273F")} ${pc.bold("React Grab")} ${pc.gray(VERSION5)}`
18395
+ `${pc2.magenta("\u273F")} ${pc2.bold("React Grab")} ${pc2.gray(VERSION5)}`
18398
18396
  );
18399
18397
  console.log();
18400
18398
  try {
@@ -18571,7 +18569,7 @@ var uninstall = new Command().name("uninstall").description("uninstall React Gra
18571
18569
  process.exit(1);
18572
18570
  }
18573
18571
  });
18574
- var VERSION6 = "0.1.0-beta.9";
18572
+ var VERSION6 = "0.1.0-beta.10";
18575
18573
  var UPDATE_COMMAND = "npm install -g grab@latest";
18576
18574
  var getLatestVersion = () => {
18577
18575
  try {
@@ -18585,7 +18583,7 @@ var getLatestVersion = () => {
18585
18583
  };
18586
18584
  var update = new Command().name("update").alias("upgrade").description("update React Grab CLI to the latest version").option("-y, --yes", "skip confirmation prompts", false).option("--check", "only check for updates, don't install", false).action(async (opts2) => {
18587
18585
  console.log(
18588
- `${pc.magenta("\u273F")} ${pc.bold("React Grab")} ${pc.gray(VERSION6)}`
18586
+ `${pc2.magenta("\u273F")} ${pc2.bold("React Grab")} ${pc2.gray(VERSION6)}`
18589
18587
  );
18590
18588
  console.log();
18591
18589
  const checkSpinner = spinner("Checking for updates").start();
@@ -18651,15 +18649,15 @@ var update = new Command().name("update").alias("upgrade").description("update R
18651
18649
  process.exit(1);
18652
18650
  }
18653
18651
  });
18654
- var isGloballyInstalled = () => {
18652
+ var getGlobalVersion = () => {
18655
18653
  try {
18656
- const result = execSync("which grab", {
18654
+ const result = execSync("grab --version", {
18657
18655
  encoding: "utf-8",
18658
18656
  stdio: ["pipe", "pipe", "pipe"]
18659
18657
  }).trim();
18660
- return result.length > 0;
18658
+ return result || null;
18661
18659
  } catch {
18662
- return false;
18660
+ return null;
18663
18661
  }
18664
18662
  };
18665
18663
  var isRunningViaNpx = () => {
@@ -18667,21 +18665,58 @@ var isRunningViaNpx = () => {
18667
18665
  const npmCommand = process.env.npm_command ?? "";
18668
18666
  return npmExecPath.includes("npx") || npmCommand === "exec";
18669
18667
  };
18670
- var installGloballyInBackground = (version2) => {
18671
- if (!isRunningViaNpx() || isGloballyInstalled()) {
18668
+ var promptGlobalInstall = async (version2) => {
18669
+ if (!isRunningViaNpx()) {
18672
18670
  return;
18673
18671
  }
18674
- const packageSpec = `grab@${version2}`;
18675
- const child = spawn("npm", ["install", "-g", packageSpec], {
18676
- detached: true,
18677
- stdio: "ignore",
18678
- shell: true
18672
+ const globalVersion = getGlobalVersion();
18673
+ const isInstalled = globalVersion !== null;
18674
+ const isOutdated = isInstalled && globalVersion !== version2;
18675
+ if (isInstalled && !isOutdated) {
18676
+ return;
18677
+ }
18678
+ logger.break();
18679
+ const message = isOutdated ? `Update global grab from ${globalVersion} to ${version2}?` : "Install grab globally so you can run it without npx?";
18680
+ const { shouldInstall } = await prompts3({
18681
+ type: "confirm",
18682
+ name: "shouldInstall",
18683
+ message,
18684
+ initial: true
18679
18685
  });
18680
- child.unref();
18686
+ if (!shouldInstall) {
18687
+ logger.dim(
18688
+ `Skipped. Run ${highlighter.info("npm install -g grab")} to install later.`
18689
+ );
18690
+ logger.break();
18691
+ return;
18692
+ }
18693
+ const packageSpec = `grab@${version2}`;
18694
+ const actionText = isOutdated ? "Updating" : "Installing";
18695
+ const installSpinner = spinner(`${actionText} ${packageSpec} globally`).start();
18696
+ try {
18697
+ execSync(`npm install -g ${packageSpec}`, {
18698
+ stdio: ["pipe", "pipe", "pipe"]
18699
+ });
18700
+ const successText = isOutdated ? "Updated" : "Installed";
18701
+ installSpinner.succeed(
18702
+ `${successText} globally. Run ${highlighter.info("grab")} to get started.`
18703
+ );
18704
+ } catch {
18705
+ const failText = isOutdated ? "Update" : "Install";
18706
+ installSpinner.fail(`Global ${failText.toLowerCase()} failed`);
18707
+ logger.break();
18708
+ logger.dim(
18709
+ `Try running: ${highlighter.info("sudo npm install -g grab")}`
18710
+ );
18711
+ logger.dim(
18712
+ `Or see: ${highlighter.info("https://docs.npmjs.com/resolving-eacces-permissions-errors")}`
18713
+ );
18714
+ }
18715
+ logger.break();
18681
18716
  };
18682
18717
 
18683
18718
  // src/cli.ts
18684
- var VERSION7 = "0.1.0-beta.9";
18719
+ var VERSION7 = "0.1.0-beta.10";
18685
18720
  var VERSION_API_URL = "https://www.react-grab.com/api/version";
18686
18721
  process.on("SIGINT", () => process.exit(0));
18687
18722
  process.on("SIGTERM", () => process.exit(0));
@@ -18690,7 +18725,6 @@ try {
18690
18725
  });
18691
18726
  } catch {
18692
18727
  }
18693
- installGloballyInBackground(VERSION7);
18694
18728
  var program = new Command().name("grab").description("add React Grab to your project").version(VERSION7, "-v, --version", "display the version number");
18695
18729
  program.addCommand(init);
18696
18730
  program.addCommand(add);
@@ -18699,4 +18733,8 @@ program.addCommand(configure);
18699
18733
  program.addCommand(browser);
18700
18734
  program.addCommand(update);
18701
18735
  program.addCommand(uninstall);
18702
- program.parse();
18736
+ var main = async () => {
18737
+ await promptGlobalInstall(VERSION7);
18738
+ await program.parseAsync();
18739
+ };
18740
+ main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-grab/cli",
3
- "version": "0.1.0-beta.10",
3
+ "version": "0.1.0-beta.11",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "react-grab": "./dist/cli.js"
@@ -30,7 +30,7 @@
30
30
  "playwright-core": "^1.50.0",
31
31
  "prompts": "^2.4.2",
32
32
  "zod": "^4.3.5",
33
- "@react-grab/browser": "0.1.0-beta.10"
33
+ "@react-grab/browser": "0.1.0-beta.11"
34
34
  },
35
35
  "scripts": {
36
36
  "dev": "tsup --watch",