@react-grab/cli 0.1.27 → 0.1.29

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 +129 -185
  2. package/dist/cli.js +130 -186
  3. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -345,10 +345,29 @@ var scanDirectoryForProjects = (rootDirectory, ignorer, maxDepth, currentDepth =
345
345
  var MAX_SCAN_DEPTH = 2;
346
346
  var findReactProjects = (projectRoot) => {
347
347
  if (detectMonorepo(projectRoot)) {
348
- return findWorkspaceProjects(projectRoot);
348
+ const workspaceProjects = findWorkspaceProjects(projectRoot);
349
+ if (workspaceProjects.length > 0) {
350
+ return workspaceProjects;
351
+ }
349
352
  }
350
353
  const ignorer = loadGitignore(projectRoot);
351
- return scanDirectoryForProjects(projectRoot, ignorer, MAX_SCAN_DEPTH);
354
+ const scannedProjects = scanDirectoryForProjects(
355
+ projectRoot,
356
+ ignorer,
357
+ MAX_SCAN_DEPTH
358
+ );
359
+ if (scannedProjects.length > 0) {
360
+ return scannedProjects;
361
+ }
362
+ let currentDirectory = path.dirname(projectRoot);
363
+ while (currentDirectory !== path.dirname(currentDirectory)) {
364
+ const parentProject = buildReactProject(currentDirectory);
365
+ if (parentProject) {
366
+ return [parentProject];
367
+ }
368
+ currentDirectory = path.dirname(currentDirectory);
369
+ }
370
+ return [];
352
371
  };
353
372
  var hasReactGrabInFile = (filePath) => {
354
373
  if (!fs.existsSync(filePath)) return false;
@@ -414,7 +433,6 @@ var AGENT_PACKAGES = [
414
433
  "@react-grab/codex",
415
434
  "@react-grab/gemini",
416
435
  "@react-grab/amp",
417
- "@react-grab/ami",
418
436
  "@react-grab/droid",
419
437
  "@react-grab/copilot",
420
438
  "@react-grab/mcp"
@@ -617,7 +635,8 @@ var installPackages = (packages, packageManager, projectRoot, isDev = true) => {
617
635
  `);
618
636
  child_process.execSync(fullCommand, {
619
637
  cwd: projectRoot,
620
- stdio: "inherit"
638
+ stdio: "inherit",
639
+ env: { ...process.env, REACT_GRAB_INIT: "1" }
621
640
  });
622
641
  };
623
642
  var getPackagesToInstall = (agent, includeReactGrab = true) => {
@@ -890,7 +909,6 @@ var AGENTS = [
890
909
  "codex",
891
910
  "gemini",
892
911
  "amp",
893
- "ami",
894
912
  "droid",
895
913
  "copilot"
896
914
  ];
@@ -901,7 +919,6 @@ var AGENT_NAMES = {
901
919
  codex: "Codex",
902
920
  gemini: "Gemini",
903
921
  amp: "Amp",
904
- ami: "Ami",
905
922
  droid: "Droid",
906
923
  copilot: "Copilot"
907
924
  };
@@ -958,19 +975,15 @@ var NEXT_PAGES_ROUTER_SCRIPT_WITH_AGENT = (agent) => {
958
975
  />
959
976
  )}`;
960
977
  };
961
- var VITE_SCRIPT = `<script type="module">
962
- if (import.meta.env.DEV) {
963
- import("react-grab");
964
- }
965
- </script>`;
966
- var VITE_SCRIPT_WITH_AGENT = (agent) => {
967
- if (agent === "none") return VITE_SCRIPT;
968
- return `<script type="module">
969
- if (import.meta.env.DEV) {
970
- import("react-grab");
971
- import("@react-grab/${agent}/client");
972
- }
973
- </script>`;
978
+ var VITE_IMPORT = `if (import.meta.env.DEV) {
979
+ import("react-grab");
980
+ }`;
981
+ var VITE_IMPORT_WITH_AGENT = (agent) => {
982
+ if (agent === "none") return VITE_IMPORT;
983
+ return `if (import.meta.env.DEV) {
984
+ import("react-grab");
985
+ import("@react-grab/${agent}/client");
986
+ }`;
974
987
  };
975
988
  var WEBPACK_IMPORT = `if (process.env.NODE_ENV === "development") {
976
989
  import("react-grab");
@@ -1166,51 +1179,7 @@ var addAgentToExistingNextApp = (originalContent, agent, filePath) => {
1166
1179
  message: "Could not find React Grab script to add agent after"
1167
1180
  };
1168
1181
  };
1169
- var addAgentToExistingVite = (originalContent, agent, filePath) => {
1170
- if (agent === "none") {
1171
- return {
1172
- success: true,
1173
- filePath,
1174
- message: "React Grab is already configured",
1175
- noChanges: true
1176
- };
1177
- }
1178
- const agentPackage = `@react-grab/${agent}`;
1179
- if (originalContent.includes(agentPackage)) {
1180
- return {
1181
- success: true,
1182
- filePath,
1183
- message: `Agent ${agent} is already configured`,
1184
- noChanges: true
1185
- };
1186
- }
1187
- const agentImport = `import("${agentPackage}/client");`;
1188
- const reactGrabImportMatch = originalContent.match(
1189
- /import\s*\(\s*["']react-grab["']\s*\);?/
1190
- );
1191
- if (reactGrabImportMatch) {
1192
- const matchedText = reactGrabImportMatch[0];
1193
- const hasSemicolon = matchedText.endsWith(";");
1194
- const newContent = originalContent.replace(
1195
- matchedText,
1196
- `${hasSemicolon ? matchedText.slice(0, -1) : matchedText};
1197
- ${agentImport}`
1198
- );
1199
- return {
1200
- success: true,
1201
- filePath,
1202
- message: `Add ${agent} agent`,
1203
- originalContent,
1204
- newContent
1205
- };
1206
- }
1207
- return {
1208
- success: false,
1209
- filePath,
1210
- message: "Could not find React Grab import to add agent after"
1211
- };
1212
- };
1213
- var addAgentToExistingWebpack = (originalContent, agent, filePath) => {
1182
+ var addAgentToExistingImport = (originalContent, agent, filePath) => {
1214
1183
  if (agent === "none") {
1215
1184
  return {
1216
1185
  success: true,
@@ -1415,41 +1384,55 @@ ${SCRIPT_IMPORT}`
1415
1384
  newContent
1416
1385
  };
1417
1386
  };
1387
+ var checkExistingInstallation = (filePath, agent, reactGrabAlreadyConfigured) => {
1388
+ const content = fs.readFileSync(filePath, "utf-8");
1389
+ if (!hasReactGrabCode(content)) return null;
1390
+ if (reactGrabAlreadyConfigured) {
1391
+ return addAgentToExistingImport(content, agent, filePath);
1392
+ }
1393
+ return {
1394
+ success: true,
1395
+ filePath,
1396
+ message: "React Grab is already installed in this file",
1397
+ noChanges: true
1398
+ };
1399
+ };
1418
1400
  var transformVite = (projectRoot, agent, reactGrabAlreadyConfigured, force = false) => {
1419
- const indexPath = findIndexHtml(projectRoot);
1420
- if (!indexPath) {
1401
+ const entryPath = findEntryFile(projectRoot);
1402
+ if (!force) {
1403
+ const indexPath = findIndexHtml(projectRoot);
1404
+ if (indexPath) {
1405
+ const existingResult = checkExistingInstallation(
1406
+ indexPath,
1407
+ agent,
1408
+ reactGrabAlreadyConfigured
1409
+ );
1410
+ if (existingResult) return existingResult;
1411
+ }
1412
+ }
1413
+ if (!entryPath) {
1421
1414
  return {
1422
1415
  success: false,
1423
1416
  filePath: "",
1424
- message: "Could not find index.html"
1425
- };
1426
- }
1427
- const originalContent = fs.readFileSync(indexPath, "utf-8");
1428
- let newContent = originalContent;
1429
- const hasReactGrabInFile2 = hasReactGrabCode(originalContent);
1430
- if (!force && hasReactGrabInFile2 && reactGrabAlreadyConfigured) {
1431
- return addAgentToExistingVite(originalContent, agent, indexPath);
1432
- }
1433
- if (!force && hasReactGrabInFile2) {
1434
- return {
1435
- success: true,
1436
- filePath: indexPath,
1437
- message: "React Grab is already installed in this file",
1438
- noChanges: true
1417
+ message: "Could not find entry file (src/index.tsx, src/main.tsx, etc.)"
1439
1418
  };
1440
1419
  }
1441
- const scriptBlock = VITE_SCRIPT_WITH_AGENT(agent);
1442
- const headMatch = newContent.match(/<head[^>]*>/i);
1443
- if (headMatch) {
1444
- newContent = newContent.replace(
1445
- headMatch[0],
1446
- `${headMatch[0]}
1447
- ${scriptBlock}`
1420
+ if (!force) {
1421
+ const existingResult = checkExistingInstallation(
1422
+ entryPath,
1423
+ agent,
1424
+ reactGrabAlreadyConfigured
1448
1425
  );
1426
+ if (existingResult) return existingResult;
1449
1427
  }
1428
+ const originalContent = fs.readFileSync(entryPath, "utf-8");
1429
+ const importBlock = VITE_IMPORT_WITH_AGENT(agent);
1430
+ const newContent = `${importBlock}
1431
+
1432
+ ${originalContent}`;
1450
1433
  return {
1451
1434
  success: true,
1452
- filePath: indexPath,
1435
+ filePath: entryPath,
1453
1436
  message: "Add React Grab" + (agent !== "none" ? ` with ${agent} agent` : ""),
1454
1437
  originalContent,
1455
1438
  newContent
@@ -1464,19 +1447,15 @@ var transformWebpack = (projectRoot, agent, reactGrabAlreadyConfigured, force =
1464
1447
  message: "Could not find entry file (src/index.tsx, src/main.tsx, etc.)"
1465
1448
  };
1466
1449
  }
1467
- const originalContent = fs.readFileSync(entryPath, "utf-8");
1468
- const hasReactGrabInFile2 = hasReactGrabCode(originalContent);
1469
- if (!force && hasReactGrabInFile2 && reactGrabAlreadyConfigured) {
1470
- return addAgentToExistingWebpack(originalContent, agent, entryPath);
1471
- }
1472
- if (!force && hasReactGrabInFile2) {
1473
- return {
1474
- success: true,
1475
- filePath: entryPath,
1476
- message: "React Grab is already installed in this file",
1477
- noChanges: true
1478
- };
1450
+ if (!force) {
1451
+ const existingResult = checkExistingInstallation(
1452
+ entryPath,
1453
+ agent,
1454
+ reactGrabAlreadyConfigured
1455
+ );
1456
+ if (existingResult) return existingResult;
1479
1457
  }
1458
+ const originalContent = fs.readFileSync(entryPath, "utf-8");
1480
1459
  const importBlock = WEBPACK_IMPORT_WITH_AGENT(agent);
1481
1460
  const newContent = `${importBlock}
1482
1461
 
@@ -1563,40 +1542,41 @@ ${newContent}`;
1563
1542
  };
1564
1543
  };
1565
1544
  var previewTransform = (projectRoot, framework, nextRouterType, agent, reactGrabAlreadyConfigured = false, force = false) => {
1545
+ const resolvedAgent = agent === "mcp" ? "none" : agent;
1566
1546
  switch (framework) {
1567
1547
  case "next":
1568
1548
  if (nextRouterType === "app") {
1569
1549
  return transformNextAppRouter(
1570
1550
  projectRoot,
1571
- agent,
1551
+ resolvedAgent,
1572
1552
  reactGrabAlreadyConfigured,
1573
1553
  force
1574
1554
  );
1575
1555
  }
1576
1556
  return transformNextPagesRouter(
1577
1557
  projectRoot,
1578
- agent,
1558
+ resolvedAgent,
1579
1559
  reactGrabAlreadyConfigured,
1580
1560
  force
1581
1561
  );
1582
1562
  case "vite":
1583
1563
  return transformVite(
1584
1564
  projectRoot,
1585
- agent,
1565
+ resolvedAgent,
1586
1566
  reactGrabAlreadyConfigured,
1587
1567
  force
1588
1568
  );
1589
1569
  case "tanstack":
1590
1570
  return transformTanStack(
1591
1571
  projectRoot,
1592
- agent,
1572
+ resolvedAgent,
1593
1573
  reactGrabAlreadyConfigured,
1594
1574
  force
1595
1575
  );
1596
1576
  case "webpack":
1597
1577
  return transformWebpack(
1598
1578
  projectRoot,
1599
- agent,
1579
+ resolvedAgent,
1600
1580
  reactGrabAlreadyConfigured,
1601
1581
  force
1602
1582
  );
@@ -1841,8 +1821,17 @@ var findReactGrabFile = (projectRoot, framework, nextRouterType) => {
1841
1821
  return findLayoutFile(projectRoot);
1842
1822
  }
1843
1823
  return findDocumentFile(projectRoot);
1844
- case "vite":
1845
- return findIndexHtml(projectRoot);
1824
+ case "vite": {
1825
+ const entryFile = findEntryFile(projectRoot);
1826
+ if (entryFile && hasReactGrabCode(fs.readFileSync(entryFile, "utf-8"))) {
1827
+ return entryFile;
1828
+ }
1829
+ const indexHtml = findIndexHtml(projectRoot);
1830
+ if (indexHtml && hasReactGrabCode(fs.readFileSync(indexHtml, "utf-8"))) {
1831
+ return indexHtml;
1832
+ }
1833
+ return entryFile;
1834
+ }
1846
1835
  case "tanstack":
1847
1836
  return findTanStackRootFile(projectRoot);
1848
1837
  case "webpack":
@@ -2253,7 +2242,7 @@ var previewCdnTransform = (projectRoot, framework, nextRouterType, targetCdnDoma
2253
2242
  };
2254
2243
 
2255
2244
  // src/commands/add.ts
2256
- var VERSION = "0.1.27";
2245
+ var VERSION = "0.1.29";
2257
2246
  var formatInstalledAgentNames = (agents) => agents.map((agent) => AGENT_NAMES[agent] || agent).join(", ");
2258
2247
  var add = new commander.Command().name("add").alias("install").description("connect React Grab to your agent").argument("[agent]", `agent to connect (${AGENTS.join(", ")}, mcp)`).option("-y, --yes", "skip confirmation prompts", false).option(
2259
2248
  "-c, --cwd <cwd>",
@@ -2291,11 +2280,36 @@ var add = new commander.Command().name("add").alias("install").description("conn
2291
2280
  }
2292
2281
  let agentIntegration;
2293
2282
  let agentsToRemove = [];
2294
- if (agentArg) {
2283
+ if (agentArg === "mcp") {
2284
+ if (isNonInteractive) {
2285
+ const results = installMcpServers();
2286
+ const hasSuccess = results.some((result2) => result2.success);
2287
+ if (!hasSuccess) {
2288
+ logger.break();
2289
+ logger.error("Failed to install MCP server.");
2290
+ logger.break();
2291
+ process.exit(1);
2292
+ }
2293
+ } else {
2294
+ const didInstall = await promptMcpInstall();
2295
+ if (!didInstall) {
2296
+ logger.break();
2297
+ process.exit(0);
2298
+ }
2299
+ }
2300
+ logger.break();
2301
+ logger.log(
2302
+ `${highlighter.success("Success!")} MCP server has been configured.`
2303
+ );
2304
+ logger.log("Restart your agents to activate.");
2305
+ logger.break();
2306
+ agentIntegration = "mcp";
2307
+ projectInfo.installedAgents = [...projectInfo.installedAgents, "mcp"];
2308
+ } else if (agentArg) {
2295
2309
  if (!AGENTS.includes(agentArg)) {
2296
2310
  logger.break();
2297
2311
  logger.error(`Invalid agent: ${agentArg}`);
2298
- logger.error(`Available agents: ${AGENTS.join(", ")}`);
2312
+ logger.error(`Available agents: ${AGENTS.join(", ")}, mcp`);
2299
2313
  logger.break();
2300
2314
  process.exit(1);
2301
2315
  }
@@ -2614,7 +2628,7 @@ var MAX_KEY_HOLD_DURATION_MS = 2e3;
2614
2628
  var MAX_CONTEXT_LINES = 50;
2615
2629
 
2616
2630
  // src/commands/configure.ts
2617
- var VERSION2 = "0.1.27";
2631
+ var VERSION2 = "0.1.29";
2618
2632
  var isMac = process.platform === "darwin";
2619
2633
  var META_LABEL = isMac ? "Cmd" : "Win";
2620
2634
  var ALT_LABEL = isMac ? "Option" : "Alt";
@@ -3170,7 +3184,7 @@ var uninstallPackagesWithFeedback = (packages, packageManager, projectRoot) => {
3170
3184
  };
3171
3185
 
3172
3186
  // src/commands/init.ts
3173
- var VERSION3 = "0.1.27";
3187
+ var VERSION3 = "0.1.29";
3174
3188
  var REPORT_URL = "https://react-grab.com/api/report-cli";
3175
3189
  var DOCS_URL = "https://github.com/aidenybai/react-grab";
3176
3190
  var reportToCli = (type, config, error) => {
@@ -3501,76 +3515,6 @@ var init = new commander.Command().name("init").description("initialize React Gr
3501
3515
  logger.break();
3502
3516
  logger.success("MCP server has been configured.");
3503
3517
  logger.log("Restart your agents to activate.");
3504
- agentIntegration2 = "mcp";
3505
- projectInfo.installedAgents = ["mcp"];
3506
- const result2 = previewTransform(
3507
- projectInfo.projectRoot,
3508
- projectInfo.framework,
3509
- projectInfo.nextRouterType,
3510
- agentIntegration2,
3511
- true
3512
- );
3513
- const packageJsonResult2 = previewPackageJsonTransform(
3514
- projectInfo.projectRoot,
3515
- agentIntegration2,
3516
- projectInfo.installedAgents,
3517
- projectInfo.packageManager
3518
- );
3519
- if (!result2.success) {
3520
- logger.break();
3521
- logger.error(result2.message);
3522
- logger.break();
3523
- process.exit(1);
3524
- }
3525
- const hasLayoutChanges2 = !result2.noChanges && result2.originalContent && result2.newContent;
3526
- const hasPackageJsonChanges2 = packageJsonResult2.success && !packageJsonResult2.noChanges && packageJsonResult2.originalContent && packageJsonResult2.newContent;
3527
- if (hasLayoutChanges2 || hasPackageJsonChanges2) {
3528
- logger.break();
3529
- if (hasLayoutChanges2) {
3530
- printDiff(
3531
- result2.filePath,
3532
- result2.originalContent,
3533
- result2.newContent
3534
- );
3535
- }
3536
- if (hasPackageJsonChanges2) {
3537
- if (hasLayoutChanges2) {
3538
- logger.break();
3539
- }
3540
- printDiff(
3541
- packageJsonResult2.filePath,
3542
- packageJsonResult2.originalContent,
3543
- packageJsonResult2.newContent
3544
- );
3545
- }
3546
- logger.break();
3547
- const { proceed } = await prompts({
3548
- type: "confirm",
3549
- name: "proceed",
3550
- message: "Apply these changes?",
3551
- initial: true
3552
- });
3553
- if (!proceed) {
3554
- logger.break();
3555
- logger.log("Agent addition cancelled.");
3556
- } else {
3557
- installPackagesWithFeedback(
3558
- getPackagesToInstall(agentIntegration2, false),
3559
- projectInfo.packageManager,
3560
- projectInfo.projectRoot
3561
- );
3562
- if (hasLayoutChanges2) {
3563
- applyTransformWithFeedback(result2);
3564
- }
3565
- if (hasPackageJsonChanges2) {
3566
- applyPackageJsonWithFeedback(packageJsonResult2);
3567
- }
3568
- logger.break();
3569
- logger.success(
3570
- `${getAgentName(agentIntegration2)} has been added.`
3571
- );
3572
- }
3573
- }
3574
3518
  } else {
3575
3519
  const { agent } = await prompts({
3576
3520
  type: "select",
@@ -4029,7 +3973,7 @@ var init = new commander.Command().name("init").description("initialize React Gr
4029
3973
  reportToCli("error", void 0, error);
4030
3974
  }
4031
3975
  });
4032
- var VERSION4 = "0.1.27";
3976
+ var VERSION4 = "0.1.29";
4033
3977
  var remove = new commander.Command().name("remove").description("disconnect React Grab from your agent").argument("[agent]", `agent to disconnect (${AGENTS.join(", ")}, mcp)`).option("-y, --yes", "skip confirmation prompts", false).option(
4034
3978
  "-c, --cwd <cwd>",
4035
3979
  "working directory (defaults to current directory)",
@@ -4205,7 +4149,7 @@ var remove = new commander.Command().name("remove").description("disconnect Reac
4205
4149
  });
4206
4150
 
4207
4151
  // src/cli.ts
4208
- var VERSION5 = "0.1.27";
4152
+ var VERSION5 = "0.1.29";
4209
4153
  var VERSION_API_URL = "https://www.react-grab.com/api/version";
4210
4154
  process.on("SIGINT", () => process.exit(0));
4211
4155
  process.on("SIGTERM", () => process.exit(0));
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import pc from 'picocolors';
4
4
  import basePrompts from 'prompts';
5
5
  import { execSync } from 'child_process';
6
6
  import fs, { existsSync, readFileSync, writeFileSync, accessSync, constants, readdirSync } from 'fs';
7
- import path, { resolve, join, relative, basename } from 'path';
7
+ import path, { resolve, join, dirname, relative, basename } from 'path';
8
8
  import { detect } from '@antfu/ni';
9
9
  import ignore from 'ignore';
10
10
  import os from 'os';
@@ -312,10 +312,29 @@ var scanDirectoryForProjects = (rootDirectory, ignorer, maxDepth, currentDepth =
312
312
  var MAX_SCAN_DEPTH = 2;
313
313
  var findReactProjects = (projectRoot) => {
314
314
  if (detectMonorepo(projectRoot)) {
315
- return findWorkspaceProjects(projectRoot);
315
+ const workspaceProjects = findWorkspaceProjects(projectRoot);
316
+ if (workspaceProjects.length > 0) {
317
+ return workspaceProjects;
318
+ }
316
319
  }
317
320
  const ignorer = loadGitignore(projectRoot);
318
- return scanDirectoryForProjects(projectRoot, ignorer, MAX_SCAN_DEPTH);
321
+ const scannedProjects = scanDirectoryForProjects(
322
+ projectRoot,
323
+ ignorer,
324
+ MAX_SCAN_DEPTH
325
+ );
326
+ if (scannedProjects.length > 0) {
327
+ return scannedProjects;
328
+ }
329
+ let currentDirectory = dirname(projectRoot);
330
+ while (currentDirectory !== dirname(currentDirectory)) {
331
+ const parentProject = buildReactProject(currentDirectory);
332
+ if (parentProject) {
333
+ return [parentProject];
334
+ }
335
+ currentDirectory = dirname(currentDirectory);
336
+ }
337
+ return [];
319
338
  };
320
339
  var hasReactGrabInFile = (filePath) => {
321
340
  if (!existsSync(filePath)) return false;
@@ -381,7 +400,6 @@ var AGENT_PACKAGES = [
381
400
  "@react-grab/codex",
382
401
  "@react-grab/gemini",
383
402
  "@react-grab/amp",
384
- "@react-grab/ami",
385
403
  "@react-grab/droid",
386
404
  "@react-grab/copilot",
387
405
  "@react-grab/mcp"
@@ -584,7 +602,8 @@ var installPackages = (packages, packageManager, projectRoot, isDev = true) => {
584
602
  `);
585
603
  execSync(fullCommand, {
586
604
  cwd: projectRoot,
587
- stdio: "inherit"
605
+ stdio: "inherit",
606
+ env: { ...process.env, REACT_GRAB_INIT: "1" }
588
607
  });
589
608
  };
590
609
  var getPackagesToInstall = (agent, includeReactGrab = true) => {
@@ -857,7 +876,6 @@ var AGENTS = [
857
876
  "codex",
858
877
  "gemini",
859
878
  "amp",
860
- "ami",
861
879
  "droid",
862
880
  "copilot"
863
881
  ];
@@ -868,7 +886,6 @@ var AGENT_NAMES = {
868
886
  codex: "Codex",
869
887
  gemini: "Gemini",
870
888
  amp: "Amp",
871
- ami: "Ami",
872
889
  droid: "Droid",
873
890
  copilot: "Copilot"
874
891
  };
@@ -925,19 +942,15 @@ var NEXT_PAGES_ROUTER_SCRIPT_WITH_AGENT = (agent) => {
925
942
  />
926
943
  )}`;
927
944
  };
928
- var VITE_SCRIPT = `<script type="module">
929
- if (import.meta.env.DEV) {
930
- import("react-grab");
931
- }
932
- </script>`;
933
- var VITE_SCRIPT_WITH_AGENT = (agent) => {
934
- if (agent === "none") return VITE_SCRIPT;
935
- return `<script type="module">
936
- if (import.meta.env.DEV) {
937
- import("react-grab");
938
- import("@react-grab/${agent}/client");
939
- }
940
- </script>`;
945
+ var VITE_IMPORT = `if (import.meta.env.DEV) {
946
+ import("react-grab");
947
+ }`;
948
+ var VITE_IMPORT_WITH_AGENT = (agent) => {
949
+ if (agent === "none") return VITE_IMPORT;
950
+ return `if (import.meta.env.DEV) {
951
+ import("react-grab");
952
+ import("@react-grab/${agent}/client");
953
+ }`;
941
954
  };
942
955
  var WEBPACK_IMPORT = `if (process.env.NODE_ENV === "development") {
943
956
  import("react-grab");
@@ -1133,51 +1146,7 @@ var addAgentToExistingNextApp = (originalContent, agent, filePath) => {
1133
1146
  message: "Could not find React Grab script to add agent after"
1134
1147
  };
1135
1148
  };
1136
- var addAgentToExistingVite = (originalContent, agent, filePath) => {
1137
- if (agent === "none") {
1138
- return {
1139
- success: true,
1140
- filePath,
1141
- message: "React Grab is already configured",
1142
- noChanges: true
1143
- };
1144
- }
1145
- const agentPackage = `@react-grab/${agent}`;
1146
- if (originalContent.includes(agentPackage)) {
1147
- return {
1148
- success: true,
1149
- filePath,
1150
- message: `Agent ${agent} is already configured`,
1151
- noChanges: true
1152
- };
1153
- }
1154
- const agentImport = `import("${agentPackage}/client");`;
1155
- const reactGrabImportMatch = originalContent.match(
1156
- /import\s*\(\s*["']react-grab["']\s*\);?/
1157
- );
1158
- if (reactGrabImportMatch) {
1159
- const matchedText = reactGrabImportMatch[0];
1160
- const hasSemicolon = matchedText.endsWith(";");
1161
- const newContent = originalContent.replace(
1162
- matchedText,
1163
- `${hasSemicolon ? matchedText.slice(0, -1) : matchedText};
1164
- ${agentImport}`
1165
- );
1166
- return {
1167
- success: true,
1168
- filePath,
1169
- message: `Add ${agent} agent`,
1170
- originalContent,
1171
- newContent
1172
- };
1173
- }
1174
- return {
1175
- success: false,
1176
- filePath,
1177
- message: "Could not find React Grab import to add agent after"
1178
- };
1179
- };
1180
- var addAgentToExistingWebpack = (originalContent, agent, filePath) => {
1149
+ var addAgentToExistingImport = (originalContent, agent, filePath) => {
1181
1150
  if (agent === "none") {
1182
1151
  return {
1183
1152
  success: true,
@@ -1382,41 +1351,55 @@ ${SCRIPT_IMPORT}`
1382
1351
  newContent
1383
1352
  };
1384
1353
  };
1354
+ var checkExistingInstallation = (filePath, agent, reactGrabAlreadyConfigured) => {
1355
+ const content = readFileSync(filePath, "utf-8");
1356
+ if (!hasReactGrabCode(content)) return null;
1357
+ if (reactGrabAlreadyConfigured) {
1358
+ return addAgentToExistingImport(content, agent, filePath);
1359
+ }
1360
+ return {
1361
+ success: true,
1362
+ filePath,
1363
+ message: "React Grab is already installed in this file",
1364
+ noChanges: true
1365
+ };
1366
+ };
1385
1367
  var transformVite = (projectRoot, agent, reactGrabAlreadyConfigured, force = false) => {
1386
- const indexPath = findIndexHtml(projectRoot);
1387
- if (!indexPath) {
1368
+ const entryPath = findEntryFile(projectRoot);
1369
+ if (!force) {
1370
+ const indexPath = findIndexHtml(projectRoot);
1371
+ if (indexPath) {
1372
+ const existingResult = checkExistingInstallation(
1373
+ indexPath,
1374
+ agent,
1375
+ reactGrabAlreadyConfigured
1376
+ );
1377
+ if (existingResult) return existingResult;
1378
+ }
1379
+ }
1380
+ if (!entryPath) {
1388
1381
  return {
1389
1382
  success: false,
1390
1383
  filePath: "",
1391
- message: "Could not find index.html"
1392
- };
1393
- }
1394
- const originalContent = readFileSync(indexPath, "utf-8");
1395
- let newContent = originalContent;
1396
- const hasReactGrabInFile2 = hasReactGrabCode(originalContent);
1397
- if (!force && hasReactGrabInFile2 && reactGrabAlreadyConfigured) {
1398
- return addAgentToExistingVite(originalContent, agent, indexPath);
1399
- }
1400
- if (!force && hasReactGrabInFile2) {
1401
- return {
1402
- success: true,
1403
- filePath: indexPath,
1404
- message: "React Grab is already installed in this file",
1405
- noChanges: true
1384
+ message: "Could not find entry file (src/index.tsx, src/main.tsx, etc.)"
1406
1385
  };
1407
1386
  }
1408
- const scriptBlock = VITE_SCRIPT_WITH_AGENT(agent);
1409
- const headMatch = newContent.match(/<head[^>]*>/i);
1410
- if (headMatch) {
1411
- newContent = newContent.replace(
1412
- headMatch[0],
1413
- `${headMatch[0]}
1414
- ${scriptBlock}`
1387
+ if (!force) {
1388
+ const existingResult = checkExistingInstallation(
1389
+ entryPath,
1390
+ agent,
1391
+ reactGrabAlreadyConfigured
1415
1392
  );
1393
+ if (existingResult) return existingResult;
1416
1394
  }
1395
+ const originalContent = readFileSync(entryPath, "utf-8");
1396
+ const importBlock = VITE_IMPORT_WITH_AGENT(agent);
1397
+ const newContent = `${importBlock}
1398
+
1399
+ ${originalContent}`;
1417
1400
  return {
1418
1401
  success: true,
1419
- filePath: indexPath,
1402
+ filePath: entryPath,
1420
1403
  message: "Add React Grab" + (agent !== "none" ? ` with ${agent} agent` : ""),
1421
1404
  originalContent,
1422
1405
  newContent
@@ -1431,19 +1414,15 @@ var transformWebpack = (projectRoot, agent, reactGrabAlreadyConfigured, force =
1431
1414
  message: "Could not find entry file (src/index.tsx, src/main.tsx, etc.)"
1432
1415
  };
1433
1416
  }
1434
- const originalContent = readFileSync(entryPath, "utf-8");
1435
- const hasReactGrabInFile2 = hasReactGrabCode(originalContent);
1436
- if (!force && hasReactGrabInFile2 && reactGrabAlreadyConfigured) {
1437
- return addAgentToExistingWebpack(originalContent, agent, entryPath);
1438
- }
1439
- if (!force && hasReactGrabInFile2) {
1440
- return {
1441
- success: true,
1442
- filePath: entryPath,
1443
- message: "React Grab is already installed in this file",
1444
- noChanges: true
1445
- };
1417
+ if (!force) {
1418
+ const existingResult = checkExistingInstallation(
1419
+ entryPath,
1420
+ agent,
1421
+ reactGrabAlreadyConfigured
1422
+ );
1423
+ if (existingResult) return existingResult;
1446
1424
  }
1425
+ const originalContent = readFileSync(entryPath, "utf-8");
1447
1426
  const importBlock = WEBPACK_IMPORT_WITH_AGENT(agent);
1448
1427
  const newContent = `${importBlock}
1449
1428
 
@@ -1530,40 +1509,41 @@ ${newContent}`;
1530
1509
  };
1531
1510
  };
1532
1511
  var previewTransform = (projectRoot, framework, nextRouterType, agent, reactGrabAlreadyConfigured = false, force = false) => {
1512
+ const resolvedAgent = agent === "mcp" ? "none" : agent;
1533
1513
  switch (framework) {
1534
1514
  case "next":
1535
1515
  if (nextRouterType === "app") {
1536
1516
  return transformNextAppRouter(
1537
1517
  projectRoot,
1538
- agent,
1518
+ resolvedAgent,
1539
1519
  reactGrabAlreadyConfigured,
1540
1520
  force
1541
1521
  );
1542
1522
  }
1543
1523
  return transformNextPagesRouter(
1544
1524
  projectRoot,
1545
- agent,
1525
+ resolvedAgent,
1546
1526
  reactGrabAlreadyConfigured,
1547
1527
  force
1548
1528
  );
1549
1529
  case "vite":
1550
1530
  return transformVite(
1551
1531
  projectRoot,
1552
- agent,
1532
+ resolvedAgent,
1553
1533
  reactGrabAlreadyConfigured,
1554
1534
  force
1555
1535
  );
1556
1536
  case "tanstack":
1557
1537
  return transformTanStack(
1558
1538
  projectRoot,
1559
- agent,
1539
+ resolvedAgent,
1560
1540
  reactGrabAlreadyConfigured,
1561
1541
  force
1562
1542
  );
1563
1543
  case "webpack":
1564
1544
  return transformWebpack(
1565
1545
  projectRoot,
1566
- agent,
1546
+ resolvedAgent,
1567
1547
  reactGrabAlreadyConfigured,
1568
1548
  force
1569
1549
  );
@@ -1808,8 +1788,17 @@ var findReactGrabFile = (projectRoot, framework, nextRouterType) => {
1808
1788
  return findLayoutFile(projectRoot);
1809
1789
  }
1810
1790
  return findDocumentFile(projectRoot);
1811
- case "vite":
1812
- return findIndexHtml(projectRoot);
1791
+ case "vite": {
1792
+ const entryFile = findEntryFile(projectRoot);
1793
+ if (entryFile && hasReactGrabCode(readFileSync(entryFile, "utf-8"))) {
1794
+ return entryFile;
1795
+ }
1796
+ const indexHtml = findIndexHtml(projectRoot);
1797
+ if (indexHtml && hasReactGrabCode(readFileSync(indexHtml, "utf-8"))) {
1798
+ return indexHtml;
1799
+ }
1800
+ return entryFile;
1801
+ }
1813
1802
  case "tanstack":
1814
1803
  return findTanStackRootFile(projectRoot);
1815
1804
  case "webpack":
@@ -2220,7 +2209,7 @@ var previewCdnTransform = (projectRoot, framework, nextRouterType, targetCdnDoma
2220
2209
  };
2221
2210
 
2222
2211
  // src/commands/add.ts
2223
- var VERSION = "0.1.27";
2212
+ var VERSION = "0.1.29";
2224
2213
  var formatInstalledAgentNames = (agents) => agents.map((agent) => AGENT_NAMES[agent] || agent).join(", ");
2225
2214
  var add = new Command().name("add").alias("install").description("connect React Grab to your agent").argument("[agent]", `agent to connect (${AGENTS.join(", ")}, mcp)`).option("-y, --yes", "skip confirmation prompts", false).option(
2226
2215
  "-c, --cwd <cwd>",
@@ -2258,11 +2247,36 @@ var add = new Command().name("add").alias("install").description("connect React
2258
2247
  }
2259
2248
  let agentIntegration;
2260
2249
  let agentsToRemove = [];
2261
- if (agentArg) {
2250
+ if (agentArg === "mcp") {
2251
+ if (isNonInteractive) {
2252
+ const results = installMcpServers();
2253
+ const hasSuccess = results.some((result2) => result2.success);
2254
+ if (!hasSuccess) {
2255
+ logger.break();
2256
+ logger.error("Failed to install MCP server.");
2257
+ logger.break();
2258
+ process.exit(1);
2259
+ }
2260
+ } else {
2261
+ const didInstall = await promptMcpInstall();
2262
+ if (!didInstall) {
2263
+ logger.break();
2264
+ process.exit(0);
2265
+ }
2266
+ }
2267
+ logger.break();
2268
+ logger.log(
2269
+ `${highlighter.success("Success!")} MCP server has been configured.`
2270
+ );
2271
+ logger.log("Restart your agents to activate.");
2272
+ logger.break();
2273
+ agentIntegration = "mcp";
2274
+ projectInfo.installedAgents = [...projectInfo.installedAgents, "mcp"];
2275
+ } else if (agentArg) {
2262
2276
  if (!AGENTS.includes(agentArg)) {
2263
2277
  logger.break();
2264
2278
  logger.error(`Invalid agent: ${agentArg}`);
2265
- logger.error(`Available agents: ${AGENTS.join(", ")}`);
2279
+ logger.error(`Available agents: ${AGENTS.join(", ")}, mcp`);
2266
2280
  logger.break();
2267
2281
  process.exit(1);
2268
2282
  }
@@ -2581,7 +2595,7 @@ var MAX_KEY_HOLD_DURATION_MS = 2e3;
2581
2595
  var MAX_CONTEXT_LINES = 50;
2582
2596
 
2583
2597
  // src/commands/configure.ts
2584
- var VERSION2 = "0.1.27";
2598
+ var VERSION2 = "0.1.29";
2585
2599
  var isMac = process.platform === "darwin";
2586
2600
  var META_LABEL = isMac ? "Cmd" : "Win";
2587
2601
  var ALT_LABEL = isMac ? "Option" : "Alt";
@@ -3137,7 +3151,7 @@ var uninstallPackagesWithFeedback = (packages, packageManager, projectRoot) => {
3137
3151
  };
3138
3152
 
3139
3153
  // src/commands/init.ts
3140
- var VERSION3 = "0.1.27";
3154
+ var VERSION3 = "0.1.29";
3141
3155
  var REPORT_URL = "https://react-grab.com/api/report-cli";
3142
3156
  var DOCS_URL = "https://github.com/aidenybai/react-grab";
3143
3157
  var reportToCli = (type, config, error) => {
@@ -3468,76 +3482,6 @@ var init = new Command().name("init").description("initialize React Grab in your
3468
3482
  logger.break();
3469
3483
  logger.success("MCP server has been configured.");
3470
3484
  logger.log("Restart your agents to activate.");
3471
- agentIntegration2 = "mcp";
3472
- projectInfo.installedAgents = ["mcp"];
3473
- const result2 = previewTransform(
3474
- projectInfo.projectRoot,
3475
- projectInfo.framework,
3476
- projectInfo.nextRouterType,
3477
- agentIntegration2,
3478
- true
3479
- );
3480
- const packageJsonResult2 = previewPackageJsonTransform(
3481
- projectInfo.projectRoot,
3482
- agentIntegration2,
3483
- projectInfo.installedAgents,
3484
- projectInfo.packageManager
3485
- );
3486
- if (!result2.success) {
3487
- logger.break();
3488
- logger.error(result2.message);
3489
- logger.break();
3490
- process.exit(1);
3491
- }
3492
- const hasLayoutChanges2 = !result2.noChanges && result2.originalContent && result2.newContent;
3493
- const hasPackageJsonChanges2 = packageJsonResult2.success && !packageJsonResult2.noChanges && packageJsonResult2.originalContent && packageJsonResult2.newContent;
3494
- if (hasLayoutChanges2 || hasPackageJsonChanges2) {
3495
- logger.break();
3496
- if (hasLayoutChanges2) {
3497
- printDiff(
3498
- result2.filePath,
3499
- result2.originalContent,
3500
- result2.newContent
3501
- );
3502
- }
3503
- if (hasPackageJsonChanges2) {
3504
- if (hasLayoutChanges2) {
3505
- logger.break();
3506
- }
3507
- printDiff(
3508
- packageJsonResult2.filePath,
3509
- packageJsonResult2.originalContent,
3510
- packageJsonResult2.newContent
3511
- );
3512
- }
3513
- logger.break();
3514
- const { proceed } = await prompts({
3515
- type: "confirm",
3516
- name: "proceed",
3517
- message: "Apply these changes?",
3518
- initial: true
3519
- });
3520
- if (!proceed) {
3521
- logger.break();
3522
- logger.log("Agent addition cancelled.");
3523
- } else {
3524
- installPackagesWithFeedback(
3525
- getPackagesToInstall(agentIntegration2, false),
3526
- projectInfo.packageManager,
3527
- projectInfo.projectRoot
3528
- );
3529
- if (hasLayoutChanges2) {
3530
- applyTransformWithFeedback(result2);
3531
- }
3532
- if (hasPackageJsonChanges2) {
3533
- applyPackageJsonWithFeedback(packageJsonResult2);
3534
- }
3535
- logger.break();
3536
- logger.success(
3537
- `${getAgentName(agentIntegration2)} has been added.`
3538
- );
3539
- }
3540
- }
3541
3485
  } else {
3542
3486
  const { agent } = await prompts({
3543
3487
  type: "select",
@@ -3996,7 +3940,7 @@ var init = new Command().name("init").description("initialize React Grab in your
3996
3940
  reportToCli("error", void 0, error);
3997
3941
  }
3998
3942
  });
3999
- var VERSION4 = "0.1.27";
3943
+ var VERSION4 = "0.1.29";
4000
3944
  var remove = new Command().name("remove").description("disconnect React Grab from your agent").argument("[agent]", `agent to disconnect (${AGENTS.join(", ")}, mcp)`).option("-y, --yes", "skip confirmation prompts", false).option(
4001
3945
  "-c, --cwd <cwd>",
4002
3946
  "working directory (defaults to current directory)",
@@ -4172,7 +4116,7 @@ var remove = new Command().name("remove").description("disconnect React Grab fro
4172
4116
  });
4173
4117
 
4174
4118
  // src/cli.ts
4175
- var VERSION5 = "0.1.27";
4119
+ var VERSION5 = "0.1.29";
4176
4120
  var VERSION_API_URL = "https://www.react-grab.com/api/version";
4177
4121
  process.on("SIGINT", () => process.exit(0));
4178
4122
  process.on("SIGTERM", () => process.exit(0));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-grab/cli",
3
- "version": "0.1.27",
3
+ "version": "0.1.29",
4
4
  "bin": {
5
5
  "react-grab": "./dist/cli.js"
6
6
  },