@react-grab/cli 0.1.11 → 0.1.13

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 +527 -87
  2. package/dist/cli.js +525 -89
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -3,9 +3,11 @@ import { Command } from 'commander';
3
3
  import pc from 'picocolors';
4
4
  import basePrompts from 'prompts';
5
5
  import { execSync } from 'child_process';
6
- import { readFileSync, existsSync, writeFileSync, accessSync, constants, readdirSync } from 'fs';
7
- import { join, basename } from 'path';
6
+ import fs, { readFileSync, existsSync, writeFileSync, accessSync, constants, readdirSync } from 'fs';
7
+ import path, { join, basename } from 'path';
8
8
  import { detect } from '@antfu/ni';
9
+ import os from 'os';
10
+ import process2 from 'process';
9
11
  import ora from 'ora';
10
12
 
11
13
  var highlighter = {
@@ -294,7 +296,8 @@ var AGENT_PACKAGES = [
294
296
  "@react-grab/codex",
295
297
  "@react-grab/gemini",
296
298
  "@react-grab/amp",
297
- "@react-grab/ami"
299
+ "@react-grab/ami",
300
+ "@react-grab/mcp"
298
301
  ];
299
302
  var detectUnsupportedFramework = (projectRoot) => {
300
303
  const packageJsonPath = join(projectRoot, "package.json");
@@ -525,6 +528,301 @@ var getPackagesToUninstall = (agent) => {
525
528
  };
526
529
  var spinner = (text, options) => ora({ text, isSilent: options?.silent });
527
530
 
531
+ // src/utils/install-mcp.ts
532
+ var SERVER_NAME = "react-grab-mcp";
533
+ var PACKAGE_NAME = "@react-grab/mcp";
534
+ var getBaseDir = () => {
535
+ const homeDir = os.homedir();
536
+ if (process2.platform === "win32") {
537
+ return process2.env.APPDATA || path.join(homeDir, "AppData", "Roaming");
538
+ }
539
+ if (process2.platform === "darwin") {
540
+ return path.join(homeDir, "Library", "Application Support");
541
+ }
542
+ return process2.env.XDG_CONFIG_HOME || path.join(homeDir, ".config");
543
+ };
544
+ var getZedConfigPath = () => {
545
+ const homeDir = os.homedir();
546
+ if (process2.platform === "win32") {
547
+ const appData = process2.env.APPDATA || path.join(homeDir, "AppData", "Roaming");
548
+ return path.join(appData, "Zed", "settings.json");
549
+ }
550
+ return path.join(homeDir, ".config", "zed", "settings.json");
551
+ };
552
+ var getClients = () => {
553
+ const homeDir = os.homedir();
554
+ const baseDir = getBaseDir();
555
+ const stdioConfig = {
556
+ command: "npx",
557
+ args: ["-y", PACKAGE_NAME, "--stdio"]
558
+ };
559
+ return [
560
+ {
561
+ name: "Cursor",
562
+ configPath: path.join(homeDir, ".cursor", "mcp.json"),
563
+ configKey: "mcpServers",
564
+ format: "json",
565
+ serverConfig: stdioConfig
566
+ },
567
+ {
568
+ name: "VS Code",
569
+ configPath: path.join(baseDir, "Code", "User", "mcp.json"),
570
+ configKey: "servers",
571
+ format: "json",
572
+ serverConfig: { type: "stdio", ...stdioConfig }
573
+ },
574
+ {
575
+ name: "Claude Code",
576
+ configPath: path.join(homeDir, ".claude.json"),
577
+ configKey: "mcpServers",
578
+ format: "json",
579
+ serverConfig: stdioConfig
580
+ },
581
+ {
582
+ name: "Amp",
583
+ configPath: path.join(homeDir, ".config", "amp", "settings.json"),
584
+ configKey: "amp.mcpServers",
585
+ format: "json",
586
+ serverConfig: stdioConfig
587
+ },
588
+ {
589
+ name: "Droid",
590
+ configPath: path.join(homeDir, ".factory", "mcp.json"),
591
+ configKey: "mcpServers",
592
+ format: "json",
593
+ serverConfig: { type: "stdio", ...stdioConfig }
594
+ },
595
+ {
596
+ name: "Codex",
597
+ configPath: path.join(
598
+ process2.env.CODEX_HOME || path.join(homeDir, ".codex"),
599
+ "config.toml"
600
+ ),
601
+ configKey: "mcp_servers",
602
+ format: "toml",
603
+ serverConfig: stdioConfig
604
+ },
605
+ {
606
+ name: "Zed",
607
+ configPath: getZedConfigPath(),
608
+ configKey: "context_servers",
609
+ format: "json",
610
+ serverConfig: { source: "custom", ...stdioConfig, env: {} }
611
+ },
612
+ {
613
+ name: "Windsurf",
614
+ configPath: path.join(homeDir, ".codeium", "windsurf", "mcp_config.json"),
615
+ configKey: "mcpServers",
616
+ format: "json",
617
+ serverConfig: stdioConfig
618
+ }
619
+ ];
620
+ };
621
+ var ensureDirectory = (filePath) => {
622
+ const directory = path.dirname(filePath);
623
+ if (!fs.existsSync(directory)) {
624
+ fs.mkdirSync(directory, { recursive: true });
625
+ }
626
+ };
627
+ var indentJson = (json, baseIndent) => json.split("\n").map((line, index) => index === 0 ? line : baseIndent + line).join("\n");
628
+ var insertIntoJsonc = (filePath, content, configKey, serverName, serverConfig) => {
629
+ if (content.includes(`"${serverName}"`)) return;
630
+ const serverJson = indentJson(
631
+ JSON.stringify(serverConfig, null, 2),
632
+ " "
633
+ );
634
+ const escapedConfigKey = configKey.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
635
+ const keyPattern = new RegExp(`"${escapedConfigKey}"\\s*:\\s*\\{`);
636
+ const keyMatch = keyPattern.exec(content);
637
+ if (keyMatch) {
638
+ const insertPosition = keyMatch.index + keyMatch[0].length;
639
+ const entry = `
640
+ "${serverName}": ${serverJson},`;
641
+ fs.writeFileSync(
642
+ filePath,
643
+ content.slice(0, insertPosition) + entry + content.slice(insertPosition)
644
+ );
645
+ return;
646
+ }
647
+ const lastBrace = content.lastIndexOf("}");
648
+ if (lastBrace === -1) return;
649
+ const beforeBrace = content.slice(0, lastBrace).trimEnd();
650
+ const withoutComments = beforeBrace.replace(/\/\/.*$/, "").trimEnd();
651
+ const lastChar = withoutComments[withoutComments.length - 1];
652
+ const needsComma = lastChar !== void 0 && lastChar !== "{" && lastChar !== ",";
653
+ const section = `${needsComma ? "," : ""}
654
+ "${configKey}": {
655
+ "${serverName}": ${serverJson}
656
+ }`;
657
+ fs.writeFileSync(filePath, beforeBrace + section + "\n}\n");
658
+ };
659
+ var installJsonClient = (client) => {
660
+ ensureDirectory(client.configPath);
661
+ if (!fs.existsSync(client.configPath)) {
662
+ const config = {
663
+ [client.configKey]: { [SERVER_NAME]: client.serverConfig }
664
+ };
665
+ fs.writeFileSync(client.configPath, JSON.stringify(config, null, 2) + "\n");
666
+ return;
667
+ }
668
+ const content = fs.readFileSync(client.configPath, "utf8");
669
+ try {
670
+ const config = JSON.parse(content);
671
+ const servers = config[client.configKey] ?? {};
672
+ servers[SERVER_NAME] = client.serverConfig;
673
+ config[client.configKey] = servers;
674
+ fs.writeFileSync(client.configPath, JSON.stringify(config, null, 2) + "\n");
675
+ } catch {
676
+ insertIntoJsonc(
677
+ client.configPath,
678
+ content,
679
+ client.configKey,
680
+ SERVER_NAME,
681
+ client.serverConfig
682
+ );
683
+ }
684
+ };
685
+ var buildTomlSection = (configKey, serverConfig) => {
686
+ const lines = [`[${configKey}.${SERVER_NAME}]`];
687
+ for (const [key, value] of Object.entries(serverConfig)) {
688
+ if (typeof value === "string") {
689
+ lines.push(`${key} = "${value}"`);
690
+ } else if (Array.isArray(value)) {
691
+ const items = value.map((item) => `"${item}"`).join(", ");
692
+ lines.push(`${key} = [${items}]`);
693
+ }
694
+ }
695
+ return lines.join("\n");
696
+ };
697
+ var installTomlClient = (client) => {
698
+ ensureDirectory(client.configPath);
699
+ const sectionHeader = `[${client.configKey}.${SERVER_NAME}]`;
700
+ const newSection = buildTomlSection(client.configKey, client.serverConfig);
701
+ if (!fs.existsSync(client.configPath)) {
702
+ fs.writeFileSync(client.configPath, newSection + "\n");
703
+ return;
704
+ }
705
+ const content = fs.readFileSync(client.configPath, "utf8");
706
+ if (!content.includes(sectionHeader)) {
707
+ fs.writeFileSync(
708
+ client.configPath,
709
+ content.trimEnd() + "\n\n" + newSection + "\n"
710
+ );
711
+ return;
712
+ }
713
+ const lines = content.split("\n");
714
+ const resultLines = [];
715
+ let isInsideOurSection = false;
716
+ let didInsertReplacement = false;
717
+ for (const line of lines) {
718
+ if (line.trim() === sectionHeader) {
719
+ isInsideOurSection = true;
720
+ if (!didInsertReplacement) {
721
+ resultLines.push(newSection);
722
+ didInsertReplacement = true;
723
+ }
724
+ continue;
725
+ }
726
+ if (isInsideOurSection && line.startsWith("[")) {
727
+ isInsideOurSection = false;
728
+ }
729
+ if (!isInsideOurSection) {
730
+ resultLines.push(line);
731
+ }
732
+ }
733
+ fs.writeFileSync(client.configPath, resultLines.join("\n"));
734
+ };
735
+ var getMcpClientNames = () => getClients().map((client) => client.name);
736
+ var installMcpServers = (selectedClients) => {
737
+ const allClients = getClients();
738
+ const clients = selectedClients ? allClients.filter((client) => selectedClients.includes(client.name)) : allClients;
739
+ const results = [];
740
+ const installSpinner = spinner("Installing MCP server.").start();
741
+ for (const client of clients) {
742
+ try {
743
+ if (client.format === "toml") {
744
+ installTomlClient(client);
745
+ } else {
746
+ installJsonClient(client);
747
+ }
748
+ results.push({
749
+ client: client.name,
750
+ configPath: client.configPath,
751
+ success: true
752
+ });
753
+ } catch (error) {
754
+ const message = error instanceof Error ? error.message : String(error);
755
+ results.push({
756
+ client: client.name,
757
+ configPath: client.configPath,
758
+ success: false,
759
+ error: message
760
+ });
761
+ }
762
+ }
763
+ const successCount = results.filter((result) => result.success).length;
764
+ const failedCount = results.length - successCount;
765
+ if (failedCount > 0) {
766
+ installSpinner.warn(
767
+ `Installed to ${successCount}/${results.length} agents.`
768
+ );
769
+ } else {
770
+ installSpinner.succeed(`Installed to ${successCount} agents.`);
771
+ }
772
+ for (const result of results) {
773
+ if (result.success) {
774
+ logger.log(
775
+ ` ${highlighter.success("\u2713")} ${result.client} ${highlighter.dim("\u2192")} ${highlighter.dim(result.configPath)}`
776
+ );
777
+ } else {
778
+ logger.log(
779
+ ` ${highlighter.error("\u2717")} ${result.client} ${highlighter.dim("\u2192")} ${result.error}`
780
+ );
781
+ }
782
+ }
783
+ return results;
784
+ };
785
+ var promptConnectionMode = async () => {
786
+ const { connectionMode } = await prompts({
787
+ type: "select",
788
+ name: "connectionMode",
789
+ message: "How would you like to connect?",
790
+ choices: [
791
+ {
792
+ title: `MCP ${highlighter.dim("(recommended)")}`,
793
+ description: "Installs to all supported agents at once",
794
+ value: "mcp"
795
+ },
796
+ {
797
+ title: "Legacy",
798
+ description: "Install a per-project agent package",
799
+ value: "legacy"
800
+ }
801
+ ]
802
+ });
803
+ return connectionMode;
804
+ };
805
+ var promptMcpInstall = async () => {
806
+ const clientNames = getMcpClientNames();
807
+ const { selectedAgents } = await prompts({
808
+ type: "multiselect",
809
+ name: "selectedAgents",
810
+ message: "Select agents to install MCP server for:",
811
+ choices: clientNames.map((name) => ({
812
+ title: name,
813
+ value: name,
814
+ selected: true
815
+ }))
816
+ });
817
+ if (selectedAgents === void 0 || selectedAgents.length === 0) {
818
+ return false;
819
+ }
820
+ logger.break();
821
+ const results = installMcpServers(selectedAgents);
822
+ const hasSuccess = results.some((result) => result.success);
823
+ return hasSuccess;
824
+ };
825
+
528
826
  // src/utils/templates.ts
529
827
  var AGENTS = [
530
828
  "claude-code",
@@ -546,6 +844,13 @@ var AGENT_NAMES = {
546
844
  ami: "Ami",
547
845
  droid: "Droid"
548
846
  };
847
+ var getAgentDisplayName = (agent) => {
848
+ if (agent === "mcp") return "MCP";
849
+ if (agent in AGENT_NAMES) {
850
+ return AGENT_NAMES[agent];
851
+ }
852
+ return agent;
853
+ };
549
854
  var NEXT_APP_ROUTER_SCRIPT = `{process.env.NODE_ENV === "development" && (
550
855
  <Script
551
856
  src="//unpkg.com/react-grab/dist/index.global.js"
@@ -1299,6 +1604,14 @@ var previewPackageJsonTransform = (projectRoot, agent, installedAgents, packageM
1299
1604
  noChanges: true
1300
1605
  };
1301
1606
  }
1607
+ if (agent === "mcp") {
1608
+ return {
1609
+ success: true,
1610
+ filePath: "",
1611
+ message: "MCP does not use package.json dev script",
1612
+ noChanges: true
1613
+ };
1614
+ }
1302
1615
  const packageJsonPath = join(projectRoot, "package.json");
1303
1616
  if (!existsSync(packageJsonPath)) {
1304
1617
  return {
@@ -1860,9 +2173,9 @@ var previewCdnTransform = (projectRoot, framework, nextRouterType, targetCdnDoma
1860
2173
  };
1861
2174
 
1862
2175
  // src/commands/add.ts
1863
- var VERSION = "0.1.11";
2176
+ var VERSION = "0.1.13";
1864
2177
  var formatInstalledAgentNames = (agents) => agents.map((agent) => AGENT_NAMES[agent] || agent).join(", ");
1865
- var add = new Command().name("add").alias("install").description("add an agent integration").argument("[agent]", `agent to add (${AGENTS.join(", ")})`).option("-y, --yes", "skip confirmation prompts", false).option(
2178
+ var add = new Command().name("add").alias("install").description("connect React Grab to your agent").argument("[agent]", `agent to add (${AGENTS.join(", ")})`).option("-y, --yes", "skip confirmation prompts", false).option(
1866
2179
  "-c, --cwd <cwd>",
1867
2180
  "working directory (defaults to current directory)",
1868
2181
  process.cwd()
@@ -1889,9 +2202,10 @@ var add = new Command().name("add").alias("install").description("add an agent i
1889
2202
  const availableAgents = AGENTS.filter(
1890
2203
  (agent) => !projectInfo.installedAgents.includes(agent)
1891
2204
  );
1892
- if (availableAgents.length === 0) {
2205
+ if (availableAgents.length === 0 && isNonInteractive && !agentArg) {
1893
2206
  logger.break();
1894
- logger.success("All agent integrations are already installed.");
2207
+ logger.success("All legacy agents are already installed.");
2208
+ logger.log("Run without -y to add MCP.");
1895
2209
  logger.break();
1896
2210
  process.exit(0);
1897
2211
  }
@@ -1925,11 +2239,11 @@ var add = new Command().name("add").alias("install").description("add an agent i
1925
2239
  message: "How would you like to proceed?",
1926
2240
  choices: [
1927
2241
  {
1928
- title: `Replace with ${AGENT_NAMES[agentIntegration]}`,
2242
+ title: `Replace with ${getAgentDisplayName(agentIntegration)}`,
1929
2243
  value: "replace"
1930
2244
  },
1931
2245
  {
1932
- title: `Add ${AGENT_NAMES[agentIntegration]} alongside existing`,
2246
+ title: `Add ${getAgentDisplayName(agentIntegration)} alongside existing`,
1933
2247
  value: "add"
1934
2248
  },
1935
2249
  { title: "Cancel", value: "cancel" }
@@ -1953,48 +2267,72 @@ var add = new Command().name("add").alias("install").description("add an agent i
1953
2267
  logger.warn(`Currently installed: ${installedNames}`);
1954
2268
  logger.break();
1955
2269
  }
1956
- const { agent } = await prompts({
1957
- type: "select",
1958
- name: "agent",
1959
- message: `Which ${highlighter.info("coding agent")} would you like to connect?`,
1960
- choices: availableAgents.map((availableAgent) => ({
1961
- title: AGENT_NAMES[availableAgent],
1962
- value: availableAgent
1963
- }))
1964
- });
1965
- if (!agent) {
2270
+ const connectionMode = await promptConnectionMode();
2271
+ if (connectionMode === void 0) {
1966
2272
  logger.break();
1967
2273
  process.exit(1);
1968
2274
  }
1969
- agentIntegration = agent;
1970
- if (projectInfo.installedAgents.length > 0) {
1971
- const installedNames = formatInstalledAgentNames(
1972
- projectInfo.installedAgents
2275
+ if (connectionMode === "mcp") {
2276
+ const didInstall = await promptMcpInstall();
2277
+ if (!didInstall) {
2278
+ logger.break();
2279
+ process.exit(0);
2280
+ }
2281
+ logger.break();
2282
+ logger.log(
2283
+ `${highlighter.success("Success!")} MCP server has been configured.`
1973
2284
  );
1974
- const { action } = await prompts({
2285
+ logger.log("Restart your agents to activate.");
2286
+ logger.break();
2287
+ agentIntegration = "mcp";
2288
+ projectInfo.installedAgents = [...projectInfo.installedAgents, "mcp"];
2289
+ } else {
2290
+ const { agent } = await prompts({
1975
2291
  type: "select",
1976
- name: "action",
1977
- message: "How would you like to proceed?",
2292
+ name: "agent",
2293
+ message: `Which ${highlighter.info("agent")} would you like to connect?`,
1978
2294
  choices: [
1979
- {
1980
- title: `Replace ${installedNames} with ${AGENT_NAMES[agentIntegration]}`,
1981
- value: "replace"
1982
- },
1983
- {
1984
- title: `Add ${AGENT_NAMES[agentIntegration]} alongside existing`,
1985
- value: "add"
1986
- },
1987
- { title: "Cancel", value: "cancel" }
2295
+ ...availableAgents.map((availableAgent) => ({
2296
+ title: AGENT_NAMES[availableAgent],
2297
+ value: availableAgent
2298
+ })),
2299
+ { title: "Skip", value: "skip" }
1988
2300
  ]
1989
2301
  });
1990
- if (!action || action === "cancel") {
1991
- logger.break();
1992
- logger.log("Changes cancelled.");
2302
+ if (!agent || agent === "skip") {
1993
2303
  logger.break();
1994
2304
  process.exit(0);
1995
2305
  }
1996
- if (action === "replace") {
1997
- agentsToRemove = [...projectInfo.installedAgents];
2306
+ agentIntegration = agent;
2307
+ if (projectInfo.installedAgents.length > 0) {
2308
+ const installedNames = formatInstalledAgentNames(
2309
+ projectInfo.installedAgents
2310
+ );
2311
+ const { action } = await prompts({
2312
+ type: "select",
2313
+ name: "action",
2314
+ message: "How would you like to proceed?",
2315
+ choices: [
2316
+ {
2317
+ title: `Replace ${installedNames} with ${getAgentDisplayName(agentIntegration)}`,
2318
+ value: "replace"
2319
+ },
2320
+ {
2321
+ title: `Add ${getAgentDisplayName(agentIntegration)} alongside existing`,
2322
+ value: "add"
2323
+ },
2324
+ { title: "Cancel", value: "cancel" }
2325
+ ]
2326
+ });
2327
+ if (!action || action === "cancel") {
2328
+ logger.break();
2329
+ logger.log("Changes cancelled.");
2330
+ logger.break();
2331
+ process.exit(0);
2332
+ }
2333
+ if (action === "replace") {
2334
+ agentsToRemove = [...projectInfo.installedAgents];
2335
+ }
1998
2336
  }
1999
2337
  }
2000
2338
  } else {
@@ -2071,7 +2409,7 @@ var add = new Command().name("add").alias("install").description("add an agent i
2071
2409
  );
2072
2410
  }
2073
2411
  const addingSpinner = spinner(
2074
- `Adding ${AGENT_NAMES[agentIntegration]}.`
2412
+ `Adding ${getAgentDisplayName(agentIntegration)}.`
2075
2413
  ).start();
2076
2414
  addingSpinner.succeed();
2077
2415
  const result = previewTransform(
@@ -2177,7 +2515,7 @@ var add = new Command().name("add").alias("install").description("add an agent i
2177
2515
  }
2178
2516
  logger.break();
2179
2517
  logger.log(
2180
- `${highlighter.success("Success!")} ${AGENT_NAMES[agentIntegration]} has been added.`
2518
+ `${highlighter.success("Success!")} ${getAgentDisplayName(agentIntegration)} has been added.`
2181
2519
  );
2182
2520
  if (packageJsonResult.warning) {
2183
2521
  logger.warn(packageJsonResult.warning);
@@ -2196,7 +2534,7 @@ var MAX_KEY_HOLD_DURATION_MS = 2e3;
2196
2534
  var MAX_CONTEXT_LINES = 50;
2197
2535
 
2198
2536
  // src/commands/configure.ts
2199
- var VERSION2 = "0.1.11";
2537
+ var VERSION2 = "0.1.13";
2200
2538
  var isMac = process.platform === "darwin";
2201
2539
  var META_LABEL = isMac ? "Cmd" : "Win";
2202
2540
  var ALT_LABEL = isMac ? "Option" : "Alt";
@@ -2699,7 +3037,7 @@ var configure = new Command().name("configure").alias("config").description("con
2699
3037
  });
2700
3038
 
2701
3039
  // src/utils/cli-helpers.ts
2702
- var formatInstalledAgentNames2 = (agents) => agents.map((agent) => AGENT_NAMES[agent] ?? agent).join(", ");
3040
+ var formatInstalledAgentNames2 = (agents) => agents.map(getAgentDisplayName).join(", ");
2703
3041
  var applyTransformWithFeedback = (result, message) => {
2704
3042
  const writeSpinner = spinner(
2705
3043
  message ?? `Applying changes to ${result.filePath}.`
@@ -2752,7 +3090,7 @@ var uninstallPackagesWithFeedback = (packages, packageManager, projectRoot) => {
2752
3090
  };
2753
3091
 
2754
3092
  // src/commands/init.ts
2755
- var VERSION3 = "0.1.11";
3093
+ var VERSION3 = "0.1.13";
2756
3094
  var REPORT_URL = "https://react-grab.com/api/report-cli";
2757
3095
  var DOCS_URL = "https://github.com/aidenybai/react-grab";
2758
3096
  var reportToCli = (type, config, error) => {
@@ -2788,12 +3126,7 @@ var UNSUPPORTED_FRAMEWORK_NAMES = {
2788
3126
  sveltekit: "SvelteKit",
2789
3127
  gatsby: "Gatsby"
2790
3128
  };
2791
- var getAgentName = (agent) => {
2792
- if (agent in AGENT_NAMES) {
2793
- return AGENT_NAMES[agent];
2794
- }
2795
- return agent;
2796
- };
3129
+ var getAgentName = getAgentDisplayName;
2797
3130
  var formatActivationKeyDisplay2 = (activationKey) => {
2798
3131
  if (!activationKey) return "Default (Option/Alt)";
2799
3132
  return activationKey.split("+").map((part) => {
@@ -2808,7 +3141,7 @@ var formatActivationKeyDisplay2 = (activationKey) => {
2808
3141
  };
2809
3142
  var init = new 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(
2810
3143
  "-a, --agent <agent>",
2811
- "agent integration (claude-code, cursor, opencode, codex, gemini, amp, droid)"
3144
+ "connect to your agent (claude-code, cursor, opencode, codex, gemini, amp, mcp)"
2812
3145
  ).option(
2813
3146
  "-k, --key <key>",
2814
3147
  "activation key (e.g., Meta+K, Ctrl+Shift+G, Space)"
@@ -3027,23 +3360,108 @@ var init = new Command().name("init").description("initialize React Grab in your
3027
3360
  const availableAgents = AGENTS.filter(
3028
3361
  (agent) => !projectInfo.installedAgents.includes(agent)
3029
3362
  );
3030
- if (availableAgents.length > 0) {
3363
+ logger.break();
3364
+ const { wantAddAgent } = await prompts({
3365
+ type: "confirm",
3366
+ name: "wantAddAgent",
3367
+ message: `Would you like to ${highlighter.info("connect it to your agent")}?`,
3368
+ initial: false
3369
+ });
3370
+ if (wantAddAgent === void 0) {
3031
3371
  logger.break();
3032
- const { wantAddAgent } = await prompts({
3033
- type: "confirm",
3034
- name: "wantAddAgent",
3035
- message: `Would you like to connect React Grab to a ${highlighter.info("coding agent")}? ${highlighter.dim("(optional)")}`,
3036
- initial: false
3037
- });
3038
- if (wantAddAgent === void 0) {
3372
+ process.exit(1);
3373
+ }
3374
+ if (wantAddAgent) {
3375
+ const connectionMode = await promptConnectionMode();
3376
+ if (connectionMode === void 0) {
3039
3377
  logger.break();
3040
3378
  process.exit(1);
3041
3379
  }
3042
- if (wantAddAgent) {
3380
+ let agentIntegration2;
3381
+ if (connectionMode === "mcp") {
3382
+ const didInstall = await promptMcpInstall();
3383
+ if (!didInstall) {
3384
+ logger.break();
3385
+ process.exit(0);
3386
+ }
3387
+ logger.break();
3388
+ logger.success("MCP server has been configured.");
3389
+ logger.log("Restart your agents to activate.");
3390
+ agentIntegration2 = "mcp";
3391
+ projectInfo.installedAgents = ["mcp"];
3392
+ const result2 = previewTransform(
3393
+ projectInfo.projectRoot,
3394
+ projectInfo.framework,
3395
+ projectInfo.nextRouterType,
3396
+ agentIntegration2,
3397
+ true
3398
+ );
3399
+ const packageJsonResult2 = previewPackageJsonTransform(
3400
+ projectInfo.projectRoot,
3401
+ agentIntegration2,
3402
+ projectInfo.installedAgents,
3403
+ projectInfo.packageManager
3404
+ );
3405
+ if (!result2.success) {
3406
+ logger.break();
3407
+ logger.error(result2.message);
3408
+ logger.break();
3409
+ process.exit(1);
3410
+ }
3411
+ const hasLayoutChanges2 = !result2.noChanges && result2.originalContent && result2.newContent;
3412
+ const hasPackageJsonChanges2 = packageJsonResult2.success && !packageJsonResult2.noChanges && packageJsonResult2.originalContent && packageJsonResult2.newContent;
3413
+ if (hasLayoutChanges2 || hasPackageJsonChanges2) {
3414
+ logger.break();
3415
+ if (hasLayoutChanges2) {
3416
+ printDiff(
3417
+ result2.filePath,
3418
+ result2.originalContent,
3419
+ result2.newContent
3420
+ );
3421
+ }
3422
+ if (hasPackageJsonChanges2) {
3423
+ if (hasLayoutChanges2) {
3424
+ logger.break();
3425
+ }
3426
+ printDiff(
3427
+ packageJsonResult2.filePath,
3428
+ packageJsonResult2.originalContent,
3429
+ packageJsonResult2.newContent
3430
+ );
3431
+ }
3432
+ logger.break();
3433
+ const { proceed } = await prompts({
3434
+ type: "confirm",
3435
+ name: "proceed",
3436
+ message: "Apply these changes?",
3437
+ initial: true
3438
+ });
3439
+ if (!proceed) {
3440
+ logger.break();
3441
+ logger.log("Agent addition cancelled.");
3442
+ } else {
3443
+ installPackagesWithFeedback(
3444
+ getPackagesToInstall(agentIntegration2, false),
3445
+ projectInfo.packageManager,
3446
+ projectInfo.projectRoot
3447
+ );
3448
+ if (hasLayoutChanges2) {
3449
+ applyTransformWithFeedback(result2);
3450
+ }
3451
+ if (hasPackageJsonChanges2) {
3452
+ applyPackageJsonWithFeedback(packageJsonResult2);
3453
+ }
3454
+ logger.break();
3455
+ logger.success(
3456
+ `${getAgentName(agentIntegration2)} has been added.`
3457
+ );
3458
+ }
3459
+ }
3460
+ } else {
3043
3461
  const { agent } = await prompts({
3044
3462
  type: "select",
3045
3463
  name: "agent",
3046
- message: `Which ${highlighter.info("coding agent")} would you like to connect?`,
3464
+ message: `Which ${highlighter.info("agent")} would you like to connect?`,
3047
3465
  choices: [
3048
3466
  ...availableAgents.map((innerAgent) => ({
3049
3467
  title: getAgentName(innerAgent),
@@ -3056,7 +3474,7 @@ var init = new Command().name("init").description("initialize React Grab in your
3056
3474
  logger.break();
3057
3475
  process.exit(0);
3058
3476
  }
3059
- const agentIntegration2 = agent;
3477
+ agentIntegration2 = agent;
3060
3478
  let agentsToRemove2 = [];
3061
3479
  if (projectInfo.installedAgents.length > 0) {
3062
3480
  const installedNames = formatInstalledAgentNames2(
@@ -3354,7 +3772,7 @@ var init = new Command().name("init").description("initialize React Grab in your
3354
3772
  const { wantAddAgent } = await prompts({
3355
3773
  type: "confirm",
3356
3774
  name: "wantAddAgent",
3357
- message: `Would you like to connect React Grab to a ${highlighter.info("coding agent")}? ${highlighter.dim("(optional)")}`,
3775
+ message: `Would you like to ${highlighter.info("connect it to your agent")}?`,
3358
3776
  initial: false
3359
3777
  });
3360
3778
  if (wantAddAgent === void 0) {
@@ -3362,24 +3780,42 @@ var init = new Command().name("init").description("initialize React Grab in your
3362
3780
  process.exit(1);
3363
3781
  }
3364
3782
  if (wantAddAgent) {
3365
- const { agent } = await prompts({
3366
- type: "select",
3367
- name: "agent",
3368
- message: `Which ${highlighter.info("coding agent")} would you like to connect?`,
3369
- choices: [
3370
- ...AGENTS.map((innerAgent) => ({
3371
- title: getAgentName(innerAgent),
3372
- value: innerAgent
3373
- })),
3374
- { title: "Skip", value: "skip" }
3375
- ]
3376
- });
3377
- if (agent === void 0) {
3783
+ const connectionMode = await promptConnectionMode();
3784
+ if (connectionMode === void 0) {
3378
3785
  logger.break();
3379
3786
  process.exit(1);
3380
3787
  }
3381
- if (agent !== "skip") {
3382
- agentIntegration = agent;
3788
+ if (connectionMode === "mcp") {
3789
+ const didInstall = await promptMcpInstall();
3790
+ if (!didInstall) {
3791
+ logger.break();
3792
+ process.exit(0);
3793
+ }
3794
+ logger.break();
3795
+ logger.success("MCP server has been configured.");
3796
+ logger.log("Continuing with React Grab installation...");
3797
+ logger.break();
3798
+ agentIntegration = "mcp";
3799
+ } else {
3800
+ const { agent } = await prompts({
3801
+ type: "select",
3802
+ name: "agent",
3803
+ message: `Which ${highlighter.info("agent")} would you like to connect?`,
3804
+ choices: [
3805
+ ...AGENTS.map((innerAgent) => ({
3806
+ title: getAgentName(innerAgent),
3807
+ value: innerAgent
3808
+ })),
3809
+ { title: "Skip", value: "skip" }
3810
+ ]
3811
+ });
3812
+ if (agent === void 0) {
3813
+ logger.break();
3814
+ process.exit(1);
3815
+ }
3816
+ if (agent !== "skip") {
3817
+ agentIntegration = agent;
3818
+ }
3383
3819
  }
3384
3820
  }
3385
3821
  }
@@ -3488,10 +3924,10 @@ var init = new Command().name("init").description("initialize React Grab in your
3488
3924
  reportToCli("error", void 0, error);
3489
3925
  }
3490
3926
  });
3491
- var VERSION4 = "0.1.11";
3492
- var remove = new Command().name("remove").description("remove an agent integration").argument(
3927
+ var VERSION4 = "0.1.13";
3928
+ var remove = new Command().name("remove").description("disconnect React Grab from your agent").argument(
3493
3929
  "[agent]",
3494
- "agent to remove (claude-code, cursor, opencode, codex, gemini, amp, ami)"
3930
+ "agent to remove (claude-code, cursor, opencode, codex, gemini, amp, ami, mcp)"
3495
3931
  ).option("-y, --yes", "skip confirmation prompts", false).option(
3496
3932
  "-c, --cwd <cwd>",
3497
3933
  "working directory (defaults to current directory)",
@@ -3518,7 +3954,7 @@ var remove = new Command().name("remove").description("remove an agent integrati
3518
3954
  if (projectInfo.installedAgents.length === 0) {
3519
3955
  preflightSpinner.succeed();
3520
3956
  logger.break();
3521
- logger.warn("No agent integrations are installed.");
3957
+ logger.warn("No agent connections are installed.");
3522
3958
  logger.break();
3523
3959
  process.exit(0);
3524
3960
  }
@@ -3529,7 +3965,7 @@ var remove = new Command().name("remove").description("remove an agent integrati
3529
3965
  logger.break();
3530
3966
  logger.error(`Agent ${highlighter.info(agentArg)} is not installed.`);
3531
3967
  logger.log(
3532
- `Installed agents: ${projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES[innerAgent] || innerAgent).join(", ")}`
3968
+ `Installed agents: ${projectInfo.installedAgents.map(getAgentDisplayName).join(", ")}`
3533
3969
  );
3534
3970
  logger.break();
3535
3971
  process.exit(1);
@@ -3540,9 +3976,9 @@ var remove = new Command().name("remove").description("remove an agent integrati
3540
3976
  const { agent } = await prompts({
3541
3977
  type: "select",
3542
3978
  name: "agent",
3543
- message: `Which ${highlighter.info("agent integration")} would you like to remove?`,
3979
+ message: `Which ${highlighter.info("agent")} would you like to disconnect?`,
3544
3980
  choices: projectInfo.installedAgents.map((innerAgent) => ({
3545
- title: AGENT_NAMES[innerAgent] || innerAgent,
3981
+ title: getAgentDisplayName(innerAgent),
3546
3982
  value: innerAgent
3547
3983
  }))
3548
3984
  });
@@ -3561,7 +3997,7 @@ var remove = new Command().name("remove").description("remove an agent integrati
3561
3997
  process.exit(1);
3562
3998
  }
3563
3999
  const removingSpinner = spinner(
3564
- `Preparing to remove ${AGENT_NAMES[agentToRemove] || agentToRemove}.`
4000
+ `Preparing to remove ${getAgentDisplayName(agentToRemove)}.`
3565
4001
  ).start();
3566
4002
  removingSpinner.succeed();
3567
4003
  const result = previewAgentRemoval(
@@ -3658,7 +4094,7 @@ var remove = new Command().name("remove").description("remove an agent integrati
3658
4094
  }
3659
4095
  logger.break();
3660
4096
  logger.log(
3661
- `${highlighter.success("Success!")} ${AGENT_NAMES[agentToRemove] || agentToRemove} has been removed.`
4097
+ `${highlighter.success("Success!")} ${getAgentDisplayName(agentToRemove)} has been removed.`
3662
4098
  );
3663
4099
  logger.break();
3664
4100
  } catch (error) {
@@ -3667,7 +4103,7 @@ var remove = new Command().name("remove").description("remove an agent integrati
3667
4103
  });
3668
4104
 
3669
4105
  // src/cli.ts
3670
- var VERSION5 = "0.1.11";
4106
+ var VERSION5 = "0.1.13";
3671
4107
  var VERSION_API_URL = "https://www.react-grab.com/api/version";
3672
4108
  process.on("SIGINT", () => process.exit(0));
3673
4109
  process.on("SIGTERM", () => process.exit(0));