@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.
- package/dist/cli.cjs +1288 -66
- package/dist/cli.js +1288 -66
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import pc from 'picocolors';
|
|
4
|
-
import
|
|
4
|
+
import prompts3 from 'prompts';
|
|
5
5
|
import { spawn, execSync } from 'child_process';
|
|
6
|
-
import {
|
|
6
|
+
import { readFileSync, existsSync, writeFileSync, accessSync, constants, readdirSync } from 'fs';
|
|
7
7
|
import { join, basename } from 'path';
|
|
8
8
|
import { detect } from '@antfu/ni';
|
|
9
9
|
import ora from 'ora';
|
|
@@ -459,6 +459,12 @@ var INSTALL_COMMANDS = {
|
|
|
459
459
|
pnpm: "pnpm add",
|
|
460
460
|
bun: "bun add"
|
|
461
461
|
};
|
|
462
|
+
var UNINSTALL_COMMANDS = {
|
|
463
|
+
npm: "npm uninstall",
|
|
464
|
+
yarn: "yarn remove",
|
|
465
|
+
pnpm: "pnpm remove",
|
|
466
|
+
bun: "bun remove"
|
|
467
|
+
};
|
|
462
468
|
var installPackages = (packages, packageManager, projectRoot, isDev = true) => {
|
|
463
469
|
if (packages.length === 0) {
|
|
464
470
|
return;
|
|
@@ -483,6 +489,22 @@ var getPackagesToInstall = (agent, includeReactGrab = true) => {
|
|
|
483
489
|
}
|
|
484
490
|
return packages;
|
|
485
491
|
};
|
|
492
|
+
var uninstallPackages = (packages, packageManager, projectRoot) => {
|
|
493
|
+
if (packages.length === 0) {
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
const command = UNINSTALL_COMMANDS[packageManager];
|
|
497
|
+
const fullCommand = `${command} ${packages.join(" ")}`;
|
|
498
|
+
console.log(`Running: ${fullCommand}
|
|
499
|
+
`);
|
|
500
|
+
execSync(fullCommand, {
|
|
501
|
+
cwd: projectRoot,
|
|
502
|
+
stdio: "inherit"
|
|
503
|
+
});
|
|
504
|
+
};
|
|
505
|
+
var getPackagesToUninstall = (agent) => {
|
|
506
|
+
return [`@react-grab/${agent}`];
|
|
507
|
+
};
|
|
486
508
|
var spinner = (text, options) => ora({ text, isSilent: options?.silent, stream: process.stdout });
|
|
487
509
|
|
|
488
510
|
// src/utils/templates.ts
|
|
@@ -668,18 +690,20 @@ var addAgentToExistingNextApp = (originalContent, agent, filePath) => {
|
|
|
668
690
|
noChanges: true
|
|
669
691
|
};
|
|
670
692
|
}
|
|
671
|
-
const agentScript =
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
693
|
+
const agentScript = `{process.env.NODE_ENV === "development" && (
|
|
694
|
+
<Script
|
|
695
|
+
src="//unpkg.com/${agentPackage}/dist/client.global.js"
|
|
696
|
+
strategy="lazyOnload"
|
|
697
|
+
/>
|
|
698
|
+
)}`;
|
|
699
|
+
const reactGrabBlockMatch = originalContent.match(
|
|
700
|
+
/\{process\.env\.NODE_ENV\s*===\s*["']development["']\s*&&\s*\(\s*<Script[^>]*react-grab[^>]*\/>\s*\)\}/is
|
|
677
701
|
);
|
|
678
|
-
if (
|
|
702
|
+
if (reactGrabBlockMatch) {
|
|
679
703
|
const newContent = originalContent.replace(
|
|
680
|
-
|
|
681
|
-
`${
|
|
682
|
-
|
|
704
|
+
reactGrabBlockMatch[0],
|
|
705
|
+
`${reactGrabBlockMatch[0]}
|
|
706
|
+
${agentScript}`
|
|
683
707
|
);
|
|
684
708
|
return {
|
|
685
709
|
success: true,
|
|
@@ -1029,20 +1053,49 @@ var applyTransform = (result) => {
|
|
|
1029
1053
|
}
|
|
1030
1054
|
return { success: true };
|
|
1031
1055
|
};
|
|
1032
|
-
var
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1056
|
+
var getPackageExecutor = (packageManager) => {
|
|
1057
|
+
switch (packageManager) {
|
|
1058
|
+
case "bun":
|
|
1059
|
+
return "bunx";
|
|
1060
|
+
case "pnpm":
|
|
1061
|
+
return "pnpm dlx";
|
|
1062
|
+
case "yarn":
|
|
1063
|
+
return "npx";
|
|
1064
|
+
case "npm":
|
|
1065
|
+
default:
|
|
1066
|
+
return "npx";
|
|
1067
|
+
}
|
|
1068
|
+
};
|
|
1069
|
+
var AGENT_PACKAGES2 = {
|
|
1070
|
+
"claude-code": "@react-grab/claude-code@latest",
|
|
1071
|
+
cursor: "@react-grab/cursor@latest",
|
|
1072
|
+
opencode: "@react-grab/opencode@latest",
|
|
1073
|
+
codex: "@react-grab/codex@latest",
|
|
1074
|
+
gemini: "@react-grab/gemini@latest",
|
|
1075
|
+
amp: "@react-grab/amp@latest"
|
|
1076
|
+
};
|
|
1077
|
+
var getAgentPrefix = (agent, packageManager) => {
|
|
1078
|
+
const agentPackage = AGENT_PACKAGES2[agent];
|
|
1079
|
+
if (!agentPackage) return null;
|
|
1080
|
+
const executor = getPackageExecutor(packageManager);
|
|
1081
|
+
return `${executor} ${agentPackage} &&`;
|
|
1082
|
+
};
|
|
1083
|
+
var getAllAgentPrefixVariants = (agent) => {
|
|
1084
|
+
const agentPackage = AGENT_PACKAGES2[agent];
|
|
1085
|
+
if (!agentPackage) return [];
|
|
1086
|
+
return [
|
|
1087
|
+
`npx ${agentPackage} &&`,
|
|
1088
|
+
`bunx ${agentPackage} &&`,
|
|
1089
|
+
`pnpm dlx ${agentPackage} &&`,
|
|
1090
|
+
`yarn dlx ${agentPackage} &&`
|
|
1091
|
+
];
|
|
1039
1092
|
};
|
|
1040
|
-
var previewPackageJsonTransform = (projectRoot, agent, installedAgents) => {
|
|
1041
|
-
if (agent === "none" || agent === "
|
|
1093
|
+
var previewPackageJsonTransform = (projectRoot, agent, installedAgents, packageManager = "npm") => {
|
|
1094
|
+
if (agent === "none" || agent === "visual-edit") {
|
|
1042
1095
|
return {
|
|
1043
1096
|
success: true,
|
|
1044
1097
|
filePath: "",
|
|
1045
|
-
message: agent === "
|
|
1098
|
+
message: agent === "visual-edit" ? "Visual Edit does not require package.json modification" : "No agent selected, skipping package.json modification",
|
|
1046
1099
|
noChanges: true
|
|
1047
1100
|
};
|
|
1048
1101
|
}
|
|
@@ -1055,7 +1108,7 @@ var previewPackageJsonTransform = (projectRoot, agent, installedAgents) => {
|
|
|
1055
1108
|
};
|
|
1056
1109
|
}
|
|
1057
1110
|
const originalContent = readFileSync(packageJsonPath, "utf-8");
|
|
1058
|
-
const agentPrefix =
|
|
1111
|
+
const agentPrefix = getAgentPrefix(agent, packageManager);
|
|
1059
1112
|
if (!agentPrefix) {
|
|
1060
1113
|
return {
|
|
1061
1114
|
success: false,
|
|
@@ -1063,7 +1116,11 @@ var previewPackageJsonTransform = (projectRoot, agent, installedAgents) => {
|
|
|
1063
1116
|
message: `Unknown agent: ${agent}`
|
|
1064
1117
|
};
|
|
1065
1118
|
}
|
|
1066
|
-
|
|
1119
|
+
const allPrefixVariants = getAllAgentPrefixVariants(agent);
|
|
1120
|
+
const hasExistingPrefix = allPrefixVariants.some(
|
|
1121
|
+
(prefix) => originalContent.includes(prefix)
|
|
1122
|
+
);
|
|
1123
|
+
if (hasExistingPrefix) {
|
|
1067
1124
|
return {
|
|
1068
1125
|
success: true,
|
|
1069
1126
|
filePath: packageJsonPath,
|
|
@@ -1086,14 +1143,19 @@ var previewPackageJsonTransform = (projectRoot, agent, installedAgents) => {
|
|
|
1086
1143
|
filePath: packageJsonPath,
|
|
1087
1144
|
message: "No dev script found in package.json",
|
|
1088
1145
|
noChanges: true,
|
|
1089
|
-
warning: `
|
|
1146
|
+
warning: `Could not inject agent into package.json (no dev script found).
|
|
1147
|
+
Run this command manually before starting your dev server:
|
|
1148
|
+
${agentPrefix} <your dev command>`
|
|
1090
1149
|
};
|
|
1091
1150
|
}
|
|
1092
1151
|
}
|
|
1093
1152
|
const currentDevScript = packageJson.scripts[targetScriptKey];
|
|
1094
1153
|
for (const installedAgent of installedAgents) {
|
|
1095
|
-
const
|
|
1096
|
-
|
|
1154
|
+
const installedPrefixVariants = getAllAgentPrefixVariants(installedAgent);
|
|
1155
|
+
const hasInstalledAgentPrefix = installedPrefixVariants.some(
|
|
1156
|
+
(prefix) => currentDevScript.includes(prefix)
|
|
1157
|
+
);
|
|
1158
|
+
if (hasInstalledAgentPrefix) {
|
|
1097
1159
|
return {
|
|
1098
1160
|
success: true,
|
|
1099
1161
|
filePath: packageJsonPath,
|
|
@@ -1337,9 +1399,192 @@ var previewOptionsTransform = (projectRoot, framework, nextRouterType, options)
|
|
|
1337
1399
|
var applyOptionsTransform = (result) => {
|
|
1338
1400
|
return applyTransform(result);
|
|
1339
1401
|
};
|
|
1402
|
+
var removeAgentFromNextApp = (originalContent, agent, filePath) => {
|
|
1403
|
+
const agentPackage = `@react-grab/${agent}`;
|
|
1404
|
+
if (!originalContent.includes(agentPackage)) {
|
|
1405
|
+
return {
|
|
1406
|
+
success: true,
|
|
1407
|
+
filePath,
|
|
1408
|
+
message: `Agent ${agent} is not configured in this file`,
|
|
1409
|
+
noChanges: true
|
|
1410
|
+
};
|
|
1411
|
+
}
|
|
1412
|
+
const agentScriptPattern = new RegExp(
|
|
1413
|
+
`\\s*\\{process\\.env\\.NODE_ENV === "development" && \\(\\s*<Script[^>]*${agentPackage.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[^>]*\\/>\\s*\\)\\}`,
|
|
1414
|
+
"gs"
|
|
1415
|
+
);
|
|
1416
|
+
const simpleScriptPattern = new RegExp(
|
|
1417
|
+
`\\s*<Script[^>]*${agentPackage.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[^>]*\\/>`,
|
|
1418
|
+
"gi"
|
|
1419
|
+
);
|
|
1420
|
+
let newContent = originalContent.replace(agentScriptPattern, "");
|
|
1421
|
+
if (newContent === originalContent) {
|
|
1422
|
+
newContent = originalContent.replace(simpleScriptPattern, "");
|
|
1423
|
+
}
|
|
1424
|
+
if (newContent === originalContent) {
|
|
1425
|
+
return {
|
|
1426
|
+
success: false,
|
|
1427
|
+
filePath,
|
|
1428
|
+
message: `Could not find agent ${agent} script to remove`
|
|
1429
|
+
};
|
|
1430
|
+
}
|
|
1431
|
+
return {
|
|
1432
|
+
success: true,
|
|
1433
|
+
filePath,
|
|
1434
|
+
message: `Remove ${agent} agent`,
|
|
1435
|
+
originalContent,
|
|
1436
|
+
newContent
|
|
1437
|
+
};
|
|
1438
|
+
};
|
|
1439
|
+
var removeAgentFromVite = (originalContent, agent, filePath) => {
|
|
1440
|
+
const agentPackage = `@react-grab/${agent}`;
|
|
1441
|
+
if (!originalContent.includes(agentPackage)) {
|
|
1442
|
+
return {
|
|
1443
|
+
success: true,
|
|
1444
|
+
filePath,
|
|
1445
|
+
message: `Agent ${agent} is not configured in this file`,
|
|
1446
|
+
noChanges: true
|
|
1447
|
+
};
|
|
1448
|
+
}
|
|
1449
|
+
const agentImportPattern = new RegExp(
|
|
1450
|
+
`\\s*import\\s*\\(\\s*["']${agentPackage.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}/client["']\\s*\\);?`,
|
|
1451
|
+
"g"
|
|
1452
|
+
);
|
|
1453
|
+
const newContent = originalContent.replace(agentImportPattern, "");
|
|
1454
|
+
if (newContent === originalContent) {
|
|
1455
|
+
return {
|
|
1456
|
+
success: false,
|
|
1457
|
+
filePath,
|
|
1458
|
+
message: `Could not find agent ${agent} import to remove`
|
|
1459
|
+
};
|
|
1460
|
+
}
|
|
1461
|
+
return {
|
|
1462
|
+
success: true,
|
|
1463
|
+
filePath,
|
|
1464
|
+
message: `Remove ${agent} agent`,
|
|
1465
|
+
originalContent,
|
|
1466
|
+
newContent
|
|
1467
|
+
};
|
|
1468
|
+
};
|
|
1469
|
+
var removeAgentFromWebpack = (originalContent, agent, filePath) => {
|
|
1470
|
+
const agentPackage = `@react-grab/${agent}`;
|
|
1471
|
+
if (!originalContent.includes(agentPackage)) {
|
|
1472
|
+
return {
|
|
1473
|
+
success: true,
|
|
1474
|
+
filePath,
|
|
1475
|
+
message: `Agent ${agent} is not configured in this file`,
|
|
1476
|
+
noChanges: true
|
|
1477
|
+
};
|
|
1478
|
+
}
|
|
1479
|
+
const agentImportPattern = new RegExp(
|
|
1480
|
+
`\\s*import\\s*\\(\\s*["']${agentPackage.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}/client["']\\s*\\);?`,
|
|
1481
|
+
"g"
|
|
1482
|
+
);
|
|
1483
|
+
const newContent = originalContent.replace(agentImportPattern, "");
|
|
1484
|
+
if (newContent === originalContent) {
|
|
1485
|
+
return {
|
|
1486
|
+
success: false,
|
|
1487
|
+
filePath,
|
|
1488
|
+
message: `Could not find agent ${agent} import to remove`
|
|
1489
|
+
};
|
|
1490
|
+
}
|
|
1491
|
+
return {
|
|
1492
|
+
success: true,
|
|
1493
|
+
filePath,
|
|
1494
|
+
message: `Remove ${agent} agent`,
|
|
1495
|
+
originalContent,
|
|
1496
|
+
newContent
|
|
1497
|
+
};
|
|
1498
|
+
};
|
|
1499
|
+
var previewAgentRemoval = (projectRoot, framework, nextRouterType, agent) => {
|
|
1500
|
+
const filePath = findReactGrabFile(projectRoot, framework, nextRouterType);
|
|
1501
|
+
if (!filePath) {
|
|
1502
|
+
return {
|
|
1503
|
+
success: true,
|
|
1504
|
+
filePath: "",
|
|
1505
|
+
message: "Could not find file containing React Grab configuration",
|
|
1506
|
+
noChanges: true
|
|
1507
|
+
};
|
|
1508
|
+
}
|
|
1509
|
+
const originalContent = readFileSync(filePath, "utf-8");
|
|
1510
|
+
switch (framework) {
|
|
1511
|
+
case "next":
|
|
1512
|
+
return removeAgentFromNextApp(originalContent, agent, filePath);
|
|
1513
|
+
case "vite":
|
|
1514
|
+
return removeAgentFromVite(originalContent, agent, filePath);
|
|
1515
|
+
case "webpack":
|
|
1516
|
+
return removeAgentFromWebpack(originalContent, agent, filePath);
|
|
1517
|
+
default:
|
|
1518
|
+
return {
|
|
1519
|
+
success: false,
|
|
1520
|
+
filePath,
|
|
1521
|
+
message: `Unknown framework: ${framework}`
|
|
1522
|
+
};
|
|
1523
|
+
}
|
|
1524
|
+
};
|
|
1525
|
+
var previewPackageJsonAgentRemoval = (projectRoot, agent) => {
|
|
1526
|
+
const packageJsonPath = join(projectRoot, "package.json");
|
|
1527
|
+
if (!existsSync(packageJsonPath)) {
|
|
1528
|
+
return {
|
|
1529
|
+
success: true,
|
|
1530
|
+
filePath: "",
|
|
1531
|
+
message: "Could not find package.json",
|
|
1532
|
+
noChanges: true
|
|
1533
|
+
};
|
|
1534
|
+
}
|
|
1535
|
+
const originalContent = readFileSync(packageJsonPath, "utf-8");
|
|
1536
|
+
const allPrefixVariants = getAllAgentPrefixVariants(agent);
|
|
1537
|
+
if (allPrefixVariants.length === 0) {
|
|
1538
|
+
return {
|
|
1539
|
+
success: true,
|
|
1540
|
+
filePath: packageJsonPath,
|
|
1541
|
+
message: `Unknown agent: ${agent}`,
|
|
1542
|
+
noChanges: true
|
|
1543
|
+
};
|
|
1544
|
+
}
|
|
1545
|
+
const hasAnyPrefix = allPrefixVariants.some(
|
|
1546
|
+
(prefix) => originalContent.includes(prefix)
|
|
1547
|
+
);
|
|
1548
|
+
if (!hasAnyPrefix) {
|
|
1549
|
+
return {
|
|
1550
|
+
success: true,
|
|
1551
|
+
filePath: packageJsonPath,
|
|
1552
|
+
message: `Agent ${agent} dev script is not configured`,
|
|
1553
|
+
noChanges: true
|
|
1554
|
+
};
|
|
1555
|
+
}
|
|
1556
|
+
try {
|
|
1557
|
+
const packageJson = JSON.parse(originalContent);
|
|
1558
|
+
for (const scriptKey of Object.keys(packageJson.scripts || {})) {
|
|
1559
|
+
let scriptValue = packageJson.scripts[scriptKey];
|
|
1560
|
+
if (typeof scriptValue === "string") {
|
|
1561
|
+
for (const prefix of allPrefixVariants) {
|
|
1562
|
+
if (scriptValue.includes(prefix)) {
|
|
1563
|
+
scriptValue = scriptValue.replace(prefix + " ", "").replace(prefix, "");
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
packageJson.scripts[scriptKey] = scriptValue;
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
const newContent = JSON.stringify(packageJson, null, 2) + "\n";
|
|
1570
|
+
return {
|
|
1571
|
+
success: true,
|
|
1572
|
+
filePath: packageJsonPath,
|
|
1573
|
+
message: `Remove ${agent} server from dev script`,
|
|
1574
|
+
originalContent,
|
|
1575
|
+
newContent
|
|
1576
|
+
};
|
|
1577
|
+
} catch {
|
|
1578
|
+
return {
|
|
1579
|
+
success: false,
|
|
1580
|
+
filePath: packageJsonPath,
|
|
1581
|
+
message: "Failed to parse package.json"
|
|
1582
|
+
};
|
|
1583
|
+
}
|
|
1584
|
+
};
|
|
1340
1585
|
|
|
1341
1586
|
// src/commands/add.ts
|
|
1342
|
-
var VERSION = "0.0.
|
|
1587
|
+
var VERSION = "0.0.92";
|
|
1343
1588
|
var AGENT_NAMES = {
|
|
1344
1589
|
"claude-code": "Claude Code",
|
|
1345
1590
|
cursor: "Cursor",
|
|
@@ -1376,7 +1621,7 @@ var add = new Command().name("add").description("add an agent integration").argu
|
|
|
1376
1621
|
process.exit(1);
|
|
1377
1622
|
}
|
|
1378
1623
|
preflightSpinner.succeed();
|
|
1379
|
-
const
|
|
1624
|
+
const allAgents = [
|
|
1380
1625
|
"claude-code",
|
|
1381
1626
|
"cursor",
|
|
1382
1627
|
"opencode",
|
|
@@ -1384,7 +1629,10 @@ var add = new Command().name("add").description("add an agent integration").argu
|
|
|
1384
1629
|
"gemini",
|
|
1385
1630
|
"amp",
|
|
1386
1631
|
"visual-edit"
|
|
1387
|
-
]
|
|
1632
|
+
];
|
|
1633
|
+
const availableAgents = allAgents.filter(
|
|
1634
|
+
(agent) => !projectInfo.installedAgents.includes(agent)
|
|
1635
|
+
);
|
|
1388
1636
|
if (availableAgents.length === 0) {
|
|
1389
1637
|
logger.break();
|
|
1390
1638
|
logger.success("All agent integrations are already installed.");
|
|
@@ -1392,16 +1640,9 @@ var add = new Command().name("add").description("add an agent integration").argu
|
|
|
1392
1640
|
process.exit(0);
|
|
1393
1641
|
}
|
|
1394
1642
|
let agentIntegration;
|
|
1643
|
+
let agentsToRemove = [];
|
|
1395
1644
|
if (agentArg) {
|
|
1396
|
-
if (!
|
|
1397
|
-
"claude-code",
|
|
1398
|
-
"cursor",
|
|
1399
|
-
"opencode",
|
|
1400
|
-
"codex",
|
|
1401
|
-
"gemini",
|
|
1402
|
-
"amp",
|
|
1403
|
-
"visual-edit"
|
|
1404
|
-
].includes(agentArg)) {
|
|
1645
|
+
if (!allAgents.includes(agentArg)) {
|
|
1405
1646
|
logger.break();
|
|
1406
1647
|
logger.error(`Invalid agent: ${agentArg}`);
|
|
1407
1648
|
logger.error(
|
|
@@ -1417,9 +1658,44 @@ var add = new Command().name("add").description("add an agent integration").argu
|
|
|
1417
1658
|
process.exit(0);
|
|
1418
1659
|
}
|
|
1419
1660
|
agentIntegration = agentArg;
|
|
1661
|
+
if (projectInfo.installedAgents.length > 0 && !isNonInteractive) {
|
|
1662
|
+
const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES[innerAgent] || innerAgent).join(", ");
|
|
1663
|
+
logger.break();
|
|
1664
|
+
logger.warn(`${installedNames} is already installed.`);
|
|
1665
|
+
const { action } = await prompts3({
|
|
1666
|
+
type: "select",
|
|
1667
|
+
name: "action",
|
|
1668
|
+
message: "How would you like to proceed?",
|
|
1669
|
+
choices: [
|
|
1670
|
+
{
|
|
1671
|
+
title: `Replace with ${AGENT_NAMES[agentIntegration]}`,
|
|
1672
|
+
value: "replace"
|
|
1673
|
+
},
|
|
1674
|
+
{
|
|
1675
|
+
title: `Add ${AGENT_NAMES[agentIntegration]} alongside existing`,
|
|
1676
|
+
value: "add"
|
|
1677
|
+
},
|
|
1678
|
+
{ title: "Cancel", value: "cancel" }
|
|
1679
|
+
]
|
|
1680
|
+
});
|
|
1681
|
+
if (!action || action === "cancel") {
|
|
1682
|
+
logger.break();
|
|
1683
|
+
logger.log("Changes cancelled.");
|
|
1684
|
+
logger.break();
|
|
1685
|
+
process.exit(0);
|
|
1686
|
+
}
|
|
1687
|
+
if (action === "replace") {
|
|
1688
|
+
agentsToRemove = [...projectInfo.installedAgents];
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1420
1691
|
} else if (!isNonInteractive) {
|
|
1421
1692
|
logger.break();
|
|
1422
|
-
|
|
1693
|
+
if (projectInfo.installedAgents.length > 0) {
|
|
1694
|
+
const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES[innerAgent] || innerAgent).join(", ");
|
|
1695
|
+
logger.warn(`Currently installed: ${installedNames}`);
|
|
1696
|
+
logger.break();
|
|
1697
|
+
}
|
|
1698
|
+
const { agent } = await prompts3({
|
|
1423
1699
|
type: "select",
|
|
1424
1700
|
name: "agent",
|
|
1425
1701
|
message: `Which ${highlighter.info("agent integration")} would you like to add?`,
|
|
@@ -1433,6 +1709,34 @@ var add = new Command().name("add").description("add an agent integration").argu
|
|
|
1433
1709
|
process.exit(1);
|
|
1434
1710
|
}
|
|
1435
1711
|
agentIntegration = agent;
|
|
1712
|
+
if (projectInfo.installedAgents.length > 0) {
|
|
1713
|
+
const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES[innerAgent] || innerAgent).join(", ");
|
|
1714
|
+
const { action } = await prompts3({
|
|
1715
|
+
type: "select",
|
|
1716
|
+
name: "action",
|
|
1717
|
+
message: "How would you like to proceed?",
|
|
1718
|
+
choices: [
|
|
1719
|
+
{
|
|
1720
|
+
title: `Replace ${installedNames} with ${AGENT_NAMES[agentIntegration]}`,
|
|
1721
|
+
value: "replace"
|
|
1722
|
+
},
|
|
1723
|
+
{
|
|
1724
|
+
title: `Add ${AGENT_NAMES[agentIntegration]} alongside existing`,
|
|
1725
|
+
value: "add"
|
|
1726
|
+
},
|
|
1727
|
+
{ title: "Cancel", value: "cancel" }
|
|
1728
|
+
]
|
|
1729
|
+
});
|
|
1730
|
+
if (!action || action === "cancel") {
|
|
1731
|
+
logger.break();
|
|
1732
|
+
logger.log("Changes cancelled.");
|
|
1733
|
+
logger.break();
|
|
1734
|
+
process.exit(0);
|
|
1735
|
+
}
|
|
1736
|
+
if (action === "replace") {
|
|
1737
|
+
agentsToRemove = [...projectInfo.installedAgents];
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1436
1740
|
} else {
|
|
1437
1741
|
logger.break();
|
|
1438
1742
|
logger.error("Please specify an agent to add.");
|
|
@@ -1440,6 +1744,72 @@ var add = new Command().name("add").description("add an agent integration").argu
|
|
|
1440
1744
|
logger.break();
|
|
1441
1745
|
process.exit(1);
|
|
1442
1746
|
}
|
|
1747
|
+
if (agentsToRemove.length > 0) {
|
|
1748
|
+
for (const agentToRemove of agentsToRemove) {
|
|
1749
|
+
const removalResult = previewAgentRemoval(
|
|
1750
|
+
projectInfo.projectRoot,
|
|
1751
|
+
projectInfo.framework,
|
|
1752
|
+
projectInfo.nextRouterType,
|
|
1753
|
+
agentToRemove
|
|
1754
|
+
);
|
|
1755
|
+
const removalPackageJsonResult = previewPackageJsonAgentRemoval(
|
|
1756
|
+
projectInfo.projectRoot,
|
|
1757
|
+
agentToRemove
|
|
1758
|
+
);
|
|
1759
|
+
const packagesToRemove = getPackagesToUninstall(agentToRemove);
|
|
1760
|
+
if (packagesToRemove.length > 0) {
|
|
1761
|
+
const uninstallSpinner = spinner(
|
|
1762
|
+
`Removing ${packagesToRemove.join(", ")}.`
|
|
1763
|
+
).start();
|
|
1764
|
+
try {
|
|
1765
|
+
uninstallPackages(
|
|
1766
|
+
packagesToRemove,
|
|
1767
|
+
projectInfo.packageManager,
|
|
1768
|
+
projectInfo.projectRoot
|
|
1769
|
+
);
|
|
1770
|
+
uninstallSpinner.succeed();
|
|
1771
|
+
} catch (error) {
|
|
1772
|
+
uninstallSpinner.fail();
|
|
1773
|
+
handleError(error);
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
if (removalResult.success && !removalResult.noChanges && removalResult.newContent) {
|
|
1777
|
+
const removeWriteSpinner = spinner(
|
|
1778
|
+
`Removing ${AGENT_NAMES[agentToRemove] || agentToRemove} from ${removalResult.filePath}.`
|
|
1779
|
+
).start();
|
|
1780
|
+
const writeResult = applyTransform(removalResult);
|
|
1781
|
+
if (!writeResult.success) {
|
|
1782
|
+
removeWriteSpinner.fail();
|
|
1783
|
+
logger.break();
|
|
1784
|
+
logger.error(writeResult.error || "Failed to write file.");
|
|
1785
|
+
logger.break();
|
|
1786
|
+
process.exit(1);
|
|
1787
|
+
}
|
|
1788
|
+
removeWriteSpinner.succeed();
|
|
1789
|
+
}
|
|
1790
|
+
if (removalPackageJsonResult.success && !removalPackageJsonResult.noChanges && removalPackageJsonResult.newContent) {
|
|
1791
|
+
const removePackageJsonSpinner = spinner(
|
|
1792
|
+
`Removing ${AGENT_NAMES[agentToRemove] || agentToRemove} from ${removalPackageJsonResult.filePath}.`
|
|
1793
|
+
).start();
|
|
1794
|
+
const packageJsonWriteResult = applyPackageJsonTransform(
|
|
1795
|
+
removalPackageJsonResult
|
|
1796
|
+
);
|
|
1797
|
+
if (!packageJsonWriteResult.success) {
|
|
1798
|
+
removePackageJsonSpinner.fail();
|
|
1799
|
+
logger.break();
|
|
1800
|
+
logger.error(
|
|
1801
|
+
packageJsonWriteResult.error || "Failed to write file."
|
|
1802
|
+
);
|
|
1803
|
+
logger.break();
|
|
1804
|
+
process.exit(1);
|
|
1805
|
+
}
|
|
1806
|
+
removePackageJsonSpinner.succeed();
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
projectInfo.installedAgents = projectInfo.installedAgents.filter(
|
|
1810
|
+
(innerAgent) => !agentsToRemove.includes(innerAgent)
|
|
1811
|
+
);
|
|
1812
|
+
}
|
|
1443
1813
|
const addingSpinner = spinner(
|
|
1444
1814
|
`Adding ${AGENT_NAMES[agentIntegration]}.`
|
|
1445
1815
|
).start();
|
|
@@ -1454,7 +1824,8 @@ var add = new Command().name("add").description("add an agent integration").argu
|
|
|
1454
1824
|
const packageJsonResult = previewPackageJsonTransform(
|
|
1455
1825
|
projectInfo.projectRoot,
|
|
1456
1826
|
agentIntegration,
|
|
1457
|
-
projectInfo.installedAgents
|
|
1827
|
+
projectInfo.installedAgents,
|
|
1828
|
+
projectInfo.packageManager
|
|
1458
1829
|
);
|
|
1459
1830
|
if (!result.success) {
|
|
1460
1831
|
logger.break();
|
|
@@ -1483,9 +1854,9 @@ var add = new Command().name("add").description("add an agent integration").argu
|
|
|
1483
1854
|
packageJsonResult.newContent
|
|
1484
1855
|
);
|
|
1485
1856
|
}
|
|
1486
|
-
if (!isNonInteractive) {
|
|
1857
|
+
if (!isNonInteractive && agentsToRemove.length === 0) {
|
|
1487
1858
|
logger.break();
|
|
1488
|
-
const { proceed } = await
|
|
1859
|
+
const { proceed } = await prompts3({
|
|
1489
1860
|
type: "confirm",
|
|
1490
1861
|
name: "proceed",
|
|
1491
1862
|
message: "Apply these changes?",
|
|
@@ -1558,7 +1929,7 @@ var add = new Command().name("add").description("add an agent integration").argu
|
|
|
1558
1929
|
handleError(error);
|
|
1559
1930
|
}
|
|
1560
1931
|
});
|
|
1561
|
-
var VERSION2 = "0.0.
|
|
1932
|
+
var VERSION2 = "0.0.92";
|
|
1562
1933
|
var MODIFIER_KEY_NAMES = {
|
|
1563
1934
|
metaKey: process.platform === "darwin" ? "\u2318 Command" : "\u229E Windows",
|
|
1564
1935
|
ctrlKey: "Ctrl",
|
|
@@ -1612,7 +1983,7 @@ var configure = new Command().name("configure").alias("config").description("con
|
|
|
1612
1983
|
logger.log(`Configure ${highlighter.info("React Grab")} options:`);
|
|
1613
1984
|
logger.break();
|
|
1614
1985
|
const collectedOptions = {};
|
|
1615
|
-
const { wantActivationKey } = await
|
|
1986
|
+
const { wantActivationKey } = await prompts3({
|
|
1616
1987
|
type: "confirm",
|
|
1617
1988
|
name: "wantActivationKey",
|
|
1618
1989
|
message: `Configure ${highlighter.info("activation key")}?`,
|
|
@@ -1623,7 +1994,7 @@ var configure = new Command().name("configure").alias("config").description("con
|
|
|
1623
1994
|
process.exit(1);
|
|
1624
1995
|
}
|
|
1625
1996
|
if (wantActivationKey) {
|
|
1626
|
-
const { key } = await
|
|
1997
|
+
const { key } = await prompts3({
|
|
1627
1998
|
type: "text",
|
|
1628
1999
|
name: "key",
|
|
1629
2000
|
message: "Enter the activation key (e.g., g, k, space):",
|
|
@@ -1633,7 +2004,7 @@ var configure = new Command().name("configure").alias("config").description("con
|
|
|
1633
2004
|
logger.break();
|
|
1634
2005
|
process.exit(1);
|
|
1635
2006
|
}
|
|
1636
|
-
const { modifiers } = await
|
|
2007
|
+
const { modifiers } = await prompts3({
|
|
1637
2008
|
type: "multiselect",
|
|
1638
2009
|
name: "modifiers",
|
|
1639
2010
|
message: "Select modifier keys (space to select, enter to confirm):",
|
|
@@ -1664,7 +2035,7 @@ var configure = new Command().name("configure").alias("config").description("con
|
|
|
1664
2035
|
` Activation key: ${highlighter.info(formatActivationKey(collectedOptions.activationKey))}`
|
|
1665
2036
|
);
|
|
1666
2037
|
}
|
|
1667
|
-
const { activationMode } = await
|
|
2038
|
+
const { activationMode } = await prompts3({
|
|
1668
2039
|
type: "select",
|
|
1669
2040
|
name: "activationMode",
|
|
1670
2041
|
message: `Select ${highlighter.info("activation mode")}:`,
|
|
@@ -1680,7 +2051,7 @@ var configure = new Command().name("configure").alias("config").description("con
|
|
|
1680
2051
|
}
|
|
1681
2052
|
collectedOptions.activationMode = activationMode;
|
|
1682
2053
|
if (activationMode === "hold") {
|
|
1683
|
-
const { keyHoldDuration } = await
|
|
2054
|
+
const { keyHoldDuration } = await prompts3({
|
|
1684
2055
|
type: "number",
|
|
1685
2056
|
name: "keyHoldDuration",
|
|
1686
2057
|
message: `Enter ${highlighter.info("key hold duration")} in milliseconds:`,
|
|
@@ -1694,7 +2065,7 @@ var configure = new Command().name("configure").alias("config").description("con
|
|
|
1694
2065
|
}
|
|
1695
2066
|
collectedOptions.keyHoldDuration = keyHoldDuration;
|
|
1696
2067
|
}
|
|
1697
|
-
const { allowActivationInsideInput } = await
|
|
2068
|
+
const { allowActivationInsideInput } = await prompts3({
|
|
1698
2069
|
type: "confirm",
|
|
1699
2070
|
name: "allowActivationInsideInput",
|
|
1700
2071
|
message: `Allow activation ${highlighter.info("inside input fields")}?`,
|
|
@@ -1705,7 +2076,7 @@ var configure = new Command().name("configure").alias("config").description("con
|
|
|
1705
2076
|
process.exit(1);
|
|
1706
2077
|
}
|
|
1707
2078
|
collectedOptions.allowActivationInsideInput = allowActivationInsideInput;
|
|
1708
|
-
const { maxContextLines } = await
|
|
2079
|
+
const { maxContextLines } = await prompts3({
|
|
1709
2080
|
type: "number",
|
|
1710
2081
|
name: "maxContextLines",
|
|
1711
2082
|
message: `Enter ${highlighter.info("max context lines")} to include:`,
|
|
@@ -1735,7 +2106,7 @@ var configure = new Command().name("configure").alias("config").description("con
|
|
|
1735
2106
|
logger.break();
|
|
1736
2107
|
printDiff(result.filePath, result.originalContent, result.newContent);
|
|
1737
2108
|
logger.break();
|
|
1738
|
-
const { proceed } = await
|
|
2109
|
+
const { proceed } = await prompts3({
|
|
1739
2110
|
type: "confirm",
|
|
1740
2111
|
name: "proceed",
|
|
1741
2112
|
message: "Apply these changes?",
|
|
@@ -1772,7 +2143,7 @@ var configure = new Command().name("configure").alias("config").description("con
|
|
|
1772
2143
|
handleError(error);
|
|
1773
2144
|
}
|
|
1774
2145
|
});
|
|
1775
|
-
var VERSION3 = "0.0.
|
|
2146
|
+
var VERSION3 = "0.0.92";
|
|
1776
2147
|
var REPORT_URL = "https://react-grab.com/api/report-cli";
|
|
1777
2148
|
var DOCS_URL = "https://github.com/aidenybai/react-grab";
|
|
1778
2149
|
var reportToCli = async (type, config, error) => {
|
|
@@ -1810,6 +2181,34 @@ var UNSUPPORTED_FRAMEWORK_NAMES = {
|
|
|
1810
2181
|
sveltekit: "SvelteKit",
|
|
1811
2182
|
gatsby: "Gatsby"
|
|
1812
2183
|
};
|
|
2184
|
+
var AGENT_NAMES2 = {
|
|
2185
|
+
"claude-code": "Claude Code",
|
|
2186
|
+
cursor: "Cursor",
|
|
2187
|
+
opencode: "OpenCode",
|
|
2188
|
+
codex: "Codex",
|
|
2189
|
+
gemini: "Gemini",
|
|
2190
|
+
amp: "Amp",
|
|
2191
|
+
ami: "Ami",
|
|
2192
|
+
"visual-edit": "Visual Edit"
|
|
2193
|
+
};
|
|
2194
|
+
var MODIFIER_KEY_NAMES2 = {
|
|
2195
|
+
metaKey: process.platform === "darwin" ? "\u2318 Command" : "\u229E Windows",
|
|
2196
|
+
ctrlKey: "Ctrl",
|
|
2197
|
+
shiftKey: "Shift",
|
|
2198
|
+
altKey: process.platform === "darwin" ? "\u2325 Option" : "Alt"
|
|
2199
|
+
};
|
|
2200
|
+
var formatActivationKey2 = (activationKey) => {
|
|
2201
|
+
if (!activationKey) return "Default (Option/Alt)";
|
|
2202
|
+
const parts = [];
|
|
2203
|
+
if (activationKey.metaKey)
|
|
2204
|
+
parts.push(process.platform === "darwin" ? "\u2318" : "Win");
|
|
2205
|
+
if (activationKey.ctrlKey) parts.push("Ctrl");
|
|
2206
|
+
if (activationKey.shiftKey) parts.push("Shift");
|
|
2207
|
+
if (activationKey.altKey)
|
|
2208
|
+
parts.push(process.platform === "darwin" ? "\u2325" : "Alt");
|
|
2209
|
+
if (activationKey.key) parts.push(activationKey.key.toUpperCase());
|
|
2210
|
+
return parts.length > 0 ? parts.join(" + ") : "Default (Option/Alt)";
|
|
2211
|
+
};
|
|
1813
2212
|
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(
|
|
1814
2213
|
"-a, --agent <agent>",
|
|
1815
2214
|
"agent integration (claude-code, cursor, opencode, codex, gemini, amp, visual-edit)"
|
|
@@ -1829,11 +2228,514 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
1829
2228
|
const projectInfo = await detectProject(cwd);
|
|
1830
2229
|
if (projectInfo.hasReactGrab && !opts.force) {
|
|
1831
2230
|
preflightSpinner.succeed();
|
|
2231
|
+
if (isNonInteractive) {
|
|
2232
|
+
logger.break();
|
|
2233
|
+
logger.warn("React Grab is already installed.");
|
|
2234
|
+
logger.log(
|
|
2235
|
+
`Use ${highlighter.info("--force")} to reconfigure, or remove ${highlighter.info("--yes")} for interactive mode.`
|
|
2236
|
+
);
|
|
2237
|
+
logger.break();
|
|
2238
|
+
process.exit(0);
|
|
2239
|
+
}
|
|
1832
2240
|
logger.break();
|
|
1833
|
-
logger.
|
|
1834
|
-
logger.
|
|
1835
|
-
|
|
2241
|
+
logger.success("React Grab is already installed.");
|
|
2242
|
+
logger.break();
|
|
2243
|
+
const allAgents = [
|
|
2244
|
+
"claude-code",
|
|
2245
|
+
"cursor",
|
|
2246
|
+
"opencode",
|
|
2247
|
+
"codex",
|
|
2248
|
+
"gemini",
|
|
2249
|
+
"amp",
|
|
2250
|
+
"visual-edit"
|
|
2251
|
+
];
|
|
2252
|
+
const availableAgents = allAgents.filter(
|
|
2253
|
+
(agent) => !projectInfo.installedAgents.includes(agent)
|
|
1836
2254
|
);
|
|
2255
|
+
if (projectInfo.installedAgents.length > 0) {
|
|
2256
|
+
const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES2[innerAgent] || innerAgent).join(", ");
|
|
2257
|
+
logger.log(
|
|
2258
|
+
`Currently installed agents: ${highlighter.info(installedNames)}`
|
|
2259
|
+
);
|
|
2260
|
+
logger.break();
|
|
2261
|
+
}
|
|
2262
|
+
let didAddAgent = false;
|
|
2263
|
+
if (availableAgents.length > 0) {
|
|
2264
|
+
const { wantAddAgent } = await prompts3({
|
|
2265
|
+
type: "confirm",
|
|
2266
|
+
name: "wantAddAgent",
|
|
2267
|
+
message: `Would you like to add an ${highlighter.info("agent integration")}?`,
|
|
2268
|
+
initial: true
|
|
2269
|
+
});
|
|
2270
|
+
if (wantAddAgent === void 0) {
|
|
2271
|
+
logger.break();
|
|
2272
|
+
process.exit(1);
|
|
2273
|
+
}
|
|
2274
|
+
if (wantAddAgent) {
|
|
2275
|
+
const { agent } = await prompts3({
|
|
2276
|
+
type: "select",
|
|
2277
|
+
name: "agent",
|
|
2278
|
+
message: `Which ${highlighter.info("agent integration")} would you like to add?`,
|
|
2279
|
+
choices: availableAgents.map((innerAgent) => ({
|
|
2280
|
+
title: AGENT_NAMES2[innerAgent],
|
|
2281
|
+
value: innerAgent
|
|
2282
|
+
}))
|
|
2283
|
+
});
|
|
2284
|
+
if (agent === void 0) {
|
|
2285
|
+
logger.break();
|
|
2286
|
+
process.exit(1);
|
|
2287
|
+
}
|
|
2288
|
+
const agentIntegration2 = agent;
|
|
2289
|
+
let agentsToRemove2 = [];
|
|
2290
|
+
if (projectInfo.installedAgents.length > 0) {
|
|
2291
|
+
const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES2[innerAgent] || innerAgent).join(", ");
|
|
2292
|
+
const { action } = await prompts3({
|
|
2293
|
+
type: "select",
|
|
2294
|
+
name: "action",
|
|
2295
|
+
message: "How would you like to proceed?",
|
|
2296
|
+
choices: [
|
|
2297
|
+
{
|
|
2298
|
+
title: `Replace ${installedNames} with ${AGENT_NAMES2[agentIntegration2]}`,
|
|
2299
|
+
value: "replace"
|
|
2300
|
+
},
|
|
2301
|
+
{
|
|
2302
|
+
title: `Add ${AGENT_NAMES2[agentIntegration2]} alongside existing`,
|
|
2303
|
+
value: "add"
|
|
2304
|
+
},
|
|
2305
|
+
{ title: "Cancel", value: "cancel" }
|
|
2306
|
+
]
|
|
2307
|
+
});
|
|
2308
|
+
if (!action || action === "cancel") {
|
|
2309
|
+
logger.break();
|
|
2310
|
+
logger.log("Agent addition cancelled.");
|
|
2311
|
+
} else {
|
|
2312
|
+
if (action === "replace") {
|
|
2313
|
+
agentsToRemove2 = [...projectInfo.installedAgents];
|
|
2314
|
+
}
|
|
2315
|
+
if (agentsToRemove2.length > 0) {
|
|
2316
|
+
for (const agentToRemove of agentsToRemove2) {
|
|
2317
|
+
const removalResult = previewAgentRemoval(
|
|
2318
|
+
projectInfo.projectRoot,
|
|
2319
|
+
projectInfo.framework,
|
|
2320
|
+
projectInfo.nextRouterType,
|
|
2321
|
+
agentToRemove
|
|
2322
|
+
);
|
|
2323
|
+
const removalPackageJsonResult = previewPackageJsonAgentRemoval(
|
|
2324
|
+
projectInfo.projectRoot,
|
|
2325
|
+
agentToRemove
|
|
2326
|
+
);
|
|
2327
|
+
const packagesToRemove = getPackagesToUninstall(agentToRemove);
|
|
2328
|
+
if (packagesToRemove.length > 0) {
|
|
2329
|
+
const uninstallSpinner = spinner(
|
|
2330
|
+
`Removing ${packagesToRemove.join(", ")}.`
|
|
2331
|
+
).start();
|
|
2332
|
+
try {
|
|
2333
|
+
uninstallPackages(
|
|
2334
|
+
packagesToRemove,
|
|
2335
|
+
projectInfo.packageManager,
|
|
2336
|
+
projectInfo.projectRoot
|
|
2337
|
+
);
|
|
2338
|
+
uninstallSpinner.succeed();
|
|
2339
|
+
} catch (error) {
|
|
2340
|
+
uninstallSpinner.fail();
|
|
2341
|
+
handleError(error);
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2344
|
+
if (removalResult.success && !removalResult.noChanges && removalResult.newContent) {
|
|
2345
|
+
const removeWriteSpinner = spinner(
|
|
2346
|
+
`Removing ${AGENT_NAMES2[agentToRemove] || agentToRemove} from ${removalResult.filePath}.`
|
|
2347
|
+
).start();
|
|
2348
|
+
const writeResult = applyTransform(removalResult);
|
|
2349
|
+
if (!writeResult.success) {
|
|
2350
|
+
removeWriteSpinner.fail();
|
|
2351
|
+
logger.break();
|
|
2352
|
+
logger.error(
|
|
2353
|
+
writeResult.error || "Failed to write file."
|
|
2354
|
+
);
|
|
2355
|
+
logger.break();
|
|
2356
|
+
process.exit(1);
|
|
2357
|
+
}
|
|
2358
|
+
removeWriteSpinner.succeed();
|
|
2359
|
+
}
|
|
2360
|
+
if (removalPackageJsonResult.success && !removalPackageJsonResult.noChanges && removalPackageJsonResult.newContent) {
|
|
2361
|
+
const removePackageJsonSpinner = spinner(
|
|
2362
|
+
`Removing ${AGENT_NAMES2[agentToRemove] || agentToRemove} from ${removalPackageJsonResult.filePath}.`
|
|
2363
|
+
).start();
|
|
2364
|
+
const packageJsonWriteResult = applyPackageJsonTransform(
|
|
2365
|
+
removalPackageJsonResult
|
|
2366
|
+
);
|
|
2367
|
+
if (!packageJsonWriteResult.success) {
|
|
2368
|
+
removePackageJsonSpinner.fail();
|
|
2369
|
+
logger.break();
|
|
2370
|
+
logger.error(
|
|
2371
|
+
packageJsonWriteResult.error || "Failed to write file."
|
|
2372
|
+
);
|
|
2373
|
+
logger.break();
|
|
2374
|
+
process.exit(1);
|
|
2375
|
+
}
|
|
2376
|
+
removePackageJsonSpinner.succeed();
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
projectInfo.installedAgents = projectInfo.installedAgents.filter(
|
|
2380
|
+
(innerAgent) => !agentsToRemove2.includes(innerAgent)
|
|
2381
|
+
);
|
|
2382
|
+
}
|
|
2383
|
+
const result2 = previewTransform(
|
|
2384
|
+
projectInfo.projectRoot,
|
|
2385
|
+
projectInfo.framework,
|
|
2386
|
+
projectInfo.nextRouterType,
|
|
2387
|
+
agentIntegration2,
|
|
2388
|
+
true
|
|
2389
|
+
);
|
|
2390
|
+
const packageJsonResult2 = previewPackageJsonTransform(
|
|
2391
|
+
projectInfo.projectRoot,
|
|
2392
|
+
agentIntegration2,
|
|
2393
|
+
projectInfo.installedAgents,
|
|
2394
|
+
projectInfo.packageManager
|
|
2395
|
+
);
|
|
2396
|
+
if (!result2.success) {
|
|
2397
|
+
logger.break();
|
|
2398
|
+
logger.error(result2.message);
|
|
2399
|
+
logger.break();
|
|
2400
|
+
process.exit(1);
|
|
2401
|
+
}
|
|
2402
|
+
const hasLayoutChanges2 = !result2.noChanges && result2.originalContent && result2.newContent;
|
|
2403
|
+
const hasPackageJsonChanges2 = packageJsonResult2.success && !packageJsonResult2.noChanges && packageJsonResult2.originalContent && packageJsonResult2.newContent;
|
|
2404
|
+
if (hasLayoutChanges2 || hasPackageJsonChanges2) {
|
|
2405
|
+
logger.break();
|
|
2406
|
+
if (hasLayoutChanges2) {
|
|
2407
|
+
printDiff(
|
|
2408
|
+
result2.filePath,
|
|
2409
|
+
result2.originalContent,
|
|
2410
|
+
result2.newContent
|
|
2411
|
+
);
|
|
2412
|
+
}
|
|
2413
|
+
if (hasPackageJsonChanges2) {
|
|
2414
|
+
if (hasLayoutChanges2) {
|
|
2415
|
+
logger.break();
|
|
2416
|
+
}
|
|
2417
|
+
printDiff(
|
|
2418
|
+
packageJsonResult2.filePath,
|
|
2419
|
+
packageJsonResult2.originalContent,
|
|
2420
|
+
packageJsonResult2.newContent
|
|
2421
|
+
);
|
|
2422
|
+
}
|
|
2423
|
+
if (agentsToRemove2.length === 0) {
|
|
2424
|
+
logger.break();
|
|
2425
|
+
const { proceed } = await prompts3({
|
|
2426
|
+
type: "confirm",
|
|
2427
|
+
name: "proceed",
|
|
2428
|
+
message: "Apply these changes?",
|
|
2429
|
+
initial: true
|
|
2430
|
+
});
|
|
2431
|
+
if (!proceed) {
|
|
2432
|
+
logger.break();
|
|
2433
|
+
logger.log("Agent addition cancelled.");
|
|
2434
|
+
} else {
|
|
2435
|
+
const packages = getPackagesToInstall(
|
|
2436
|
+
agentIntegration2,
|
|
2437
|
+
false
|
|
2438
|
+
);
|
|
2439
|
+
if (packages.length > 0) {
|
|
2440
|
+
const installSpinner = spinner(
|
|
2441
|
+
`Installing ${packages.join(", ")}.`
|
|
2442
|
+
).start();
|
|
2443
|
+
try {
|
|
2444
|
+
installPackages(
|
|
2445
|
+
packages,
|
|
2446
|
+
projectInfo.packageManager,
|
|
2447
|
+
projectInfo.projectRoot
|
|
2448
|
+
);
|
|
2449
|
+
installSpinner.succeed();
|
|
2450
|
+
} catch (error) {
|
|
2451
|
+
installSpinner.fail();
|
|
2452
|
+
handleError(error);
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
if (hasLayoutChanges2) {
|
|
2456
|
+
const writeSpinner = spinner(
|
|
2457
|
+
`Applying changes to ${result2.filePath}.`
|
|
2458
|
+
).start();
|
|
2459
|
+
const writeResult = applyTransform(result2);
|
|
2460
|
+
if (!writeResult.success) {
|
|
2461
|
+
writeSpinner.fail();
|
|
2462
|
+
logger.break();
|
|
2463
|
+
logger.error(
|
|
2464
|
+
writeResult.error || "Failed to write file."
|
|
2465
|
+
);
|
|
2466
|
+
logger.break();
|
|
2467
|
+
process.exit(1);
|
|
2468
|
+
}
|
|
2469
|
+
writeSpinner.succeed();
|
|
2470
|
+
}
|
|
2471
|
+
if (hasPackageJsonChanges2) {
|
|
2472
|
+
const packageJsonSpinner = spinner(
|
|
2473
|
+
`Applying changes to ${packageJsonResult2.filePath}.`
|
|
2474
|
+
).start();
|
|
2475
|
+
const packageJsonWriteResult = applyPackageJsonTransform(packageJsonResult2);
|
|
2476
|
+
if (!packageJsonWriteResult.success) {
|
|
2477
|
+
packageJsonSpinner.fail();
|
|
2478
|
+
logger.break();
|
|
2479
|
+
logger.error(
|
|
2480
|
+
packageJsonWriteResult.error || "Failed to write file."
|
|
2481
|
+
);
|
|
2482
|
+
logger.break();
|
|
2483
|
+
process.exit(1);
|
|
2484
|
+
}
|
|
2485
|
+
packageJsonSpinner.succeed();
|
|
2486
|
+
}
|
|
2487
|
+
didAddAgent = true;
|
|
2488
|
+
logger.break();
|
|
2489
|
+
logger.success(
|
|
2490
|
+
`${AGENT_NAMES2[agentIntegration2]} has been added.`
|
|
2491
|
+
);
|
|
2492
|
+
}
|
|
2493
|
+
} else {
|
|
2494
|
+
const packages = getPackagesToInstall(
|
|
2495
|
+
agentIntegration2,
|
|
2496
|
+
false
|
|
2497
|
+
);
|
|
2498
|
+
if (packages.length > 0) {
|
|
2499
|
+
const installSpinner = spinner(
|
|
2500
|
+
`Installing ${packages.join(", ")}.`
|
|
2501
|
+
).start();
|
|
2502
|
+
try {
|
|
2503
|
+
installPackages(
|
|
2504
|
+
packages,
|
|
2505
|
+
projectInfo.packageManager,
|
|
2506
|
+
projectInfo.projectRoot
|
|
2507
|
+
);
|
|
2508
|
+
installSpinner.succeed();
|
|
2509
|
+
} catch (error) {
|
|
2510
|
+
installSpinner.fail();
|
|
2511
|
+
handleError(error);
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
if (hasLayoutChanges2) {
|
|
2515
|
+
const writeSpinner = spinner(
|
|
2516
|
+
`Applying changes to ${result2.filePath}.`
|
|
2517
|
+
).start();
|
|
2518
|
+
const writeResult = applyTransform(result2);
|
|
2519
|
+
if (!writeResult.success) {
|
|
2520
|
+
writeSpinner.fail();
|
|
2521
|
+
logger.break();
|
|
2522
|
+
logger.error(
|
|
2523
|
+
writeResult.error || "Failed to write file."
|
|
2524
|
+
);
|
|
2525
|
+
logger.break();
|
|
2526
|
+
process.exit(1);
|
|
2527
|
+
}
|
|
2528
|
+
writeSpinner.succeed();
|
|
2529
|
+
}
|
|
2530
|
+
if (hasPackageJsonChanges2) {
|
|
2531
|
+
const packageJsonSpinner = spinner(
|
|
2532
|
+
`Applying changes to ${packageJsonResult2.filePath}.`
|
|
2533
|
+
).start();
|
|
2534
|
+
const packageJsonWriteResult = applyPackageJsonTransform(packageJsonResult2);
|
|
2535
|
+
if (!packageJsonWriteResult.success) {
|
|
2536
|
+
packageJsonSpinner.fail();
|
|
2537
|
+
logger.break();
|
|
2538
|
+
logger.error(
|
|
2539
|
+
packageJsonWriteResult.error || "Failed to write file."
|
|
2540
|
+
);
|
|
2541
|
+
logger.break();
|
|
2542
|
+
process.exit(1);
|
|
2543
|
+
}
|
|
2544
|
+
packageJsonSpinner.succeed();
|
|
2545
|
+
}
|
|
2546
|
+
didAddAgent = true;
|
|
2547
|
+
logger.break();
|
|
2548
|
+
logger.success(
|
|
2549
|
+
`${AGENT_NAMES2[agentIntegration2]} has been added.`
|
|
2550
|
+
);
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
} else {
|
|
2557
|
+
logger.log("All agent integrations are already installed.");
|
|
2558
|
+
}
|
|
2559
|
+
logger.break();
|
|
2560
|
+
const { wantCustomizeOptions } = await prompts3({
|
|
2561
|
+
type: "confirm",
|
|
2562
|
+
name: "wantCustomizeOptions",
|
|
2563
|
+
message: `Would you like to customize ${highlighter.info("options")}?`,
|
|
2564
|
+
initial: false
|
|
2565
|
+
});
|
|
2566
|
+
if (wantCustomizeOptions === void 0) {
|
|
2567
|
+
logger.break();
|
|
2568
|
+
process.exit(1);
|
|
2569
|
+
}
|
|
2570
|
+
if (wantCustomizeOptions) {
|
|
2571
|
+
logger.break();
|
|
2572
|
+
logger.log(`Configure ${highlighter.info("React Grab")} options:`);
|
|
2573
|
+
logger.break();
|
|
2574
|
+
const collectedOptions = {};
|
|
2575
|
+
const { wantActivationKey } = await prompts3({
|
|
2576
|
+
type: "confirm",
|
|
2577
|
+
name: "wantActivationKey",
|
|
2578
|
+
message: `Configure ${highlighter.info("activation key")}?`,
|
|
2579
|
+
initial: false
|
|
2580
|
+
});
|
|
2581
|
+
if (wantActivationKey === void 0) {
|
|
2582
|
+
logger.break();
|
|
2583
|
+
process.exit(1);
|
|
2584
|
+
}
|
|
2585
|
+
if (wantActivationKey) {
|
|
2586
|
+
const { key } = await prompts3({
|
|
2587
|
+
type: "text",
|
|
2588
|
+
name: "key",
|
|
2589
|
+
message: "Enter the activation key (e.g., g, k, space):",
|
|
2590
|
+
initial: ""
|
|
2591
|
+
});
|
|
2592
|
+
if (key === void 0) {
|
|
2593
|
+
logger.break();
|
|
2594
|
+
process.exit(1);
|
|
2595
|
+
}
|
|
2596
|
+
const { modifiers } = await prompts3({
|
|
2597
|
+
type: "multiselect",
|
|
2598
|
+
name: "modifiers",
|
|
2599
|
+
message: "Select modifier keys (space to select, enter to confirm):",
|
|
2600
|
+
choices: [
|
|
2601
|
+
{ title: MODIFIER_KEY_NAMES2.metaKey, value: "metaKey" },
|
|
2602
|
+
{ title: MODIFIER_KEY_NAMES2.ctrlKey, value: "ctrlKey" },
|
|
2603
|
+
{ title: MODIFIER_KEY_NAMES2.shiftKey, value: "shiftKey" },
|
|
2604
|
+
{
|
|
2605
|
+
title: MODIFIER_KEY_NAMES2.altKey,
|
|
2606
|
+
value: "altKey",
|
|
2607
|
+
selected: true
|
|
2608
|
+
}
|
|
2609
|
+
],
|
|
2610
|
+
hint: "- Space to select, Enter to confirm"
|
|
2611
|
+
});
|
|
2612
|
+
if (modifiers === void 0) {
|
|
2613
|
+
logger.break();
|
|
2614
|
+
process.exit(1);
|
|
2615
|
+
}
|
|
2616
|
+
collectedOptions.activationKey = {
|
|
2617
|
+
...key && { key: key.toLowerCase() },
|
|
2618
|
+
...modifiers.includes("metaKey") && { metaKey: true },
|
|
2619
|
+
...modifiers.includes("ctrlKey") && { ctrlKey: true },
|
|
2620
|
+
...modifiers.includes("shiftKey") && { shiftKey: true },
|
|
2621
|
+
...modifiers.includes("altKey") && { altKey: true }
|
|
2622
|
+
};
|
|
2623
|
+
logger.log(
|
|
2624
|
+
` Activation key: ${highlighter.info(formatActivationKey2(collectedOptions.activationKey))}`
|
|
2625
|
+
);
|
|
2626
|
+
}
|
|
2627
|
+
const { activationMode } = await prompts3({
|
|
2628
|
+
type: "select",
|
|
2629
|
+
name: "activationMode",
|
|
2630
|
+
message: `Select ${highlighter.info("activation mode")}:`,
|
|
2631
|
+
choices: [
|
|
2632
|
+
{
|
|
2633
|
+
title: "Toggle (press to activate/deactivate)",
|
|
2634
|
+
value: "toggle"
|
|
2635
|
+
},
|
|
2636
|
+
{ title: "Hold (hold key to keep active)", value: "hold" }
|
|
2637
|
+
],
|
|
2638
|
+
initial: 0
|
|
2639
|
+
});
|
|
2640
|
+
if (activationMode === void 0) {
|
|
2641
|
+
logger.break();
|
|
2642
|
+
process.exit(1);
|
|
2643
|
+
}
|
|
2644
|
+
collectedOptions.activationMode = activationMode;
|
|
2645
|
+
if (activationMode === "hold") {
|
|
2646
|
+
const { keyHoldDuration } = await prompts3({
|
|
2647
|
+
type: "number",
|
|
2648
|
+
name: "keyHoldDuration",
|
|
2649
|
+
message: `Enter ${highlighter.info("key hold duration")} in milliseconds:`,
|
|
2650
|
+
initial: 150,
|
|
2651
|
+
min: 0,
|
|
2652
|
+
max: 2e3
|
|
2653
|
+
});
|
|
2654
|
+
if (keyHoldDuration === void 0) {
|
|
2655
|
+
logger.break();
|
|
2656
|
+
process.exit(1);
|
|
2657
|
+
}
|
|
2658
|
+
collectedOptions.keyHoldDuration = keyHoldDuration;
|
|
2659
|
+
}
|
|
2660
|
+
const { allowActivationInsideInput } = await prompts3({
|
|
2661
|
+
type: "confirm",
|
|
2662
|
+
name: "allowActivationInsideInput",
|
|
2663
|
+
message: `Allow activation ${highlighter.info("inside input fields")}?`,
|
|
2664
|
+
initial: true
|
|
2665
|
+
});
|
|
2666
|
+
if (allowActivationInsideInput === void 0) {
|
|
2667
|
+
logger.break();
|
|
2668
|
+
process.exit(1);
|
|
2669
|
+
}
|
|
2670
|
+
collectedOptions.allowActivationInsideInput = allowActivationInsideInput;
|
|
2671
|
+
const { maxContextLines } = await prompts3({
|
|
2672
|
+
type: "number",
|
|
2673
|
+
name: "maxContextLines",
|
|
2674
|
+
message: `Enter ${highlighter.info("max context lines")} to include:`,
|
|
2675
|
+
initial: 3,
|
|
2676
|
+
min: 0,
|
|
2677
|
+
max: 50
|
|
2678
|
+
});
|
|
2679
|
+
if (maxContextLines === void 0) {
|
|
2680
|
+
logger.break();
|
|
2681
|
+
process.exit(1);
|
|
2682
|
+
}
|
|
2683
|
+
collectedOptions.maxContextLines = maxContextLines;
|
|
2684
|
+
const optionsResult = previewOptionsTransform(
|
|
2685
|
+
projectInfo.projectRoot,
|
|
2686
|
+
projectInfo.framework,
|
|
2687
|
+
projectInfo.nextRouterType,
|
|
2688
|
+
collectedOptions
|
|
2689
|
+
);
|
|
2690
|
+
if (!optionsResult.success) {
|
|
2691
|
+
logger.break();
|
|
2692
|
+
logger.error(optionsResult.message);
|
|
2693
|
+
logger.break();
|
|
2694
|
+
process.exit(1);
|
|
2695
|
+
}
|
|
2696
|
+
const hasOptionsChanges = !optionsResult.noChanges && optionsResult.originalContent && optionsResult.newContent;
|
|
2697
|
+
if (hasOptionsChanges) {
|
|
2698
|
+
logger.break();
|
|
2699
|
+
printDiff(
|
|
2700
|
+
optionsResult.filePath,
|
|
2701
|
+
optionsResult.originalContent,
|
|
2702
|
+
optionsResult.newContent
|
|
2703
|
+
);
|
|
2704
|
+
logger.break();
|
|
2705
|
+
const { proceed } = await prompts3({
|
|
2706
|
+
type: "confirm",
|
|
2707
|
+
name: "proceed",
|
|
2708
|
+
message: "Apply these changes?",
|
|
2709
|
+
initial: true
|
|
2710
|
+
});
|
|
2711
|
+
if (!proceed) {
|
|
2712
|
+
logger.break();
|
|
2713
|
+
logger.log("Options configuration cancelled.");
|
|
2714
|
+
} else {
|
|
2715
|
+
const writeSpinner = spinner(
|
|
2716
|
+
`Applying changes to ${optionsResult.filePath}.`
|
|
2717
|
+
).start();
|
|
2718
|
+
const writeResult = applyOptionsTransform(optionsResult);
|
|
2719
|
+
if (!writeResult.success) {
|
|
2720
|
+
writeSpinner.fail();
|
|
2721
|
+
logger.break();
|
|
2722
|
+
logger.error(writeResult.error || "Failed to write file.");
|
|
2723
|
+
logger.break();
|
|
2724
|
+
process.exit(1);
|
|
2725
|
+
}
|
|
2726
|
+
writeSpinner.succeed();
|
|
2727
|
+
logger.break();
|
|
2728
|
+
logger.success("React Grab options have been configured.");
|
|
2729
|
+
}
|
|
2730
|
+
} else {
|
|
2731
|
+
logger.break();
|
|
2732
|
+
logger.log("No option changes needed.");
|
|
2733
|
+
}
|
|
2734
|
+
}
|
|
2735
|
+
if (!didAddAgent && !wantCustomizeOptions) {
|
|
2736
|
+
logger.break();
|
|
2737
|
+
logger.log("No changes made.");
|
|
2738
|
+
}
|
|
1837
2739
|
logger.break();
|
|
1838
2740
|
process.exit(0);
|
|
1839
2741
|
}
|
|
@@ -1868,7 +2770,7 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
1868
2770
|
return 0;
|
|
1869
2771
|
}
|
|
1870
2772
|
);
|
|
1871
|
-
const { selectedProject } = await
|
|
2773
|
+
const { selectedProject } = await prompts3({
|
|
1872
2774
|
type: "select",
|
|
1873
2775
|
name: "selectedProject",
|
|
1874
2776
|
message: "Select a project to install React Grab:",
|
|
@@ -1929,9 +2831,15 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
1929
2831
|
let finalPackageManager = projectInfo.packageManager;
|
|
1930
2832
|
let finalNextRouterType = projectInfo.nextRouterType;
|
|
1931
2833
|
let agentIntegration = opts.agent || "none";
|
|
2834
|
+
let agentsToRemove = [];
|
|
1932
2835
|
if (!isNonInteractive && !opts.agent) {
|
|
1933
2836
|
logger.break();
|
|
1934
|
-
|
|
2837
|
+
if (opts.force && projectInfo.installedAgents.length > 0) {
|
|
2838
|
+
const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES2[innerAgent] || innerAgent).join(", ");
|
|
2839
|
+
logger.warn(`Currently installed: ${installedNames}`);
|
|
2840
|
+
logger.break();
|
|
2841
|
+
}
|
|
2842
|
+
const { agent } = await prompts3({
|
|
1935
2843
|
type: "select",
|
|
1936
2844
|
name: "agent",
|
|
1937
2845
|
message: `Would you like to add an ${highlighter.info("agent integration")}?`,
|
|
@@ -1951,6 +2859,63 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
1951
2859
|
process.exit(1);
|
|
1952
2860
|
}
|
|
1953
2861
|
agentIntegration = agent;
|
|
2862
|
+
if (opts.force && projectInfo.installedAgents.length > 0 && agentIntegration !== "none" && !projectInfo.installedAgents.includes(agentIntegration)) {
|
|
2863
|
+
const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES2[innerAgent] || innerAgent).join(", ");
|
|
2864
|
+
const { action } = await prompts3({
|
|
2865
|
+
type: "select",
|
|
2866
|
+
name: "action",
|
|
2867
|
+
message: "How would you like to proceed?",
|
|
2868
|
+
choices: [
|
|
2869
|
+
{
|
|
2870
|
+
title: `Replace ${installedNames} with ${AGENT_NAMES2[agentIntegration]}`,
|
|
2871
|
+
value: "replace"
|
|
2872
|
+
},
|
|
2873
|
+
{
|
|
2874
|
+
title: `Add ${AGENT_NAMES2[agentIntegration]} alongside existing`,
|
|
2875
|
+
value: "add"
|
|
2876
|
+
},
|
|
2877
|
+
{ title: "Cancel", value: "cancel" }
|
|
2878
|
+
]
|
|
2879
|
+
});
|
|
2880
|
+
if (!action || action === "cancel") {
|
|
2881
|
+
logger.break();
|
|
2882
|
+
logger.log("Changes cancelled.");
|
|
2883
|
+
logger.break();
|
|
2884
|
+
process.exit(0);
|
|
2885
|
+
}
|
|
2886
|
+
if (action === "replace") {
|
|
2887
|
+
agentsToRemove = [...projectInfo.installedAgents];
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
} else if (opts.agent && opts.force && projectInfo.installedAgents.length > 0 && !projectInfo.installedAgents.includes(opts.agent) && !isNonInteractive) {
|
|
2891
|
+
const installedNames = projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES2[innerAgent] || innerAgent).join(", ");
|
|
2892
|
+
logger.break();
|
|
2893
|
+
logger.warn(`Currently installed: ${installedNames}`);
|
|
2894
|
+
const { action } = await prompts3({
|
|
2895
|
+
type: "select",
|
|
2896
|
+
name: "action",
|
|
2897
|
+
message: "How would you like to proceed?",
|
|
2898
|
+
choices: [
|
|
2899
|
+
{
|
|
2900
|
+
title: `Replace ${installedNames} with ${AGENT_NAMES2[agentIntegration]}`,
|
|
2901
|
+
value: "replace"
|
|
2902
|
+
},
|
|
2903
|
+
{
|
|
2904
|
+
title: `Add ${AGENT_NAMES2[agentIntegration]} alongside existing`,
|
|
2905
|
+
value: "add"
|
|
2906
|
+
},
|
|
2907
|
+
{ title: "Cancel", value: "cancel" }
|
|
2908
|
+
]
|
|
2909
|
+
});
|
|
2910
|
+
if (!action || action === "cancel") {
|
|
2911
|
+
logger.break();
|
|
2912
|
+
logger.log("Changes cancelled.");
|
|
2913
|
+
logger.break();
|
|
2914
|
+
process.exit(0);
|
|
2915
|
+
}
|
|
2916
|
+
if (action === "replace") {
|
|
2917
|
+
agentsToRemove = [...projectInfo.installedAgents];
|
|
2918
|
+
}
|
|
1954
2919
|
}
|
|
1955
2920
|
const result = previewTransform(
|
|
1956
2921
|
projectInfo.projectRoot,
|
|
@@ -1962,7 +2927,8 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
1962
2927
|
const packageJsonResult = previewPackageJsonTransform(
|
|
1963
2928
|
projectInfo.projectRoot,
|
|
1964
2929
|
agentIntegration,
|
|
1965
|
-
projectInfo.installedAgents
|
|
2930
|
+
projectInfo.installedAgents,
|
|
2931
|
+
finalPackageManager
|
|
1966
2932
|
);
|
|
1967
2933
|
if (!result.success) {
|
|
1968
2934
|
logger.break();
|
|
@@ -1997,7 +2963,7 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
1997
2963
|
logger.warn("Please verify the changes before committing.");
|
|
1998
2964
|
if (!isNonInteractive) {
|
|
1999
2965
|
logger.break();
|
|
2000
|
-
const { proceed } = await
|
|
2966
|
+
const { proceed } = await prompts3({
|
|
2001
2967
|
type: "confirm",
|
|
2002
2968
|
name: "proceed",
|
|
2003
2969
|
message: "Apply these changes?",
|
|
@@ -2011,6 +2977,72 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
2011
2977
|
}
|
|
2012
2978
|
}
|
|
2013
2979
|
}
|
|
2980
|
+
if (agentsToRemove.length > 0) {
|
|
2981
|
+
for (const agentToRemove of agentsToRemove) {
|
|
2982
|
+
const removalResult = previewAgentRemoval(
|
|
2983
|
+
projectInfo.projectRoot,
|
|
2984
|
+
projectInfo.framework,
|
|
2985
|
+
projectInfo.nextRouterType,
|
|
2986
|
+
agentToRemove
|
|
2987
|
+
);
|
|
2988
|
+
const removalPackageJsonResult = previewPackageJsonAgentRemoval(
|
|
2989
|
+
projectInfo.projectRoot,
|
|
2990
|
+
agentToRemove
|
|
2991
|
+
);
|
|
2992
|
+
const packagesToRemove = getPackagesToUninstall(agentToRemove);
|
|
2993
|
+
if (packagesToRemove.length > 0 && !opts.skipInstall) {
|
|
2994
|
+
const uninstallSpinner = spinner(
|
|
2995
|
+
`Removing ${packagesToRemove.join(", ")}.`
|
|
2996
|
+
).start();
|
|
2997
|
+
try {
|
|
2998
|
+
uninstallPackages(
|
|
2999
|
+
packagesToRemove,
|
|
3000
|
+
finalPackageManager,
|
|
3001
|
+
projectInfo.projectRoot
|
|
3002
|
+
);
|
|
3003
|
+
uninstallSpinner.succeed();
|
|
3004
|
+
} catch (error) {
|
|
3005
|
+
uninstallSpinner.fail();
|
|
3006
|
+
handleError(error);
|
|
3007
|
+
}
|
|
3008
|
+
}
|
|
3009
|
+
if (removalResult.success && !removalResult.noChanges && removalResult.newContent) {
|
|
3010
|
+
const removeWriteSpinner = spinner(
|
|
3011
|
+
`Removing ${AGENT_NAMES2[agentToRemove] || agentToRemove} from ${removalResult.filePath}.`
|
|
3012
|
+
).start();
|
|
3013
|
+
const writeResult = applyTransform(removalResult);
|
|
3014
|
+
if (!writeResult.success) {
|
|
3015
|
+
removeWriteSpinner.fail();
|
|
3016
|
+
logger.break();
|
|
3017
|
+
logger.error(writeResult.error || "Failed to write file.");
|
|
3018
|
+
logger.break();
|
|
3019
|
+
process.exit(1);
|
|
3020
|
+
}
|
|
3021
|
+
removeWriteSpinner.succeed();
|
|
3022
|
+
}
|
|
3023
|
+
if (removalPackageJsonResult.success && !removalPackageJsonResult.noChanges && removalPackageJsonResult.newContent) {
|
|
3024
|
+
const removePackageJsonSpinner = spinner(
|
|
3025
|
+
`Removing ${AGENT_NAMES2[agentToRemove] || agentToRemove} from ${removalPackageJsonResult.filePath}.`
|
|
3026
|
+
).start();
|
|
3027
|
+
const packageJsonWriteResult = applyPackageJsonTransform(
|
|
3028
|
+
removalPackageJsonResult
|
|
3029
|
+
);
|
|
3030
|
+
if (!packageJsonWriteResult.success) {
|
|
3031
|
+
removePackageJsonSpinner.fail();
|
|
3032
|
+
logger.break();
|
|
3033
|
+
logger.error(
|
|
3034
|
+
packageJsonWriteResult.error || "Failed to write file."
|
|
3035
|
+
);
|
|
3036
|
+
logger.break();
|
|
3037
|
+
process.exit(1);
|
|
3038
|
+
}
|
|
3039
|
+
removePackageJsonSpinner.succeed();
|
|
3040
|
+
}
|
|
3041
|
+
}
|
|
3042
|
+
projectInfo.installedAgents = projectInfo.installedAgents.filter(
|
|
3043
|
+
(innerAgent) => !agentsToRemove.includes(innerAgent)
|
|
3044
|
+
);
|
|
3045
|
+
}
|
|
2014
3046
|
const shouldInstallReactGrab = !projectInfo.hasReactGrab;
|
|
2015
3047
|
const shouldInstallAgent = agentIntegration !== "none" && !projectInfo.installedAgents.includes(agentIntegration);
|
|
2016
3048
|
if (!opts.skipInstall && (shouldInstallReactGrab || shouldInstallAgent)) {
|
|
@@ -2068,7 +3100,9 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
2068
3100
|
`${highlighter.success("Success!")} React Grab has been installed.`
|
|
2069
3101
|
);
|
|
2070
3102
|
if (packageJsonResult.warning) {
|
|
3103
|
+
logger.break();
|
|
2071
3104
|
logger.warn(packageJsonResult.warning);
|
|
3105
|
+
logger.break();
|
|
2072
3106
|
} else {
|
|
2073
3107
|
logger.log("You may now start your development server.");
|
|
2074
3108
|
}
|
|
@@ -2085,7 +3119,194 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
2085
3119
|
await reportToCli("error", void 0, error);
|
|
2086
3120
|
}
|
|
2087
3121
|
});
|
|
2088
|
-
var VERSION4 = "0.0.
|
|
3122
|
+
var VERSION4 = "0.0.92";
|
|
3123
|
+
var AGENT_NAMES3 = {
|
|
3124
|
+
"claude-code": "Claude Code",
|
|
3125
|
+
cursor: "Cursor",
|
|
3126
|
+
opencode: "OpenCode",
|
|
3127
|
+
codex: "Codex",
|
|
3128
|
+
gemini: "Gemini",
|
|
3129
|
+
amp: "Amp",
|
|
3130
|
+
ami: "Ami",
|
|
3131
|
+
"visual-edit": "Visual Edit"
|
|
3132
|
+
};
|
|
3133
|
+
var remove = new Command().name("remove").description("remove an agent integration").argument(
|
|
3134
|
+
"[agent]",
|
|
3135
|
+
"agent to remove (claude-code, cursor, opencode, codex, gemini, amp, ami, visual-edit)"
|
|
3136
|
+
).option("-y, --yes", "skip confirmation prompts", false).option(
|
|
3137
|
+
"-c, --cwd <cwd>",
|
|
3138
|
+
"working directory (defaults to current directory)",
|
|
3139
|
+
process.cwd()
|
|
3140
|
+
).action(async (agentArg, opts) => {
|
|
3141
|
+
console.log(
|
|
3142
|
+
`${pc.magenta("\u273F")} ${pc.bold("React Grab")} ${pc.gray(VERSION4)}`
|
|
3143
|
+
);
|
|
3144
|
+
console.log();
|
|
3145
|
+
try {
|
|
3146
|
+
const cwd = opts.cwd;
|
|
3147
|
+
const isNonInteractive = opts.yes;
|
|
3148
|
+
const preflightSpinner = spinner("Preflight checks.").start();
|
|
3149
|
+
const projectInfo = await detectProject(cwd);
|
|
3150
|
+
if (!projectInfo.hasReactGrab) {
|
|
3151
|
+
preflightSpinner.fail("React Grab is not installed.");
|
|
3152
|
+
logger.break();
|
|
3153
|
+
logger.error(
|
|
3154
|
+
`Run ${highlighter.info("react-grab init")} first to install React Grab.`
|
|
3155
|
+
);
|
|
3156
|
+
logger.break();
|
|
3157
|
+
process.exit(1);
|
|
3158
|
+
}
|
|
3159
|
+
if (projectInfo.installedAgents.length === 0) {
|
|
3160
|
+
preflightSpinner.succeed();
|
|
3161
|
+
logger.break();
|
|
3162
|
+
logger.warn("No agent integrations are installed.");
|
|
3163
|
+
logger.break();
|
|
3164
|
+
process.exit(0);
|
|
3165
|
+
}
|
|
3166
|
+
preflightSpinner.succeed();
|
|
3167
|
+
let agentToRemove;
|
|
3168
|
+
if (agentArg) {
|
|
3169
|
+
if (!projectInfo.installedAgents.includes(agentArg)) {
|
|
3170
|
+
logger.break();
|
|
3171
|
+
logger.error(`Agent ${highlighter.info(agentArg)} is not installed.`);
|
|
3172
|
+
logger.log(
|
|
3173
|
+
`Installed agents: ${projectInfo.installedAgents.map((innerAgent) => AGENT_NAMES3[innerAgent] || innerAgent).join(", ")}`
|
|
3174
|
+
);
|
|
3175
|
+
logger.break();
|
|
3176
|
+
process.exit(1);
|
|
3177
|
+
}
|
|
3178
|
+
agentToRemove = agentArg;
|
|
3179
|
+
} else if (!isNonInteractive) {
|
|
3180
|
+
logger.break();
|
|
3181
|
+
const { agent } = await prompts3({
|
|
3182
|
+
type: "select",
|
|
3183
|
+
name: "agent",
|
|
3184
|
+
message: `Which ${highlighter.info("agent integration")} would you like to remove?`,
|
|
3185
|
+
choices: projectInfo.installedAgents.map((innerAgent) => ({
|
|
3186
|
+
title: AGENT_NAMES3[innerAgent] || innerAgent,
|
|
3187
|
+
value: innerAgent
|
|
3188
|
+
}))
|
|
3189
|
+
});
|
|
3190
|
+
if (!agent) {
|
|
3191
|
+
logger.break();
|
|
3192
|
+
process.exit(1);
|
|
3193
|
+
}
|
|
3194
|
+
agentToRemove = agent;
|
|
3195
|
+
} else {
|
|
3196
|
+
logger.break();
|
|
3197
|
+
logger.error("Please specify an agent to remove.");
|
|
3198
|
+
logger.error(
|
|
3199
|
+
"Installed agents: " + projectInfo.installedAgents.join(", ")
|
|
3200
|
+
);
|
|
3201
|
+
logger.break();
|
|
3202
|
+
process.exit(1);
|
|
3203
|
+
}
|
|
3204
|
+
const removingSpinner = spinner(
|
|
3205
|
+
`Preparing to remove ${AGENT_NAMES3[agentToRemove] || agentToRemove}.`
|
|
3206
|
+
).start();
|
|
3207
|
+
removingSpinner.succeed();
|
|
3208
|
+
const result = previewAgentRemoval(
|
|
3209
|
+
projectInfo.projectRoot,
|
|
3210
|
+
projectInfo.framework,
|
|
3211
|
+
projectInfo.nextRouterType,
|
|
3212
|
+
agentToRemove
|
|
3213
|
+
);
|
|
3214
|
+
const packageJsonResult = previewPackageJsonAgentRemoval(
|
|
3215
|
+
projectInfo.projectRoot,
|
|
3216
|
+
agentToRemove
|
|
3217
|
+
);
|
|
3218
|
+
const hasLayoutChanges = result.success && !result.noChanges && result.originalContent && result.newContent;
|
|
3219
|
+
const hasPackageJsonChanges = packageJsonResult.success && !packageJsonResult.noChanges && packageJsonResult.originalContent && packageJsonResult.newContent;
|
|
3220
|
+
if (hasLayoutChanges || hasPackageJsonChanges) {
|
|
3221
|
+
logger.break();
|
|
3222
|
+
if (hasLayoutChanges) {
|
|
3223
|
+
printDiff(
|
|
3224
|
+
result.filePath,
|
|
3225
|
+
result.originalContent,
|
|
3226
|
+
result.newContent
|
|
3227
|
+
);
|
|
3228
|
+
}
|
|
3229
|
+
if (hasPackageJsonChanges) {
|
|
3230
|
+
if (hasLayoutChanges) {
|
|
3231
|
+
logger.break();
|
|
3232
|
+
}
|
|
3233
|
+
printDiff(
|
|
3234
|
+
packageJsonResult.filePath,
|
|
3235
|
+
packageJsonResult.originalContent,
|
|
3236
|
+
packageJsonResult.newContent
|
|
3237
|
+
);
|
|
3238
|
+
}
|
|
3239
|
+
if (!isNonInteractive) {
|
|
3240
|
+
logger.break();
|
|
3241
|
+
const { proceed } = await prompts3({
|
|
3242
|
+
type: "confirm",
|
|
3243
|
+
name: "proceed",
|
|
3244
|
+
message: "Apply these changes?",
|
|
3245
|
+
initial: true
|
|
3246
|
+
});
|
|
3247
|
+
if (!proceed) {
|
|
3248
|
+
logger.break();
|
|
3249
|
+
logger.log("Changes cancelled.");
|
|
3250
|
+
logger.break();
|
|
3251
|
+
process.exit(0);
|
|
3252
|
+
}
|
|
3253
|
+
}
|
|
3254
|
+
}
|
|
3255
|
+
const packages = getPackagesToUninstall(agentToRemove);
|
|
3256
|
+
if (packages.length > 0) {
|
|
3257
|
+
const uninstallSpinner = spinner(
|
|
3258
|
+
`Removing ${packages.join(", ")}.`
|
|
3259
|
+
).start();
|
|
3260
|
+
try {
|
|
3261
|
+
uninstallPackages(
|
|
3262
|
+
packages,
|
|
3263
|
+
projectInfo.packageManager,
|
|
3264
|
+
projectInfo.projectRoot
|
|
3265
|
+
);
|
|
3266
|
+
uninstallSpinner.succeed();
|
|
3267
|
+
} catch (error) {
|
|
3268
|
+
uninstallSpinner.fail();
|
|
3269
|
+
handleError(error);
|
|
3270
|
+
}
|
|
3271
|
+
}
|
|
3272
|
+
if (hasLayoutChanges) {
|
|
3273
|
+
const writeSpinner = spinner(
|
|
3274
|
+
`Applying changes to ${result.filePath}.`
|
|
3275
|
+
).start();
|
|
3276
|
+
const writeResult = applyTransform(result);
|
|
3277
|
+
if (!writeResult.success) {
|
|
3278
|
+
writeSpinner.fail();
|
|
3279
|
+
logger.break();
|
|
3280
|
+
logger.error(writeResult.error || "Failed to write file.");
|
|
3281
|
+
logger.break();
|
|
3282
|
+
process.exit(1);
|
|
3283
|
+
}
|
|
3284
|
+
writeSpinner.succeed();
|
|
3285
|
+
}
|
|
3286
|
+
if (hasPackageJsonChanges) {
|
|
3287
|
+
const packageJsonSpinner = spinner(
|
|
3288
|
+
`Applying changes to ${packageJsonResult.filePath}.`
|
|
3289
|
+
).start();
|
|
3290
|
+
const packageJsonWriteResult = applyPackageJsonTransform(packageJsonResult);
|
|
3291
|
+
if (!packageJsonWriteResult.success) {
|
|
3292
|
+
packageJsonSpinner.fail();
|
|
3293
|
+
logger.break();
|
|
3294
|
+
logger.error(packageJsonWriteResult.error || "Failed to write file.");
|
|
3295
|
+
logger.break();
|
|
3296
|
+
process.exit(1);
|
|
3297
|
+
}
|
|
3298
|
+
packageJsonSpinner.succeed();
|
|
3299
|
+
}
|
|
3300
|
+
logger.break();
|
|
3301
|
+
logger.log(
|
|
3302
|
+
`${highlighter.success("Success!")} ${AGENT_NAMES3[agentToRemove] || agentToRemove} has been removed.`
|
|
3303
|
+
);
|
|
3304
|
+
logger.break();
|
|
3305
|
+
} catch (error) {
|
|
3306
|
+
handleError(error);
|
|
3307
|
+
}
|
|
3308
|
+
});
|
|
3309
|
+
var VERSION5 = "0.0.92";
|
|
2089
3310
|
var DEFAULT_PROXY_PORT = 2e3;
|
|
2090
3311
|
var REACT_GRAB_SCRIPT = '<script src="https://unpkg.com/react-grab/dist/index.global.js"></script>';
|
|
2091
3312
|
var buildProviderScript = (provider) => `<script src="https://unpkg.com/${provider}/dist/client.global.js"></script>`;
|
|
@@ -2130,13 +3351,13 @@ var start = new Command().name("start").alias("proxy").description("start a prox
|
|
|
2130
3351
|
"provider package to run via npx (e.g., @react-grab/cursor)"
|
|
2131
3352
|
).action(async (urlArg, opts) => {
|
|
2132
3353
|
console.log(
|
|
2133
|
-
`${pc.magenta("\u273F")} ${pc.bold("React Grab")} ${pc.gray(
|
|
3354
|
+
`${pc.magenta("\u273F")} ${pc.bold("React Grab")} ${pc.gray(VERSION5)}`
|
|
2134
3355
|
);
|
|
2135
3356
|
console.log();
|
|
2136
3357
|
let url = urlArg;
|
|
2137
3358
|
let provider = opts.provider;
|
|
2138
3359
|
if (!url) {
|
|
2139
|
-
const { targetUrl: promptedUrl } = await
|
|
3360
|
+
const { targetUrl: promptedUrl } = await prompts3({
|
|
2140
3361
|
type: "text",
|
|
2141
3362
|
name: "targetUrl",
|
|
2142
3363
|
message: "Enter the target URL to proxy:",
|
|
@@ -2148,7 +3369,7 @@ var start = new Command().name("start").alias("proxy").description("start a prox
|
|
|
2148
3369
|
}
|
|
2149
3370
|
url = promptedUrl;
|
|
2150
3371
|
if (!provider) {
|
|
2151
|
-
const { selectedProvider } = await
|
|
3372
|
+
const { selectedProvider } = await prompts3({
|
|
2152
3373
|
type: "select",
|
|
2153
3374
|
name: "selectedProvider",
|
|
2154
3375
|
message: `Select a ${highlighter.info("provider")} to use:`,
|
|
@@ -2315,7 +3536,7 @@ var start = new Command().name("start").alias("proxy").description("start a prox
|
|
|
2315
3536
|
|
|
2316
3537
|
// src/cli.ts
|
|
2317
3538
|
process.noDeprecation = true;
|
|
2318
|
-
var
|
|
3539
|
+
var VERSION6 = "0.0.92";
|
|
2319
3540
|
var VERSION_API_URL = "https://www.react-grab.com/api/version";
|
|
2320
3541
|
process.on("SIGINT", () => process.exit(0));
|
|
2321
3542
|
process.on("SIGTERM", () => process.exit(0));
|
|
@@ -2324,9 +3545,10 @@ try {
|
|
|
2324
3545
|
});
|
|
2325
3546
|
} catch {
|
|
2326
3547
|
}
|
|
2327
|
-
var program = new Command().name("react-grab").description("add React Grab to your project").version(
|
|
3548
|
+
var program = new Command().name("react-grab").description("add React Grab to your project").version(VERSION6, "-v, --version", "display the version number");
|
|
2328
3549
|
program.addCommand(init);
|
|
2329
3550
|
program.addCommand(add);
|
|
3551
|
+
program.addCommand(remove);
|
|
2330
3552
|
program.addCommand(configure);
|
|
2331
3553
|
program.addCommand(start);
|
|
2332
3554
|
program.parse();
|