@react-grab/cli 0.1.0-beta.7 → 0.1.0-beta.9

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 (4) hide show
  1. package/README.md +19 -19
  2. package/dist/cli.cjs +231 -150
  3. package/dist/cli.js +231 -150
  4. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -127,18 +127,18 @@ var MCP_CLIENTS = [
127
127
  // "claude",
128
128
  ];
129
129
  var MCP_CLIENT_NAMES = {
130
- "cursor": "Cursor",
130
+ cursor: "Cursor",
131
131
  "claude-code": "Claude Code",
132
- "vscode": "VSCode",
133
- "opencode": "OpenCode",
134
- "codex": "Codex",
132
+ vscode: "VSCode",
133
+ opencode: "OpenCode",
134
+ codex: "Codex",
135
135
  "gemini-cli": "Gemini CLI",
136
136
  // "cline": "Cline",
137
137
  // "roo-cline": "Roo Cline",
138
- "windsurf": "Windsurf",
139
- "zed": "Zed",
138
+ windsurf: "Windsurf",
139
+ zed: "Zed",
140
140
  // "warp": "Warp",
141
- "droid": "Droid"
141
+ droid: "Droid"
142
142
  // "claude": "Claude Desktop",
143
143
  };
144
144
  var SKILL_AGENTS = [
@@ -1258,7 +1258,9 @@ var findSkillAgent = (id) => {
1258
1258
  };
1259
1259
  var formatInstalledAgentNames = (agents) => agents.map((agent) => AGENT_NAMES[agent] ?? agent).join(", ");
1260
1260
  var applyTransformWithFeedback = (result, message) => {
1261
- const writeSpinner = spinner(message ?? `Applying changes to ${result.filePath}.`).start();
1261
+ const writeSpinner = spinner(
1262
+ message ?? `Applying changes to ${result.filePath}.`
1263
+ ).start();
1262
1264
  const writeResult = applyTransform(result);
1263
1265
  if (!writeResult.success) {
1264
1266
  writeSpinner.fail();
@@ -1270,7 +1272,9 @@ var applyTransformWithFeedback = (result, message) => {
1270
1272
  writeSpinner.succeed();
1271
1273
  };
1272
1274
  var applyPackageJsonWithFeedback = (result, message) => {
1273
- const writeSpinner = spinner(message ?? `Applying changes to ${result.filePath}.`).start();
1275
+ const writeSpinner = spinner(
1276
+ message ?? `Applying changes to ${result.filePath}.`
1277
+ ).start();
1274
1278
  const writeResult = applyPackageJsonTransform(result);
1275
1279
  if (!writeResult.success) {
1276
1280
  writeSpinner.fail();
@@ -1702,21 +1706,29 @@ ${BOLD}File: ${filePath}${RESET}`);
1702
1706
  console.log(formatDiff(diff));
1703
1707
  console.log("\u2500".repeat(60));
1704
1708
  };
1705
- var VERSION = "0.1.0-beta.6";
1709
+ var VERSION = "0.1.0-beta.8";
1706
1710
  var configureMcp = (mcpClient, cwd, customPkg) => {
1707
- const mcpCommand = customPkg ? `npx -y ${customPkg} browser mcp` : `npx -y @react-grab/cli browser mcp`;
1708
- const mcpSpinner = spinner(`Installing MCP server for ${MCP_CLIENT_NAMES[mcpClient]}`).start();
1711
+ const mcpCommand = customPkg ? `npx -y ${customPkg} browser mcp` : `npx -y grab browser mcp`;
1712
+ const mcpSpinner = spinner(
1713
+ `Installing MCP server for ${MCP_CLIENT_NAMES[mcpClient]}`
1714
+ ).start();
1709
1715
  try {
1710
- execSync(
1711
- `npx -y install-mcp '${mcpCommand}' --client ${mcpClient} --yes`,
1712
- { stdio: "ignore", cwd }
1716
+ execSync(`npx -y install-mcp '${mcpCommand}' --client ${mcpClient} --yes`, {
1717
+ stdio: "ignore",
1718
+ cwd
1719
+ });
1720
+ mcpSpinner.succeed(
1721
+ `MCP server installed for ${MCP_CLIENT_NAMES[mcpClient]}`
1713
1722
  );
1714
- mcpSpinner.succeed(`MCP server installed for ${MCP_CLIENT_NAMES[mcpClient]}`);
1715
1723
  logger.break();
1716
1724
  process.exit(0);
1717
1725
  } catch {
1718
- mcpSpinner.fail(`Failed to configure MCP for ${MCP_CLIENT_NAMES[mcpClient]}`);
1719
- logger.dim(`Try manually: npx -y install-mcp '${mcpCommand}' --client ${mcpClient}`);
1726
+ mcpSpinner.fail(
1727
+ `Failed to configure MCP for ${MCP_CLIENT_NAMES[mcpClient]}`
1728
+ );
1729
+ logger.dim(
1730
+ `Try manually: npx -y install-mcp '${mcpCommand}' --client ${mcpClient}`
1731
+ );
1720
1732
  logger.break();
1721
1733
  process.exit(1);
1722
1734
  }
@@ -1734,21 +1746,17 @@ var installSkill = (agent, cwd) => {
1734
1746
  process.exit(0);
1735
1747
  } catch {
1736
1748
  skillSpinner.fail(`Failed to install skill for ${agent.name}`);
1737
- logger.warn(`Try manually: npx -y add-skill aidenybai/react-grab --agent ${agent.id}`);
1749
+ logger.warn(
1750
+ `Try manually: npx -y add-skill aidenybai/react-grab --agent ${agent.id}`
1751
+ );
1738
1752
  logger.break();
1739
1753
  process.exit(1);
1740
1754
  }
1741
1755
  };
1742
- var add = new Command().name("add").alias("install").description("add browser automation for your AI agent").argument(
1743
- "[agent]",
1744
- `agent to add (${AGENTS.join(", ")}, mcp, skill)`
1745
- ).option("-y, --yes", "skip confirmation prompts", false).option(
1756
+ var add = new Command().name("add").alias("install").description("add browser automation for your AI agent").argument("[agent]", `agent to add (${AGENTS.join(", ")}, mcp, skill)`).option("-y, --yes", "skip confirmation prompts", false).option(
1746
1757
  "--client <client>",
1747
1758
  "MCP client to configure (cursor, claude-code, vscode, etc.)"
1748
- ).option(
1749
- "--pkg <pkg>",
1750
- "custom package URL for CLI (e.g., @react-grab/cli)"
1751
- ).option(
1759
+ ).option("--pkg <pkg>", "custom package URL for CLI (e.g., grab)").option(
1752
1760
  "-c, --cwd <cwd>",
1753
1761
  "working directory (defaults to current directory)",
1754
1762
  process.cwd()
@@ -1805,7 +1813,9 @@ var add = new Command().name("add").alias("install").description("add browser au
1805
1813
  if (clientArg && !selectedAgent) {
1806
1814
  logger.break();
1807
1815
  logger.error(`Invalid skill agent: ${clientArg}`);
1808
- logger.error(`Available agents: ${SKILL_AGENTS.map((a) => a.id).join(", ")}`);
1816
+ logger.error(
1817
+ `Available agents: ${SKILL_AGENTS.map((a) => a.id).join(", ")}`
1818
+ );
1809
1819
  logger.break();
1810
1820
  process.exit(1);
1811
1821
  }
@@ -1813,7 +1823,9 @@ var add = new Command().name("add").alias("install").description("add browser au
1813
1823
  if (detectedAgents.length === 0) {
1814
1824
  logger.break();
1815
1825
  logger.warn("No supported agent folders detected.");
1816
- logger.log("Supported agents: " + SKILL_AGENTS.map((a) => a.id).join(", "));
1826
+ logger.log(
1827
+ "Supported agents: " + SKILL_AGENTS.map((a) => a.id).join(", ")
1828
+ );
1817
1829
  logger.break();
1818
1830
  process.exit(0);
1819
1831
  }
@@ -1839,7 +1851,9 @@ var add = new Command().name("add").alias("install").description("add browser au
1839
1851
  if (!selectedAgent) {
1840
1852
  logger.break();
1841
1853
  logger.error("Please specify an agent with --client");
1842
- logger.error(`Available agents: ${SKILL_AGENTS.map((a) => a.id).join(", ")}`);
1854
+ logger.error(
1855
+ `Available agents: ${SKILL_AGENTS.map((a) => a.id).join(", ")}`
1856
+ );
1843
1857
  logger.break();
1844
1858
  process.exit(1);
1845
1859
  }
@@ -1887,14 +1901,20 @@ var add = new Command().name("add").alias("install").description("add browser au
1887
1901
  logger.break();
1888
1902
  process.exit(1);
1889
1903
  }
1890
- configureMcp(client, cwd, opts2.pkg);
1904
+ configureMcp(
1905
+ client,
1906
+ cwd,
1907
+ opts2.pkg
1908
+ );
1891
1909
  }
1892
1910
  if (addType === "skill") {
1893
1911
  const detectedAgents = detectSkillAgents(cwd);
1894
1912
  if (detectedAgents.length === 0) {
1895
1913
  logger.break();
1896
1914
  logger.warn("No supported agent folders detected.");
1897
- logger.log("Supported agents: " + SKILL_AGENTS.map((a) => a.id).join(", "));
1915
+ logger.log(
1916
+ "Supported agents: " + SKILL_AGENTS.map((a) => a.id).join(", ")
1917
+ );
1898
1918
  logger.break();
1899
1919
  process.exit(0);
1900
1920
  }
@@ -2451,9 +2471,14 @@ var createComponentHelper = (getActivePage2) => {
2451
2471
  async (args) => {
2452
2472
  const g2 = globalThis;
2453
2473
  if (!g2.__REACT_GRAB_FIND_BY_COMPONENT__) {
2454
- throw new Error("React introspection not available. Make sure react-grab is installed.");
2474
+ throw new Error(
2475
+ "React introspection not available. Make sure react-grab is installed."
2476
+ );
2455
2477
  }
2456
- const result = await g2.__REACT_GRAB_FIND_BY_COMPONENT__(args.name, args.nth !== void 0 ? { nth: args.nth } : void 0);
2478
+ const result = await g2.__REACT_GRAB_FIND_BY_COMPONENT__(
2479
+ args.name,
2480
+ args.nth !== void 0 ? { nth: args.nth } : void 0
2481
+ );
2457
2482
  if (!result) return null;
2458
2483
  if (args.nth !== void 0) {
2459
2484
  const single = result;
@@ -2464,7 +2489,10 @@ var createComponentHelper = (getActivePage2) => {
2464
2489
  },
2465
2490
  { name: componentName, nth }
2466
2491
  );
2467
- const isNull = await currentPage2.evaluate((value) => value === null, elementHandles);
2492
+ const isNull = await currentPage2.evaluate(
2493
+ (value) => value === null,
2494
+ elementHandles
2495
+ );
2468
2496
  if (isNull) {
2469
2497
  await elementHandles.dispose();
2470
2498
  return null;
@@ -2512,7 +2540,8 @@ var createDragHelper = (getActivePage2) => {
2512
2540
  }) => {
2513
2541
  const fromElement = document.querySelector(fromSel);
2514
2542
  const toElement = document.querySelector(toSel);
2515
- if (!fromElement) throw new Error(`Source element not found: ${fromSel}`);
2543
+ if (!fromElement)
2544
+ throw new Error(`Source element not found: ${fromSel}`);
2516
2545
  if (!toElement) throw new Error(`Target element not found: ${toSel}`);
2517
2546
  const dataTransferObject = new DataTransfer();
2518
2547
  for (const [type, value] of Object.entries(data)) {
@@ -2574,16 +2603,26 @@ var createDispatchHelper = (getActivePage2) => {
2574
2603
  for (const [type, value] of Object.entries(opts2.dataTransfer)) {
2575
2604
  dataTransferObject.setData(type, value);
2576
2605
  }
2577
- return new DragEvent(eventType, { ...baseOpts, dataTransfer: dataTransferObject });
2606
+ return new DragEvent(eventType, {
2607
+ ...baseOpts,
2608
+ dataTransfer: dataTransferObject
2609
+ });
2578
2610
  }
2579
2611
  if (opts2.detail !== void 0) {
2580
- return new CustomEvent(eventType, { ...baseOpts, detail: opts2.detail });
2612
+ return new CustomEvent(eventType, {
2613
+ ...baseOpts,
2614
+ detail: opts2.detail
2615
+ });
2581
2616
  }
2582
2617
  return new Event(eventType, baseOpts);
2583
2618
  };
2584
2619
  return element.dispatchEvent(createEvent());
2585
2620
  },
2586
- { sel: selector, eventType: event, opts: { bubbles, cancelable, dataTransfer, detail } }
2621
+ {
2622
+ sel: selector,
2623
+ eventType: event,
2624
+ opts: { bubbles, cancelable, dataTransfer, detail }
2625
+ }
2587
2626
  );
2588
2627
  };
2589
2628
  };
@@ -2632,11 +2671,16 @@ var createWaitForHelper = (getActivePage2) => {
2632
2671
  const currentPage2 = getActivePage2();
2633
2672
  const timeout = options2?.timeout;
2634
2673
  if (LOAD_STATES.has(selectorOrState)) {
2635
- await currentPage2.waitForLoadState(selectorOrState, { timeout });
2674
+ await currentPage2.waitForLoadState(
2675
+ selectorOrState,
2676
+ { timeout }
2677
+ );
2636
2678
  return;
2637
2679
  }
2638
2680
  if (/^e\d+$/.test(selectorOrState)) {
2639
- await currentPage2.waitForSelector(`[aria-ref="${selectorOrState}"]`, { timeout });
2681
+ await currentPage2.waitForSelector(`[aria-ref="${selectorOrState}"]`, {
2682
+ timeout
2683
+ });
2640
2684
  return;
2641
2685
  }
2642
2686
  await currentPage2.waitForSelector(selectorOrState, { timeout });
@@ -16473,7 +16517,9 @@ After getting refs, use browser_execute with: getRef('e1').click()`,
16473
16517
  screenshot: external_exports.boolean().optional().default(false).describe(
16474
16518
  "Viewport screenshot. For element screenshots (PREFERRED), use browser_execute: getRef('eX').screenshot()"
16475
16519
  ),
16476
- reactTree: external_exports.boolean().optional().default(false).describe("(Experimental) React tree view. Note: Regular snapshot already includes [component=X] and [source=X] - prefer that."),
16520
+ reactTree: external_exports.boolean().optional().default(false).describe(
16521
+ "(Experimental) React tree view. Note: Regular snapshot already includes [component=X] and [source=X] - prefer that."
16522
+ ),
16477
16523
  includeProps: external_exports.boolean().optional().default(false).describe("Include props when reactTree=true")
16478
16524
  }
16479
16525
  },
@@ -16502,7 +16548,10 @@ After getting refs, use browser_execute with: getRef('e1').click()`,
16502
16548
  }
16503
16549
  return g2.__REACT_GRAB_GET_COMPONENT_TREE__(opts2);
16504
16550
  },
16505
- { maxDepth: maxDepth ?? DEFAULT_COMPONENT_TREE_MAX_DEPTH, includeProps: includeProps ?? false }
16551
+ {
16552
+ maxDepth: maxDepth ?? DEFAULT_COMPONENT_TREE_MAX_DEPTH,
16553
+ includeProps: includeProps ?? false
16554
+ }
16506
16555
  );
16507
16556
  const renderTree = (nodes) => {
16508
16557
  const lines = [];
@@ -16523,7 +16572,9 @@ After getting refs, use browser_execute with: getRef('e1').click()`,
16523
16572
  };
16524
16573
  textResult = renderTree(componentTree) || "No React components found. Make sure react-grab is installed and the page uses React.";
16525
16574
  } else {
16526
- textResult = await createSnapshotHelper(() => activePage)({ maxDepth });
16575
+ textResult = await createSnapshotHelper(() => activePage)({
16576
+ maxDepth
16577
+ });
16527
16578
  }
16528
16579
  if (screenshot) {
16529
16580
  const screenshotBuffer = await activePage.screenshot({
@@ -16691,7 +16742,7 @@ PERFORMANCE: Batch multiple actions in one execute call.`,
16691
16742
  };
16692
16743
 
16693
16744
  // src/commands/browser.ts
16694
- var VERSION2 = "0.1.0-beta.6";
16745
+ var VERSION2 = "0.1.0-beta.8";
16695
16746
  var printHeader = () => {
16696
16747
  console.log(
16697
16748
  `${pc.magenta("\u273F")} ${pc.bold("React Grab")} ${pc.gray(VERSION2)}`
@@ -16757,7 +16808,10 @@ var dump = new Command().name("dump").description("dump cookies from a browser")
16757
16808
  exitWithError(error48);
16758
16809
  }
16759
16810
  });
16760
- var start = new Command().name("start").description("start browser server manually (auto-starts on first execute)").option("-p, --port <port>", "HTTP API port", String(DEFAULT_SERVER_PORT)).option("--headed", "show browser window (default is headless)").option("-b, --browser <browser>", "source browser for cookies (chrome, edge, brave, arc)").option("-d, --domain <domain>", "only load cookies matching this domain").option("--foreground", "run in foreground instead of detaching").action(async (options2) => {
16811
+ var start = new Command().name("start").description("start browser server manually (auto-starts on first execute)").option("-p, --port <port>", "HTTP API port", String(DEFAULT_SERVER_PORT)).option("--headed", "show browser window (default is headless)").option(
16812
+ "-b, --browser <browser>",
16813
+ "source browser for cookies (chrome, edge, brave, arc)"
16814
+ ).option("-d, --domain <domain>", "only load cookies matching this domain").option("--foreground", "run in foreground instead of detaching").action(async (options2) => {
16761
16815
  const isForeground = options2.foreground;
16762
16816
  if (!isForeground) {
16763
16817
  printHeader();
@@ -16817,7 +16871,9 @@ var start = new Command().name("start").description("start browser server manual
16817
16871
  await new Promise(() => {
16818
16872
  });
16819
16873
  } catch (error48) {
16820
- console.error(error48 instanceof Error ? error48.message : "Failed to start server");
16874
+ console.error(
16875
+ error48 instanceof Error ? error48.message : "Failed to start server"
16876
+ );
16821
16877
  process.exit(1);
16822
16878
  }
16823
16879
  });
@@ -16844,17 +16900,21 @@ var status = new Command().name("status").description("check server status").opt
16844
16900
  const info = getServerInfo();
16845
16901
  let pagesData = [];
16846
16902
  try {
16847
- const pagesResponse = await fetch(`http://127.0.0.1:${info?.port}/pages`);
16903
+ const pagesResponse = await fetch(
16904
+ `http://127.0.0.1:${info?.port}/pages`
16905
+ );
16848
16906
  const pagesResult = await pagesResponse.json();
16849
16907
  pagesData = pagesResult.pages;
16850
16908
  } catch {
16851
16909
  }
16852
16910
  if (jsonMode) {
16853
- console.log(JSON.stringify({
16854
- running: true,
16855
- port: info?.port,
16856
- pages: pagesData
16857
- }));
16911
+ console.log(
16912
+ JSON.stringify({
16913
+ running: true,
16914
+ port: info?.port,
16915
+ pages: pagesData
16916
+ })
16917
+ );
16858
16918
  } else {
16859
16919
  logger.success(`Server running on port ${info?.port}`);
16860
16920
  if (pagesData.length > 0) {
@@ -16867,17 +16927,30 @@ var status = new Command().name("status").description("check server status").opt
16867
16927
  }
16868
16928
  } else {
16869
16929
  if (jsonMode) {
16870
- console.log(JSON.stringify({
16871
- running: false,
16872
- port: null,
16873
- pages: []
16874
- }));
16930
+ console.log(
16931
+ JSON.stringify({
16932
+ running: false,
16933
+ port: null,
16934
+ pages: []
16935
+ })
16936
+ );
16875
16937
  } else {
16876
16938
  logger.log("Server not running");
16877
16939
  }
16878
16940
  }
16879
16941
  });
16880
- var execute = new Command().name("execute").description("run Playwright code with 'page' variable available").argument("<code>", "JavaScript code to execute (use 'page' for Playwright Page, 'return' for output)").option("-b, --browser <browser>", "source browser for cookies").option("-d, --domain <domain>", "filter cookies by domain").option("-u, --url <url>", "navigate to URL before executing").option("-p, --page <name>", "named page context for multi-turn sessions", "default").option("-t, --timeout <ms>", `navigation timeout in milliseconds (default: ${DEFAULT_NAVIGATION_TIMEOUT_MS})`, String(DEFAULT_NAVIGATION_TIMEOUT_MS)).action(async (code, options2) => {
16942
+ var execute = new Command().name("execute").description("run Playwright code with 'page' variable available").argument(
16943
+ "<code>",
16944
+ "JavaScript code to execute (use 'page' for Playwright Page, 'return' for output)"
16945
+ ).option("-b, --browser <browser>", "source browser for cookies").option("-d, --domain <domain>", "filter cookies by domain").option("-u, --url <url>", "navigate to URL before executing").option(
16946
+ "-p, --page <name>",
16947
+ "named page context for multi-turn sessions",
16948
+ "default"
16949
+ ).option(
16950
+ "-t, --timeout <ms>",
16951
+ `navigation timeout in milliseconds (default: ${DEFAULT_NAVIGATION_TIMEOUT_MS})`,
16952
+ String(DEFAULT_NAVIGATION_TIMEOUT_MS)
16953
+ ).action(async (code, options2) => {
16881
16954
  const pageName = options2.page;
16882
16955
  const navigationTimeout = parseInt(options2.timeout, 10);
16883
16956
  let activePage = null;
@@ -16943,7 +17016,15 @@ var execute = new Command().name("execute").description("run Playwright code wit
16943
17016
  );
16944
17017
  console.log(JSON.stringify(await outputJson(true, result)));
16945
17018
  } catch (error48) {
16946
- console.log(JSON.stringify(await outputJson(false, void 0, error48 instanceof Error ? error48.message : "Failed")));
17019
+ console.log(
17020
+ JSON.stringify(
17021
+ await outputJson(
17022
+ false,
17023
+ void 0,
17024
+ error48 instanceof Error ? error48.message : "Failed"
17025
+ )
17026
+ )
17027
+ );
16947
17028
  exitCode = 1;
16948
17029
  } finally {
16949
17030
  if (activePage && pageOpenHandler) {
@@ -16965,13 +17046,19 @@ var pages = new Command().name("pages").description("manage server pages").optio
16965
17046
  const pagesResponse2 = await fetch(`${serverUrl}/pages`);
16966
17047
  const pagesResult2 = await pagesResponse2.json();
16967
17048
  for (const pageEntry of pagesResult2.pages) {
16968
- await fetch(`${serverUrl}/pages/${encodeURIComponent(pageEntry.name)}`, { method: "DELETE" });
17049
+ await fetch(
17050
+ `${serverUrl}/pages/${encodeURIComponent(pageEntry.name)}`,
17051
+ { method: "DELETE" }
17052
+ );
16969
17053
  logger.success(`Unregistered ${pageEntry.name}`);
16970
17054
  }
16971
17055
  return;
16972
17056
  }
16973
17057
  if (options2.kill) {
16974
- const deleteResponse = await fetch(`${serverUrl}/pages/${encodeURIComponent(options2.kill)}`, { method: "DELETE" });
17058
+ const deleteResponse = await fetch(
17059
+ `${serverUrl}/pages/${encodeURIComponent(options2.kill)}`,
17060
+ { method: "DELETE" }
17061
+ );
16975
17062
  if (deleteResponse.ok) {
16976
17063
  logger.success(`Unregistered ${options2.kill}`);
16977
17064
  } else {
@@ -17111,7 +17198,9 @@ MULTI-PAGE SESSIONS
17111
17198
 
17112
17199
  PLAYWRIGHT DOCS: https://playwright.dev/docs/api/class-page
17113
17200
  `;
17114
- var browser = new Command().name("browser").description("browser automation with persistent page state and real cookie injection").addHelpText("after", BROWSER_HELP).action(() => {
17201
+ var browser = new Command().name("browser").description(
17202
+ "browser automation with persistent page state and real cookie injection"
17203
+ ).addHelpText("after", BROWSER_HELP).action(() => {
17115
17204
  browser.help();
17116
17205
  });
17117
17206
  var mcp = new Command().name("mcp").description("start MCP server for browser automation (stdio transport)").action(async () => {
@@ -17161,7 +17250,7 @@ browser.addCommand(status);
17161
17250
  browser.addCommand(execute);
17162
17251
  browser.addCommand(pages);
17163
17252
  browser.addCommand(mcp);
17164
- var VERSION3 = "0.1.0-beta.6";
17253
+ var VERSION3 = "0.1.0-beta.8";
17165
17254
  var isMac = process.platform === "darwin";
17166
17255
  var META_LABEL = isMac ? "Cmd" : "Win";
17167
17256
  var ALT_LABEL = isMac ? "Option" : "Alt";
@@ -17359,19 +17448,13 @@ var comboToString = (combo) => {
17359
17448
  var configure = new Command().name("configure").alias("config").description("configure React Grab options").option("-y, --yes", "skip confirmation prompts", false).option(
17360
17449
  "-k, --key <key>",
17361
17450
  "activation key (e.g., Meta+K, Ctrl+Shift+G, Space)"
17362
- ).option(
17363
- "-m, --mode <mode>",
17364
- "activation mode (toggle, hold)"
17365
- ).option(
17451
+ ).option("-m, --mode <mode>", "activation mode (toggle, hold)").option(
17366
17452
  "--hold-duration <ms>",
17367
17453
  "key hold duration in milliseconds (for hold mode)"
17368
17454
  ).option(
17369
17455
  "--allow-input <boolean>",
17370
17456
  "allow activation inside input fields (true/false)"
17371
- ).option(
17372
- "--context-lines <lines>",
17373
- "max context lines to include"
17374
- ).option(
17457
+ ).option("--context-lines <lines>", "max context lines to include").option(
17375
17458
  "-c, --cwd <cwd>",
17376
17459
  "working directory (defaults to current directory)",
17377
17460
  process.cwd()
@@ -17418,22 +17501,30 @@ var configure = new Command().name("configure").alias("config").description("con
17418
17501
  if (opts2.holdDuration) {
17419
17502
  const duration3 = parseInt(opts2.holdDuration, 10);
17420
17503
  if (isNaN(duration3) || duration3 < 0 || duration3 > MAX_KEY_HOLD_DURATION_MS) {
17421
- logger.error(`Invalid hold duration. Must be 0-${MAX_KEY_HOLD_DURATION_MS}ms.`);
17504
+ logger.error(
17505
+ `Invalid hold duration. Must be 0-${MAX_KEY_HOLD_DURATION_MS}ms.`
17506
+ );
17422
17507
  logger.break();
17423
17508
  process.exit(1);
17424
17509
  }
17425
17510
  collectedOptions.keyHoldDuration = duration3;
17426
- logger.log(` Key hold duration: ${highlighter.info(`${duration3}ms`)}`);
17511
+ logger.log(
17512
+ ` Key hold duration: ${highlighter.info(`${duration3}ms`)}`
17513
+ );
17427
17514
  }
17428
17515
  if (opts2.allowInput !== void 0) {
17429
17516
  const allowInput = opts2.allowInput === "true" || opts2.allowInput === true;
17430
17517
  collectedOptions.allowActivationInsideInput = allowInput;
17431
- logger.log(` Allow activation inside input: ${highlighter.info(String(allowInput))}`);
17518
+ logger.log(
17519
+ ` Allow activation inside input: ${highlighter.info(String(allowInput))}`
17520
+ );
17432
17521
  }
17433
17522
  if (opts2.contextLines) {
17434
17523
  const lines = parseInt(opts2.contextLines, 10);
17435
17524
  if (isNaN(lines) || lines < 0 || lines > MAX_CONTEXT_LINES) {
17436
- logger.error(`Invalid context lines. Must be 0-${MAX_CONTEXT_LINES}.`);
17525
+ logger.error(
17526
+ `Invalid context lines. Must be 0-${MAX_CONTEXT_LINES}.`
17527
+ );
17437
17528
  logger.break();
17438
17529
  process.exit(1);
17439
17530
  }
@@ -17483,7 +17574,10 @@ var configure = new Command().name("configure").alias("config").description("con
17483
17574
  name: "activationMode",
17484
17575
  message: `Select ${highlighter.info("activation mode")}:`,
17485
17576
  choices: [
17486
- { title: "Toggle (press to activate/deactivate)", value: "toggle" },
17577
+ {
17578
+ title: "Toggle (press to activate/deactivate)",
17579
+ value: "toggle"
17580
+ },
17487
17581
  { title: "Hold (hold key to keep active)", value: "hold" }
17488
17582
  ],
17489
17583
  initial: 0
@@ -17549,7 +17643,9 @@ var configure = new Command().name("configure").alias("config").description("con
17549
17643
  logger.warn(result.message);
17550
17644
  logger.break();
17551
17645
  const configJson = JSON.stringify(collectedOptions);
17552
- logger.log(`Add this to your ${highlighter.info("init()")} call or ${highlighter.info("data-options")} attribute:`);
17646
+ logger.log(
17647
+ `Add this to your ${highlighter.info("init()")} call or ${highlighter.info("data-options")} attribute:`
17648
+ );
17553
17649
  logger.break();
17554
17650
  console.log(` ${pc.cyan(configJson)}`);
17555
17651
  logger.break();
@@ -17599,7 +17695,7 @@ var configure = new Command().name("configure").alias("config").description("con
17599
17695
  handleError(error48);
17600
17696
  }
17601
17697
  });
17602
- var VERSION4 = "0.1.0-beta.6";
17698
+ var VERSION4 = "0.1.0-beta.8";
17603
17699
  var REPORT_URL = "https://react-grab.com/api/report-cli";
17604
17700
  var DOCS_URL = "https://github.com/aidenybai/react-grab";
17605
17701
  var promptSkillInstall = async (cwd) => {
@@ -17607,7 +17703,9 @@ var promptSkillInstall = async (cwd) => {
17607
17703
  if (detectedAgents.length === 0) {
17608
17704
  return;
17609
17705
  }
17610
- logger.log(`The ${highlighter.info("React Grab skill")} gives your agent access to the browser.`);
17706
+ logger.log(
17707
+ `The ${highlighter.info("React Grab skill")} gives your agent access to the browser.`
17708
+ );
17611
17709
  logger.log(`Learn more at ${highlighter.info("https://skill.md")}`);
17612
17710
  logger.break();
17613
17711
  const { wantSkill } = await prompts3({
@@ -17631,16 +17729,23 @@ var promptSkillInstall = async (cwd) => {
17631
17729
  });
17632
17730
  if (selectedAgent) {
17633
17731
  logger.break();
17634
- const skillSpinner = spinner(`Installing skill for ${selectedAgent.name}`).start();
17732
+ const skillSpinner = spinner(
17733
+ `Installing skill for ${selectedAgent.name}`
17734
+ ).start();
17635
17735
  try {
17636
- execSync(`npx -y add-skill aidenybai/react-grab -y --agent ${selectedAgent.id}`, {
17637
- stdio: "ignore",
17638
- cwd
17639
- });
17736
+ execSync(
17737
+ `npx -y add-skill aidenybai/react-grab -y --agent ${selectedAgent.id}`,
17738
+ {
17739
+ stdio: "ignore",
17740
+ cwd
17741
+ }
17742
+ );
17640
17743
  skillSpinner.succeed(`Skill installed for ${selectedAgent.name}.`);
17641
17744
  } catch {
17642
17745
  skillSpinner.fail(`Failed to install skill for ${selectedAgent.name}.`);
17643
- logger.warn(`Try manually: npx -y add-skill aidenybai/react-grab --agent ${selectedAgent.id}`);
17746
+ logger.warn(
17747
+ `Try manually: npx -y add-skill aidenybai/react-grab --agent ${selectedAgent.id}`
17748
+ );
17644
17749
  }
17645
17750
  }
17646
17751
  logger.break();
@@ -17701,10 +17806,7 @@ var init = new Command().name("init").description("initialize React Grab in your
17701
17806
  ).option(
17702
17807
  "-k, --key <key>",
17703
17808
  "activation key (e.g., Meta+K, Ctrl+Shift+G, Space)"
17704
- ).option("--skip-install", "skip package installation", false).option(
17705
- "--pkg <pkg>",
17706
- "custom package URL for CLI (e.g., @react-grab/cli)"
17707
- ).option(
17809
+ ).option("--skip-install", "skip package installation", false).option("--pkg <pkg>", "custom package URL for CLI (e.g., grab)").option(
17708
17810
  "-c, --cwd <cwd>",
17709
17811
  "working directory (defaults to current directory)",
17710
17812
  process.cwd()
@@ -17952,7 +18054,9 @@ var init = new Command().name("init").description("initialize React Grab in your
17952
18054
  const agentIntegration2 = agent;
17953
18055
  let agentsToRemove2 = [];
17954
18056
  if (projectInfo.installedAgents.length > 0) {
17955
- const installedNames = formatInstalledAgentNames(projectInfo.installedAgents);
18057
+ const installedNames = formatInstalledAgentNames(
18058
+ projectInfo.installedAgents
18059
+ );
17956
18060
  const { action } = await prompts3({
17957
18061
  type: "select",
17958
18062
  name: "action",
@@ -18280,7 +18384,7 @@ var init = new Command().name("init").description("initialize React Grab in your
18280
18384
  reportToCli("error", void 0, error48);
18281
18385
  }
18282
18386
  });
18283
- var VERSION5 = "0.1.0-beta.6";
18387
+ var VERSION5 = "0.1.0-beta.8";
18284
18388
  var remove = new Command().name("remove").description("remove an agent integration").argument(
18285
18389
  "[agent]",
18286
18390
  "agent to remove (claude-code, cursor, opencode, codex, gemini, amp, ami, visual-edit)"
@@ -18457,22 +18561,21 @@ var remove = new Command().name("remove").description("remove an agent integrati
18457
18561
  handleError(error48);
18458
18562
  }
18459
18563
  });
18460
- var VERSION6 = "0.1.0-beta.6";
18461
- var UPDATE_COMMANDS = {
18462
- npm: "npm install -g grab@latest",
18463
- yarn: "yarn global add grab@latest",
18464
- pnpm: "pnpm add -g grab@latest",
18465
- bun: "bun add -g grab@latest"
18466
- };
18467
- var MANAGER_NAMES = {
18468
- npm: "npm",
18469
- yarn: "Yarn",
18470
- pnpm: "pnpm",
18471
- bun: "Bun"
18472
- };
18473
- var execSilent = (command) => {
18564
+ var uninstall = new Command().name("uninstall").description("uninstall React Grab CLI globally").action(() => {
18565
+ console.log("Uninstalling React Grab CLI...");
18566
+ try {
18567
+ execSync("npm uninstall -g grab", { stdio: "inherit" });
18568
+ console.log("React Grab CLI has been uninstalled.");
18569
+ } catch {
18570
+ console.error("Failed to uninstall. Please try: npm uninstall -g grab");
18571
+ process.exit(1);
18572
+ }
18573
+ });
18574
+ var VERSION6 = "0.1.0-beta.8";
18575
+ var UPDATE_COMMAND = "npm install -g grab@latest";
18576
+ var getLatestVersion = () => {
18474
18577
  try {
18475
- return execSync(command, {
18578
+ return execSync("npm view grab version", {
18476
18579
  encoding: "utf-8",
18477
18580
  stdio: ["pipe", "pipe", "pipe"]
18478
18581
  }).trim();
@@ -18480,47 +18583,24 @@ var execSilent = (command) => {
18480
18583
  return null;
18481
18584
  }
18482
18585
  };
18483
- var getInstalledVersion = () => {
18484
- const output = execSilent("grab --version");
18485
- if (!output) return null;
18486
- const match = output.match(/(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)/);
18487
- return match ? match[1] : null;
18488
- };
18489
- var getLatestVersion = () => execSilent("npm view grab version");
18490
- var isPackageManagerInstalled = (manager) => execSilent(`${manager} --version`) !== null;
18491
- var detectGlobalPackageManager = () => {
18492
- const managers = ["pnpm", "yarn", "bun"];
18493
- for (const manager of managers) {
18494
- if (isPackageManagerInstalled(manager)) {
18495
- return manager;
18496
- }
18497
- }
18498
- return "npm";
18499
- };
18500
- var update = new Command().name("update").alias("upgrade").description("update grab to the latest version").option("-y, --yes", "skip confirmation prompts", false).option("--check", "only check for updates, don't install", false).action(async (opts2) => {
18586
+ 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) => {
18501
18587
  console.log(
18502
18588
  `${pc.magenta("\u273F")} ${pc.bold("React Grab")} ${pc.gray(VERSION6)}`
18503
18589
  );
18504
18590
  console.log();
18505
18591
  const checkSpinner = spinner("Checking for updates").start();
18506
- const installedVersion = getInstalledVersion();
18507
18592
  const latestVersion = getLatestVersion();
18508
18593
  if (!latestVersion) {
18509
- checkSpinner.fail("Failed to fetch latest version from npm");
18510
- logger.break();
18511
- logger.error("Could not reach npm registry. Check your network connection.");
18512
- logger.break();
18513
- process.exit(1);
18514
- }
18515
- if (!installedVersion) {
18516
- checkSpinner.fail("grab is not installed globally");
18594
+ checkSpinner.fail("Failed to fetch latest version");
18517
18595
  logger.break();
18518
- logger.log(`Install it with: ${highlighter.info("npm install -g grab")}`);
18596
+ logger.error(
18597
+ "Could not reach npm registry. Check your network connection."
18598
+ );
18519
18599
  logger.break();
18520
18600
  process.exit(1);
18521
18601
  }
18522
- checkSpinner.succeed(`Current version: ${highlighter.info(installedVersion)}`);
18523
- if (installedVersion === latestVersion) {
18602
+ checkSpinner.succeed(`Current version: ${highlighter.info(VERSION6)}`);
18603
+ if (VERSION6 === latestVersion) {
18524
18604
  logger.break();
18525
18605
  logger.success(`You're already on the latest version (${latestVersion})`);
18526
18606
  logger.break();
@@ -18529,17 +18609,18 @@ var update = new Command().name("update").alias("upgrade").description("update g
18529
18609
  logger.log(`Latest version: ${highlighter.success(latestVersion)}`);
18530
18610
  logger.break();
18531
18611
  if (opts2.check) {
18532
- logger.log(`Update available: ${installedVersion} \u2192 ${latestVersion}`);
18533
- logger.log(`Run ${highlighter.info("grab update")} to install the update.`);
18612
+ logger.log(`Update available: ${VERSION6} \u2192 ${latestVersion}`);
18613
+ logger.log(
18614
+ `Run ${highlighter.info("grab update")} to install the update.`
18615
+ );
18534
18616
  logger.break();
18535
18617
  process.exit(0);
18536
18618
  }
18537
- const packageManager = detectGlobalPackageManager();
18538
18619
  if (!opts2.yes) {
18539
18620
  const { shouldProceed } = await prompts3({
18540
18621
  type: "confirm",
18541
18622
  name: "shouldProceed",
18542
- message: `Update grab from ${installedVersion} to ${latestVersion} using ${MANAGER_NAMES[packageManager]}?`,
18623
+ message: `Update from ${VERSION6} to ${latestVersion}?`,
18543
18624
  initial: true
18544
18625
  });
18545
18626
  if (!shouldProceed) {
@@ -18550,20 +18631,19 @@ var update = new Command().name("update").alias("upgrade").description("update g
18550
18631
  }
18551
18632
  }
18552
18633
  logger.break();
18553
- const updateSpinner = spinner(`Updating grab to ${latestVersion}`).start();
18634
+ const updateSpinner = spinner(`Updating to ${latestVersion}`).start();
18554
18635
  try {
18555
- const command = UPDATE_COMMANDS[packageManager];
18556
- execSync(command, {
18557
- stdio: ["pipe", "pipe", "pipe"]
18558
- });
18559
- updateSpinner.succeed(`Updated grab to ${latestVersion}`);
18636
+ execSync(UPDATE_COMMAND, { stdio: ["pipe", "pipe", "pipe"] });
18637
+ updateSpinner.succeed(`Updated to ${latestVersion}`);
18560
18638
  logger.break();
18561
18639
  logger.success("Update complete!");
18562
18640
  logger.break();
18563
18641
  } catch (error48) {
18564
- updateSpinner.fail("Failed to update grab");
18642
+ updateSpinner.fail("Failed to update");
18565
18643
  logger.break();
18566
- logger.error(`Update failed. Try manually: ${highlighter.info(UPDATE_COMMANDS[packageManager])}`);
18644
+ logger.error(
18645
+ `Update failed. Try manually: ${highlighter.info(UPDATE_COMMAND)}`
18646
+ );
18567
18647
  if (error48 instanceof Error && error48.message) {
18568
18648
  logger.dim(error48.message);
18569
18649
  }
@@ -18573,7 +18653,7 @@ var update = new Command().name("update").alias("upgrade").description("update g
18573
18653
  });
18574
18654
 
18575
18655
  // src/cli.ts
18576
- var VERSION7 = "0.1.0-beta.6";
18656
+ var VERSION7 = "0.1.0-beta.8";
18577
18657
  var VERSION_API_URL = "https://www.react-grab.com/api/version";
18578
18658
  process.on("SIGINT", () => process.exit(0));
18579
18659
  process.on("SIGTERM", () => process.exit(0));
@@ -18589,4 +18669,5 @@ program.addCommand(remove);
18589
18669
  program.addCommand(configure);
18590
18670
  program.addCommand(browser);
18591
18671
  program.addCommand(update);
18672
+ program.addCommand(uninstall);
18592
18673
  program.parse();