@react-grab/cli 0.0.90 → 0.0.92

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 +1288 -66
  2. package/dist/cli.js +1288 -66
  3. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  var commander = require('commander');
5
5
  var pc = require('picocolors');
6
- var prompts2 = require('prompts');
6
+ var prompts3 = require('prompts');
7
7
  var child_process = require('child_process');
8
8
  var fs = require('fs');
9
9
  var path = require('path');
@@ -15,7 +15,7 @@ var httpProxyMiddleware = require('http-proxy-middleware');
15
15
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
16
16
 
17
17
  var pc__default = /*#__PURE__*/_interopDefault(pc);
18
- var prompts2__default = /*#__PURE__*/_interopDefault(prompts2);
18
+ var prompts3__default = /*#__PURE__*/_interopDefault(prompts3);
19
19
  var ora__default = /*#__PURE__*/_interopDefault(ora);
20
20
 
21
21
  var detectPackageManager = async (projectRoot) => {
@@ -467,6 +467,12 @@ var INSTALL_COMMANDS = {
467
467
  pnpm: "pnpm add",
468
468
  bun: "bun add"
469
469
  };
470
+ var UNINSTALL_COMMANDS = {
471
+ npm: "npm uninstall",
472
+ yarn: "yarn remove",
473
+ pnpm: "pnpm remove",
474
+ bun: "bun remove"
475
+ };
470
476
  var installPackages = (packages, packageManager, projectRoot, isDev = true) => {
471
477
  if (packages.length === 0) {
472
478
  return;
@@ -491,6 +497,22 @@ var getPackagesToInstall = (agent, includeReactGrab = true) => {
491
497
  }
492
498
  return packages;
493
499
  };
500
+ var uninstallPackages = (packages, packageManager, projectRoot) => {
501
+ if (packages.length === 0) {
502
+ return;
503
+ }
504
+ const command = UNINSTALL_COMMANDS[packageManager];
505
+ const fullCommand = `${command} ${packages.join(" ")}`;
506
+ console.log(`Running: ${fullCommand}
507
+ `);
508
+ child_process.execSync(fullCommand, {
509
+ cwd: projectRoot,
510
+ stdio: "inherit"
511
+ });
512
+ };
513
+ var getPackagesToUninstall = (agent) => {
514
+ return [`@react-grab/${agent}`];
515
+ };
494
516
  var spinner = (text, options) => ora__default.default({ text, isSilent: options?.silent, stream: process.stdout });
495
517
 
496
518
  // src/utils/templates.ts
@@ -676,18 +698,20 @@ var addAgentToExistingNextApp = (originalContent, agent, filePath) => {
676
698
  noChanges: true
677
699
  };
678
700
  }
679
- const agentScript = `<Script
680
- src="//unpkg.com/${agentPackage}/dist/client.global.js"
681
- strategy="lazyOnload"
682
- />`;
683
- const reactGrabScriptMatch = originalContent.match(
684
- /<(?:Script|script|NextScript)[^>]*react-grab[^>]*\/?>/is
701
+ const agentScript = `{process.env.NODE_ENV === "development" && (
702
+ <Script
703
+ src="//unpkg.com/${agentPackage}/dist/client.global.js"
704
+ strategy="lazyOnload"
705
+ />
706
+ )}`;
707
+ const reactGrabBlockMatch = originalContent.match(
708
+ /\{process\.env\.NODE_ENV\s*===\s*["']development["']\s*&&\s*\(\s*<Script[^>]*react-grab[^>]*\/>\s*\)\}/is
685
709
  );
686
- if (reactGrabScriptMatch) {
710
+ if (reactGrabBlockMatch) {
687
711
  const newContent = originalContent.replace(
688
- reactGrabScriptMatch[0],
689
- `${reactGrabScriptMatch[0]}
690
- ${agentScript}`
712
+ reactGrabBlockMatch[0],
713
+ `${reactGrabBlockMatch[0]}
714
+ ${agentScript}`
691
715
  );
692
716
  return {
693
717
  success: true,
@@ -1037,20 +1061,49 @@ var applyTransform = (result) => {
1037
1061
  }
1038
1062
  return { success: true };
1039
1063
  };
1040
- var AGENT_PREFIXES = {
1041
- "claude-code": "npx @react-grab/claude-code@latest &&",
1042
- cursor: "npx @react-grab/cursor@latest &&",
1043
- opencode: "npx @react-grab/opencode@latest &&",
1044
- codex: "npx @react-grab/codex@latest &&",
1045
- gemini: "npx @react-grab/gemini@latest &&",
1046
- amp: "npx @react-grab/amp@latest &&"
1064
+ var getPackageExecutor = (packageManager) => {
1065
+ switch (packageManager) {
1066
+ case "bun":
1067
+ return "bunx";
1068
+ case "pnpm":
1069
+ return "pnpm dlx";
1070
+ case "yarn":
1071
+ return "npx";
1072
+ case "npm":
1073
+ default:
1074
+ return "npx";
1075
+ }
1076
+ };
1077
+ var AGENT_PACKAGES2 = {
1078
+ "claude-code": "@react-grab/claude-code@latest",
1079
+ cursor: "@react-grab/cursor@latest",
1080
+ opencode: "@react-grab/opencode@latest",
1081
+ codex: "@react-grab/codex@latest",
1082
+ gemini: "@react-grab/gemini@latest",
1083
+ amp: "@react-grab/amp@latest"
1084
+ };
1085
+ var getAgentPrefix = (agent, packageManager) => {
1086
+ const agentPackage = AGENT_PACKAGES2[agent];
1087
+ if (!agentPackage) return null;
1088
+ const executor = getPackageExecutor(packageManager);
1089
+ return `${executor} ${agentPackage} &&`;
1090
+ };
1091
+ var getAllAgentPrefixVariants = (agent) => {
1092
+ const agentPackage = AGENT_PACKAGES2[agent];
1093
+ if (!agentPackage) return [];
1094
+ return [
1095
+ `npx ${agentPackage} &&`,
1096
+ `bunx ${agentPackage} &&`,
1097
+ `pnpm dlx ${agentPackage} &&`,
1098
+ `yarn dlx ${agentPackage} &&`
1099
+ ];
1047
1100
  };
1048
- var previewPackageJsonTransform = (projectRoot, agent, installedAgents) => {
1049
- if (agent === "none" || agent === "ami" || agent === "visual-edit") {
1101
+ var previewPackageJsonTransform = (projectRoot, agent, installedAgents, packageManager = "npm") => {
1102
+ if (agent === "none" || agent === "visual-edit") {
1050
1103
  return {
1051
1104
  success: true,
1052
1105
  filePath: "",
1053
- message: agent === "ami" || agent === "visual-edit" ? `${agent === "ami" ? "Ami" : "Visual Edit"} does not require package.json modification` : "No agent selected, skipping package.json modification",
1106
+ message: agent === "visual-edit" ? "Visual Edit does not require package.json modification" : "No agent selected, skipping package.json modification",
1054
1107
  noChanges: true
1055
1108
  };
1056
1109
  }
@@ -1063,7 +1116,7 @@ var previewPackageJsonTransform = (projectRoot, agent, installedAgents) => {
1063
1116
  };
1064
1117
  }
1065
1118
  const originalContent = fs.readFileSync(packageJsonPath, "utf-8");
1066
- const agentPrefix = AGENT_PREFIXES[agent];
1119
+ const agentPrefix = getAgentPrefix(agent, packageManager);
1067
1120
  if (!agentPrefix) {
1068
1121
  return {
1069
1122
  success: false,
@@ -1071,7 +1124,11 @@ var previewPackageJsonTransform = (projectRoot, agent, installedAgents) => {
1071
1124
  message: `Unknown agent: ${agent}`
1072
1125
  };
1073
1126
  }
1074
- if (originalContent.includes(agentPrefix)) {
1127
+ const allPrefixVariants = getAllAgentPrefixVariants(agent);
1128
+ const hasExistingPrefix = allPrefixVariants.some(
1129
+ (prefix) => originalContent.includes(prefix)
1130
+ );
1131
+ if (hasExistingPrefix) {
1075
1132
  return {
1076
1133
  success: true,
1077
1134
  filePath: packageJsonPath,
@@ -1094,14 +1151,19 @@ var previewPackageJsonTransform = (projectRoot, agent, installedAgents) => {
1094
1151
  filePath: packageJsonPath,
1095
1152
  message: "No dev script found in package.json",
1096
1153
  noChanges: true,
1097
- warning: `No dev script found. Run: ${agentPrefix} <your dev command>`
1154
+ warning: `Could not inject agent into package.json (no dev script found).
1155
+ Run this command manually before starting your dev server:
1156
+ ${agentPrefix} <your dev command>`
1098
1157
  };
1099
1158
  }
1100
1159
  }
1101
1160
  const currentDevScript = packageJson.scripts[targetScriptKey];
1102
1161
  for (const installedAgent of installedAgents) {
1103
- const existingPrefix = AGENT_PREFIXES[installedAgent];
1104
- if (existingPrefix && currentDevScript.includes(existingPrefix)) {
1162
+ const installedPrefixVariants = getAllAgentPrefixVariants(installedAgent);
1163
+ const hasInstalledAgentPrefix = installedPrefixVariants.some(
1164
+ (prefix) => currentDevScript.includes(prefix)
1165
+ );
1166
+ if (hasInstalledAgentPrefix) {
1105
1167
  return {
1106
1168
  success: true,
1107
1169
  filePath: packageJsonPath,
@@ -1345,9 +1407,192 @@ var previewOptionsTransform = (projectRoot, framework, nextRouterType, options)
1345
1407
  var applyOptionsTransform = (result) => {
1346
1408
  return applyTransform(result);
1347
1409
  };
1410
+ var removeAgentFromNextApp = (originalContent, agent, filePath) => {
1411
+ const agentPackage = `@react-grab/${agent}`;
1412
+ if (!originalContent.includes(agentPackage)) {
1413
+ return {
1414
+ success: true,
1415
+ filePath,
1416
+ message: `Agent ${agent} is not configured in this file`,
1417
+ noChanges: true
1418
+ };
1419
+ }
1420
+ const agentScriptPattern = new RegExp(
1421
+ `\\s*\\{process\\.env\\.NODE_ENV === "development" && \\(\\s*<Script[^>]*${agentPackage.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[^>]*\\/>\\s*\\)\\}`,
1422
+ "gs"
1423
+ );
1424
+ const simpleScriptPattern = new RegExp(
1425
+ `\\s*<Script[^>]*${agentPackage.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[^>]*\\/>`,
1426
+ "gi"
1427
+ );
1428
+ let newContent = originalContent.replace(agentScriptPattern, "");
1429
+ if (newContent === originalContent) {
1430
+ newContent = originalContent.replace(simpleScriptPattern, "");
1431
+ }
1432
+ if (newContent === originalContent) {
1433
+ return {
1434
+ success: false,
1435
+ filePath,
1436
+ message: `Could not find agent ${agent} script to remove`
1437
+ };
1438
+ }
1439
+ return {
1440
+ success: true,
1441
+ filePath,
1442
+ message: `Remove ${agent} agent`,
1443
+ originalContent,
1444
+ newContent
1445
+ };
1446
+ };
1447
+ var removeAgentFromVite = (originalContent, agent, filePath) => {
1448
+ const agentPackage = `@react-grab/${agent}`;
1449
+ if (!originalContent.includes(agentPackage)) {
1450
+ return {
1451
+ success: true,
1452
+ filePath,
1453
+ message: `Agent ${agent} is not configured in this file`,
1454
+ noChanges: true
1455
+ };
1456
+ }
1457
+ const agentImportPattern = new RegExp(
1458
+ `\\s*import\\s*\\(\\s*["']${agentPackage.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}/client["']\\s*\\);?`,
1459
+ "g"
1460
+ );
1461
+ const newContent = originalContent.replace(agentImportPattern, "");
1462
+ if (newContent === originalContent) {
1463
+ return {
1464
+ success: false,
1465
+ filePath,
1466
+ message: `Could not find agent ${agent} import to remove`
1467
+ };
1468
+ }
1469
+ return {
1470
+ success: true,
1471
+ filePath,
1472
+ message: `Remove ${agent} agent`,
1473
+ originalContent,
1474
+ newContent
1475
+ };
1476
+ };
1477
+ var removeAgentFromWebpack = (originalContent, agent, filePath) => {
1478
+ const agentPackage = `@react-grab/${agent}`;
1479
+ if (!originalContent.includes(agentPackage)) {
1480
+ return {
1481
+ success: true,
1482
+ filePath,
1483
+ message: `Agent ${agent} is not configured in this file`,
1484
+ noChanges: true
1485
+ };
1486
+ }
1487
+ const agentImportPattern = new RegExp(
1488
+ `\\s*import\\s*\\(\\s*["']${agentPackage.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}/client["']\\s*\\);?`,
1489
+ "g"
1490
+ );
1491
+ const newContent = originalContent.replace(agentImportPattern, "");
1492
+ if (newContent === originalContent) {
1493
+ return {
1494
+ success: false,
1495
+ filePath,
1496
+ message: `Could not find agent ${agent} import to remove`
1497
+ };
1498
+ }
1499
+ return {
1500
+ success: true,
1501
+ filePath,
1502
+ message: `Remove ${agent} agent`,
1503
+ originalContent,
1504
+ newContent
1505
+ };
1506
+ };
1507
+ var previewAgentRemoval = (projectRoot, framework, nextRouterType, agent) => {
1508
+ const filePath = findReactGrabFile(projectRoot, framework, nextRouterType);
1509
+ if (!filePath) {
1510
+ return {
1511
+ success: true,
1512
+ filePath: "",
1513
+ message: "Could not find file containing React Grab configuration",
1514
+ noChanges: true
1515
+ };
1516
+ }
1517
+ const originalContent = fs.readFileSync(filePath, "utf-8");
1518
+ switch (framework) {
1519
+ case "next":
1520
+ return removeAgentFromNextApp(originalContent, agent, filePath);
1521
+ case "vite":
1522
+ return removeAgentFromVite(originalContent, agent, filePath);
1523
+ case "webpack":
1524
+ return removeAgentFromWebpack(originalContent, agent, filePath);
1525
+ default:
1526
+ return {
1527
+ success: false,
1528
+ filePath,
1529
+ message: `Unknown framework: ${framework}`
1530
+ };
1531
+ }
1532
+ };
1533
+ var previewPackageJsonAgentRemoval = (projectRoot, agent) => {
1534
+ const packageJsonPath = path.join(projectRoot, "package.json");
1535
+ if (!fs.existsSync(packageJsonPath)) {
1536
+ return {
1537
+ success: true,
1538
+ filePath: "",
1539
+ message: "Could not find package.json",
1540
+ noChanges: true
1541
+ };
1542
+ }
1543
+ const originalContent = fs.readFileSync(packageJsonPath, "utf-8");
1544
+ const allPrefixVariants = getAllAgentPrefixVariants(agent);
1545
+ if (allPrefixVariants.length === 0) {
1546
+ return {
1547
+ success: true,
1548
+ filePath: packageJsonPath,
1549
+ message: `Unknown agent: ${agent}`,
1550
+ noChanges: true
1551
+ };
1552
+ }
1553
+ const hasAnyPrefix = allPrefixVariants.some(
1554
+ (prefix) => originalContent.includes(prefix)
1555
+ );
1556
+ if (!hasAnyPrefix) {
1557
+ return {
1558
+ success: true,
1559
+ filePath: packageJsonPath,
1560
+ message: `Agent ${agent} dev script is not configured`,
1561
+ noChanges: true
1562
+ };
1563
+ }
1564
+ try {
1565
+ const packageJson = JSON.parse(originalContent);
1566
+ for (const scriptKey of Object.keys(packageJson.scripts || {})) {
1567
+ let scriptValue = packageJson.scripts[scriptKey];
1568
+ if (typeof scriptValue === "string") {
1569
+ for (const prefix of allPrefixVariants) {
1570
+ if (scriptValue.includes(prefix)) {
1571
+ scriptValue = scriptValue.replace(prefix + " ", "").replace(prefix, "");
1572
+ }
1573
+ }
1574
+ packageJson.scripts[scriptKey] = scriptValue;
1575
+ }
1576
+ }
1577
+ const newContent = JSON.stringify(packageJson, null, 2) + "\n";
1578
+ return {
1579
+ success: true,
1580
+ filePath: packageJsonPath,
1581
+ message: `Remove ${agent} server from dev script`,
1582
+ originalContent,
1583
+ newContent
1584
+ };
1585
+ } catch {
1586
+ return {
1587
+ success: false,
1588
+ filePath: packageJsonPath,
1589
+ message: "Failed to parse package.json"
1590
+ };
1591
+ }
1592
+ };
1348
1593
 
1349
1594
  // src/commands/add.ts
1350
- var VERSION = "0.0.90";
1595
+ var VERSION = "0.0.92";
1351
1596
  var AGENT_NAMES = {
1352
1597
  "claude-code": "Claude Code",
1353
1598
  cursor: "Cursor",
@@ -1384,7 +1629,7 @@ var add = new commander.Command().name("add").description("add an agent integrat
1384
1629
  process.exit(1);
1385
1630
  }
1386
1631
  preflightSpinner.succeed();
1387
- const availableAgents = [
1632
+ const allAgents = [
1388
1633
  "claude-code",
1389
1634
  "cursor",
1390
1635
  "opencode",
@@ -1392,7 +1637,10 @@ var add = new commander.Command().name("add").description("add an agent integrat
1392
1637
  "gemini",
1393
1638
  "amp",
1394
1639
  "visual-edit"
1395
- ].filter((agent) => !projectInfo.installedAgents.includes(agent));
1640
+ ];
1641
+ const availableAgents = allAgents.filter(
1642
+ (agent) => !projectInfo.installedAgents.includes(agent)
1643
+ );
1396
1644
  if (availableAgents.length === 0) {
1397
1645
  logger.break();
1398
1646
  logger.success("All agent integrations are already installed.");
@@ -1400,16 +1648,9 @@ var add = new commander.Command().name("add").description("add an agent integrat
1400
1648
  process.exit(0);
1401
1649
  }
1402
1650
  let agentIntegration;
1651
+ let agentsToRemove = [];
1403
1652
  if (agentArg) {
1404
- if (![
1405
- "claude-code",
1406
- "cursor",
1407
- "opencode",
1408
- "codex",
1409
- "gemini",
1410
- "amp",
1411
- "visual-edit"
1412
- ].includes(agentArg)) {
1653
+ if (!allAgents.includes(agentArg)) {
1413
1654
  logger.break();
1414
1655
  logger.error(`Invalid agent: ${agentArg}`);
1415
1656
  logger.error(
@@ -1425,9 +1666,44 @@ var add = new commander.Command().name("add").description("add an agent integrat
1425
1666
  process.exit(0);
1426
1667
  }
1427
1668
  agentIntegration = agentArg;
1669
+ if (projectInfo.installedAgents.length > 0 && !isNonInteractive) {
1670
+ const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES[innerAgent] || innerAgent).join(", ");
1671
+ logger.break();
1672
+ logger.warn(`${installedNames} is already installed.`);
1673
+ const { action } = await prompts3__default.default({
1674
+ type: "select",
1675
+ name: "action",
1676
+ message: "How would you like to proceed?",
1677
+ choices: [
1678
+ {
1679
+ title: `Replace with ${AGENT_NAMES[agentIntegration]}`,
1680
+ value: "replace"
1681
+ },
1682
+ {
1683
+ title: `Add ${AGENT_NAMES[agentIntegration]} alongside existing`,
1684
+ value: "add"
1685
+ },
1686
+ { title: "Cancel", value: "cancel" }
1687
+ ]
1688
+ });
1689
+ if (!action || action === "cancel") {
1690
+ logger.break();
1691
+ logger.log("Changes cancelled.");
1692
+ logger.break();
1693
+ process.exit(0);
1694
+ }
1695
+ if (action === "replace") {
1696
+ agentsToRemove = [...projectInfo.installedAgents];
1697
+ }
1698
+ }
1428
1699
  } else if (!isNonInteractive) {
1429
1700
  logger.break();
1430
- const { agent } = await prompts2__default.default({
1701
+ if (projectInfo.installedAgents.length > 0) {
1702
+ const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES[innerAgent] || innerAgent).join(", ");
1703
+ logger.warn(`Currently installed: ${installedNames}`);
1704
+ logger.break();
1705
+ }
1706
+ const { agent } = await prompts3__default.default({
1431
1707
  type: "select",
1432
1708
  name: "agent",
1433
1709
  message: `Which ${highlighter.info("agent integration")} would you like to add?`,
@@ -1441,6 +1717,34 @@ var add = new commander.Command().name("add").description("add an agent integrat
1441
1717
  process.exit(1);
1442
1718
  }
1443
1719
  agentIntegration = agent;
1720
+ if (projectInfo.installedAgents.length > 0) {
1721
+ const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES[innerAgent] || innerAgent).join(", ");
1722
+ const { action } = await prompts3__default.default({
1723
+ type: "select",
1724
+ name: "action",
1725
+ message: "How would you like to proceed?",
1726
+ choices: [
1727
+ {
1728
+ title: `Replace ${installedNames} with ${AGENT_NAMES[agentIntegration]}`,
1729
+ value: "replace"
1730
+ },
1731
+ {
1732
+ title: `Add ${AGENT_NAMES[agentIntegration]} alongside existing`,
1733
+ value: "add"
1734
+ },
1735
+ { title: "Cancel", value: "cancel" }
1736
+ ]
1737
+ });
1738
+ if (!action || action === "cancel") {
1739
+ logger.break();
1740
+ logger.log("Changes cancelled.");
1741
+ logger.break();
1742
+ process.exit(0);
1743
+ }
1744
+ if (action === "replace") {
1745
+ agentsToRemove = [...projectInfo.installedAgents];
1746
+ }
1747
+ }
1444
1748
  } else {
1445
1749
  logger.break();
1446
1750
  logger.error("Please specify an agent to add.");
@@ -1448,6 +1752,72 @@ var add = new commander.Command().name("add").description("add an agent integrat
1448
1752
  logger.break();
1449
1753
  process.exit(1);
1450
1754
  }
1755
+ if (agentsToRemove.length > 0) {
1756
+ for (const agentToRemove of agentsToRemove) {
1757
+ const removalResult = previewAgentRemoval(
1758
+ projectInfo.projectRoot,
1759
+ projectInfo.framework,
1760
+ projectInfo.nextRouterType,
1761
+ agentToRemove
1762
+ );
1763
+ const removalPackageJsonResult = previewPackageJsonAgentRemoval(
1764
+ projectInfo.projectRoot,
1765
+ agentToRemove
1766
+ );
1767
+ const packagesToRemove = getPackagesToUninstall(agentToRemove);
1768
+ if (packagesToRemove.length > 0) {
1769
+ const uninstallSpinner = spinner(
1770
+ `Removing ${packagesToRemove.join(", ")}.`
1771
+ ).start();
1772
+ try {
1773
+ uninstallPackages(
1774
+ packagesToRemove,
1775
+ projectInfo.packageManager,
1776
+ projectInfo.projectRoot
1777
+ );
1778
+ uninstallSpinner.succeed();
1779
+ } catch (error) {
1780
+ uninstallSpinner.fail();
1781
+ handleError(error);
1782
+ }
1783
+ }
1784
+ if (removalResult.success && !removalResult.noChanges && removalResult.newContent) {
1785
+ const removeWriteSpinner = spinner(
1786
+ `Removing ${AGENT_NAMES[agentToRemove] || agentToRemove} from ${removalResult.filePath}.`
1787
+ ).start();
1788
+ const writeResult = applyTransform(removalResult);
1789
+ if (!writeResult.success) {
1790
+ removeWriteSpinner.fail();
1791
+ logger.break();
1792
+ logger.error(writeResult.error || "Failed to write file.");
1793
+ logger.break();
1794
+ process.exit(1);
1795
+ }
1796
+ removeWriteSpinner.succeed();
1797
+ }
1798
+ if (removalPackageJsonResult.success && !removalPackageJsonResult.noChanges && removalPackageJsonResult.newContent) {
1799
+ const removePackageJsonSpinner = spinner(
1800
+ `Removing ${AGENT_NAMES[agentToRemove] || agentToRemove} from ${removalPackageJsonResult.filePath}.`
1801
+ ).start();
1802
+ const packageJsonWriteResult = applyPackageJsonTransform(
1803
+ removalPackageJsonResult
1804
+ );
1805
+ if (!packageJsonWriteResult.success) {
1806
+ removePackageJsonSpinner.fail();
1807
+ logger.break();
1808
+ logger.error(
1809
+ packageJsonWriteResult.error || "Failed to write file."
1810
+ );
1811
+ logger.break();
1812
+ process.exit(1);
1813
+ }
1814
+ removePackageJsonSpinner.succeed();
1815
+ }
1816
+ }
1817
+ projectInfo.installedAgents = projectInfo.installedAgents.filter(
1818
+ (innerAgent) => !agentsToRemove.includes(innerAgent)
1819
+ );
1820
+ }
1451
1821
  const addingSpinner = spinner(
1452
1822
  `Adding ${AGENT_NAMES[agentIntegration]}.`
1453
1823
  ).start();
@@ -1462,7 +1832,8 @@ var add = new commander.Command().name("add").description("add an agent integrat
1462
1832
  const packageJsonResult = previewPackageJsonTransform(
1463
1833
  projectInfo.projectRoot,
1464
1834
  agentIntegration,
1465
- projectInfo.installedAgents
1835
+ projectInfo.installedAgents,
1836
+ projectInfo.packageManager
1466
1837
  );
1467
1838
  if (!result.success) {
1468
1839
  logger.break();
@@ -1491,9 +1862,9 @@ var add = new commander.Command().name("add").description("add an agent integrat
1491
1862
  packageJsonResult.newContent
1492
1863
  );
1493
1864
  }
1494
- if (!isNonInteractive) {
1865
+ if (!isNonInteractive && agentsToRemove.length === 0) {
1495
1866
  logger.break();
1496
- const { proceed } = await prompts2__default.default({
1867
+ const { proceed } = await prompts3__default.default({
1497
1868
  type: "confirm",
1498
1869
  name: "proceed",
1499
1870
  message: "Apply these changes?",
@@ -1566,7 +1937,7 @@ var add = new commander.Command().name("add").description("add an agent integrat
1566
1937
  handleError(error);
1567
1938
  }
1568
1939
  });
1569
- var VERSION2 = "0.0.90";
1940
+ var VERSION2 = "0.0.92";
1570
1941
  var MODIFIER_KEY_NAMES = {
1571
1942
  metaKey: process.platform === "darwin" ? "\u2318 Command" : "\u229E Windows",
1572
1943
  ctrlKey: "Ctrl",
@@ -1620,7 +1991,7 @@ var configure = new commander.Command().name("configure").alias("config").descri
1620
1991
  logger.log(`Configure ${highlighter.info("React Grab")} options:`);
1621
1992
  logger.break();
1622
1993
  const collectedOptions = {};
1623
- const { wantActivationKey } = await prompts2__default.default({
1994
+ const { wantActivationKey } = await prompts3__default.default({
1624
1995
  type: "confirm",
1625
1996
  name: "wantActivationKey",
1626
1997
  message: `Configure ${highlighter.info("activation key")}?`,
@@ -1631,7 +2002,7 @@ var configure = new commander.Command().name("configure").alias("config").descri
1631
2002
  process.exit(1);
1632
2003
  }
1633
2004
  if (wantActivationKey) {
1634
- const { key } = await prompts2__default.default({
2005
+ const { key } = await prompts3__default.default({
1635
2006
  type: "text",
1636
2007
  name: "key",
1637
2008
  message: "Enter the activation key (e.g., g, k, space):",
@@ -1641,7 +2012,7 @@ var configure = new commander.Command().name("configure").alias("config").descri
1641
2012
  logger.break();
1642
2013
  process.exit(1);
1643
2014
  }
1644
- const { modifiers } = await prompts2__default.default({
2015
+ const { modifiers } = await prompts3__default.default({
1645
2016
  type: "multiselect",
1646
2017
  name: "modifiers",
1647
2018
  message: "Select modifier keys (space to select, enter to confirm):",
@@ -1672,7 +2043,7 @@ var configure = new commander.Command().name("configure").alias("config").descri
1672
2043
  ` Activation key: ${highlighter.info(formatActivationKey(collectedOptions.activationKey))}`
1673
2044
  );
1674
2045
  }
1675
- const { activationMode } = await prompts2__default.default({
2046
+ const { activationMode } = await prompts3__default.default({
1676
2047
  type: "select",
1677
2048
  name: "activationMode",
1678
2049
  message: `Select ${highlighter.info("activation mode")}:`,
@@ -1688,7 +2059,7 @@ var configure = new commander.Command().name("configure").alias("config").descri
1688
2059
  }
1689
2060
  collectedOptions.activationMode = activationMode;
1690
2061
  if (activationMode === "hold") {
1691
- const { keyHoldDuration } = await prompts2__default.default({
2062
+ const { keyHoldDuration } = await prompts3__default.default({
1692
2063
  type: "number",
1693
2064
  name: "keyHoldDuration",
1694
2065
  message: `Enter ${highlighter.info("key hold duration")} in milliseconds:`,
@@ -1702,7 +2073,7 @@ var configure = new commander.Command().name("configure").alias("config").descri
1702
2073
  }
1703
2074
  collectedOptions.keyHoldDuration = keyHoldDuration;
1704
2075
  }
1705
- const { allowActivationInsideInput } = await prompts2__default.default({
2076
+ const { allowActivationInsideInput } = await prompts3__default.default({
1706
2077
  type: "confirm",
1707
2078
  name: "allowActivationInsideInput",
1708
2079
  message: `Allow activation ${highlighter.info("inside input fields")}?`,
@@ -1713,7 +2084,7 @@ var configure = new commander.Command().name("configure").alias("config").descri
1713
2084
  process.exit(1);
1714
2085
  }
1715
2086
  collectedOptions.allowActivationInsideInput = allowActivationInsideInput;
1716
- const { maxContextLines } = await prompts2__default.default({
2087
+ const { maxContextLines } = await prompts3__default.default({
1717
2088
  type: "number",
1718
2089
  name: "maxContextLines",
1719
2090
  message: `Enter ${highlighter.info("max context lines")} to include:`,
@@ -1743,7 +2114,7 @@ var configure = new commander.Command().name("configure").alias("config").descri
1743
2114
  logger.break();
1744
2115
  printDiff(result.filePath, result.originalContent, result.newContent);
1745
2116
  logger.break();
1746
- const { proceed } = await prompts2__default.default({
2117
+ const { proceed } = await prompts3__default.default({
1747
2118
  type: "confirm",
1748
2119
  name: "proceed",
1749
2120
  message: "Apply these changes?",
@@ -1780,7 +2151,7 @@ var configure = new commander.Command().name("configure").alias("config").descri
1780
2151
  handleError(error);
1781
2152
  }
1782
2153
  });
1783
- var VERSION3 = "0.0.90";
2154
+ var VERSION3 = "0.0.92";
1784
2155
  var REPORT_URL = "https://react-grab.com/api/report-cli";
1785
2156
  var DOCS_URL = "https://github.com/aidenybai/react-grab";
1786
2157
  var reportToCli = async (type, config, error) => {
@@ -1818,6 +2189,34 @@ var UNSUPPORTED_FRAMEWORK_NAMES = {
1818
2189
  sveltekit: "SvelteKit",
1819
2190
  gatsby: "Gatsby"
1820
2191
  };
2192
+ var AGENT_NAMES2 = {
2193
+ "claude-code": "Claude Code",
2194
+ cursor: "Cursor",
2195
+ opencode: "OpenCode",
2196
+ codex: "Codex",
2197
+ gemini: "Gemini",
2198
+ amp: "Amp",
2199
+ ami: "Ami",
2200
+ "visual-edit": "Visual Edit"
2201
+ };
2202
+ var MODIFIER_KEY_NAMES2 = {
2203
+ metaKey: process.platform === "darwin" ? "\u2318 Command" : "\u229E Windows",
2204
+ ctrlKey: "Ctrl",
2205
+ shiftKey: "Shift",
2206
+ altKey: process.platform === "darwin" ? "\u2325 Option" : "Alt"
2207
+ };
2208
+ var formatActivationKey2 = (activationKey) => {
2209
+ if (!activationKey) return "Default (Option/Alt)";
2210
+ const parts = [];
2211
+ if (activationKey.metaKey)
2212
+ parts.push(process.platform === "darwin" ? "\u2318" : "Win");
2213
+ if (activationKey.ctrlKey) parts.push("Ctrl");
2214
+ if (activationKey.shiftKey) parts.push("Shift");
2215
+ if (activationKey.altKey)
2216
+ parts.push(process.platform === "darwin" ? "\u2325" : "Alt");
2217
+ if (activationKey.key) parts.push(activationKey.key.toUpperCase());
2218
+ return parts.length > 0 ? parts.join(" + ") : "Default (Option/Alt)";
2219
+ };
1821
2220
  var init = new commander.Command().name("init").description("initialize React Grab in your project").option("-y, --yes", "skip confirmation prompts", false).option("-f, --force", "force overwrite existing config", false).option(
1822
2221
  "-a, --agent <agent>",
1823
2222
  "agent integration (claude-code, cursor, opencode, codex, gemini, amp, visual-edit)"
@@ -1837,11 +2236,514 @@ var init = new commander.Command().name("init").description("initialize React Gr
1837
2236
  const projectInfo = await detectProject(cwd);
1838
2237
  if (projectInfo.hasReactGrab && !opts.force) {
1839
2238
  preflightSpinner.succeed();
2239
+ if (isNonInteractive) {
2240
+ logger.break();
2241
+ logger.warn("React Grab is already installed.");
2242
+ logger.log(
2243
+ `Use ${highlighter.info("--force")} to reconfigure, or remove ${highlighter.info("--yes")} for interactive mode.`
2244
+ );
2245
+ logger.break();
2246
+ process.exit(0);
2247
+ }
1840
2248
  logger.break();
1841
- logger.warn("React Grab is already installed.");
1842
- logger.log(
1843
- `Use ${highlighter.info("--force")} to reconfigure, or ${highlighter.info("npx grab@latest add")} to add an agent.`
2249
+ logger.success("React Grab is already installed.");
2250
+ logger.break();
2251
+ const allAgents = [
2252
+ "claude-code",
2253
+ "cursor",
2254
+ "opencode",
2255
+ "codex",
2256
+ "gemini",
2257
+ "amp",
2258
+ "visual-edit"
2259
+ ];
2260
+ const availableAgents = allAgents.filter(
2261
+ (agent) => !projectInfo.installedAgents.includes(agent)
1844
2262
  );
2263
+ if (projectInfo.installedAgents.length > 0) {
2264
+ const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES2[innerAgent] || innerAgent).join(", ");
2265
+ logger.log(
2266
+ `Currently installed agents: ${highlighter.info(installedNames)}`
2267
+ );
2268
+ logger.break();
2269
+ }
2270
+ let didAddAgent = false;
2271
+ if (availableAgents.length > 0) {
2272
+ const { wantAddAgent } = await prompts3__default.default({
2273
+ type: "confirm",
2274
+ name: "wantAddAgent",
2275
+ message: `Would you like to add an ${highlighter.info("agent integration")}?`,
2276
+ initial: true
2277
+ });
2278
+ if (wantAddAgent === void 0) {
2279
+ logger.break();
2280
+ process.exit(1);
2281
+ }
2282
+ if (wantAddAgent) {
2283
+ const { agent } = await prompts3__default.default({
2284
+ type: "select",
2285
+ name: "agent",
2286
+ message: `Which ${highlighter.info("agent integration")} would you like to add?`,
2287
+ choices: availableAgents.map((innerAgent) => ({
2288
+ title: AGENT_NAMES2[innerAgent],
2289
+ value: innerAgent
2290
+ }))
2291
+ });
2292
+ if (agent === void 0) {
2293
+ logger.break();
2294
+ process.exit(1);
2295
+ }
2296
+ const agentIntegration2 = agent;
2297
+ let agentsToRemove2 = [];
2298
+ if (projectInfo.installedAgents.length > 0) {
2299
+ const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES2[innerAgent] || innerAgent).join(", ");
2300
+ const { action } = await prompts3__default.default({
2301
+ type: "select",
2302
+ name: "action",
2303
+ message: "How would you like to proceed?",
2304
+ choices: [
2305
+ {
2306
+ title: `Replace ${installedNames} with ${AGENT_NAMES2[agentIntegration2]}`,
2307
+ value: "replace"
2308
+ },
2309
+ {
2310
+ title: `Add ${AGENT_NAMES2[agentIntegration2]} alongside existing`,
2311
+ value: "add"
2312
+ },
2313
+ { title: "Cancel", value: "cancel" }
2314
+ ]
2315
+ });
2316
+ if (!action || action === "cancel") {
2317
+ logger.break();
2318
+ logger.log("Agent addition cancelled.");
2319
+ } else {
2320
+ if (action === "replace") {
2321
+ agentsToRemove2 = [...projectInfo.installedAgents];
2322
+ }
2323
+ if (agentsToRemove2.length > 0) {
2324
+ for (const agentToRemove of agentsToRemove2) {
2325
+ const removalResult = previewAgentRemoval(
2326
+ projectInfo.projectRoot,
2327
+ projectInfo.framework,
2328
+ projectInfo.nextRouterType,
2329
+ agentToRemove
2330
+ );
2331
+ const removalPackageJsonResult = previewPackageJsonAgentRemoval(
2332
+ projectInfo.projectRoot,
2333
+ agentToRemove
2334
+ );
2335
+ const packagesToRemove = getPackagesToUninstall(agentToRemove);
2336
+ if (packagesToRemove.length > 0) {
2337
+ const uninstallSpinner = spinner(
2338
+ `Removing ${packagesToRemove.join(", ")}.`
2339
+ ).start();
2340
+ try {
2341
+ uninstallPackages(
2342
+ packagesToRemove,
2343
+ projectInfo.packageManager,
2344
+ projectInfo.projectRoot
2345
+ );
2346
+ uninstallSpinner.succeed();
2347
+ } catch (error) {
2348
+ uninstallSpinner.fail();
2349
+ handleError(error);
2350
+ }
2351
+ }
2352
+ if (removalResult.success && !removalResult.noChanges && removalResult.newContent) {
2353
+ const removeWriteSpinner = spinner(
2354
+ `Removing ${AGENT_NAMES2[agentToRemove] || agentToRemove} from ${removalResult.filePath}.`
2355
+ ).start();
2356
+ const writeResult = applyTransform(removalResult);
2357
+ if (!writeResult.success) {
2358
+ removeWriteSpinner.fail();
2359
+ logger.break();
2360
+ logger.error(
2361
+ writeResult.error || "Failed to write file."
2362
+ );
2363
+ logger.break();
2364
+ process.exit(1);
2365
+ }
2366
+ removeWriteSpinner.succeed();
2367
+ }
2368
+ if (removalPackageJsonResult.success && !removalPackageJsonResult.noChanges && removalPackageJsonResult.newContent) {
2369
+ const removePackageJsonSpinner = spinner(
2370
+ `Removing ${AGENT_NAMES2[agentToRemove] || agentToRemove} from ${removalPackageJsonResult.filePath}.`
2371
+ ).start();
2372
+ const packageJsonWriteResult = applyPackageJsonTransform(
2373
+ removalPackageJsonResult
2374
+ );
2375
+ if (!packageJsonWriteResult.success) {
2376
+ removePackageJsonSpinner.fail();
2377
+ logger.break();
2378
+ logger.error(
2379
+ packageJsonWriteResult.error || "Failed to write file."
2380
+ );
2381
+ logger.break();
2382
+ process.exit(1);
2383
+ }
2384
+ removePackageJsonSpinner.succeed();
2385
+ }
2386
+ }
2387
+ projectInfo.installedAgents = projectInfo.installedAgents.filter(
2388
+ (innerAgent) => !agentsToRemove2.includes(innerAgent)
2389
+ );
2390
+ }
2391
+ const result2 = previewTransform(
2392
+ projectInfo.projectRoot,
2393
+ projectInfo.framework,
2394
+ projectInfo.nextRouterType,
2395
+ agentIntegration2,
2396
+ true
2397
+ );
2398
+ const packageJsonResult2 = previewPackageJsonTransform(
2399
+ projectInfo.projectRoot,
2400
+ agentIntegration2,
2401
+ projectInfo.installedAgents,
2402
+ projectInfo.packageManager
2403
+ );
2404
+ if (!result2.success) {
2405
+ logger.break();
2406
+ logger.error(result2.message);
2407
+ logger.break();
2408
+ process.exit(1);
2409
+ }
2410
+ const hasLayoutChanges2 = !result2.noChanges && result2.originalContent && result2.newContent;
2411
+ const hasPackageJsonChanges2 = packageJsonResult2.success && !packageJsonResult2.noChanges && packageJsonResult2.originalContent && packageJsonResult2.newContent;
2412
+ if (hasLayoutChanges2 || hasPackageJsonChanges2) {
2413
+ logger.break();
2414
+ if (hasLayoutChanges2) {
2415
+ printDiff(
2416
+ result2.filePath,
2417
+ result2.originalContent,
2418
+ result2.newContent
2419
+ );
2420
+ }
2421
+ if (hasPackageJsonChanges2) {
2422
+ if (hasLayoutChanges2) {
2423
+ logger.break();
2424
+ }
2425
+ printDiff(
2426
+ packageJsonResult2.filePath,
2427
+ packageJsonResult2.originalContent,
2428
+ packageJsonResult2.newContent
2429
+ );
2430
+ }
2431
+ if (agentsToRemove2.length === 0) {
2432
+ logger.break();
2433
+ const { proceed } = await prompts3__default.default({
2434
+ type: "confirm",
2435
+ name: "proceed",
2436
+ message: "Apply these changes?",
2437
+ initial: true
2438
+ });
2439
+ if (!proceed) {
2440
+ logger.break();
2441
+ logger.log("Agent addition cancelled.");
2442
+ } else {
2443
+ const packages = getPackagesToInstall(
2444
+ agentIntegration2,
2445
+ false
2446
+ );
2447
+ if (packages.length > 0) {
2448
+ const installSpinner = spinner(
2449
+ `Installing ${packages.join(", ")}.`
2450
+ ).start();
2451
+ try {
2452
+ installPackages(
2453
+ packages,
2454
+ projectInfo.packageManager,
2455
+ projectInfo.projectRoot
2456
+ );
2457
+ installSpinner.succeed();
2458
+ } catch (error) {
2459
+ installSpinner.fail();
2460
+ handleError(error);
2461
+ }
2462
+ }
2463
+ if (hasLayoutChanges2) {
2464
+ const writeSpinner = spinner(
2465
+ `Applying changes to ${result2.filePath}.`
2466
+ ).start();
2467
+ const writeResult = applyTransform(result2);
2468
+ if (!writeResult.success) {
2469
+ writeSpinner.fail();
2470
+ logger.break();
2471
+ logger.error(
2472
+ writeResult.error || "Failed to write file."
2473
+ );
2474
+ logger.break();
2475
+ process.exit(1);
2476
+ }
2477
+ writeSpinner.succeed();
2478
+ }
2479
+ if (hasPackageJsonChanges2) {
2480
+ const packageJsonSpinner = spinner(
2481
+ `Applying changes to ${packageJsonResult2.filePath}.`
2482
+ ).start();
2483
+ const packageJsonWriteResult = applyPackageJsonTransform(packageJsonResult2);
2484
+ if (!packageJsonWriteResult.success) {
2485
+ packageJsonSpinner.fail();
2486
+ logger.break();
2487
+ logger.error(
2488
+ packageJsonWriteResult.error || "Failed to write file."
2489
+ );
2490
+ logger.break();
2491
+ process.exit(1);
2492
+ }
2493
+ packageJsonSpinner.succeed();
2494
+ }
2495
+ didAddAgent = true;
2496
+ logger.break();
2497
+ logger.success(
2498
+ `${AGENT_NAMES2[agentIntegration2]} has been added.`
2499
+ );
2500
+ }
2501
+ } else {
2502
+ const packages = getPackagesToInstall(
2503
+ agentIntegration2,
2504
+ false
2505
+ );
2506
+ if (packages.length > 0) {
2507
+ const installSpinner = spinner(
2508
+ `Installing ${packages.join(", ")}.`
2509
+ ).start();
2510
+ try {
2511
+ installPackages(
2512
+ packages,
2513
+ projectInfo.packageManager,
2514
+ projectInfo.projectRoot
2515
+ );
2516
+ installSpinner.succeed();
2517
+ } catch (error) {
2518
+ installSpinner.fail();
2519
+ handleError(error);
2520
+ }
2521
+ }
2522
+ if (hasLayoutChanges2) {
2523
+ const writeSpinner = spinner(
2524
+ `Applying changes to ${result2.filePath}.`
2525
+ ).start();
2526
+ const writeResult = applyTransform(result2);
2527
+ if (!writeResult.success) {
2528
+ writeSpinner.fail();
2529
+ logger.break();
2530
+ logger.error(
2531
+ writeResult.error || "Failed to write file."
2532
+ );
2533
+ logger.break();
2534
+ process.exit(1);
2535
+ }
2536
+ writeSpinner.succeed();
2537
+ }
2538
+ if (hasPackageJsonChanges2) {
2539
+ const packageJsonSpinner = spinner(
2540
+ `Applying changes to ${packageJsonResult2.filePath}.`
2541
+ ).start();
2542
+ const packageJsonWriteResult = applyPackageJsonTransform(packageJsonResult2);
2543
+ if (!packageJsonWriteResult.success) {
2544
+ packageJsonSpinner.fail();
2545
+ logger.break();
2546
+ logger.error(
2547
+ packageJsonWriteResult.error || "Failed to write file."
2548
+ );
2549
+ logger.break();
2550
+ process.exit(1);
2551
+ }
2552
+ packageJsonSpinner.succeed();
2553
+ }
2554
+ didAddAgent = true;
2555
+ logger.break();
2556
+ logger.success(
2557
+ `${AGENT_NAMES2[agentIntegration2]} has been added.`
2558
+ );
2559
+ }
2560
+ }
2561
+ }
2562
+ }
2563
+ }
2564
+ } else {
2565
+ logger.log("All agent integrations are already installed.");
2566
+ }
2567
+ logger.break();
2568
+ const { wantCustomizeOptions } = await prompts3__default.default({
2569
+ type: "confirm",
2570
+ name: "wantCustomizeOptions",
2571
+ message: `Would you like to customize ${highlighter.info("options")}?`,
2572
+ initial: false
2573
+ });
2574
+ if (wantCustomizeOptions === void 0) {
2575
+ logger.break();
2576
+ process.exit(1);
2577
+ }
2578
+ if (wantCustomizeOptions) {
2579
+ logger.break();
2580
+ logger.log(`Configure ${highlighter.info("React Grab")} options:`);
2581
+ logger.break();
2582
+ const collectedOptions = {};
2583
+ const { wantActivationKey } = await prompts3__default.default({
2584
+ type: "confirm",
2585
+ name: "wantActivationKey",
2586
+ message: `Configure ${highlighter.info("activation key")}?`,
2587
+ initial: false
2588
+ });
2589
+ if (wantActivationKey === void 0) {
2590
+ logger.break();
2591
+ process.exit(1);
2592
+ }
2593
+ if (wantActivationKey) {
2594
+ const { key } = await prompts3__default.default({
2595
+ type: "text",
2596
+ name: "key",
2597
+ message: "Enter the activation key (e.g., g, k, space):",
2598
+ initial: ""
2599
+ });
2600
+ if (key === void 0) {
2601
+ logger.break();
2602
+ process.exit(1);
2603
+ }
2604
+ const { modifiers } = await prompts3__default.default({
2605
+ type: "multiselect",
2606
+ name: "modifiers",
2607
+ message: "Select modifier keys (space to select, enter to confirm):",
2608
+ choices: [
2609
+ { title: MODIFIER_KEY_NAMES2.metaKey, value: "metaKey" },
2610
+ { title: MODIFIER_KEY_NAMES2.ctrlKey, value: "ctrlKey" },
2611
+ { title: MODIFIER_KEY_NAMES2.shiftKey, value: "shiftKey" },
2612
+ {
2613
+ title: MODIFIER_KEY_NAMES2.altKey,
2614
+ value: "altKey",
2615
+ selected: true
2616
+ }
2617
+ ],
2618
+ hint: "- Space to select, Enter to confirm"
2619
+ });
2620
+ if (modifiers === void 0) {
2621
+ logger.break();
2622
+ process.exit(1);
2623
+ }
2624
+ collectedOptions.activationKey = {
2625
+ ...key && { key: key.toLowerCase() },
2626
+ ...modifiers.includes("metaKey") && { metaKey: true },
2627
+ ...modifiers.includes("ctrlKey") && { ctrlKey: true },
2628
+ ...modifiers.includes("shiftKey") && { shiftKey: true },
2629
+ ...modifiers.includes("altKey") && { altKey: true }
2630
+ };
2631
+ logger.log(
2632
+ ` Activation key: ${highlighter.info(formatActivationKey2(collectedOptions.activationKey))}`
2633
+ );
2634
+ }
2635
+ const { activationMode } = await prompts3__default.default({
2636
+ type: "select",
2637
+ name: "activationMode",
2638
+ message: `Select ${highlighter.info("activation mode")}:`,
2639
+ choices: [
2640
+ {
2641
+ title: "Toggle (press to activate/deactivate)",
2642
+ value: "toggle"
2643
+ },
2644
+ { title: "Hold (hold key to keep active)", value: "hold" }
2645
+ ],
2646
+ initial: 0
2647
+ });
2648
+ if (activationMode === void 0) {
2649
+ logger.break();
2650
+ process.exit(1);
2651
+ }
2652
+ collectedOptions.activationMode = activationMode;
2653
+ if (activationMode === "hold") {
2654
+ const { keyHoldDuration } = await prompts3__default.default({
2655
+ type: "number",
2656
+ name: "keyHoldDuration",
2657
+ message: `Enter ${highlighter.info("key hold duration")} in milliseconds:`,
2658
+ initial: 150,
2659
+ min: 0,
2660
+ max: 2e3
2661
+ });
2662
+ if (keyHoldDuration === void 0) {
2663
+ logger.break();
2664
+ process.exit(1);
2665
+ }
2666
+ collectedOptions.keyHoldDuration = keyHoldDuration;
2667
+ }
2668
+ const { allowActivationInsideInput } = await prompts3__default.default({
2669
+ type: "confirm",
2670
+ name: "allowActivationInsideInput",
2671
+ message: `Allow activation ${highlighter.info("inside input fields")}?`,
2672
+ initial: true
2673
+ });
2674
+ if (allowActivationInsideInput === void 0) {
2675
+ logger.break();
2676
+ process.exit(1);
2677
+ }
2678
+ collectedOptions.allowActivationInsideInput = allowActivationInsideInput;
2679
+ const { maxContextLines } = await prompts3__default.default({
2680
+ type: "number",
2681
+ name: "maxContextLines",
2682
+ message: `Enter ${highlighter.info("max context lines")} to include:`,
2683
+ initial: 3,
2684
+ min: 0,
2685
+ max: 50
2686
+ });
2687
+ if (maxContextLines === void 0) {
2688
+ logger.break();
2689
+ process.exit(1);
2690
+ }
2691
+ collectedOptions.maxContextLines = maxContextLines;
2692
+ const optionsResult = previewOptionsTransform(
2693
+ projectInfo.projectRoot,
2694
+ projectInfo.framework,
2695
+ projectInfo.nextRouterType,
2696
+ collectedOptions
2697
+ );
2698
+ if (!optionsResult.success) {
2699
+ logger.break();
2700
+ logger.error(optionsResult.message);
2701
+ logger.break();
2702
+ process.exit(1);
2703
+ }
2704
+ const hasOptionsChanges = !optionsResult.noChanges && optionsResult.originalContent && optionsResult.newContent;
2705
+ if (hasOptionsChanges) {
2706
+ logger.break();
2707
+ printDiff(
2708
+ optionsResult.filePath,
2709
+ optionsResult.originalContent,
2710
+ optionsResult.newContent
2711
+ );
2712
+ logger.break();
2713
+ const { proceed } = await prompts3__default.default({
2714
+ type: "confirm",
2715
+ name: "proceed",
2716
+ message: "Apply these changes?",
2717
+ initial: true
2718
+ });
2719
+ if (!proceed) {
2720
+ logger.break();
2721
+ logger.log("Options configuration cancelled.");
2722
+ } else {
2723
+ const writeSpinner = spinner(
2724
+ `Applying changes to ${optionsResult.filePath}.`
2725
+ ).start();
2726
+ const writeResult = applyOptionsTransform(optionsResult);
2727
+ if (!writeResult.success) {
2728
+ writeSpinner.fail();
2729
+ logger.break();
2730
+ logger.error(writeResult.error || "Failed to write file.");
2731
+ logger.break();
2732
+ process.exit(1);
2733
+ }
2734
+ writeSpinner.succeed();
2735
+ logger.break();
2736
+ logger.success("React Grab options have been configured.");
2737
+ }
2738
+ } else {
2739
+ logger.break();
2740
+ logger.log("No option changes needed.");
2741
+ }
2742
+ }
2743
+ if (!didAddAgent && !wantCustomizeOptions) {
2744
+ logger.break();
2745
+ logger.log("No changes made.");
2746
+ }
1845
2747
  logger.break();
1846
2748
  process.exit(0);
1847
2749
  }
@@ -1876,7 +2778,7 @@ var init = new commander.Command().name("init").description("initialize React Gr
1876
2778
  return 0;
1877
2779
  }
1878
2780
  );
1879
- const { selectedProject } = await prompts2__default.default({
2781
+ const { selectedProject } = await prompts3__default.default({
1880
2782
  type: "select",
1881
2783
  name: "selectedProject",
1882
2784
  message: "Select a project to install React Grab:",
@@ -1937,9 +2839,15 @@ var init = new commander.Command().name("init").description("initialize React Gr
1937
2839
  let finalPackageManager = projectInfo.packageManager;
1938
2840
  let finalNextRouterType = projectInfo.nextRouterType;
1939
2841
  let agentIntegration = opts.agent || "none";
2842
+ let agentsToRemove = [];
1940
2843
  if (!isNonInteractive && !opts.agent) {
1941
2844
  logger.break();
1942
- const { agent } = await prompts2__default.default({
2845
+ if (opts.force && projectInfo.installedAgents.length > 0) {
2846
+ const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES2[innerAgent] || innerAgent).join(", ");
2847
+ logger.warn(`Currently installed: ${installedNames}`);
2848
+ logger.break();
2849
+ }
2850
+ const { agent } = await prompts3__default.default({
1943
2851
  type: "select",
1944
2852
  name: "agent",
1945
2853
  message: `Would you like to add an ${highlighter.info("agent integration")}?`,
@@ -1959,6 +2867,63 @@ var init = new commander.Command().name("init").description("initialize React Gr
1959
2867
  process.exit(1);
1960
2868
  }
1961
2869
  agentIntegration = agent;
2870
+ if (opts.force && projectInfo.installedAgents.length > 0 && agentIntegration !== "none" && !projectInfo.installedAgents.includes(agentIntegration)) {
2871
+ const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES2[innerAgent] || innerAgent).join(", ");
2872
+ const { action } = await prompts3__default.default({
2873
+ type: "select",
2874
+ name: "action",
2875
+ message: "How would you like to proceed?",
2876
+ choices: [
2877
+ {
2878
+ title: `Replace ${installedNames} with ${AGENT_NAMES2[agentIntegration]}`,
2879
+ value: "replace"
2880
+ },
2881
+ {
2882
+ title: `Add ${AGENT_NAMES2[agentIntegration]} alongside existing`,
2883
+ value: "add"
2884
+ },
2885
+ { title: "Cancel", value: "cancel" }
2886
+ ]
2887
+ });
2888
+ if (!action || action === "cancel") {
2889
+ logger.break();
2890
+ logger.log("Changes cancelled.");
2891
+ logger.break();
2892
+ process.exit(0);
2893
+ }
2894
+ if (action === "replace") {
2895
+ agentsToRemove = [...projectInfo.installedAgents];
2896
+ }
2897
+ }
2898
+ } else if (opts.agent && opts.force && projectInfo.installedAgents.length > 0 && !projectInfo.installedAgents.includes(opts.agent) && !isNonInteractive) {
2899
+ const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES2[innerAgent] || innerAgent).join(", ");
2900
+ logger.break();
2901
+ logger.warn(`Currently installed: ${installedNames}`);
2902
+ const { action } = await prompts3__default.default({
2903
+ type: "select",
2904
+ name: "action",
2905
+ message: "How would you like to proceed?",
2906
+ choices: [
2907
+ {
2908
+ title: `Replace ${installedNames} with ${AGENT_NAMES2[agentIntegration]}`,
2909
+ value: "replace"
2910
+ },
2911
+ {
2912
+ title: `Add ${AGENT_NAMES2[agentIntegration]} alongside existing`,
2913
+ value: "add"
2914
+ },
2915
+ { title: "Cancel", value: "cancel" }
2916
+ ]
2917
+ });
2918
+ if (!action || action === "cancel") {
2919
+ logger.break();
2920
+ logger.log("Changes cancelled.");
2921
+ logger.break();
2922
+ process.exit(0);
2923
+ }
2924
+ if (action === "replace") {
2925
+ agentsToRemove = [...projectInfo.installedAgents];
2926
+ }
1962
2927
  }
1963
2928
  const result = previewTransform(
1964
2929
  projectInfo.projectRoot,
@@ -1970,7 +2935,8 @@ var init = new commander.Command().name("init").description("initialize React Gr
1970
2935
  const packageJsonResult = previewPackageJsonTransform(
1971
2936
  projectInfo.projectRoot,
1972
2937
  agentIntegration,
1973
- projectInfo.installedAgents
2938
+ projectInfo.installedAgents,
2939
+ finalPackageManager
1974
2940
  );
1975
2941
  if (!result.success) {
1976
2942
  logger.break();
@@ -2005,7 +2971,7 @@ var init = new commander.Command().name("init").description("initialize React Gr
2005
2971
  logger.warn("Please verify the changes before committing.");
2006
2972
  if (!isNonInteractive) {
2007
2973
  logger.break();
2008
- const { proceed } = await prompts2__default.default({
2974
+ const { proceed } = await prompts3__default.default({
2009
2975
  type: "confirm",
2010
2976
  name: "proceed",
2011
2977
  message: "Apply these changes?",
@@ -2019,6 +2985,72 @@ var init = new commander.Command().name("init").description("initialize React Gr
2019
2985
  }
2020
2986
  }
2021
2987
  }
2988
+ if (agentsToRemove.length > 0) {
2989
+ for (const agentToRemove of agentsToRemove) {
2990
+ const removalResult = previewAgentRemoval(
2991
+ projectInfo.projectRoot,
2992
+ projectInfo.framework,
2993
+ projectInfo.nextRouterType,
2994
+ agentToRemove
2995
+ );
2996
+ const removalPackageJsonResult = previewPackageJsonAgentRemoval(
2997
+ projectInfo.projectRoot,
2998
+ agentToRemove
2999
+ );
3000
+ const packagesToRemove = getPackagesToUninstall(agentToRemove);
3001
+ if (packagesToRemove.length > 0 && !opts.skipInstall) {
3002
+ const uninstallSpinner = spinner(
3003
+ `Removing ${packagesToRemove.join(", ")}.`
3004
+ ).start();
3005
+ try {
3006
+ uninstallPackages(
3007
+ packagesToRemove,
3008
+ finalPackageManager,
3009
+ projectInfo.projectRoot
3010
+ );
3011
+ uninstallSpinner.succeed();
3012
+ } catch (error) {
3013
+ uninstallSpinner.fail();
3014
+ handleError(error);
3015
+ }
3016
+ }
3017
+ if (removalResult.success && !removalResult.noChanges && removalResult.newContent) {
3018
+ const removeWriteSpinner = spinner(
3019
+ `Removing ${AGENT_NAMES2[agentToRemove] || agentToRemove} from ${removalResult.filePath}.`
3020
+ ).start();
3021
+ const writeResult = applyTransform(removalResult);
3022
+ if (!writeResult.success) {
3023
+ removeWriteSpinner.fail();
3024
+ logger.break();
3025
+ logger.error(writeResult.error || "Failed to write file.");
3026
+ logger.break();
3027
+ process.exit(1);
3028
+ }
3029
+ removeWriteSpinner.succeed();
3030
+ }
3031
+ if (removalPackageJsonResult.success && !removalPackageJsonResult.noChanges && removalPackageJsonResult.newContent) {
3032
+ const removePackageJsonSpinner = spinner(
3033
+ `Removing ${AGENT_NAMES2[agentToRemove] || agentToRemove} from ${removalPackageJsonResult.filePath}.`
3034
+ ).start();
3035
+ const packageJsonWriteResult = applyPackageJsonTransform(
3036
+ removalPackageJsonResult
3037
+ );
3038
+ if (!packageJsonWriteResult.success) {
3039
+ removePackageJsonSpinner.fail();
3040
+ logger.break();
3041
+ logger.error(
3042
+ packageJsonWriteResult.error || "Failed to write file."
3043
+ );
3044
+ logger.break();
3045
+ process.exit(1);
3046
+ }
3047
+ removePackageJsonSpinner.succeed();
3048
+ }
3049
+ }
3050
+ projectInfo.installedAgents = projectInfo.installedAgents.filter(
3051
+ (innerAgent) => !agentsToRemove.includes(innerAgent)
3052
+ );
3053
+ }
2022
3054
  const shouldInstallReactGrab = !projectInfo.hasReactGrab;
2023
3055
  const shouldInstallAgent = agentIntegration !== "none" && !projectInfo.installedAgents.includes(agentIntegration);
2024
3056
  if (!opts.skipInstall && (shouldInstallReactGrab || shouldInstallAgent)) {
@@ -2076,7 +3108,9 @@ var init = new commander.Command().name("init").description("initialize React Gr
2076
3108
  `${highlighter.success("Success!")} React Grab has been installed.`
2077
3109
  );
2078
3110
  if (packageJsonResult.warning) {
3111
+ logger.break();
2079
3112
  logger.warn(packageJsonResult.warning);
3113
+ logger.break();
2080
3114
  } else {
2081
3115
  logger.log("You may now start your development server.");
2082
3116
  }
@@ -2093,7 +3127,194 @@ var init = new commander.Command().name("init").description("initialize React Gr
2093
3127
  await reportToCli("error", void 0, error);
2094
3128
  }
2095
3129
  });
2096
- var VERSION4 = "0.0.90";
3130
+ var VERSION4 = "0.0.92";
3131
+ var AGENT_NAMES3 = {
3132
+ "claude-code": "Claude Code",
3133
+ cursor: "Cursor",
3134
+ opencode: "OpenCode",
3135
+ codex: "Codex",
3136
+ gemini: "Gemini",
3137
+ amp: "Amp",
3138
+ ami: "Ami",
3139
+ "visual-edit": "Visual Edit"
3140
+ };
3141
+ var remove = new commander.Command().name("remove").description("remove an agent integration").argument(
3142
+ "[agent]",
3143
+ "agent to remove (claude-code, cursor, opencode, codex, gemini, amp, ami, visual-edit)"
3144
+ ).option("-y, --yes", "skip confirmation prompts", false).option(
3145
+ "-c, --cwd <cwd>",
3146
+ "working directory (defaults to current directory)",
3147
+ process.cwd()
3148
+ ).action(async (agentArg, opts) => {
3149
+ console.log(
3150
+ `${pc__default.default.magenta("\u273F")} ${pc__default.default.bold("React Grab")} ${pc__default.default.gray(VERSION4)}`
3151
+ );
3152
+ console.log();
3153
+ try {
3154
+ const cwd = opts.cwd;
3155
+ const isNonInteractive = opts.yes;
3156
+ const preflightSpinner = spinner("Preflight checks.").start();
3157
+ const projectInfo = await detectProject(cwd);
3158
+ if (!projectInfo.hasReactGrab) {
3159
+ preflightSpinner.fail("React Grab is not installed.");
3160
+ logger.break();
3161
+ logger.error(
3162
+ `Run ${highlighter.info("react-grab init")} first to install React Grab.`
3163
+ );
3164
+ logger.break();
3165
+ process.exit(1);
3166
+ }
3167
+ if (projectInfo.installedAgents.length === 0) {
3168
+ preflightSpinner.succeed();
3169
+ logger.break();
3170
+ logger.warn("No agent integrations are installed.");
3171
+ logger.break();
3172
+ process.exit(0);
3173
+ }
3174
+ preflightSpinner.succeed();
3175
+ let agentToRemove;
3176
+ if (agentArg) {
3177
+ if (!projectInfo.installedAgents.includes(agentArg)) {
3178
+ logger.break();
3179
+ logger.error(`Agent ${highlighter.info(agentArg)} is not installed.`);
3180
+ logger.log(
3181
+ `Installed agents: ${projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES3[innerAgent] || innerAgent).join(", ")}`
3182
+ );
3183
+ logger.break();
3184
+ process.exit(1);
3185
+ }
3186
+ agentToRemove = agentArg;
3187
+ } else if (!isNonInteractive) {
3188
+ logger.break();
3189
+ const { agent } = await prompts3__default.default({
3190
+ type: "select",
3191
+ name: "agent",
3192
+ message: `Which ${highlighter.info("agent integration")} would you like to remove?`,
3193
+ choices: projectInfo.installedAgents.map((innerAgent) => ({
3194
+ title: AGENT_NAMES3[innerAgent] || innerAgent,
3195
+ value: innerAgent
3196
+ }))
3197
+ });
3198
+ if (!agent) {
3199
+ logger.break();
3200
+ process.exit(1);
3201
+ }
3202
+ agentToRemove = agent;
3203
+ } else {
3204
+ logger.break();
3205
+ logger.error("Please specify an agent to remove.");
3206
+ logger.error(
3207
+ "Installed agents: " + projectInfo.installedAgents.join(", ")
3208
+ );
3209
+ logger.break();
3210
+ process.exit(1);
3211
+ }
3212
+ const removingSpinner = spinner(
3213
+ `Preparing to remove ${AGENT_NAMES3[agentToRemove] || agentToRemove}.`
3214
+ ).start();
3215
+ removingSpinner.succeed();
3216
+ const result = previewAgentRemoval(
3217
+ projectInfo.projectRoot,
3218
+ projectInfo.framework,
3219
+ projectInfo.nextRouterType,
3220
+ agentToRemove
3221
+ );
3222
+ const packageJsonResult = previewPackageJsonAgentRemoval(
3223
+ projectInfo.projectRoot,
3224
+ agentToRemove
3225
+ );
3226
+ const hasLayoutChanges = result.success && !result.noChanges && result.originalContent && result.newContent;
3227
+ const hasPackageJsonChanges = packageJsonResult.success && !packageJsonResult.noChanges && packageJsonResult.originalContent && packageJsonResult.newContent;
3228
+ if (hasLayoutChanges || hasPackageJsonChanges) {
3229
+ logger.break();
3230
+ if (hasLayoutChanges) {
3231
+ printDiff(
3232
+ result.filePath,
3233
+ result.originalContent,
3234
+ result.newContent
3235
+ );
3236
+ }
3237
+ if (hasPackageJsonChanges) {
3238
+ if (hasLayoutChanges) {
3239
+ logger.break();
3240
+ }
3241
+ printDiff(
3242
+ packageJsonResult.filePath,
3243
+ packageJsonResult.originalContent,
3244
+ packageJsonResult.newContent
3245
+ );
3246
+ }
3247
+ if (!isNonInteractive) {
3248
+ logger.break();
3249
+ const { proceed } = await prompts3__default.default({
3250
+ type: "confirm",
3251
+ name: "proceed",
3252
+ message: "Apply these changes?",
3253
+ initial: true
3254
+ });
3255
+ if (!proceed) {
3256
+ logger.break();
3257
+ logger.log("Changes cancelled.");
3258
+ logger.break();
3259
+ process.exit(0);
3260
+ }
3261
+ }
3262
+ }
3263
+ const packages = getPackagesToUninstall(agentToRemove);
3264
+ if (packages.length > 0) {
3265
+ const uninstallSpinner = spinner(
3266
+ `Removing ${packages.join(", ")}.`
3267
+ ).start();
3268
+ try {
3269
+ uninstallPackages(
3270
+ packages,
3271
+ projectInfo.packageManager,
3272
+ projectInfo.projectRoot
3273
+ );
3274
+ uninstallSpinner.succeed();
3275
+ } catch (error) {
3276
+ uninstallSpinner.fail();
3277
+ handleError(error);
3278
+ }
3279
+ }
3280
+ if (hasLayoutChanges) {
3281
+ const writeSpinner = spinner(
3282
+ `Applying changes to ${result.filePath}.`
3283
+ ).start();
3284
+ const writeResult = applyTransform(result);
3285
+ if (!writeResult.success) {
3286
+ writeSpinner.fail();
3287
+ logger.break();
3288
+ logger.error(writeResult.error || "Failed to write file.");
3289
+ logger.break();
3290
+ process.exit(1);
3291
+ }
3292
+ writeSpinner.succeed();
3293
+ }
3294
+ if (hasPackageJsonChanges) {
3295
+ const packageJsonSpinner = spinner(
3296
+ `Applying changes to ${packageJsonResult.filePath}.`
3297
+ ).start();
3298
+ const packageJsonWriteResult = applyPackageJsonTransform(packageJsonResult);
3299
+ if (!packageJsonWriteResult.success) {
3300
+ packageJsonSpinner.fail();
3301
+ logger.break();
3302
+ logger.error(packageJsonWriteResult.error || "Failed to write file.");
3303
+ logger.break();
3304
+ process.exit(1);
3305
+ }
3306
+ packageJsonSpinner.succeed();
3307
+ }
3308
+ logger.break();
3309
+ logger.log(
3310
+ `${highlighter.success("Success!")} ${AGENT_NAMES3[agentToRemove] || agentToRemove} has been removed.`
3311
+ );
3312
+ logger.break();
3313
+ } catch (error) {
3314
+ handleError(error);
3315
+ }
3316
+ });
3317
+ var VERSION5 = "0.0.92";
2097
3318
  var DEFAULT_PROXY_PORT = 2e3;
2098
3319
  var REACT_GRAB_SCRIPT = '<script src="https://unpkg.com/react-grab/dist/index.global.js"></script>';
2099
3320
  var buildProviderScript = (provider) => `<script src="https://unpkg.com/${provider}/dist/client.global.js"></script>`;
@@ -2138,13 +3359,13 @@ var start = new commander.Command().name("start").alias("proxy").description("st
2138
3359
  "provider package to run via npx (e.g., @react-grab/cursor)"
2139
3360
  ).action(async (urlArg, opts) => {
2140
3361
  console.log(
2141
- `${pc__default.default.magenta("\u273F")} ${pc__default.default.bold("React Grab")} ${pc__default.default.gray(VERSION4)}`
3362
+ `${pc__default.default.magenta("\u273F")} ${pc__default.default.bold("React Grab")} ${pc__default.default.gray(VERSION5)}`
2142
3363
  );
2143
3364
  console.log();
2144
3365
  let url = urlArg;
2145
3366
  let provider = opts.provider;
2146
3367
  if (!url) {
2147
- const { targetUrl: promptedUrl } = await prompts2__default.default({
3368
+ const { targetUrl: promptedUrl } = await prompts3__default.default({
2148
3369
  type: "text",
2149
3370
  name: "targetUrl",
2150
3371
  message: "Enter the target URL to proxy:",
@@ -2156,7 +3377,7 @@ var start = new commander.Command().name("start").alias("proxy").description("st
2156
3377
  }
2157
3378
  url = promptedUrl;
2158
3379
  if (!provider) {
2159
- const { selectedProvider } = await prompts2__default.default({
3380
+ const { selectedProvider } = await prompts3__default.default({
2160
3381
  type: "select",
2161
3382
  name: "selectedProvider",
2162
3383
  message: `Select a ${highlighter.info("provider")} to use:`,
@@ -2323,7 +3544,7 @@ var start = new commander.Command().name("start").alias("proxy").description("st
2323
3544
 
2324
3545
  // src/cli.ts
2325
3546
  process.noDeprecation = true;
2326
- var VERSION5 = "0.0.90";
3547
+ var VERSION6 = "0.0.92";
2327
3548
  var VERSION_API_URL = "https://www.react-grab.com/api/version";
2328
3549
  process.on("SIGINT", () => process.exit(0));
2329
3550
  process.on("SIGTERM", () => process.exit(0));
@@ -2332,9 +3553,10 @@ try {
2332
3553
  });
2333
3554
  } catch {
2334
3555
  }
2335
- var program = new commander.Command().name("react-grab").description("add React Grab to your project").version(VERSION5, "-v, --version", "display the version number");
3556
+ var program = new commander.Command().name("react-grab").description("add React Grab to your project").version(VERSION6, "-v, --version", "display the version number");
2336
3557
  program.addCommand(init);
2337
3558
  program.addCommand(add);
3559
+ program.addCommand(remove);
2338
3560
  program.addCommand(configure);
2339
3561
  program.addCommand(start);
2340
3562
  program.parse();