@react-grab/cli 0.0.72 → 0.0.74
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 +470 -504
- package/dist/cli.js +469 -503
- package/package.json +6 -5
package/dist/cli.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import { readFileSync, existsSync, writeFileSync, readdirSync, accessSync, constants } from 'fs';
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import prompts2 from 'prompts';
|
|
4
|
+
import { execSync } from 'child_process';
|
|
5
|
+
import { existsSync, readFileSync, writeFileSync, accessSync, constants, readdirSync } from 'fs';
|
|
7
6
|
import { join, basename } from 'path';
|
|
8
7
|
import { detect } from '@antfu/ni';
|
|
9
|
-
import {
|
|
8
|
+
import { cyan, dim, green, yellow, red } from 'kleur/colors';
|
|
9
|
+
import ora from 'ora';
|
|
10
10
|
|
|
11
11
|
var detectPackageManager = async (projectRoot) => {
|
|
12
12
|
const detected = await detect({ cwd: projectRoot });
|
|
@@ -294,7 +294,7 @@ var detectProject = async (projectRoot = process.cwd()) => {
|
|
|
294
294
|
};
|
|
295
295
|
};
|
|
296
296
|
|
|
297
|
-
// src/diff.ts
|
|
297
|
+
// src/utils/diff.ts
|
|
298
298
|
var RED = "\x1B[31m";
|
|
299
299
|
var GREEN = "\x1B[32m";
|
|
300
300
|
var GRAY = "\x1B[90m";
|
|
@@ -381,6 +381,50 @@ ${BOLD}File: ${filePath}${RESET}`);
|
|
|
381
381
|
console.log(formatDiff(diff));
|
|
382
382
|
console.log("\u2500".repeat(60));
|
|
383
383
|
};
|
|
384
|
+
var highlighter = {
|
|
385
|
+
error: red,
|
|
386
|
+
warn: yellow,
|
|
387
|
+
info: cyan,
|
|
388
|
+
success: green,
|
|
389
|
+
dim
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
// src/utils/logger.ts
|
|
393
|
+
var logger = {
|
|
394
|
+
error(...args) {
|
|
395
|
+
console.log(highlighter.error(args.join(" ")));
|
|
396
|
+
},
|
|
397
|
+
warn(...args) {
|
|
398
|
+
console.log(highlighter.warn(args.join(" ")));
|
|
399
|
+
},
|
|
400
|
+
info(...args) {
|
|
401
|
+
console.log(highlighter.info(args.join(" ")));
|
|
402
|
+
},
|
|
403
|
+
success(...args) {
|
|
404
|
+
console.log(highlighter.success(args.join(" ")));
|
|
405
|
+
},
|
|
406
|
+
log(...args) {
|
|
407
|
+
console.log(args.join(" "));
|
|
408
|
+
},
|
|
409
|
+
break() {
|
|
410
|
+
console.log("");
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
// src/utils/handle-error.ts
|
|
415
|
+
var handleError = (error) => {
|
|
416
|
+
logger.break();
|
|
417
|
+
logger.error(
|
|
418
|
+
"Something went wrong. Please check the error below for more details."
|
|
419
|
+
);
|
|
420
|
+
logger.error("If the problem persists, please open an issue on GitHub.");
|
|
421
|
+
logger.error("");
|
|
422
|
+
if (error instanceof Error) {
|
|
423
|
+
logger.error(error.message);
|
|
424
|
+
}
|
|
425
|
+
logger.break();
|
|
426
|
+
process.exit(1);
|
|
427
|
+
};
|
|
384
428
|
var INSTALL_COMMANDS = {
|
|
385
429
|
npm: "npm install",
|
|
386
430
|
yarn: "yarn add",
|
|
@@ -411,8 +455,9 @@ var getPackagesToInstall = (agent, includeReactGrab = true) => {
|
|
|
411
455
|
}
|
|
412
456
|
return packages;
|
|
413
457
|
};
|
|
458
|
+
var spinner = (text, options) => ora({ text, isSilent: options?.silent, stream: process.stdout });
|
|
414
459
|
|
|
415
|
-
// src/templates.ts
|
|
460
|
+
// src/utils/templates.ts
|
|
416
461
|
var NEXT_APP_ROUTER_SCRIPT = `{process.env.NODE_ENV === "development" && (
|
|
417
462
|
<Script
|
|
418
463
|
src="//unpkg.com/react-grab/dist/index.global.js"
|
|
@@ -485,7 +530,7 @@ var WEBPACK_IMPORT_WITH_AGENT = (agent) => {
|
|
|
485
530
|
};
|
|
486
531
|
var SCRIPT_IMPORT = 'import Script from "next/script";';
|
|
487
532
|
|
|
488
|
-
// src/transform.ts
|
|
533
|
+
// src/utils/transform.ts
|
|
489
534
|
var hasReactGrabCode = (content) => {
|
|
490
535
|
const fuzzyPatterns = [
|
|
491
536
|
/["'`][^"'`]*react-grab/,
|
|
@@ -641,11 +686,13 @@ var addAgentToExistingVite = (originalContent, agent, filePath) => {
|
|
|
641
686
|
};
|
|
642
687
|
}
|
|
643
688
|
const agentImport = `import("${agentPackage}/client");`;
|
|
644
|
-
const reactGrabImportMatch = originalContent.match(/import\s*\(\s*["']react-grab["']\s*\)
|
|
689
|
+
const reactGrabImportMatch = originalContent.match(/import\s*\(\s*["']react-grab["']\s*\);?/);
|
|
645
690
|
if (reactGrabImportMatch) {
|
|
691
|
+
const matchedText = reactGrabImportMatch[0];
|
|
692
|
+
const hasSemicolon = matchedText.endsWith(";");
|
|
646
693
|
const newContent = originalContent.replace(
|
|
647
|
-
|
|
648
|
-
`${
|
|
694
|
+
matchedText,
|
|
695
|
+
`${hasSemicolon ? matchedText.slice(0, -1) : matchedText};
|
|
649
696
|
${agentImport}`
|
|
650
697
|
);
|
|
651
698
|
return {
|
|
@@ -681,11 +728,13 @@ var addAgentToExistingWebpack = (originalContent, agent, filePath) => {
|
|
|
681
728
|
};
|
|
682
729
|
}
|
|
683
730
|
const agentImport = `import("${agentPackage}/client");`;
|
|
684
|
-
const reactGrabImportMatch = originalContent.match(/import\s*\(\s*["']react-grab["']\s*\)
|
|
731
|
+
const reactGrabImportMatch = originalContent.match(/import\s*\(\s*["']react-grab["']\s*\);?/);
|
|
685
732
|
if (reactGrabImportMatch) {
|
|
733
|
+
const matchedText = reactGrabImportMatch[0];
|
|
734
|
+
const hasSemicolon = matchedText.endsWith(";");
|
|
686
735
|
const newContent = originalContent.replace(
|
|
687
|
-
|
|
688
|
-
`${
|
|
736
|
+
matchedText,
|
|
737
|
+
`${hasSemicolon ? matchedText.slice(0, -1) : matchedText};
|
|
689
738
|
${agentImport}`
|
|
690
739
|
);
|
|
691
740
|
return {
|
|
@@ -931,11 +980,11 @@ var AGENT_PREFIXES = {
|
|
|
931
980
|
opencode: "npx @react-grab/opencode@latest &&"
|
|
932
981
|
};
|
|
933
982
|
var previewPackageJsonTransform = (projectRoot, agent, installedAgents) => {
|
|
934
|
-
if (agent === "none") {
|
|
983
|
+
if (agent === "none" || agent === "ami") {
|
|
935
984
|
return {
|
|
936
985
|
success: true,
|
|
937
986
|
filePath: "",
|
|
938
|
-
message: "No agent selected, skipping package.json modification",
|
|
987
|
+
message: agent === "ami" ? "Ami does not require package.json modification" : "No agent selected, skipping package.json modification",
|
|
939
988
|
noChanges: true
|
|
940
989
|
};
|
|
941
990
|
}
|
|
@@ -1023,9 +1072,188 @@ var applyPackageJsonTransform = (result) => {
|
|
|
1023
1072
|
return { success: true };
|
|
1024
1073
|
};
|
|
1025
1074
|
|
|
1026
|
-
// src/
|
|
1027
|
-
var
|
|
1028
|
-
|
|
1075
|
+
// src/commands/add.ts
|
|
1076
|
+
var AGENT_NAMES = {
|
|
1077
|
+
"claude-code": "Claude Code",
|
|
1078
|
+
cursor: "Cursor",
|
|
1079
|
+
opencode: "Opencode",
|
|
1080
|
+
ami: "Ami"
|
|
1081
|
+
};
|
|
1082
|
+
var add = new Command().name("add").description("add an agent integration").argument("[agent]", "agent to add (claude-code, cursor, opencode, ami)").option("-y, --yes", "skip confirmation prompts", false).option(
|
|
1083
|
+
"-c, --cwd <cwd>",
|
|
1084
|
+
"working directory (defaults to current directory)",
|
|
1085
|
+
process.cwd()
|
|
1086
|
+
).action(async (agentArg, opts) => {
|
|
1087
|
+
try {
|
|
1088
|
+
const cwd = opts.cwd;
|
|
1089
|
+
const isNonInteractive = opts.yes;
|
|
1090
|
+
logger.log(`\u269B ${highlighter.info("React Grab")}`);
|
|
1091
|
+
logger.break();
|
|
1092
|
+
const preflightSpinner = spinner("Preflight checks.").start();
|
|
1093
|
+
const projectInfo = await detectProject(cwd);
|
|
1094
|
+
if (!projectInfo.hasReactGrab) {
|
|
1095
|
+
preflightSpinner.fail("React Grab is not installed.");
|
|
1096
|
+
logger.break();
|
|
1097
|
+
logger.error(
|
|
1098
|
+
`Run ${highlighter.info("react-grab init")} first to install React Grab.`
|
|
1099
|
+
);
|
|
1100
|
+
logger.break();
|
|
1101
|
+
process.exit(1);
|
|
1102
|
+
}
|
|
1103
|
+
preflightSpinner.succeed();
|
|
1104
|
+
const availableAgents = ["claude-code", "cursor", "opencode", "ami"].filter((agent) => !projectInfo.installedAgents.includes(agent));
|
|
1105
|
+
if (availableAgents.length === 0) {
|
|
1106
|
+
logger.break();
|
|
1107
|
+
logger.success("All agent integrations are already installed.");
|
|
1108
|
+
logger.break();
|
|
1109
|
+
process.exit(0);
|
|
1110
|
+
}
|
|
1111
|
+
let agentIntegration;
|
|
1112
|
+
if (agentArg) {
|
|
1113
|
+
if (!["claude-code", "cursor", "opencode", "ami"].includes(agentArg)) {
|
|
1114
|
+
logger.break();
|
|
1115
|
+
logger.error(`Invalid agent: ${agentArg}`);
|
|
1116
|
+
logger.error("Available agents: claude-code, cursor, opencode, ami");
|
|
1117
|
+
logger.break();
|
|
1118
|
+
process.exit(1);
|
|
1119
|
+
}
|
|
1120
|
+
if (projectInfo.installedAgents.includes(agentArg)) {
|
|
1121
|
+
logger.break();
|
|
1122
|
+
logger.warn(`${AGENT_NAMES[agentArg]} is already installed.`);
|
|
1123
|
+
logger.break();
|
|
1124
|
+
process.exit(0);
|
|
1125
|
+
}
|
|
1126
|
+
agentIntegration = agentArg;
|
|
1127
|
+
} else if (!isNonInteractive) {
|
|
1128
|
+
logger.break();
|
|
1129
|
+
const { agent } = await prompts2({
|
|
1130
|
+
type: "select",
|
|
1131
|
+
name: "agent",
|
|
1132
|
+
message: `Which ${highlighter.info("agent integration")} would you like to add?`,
|
|
1133
|
+
choices: availableAgents.map((innerAgent) => ({
|
|
1134
|
+
title: AGENT_NAMES[innerAgent],
|
|
1135
|
+
value: innerAgent
|
|
1136
|
+
}))
|
|
1137
|
+
});
|
|
1138
|
+
if (!agent) {
|
|
1139
|
+
logger.break();
|
|
1140
|
+
process.exit(1);
|
|
1141
|
+
}
|
|
1142
|
+
agentIntegration = agent;
|
|
1143
|
+
} else {
|
|
1144
|
+
logger.break();
|
|
1145
|
+
logger.error("Please specify an agent to add.");
|
|
1146
|
+
logger.error("Available agents: " + availableAgents.join(", "));
|
|
1147
|
+
logger.break();
|
|
1148
|
+
process.exit(1);
|
|
1149
|
+
}
|
|
1150
|
+
const addingSpinner = spinner(
|
|
1151
|
+
`Adding ${AGENT_NAMES[agentIntegration]}.`
|
|
1152
|
+
).start();
|
|
1153
|
+
addingSpinner.succeed();
|
|
1154
|
+
const result = previewTransform(
|
|
1155
|
+
projectInfo.projectRoot,
|
|
1156
|
+
projectInfo.framework,
|
|
1157
|
+
projectInfo.nextRouterType,
|
|
1158
|
+
agentIntegration,
|
|
1159
|
+
true
|
|
1160
|
+
);
|
|
1161
|
+
const packageJsonResult = previewPackageJsonTransform(
|
|
1162
|
+
projectInfo.projectRoot,
|
|
1163
|
+
agentIntegration,
|
|
1164
|
+
projectInfo.installedAgents
|
|
1165
|
+
);
|
|
1166
|
+
if (!result.success) {
|
|
1167
|
+
logger.break();
|
|
1168
|
+
logger.error(result.message);
|
|
1169
|
+
logger.break();
|
|
1170
|
+
process.exit(1);
|
|
1171
|
+
}
|
|
1172
|
+
const hasLayoutChanges = !result.noChanges && result.originalContent && result.newContent;
|
|
1173
|
+
const hasPackageJsonChanges = packageJsonResult.success && !packageJsonResult.noChanges && packageJsonResult.originalContent && packageJsonResult.newContent;
|
|
1174
|
+
if (hasLayoutChanges || hasPackageJsonChanges) {
|
|
1175
|
+
logger.break();
|
|
1176
|
+
if (hasLayoutChanges) {
|
|
1177
|
+
printDiff(result.filePath, result.originalContent, result.newContent);
|
|
1178
|
+
}
|
|
1179
|
+
if (hasPackageJsonChanges) {
|
|
1180
|
+
if (hasLayoutChanges) {
|
|
1181
|
+
logger.break();
|
|
1182
|
+
}
|
|
1183
|
+
printDiff(
|
|
1184
|
+
packageJsonResult.filePath,
|
|
1185
|
+
packageJsonResult.originalContent,
|
|
1186
|
+
packageJsonResult.newContent
|
|
1187
|
+
);
|
|
1188
|
+
}
|
|
1189
|
+
if (!isNonInteractive) {
|
|
1190
|
+
logger.break();
|
|
1191
|
+
const { proceed } = await prompts2({
|
|
1192
|
+
type: "confirm",
|
|
1193
|
+
name: "proceed",
|
|
1194
|
+
message: "Apply these changes?",
|
|
1195
|
+
initial: true
|
|
1196
|
+
});
|
|
1197
|
+
if (!proceed) {
|
|
1198
|
+
logger.break();
|
|
1199
|
+
logger.log("Changes cancelled.");
|
|
1200
|
+
logger.break();
|
|
1201
|
+
process.exit(0);
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
const packages = getPackagesToInstall(agentIntegration, false);
|
|
1206
|
+
if (packages.length > 0) {
|
|
1207
|
+
const installSpinner = spinner(
|
|
1208
|
+
`Installing ${packages.join(", ")}.`
|
|
1209
|
+
).start();
|
|
1210
|
+
try {
|
|
1211
|
+
installPackages(packages, projectInfo.packageManager, projectInfo.projectRoot);
|
|
1212
|
+
installSpinner.succeed();
|
|
1213
|
+
} catch (error) {
|
|
1214
|
+
installSpinner.fail();
|
|
1215
|
+
handleError(error);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
if (hasLayoutChanges) {
|
|
1219
|
+
const writeSpinner = spinner(`Applying changes to ${result.filePath}.`).start();
|
|
1220
|
+
const writeResult = applyTransform(result);
|
|
1221
|
+
if (!writeResult.success) {
|
|
1222
|
+
writeSpinner.fail();
|
|
1223
|
+
logger.break();
|
|
1224
|
+
logger.error(writeResult.error || "Failed to write file.");
|
|
1225
|
+
logger.break();
|
|
1226
|
+
process.exit(1);
|
|
1227
|
+
}
|
|
1228
|
+
writeSpinner.succeed();
|
|
1229
|
+
}
|
|
1230
|
+
if (hasPackageJsonChanges) {
|
|
1231
|
+
const packageJsonSpinner = spinner(
|
|
1232
|
+
`Applying changes to ${packageJsonResult.filePath}.`
|
|
1233
|
+
).start();
|
|
1234
|
+
const packageJsonWriteResult = applyPackageJsonTransform(packageJsonResult);
|
|
1235
|
+
if (!packageJsonWriteResult.success) {
|
|
1236
|
+
packageJsonSpinner.fail();
|
|
1237
|
+
logger.break();
|
|
1238
|
+
logger.error(packageJsonWriteResult.error || "Failed to write file.");
|
|
1239
|
+
logger.break();
|
|
1240
|
+
process.exit(1);
|
|
1241
|
+
}
|
|
1242
|
+
packageJsonSpinner.succeed();
|
|
1243
|
+
}
|
|
1244
|
+
logger.break();
|
|
1245
|
+
logger.log(
|
|
1246
|
+
`${highlighter.success("Success!")} ${AGENT_NAMES[agentIntegration]} has been added.`
|
|
1247
|
+
);
|
|
1248
|
+
logger.log("Make sure to start the agent server before using it.");
|
|
1249
|
+
logger.break();
|
|
1250
|
+
} catch (error) {
|
|
1251
|
+
handleError(error);
|
|
1252
|
+
}
|
|
1253
|
+
});
|
|
1254
|
+
var VERSION = "0.0.74";
|
|
1255
|
+
var REPORT_URL = "https://react-grab.com/api/report-cli";
|
|
1256
|
+
var DOCS_URL = "https://github.com/aidenybai/react-grab";
|
|
1029
1257
|
var reportToCli = async (type, config, error) => {
|
|
1030
1258
|
try {
|
|
1031
1259
|
await fetch(REPORT_URL, {
|
|
@@ -1055,416 +1283,155 @@ var PACKAGE_MANAGER_NAMES = {
|
|
|
1055
1283
|
pnpm: "pnpm",
|
|
1056
1284
|
bun: "Bun"
|
|
1057
1285
|
};
|
|
1058
|
-
var AGENT_NAMES = {
|
|
1059
|
-
"claude-code": "Claude Code",
|
|
1060
|
-
cursor: "Cursor",
|
|
1061
|
-
opencode: "Opencode"
|
|
1062
|
-
};
|
|
1063
1286
|
var UNSUPPORTED_FRAMEWORK_NAMES = {
|
|
1064
1287
|
remix: "Remix",
|
|
1065
1288
|
astro: "Astro",
|
|
1066
1289
|
sveltekit: "SvelteKit",
|
|
1067
1290
|
gatsby: "Gatsby"
|
|
1068
1291
|
};
|
|
1069
|
-
var
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
console.log(
|
|
1091
|
-
` ${pc.gray(' src="//unpkg.com/react-grab/dist/index.global.js"')}`
|
|
1092
|
-
);
|
|
1093
|
-
console.log(` ${pc.gray(' crossOrigin="anonymous"')}`);
|
|
1094
|
-
console.log(` ${pc.gray(' strategy="beforeInteractive"')}`);
|
|
1095
|
-
console.log(` ${pc.gray(" />")}`);
|
|
1096
|
-
console.log(` ${pc.gray(")}")}`);
|
|
1097
|
-
} else if (framework === "next" && nextRouterType === "pages") {
|
|
1098
|
-
console.log(`${pc.bold("Next.js Pages Router:")}`);
|
|
1099
|
-
console.log(` 1. Install: ${pc.cyan("npm install -D react-grab")}`);
|
|
1100
|
-
console.log(` 2. Add to ${pc.cyan("pages/_document.tsx")} inside <Head>:`);
|
|
1101
|
-
console.log(` ${pc.gray('import Script from "next/script";')}`);
|
|
1102
|
-
console.log(
|
|
1103
|
-
` ${pc.gray('{process.env.NODE_ENV === "development" && (')}`
|
|
1104
|
-
);
|
|
1105
|
-
console.log(` ${pc.gray(" <Script")}`);
|
|
1106
|
-
console.log(
|
|
1107
|
-
` ${pc.gray(' src="//unpkg.com/react-grab/dist/index.global.js"')}`
|
|
1108
|
-
);
|
|
1109
|
-
console.log(` ${pc.gray(' crossOrigin="anonymous"')}`);
|
|
1110
|
-
console.log(` ${pc.gray(' strategy="beforeInteractive"')}`);
|
|
1111
|
-
console.log(` ${pc.gray(" />")}`);
|
|
1112
|
-
console.log(` ${pc.gray(")}")}`);
|
|
1113
|
-
} else if (framework === "vite") {
|
|
1114
|
-
console.log(`${pc.bold("Vite:")}`);
|
|
1115
|
-
console.log(` 1. Install: ${pc.cyan("npm install -D react-grab")}`);
|
|
1116
|
-
console.log(` 2. Add to ${pc.cyan("index.html")} inside <head>:`);
|
|
1117
|
-
console.log(` ${pc.gray('<script type="module">')}`);
|
|
1118
|
-
console.log(
|
|
1119
|
-
` ${pc.gray(' if (import.meta.env.DEV) { import("react-grab"); }')}`
|
|
1120
|
-
);
|
|
1121
|
-
console.log(` ${pc.gray("</script>")}`);
|
|
1122
|
-
} else if (framework === "webpack") {
|
|
1123
|
-
console.log(`${pc.bold("Webpack:")}`);
|
|
1124
|
-
console.log(` 1. Install: ${pc.cyan("npm install -D react-grab")}`);
|
|
1125
|
-
console.log(
|
|
1126
|
-
` 2. Add to your entry file (e.g., ${pc.cyan("src/index.tsx")}):`
|
|
1127
|
-
);
|
|
1128
|
-
console.log(
|
|
1129
|
-
` ${pc.gray('if (process.env.NODE_ENV === "development") {')}`
|
|
1130
|
-
);
|
|
1131
|
-
console.log(` ${pc.gray(' import("react-grab");')}`);
|
|
1132
|
-
console.log(` ${pc.gray("}")}`);
|
|
1133
|
-
} else {
|
|
1134
|
-
console.log(
|
|
1135
|
-
`${pc.bold("Next.js App Router:")} Add to ${pc.cyan("app/layout.tsx")} inside <head>:`
|
|
1136
|
-
);
|
|
1137
|
-
console.log(` ${pc.gray('import Script from "next/script";')}`);
|
|
1138
|
-
console.log(
|
|
1139
|
-
` ${pc.gray('{process.env.NODE_ENV === "development" && (')}`
|
|
1140
|
-
);
|
|
1141
|
-
console.log(
|
|
1142
|
-
` ${pc.gray(' <Script src="//unpkg.com/react-grab/dist/index.global.js" strategy="beforeInteractive" />')}`
|
|
1143
|
-
);
|
|
1144
|
-
console.log(` ${pc.gray(")}")}`);
|
|
1145
|
-
console.log("");
|
|
1146
|
-
console.log(
|
|
1147
|
-
`${pc.bold("Next.js Pages Router:")} Add to ${pc.cyan("pages/_document.tsx")} inside <Head>:`
|
|
1148
|
-
);
|
|
1149
|
-
console.log(` ${pc.gray('import Script from "next/script";')}`);
|
|
1150
|
-
console.log(
|
|
1151
|
-
` ${pc.gray('{process.env.NODE_ENV === "development" && (')}`
|
|
1152
|
-
);
|
|
1153
|
-
console.log(
|
|
1154
|
-
` ${pc.gray(' <Script src="//unpkg.com/react-grab/dist/index.global.js" strategy="beforeInteractive" />')}`
|
|
1155
|
-
);
|
|
1156
|
-
console.log(` ${pc.gray(")}")}`);
|
|
1157
|
-
console.log("");
|
|
1158
|
-
console.log(
|
|
1159
|
-
`${pc.bold("Vite:")} Add to ${pc.cyan("index.html")} inside <head>:`
|
|
1160
|
-
);
|
|
1161
|
-
console.log(` ${pc.gray('<script type="module">')}`);
|
|
1162
|
-
console.log(
|
|
1163
|
-
` ${pc.gray(' if (import.meta.env.DEV) { import("react-grab"); }')}`
|
|
1164
|
-
);
|
|
1165
|
-
console.log(` ${pc.gray("</script>")}`);
|
|
1166
|
-
console.log("");
|
|
1167
|
-
console.log(
|
|
1168
|
-
`${pc.bold("Webpack:")} Add to entry file (e.g., ${pc.cyan("src/index.tsx")}):`
|
|
1169
|
-
);
|
|
1170
|
-
console.log(
|
|
1171
|
-
` ${pc.gray('if (process.env.NODE_ENV === "development") {')}`
|
|
1172
|
-
);
|
|
1173
|
-
console.log(` ${pc.gray(' import("react-grab");')}`);
|
|
1174
|
-
console.log(` ${pc.gray("}")}`);
|
|
1175
|
-
console.log("");
|
|
1176
|
-
console.log(`For full instructions, visit:`);
|
|
1177
|
-
console.log(
|
|
1178
|
-
` ${pc.cyan("https://github.com/aidenybai/react-grab#readme")}`
|
|
1179
|
-
);
|
|
1180
|
-
return;
|
|
1181
|
-
}
|
|
1182
|
-
showDocsLink();
|
|
1183
|
-
};
|
|
1184
|
-
var showAccuracyWarning = () => {
|
|
1185
|
-
console.log(
|
|
1186
|
-
`
|
|
1187
|
-
${pc.yellow("\u26A0\uFE0F")} ${pc.yellow("Auto-detection may not be 100% accurate.")}`
|
|
1188
|
-
);
|
|
1189
|
-
console.log(
|
|
1190
|
-
`${pc.yellow(" Please verify the changes in your file before committing.")}`
|
|
1191
|
-
);
|
|
1192
|
-
};
|
|
1193
|
-
var parseArgs = async () => {
|
|
1194
|
-
const argv = await yargs(hideBin(process.argv)).scriptName("react-grab").usage(
|
|
1195
|
-
`${pc.magenta("\u269B")} ${pc.bold("React Grab CLI")} ${pc.gray(`v${VERSION}`)}
|
|
1196
|
-
|
|
1197
|
-
${pc.cyan("Usage:")} $0 [options]
|
|
1198
|
-
|
|
1199
|
-
React Grab adds AI-powered context selection to your React application,
|
|
1200
|
-
allowing you to select components and copy their context for AI assistants.
|
|
1201
|
-
|
|
1202
|
-
The CLI auto-detects your project configuration (framework, package manager,
|
|
1203
|
-
router type) and installs React Grab with optional agent integrations.`
|
|
1204
|
-
).option("framework", {
|
|
1205
|
-
alias: "f",
|
|
1206
|
-
type: "string",
|
|
1207
|
-
choices: ["next", "vite", "webpack"],
|
|
1208
|
-
description: "Override detected framework"
|
|
1209
|
-
}).option("package-manager", {
|
|
1210
|
-
alias: "p",
|
|
1211
|
-
type: "string",
|
|
1212
|
-
choices: ["npm", "yarn", "pnpm", "bun"],
|
|
1213
|
-
description: "Override detected package manager"
|
|
1214
|
-
}).option("router", {
|
|
1215
|
-
alias: "r",
|
|
1216
|
-
type: "string",
|
|
1217
|
-
choices: ["app", "pages"],
|
|
1218
|
-
description: "Next.js router type (only for Next.js projects)"
|
|
1219
|
-
}).option("agent", {
|
|
1220
|
-
alias: "a",
|
|
1221
|
-
type: "string",
|
|
1222
|
-
choices: ["claude-code", "cursor", "opencode", "none"],
|
|
1223
|
-
description: "Agent integration to automatically forward selected elements to agent instead of copying to clipboard"
|
|
1224
|
-
}).option("yes", {
|
|
1225
|
-
alias: "y",
|
|
1226
|
-
type: "boolean",
|
|
1227
|
-
default: false,
|
|
1228
|
-
description: "Skip all prompts and use auto-detected/default values"
|
|
1229
|
-
}).option("skip-install", {
|
|
1230
|
-
type: "boolean",
|
|
1231
|
-
default: false,
|
|
1232
|
-
description: "Only modify config files, skip npm/yarn/pnpm install"
|
|
1233
|
-
}).help().alias("help", "h").version(VERSION).alias("version", "v").example("$0", "Run interactive setup with prompts").example("$0 -y", "Auto-detect everything and install without prompts").example("$0 -f next -r app", "Configure for Next.js App Router").example(
|
|
1234
|
-
"$0 -a cursor -y",
|
|
1235
|
-
"Add Cursor agent integration non-interactively"
|
|
1236
|
-
).example("$0 -p pnpm -a claude-code", "Use pnpm and add Claude Code agent").example(
|
|
1237
|
-
"$0 --skip-install",
|
|
1238
|
-
"Only modify files, install packages manually"
|
|
1239
|
-
).epilog(
|
|
1240
|
-
`${pc.bold("Agent Integrations:")}
|
|
1241
|
-
${pc.cyan("claude-code")} Connect React Grab to Claude Code
|
|
1242
|
-
${pc.cyan("cursor")} Connect React Grab to Cursor IDE
|
|
1243
|
-
${pc.cyan("opencode")} Connect React Grab to Opencode
|
|
1244
|
-
|
|
1245
|
-
${pc.bold("Supported Frameworks:")}
|
|
1246
|
-
${pc.cyan("next")} Next.js (App Router & Pages Router)
|
|
1247
|
-
${pc.cyan("vite")} Vite-based React projects
|
|
1248
|
-
${pc.cyan("webpack")} Webpack-based React projects
|
|
1249
|
-
|
|
1250
|
-
${pc.bold("Documentation:")} ${pc.underline(DOCS_URL)}`
|
|
1251
|
-
).wrap(Math.min(100, process.stdout.columns || 80)).parse();
|
|
1252
|
-
return {
|
|
1253
|
-
framework: argv.framework,
|
|
1254
|
-
packageManager: argv["package-manager"],
|
|
1255
|
-
router: argv.router,
|
|
1256
|
-
agent: argv.agent,
|
|
1257
|
-
yes: argv.yes,
|
|
1258
|
-
skipInstall: argv["skip-install"]
|
|
1259
|
-
};
|
|
1260
|
-
};
|
|
1261
|
-
var main = async () => {
|
|
1262
|
-
const args = await parseArgs();
|
|
1263
|
-
const isNonInteractive = args.yes;
|
|
1264
|
-
console.log(
|
|
1265
|
-
`
|
|
1266
|
-
${pc.magenta("\u269B")} ${pc.bold("React Grab")} ${pc.gray(VERSION)}`
|
|
1267
|
-
);
|
|
1268
|
-
const projectInfo = await detectProject(process.cwd());
|
|
1269
|
-
console.log(
|
|
1270
|
-
`- Framework: ${pc.cyan(FRAMEWORK_NAMES[projectInfo.framework])}`
|
|
1271
|
-
);
|
|
1272
|
-
console.log(
|
|
1273
|
-
`- Package Manager: ${pc.cyan(PACKAGE_MANAGER_NAMES[projectInfo.packageManager])}`
|
|
1274
|
-
);
|
|
1275
|
-
if (projectInfo.framework === "next") {
|
|
1276
|
-
console.log(
|
|
1277
|
-
`- Router Type: ${pc.cyan(projectInfo.nextRouterType === "app" ? "App Router" : "Pages Router")}`
|
|
1278
|
-
);
|
|
1279
|
-
}
|
|
1280
|
-
console.log(
|
|
1281
|
-
`- Monorepo: ${pc.cyan(projectInfo.isMonorepo ? "Yes" : "No")}`
|
|
1282
|
-
);
|
|
1283
|
-
console.log(
|
|
1284
|
-
`- React Grab: ${projectInfo.hasReactGrab ? pc.green("Installed") : pc.yellow("Not installed")}`
|
|
1285
|
-
);
|
|
1286
|
-
if (projectInfo.installedAgents.length > 0) {
|
|
1287
|
-
console.log(
|
|
1288
|
-
`- Agents: ${pc.cyan(projectInfo.installedAgents.map((agent) => AGENT_NAMES[agent] || agent).join(", "))}`
|
|
1289
|
-
);
|
|
1290
|
-
}
|
|
1291
|
-
console.log("");
|
|
1292
|
-
if (projectInfo.unsupportedFramework) {
|
|
1293
|
-
const frameworkName = UNSUPPORTED_FRAMEWORK_NAMES[projectInfo.unsupportedFramework];
|
|
1294
|
-
console.log(
|
|
1295
|
-
`${pc.yellow("\u26A0\uFE0F")} ${pc.yellow(`Detected ${frameworkName} - this framework requires manual setup.`)}`
|
|
1296
|
-
);
|
|
1297
|
-
console.log(
|
|
1298
|
-
`${pc.yellow(" React Grab may not work correctly with auto-configuration.")}
|
|
1299
|
-
`
|
|
1300
|
-
);
|
|
1301
|
-
showManualInstructions(projectInfo.framework, projectInfo.nextRouterType);
|
|
1302
|
-
process.exit(0);
|
|
1303
|
-
}
|
|
1304
|
-
if (projectInfo.framework === "unknown") {
|
|
1305
|
-
if (projectInfo.isMonorepo && !isNonInteractive) {
|
|
1306
|
-
const workspaceProjects = findWorkspaceProjects(projectInfo.projectRoot);
|
|
1307
|
-
const reactProjects = workspaceProjects.filter(
|
|
1308
|
-
(p) => p.hasReact || p.framework !== "unknown"
|
|
1292
|
+
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(
|
|
1293
|
+
"-a, --agent <agent>",
|
|
1294
|
+
"agent integration (claude-code, cursor, opencode, ami)"
|
|
1295
|
+
).option("--skip-install", "skip package installation", false).option(
|
|
1296
|
+
"-c, --cwd <cwd>",
|
|
1297
|
+
"working directory (defaults to current directory)",
|
|
1298
|
+
process.cwd()
|
|
1299
|
+
).action(async (opts) => {
|
|
1300
|
+
try {
|
|
1301
|
+
const cwd = opts.cwd;
|
|
1302
|
+
const isNonInteractive = opts.yes;
|
|
1303
|
+
logger.log(`\u269B ${highlighter.info("React Grab")}`);
|
|
1304
|
+
logger.break();
|
|
1305
|
+
const preflightSpinner = spinner("Preflight checks.").start();
|
|
1306
|
+
const projectInfo = await detectProject(cwd);
|
|
1307
|
+
if (projectInfo.hasReactGrab && !opts.force) {
|
|
1308
|
+
preflightSpinner.succeed();
|
|
1309
|
+
logger.break();
|
|
1310
|
+
logger.warn("React Grab is already installed.");
|
|
1311
|
+
logger.log(
|
|
1312
|
+
`Use ${highlighter.info("--force")} to reconfigure, or ${highlighter.info("react-grab add")} to add an agent.`
|
|
1309
1313
|
);
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1314
|
+
logger.break();
|
|
1315
|
+
process.exit(0);
|
|
1316
|
+
}
|
|
1317
|
+
preflightSpinner.succeed();
|
|
1318
|
+
const frameworkSpinner = spinner("Verifying framework.").start();
|
|
1319
|
+
if (projectInfo.unsupportedFramework) {
|
|
1320
|
+
const frameworkName = UNSUPPORTED_FRAMEWORK_NAMES[projectInfo.unsupportedFramework];
|
|
1321
|
+
frameworkSpinner.fail(`Found ${highlighter.info(frameworkName)}.`);
|
|
1322
|
+
logger.break();
|
|
1323
|
+
logger.log(`${frameworkName} is not yet supported by automatic setup.`);
|
|
1324
|
+
logger.log(`Visit ${highlighter.info(DOCS_URL)} for manual setup.`);
|
|
1325
|
+
logger.break();
|
|
1326
|
+
process.exit(1);
|
|
1327
|
+
}
|
|
1328
|
+
if (projectInfo.framework === "unknown") {
|
|
1329
|
+
if (projectInfo.isMonorepo && !isNonInteractive) {
|
|
1330
|
+
frameworkSpinner.info("Verifying framework. Found monorepo.");
|
|
1331
|
+
const workspaceProjects = findWorkspaceProjects(
|
|
1332
|
+
projectInfo.projectRoot
|
|
1326
1333
|
);
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
projectInfo.framework = newProjectInfo.framework;
|
|
1330
|
-
projectInfo.nextRouterType = newProjectInfo.nextRouterType;
|
|
1331
|
-
projectInfo.hasReactGrab = newProjectInfo.hasReactGrab;
|
|
1332
|
-
projectInfo.installedAgents = newProjectInfo.installedAgents;
|
|
1333
|
-
projectInfo.projectRoot = newProjectInfo.projectRoot;
|
|
1334
|
-
console.log(
|
|
1335
|
-
`- Framework: ${pc.cyan(FRAMEWORK_NAMES[newProjectInfo.framework])}`
|
|
1334
|
+
const reactProjects = workspaceProjects.filter(
|
|
1335
|
+
(project) => project.hasReact || project.framework !== "unknown"
|
|
1336
1336
|
);
|
|
1337
|
-
if (
|
|
1338
|
-
|
|
1339
|
-
|
|
1337
|
+
if (reactProjects.length > 0) {
|
|
1338
|
+
logger.break();
|
|
1339
|
+
const sortedProjects = [...reactProjects].sort(
|
|
1340
|
+
(projectA, projectB) => {
|
|
1341
|
+
if (projectA.framework === "unknown" && projectB.framework !== "unknown")
|
|
1342
|
+
return 1;
|
|
1343
|
+
if (projectA.framework !== "unknown" && projectB.framework === "unknown")
|
|
1344
|
+
return -1;
|
|
1345
|
+
return 0;
|
|
1346
|
+
}
|
|
1340
1347
|
);
|
|
1348
|
+
const { selectedProject } = await prompts2({
|
|
1349
|
+
type: "select",
|
|
1350
|
+
name: "selectedProject",
|
|
1351
|
+
message: "Select a project to install React Grab:",
|
|
1352
|
+
choices: sortedProjects.map((project) => {
|
|
1353
|
+
const frameworkLabel = project.framework !== "unknown" ? ` ${highlighter.dim(`(${FRAMEWORK_NAMES[project.framework]})`)}` : "";
|
|
1354
|
+
return {
|
|
1355
|
+
title: `${project.name}${frameworkLabel}`,
|
|
1356
|
+
value: project.path
|
|
1357
|
+
};
|
|
1358
|
+
})
|
|
1359
|
+
});
|
|
1360
|
+
if (!selectedProject) {
|
|
1361
|
+
logger.break();
|
|
1362
|
+
process.exit(1);
|
|
1363
|
+
}
|
|
1364
|
+
process.chdir(selectedProject);
|
|
1365
|
+
const newProjectInfo = await detectProject(selectedProject);
|
|
1366
|
+
Object.assign(projectInfo, newProjectInfo);
|
|
1367
|
+
const newFrameworkSpinner = spinner("Verifying framework.").start();
|
|
1368
|
+
newFrameworkSpinner.succeed(
|
|
1369
|
+
`Verifying framework. Found ${highlighter.info(FRAMEWORK_NAMES[newProjectInfo.framework])}.`
|
|
1370
|
+
);
|
|
1371
|
+
} else {
|
|
1372
|
+
frameworkSpinner.fail("Could not detect a supported framework.");
|
|
1373
|
+
logger.break();
|
|
1374
|
+
logger.log(`Visit ${highlighter.info(DOCS_URL)} for manual setup.`);
|
|
1375
|
+
logger.break();
|
|
1376
|
+
process.exit(1);
|
|
1341
1377
|
}
|
|
1342
|
-
console.log(
|
|
1343
|
-
`- React Grab: ${newProjectInfo.hasReactGrab ? pc.green("Installed") : pc.yellow("Not installed")}`
|
|
1344
|
-
);
|
|
1345
|
-
console.log("");
|
|
1346
1378
|
} else {
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1379
|
+
frameworkSpinner.fail("Could not detect a supported framework.");
|
|
1380
|
+
logger.break();
|
|
1381
|
+
logger.log(
|
|
1382
|
+
"React Grab supports Next.js, Vite, and Webpack projects."
|
|
1350
1383
|
);
|
|
1351
|
-
|
|
1352
|
-
|
|
1384
|
+
logger.log(`Visit ${highlighter.info(DOCS_URL)} for manual setup.`);
|
|
1385
|
+
logger.break();
|
|
1386
|
+
process.exit(1);
|
|
1353
1387
|
}
|
|
1354
1388
|
} else {
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
`
|
|
1389
|
+
frameworkSpinner.succeed(
|
|
1390
|
+
`Verifying framework. Found ${highlighter.info(FRAMEWORK_NAMES[projectInfo.framework])}.`
|
|
1358
1391
|
);
|
|
1359
|
-
showManualInstructions("unknown");
|
|
1360
|
-
process.exit(0);
|
|
1361
1392
|
}
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
} else if (projectInfo.hasReactGrab && args.agent && args.agent !== "none") {
|
|
1374
|
-
action = "add-agent";
|
|
1375
|
-
} else if (projectInfo.hasReactGrab && isNonInteractive && !args.agent) {
|
|
1376
|
-
console.log(
|
|
1377
|
-
`${pc.yellow("\u26A0\uFE0F")} ${pc.yellow("React Grab is already installed.")}`
|
|
1378
|
-
);
|
|
1379
|
-
console.log(
|
|
1380
|
-
`${pc.yellow(" Use --agent to add an agent, or run without -y for interactive mode.")}
|
|
1381
|
-
`
|
|
1393
|
+
if (projectInfo.framework === "next") {
|
|
1394
|
+
const routerSpinner = spinner("Detecting router type.").start();
|
|
1395
|
+
routerSpinner.succeed(
|
|
1396
|
+
`Detecting router type. Found ${highlighter.info(projectInfo.nextRouterType === "app" ? "App Router" : "Pages Router")}.`
|
|
1397
|
+
);
|
|
1398
|
+
}
|
|
1399
|
+
const packageManagerSpinner = spinner(
|
|
1400
|
+
"Detecting package manager."
|
|
1401
|
+
).start();
|
|
1402
|
+
packageManagerSpinner.succeed(
|
|
1403
|
+
`Detecting package manager. Found ${highlighter.info(PACKAGE_MANAGER_NAMES[projectInfo.packageManager])}.`
|
|
1382
1404
|
);
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
if (!confirmSettings) {
|
|
1394
|
-
finalFramework = await select({
|
|
1395
|
-
message: "Select your framework:",
|
|
1396
|
-
choices: [
|
|
1397
|
-
{ name: "Next.js", value: "next" },
|
|
1398
|
-
{ name: "Vite", value: "vite" },
|
|
1399
|
-
{ name: "Webpack", value: "webpack" }
|
|
1400
|
-
],
|
|
1401
|
-
default: projectInfo.framework
|
|
1402
|
-
});
|
|
1403
|
-
finalPackageManager = await select({
|
|
1404
|
-
message: "Select your package manager:",
|
|
1405
|
+
let finalFramework = projectInfo.framework;
|
|
1406
|
+
let finalPackageManager = projectInfo.packageManager;
|
|
1407
|
+
let finalNextRouterType = projectInfo.nextRouterType;
|
|
1408
|
+
let agentIntegration = opts.agent || "none";
|
|
1409
|
+
if (!isNonInteractive && !opts.agent) {
|
|
1410
|
+
logger.break();
|
|
1411
|
+
const { agent } = await prompts2({
|
|
1412
|
+
type: "select",
|
|
1413
|
+
name: "agent",
|
|
1414
|
+
message: `Would you like to add an ${highlighter.info("agent integration")}?`,
|
|
1405
1415
|
choices: [
|
|
1406
|
-
{
|
|
1407
|
-
{
|
|
1408
|
-
{
|
|
1409
|
-
{
|
|
1410
|
-
|
|
1411
|
-
|
|
1416
|
+
{ title: "None", value: "none" },
|
|
1417
|
+
{ title: "Claude Code", value: "claude-code" },
|
|
1418
|
+
{ title: "Cursor", value: "cursor" },
|
|
1419
|
+
{ title: "Opencode", value: "opencode" },
|
|
1420
|
+
{ title: "Ami", value: "ami" }
|
|
1421
|
+
]
|
|
1412
1422
|
});
|
|
1413
|
-
if (
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
choices: [
|
|
1417
|
-
{ name: "App Router", value: "app" },
|
|
1418
|
-
{ name: "Pages Router", value: "pages" }
|
|
1419
|
-
],
|
|
1420
|
-
default: projectInfo.nextRouterType === "app" ? "app" : "pages"
|
|
1421
|
-
});
|
|
1423
|
+
if (agent === void 0) {
|
|
1424
|
+
logger.break();
|
|
1425
|
+
process.exit(1);
|
|
1422
1426
|
}
|
|
1427
|
+
agentIntegration = agent;
|
|
1423
1428
|
}
|
|
1424
|
-
}
|
|
1425
|
-
let agentIntegration = args.agent || "none";
|
|
1426
|
-
const shouldAskForAgent = (action === "install-all" || action === "add-agent") && !args.agent;
|
|
1427
|
-
if (shouldAskForAgent && !isNonInteractive) {
|
|
1428
|
-
const availableAgents = [
|
|
1429
|
-
{ name: "Claude Code", value: "claude-code" },
|
|
1430
|
-
{ name: "Cursor", value: "cursor" },
|
|
1431
|
-
{ name: "Opencode", value: "opencode" }
|
|
1432
|
-
].filter((agent) => !projectInfo.installedAgents.includes(agent.value));
|
|
1433
|
-
if (availableAgents.length === 0) {
|
|
1434
|
-
console.log(
|
|
1435
|
-
`
|
|
1436
|
-
${pc.green("All agent integrations are already installed.")}
|
|
1437
|
-
`
|
|
1438
|
-
);
|
|
1439
|
-
} else if (action === "add-agent") {
|
|
1440
|
-
agentIntegration = await select({
|
|
1441
|
-
message: "Select an agent integration to add:",
|
|
1442
|
-
choices: availableAgents
|
|
1443
|
-
});
|
|
1444
|
-
} else {
|
|
1445
|
-
const wantAgentIntegration = await confirm({
|
|
1446
|
-
message: "Do you want to add an agent integration (Claude Code, Cursor, or Opencode)?",
|
|
1447
|
-
default: false
|
|
1448
|
-
});
|
|
1449
|
-
if (wantAgentIntegration) {
|
|
1450
|
-
agentIntegration = await select({
|
|
1451
|
-
message: "Select an agent integration:",
|
|
1452
|
-
choices: availableAgents
|
|
1453
|
-
});
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
}
|
|
1457
|
-
const shouldTransform = action === "reconfigure" || action === "install-all" || action === "add-agent" && agentIntegration !== "none";
|
|
1458
|
-
if (shouldTransform) {
|
|
1459
|
-
console.log(`
|
|
1460
|
-
${pc.magenta("\u269B")} Previewing changes...
|
|
1461
|
-
`);
|
|
1462
1429
|
const result = previewTransform(
|
|
1463
1430
|
projectInfo.projectRoot,
|
|
1464
1431
|
finalFramework,
|
|
1465
1432
|
finalNextRouterType,
|
|
1466
1433
|
agentIntegration,
|
|
1467
|
-
|
|
1434
|
+
false
|
|
1468
1435
|
);
|
|
1469
1436
|
const packageJsonResult = previewPackageJsonTransform(
|
|
1470
1437
|
projectInfo.projectRoot,
|
|
@@ -1472,24 +1439,26 @@ ${pc.magenta("\u269B")} Previewing changes...
|
|
|
1472
1439
|
projectInfo.installedAgents
|
|
1473
1440
|
);
|
|
1474
1441
|
if (!result.success) {
|
|
1475
|
-
|
|
1476
|
-
|
|
1442
|
+
logger.break();
|
|
1443
|
+
logger.error(result.message);
|
|
1444
|
+
logger.error(`Visit ${highlighter.info(DOCS_URL)} for manual setup.`);
|
|
1445
|
+
logger.break();
|
|
1477
1446
|
process.exit(1);
|
|
1478
1447
|
}
|
|
1479
1448
|
const hasLayoutChanges = !result.noChanges && result.originalContent && result.newContent;
|
|
1480
1449
|
const hasPackageJsonChanges = packageJsonResult.success && !packageJsonResult.noChanges && packageJsonResult.originalContent && packageJsonResult.newContent;
|
|
1481
|
-
if (
|
|
1482
|
-
|
|
1483
|
-
if (packageJsonResult.message) {
|
|
1484
|
-
console.log(`${pc.cyan("Info:")} ${packageJsonResult.message}`);
|
|
1485
|
-
}
|
|
1486
|
-
} else {
|
|
1450
|
+
if (hasLayoutChanges || hasPackageJsonChanges) {
|
|
1451
|
+
logger.break();
|
|
1487
1452
|
if (hasLayoutChanges) {
|
|
1488
|
-
printDiff(
|
|
1453
|
+
printDiff(
|
|
1454
|
+
result.filePath,
|
|
1455
|
+
result.originalContent,
|
|
1456
|
+
result.newContent
|
|
1457
|
+
);
|
|
1489
1458
|
}
|
|
1490
1459
|
if (hasPackageJsonChanges) {
|
|
1491
1460
|
if (hasLayoutChanges) {
|
|
1492
|
-
|
|
1461
|
+
logger.break();
|
|
1493
1462
|
}
|
|
1494
1463
|
printDiff(
|
|
1495
1464
|
packageJsonResult.filePath,
|
|
@@ -1497,104 +1466,101 @@ ${pc.magenta("\u269B")} Previewing changes...
|
|
|
1497
1466
|
packageJsonResult.newContent
|
|
1498
1467
|
);
|
|
1499
1468
|
}
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1469
|
+
logger.break();
|
|
1470
|
+
logger.warn("Auto-detection may not be 100% accurate.");
|
|
1471
|
+
logger.warn("Please verify the changes before committing.");
|
|
1472
|
+
if (!isNonInteractive) {
|
|
1473
|
+
logger.break();
|
|
1474
|
+
const { proceed } = await prompts2({
|
|
1475
|
+
type: "confirm",
|
|
1476
|
+
name: "proceed",
|
|
1477
|
+
message: "Apply these changes?",
|
|
1478
|
+
initial: true
|
|
1479
|
+
});
|
|
1480
|
+
if (!proceed) {
|
|
1481
|
+
logger.break();
|
|
1482
|
+
logger.log("Changes cancelled.");
|
|
1483
|
+
logger.break();
|
|
1484
|
+
process.exit(0);
|
|
1513
1485
|
}
|
|
1514
1486
|
}
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1487
|
+
}
|
|
1488
|
+
const shouldInstallReactGrab = !projectInfo.hasReactGrab;
|
|
1489
|
+
const shouldInstallAgent = agentIntegration !== "none" && !projectInfo.installedAgents.includes(agentIntegration);
|
|
1490
|
+
if (!opts.skipInstall && (shouldInstallReactGrab || shouldInstallAgent)) {
|
|
1491
|
+
const packages = getPackagesToInstall(
|
|
1492
|
+
agentIntegration,
|
|
1493
|
+
shouldInstallReactGrab
|
|
1494
|
+
);
|
|
1495
|
+
if (packages.length > 0) {
|
|
1496
|
+
const installSpinner = spinner(
|
|
1497
|
+
`Installing ${packages.join(", ")}.`
|
|
1498
|
+
).start();
|
|
1499
|
+
try {
|
|
1500
|
+
installPackages(
|
|
1501
|
+
packages,
|
|
1502
|
+
finalPackageManager,
|
|
1503
|
+
projectInfo.projectRoot
|
|
1527
1504
|
);
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
projectInfo.projectRoot
|
|
1533
|
-
);
|
|
1534
|
-
console.log(`
|
|
1535
|
-
${pc.green("Packages installed successfully!")}
|
|
1536
|
-
`);
|
|
1537
|
-
} catch (error) {
|
|
1538
|
-
console.error(`
|
|
1539
|
-
${pc.red("Failed to install packages:")}`, error);
|
|
1540
|
-
showDocsLink();
|
|
1541
|
-
process.exit(1);
|
|
1542
|
-
}
|
|
1505
|
+
installSpinner.succeed();
|
|
1506
|
+
} catch (error) {
|
|
1507
|
+
installSpinner.fail();
|
|
1508
|
+
handleError(error);
|
|
1543
1509
|
}
|
|
1544
1510
|
}
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1511
|
+
}
|
|
1512
|
+
if (hasLayoutChanges) {
|
|
1513
|
+
const writeSpinner = spinner(
|
|
1514
|
+
`Applying changes to ${result.filePath}.`
|
|
1515
|
+
).start();
|
|
1516
|
+
const writeResult = applyTransform(result);
|
|
1517
|
+
if (!writeResult.success) {
|
|
1518
|
+
writeSpinner.fail();
|
|
1519
|
+
logger.break();
|
|
1520
|
+
logger.error(writeResult.error || "Failed to write file.");
|
|
1521
|
+
logger.break();
|
|
1522
|
+
process.exit(1);
|
|
1555
1523
|
}
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1524
|
+
writeSpinner.succeed();
|
|
1525
|
+
}
|
|
1526
|
+
if (hasPackageJsonChanges) {
|
|
1527
|
+
const packageJsonSpinner = spinner(
|
|
1528
|
+
`Applying changes to ${packageJsonResult.filePath}.`
|
|
1529
|
+
).start();
|
|
1530
|
+
const packageJsonWriteResult = applyPackageJsonTransform(packageJsonResult);
|
|
1531
|
+
if (!packageJsonWriteResult.success) {
|
|
1532
|
+
packageJsonSpinner.fail();
|
|
1533
|
+
logger.break();
|
|
1534
|
+
logger.error(packageJsonWriteResult.error || "Failed to write file.");
|
|
1535
|
+
logger.break();
|
|
1536
|
+
process.exit(1);
|
|
1567
1537
|
}
|
|
1538
|
+
packageJsonSpinner.succeed();
|
|
1568
1539
|
}
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
console.log(`
|
|
1573
|
-
Next steps:`);
|
|
1574
|
-
console.log(`- Start your development server`);
|
|
1575
|
-
console.log(`- Select an element to copy its context`);
|
|
1576
|
-
console.log(`- Learn more at ${pc.cyan(DOCS_URL)}
|
|
1577
|
-
`);
|
|
1578
|
-
if (agentIntegration !== "none") {
|
|
1579
|
-
console.log(
|
|
1580
|
-
`${pc.magenta("\u269B")} Agent: ${pc.cyan(AGENT_NAMES[agentIntegration])}`
|
|
1540
|
+
logger.break();
|
|
1541
|
+
logger.log(
|
|
1542
|
+
`${highlighter.success("Success!")} React Grab has been installed.`
|
|
1581
1543
|
);
|
|
1582
|
-
|
|
1583
|
-
|
|
1544
|
+
logger.log("You may now start your development server.");
|
|
1545
|
+
logger.break();
|
|
1546
|
+
await reportToCli("completed", {
|
|
1547
|
+
framework: finalFramework,
|
|
1548
|
+
packageManager: finalPackageManager,
|
|
1549
|
+
router: finalNextRouterType,
|
|
1550
|
+
agent: agentIntegration !== "none" ? agentIntegration : void 0,
|
|
1551
|
+
isMonorepo: projectInfo.isMonorepo
|
|
1552
|
+
});
|
|
1553
|
+
} catch (error) {
|
|
1554
|
+
handleError(error);
|
|
1555
|
+
await reportToCli("error", void 0, error);
|
|
1584
1556
|
}
|
|
1585
|
-
await reportToCli("completed", {
|
|
1586
|
-
framework: finalFramework,
|
|
1587
|
-
packageManager: finalPackageManager,
|
|
1588
|
-
router: finalNextRouterType,
|
|
1589
|
-
agent: agentIntegration !== "none" ? agentIntegration : void 0,
|
|
1590
|
-
isMonorepo: projectInfo.isMonorepo
|
|
1591
|
-
});
|
|
1592
|
-
};
|
|
1593
|
-
main().catch(async (error) => {
|
|
1594
|
-
console.error(`${pc.red("Error:")}`, error);
|
|
1595
|
-
console.log("\nFor manual installation instructions, visit:");
|
|
1596
|
-
console.log(` ${DOCS_URL}
|
|
1597
|
-
`);
|
|
1598
|
-
await reportToCli("error", void 0, error);
|
|
1599
|
-
process.exit(1);
|
|
1600
1557
|
});
|
|
1558
|
+
|
|
1559
|
+
// src/cli.ts
|
|
1560
|
+
var VERSION2 = "0.0.74";
|
|
1561
|
+
process.on("SIGINT", () => process.exit(0));
|
|
1562
|
+
process.on("SIGTERM", () => process.exit(0));
|
|
1563
|
+
var program = new Command().name("react-grab").description("add React Grab to your project").version(VERSION2, "-v, --version", "display the version number");
|
|
1564
|
+
program.addCommand(init);
|
|
1565
|
+
program.addCommand(add);
|
|
1566
|
+
program.parse();
|