@react-grab/cli 0.0.70 → 0.0.71
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 +453 -76
- package/dist/cli.js +455 -78
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -80,22 +80,165 @@ var detectMonorepo = (projectRoot) => {
|
|
|
80
80
|
}
|
|
81
81
|
return false;
|
|
82
82
|
};
|
|
83
|
-
var
|
|
83
|
+
var getWorkspacePatterns = (projectRoot) => {
|
|
84
|
+
const patterns = [];
|
|
85
|
+
const pnpmWorkspacePath = path.join(projectRoot, "pnpm-workspace.yaml");
|
|
86
|
+
if (fs.existsSync(pnpmWorkspacePath)) {
|
|
87
|
+
const content = fs.readFileSync(pnpmWorkspacePath, "utf-8");
|
|
88
|
+
const lines = content.split("\n");
|
|
89
|
+
let inPackages = false;
|
|
90
|
+
for (const line of lines) {
|
|
91
|
+
if (line.match(/^packages:\s*$/)) {
|
|
92
|
+
inPackages = true;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (inPackages) {
|
|
96
|
+
if (line.match(/^[a-zA-Z]/) || line.trim() === "") {
|
|
97
|
+
if (line.match(/^[a-zA-Z]/)) inPackages = false;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const match = line.match(/^\s*-\s*['"]?([^'"#\n]+?)['"]?\s*$/);
|
|
101
|
+
if (match) {
|
|
102
|
+
patterns.push(match[1].trim());
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const lernaJsonPath = path.join(projectRoot, "lerna.json");
|
|
108
|
+
if (fs.existsSync(lernaJsonPath)) {
|
|
109
|
+
try {
|
|
110
|
+
const lernaJson = JSON.parse(fs.readFileSync(lernaJsonPath, "utf-8"));
|
|
111
|
+
if (Array.isArray(lernaJson.packages)) {
|
|
112
|
+
patterns.push(...lernaJson.packages);
|
|
113
|
+
}
|
|
114
|
+
} catch {
|
|
115
|
+
}
|
|
116
|
+
}
|
|
84
117
|
const packageJsonPath = path.join(projectRoot, "package.json");
|
|
85
|
-
if (
|
|
86
|
-
|
|
118
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
119
|
+
try {
|
|
120
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
121
|
+
if (Array.isArray(packageJson.workspaces)) {
|
|
122
|
+
patterns.push(...packageJson.workspaces);
|
|
123
|
+
} else if (packageJson.workspaces?.packages) {
|
|
124
|
+
patterns.push(...packageJson.workspaces.packages);
|
|
125
|
+
}
|
|
126
|
+
} catch {
|
|
127
|
+
}
|
|
87
128
|
}
|
|
129
|
+
return [...new Set(patterns)];
|
|
130
|
+
};
|
|
131
|
+
var expandWorkspacePattern = (projectRoot, pattern) => {
|
|
132
|
+
const results = [];
|
|
133
|
+
const cleanPattern = pattern.replace(/\/\*$/, "");
|
|
134
|
+
const basePath = path.join(projectRoot, cleanPattern);
|
|
135
|
+
if (!fs.existsSync(basePath)) return results;
|
|
136
|
+
try {
|
|
137
|
+
const entries = fs.readdirSync(basePath, { withFileTypes: true });
|
|
138
|
+
for (const entry of entries) {
|
|
139
|
+
if (entry.isDirectory()) {
|
|
140
|
+
const packageJsonPath = path.join(basePath, entry.name, "package.json");
|
|
141
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
142
|
+
results.push(path.join(basePath, entry.name));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
} catch {
|
|
147
|
+
return results;
|
|
148
|
+
}
|
|
149
|
+
return results;
|
|
150
|
+
};
|
|
151
|
+
var hasReactDependency = (projectPath) => {
|
|
152
|
+
const packageJsonPath = path.join(projectPath, "package.json");
|
|
153
|
+
if (!fs.existsSync(packageJsonPath)) return false;
|
|
88
154
|
try {
|
|
89
155
|
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
...packageJson.devDependencies
|
|
93
|
-
};
|
|
94
|
-
return Boolean(allDependencies["react-grab"]);
|
|
156
|
+
const allDeps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
157
|
+
return Boolean(allDeps["react"] || allDeps["react-dom"]);
|
|
95
158
|
} catch {
|
|
96
159
|
return false;
|
|
97
160
|
}
|
|
98
161
|
};
|
|
162
|
+
var findWorkspaceProjects = (projectRoot) => {
|
|
163
|
+
const patterns = getWorkspacePatterns(projectRoot);
|
|
164
|
+
const projects = [];
|
|
165
|
+
for (const pattern of patterns) {
|
|
166
|
+
const projectPaths = expandWorkspacePattern(projectRoot, pattern);
|
|
167
|
+
for (const projectPath of projectPaths) {
|
|
168
|
+
const framework = detectFramework(projectPath);
|
|
169
|
+
const hasReact = hasReactDependency(projectPath);
|
|
170
|
+
if (hasReact || framework !== "unknown") {
|
|
171
|
+
const packageJsonPath = path.join(projectPath, "package.json");
|
|
172
|
+
let name = path.basename(projectPath);
|
|
173
|
+
try {
|
|
174
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
175
|
+
name = packageJson.name || name;
|
|
176
|
+
} catch {
|
|
177
|
+
}
|
|
178
|
+
projects.push({
|
|
179
|
+
name,
|
|
180
|
+
path: projectPath,
|
|
181
|
+
framework,
|
|
182
|
+
hasReact
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return projects;
|
|
188
|
+
};
|
|
189
|
+
var hasReactGrabInFile = (filePath) => {
|
|
190
|
+
if (!fs.existsSync(filePath)) return false;
|
|
191
|
+
try {
|
|
192
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
193
|
+
const fuzzyPatterns = [
|
|
194
|
+
/["'`][^"'`]*react-grab/,
|
|
195
|
+
/react-grab[^"'`]*["'`]/,
|
|
196
|
+
/<[^>]*react-grab/i,
|
|
197
|
+
/import[^;]*react-grab/i,
|
|
198
|
+
/require[^)]*react-grab/i,
|
|
199
|
+
/from\s+[^;]*react-grab/i,
|
|
200
|
+
/src[^>]*react-grab/i
|
|
201
|
+
];
|
|
202
|
+
return fuzzyPatterns.some((pattern) => pattern.test(content));
|
|
203
|
+
} catch {
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
var detectReactGrab = (projectRoot) => {
|
|
208
|
+
const packageJsonPath = path.join(projectRoot, "package.json");
|
|
209
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
210
|
+
try {
|
|
211
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
212
|
+
const allDependencies = {
|
|
213
|
+
...packageJson.dependencies,
|
|
214
|
+
...packageJson.devDependencies
|
|
215
|
+
};
|
|
216
|
+
if (allDependencies["react-grab"]) {
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
} catch {
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
const filesToCheck = [
|
|
223
|
+
path.join(projectRoot, "app", "layout.tsx"),
|
|
224
|
+
path.join(projectRoot, "app", "layout.jsx"),
|
|
225
|
+
path.join(projectRoot, "src", "app", "layout.tsx"),
|
|
226
|
+
path.join(projectRoot, "src", "app", "layout.jsx"),
|
|
227
|
+
path.join(projectRoot, "pages", "_document.tsx"),
|
|
228
|
+
path.join(projectRoot, "pages", "_document.jsx"),
|
|
229
|
+
path.join(projectRoot, "instrumentation-client.ts"),
|
|
230
|
+
path.join(projectRoot, "instrumentation-client.js"),
|
|
231
|
+
path.join(projectRoot, "src", "instrumentation-client.ts"),
|
|
232
|
+
path.join(projectRoot, "src", "instrumentation-client.js"),
|
|
233
|
+
path.join(projectRoot, "index.html"),
|
|
234
|
+
path.join(projectRoot, "public", "index.html"),
|
|
235
|
+
path.join(projectRoot, "src", "index.tsx"),
|
|
236
|
+
path.join(projectRoot, "src", "index.ts"),
|
|
237
|
+
path.join(projectRoot, "src", "main.tsx"),
|
|
238
|
+
path.join(projectRoot, "src", "main.ts")
|
|
239
|
+
];
|
|
240
|
+
return filesToCheck.some(hasReactGrabInFile);
|
|
241
|
+
};
|
|
99
242
|
var AGENT_PACKAGES = ["@react-grab/claude-code", "@react-grab/cursor", "@react-grab/opencode"];
|
|
100
243
|
var detectUnsupportedFramework = (projectRoot) => {
|
|
101
244
|
const packageJsonPath = path.join(projectRoot, "package.json");
|
|
@@ -350,6 +493,19 @@ var WEBPACK_IMPORT_WITH_AGENT = (agent) => {
|
|
|
350
493
|
var SCRIPT_IMPORT = 'import Script from "next/script";';
|
|
351
494
|
|
|
352
495
|
// src/transform.ts
|
|
496
|
+
var hasReactGrabCode = (content) => {
|
|
497
|
+
const fuzzyPatterns = [
|
|
498
|
+
/["'`][^"'`]*react-grab/,
|
|
499
|
+
/react-grab[^"'`]*["'`]/,
|
|
500
|
+
/<[^>]*react-grab/i,
|
|
501
|
+
/import[^;]*react-grab/i,
|
|
502
|
+
/require[^)]*react-grab/i,
|
|
503
|
+
/from\s+[^;]*react-grab/i,
|
|
504
|
+
/src[^>]*react-grab/i,
|
|
505
|
+
/href[^>]*react-grab/i
|
|
506
|
+
];
|
|
507
|
+
return fuzzyPatterns.some((pattern) => pattern.test(content));
|
|
508
|
+
};
|
|
353
509
|
var findLayoutFile = (projectRoot) => {
|
|
354
510
|
const possiblePaths = [
|
|
355
511
|
path.join(projectRoot, "app", "layout.tsx"),
|
|
@@ -364,6 +520,26 @@ var findLayoutFile = (projectRoot) => {
|
|
|
364
520
|
}
|
|
365
521
|
return null;
|
|
366
522
|
};
|
|
523
|
+
var findInstrumentationFile = (projectRoot) => {
|
|
524
|
+
const possiblePaths = [
|
|
525
|
+
path.join(projectRoot, "instrumentation-client.ts"),
|
|
526
|
+
path.join(projectRoot, "instrumentation-client.js"),
|
|
527
|
+
path.join(projectRoot, "src", "instrumentation-client.ts"),
|
|
528
|
+
path.join(projectRoot, "src", "instrumentation-client.js")
|
|
529
|
+
];
|
|
530
|
+
for (const filePath of possiblePaths) {
|
|
531
|
+
if (fs.existsSync(filePath)) {
|
|
532
|
+
return filePath;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
return null;
|
|
536
|
+
};
|
|
537
|
+
var hasReactGrabInInstrumentation = (projectRoot) => {
|
|
538
|
+
const instrumentationPath = findInstrumentationFile(projectRoot);
|
|
539
|
+
if (!instrumentationPath) return false;
|
|
540
|
+
const content = fs.readFileSync(instrumentationPath, "utf-8");
|
|
541
|
+
return hasReactGrabCode(content);
|
|
542
|
+
};
|
|
367
543
|
var findDocumentFile = (projectRoot) => {
|
|
368
544
|
const possiblePaths = [
|
|
369
545
|
path.join(projectRoot, "pages", "_document.tsx"),
|
|
@@ -431,7 +607,7 @@ var addAgentToExistingNextApp = (originalContent, agent, filePath) => {
|
|
|
431
607
|
strategy="lazyOnload"
|
|
432
608
|
/>`;
|
|
433
609
|
const reactGrabScriptMatch = originalContent.match(
|
|
434
|
-
/<Script[^>]*
|
|
610
|
+
/<(?:Script|script|NextScript)[^>]*react-grab[^>]*\/?>/is
|
|
435
611
|
);
|
|
436
612
|
if (reactGrabScriptMatch) {
|
|
437
613
|
const newContent = originalContent.replace(
|
|
@@ -544,15 +720,16 @@ var transformNextAppRouter = (projectRoot, agent, reactGrabAlreadyConfigured) =>
|
|
|
544
720
|
}
|
|
545
721
|
const originalContent = fs.readFileSync(layoutPath, "utf-8");
|
|
546
722
|
let newContent = originalContent;
|
|
547
|
-
const
|
|
548
|
-
|
|
723
|
+
const hasReactGrabInFile2 = hasReactGrabCode(originalContent);
|
|
724
|
+
const hasReactGrabInInstrumentationFile = hasReactGrabInInstrumentation(projectRoot);
|
|
725
|
+
if (hasReactGrabInFile2 && reactGrabAlreadyConfigured) {
|
|
549
726
|
return addAgentToExistingNextApp(originalContent, agent, layoutPath);
|
|
550
727
|
}
|
|
551
|
-
if (
|
|
728
|
+
if (hasReactGrabInFile2 || hasReactGrabInInstrumentationFile) {
|
|
552
729
|
return {
|
|
553
730
|
success: true,
|
|
554
731
|
filePath: layoutPath,
|
|
555
|
-
message: "React Grab is already installed in this file",
|
|
732
|
+
message: "React Grab is already installed" + (hasReactGrabInInstrumentationFile ? " in instrumentation-client" : " in this file"),
|
|
556
733
|
noChanges: true
|
|
557
734
|
};
|
|
558
735
|
}
|
|
@@ -603,15 +780,16 @@ var transformNextPagesRouter = (projectRoot, agent, reactGrabAlreadyConfigured)
|
|
|
603
780
|
}
|
|
604
781
|
const originalContent = fs.readFileSync(documentPath, "utf-8");
|
|
605
782
|
let newContent = originalContent;
|
|
606
|
-
const
|
|
607
|
-
|
|
783
|
+
const hasReactGrabInFile2 = hasReactGrabCode(originalContent);
|
|
784
|
+
const hasReactGrabInInstrumentationFile = hasReactGrabInInstrumentation(projectRoot);
|
|
785
|
+
if (hasReactGrabInFile2 && reactGrabAlreadyConfigured) {
|
|
608
786
|
return addAgentToExistingNextApp(originalContent, agent, documentPath);
|
|
609
787
|
}
|
|
610
|
-
if (
|
|
788
|
+
if (hasReactGrabInFile2 || hasReactGrabInInstrumentationFile) {
|
|
611
789
|
return {
|
|
612
790
|
success: true,
|
|
613
791
|
filePath: documentPath,
|
|
614
|
-
message: "React Grab is already installed in this file",
|
|
792
|
+
message: "React Grab is already installed" + (hasReactGrabInInstrumentationFile ? " in instrumentation-client" : " in this file"),
|
|
615
793
|
noChanges: true
|
|
616
794
|
};
|
|
617
795
|
}
|
|
@@ -647,11 +825,11 @@ var transformVite = (projectRoot, agent, reactGrabAlreadyConfigured) => {
|
|
|
647
825
|
}
|
|
648
826
|
const originalContent = fs.readFileSync(indexPath, "utf-8");
|
|
649
827
|
let newContent = originalContent;
|
|
650
|
-
const
|
|
651
|
-
if (
|
|
828
|
+
const hasReactGrabInFile2 = hasReactGrabCode(originalContent);
|
|
829
|
+
if (hasReactGrabInFile2 && reactGrabAlreadyConfigured) {
|
|
652
830
|
return addAgentToExistingVite(originalContent, agent, indexPath);
|
|
653
831
|
}
|
|
654
|
-
if (
|
|
832
|
+
if (hasReactGrabInFile2) {
|
|
655
833
|
return {
|
|
656
834
|
success: true,
|
|
657
835
|
filePath: indexPath,
|
|
@@ -683,11 +861,11 @@ var transformWebpack = (projectRoot, agent, reactGrabAlreadyConfigured) => {
|
|
|
683
861
|
};
|
|
684
862
|
}
|
|
685
863
|
const originalContent = fs.readFileSync(entryPath, "utf-8");
|
|
686
|
-
const
|
|
687
|
-
if (
|
|
864
|
+
const hasReactGrabInFile2 = hasReactGrabCode(originalContent);
|
|
865
|
+
if (hasReactGrabInFile2 && reactGrabAlreadyConfigured) {
|
|
688
866
|
return addAgentToExistingWebpack(originalContent, agent, entryPath);
|
|
689
867
|
}
|
|
690
|
-
if (
|
|
868
|
+
if (hasReactGrabInFile2) {
|
|
691
869
|
return {
|
|
692
870
|
success: true,
|
|
693
871
|
filePath: entryPath,
|
|
@@ -853,7 +1031,25 @@ var applyPackageJsonTransform = (result) => {
|
|
|
853
1031
|
};
|
|
854
1032
|
|
|
855
1033
|
// src/cli.ts
|
|
856
|
-
var VERSION = "0.0.
|
|
1034
|
+
var VERSION = "0.0.71";
|
|
1035
|
+
var REPORT_URL = "https://reactgrab.com/api/report-cli";
|
|
1036
|
+
var reportToCli = async (type, config, error) => {
|
|
1037
|
+
try {
|
|
1038
|
+
await fetch(REPORT_URL, {
|
|
1039
|
+
method: "POST",
|
|
1040
|
+
headers: { "Content-Type": "application/json" },
|
|
1041
|
+
body: JSON.stringify({
|
|
1042
|
+
type,
|
|
1043
|
+
version: VERSION,
|
|
1044
|
+
config,
|
|
1045
|
+
error: error ? { message: error.message, stack: error.stack } : void 0,
|
|
1046
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1047
|
+
})
|
|
1048
|
+
}).catch(() => {
|
|
1049
|
+
});
|
|
1050
|
+
} catch {
|
|
1051
|
+
}
|
|
1052
|
+
};
|
|
857
1053
|
var FRAMEWORK_NAMES = {
|
|
858
1054
|
next: "Next.js",
|
|
859
1055
|
vite: "Vite",
|
|
@@ -884,49 +1080,122 @@ var showDocsLink = () => {
|
|
|
884
1080
|
`);
|
|
885
1081
|
};
|
|
886
1082
|
var showManualInstructions = (framework, nextRouterType) => {
|
|
887
|
-
console.log(
|
|
1083
|
+
console.log(
|
|
1084
|
+
`
|
|
888
1085
|
${pc__default.default.yellow("\u26A0\uFE0F")} ${pc__default.default.yellow("Manual Setup Instructions:")}
|
|
889
|
-
`
|
|
1086
|
+
`
|
|
1087
|
+
);
|
|
890
1088
|
if (framework === "next" && nextRouterType === "app") {
|
|
891
1089
|
console.log(`${pc__default.default.bold("Next.js App Router:")}`);
|
|
892
1090
|
console.log(` 1. Install: ${pc__default.default.cyan("npm install -D react-grab")}`);
|
|
893
|
-
console.log(` 2. Add to ${pc__default.default.cyan("app/layout.tsx")}
|
|
1091
|
+
console.log(` 2. Add to ${pc__default.default.cyan("app/layout.tsx")} inside <head>:`);
|
|
894
1092
|
console.log(` ${pc__default.default.gray('import Script from "next/script";')}`);
|
|
895
|
-
console.log(
|
|
896
|
-
|
|
1093
|
+
console.log(
|
|
1094
|
+
` ${pc__default.default.gray('{process.env.NODE_ENV === "development" && (')}`
|
|
1095
|
+
);
|
|
1096
|
+
console.log(` ${pc__default.default.gray(" <Script")}`);
|
|
1097
|
+
console.log(
|
|
1098
|
+
` ${pc__default.default.gray(' src="//unpkg.com/react-grab/dist/index.global.js"')}`
|
|
1099
|
+
);
|
|
1100
|
+
console.log(` ${pc__default.default.gray(' crossOrigin="anonymous"')}`);
|
|
1101
|
+
console.log(` ${pc__default.default.gray(' strategy="beforeInteractive"')}`);
|
|
1102
|
+
console.log(` ${pc__default.default.gray(" />")}`);
|
|
1103
|
+
console.log(` ${pc__default.default.gray(")}")}`);
|
|
897
1104
|
} else if (framework === "next" && nextRouterType === "pages") {
|
|
898
1105
|
console.log(`${pc__default.default.bold("Next.js Pages Router:")}`);
|
|
899
1106
|
console.log(` 1. Install: ${pc__default.default.cyan("npm install -D react-grab")}`);
|
|
900
|
-
console.log(` 2.
|
|
1107
|
+
console.log(` 2. Add to ${pc__default.default.cyan("pages/_document.tsx")} inside <Head>:`);
|
|
901
1108
|
console.log(` ${pc__default.default.gray('import Script from "next/script";')}`);
|
|
902
|
-
console.log(
|
|
903
|
-
|
|
1109
|
+
console.log(
|
|
1110
|
+
` ${pc__default.default.gray('{process.env.NODE_ENV === "development" && (')}`
|
|
1111
|
+
);
|
|
1112
|
+
console.log(` ${pc__default.default.gray(" <Script")}`);
|
|
1113
|
+
console.log(
|
|
1114
|
+
` ${pc__default.default.gray(' src="//unpkg.com/react-grab/dist/index.global.js"')}`
|
|
1115
|
+
);
|
|
1116
|
+
console.log(` ${pc__default.default.gray(' crossOrigin="anonymous"')}`);
|
|
1117
|
+
console.log(` ${pc__default.default.gray(' strategy="beforeInteractive"')}`);
|
|
1118
|
+
console.log(` ${pc__default.default.gray(" />")}`);
|
|
1119
|
+
console.log(` ${pc__default.default.gray(")}")}`);
|
|
904
1120
|
} else if (framework === "vite") {
|
|
905
1121
|
console.log(`${pc__default.default.bold("Vite:")}`);
|
|
906
1122
|
console.log(` 1. Install: ${pc__default.default.cyan("npm install -D react-grab")}`);
|
|
907
1123
|
console.log(` 2. Add to ${pc__default.default.cyan("index.html")} inside <head>:`);
|
|
908
1124
|
console.log(` ${pc__default.default.gray('<script type="module">')}`);
|
|
909
|
-
console.log(
|
|
1125
|
+
console.log(
|
|
1126
|
+
` ${pc__default.default.gray(' if (import.meta.env.DEV) { import("react-grab"); }')}`
|
|
1127
|
+
);
|
|
910
1128
|
console.log(` ${pc__default.default.gray("</script>")}`);
|
|
911
1129
|
} else if (framework === "webpack") {
|
|
912
1130
|
console.log(`${pc__default.default.bold("Webpack:")}`);
|
|
913
1131
|
console.log(` 1. Install: ${pc__default.default.cyan("npm install -D react-grab")}`);
|
|
914
|
-
console.log(
|
|
915
|
-
|
|
1132
|
+
console.log(
|
|
1133
|
+
` 2. Add to your entry file (e.g., ${pc__default.default.cyan("src/index.tsx")}):`
|
|
1134
|
+
);
|
|
1135
|
+
console.log(
|
|
1136
|
+
` ${pc__default.default.gray('if (process.env.NODE_ENV === "development") {')}`
|
|
1137
|
+
);
|
|
916
1138
|
console.log(` ${pc__default.default.gray(' import("react-grab");')}`);
|
|
917
1139
|
console.log(` ${pc__default.default.gray("}")}`);
|
|
918
1140
|
} else {
|
|
919
|
-
console.log(
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
console.log(`
|
|
1141
|
+
console.log(
|
|
1142
|
+
`${pc__default.default.bold("Next.js App Router:")} Add to ${pc__default.default.cyan("app/layout.tsx")} inside <head>:`
|
|
1143
|
+
);
|
|
1144
|
+
console.log(` ${pc__default.default.gray('import Script from "next/script";')}`);
|
|
1145
|
+
console.log(
|
|
1146
|
+
` ${pc__default.default.gray('{process.env.NODE_ENV === "development" && (')}`
|
|
1147
|
+
);
|
|
1148
|
+
console.log(
|
|
1149
|
+
` ${pc__default.default.gray(' <Script src="//unpkg.com/react-grab/dist/index.global.js" strategy="beforeInteractive" />')}`
|
|
1150
|
+
);
|
|
1151
|
+
console.log(` ${pc__default.default.gray(")}")}`);
|
|
1152
|
+
console.log("");
|
|
1153
|
+
console.log(
|
|
1154
|
+
`${pc__default.default.bold("Next.js Pages Router:")} Add to ${pc__default.default.cyan("pages/_document.tsx")} inside <Head>:`
|
|
1155
|
+
);
|
|
1156
|
+
console.log(` ${pc__default.default.gray('import Script from "next/script";')}`);
|
|
1157
|
+
console.log(
|
|
1158
|
+
` ${pc__default.default.gray('{process.env.NODE_ENV === "development" && (')}`
|
|
1159
|
+
);
|
|
1160
|
+
console.log(
|
|
1161
|
+
` ${pc__default.default.gray(' <Script src="//unpkg.com/react-grab/dist/index.global.js" strategy="beforeInteractive" />')}`
|
|
1162
|
+
);
|
|
1163
|
+
console.log(` ${pc__default.default.gray(")}")}`);
|
|
1164
|
+
console.log("");
|
|
1165
|
+
console.log(
|
|
1166
|
+
`${pc__default.default.bold("Vite:")} Add to ${pc__default.default.cyan("index.html")} inside <head>:`
|
|
1167
|
+
);
|
|
1168
|
+
console.log(` ${pc__default.default.gray('<script type="module">')}`);
|
|
1169
|
+
console.log(
|
|
1170
|
+
` ${pc__default.default.gray(' if (import.meta.env.DEV) { import("react-grab"); }')}`
|
|
1171
|
+
);
|
|
1172
|
+
console.log(` ${pc__default.default.gray("</script>")}`);
|
|
1173
|
+
console.log("");
|
|
1174
|
+
console.log(
|
|
1175
|
+
`${pc__default.default.bold("Webpack:")} Add to entry file (e.g., ${pc__default.default.cyan("src/index.tsx")}):`
|
|
1176
|
+
);
|
|
1177
|
+
console.log(
|
|
1178
|
+
` ${pc__default.default.gray('if (process.env.NODE_ENV === "development") {')}`
|
|
1179
|
+
);
|
|
1180
|
+
console.log(` ${pc__default.default.gray(' import("react-grab");')}`);
|
|
1181
|
+
console.log(` ${pc__default.default.gray("}")}`);
|
|
1182
|
+
console.log("");
|
|
1183
|
+
console.log(`For full instructions, visit:`);
|
|
1184
|
+
console.log(
|
|
1185
|
+
` ${pc__default.default.cyan("https://github.com/aidenybai/react-grab#readme")}`
|
|
1186
|
+
);
|
|
1187
|
+
return;
|
|
923
1188
|
}
|
|
924
1189
|
showDocsLink();
|
|
925
1190
|
};
|
|
926
1191
|
var showAccuracyWarning = () => {
|
|
927
|
-
console.log(
|
|
928
|
-
|
|
929
|
-
|
|
1192
|
+
console.log(
|
|
1193
|
+
`
|
|
1194
|
+
${pc__default.default.yellow("\u26A0\uFE0F")} ${pc__default.default.yellow("Auto-detection may not be 100% accurate.")}`
|
|
1195
|
+
);
|
|
1196
|
+
console.log(
|
|
1197
|
+
`${pc__default.default.yellow(" Please verify the changes in your file before committing.")}`
|
|
1198
|
+
);
|
|
930
1199
|
};
|
|
931
1200
|
var parseArgs = async () => {
|
|
932
1201
|
const argv = await yargs__default.default(helpers.hideBin(process.argv)).scriptName("react-grab").usage(
|
|
@@ -968,7 +1237,13 @@ router type) and installs React Grab with optional agent integrations.`
|
|
|
968
1237
|
type: "boolean",
|
|
969
1238
|
default: false,
|
|
970
1239
|
description: "Only modify config files, skip npm/yarn/pnpm install"
|
|
971
|
-
}).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(
|
|
1240
|
+
}).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(
|
|
1241
|
+
"$0 -a cursor -y",
|
|
1242
|
+
"Add Cursor agent integration non-interactively"
|
|
1243
|
+
).example("$0 -p pnpm -a claude-code", "Use pnpm and add Claude Code agent").example(
|
|
1244
|
+
"$0 --skip-install",
|
|
1245
|
+
"Only modify files, install packages manually"
|
|
1246
|
+
).epilog(
|
|
972
1247
|
`${pc__default.default.bold("Agent Integrations:")}
|
|
973
1248
|
${pc__default.default.cyan("claude-code")} Connect React Grab to Claude Code
|
|
974
1249
|
${pc__default.default.cyan("cursor")} Connect React Grab to Cursor IDE
|
|
@@ -993,33 +1268,104 @@ ${pc__default.default.bold("Documentation:")} ${pc__default.default.underline(DO
|
|
|
993
1268
|
var main = async () => {
|
|
994
1269
|
const args = await parseArgs();
|
|
995
1270
|
const isNonInteractive = args.yes;
|
|
996
|
-
console.log(
|
|
997
|
-
|
|
1271
|
+
console.log(
|
|
1272
|
+
`
|
|
1273
|
+
${pc__default.default.magenta("\u269B")} ${pc__default.default.bold("React Grab")} ${pc__default.default.gray(VERSION)}`
|
|
1274
|
+
);
|
|
998
1275
|
const projectInfo = await detectProject(process.cwd());
|
|
999
|
-
console.log(
|
|
1000
|
-
|
|
1276
|
+
console.log(
|
|
1277
|
+
`- Framework: ${pc__default.default.cyan(FRAMEWORK_NAMES[projectInfo.framework])}`
|
|
1278
|
+
);
|
|
1279
|
+
console.log(
|
|
1280
|
+
`- Package Manager: ${pc__default.default.cyan(PACKAGE_MANAGER_NAMES[projectInfo.packageManager])}`
|
|
1281
|
+
);
|
|
1001
1282
|
if (projectInfo.framework === "next") {
|
|
1002
|
-
console.log(
|
|
1283
|
+
console.log(
|
|
1284
|
+
`- Router Type: ${pc__default.default.cyan(projectInfo.nextRouterType === "app" ? "App Router" : "Pages Router")}`
|
|
1285
|
+
);
|
|
1003
1286
|
}
|
|
1004
|
-
console.log(
|
|
1005
|
-
|
|
1287
|
+
console.log(
|
|
1288
|
+
`- Monorepo: ${pc__default.default.cyan(projectInfo.isMonorepo ? "Yes" : "No")}`
|
|
1289
|
+
);
|
|
1290
|
+
console.log(
|
|
1291
|
+
`- React Grab: ${projectInfo.hasReactGrab ? pc__default.default.green("Installed") : pc__default.default.yellow("Not installed")}`
|
|
1292
|
+
);
|
|
1006
1293
|
if (projectInfo.installedAgents.length > 0) {
|
|
1007
|
-
console.log(
|
|
1294
|
+
console.log(
|
|
1295
|
+
`- Agents: ${pc__default.default.cyan(projectInfo.installedAgents.map((agent) => AGENT_NAMES[agent] || agent).join(", "))}`
|
|
1296
|
+
);
|
|
1008
1297
|
}
|
|
1009
1298
|
console.log("");
|
|
1010
1299
|
if (projectInfo.unsupportedFramework) {
|
|
1011
1300
|
const frameworkName = UNSUPPORTED_FRAMEWORK_NAMES[projectInfo.unsupportedFramework];
|
|
1012
|
-
console.log(
|
|
1013
|
-
|
|
1014
|
-
|
|
1301
|
+
console.log(
|
|
1302
|
+
`${pc__default.default.yellow("\u26A0\uFE0F")} ${pc__default.default.yellow(`Detected ${frameworkName} - this framework requires manual setup.`)}`
|
|
1303
|
+
);
|
|
1304
|
+
console.log(
|
|
1305
|
+
`${pc__default.default.yellow(" React Grab may not work correctly with auto-configuration.")}
|
|
1306
|
+
`
|
|
1307
|
+
);
|
|
1015
1308
|
showManualInstructions(projectInfo.framework, projectInfo.nextRouterType);
|
|
1016
1309
|
process.exit(0);
|
|
1017
1310
|
}
|
|
1018
1311
|
if (projectInfo.framework === "unknown") {
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1312
|
+
if (projectInfo.isMonorepo && !isNonInteractive) {
|
|
1313
|
+
const workspaceProjects = findWorkspaceProjects(projectInfo.projectRoot);
|
|
1314
|
+
const reactProjects = workspaceProjects.filter(
|
|
1315
|
+
(p) => p.hasReact || p.framework !== "unknown"
|
|
1316
|
+
);
|
|
1317
|
+
if (reactProjects.length > 0) {
|
|
1318
|
+
console.log(
|
|
1319
|
+
`${pc__default.default.cyan("\u2139")} ${pc__default.default.cyan("Found React projects in this monorepo:")}
|
|
1320
|
+
`
|
|
1321
|
+
);
|
|
1322
|
+
const selectedProject = await prompts.select({
|
|
1323
|
+
message: "Select a project to install React Grab:",
|
|
1324
|
+
choices: reactProjects.map((project) => ({
|
|
1325
|
+
name: `${project.name} ${pc__default.default.gray(`(${FRAMEWORK_NAMES[project.framework] || "React"})`)}`,
|
|
1326
|
+
value: project.path
|
|
1327
|
+
}))
|
|
1328
|
+
});
|
|
1329
|
+
console.log(
|
|
1330
|
+
`
|
|
1331
|
+
${pc__default.default.magenta("\u269B")} Switching to ${pc__default.default.cyan(selectedProject)}...
|
|
1332
|
+
`
|
|
1333
|
+
);
|
|
1334
|
+
process.chdir(selectedProject);
|
|
1335
|
+
const newProjectInfo = await detectProject(selectedProject);
|
|
1336
|
+
projectInfo.framework = newProjectInfo.framework;
|
|
1337
|
+
projectInfo.nextRouterType = newProjectInfo.nextRouterType;
|
|
1338
|
+
projectInfo.hasReactGrab = newProjectInfo.hasReactGrab;
|
|
1339
|
+
projectInfo.installedAgents = newProjectInfo.installedAgents;
|
|
1340
|
+
projectInfo.projectRoot = newProjectInfo.projectRoot;
|
|
1341
|
+
console.log(
|
|
1342
|
+
`- Framework: ${pc__default.default.cyan(FRAMEWORK_NAMES[newProjectInfo.framework])}`
|
|
1343
|
+
);
|
|
1344
|
+
if (newProjectInfo.framework === "next") {
|
|
1345
|
+
console.log(
|
|
1346
|
+
`- Router Type: ${pc__default.default.cyan(newProjectInfo.nextRouterType === "app" ? "App Router" : "Pages Router")}`
|
|
1347
|
+
);
|
|
1348
|
+
}
|
|
1349
|
+
console.log(
|
|
1350
|
+
`- React Grab: ${newProjectInfo.hasReactGrab ? pc__default.default.green("Installed") : pc__default.default.yellow("Not installed")}`
|
|
1351
|
+
);
|
|
1352
|
+
console.log("");
|
|
1353
|
+
} else {
|
|
1354
|
+
console.log(
|
|
1355
|
+
`${pc__default.default.yellow("\u26A0\uFE0F")} ${pc__default.default.yellow("Could not detect framework automatically.")}
|
|
1356
|
+
`
|
|
1357
|
+
);
|
|
1358
|
+
showManualInstructions("unknown");
|
|
1359
|
+
process.exit(0);
|
|
1360
|
+
}
|
|
1361
|
+
} else {
|
|
1362
|
+
console.log(
|
|
1363
|
+
`${pc__default.default.yellow("\u26A0\uFE0F")} ${pc__default.default.yellow("Could not detect framework automatically.")}
|
|
1364
|
+
`
|
|
1365
|
+
);
|
|
1366
|
+
showManualInstructions("unknown");
|
|
1367
|
+
process.exit(0);
|
|
1368
|
+
}
|
|
1023
1369
|
}
|
|
1024
1370
|
let action = "install-all";
|
|
1025
1371
|
if (projectInfo.hasReactGrab && !isNonInteractive) {
|
|
@@ -1034,9 +1380,13 @@ ${pc__default.default.magenta("\u269B")} ${pc__default.default.bold("React Grab"
|
|
|
1034
1380
|
} else if (projectInfo.hasReactGrab && args.agent && args.agent !== "none") {
|
|
1035
1381
|
action = "add-agent";
|
|
1036
1382
|
} else if (projectInfo.hasReactGrab && isNonInteractive && !args.agent) {
|
|
1037
|
-
console.log(
|
|
1038
|
-
|
|
1039
|
-
|
|
1383
|
+
console.log(
|
|
1384
|
+
`${pc__default.default.yellow("\u26A0\uFE0F")} ${pc__default.default.yellow("React Grab is already installed.")}`
|
|
1385
|
+
);
|
|
1386
|
+
console.log(
|
|
1387
|
+
`${pc__default.default.yellow(" Use --agent to add an agent, or run without -y for interactive mode.")}
|
|
1388
|
+
`
|
|
1389
|
+
);
|
|
1040
1390
|
action = "reconfigure";
|
|
1041
1391
|
}
|
|
1042
1392
|
let finalFramework = args.framework || projectInfo.framework;
|
|
@@ -1088,9 +1438,11 @@ ${pc__default.default.magenta("\u269B")} ${pc__default.default.bold("React Grab"
|
|
|
1088
1438
|
{ name: "Opencode", value: "opencode" }
|
|
1089
1439
|
].filter((agent) => !projectInfo.installedAgents.includes(agent.value));
|
|
1090
1440
|
if (availableAgents.length === 0) {
|
|
1091
|
-
console.log(
|
|
1441
|
+
console.log(
|
|
1442
|
+
`
|
|
1092
1443
|
${pc__default.default.green("All agent integrations are already installed.")}
|
|
1093
|
-
`
|
|
1444
|
+
`
|
|
1445
|
+
);
|
|
1094
1446
|
} else if (action === "add-agent") {
|
|
1095
1447
|
agentIntegration = await prompts.select({
|
|
1096
1448
|
message: "Select an agent integration to add:",
|
|
@@ -1146,7 +1498,11 @@ ${pc__default.default.magenta("\u269B")} Previewing changes...
|
|
|
1146
1498
|
if (hasLayoutChanges) {
|
|
1147
1499
|
console.log("");
|
|
1148
1500
|
}
|
|
1149
|
-
printDiff(
|
|
1501
|
+
printDiff(
|
|
1502
|
+
packageJsonResult.filePath,
|
|
1503
|
+
packageJsonResult.originalContent,
|
|
1504
|
+
packageJsonResult.newContent
|
|
1505
|
+
);
|
|
1150
1506
|
}
|
|
1151
1507
|
if (hasLayoutChanges || hasPackageJsonChanges) {
|
|
1152
1508
|
showAccuracyWarning();
|
|
@@ -1163,16 +1519,25 @@ ${pc__default.default.yellow("Changes cancelled.")}
|
|
|
1163
1519
|
}
|
|
1164
1520
|
}
|
|
1165
1521
|
}
|
|
1166
|
-
const shouldInstallReactGrab = action === "install-all" && !projectInfo.hasReactGrab;
|
|
1522
|
+
const shouldInstallReactGrab = (action === "install-all" || action === "add-agent") && !projectInfo.hasReactGrab;
|
|
1167
1523
|
const shouldInstallAgent = agentIntegration !== "none" && !projectInfo.installedAgents.includes(agentIntegration);
|
|
1168
1524
|
if (!args.skipInstall && (shouldInstallReactGrab || shouldInstallAgent)) {
|
|
1169
|
-
const packages = getPackagesToInstall(
|
|
1525
|
+
const packages = getPackagesToInstall(
|
|
1526
|
+
agentIntegration,
|
|
1527
|
+
shouldInstallReactGrab
|
|
1528
|
+
);
|
|
1170
1529
|
if (packages.length > 0) {
|
|
1171
|
-
console.log(
|
|
1530
|
+
console.log(
|
|
1531
|
+
`
|
|
1172
1532
|
${pc__default.default.magenta("\u269B")} Installing: ${pc__default.default.cyan(packages.join(", "))}
|
|
1173
|
-
`
|
|
1533
|
+
`
|
|
1534
|
+
);
|
|
1174
1535
|
try {
|
|
1175
|
-
installPackages(
|
|
1536
|
+
installPackages(
|
|
1537
|
+
packages,
|
|
1538
|
+
finalPackageManager,
|
|
1539
|
+
projectInfo.projectRoot
|
|
1540
|
+
);
|
|
1176
1541
|
console.log(`
|
|
1177
1542
|
${pc__default.default.green("Packages installed successfully!")}
|
|
1178
1543
|
`);
|
|
@@ -1198,8 +1563,10 @@ ${pc__default.default.green("Applied:")} ${result.filePath}`);
|
|
|
1198
1563
|
if (hasPackageJsonChanges) {
|
|
1199
1564
|
const packageJsonWriteResult = applyPackageJsonTransform(packageJsonResult);
|
|
1200
1565
|
if (!packageJsonWriteResult.success) {
|
|
1201
|
-
console.error(
|
|
1202
|
-
|
|
1566
|
+
console.error(
|
|
1567
|
+
`
|
|
1568
|
+
${pc__default.default.red("Error:")} ${packageJsonWriteResult.error}`
|
|
1569
|
+
);
|
|
1203
1570
|
showDocsLink();
|
|
1204
1571
|
process.exit(1);
|
|
1205
1572
|
}
|
|
@@ -1211,20 +1578,30 @@ ${pc__default.default.red("Error:")} ${packageJsonWriteResult.error}`);
|
|
|
1211
1578
|
${pc__default.default.green("Done!")}`);
|
|
1212
1579
|
console.log(`
|
|
1213
1580
|
Next steps:`);
|
|
1214
|
-
console.log(
|
|
1215
|
-
console.log(
|
|
1216
|
-
console.log(
|
|
1581
|
+
console.log(`- Start your development server`);
|
|
1582
|
+
console.log(`- Select an element to copy its context`);
|
|
1583
|
+
console.log(`- Learn more at ${pc__default.default.cyan(DOCS_URL)}
|
|
1217
1584
|
`);
|
|
1218
1585
|
if (agentIntegration !== "none") {
|
|
1219
|
-
console.log(
|
|
1586
|
+
console.log(
|
|
1587
|
+
`${pc__default.default.magenta("\u269B")} Agent: ${pc__default.default.cyan(AGENT_NAMES[agentIntegration])}`
|
|
1588
|
+
);
|
|
1220
1589
|
console.log(` Make sure to start the agent server before using it.
|
|
1221
1590
|
`);
|
|
1222
1591
|
}
|
|
1592
|
+
await reportToCli("completed", {
|
|
1593
|
+
framework: finalFramework,
|
|
1594
|
+
packageManager: finalPackageManager,
|
|
1595
|
+
router: finalNextRouterType,
|
|
1596
|
+
agent: agentIntegration !== "none" ? agentIntegration : void 0,
|
|
1597
|
+
isMonorepo: projectInfo.isMonorepo
|
|
1598
|
+
});
|
|
1223
1599
|
};
|
|
1224
|
-
main().catch((error) => {
|
|
1600
|
+
main().catch(async (error) => {
|
|
1225
1601
|
console.error(`${pc__default.default.red("Error:")}`, error);
|
|
1226
1602
|
console.log("\nFor manual installation instructions, visit:");
|
|
1227
1603
|
console.log(` ${DOCS_URL}
|
|
1228
1604
|
`);
|
|
1605
|
+
await reportToCli("error", void 0, error);
|
|
1229
1606
|
process.exit(1);
|
|
1230
1607
|
});
|