@react-grab/cli 0.1.44 → 0.1.45-dev.b85b9b1
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/README.md +3 -3
- package/dist/cli.cjs +181 -184
- package/dist/cli.js +181 -184
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
- package/skills/react-grab/SKILL.md +31 -10
package/dist/cli.js
CHANGED
|
@@ -25,6 +25,71 @@ const AGENT_ENVIRONMENT_VARIABLES = [
|
|
|
25
25
|
const isEnvironmentVariableSet = (variable) => Boolean(process.env[variable]);
|
|
26
26
|
const detectNonInteractive = (yesFlag) => yesFlag || AGENT_ENVIRONMENT_VARIABLES.some(isEnvironmentVariableSet) || !process.stdin.isTTY;
|
|
27
27
|
//#endregion
|
|
28
|
+
//#region src/utils/react-grab-code.ts
|
|
29
|
+
const REACT_GRAB_SPECIFIER_PATTERN = String.raw`react-grab(?:\/[^"']+)?`;
|
|
30
|
+
const stripComments = (content) => content.replace(/<!--[\s\S]*?-->/g, "").replace(/\{\/\*[\s\S]*?\*\/\}/g, "").replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|\s)\/\/.*$/gm, "$1");
|
|
31
|
+
const stripTypeOnlyReactGrabImports = (content) => {
|
|
32
|
+
return content.replace(new RegExp(String.raw`import\s+type\s+[^;]+from\s+["']${REACT_GRAB_SPECIFIER_PATTERN}["'];?`, "g"), "").replace(new RegExp(String.raw`import\s*\{\s*type\s+[^,}]+(?:\s*,\s*type\s+[^,}]+)*\s*,?\s*\}\s*from\s+["']${REACT_GRAB_SPECIFIER_PATTERN}["'];?`, "g"), "");
|
|
33
|
+
};
|
|
34
|
+
const hasReactGrabSetupCode = (content) => {
|
|
35
|
+
const setupCandidateContent = stripTypeOnlyReactGrabImports(stripComments(content));
|
|
36
|
+
return [
|
|
37
|
+
new RegExp(String.raw`import\s*\(\s*["']${REACT_GRAB_SPECIFIER_PATTERN}["']\s*\)`),
|
|
38
|
+
new RegExp(String.raw`import\s+(?!type\b)(?:[^"';]+from\s+)?["']${REACT_GRAB_SPECIFIER_PATTERN}["']`),
|
|
39
|
+
new RegExp(String.raw`require\s*\(\s*["']${REACT_GRAB_SPECIFIER_PATTERN}["']\s*\)`),
|
|
40
|
+
/<Script[\s\S]*?src\s*=\s*(?:["'][^"']*react-grab[^"']*["']|\{(?:["'][^"']*react-grab[^"']*["']|`[^`]*react-grab[^`]*`)\})/i,
|
|
41
|
+
/<script[\s\S]*?src\s*=\s*["'][^"']*react-grab[^"']*["']/i
|
|
42
|
+
].some((pattern) => pattern.test(setupCandidateContent));
|
|
43
|
+
};
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/utils/react-grab-setup-files.ts
|
|
46
|
+
const COMPONENT_EXTENSIONS = [
|
|
47
|
+
"tsx",
|
|
48
|
+
"jsx",
|
|
49
|
+
"ts",
|
|
50
|
+
"js"
|
|
51
|
+
];
|
|
52
|
+
const INSTRUMENTATION_EXTENSIONS = [
|
|
53
|
+
"ts",
|
|
54
|
+
"tsx",
|
|
55
|
+
"js",
|
|
56
|
+
"jsx",
|
|
57
|
+
"mts",
|
|
58
|
+
"cts",
|
|
59
|
+
"mjs",
|
|
60
|
+
"cjs"
|
|
61
|
+
];
|
|
62
|
+
const ROUTE_EXTENSIONS = ["tsx", "jsx"];
|
|
63
|
+
const createFileCandidates = (projectRoot, directories, baseName, extensions) => {
|
|
64
|
+
const fileCandidates = [];
|
|
65
|
+
for (const directory of directories) for (const extension of extensions) fileCandidates.push(join(projectRoot, directory, `${baseName}.${extension}`));
|
|
66
|
+
return fileCandidates;
|
|
67
|
+
};
|
|
68
|
+
const findExistingFile = (fileCandidates) => {
|
|
69
|
+
for (const filePath of fileCandidates) if (existsSync(filePath)) return filePath;
|
|
70
|
+
return null;
|
|
71
|
+
};
|
|
72
|
+
const getLayoutFileCandidates = (projectRoot) => createFileCandidates(projectRoot, ["app", "src/app"], "layout", COMPONENT_EXTENSIONS);
|
|
73
|
+
const getDocumentFileCandidates = (projectRoot) => createFileCandidates(projectRoot, ["pages", "src/pages"], "_document", COMPONENT_EXTENSIONS);
|
|
74
|
+
const getInstrumentationFileCandidates = (projectRoot) => createFileCandidates(projectRoot, ["", "src"], "instrumentation-client", INSTRUMENTATION_EXTENSIONS);
|
|
75
|
+
const getIndexHtmlCandidates = (projectRoot) => [join(projectRoot, "index.html"), join(projectRoot, "public", "index.html")];
|
|
76
|
+
const getEntryFileCandidates = (projectRoot) => [...createFileCandidates(projectRoot, ["src"], "index", COMPONENT_EXTENSIONS), ...createFileCandidates(projectRoot, ["src"], "main", COMPONENT_EXTENSIONS)];
|
|
77
|
+
const getTanStackRootFileCandidates = (projectRoot) => createFileCandidates(projectRoot, ["src/routes", "app/routes"], "__root", ROUTE_EXTENSIONS);
|
|
78
|
+
const getReactGrabSetupFileCandidates = (projectRoot) => [
|
|
79
|
+
...getLayoutFileCandidates(projectRoot),
|
|
80
|
+
...getDocumentFileCandidates(projectRoot),
|
|
81
|
+
...getInstrumentationFileCandidates(projectRoot),
|
|
82
|
+
...getIndexHtmlCandidates(projectRoot),
|
|
83
|
+
...getEntryFileCandidates(projectRoot),
|
|
84
|
+
...getTanStackRootFileCandidates(projectRoot)
|
|
85
|
+
];
|
|
86
|
+
const findLayoutFile = (projectRoot) => findExistingFile(getLayoutFileCandidates(projectRoot));
|
|
87
|
+
const findDocumentFile = (projectRoot) => findExistingFile(getDocumentFileCandidates(projectRoot));
|
|
88
|
+
const findIndexHtml = (projectRoot) => findExistingFile(getIndexHtmlCandidates(projectRoot));
|
|
89
|
+
const findEntryFile = (projectRoot) => findExistingFile(getEntryFileCandidates(projectRoot));
|
|
90
|
+
const findTanStackRootFile = (projectRoot) => findExistingFile(getTanStackRootFileCandidates(projectRoot));
|
|
91
|
+
const isInstrumentationFile = (filePath) => /(?:^|[/\\])instrumentation-client\.[cm]?[jt]sx?$/.test(filePath);
|
|
92
|
+
//#endregion
|
|
28
93
|
//#region src/utils/detect.ts
|
|
29
94
|
const VALID_PACKAGE_MANAGERS = new Set([
|
|
30
95
|
"npm",
|
|
@@ -238,10 +303,14 @@ const scanDirectoryForProjects = (rootDirectory, ignorer, maxDepth, currentDepth
|
|
|
238
303
|
return projects;
|
|
239
304
|
};
|
|
240
305
|
const MAX_SCAN_DEPTH = 2;
|
|
306
|
+
const normalizePathForComparison = (filePath) => filePath.replace(/\\/g, "/");
|
|
241
307
|
const findReactProjects = (projectRoot) => {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
308
|
+
const monorepoRoot = detectMonorepo(projectRoot) ? projectRoot : findEnclosingMonorepoRoot(projectRoot);
|
|
309
|
+
if (monorepoRoot) {
|
|
310
|
+
const workspaceProjects = findWorkspaceProjects(monorepoRoot);
|
|
311
|
+
const localProject = projectRoot === monorepoRoot ? null : buildReactProject(projectRoot);
|
|
312
|
+
const projects = localProject ? [localProject, ...workspaceProjects.filter((project) => normalizePathForComparison(project.path) !== normalizePathForComparison(localProject.path))] : workspaceProjects;
|
|
313
|
+
if (projects.length > 0) return projects;
|
|
245
314
|
}
|
|
246
315
|
const scannedProjects = scanDirectoryForProjects(projectRoot, loadGitignore(projectRoot), MAX_SCAN_DEPTH);
|
|
247
316
|
if (scannedProjects.length > 0) return scannedProjects;
|
|
@@ -253,47 +322,20 @@ const findReactProjects = (projectRoot) => {
|
|
|
253
322
|
}
|
|
254
323
|
return [];
|
|
255
324
|
};
|
|
256
|
-
const
|
|
325
|
+
const hasReactGrabSetupInFile = (filePath) => {
|
|
257
326
|
if (!existsSync(filePath)) return false;
|
|
258
327
|
try {
|
|
259
|
-
|
|
260
|
-
return [
|
|
261
|
-
/["'`][^"'`]*react-grab/,
|
|
262
|
-
/react-grab[^"'`]*["'`]/,
|
|
263
|
-
/<[^>]*react-grab/i,
|
|
264
|
-
/import[^;]*react-grab/i,
|
|
265
|
-
/require[^)]*react-grab/i,
|
|
266
|
-
/from\s+[^;]*react-grab/i,
|
|
267
|
-
/src[^>]*react-grab/i
|
|
268
|
-
].some((pattern) => pattern.test(content));
|
|
328
|
+
return hasReactGrabSetupCode(readFileSync(filePath, "utf-8"));
|
|
269
329
|
} catch {
|
|
270
330
|
return false;
|
|
271
331
|
}
|
|
272
332
|
};
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
return [
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
join(projectRoot, "src", "app", "layout.jsx"),
|
|
280
|
-
join(projectRoot, "pages", "_document.tsx"),
|
|
281
|
-
join(projectRoot, "pages", "_document.jsx"),
|
|
282
|
-
join(projectRoot, "instrumentation-client.ts"),
|
|
283
|
-
join(projectRoot, "instrumentation-client.js"),
|
|
284
|
-
join(projectRoot, "src", "instrumentation-client.ts"),
|
|
285
|
-
join(projectRoot, "src", "instrumentation-client.js"),
|
|
286
|
-
join(projectRoot, "index.html"),
|
|
287
|
-
join(projectRoot, "public", "index.html"),
|
|
288
|
-
join(projectRoot, "src", "index.tsx"),
|
|
289
|
-
join(projectRoot, "src", "index.ts"),
|
|
290
|
-
join(projectRoot, "src", "main.tsx"),
|
|
291
|
-
join(projectRoot, "src", "main.ts"),
|
|
292
|
-
join(projectRoot, "src", "routes", "__root.tsx"),
|
|
293
|
-
join(projectRoot, "src", "routes", "__root.jsx"),
|
|
294
|
-
join(projectRoot, "app", "routes", "__root.tsx"),
|
|
295
|
-
join(projectRoot, "app", "routes", "__root.jsx")
|
|
296
|
-
].some(hasReactGrabInFile);
|
|
333
|
+
const detectReactGrabDependency = (projectRoot) => {
|
|
334
|
+
const dependencies = readMergedDependencies(projectRoot);
|
|
335
|
+
return Boolean(dependencies?.["react-grab"]);
|
|
336
|
+
};
|
|
337
|
+
const detectReactGrabConfigured = (projectRoot) => {
|
|
338
|
+
return getReactGrabSetupFileCandidates(projectRoot).some(hasReactGrabSetupInFile);
|
|
297
339
|
};
|
|
298
340
|
const detectUnsupportedFramework = (projectRoot) => {
|
|
299
341
|
const dependencies = readMergedDependencies(projectRoot);
|
|
@@ -314,13 +356,17 @@ const detectReactGrabVersion = (projectRoot) => {
|
|
|
314
356
|
const detectProject = async (projectRoot = process.cwd()) => {
|
|
315
357
|
const localFramework = detectFramework(projectRoot);
|
|
316
358
|
const framework = localFramework === "unknown" ? detectFrameworkFromMonorepoRoot(projectRoot) : localFramework;
|
|
359
|
+
const packageManager = await detectPackageManager(projectRoot);
|
|
360
|
+
const isMonorepo = detectMonorepo(projectRoot) || findEnclosingMonorepoRoot(projectRoot) !== null;
|
|
361
|
+
const isReactGrabConfigured = detectReactGrabConfigured(projectRoot);
|
|
317
362
|
return {
|
|
318
|
-
packageManager
|
|
363
|
+
packageManager,
|
|
319
364
|
framework,
|
|
320
365
|
nextRouterType: framework === "next" ? detectNextRouterType(projectRoot) : "unknown",
|
|
321
|
-
isMonorepo
|
|
366
|
+
isMonorepo,
|
|
322
367
|
projectRoot,
|
|
323
|
-
hasReactGrab:
|
|
368
|
+
hasReactGrab: detectReactGrabDependency(projectRoot) || isReactGrabConfigured,
|
|
369
|
+
isReactGrabConfigured,
|
|
324
370
|
reactGrabVersion: detectReactGrabVersion(projectRoot),
|
|
325
371
|
unsupportedFramework: detectUnsupportedFramework(projectRoot)
|
|
326
372
|
};
|
|
@@ -491,7 +537,7 @@ const removeSkill = async ({ cwd = process.cwd(), global = false } = {}) => {
|
|
|
491
537
|
};
|
|
492
538
|
//#endregion
|
|
493
539
|
//#region src/commands/add.ts
|
|
494
|
-
const VERSION$5 = "0.1.
|
|
540
|
+
const VERSION$5 = "0.1.45-dev.b85b9b1";
|
|
495
541
|
const add$1 = new Command().name("add").alias("install").description("install the React Grab skill for your agent").option("-y, --yes", "skip confirmation prompts", false).option("-c, --cwd <cwd>", "working directory (defaults to current directory)", process.cwd()).option("-g, --global", "install the skill globally instead of in the project", false).action(async (opts) => {
|
|
496
542
|
console.log(`${pc.magenta("✿")} ${pc.bold("React Grab")} ${pc.gray(VERSION$5)}`);
|
|
497
543
|
console.log();
|
|
@@ -646,80 +692,14 @@ const TANSTACK_EFFECT = `useEffect(() => {
|
|
|
646
692
|
const SCRIPT_IMPORT = "import Script from \"next/script\";";
|
|
647
693
|
//#endregion
|
|
648
694
|
//#region src/utils/transform.ts
|
|
649
|
-
const hasReactGrabCode = (content) => {
|
|
650
|
-
return [
|
|
651
|
-
/["'`][^"'`]*react-grab/,
|
|
652
|
-
/react-grab[^"'`]*["'`]/,
|
|
653
|
-
/<[^>]*react-grab/i,
|
|
654
|
-
/import[^;]*react-grab/i,
|
|
655
|
-
/require[^)]*react-grab/i,
|
|
656
|
-
/from\s+[^;]*react-grab/i,
|
|
657
|
-
/src[^>]*react-grab/i,
|
|
658
|
-
/href[^>]*react-grab/i
|
|
659
|
-
].some((pattern) => pattern.test(content));
|
|
660
|
-
};
|
|
661
|
-
const findLayoutFile = (projectRoot) => {
|
|
662
|
-
const possiblePaths = [
|
|
663
|
-
join(projectRoot, "app", "layout.tsx"),
|
|
664
|
-
join(projectRoot, "app", "layout.jsx"),
|
|
665
|
-
join(projectRoot, "src", "app", "layout.tsx"),
|
|
666
|
-
join(projectRoot, "src", "app", "layout.jsx")
|
|
667
|
-
];
|
|
668
|
-
for (const filePath of possiblePaths) if (existsSync(filePath)) return filePath;
|
|
669
|
-
return null;
|
|
670
|
-
};
|
|
671
|
-
const findInstrumentationFile = (projectRoot) => {
|
|
672
|
-
const possiblePaths = [
|
|
673
|
-
join(projectRoot, "instrumentation-client.ts"),
|
|
674
|
-
join(projectRoot, "instrumentation-client.js"),
|
|
675
|
-
join(projectRoot, "src", "instrumentation-client.ts"),
|
|
676
|
-
join(projectRoot, "src", "instrumentation-client.js")
|
|
677
|
-
];
|
|
678
|
-
for (const filePath of possiblePaths) if (existsSync(filePath)) return filePath;
|
|
679
|
-
return null;
|
|
680
|
-
};
|
|
681
695
|
const hasReactGrabInInstrumentation = (projectRoot) => {
|
|
682
|
-
|
|
683
|
-
if (!instrumentationPath) return false;
|
|
684
|
-
return hasReactGrabCode(readFileSync(instrumentationPath, "utf-8"));
|
|
685
|
-
};
|
|
686
|
-
const findDocumentFile = (projectRoot) => {
|
|
687
|
-
const possiblePaths = [
|
|
688
|
-
join(projectRoot, "pages", "_document.tsx"),
|
|
689
|
-
join(projectRoot, "pages", "_document.jsx"),
|
|
690
|
-
join(projectRoot, "src", "pages", "_document.tsx"),
|
|
691
|
-
join(projectRoot, "src", "pages", "_document.jsx")
|
|
692
|
-
];
|
|
693
|
-
for (const filePath of possiblePaths) if (existsSync(filePath)) return filePath;
|
|
694
|
-
return null;
|
|
695
|
-
};
|
|
696
|
-
const findIndexHtml = (projectRoot) => {
|
|
697
|
-
const possiblePaths = [join(projectRoot, "index.html"), join(projectRoot, "public", "index.html")];
|
|
698
|
-
for (const filePath of possiblePaths) if (existsSync(filePath)) return filePath;
|
|
699
|
-
return null;
|
|
700
|
-
};
|
|
701
|
-
const findEntryFile = (projectRoot) => {
|
|
702
|
-
const possiblePaths = [
|
|
703
|
-
join(projectRoot, "src", "index.tsx"),
|
|
704
|
-
join(projectRoot, "src", "index.jsx"),
|
|
705
|
-
join(projectRoot, "src", "index.ts"),
|
|
706
|
-
join(projectRoot, "src", "index.js"),
|
|
707
|
-
join(projectRoot, "src", "main.tsx"),
|
|
708
|
-
join(projectRoot, "src", "main.jsx"),
|
|
709
|
-
join(projectRoot, "src", "main.ts"),
|
|
710
|
-
join(projectRoot, "src", "main.js")
|
|
711
|
-
];
|
|
712
|
-
for (const filePath of possiblePaths) if (existsSync(filePath)) return filePath;
|
|
713
|
-
return null;
|
|
696
|
+
return findFileWithReactGrabSetup(getInstrumentationFileCandidates(projectRoot)) !== null;
|
|
714
697
|
};
|
|
715
|
-
const
|
|
716
|
-
const
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
join(projectRoot, "app", "routes", "__root.jsx")
|
|
721
|
-
];
|
|
722
|
-
for (const filePath of possiblePaths) if (existsSync(filePath)) return filePath;
|
|
698
|
+
const findFileWithReactGrabSetup = (fileCandidates) => {
|
|
699
|
+
for (const filePath of fileCandidates) {
|
|
700
|
+
if (!existsSync(filePath)) continue;
|
|
701
|
+
if (hasReactGrabSetupCode(readFileSync(filePath, "utf-8"))) return filePath;
|
|
702
|
+
}
|
|
723
703
|
return null;
|
|
724
704
|
};
|
|
725
705
|
const alreadyConfiguredResult = (filePath) => ({
|
|
@@ -728,19 +708,19 @@ const alreadyConfiguredResult = (filePath) => ({
|
|
|
728
708
|
message: "React Grab is already configured",
|
|
729
709
|
noChanges: true
|
|
730
710
|
});
|
|
731
|
-
const transformNextAppRouter = (projectRoot, reactGrabAlreadyConfigured
|
|
711
|
+
const transformNextAppRouter = (projectRoot, reactGrabAlreadyConfigured) => {
|
|
732
712
|
const layoutPath = findLayoutFile(projectRoot);
|
|
733
713
|
if (!layoutPath) return {
|
|
734
714
|
success: false,
|
|
735
715
|
filePath: "",
|
|
736
|
-
message: "Could not find app/layout.tsx or app/layout.
|
|
716
|
+
message: "Could not find app/layout.tsx, app/layout.jsx, app/layout.ts, or app/layout.js"
|
|
737
717
|
};
|
|
738
718
|
const originalContent = readFileSync(layoutPath, "utf-8");
|
|
739
719
|
let newContent = originalContent;
|
|
740
|
-
const hasReactGrabInFile =
|
|
720
|
+
const hasReactGrabInFile = hasReactGrabSetupCode(originalContent);
|
|
741
721
|
const hasReactGrabInInstrumentationFile = hasReactGrabInInstrumentation(projectRoot);
|
|
742
|
-
if (
|
|
743
|
-
if (
|
|
722
|
+
if (hasReactGrabInFile && reactGrabAlreadyConfigured) return alreadyConfiguredResult(layoutPath);
|
|
723
|
+
if (hasReactGrabInFile || hasReactGrabInInstrumentationFile) return {
|
|
744
724
|
success: true,
|
|
745
725
|
filePath: layoutPath,
|
|
746
726
|
message: "React Grab is already installed" + (hasReactGrabInInstrumentationFile ? " in instrumentation-client" : " in this file"),
|
|
@@ -765,19 +745,19 @@ const transformNextAppRouter = (projectRoot, reactGrabAlreadyConfigured, force =
|
|
|
765
745
|
newContent
|
|
766
746
|
};
|
|
767
747
|
};
|
|
768
|
-
const transformNextPagesRouter = (projectRoot, reactGrabAlreadyConfigured
|
|
748
|
+
const transformNextPagesRouter = (projectRoot, reactGrabAlreadyConfigured) => {
|
|
769
749
|
const documentPath = findDocumentFile(projectRoot);
|
|
770
750
|
if (!documentPath) return {
|
|
771
751
|
success: false,
|
|
772
752
|
filePath: "",
|
|
773
|
-
message: "Could not find pages/_document.tsx or pages/_document.
|
|
753
|
+
message: "Could not find pages/_document.tsx, pages/_document.jsx, pages/_document.ts, or pages/_document.js.\n\nTo set up React Grab with Pages Router, create pages/_document.tsx with:\n\n import { Html, Head, Main, NextScript } from \"next/document\";\n import Script from \"next/script\";\n\n export default function Document() {\n return (\n <Html>\n <Head>\n {process.env.NODE_ENV === \"development\" && (\n <Script src=\"//unpkg.com/react-grab/dist/index.global.js\" strategy=\"beforeInteractive\" />\n )}\n </Head>\n <body>\n <Main />\n <NextScript />\n </body>\n </Html>\n );\n }"
|
|
774
754
|
};
|
|
775
755
|
const originalContent = readFileSync(documentPath, "utf-8");
|
|
776
756
|
let newContent = originalContent;
|
|
777
|
-
const hasReactGrabInFile =
|
|
757
|
+
const hasReactGrabInFile = hasReactGrabSetupCode(originalContent);
|
|
778
758
|
const hasReactGrabInInstrumentationFile = hasReactGrabInInstrumentation(projectRoot);
|
|
779
|
-
if (
|
|
780
|
-
if (
|
|
759
|
+
if (hasReactGrabInFile && reactGrabAlreadyConfigured) return alreadyConfiguredResult(documentPath);
|
|
760
|
+
if (hasReactGrabInFile || hasReactGrabInInstrumentationFile) return {
|
|
781
761
|
success: true,
|
|
782
762
|
filePath: documentPath,
|
|
783
763
|
message: "React Grab is already installed" + (hasReactGrabInInstrumentationFile ? " in instrumentation-client" : " in this file"),
|
|
@@ -798,7 +778,7 @@ const transformNextPagesRouter = (projectRoot, reactGrabAlreadyConfigured, force
|
|
|
798
778
|
};
|
|
799
779
|
};
|
|
800
780
|
const checkExistingInstallation = (filePath, reactGrabAlreadyConfigured) => {
|
|
801
|
-
if (!
|
|
781
|
+
if (!hasReactGrabSetupCode(readFileSync(filePath, "utf-8"))) return null;
|
|
802
782
|
return {
|
|
803
783
|
success: true,
|
|
804
784
|
filePath,
|
|
@@ -806,24 +786,20 @@ const checkExistingInstallation = (filePath, reactGrabAlreadyConfigured) => {
|
|
|
806
786
|
noChanges: true
|
|
807
787
|
};
|
|
808
788
|
};
|
|
809
|
-
const transformVite = (projectRoot, reactGrabAlreadyConfigured
|
|
789
|
+
const transformVite = (projectRoot, reactGrabAlreadyConfigured) => {
|
|
810
790
|
const entryPath = findEntryFile(projectRoot);
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
if (existingResult) return existingResult;
|
|
816
|
-
}
|
|
791
|
+
const indexPath = findIndexHtml(projectRoot);
|
|
792
|
+
if (indexPath) {
|
|
793
|
+
const existingResult = checkExistingInstallation(indexPath, reactGrabAlreadyConfigured);
|
|
794
|
+
if (existingResult) return existingResult;
|
|
817
795
|
}
|
|
818
796
|
if (!entryPath) return {
|
|
819
797
|
success: false,
|
|
820
798
|
filePath: "",
|
|
821
799
|
message: "Could not find entry file (src/index.tsx, src/main.tsx, etc.)"
|
|
822
800
|
};
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
if (existingResult) return existingResult;
|
|
826
|
-
}
|
|
801
|
+
const existingResult = checkExistingInstallation(entryPath, reactGrabAlreadyConfigured);
|
|
802
|
+
if (existingResult) return existingResult;
|
|
827
803
|
const originalContent = readFileSync(entryPath, "utf-8");
|
|
828
804
|
return {
|
|
829
805
|
success: true,
|
|
@@ -833,17 +809,15 @@ const transformVite = (projectRoot, reactGrabAlreadyConfigured, force = false) =
|
|
|
833
809
|
newContent: `${VITE_IMPORT}\n\n${originalContent}`
|
|
834
810
|
};
|
|
835
811
|
};
|
|
836
|
-
const transformWebpack = (projectRoot, reactGrabAlreadyConfigured
|
|
812
|
+
const transformWebpack = (projectRoot, reactGrabAlreadyConfigured) => {
|
|
837
813
|
const entryPath = findEntryFile(projectRoot);
|
|
838
814
|
if (!entryPath) return {
|
|
839
815
|
success: false,
|
|
840
816
|
filePath: "",
|
|
841
817
|
message: "Could not find entry file (src/index.tsx, src/main.tsx, etc.)"
|
|
842
818
|
};
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
if (existingResult) return existingResult;
|
|
846
|
-
}
|
|
819
|
+
const existingResult = checkExistingInstallation(entryPath, reactGrabAlreadyConfigured);
|
|
820
|
+
if (existingResult) return existingResult;
|
|
847
821
|
const originalContent = readFileSync(entryPath, "utf-8");
|
|
848
822
|
return {
|
|
849
823
|
success: true,
|
|
@@ -853,7 +827,7 @@ const transformWebpack = (projectRoot, reactGrabAlreadyConfigured, force = false
|
|
|
853
827
|
newContent: `${WEBPACK_IMPORT}\n\n${originalContent}`
|
|
854
828
|
};
|
|
855
829
|
};
|
|
856
|
-
const transformTanStack = (projectRoot, reactGrabAlreadyConfigured
|
|
830
|
+
const transformTanStack = (projectRoot, reactGrabAlreadyConfigured) => {
|
|
857
831
|
const rootPath = findTanStackRootFile(projectRoot);
|
|
858
832
|
if (!rootPath) return {
|
|
859
833
|
success: false,
|
|
@@ -862,9 +836,9 @@ const transformTanStack = (projectRoot, reactGrabAlreadyConfigured, force = fals
|
|
|
862
836
|
};
|
|
863
837
|
const originalContent = readFileSync(rootPath, "utf-8");
|
|
864
838
|
let newContent = originalContent;
|
|
865
|
-
const hasReactGrabInFile =
|
|
866
|
-
if (
|
|
867
|
-
if (
|
|
839
|
+
const hasReactGrabInFile = hasReactGrabSetupCode(originalContent);
|
|
840
|
+
if (hasReactGrabInFile && reactGrabAlreadyConfigured) return alreadyConfiguredResult(rootPath);
|
|
841
|
+
if (hasReactGrabInFile) return {
|
|
868
842
|
success: true,
|
|
869
843
|
filePath: rootPath,
|
|
870
844
|
message: "React Grab is already installed in this file",
|
|
@@ -907,14 +881,14 @@ const hasFrameworkEntryPoint = (projectRoot, framework, nextRouterType) => {
|
|
|
907
881
|
default: return false;
|
|
908
882
|
}
|
|
909
883
|
};
|
|
910
|
-
const previewTransform = (projectRoot, framework, nextRouterType, reactGrabAlreadyConfigured = false
|
|
884
|
+
const previewTransform = (projectRoot, framework, nextRouterType, reactGrabAlreadyConfigured = false) => {
|
|
911
885
|
switch (framework) {
|
|
912
886
|
case "next":
|
|
913
|
-
if (nextRouterType === "app") return transformNextAppRouter(projectRoot, reactGrabAlreadyConfigured
|
|
914
|
-
return transformNextPagesRouter(projectRoot, reactGrabAlreadyConfigured
|
|
915
|
-
case "vite": return transformVite(projectRoot, reactGrabAlreadyConfigured
|
|
916
|
-
case "tanstack": return transformTanStack(projectRoot, reactGrabAlreadyConfigured
|
|
917
|
-
case "webpack": return transformWebpack(projectRoot, reactGrabAlreadyConfigured
|
|
887
|
+
if (nextRouterType === "app") return transformNextAppRouter(projectRoot, reactGrabAlreadyConfigured);
|
|
888
|
+
return transformNextPagesRouter(projectRoot, reactGrabAlreadyConfigured);
|
|
889
|
+
case "vite": return transformVite(projectRoot, reactGrabAlreadyConfigured);
|
|
890
|
+
case "tanstack": return transformTanStack(projectRoot, reactGrabAlreadyConfigured);
|
|
891
|
+
case "webpack": return transformWebpack(projectRoot, reactGrabAlreadyConfigured);
|
|
918
892
|
default: return {
|
|
919
893
|
success: false,
|
|
920
894
|
filePath: "",
|
|
@@ -968,18 +942,24 @@ const formatOptionsAsJson = (options) => {
|
|
|
968
942
|
};
|
|
969
943
|
const findReactGrabFile = (projectRoot, framework, nextRouterType) => {
|
|
970
944
|
switch (framework) {
|
|
971
|
-
case "next":
|
|
972
|
-
|
|
973
|
-
|
|
945
|
+
case "next": {
|
|
946
|
+
const primaryFile = nextRouterType === "app" ? findLayoutFile(projectRoot) : findDocumentFile(projectRoot);
|
|
947
|
+
const primarySetupFile = findFileWithReactGrabSetup(nextRouterType === "app" ? getLayoutFileCandidates(projectRoot) : getDocumentFileCandidates(projectRoot));
|
|
948
|
+
if (primarySetupFile) return primarySetupFile;
|
|
949
|
+
const instrumentationFile = findFileWithReactGrabSetup(getInstrumentationFileCandidates(projectRoot));
|
|
950
|
+
if (instrumentationFile) return instrumentationFile;
|
|
951
|
+
return primaryFile;
|
|
952
|
+
}
|
|
974
953
|
case "vite": {
|
|
975
954
|
const entryFile = findEntryFile(projectRoot);
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
955
|
+
const entrySetupFile = findFileWithReactGrabSetup(getEntryFileCandidates(projectRoot));
|
|
956
|
+
if (entrySetupFile) return entrySetupFile;
|
|
957
|
+
const indexHtml = findFileWithReactGrabSetup(getIndexHtmlCandidates(projectRoot));
|
|
958
|
+
if (indexHtml) return indexHtml;
|
|
979
959
|
return entryFile;
|
|
980
960
|
}
|
|
981
|
-
case "tanstack": return findTanStackRootFile(projectRoot);
|
|
982
|
-
case "webpack": return findEntryFile(projectRoot);
|
|
961
|
+
case "tanstack": return findFileWithReactGrabSetup(getTanStackRootFileCandidates(projectRoot)) ?? findTanStackRootFile(projectRoot);
|
|
962
|
+
case "webpack": return findFileWithReactGrabSetup(getEntryFileCandidates(projectRoot)) ?? findEntryFile(projectRoot);
|
|
983
963
|
default: return null;
|
|
984
964
|
}
|
|
985
965
|
};
|
|
@@ -1007,13 +987,14 @@ const addOptionsToNextScript = (originalContent, options, filePath) => {
|
|
|
1007
987
|
};
|
|
1008
988
|
};
|
|
1009
989
|
const addOptionsToDynamicImport = (originalContent, options, filePath) => {
|
|
1010
|
-
const reactGrabImportWithInitMatch = originalContent.match(/import\s*\(\s*["']react-grab["']\s*\)(?:\.then\s*\(\s
|
|
990
|
+
const reactGrabImportWithInitMatch = originalContent.match(/(void\s+)?import\s*\(\s*["']react-grab(?:\/[^"']+)?["']\s*\)(?:\.then\s*\(\s*(?:\(m\)\s*=>\s*m\.init\s*\([^)]*\)|\(\{\s*init\s*\}\)\s*=>\s*init\s*\([^)]*\))\s*\))?/);
|
|
1011
991
|
if (!reactGrabImportWithInitMatch) return {
|
|
1012
992
|
success: false,
|
|
1013
993
|
filePath,
|
|
1014
994
|
message: "Could not find React Grab import"
|
|
1015
995
|
};
|
|
1016
|
-
const
|
|
996
|
+
const optionsJson = formatOptionsAsJson(options);
|
|
997
|
+
const newImport = `${reactGrabImportWithInitMatch[1] ?? ""}import("react-grab").then((m) => m.init(${optionsJson}))`;
|
|
1017
998
|
return {
|
|
1018
999
|
success: true,
|
|
1019
1000
|
filePath,
|
|
@@ -1023,13 +1004,14 @@ const addOptionsToDynamicImport = (originalContent, options, filePath) => {
|
|
|
1023
1004
|
};
|
|
1024
1005
|
};
|
|
1025
1006
|
const addOptionsToTanStackImport = (originalContent, options, filePath) => {
|
|
1026
|
-
const reactGrabImportWithInitMatch = originalContent.match(/(?:void\s+
|
|
1007
|
+
const reactGrabImportWithInitMatch = originalContent.match(/(?:(void\s+)?import\s*\(\s*["']react-grab\/core["']\s*\)\.then\s*\(\s*(?:\(\s*\{\s*init\s*\}\s*\)\s*=>\s*init\s*\([^)]*\)|\(m\)\s*=>\s*m\.init\s*\([^)]*\))\s*\)|(void\s+)?import\s*\(\s*["']react-grab(?!\/core)(?:\/[^"']+)?["']\s*\))/);
|
|
1027
1008
|
if (!reactGrabImportWithInitMatch) return {
|
|
1028
1009
|
success: false,
|
|
1029
1010
|
filePath,
|
|
1030
1011
|
message: "Could not find React Grab import"
|
|
1031
1012
|
};
|
|
1032
|
-
const
|
|
1013
|
+
const optionsJson = formatOptionsAsJson(options);
|
|
1014
|
+
const newImport = `${reactGrabImportWithInitMatch[1] ?? reactGrabImportWithInitMatch[2] ?? ""}import("react-grab/core").then(({ init }) => init(${optionsJson}))`;
|
|
1033
1015
|
return {
|
|
1034
1016
|
success: true,
|
|
1035
1017
|
filePath,
|
|
@@ -1038,6 +1020,11 @@ const addOptionsToTanStackImport = (originalContent, options, filePath) => {
|
|
|
1038
1020
|
newContent: originalContent.replace(reactGrabImportWithInitMatch[0], newImport)
|
|
1039
1021
|
};
|
|
1040
1022
|
};
|
|
1023
|
+
const addOptionsToAnyImport = (originalContent, options, filePath) => {
|
|
1024
|
+
const dynamicImportResult = addOptionsToDynamicImport(originalContent, options, filePath);
|
|
1025
|
+
if (dynamicImportResult.success) return dynamicImportResult;
|
|
1026
|
+
return addOptionsToTanStackImport(originalContent, options, filePath);
|
|
1027
|
+
};
|
|
1041
1028
|
const previewOptionsTransform = (projectRoot, framework, nextRouterType, options) => {
|
|
1042
1029
|
const filePath = findReactGrabFile(projectRoot, framework, nextRouterType);
|
|
1043
1030
|
if (!filePath) return {
|
|
@@ -1046,13 +1033,15 @@ const previewOptionsTransform = (projectRoot, framework, nextRouterType, options
|
|
|
1046
1033
|
message: "Could not find file containing React Grab configuration"
|
|
1047
1034
|
};
|
|
1048
1035
|
const originalContent = readFileSync(filePath, "utf-8");
|
|
1049
|
-
if (!
|
|
1036
|
+
if (!hasReactGrabSetupCode(originalContent)) return {
|
|
1050
1037
|
success: false,
|
|
1051
1038
|
filePath,
|
|
1052
1039
|
message: "Could not find React Grab code in the file"
|
|
1053
1040
|
};
|
|
1054
1041
|
switch (framework) {
|
|
1055
|
-
case "next":
|
|
1042
|
+
case "next":
|
|
1043
|
+
if (isInstrumentationFile(filePath)) return addOptionsToAnyImport(originalContent, options, filePath);
|
|
1044
|
+
return addOptionsToNextScript(originalContent, options, filePath);
|
|
1056
1045
|
case "vite": return addOptionsToDynamicImport(originalContent, options, filePath);
|
|
1057
1046
|
case "tanstack": return addOptionsToTanStackImport(originalContent, options, filePath);
|
|
1058
1047
|
case "webpack": return addOptionsToDynamicImport(originalContent, options, filePath);
|
|
@@ -1110,7 +1099,7 @@ const formatActivationKeyDisplay = (activationKey) => {
|
|
|
1110
1099
|
};
|
|
1111
1100
|
//#endregion
|
|
1112
1101
|
//#region src/commands/configure.ts
|
|
1113
|
-
const VERSION$4 = "0.1.
|
|
1102
|
+
const VERSION$4 = "0.1.45-dev.b85b9b1";
|
|
1114
1103
|
const isMac = process.platform === "darwin";
|
|
1115
1104
|
const META_LABEL = isMac ? "Cmd" : "Win";
|
|
1116
1105
|
const ALT_LABEL = isMac ? "Option" : "Alt";
|
|
@@ -1380,8 +1369,8 @@ const generateSuggestions = (input) => {
|
|
|
1380
1369
|
const CONFIG_OPTIONS = [
|
|
1381
1370
|
{
|
|
1382
1371
|
id: "activationKey",
|
|
1383
|
-
title: "
|
|
1384
|
-
description: "The
|
|
1372
|
+
title: "Shortcut",
|
|
1373
|
+
description: "The shortcut used to activate React Grab (e.g., g, k, space)"
|
|
1385
1374
|
},
|
|
1386
1375
|
{
|
|
1387
1376
|
id: "activationMode",
|
|
@@ -1416,7 +1405,7 @@ const comboToString = (combo) => {
|
|
|
1416
1405
|
}
|
|
1417
1406
|
return parts.join("+");
|
|
1418
1407
|
};
|
|
1419
|
-
const configure = new Command().name("configure").alias("config").description("configure React Grab options").option("-y, --yes", "skip confirmation prompts", false).option("-k, --key <key>", "
|
|
1408
|
+
const configure = new Command().name("configure").alias("config").description("configure React Grab options").option("-y, --yes", "skip confirmation prompts", false).option("-k, --key <key>", "shortcut (e.g., Meta+K, Ctrl+Shift+G, Space)").option("-m, --mode <mode>", "activation mode (toggle, hold)").option("--hold-duration <ms>", "key hold duration in milliseconds (for hold mode)").option("--allow-input <boolean>", "allow activation inside input fields (true/false)").option("--context-lines <lines>", "max context lines to include").option("--cdn <domain>", "CDN domain (e.g., unpkg.com, custom.react-grab.com)").option("-c, --cwd <cwd>", "working directory (defaults to current directory)", process.cwd()).action(async (opts) => {
|
|
1420
1409
|
console.log(`${pc.magenta("✿")} ${pc.bold("React Grab")} ${pc.gray(VERSION$4)}`);
|
|
1421
1410
|
console.log();
|
|
1422
1411
|
try {
|
|
@@ -1430,6 +1419,13 @@ const configure = new Command().name("configure").alias("config").description("c
|
|
|
1430
1419
|
logger.break();
|
|
1431
1420
|
process.exit(1);
|
|
1432
1421
|
}
|
|
1422
|
+
if (!projectInfo.isReactGrabConfigured) {
|
|
1423
|
+
preflightSpinner.fail("React Grab is installed, but setup is missing.");
|
|
1424
|
+
logger.break();
|
|
1425
|
+
logger.error(`Run ${highlighter.info("react-grab init")} to add the setup script/import before configuring options.`);
|
|
1426
|
+
logger.break();
|
|
1427
|
+
process.exit(1);
|
|
1428
|
+
}
|
|
1433
1429
|
preflightSpinner.succeed();
|
|
1434
1430
|
if (opts.cdn) {
|
|
1435
1431
|
const result = previewCdnTransform(projectInfo.projectRoot, projectInfo.framework, projectInfo.nextRouterType, opts.cdn);
|
|
@@ -1485,7 +1481,7 @@ const configure = new Command().name("configure").alias("config").description("c
|
|
|
1485
1481
|
if (hasFlags) {
|
|
1486
1482
|
if (opts.key) {
|
|
1487
1483
|
collectedOptions.activationKey = opts.key;
|
|
1488
|
-
logger.log(`
|
|
1484
|
+
logger.log(` Shortcut: ${highlighter.info(formatActivationKeyDisplay(collectedOptions.activationKey))}`);
|
|
1489
1485
|
}
|
|
1490
1486
|
if (opts.mode) {
|
|
1491
1487
|
if (opts.mode !== "toggle" && opts.mode !== "hold") {
|
|
@@ -1550,7 +1546,7 @@ const configure = new Command().name("configure").alias("config").description("c
|
|
|
1550
1546
|
process.exit(1);
|
|
1551
1547
|
}
|
|
1552
1548
|
collectedOptions.activationKey = comboToString(selectedCombo);
|
|
1553
|
-
logger.log(`
|
|
1549
|
+
logger.log(` Shortcut: ${highlighter.info(formatActivationKeyDisplay(collectedOptions.activationKey))}`);
|
|
1554
1550
|
}
|
|
1555
1551
|
if (selectedOption === "activationMode") {
|
|
1556
1552
|
const { activationMode } = await prompts({
|
|
@@ -1735,7 +1731,7 @@ const isTelemetryEnabled = () => {
|
|
|
1735
1731
|
};
|
|
1736
1732
|
//#endregion
|
|
1737
1733
|
//#region src/commands/init.ts
|
|
1738
|
-
const VERSION$3 = "0.1.
|
|
1734
|
+
const VERSION$3 = "0.1.45-dev.b85b9b1";
|
|
1739
1735
|
const REPORT_URL = "https://react-grab.com/api/report-cli";
|
|
1740
1736
|
const DOCS_URL = "https://github.com/aidenybai/react-grab";
|
|
1741
1737
|
const reportToCli = (type, config, error) => {
|
|
@@ -1803,7 +1799,7 @@ const failWithManualSetup = (failingSpinner, message, { listSupportedFrameworks
|
|
|
1803
1799
|
logger.break();
|
|
1804
1800
|
process.exit(1);
|
|
1805
1801
|
};
|
|
1806
|
-
const init = new Command().name("init").alias("setup").description("initialize React Grab in your project").option("-y, --yes", "skip confirmation prompts", false).option("-f, --force", "
|
|
1802
|
+
const init = new Command().name("init").alias("setup").description("initialize React Grab in your project").option("-y, --yes", "skip confirmation prompts", false).option("-f, --force", "re-run setup checks even when React Grab is already configured", false).option("-k, --key <key>", "shortcut (e.g., Meta+K, Ctrl+Shift+G, Space)").option("--skip-install", "skip package installation", false).option("--pkg <pkg>", "custom package URL for CLI (e.g., grab)").option("-c, --cwd <cwd>", "working directory (defaults to current directory)", process.cwd()).option("-g, --global", "install the skill globally instead of in the project", false).action(async (opts) => {
|
|
1807
1803
|
console.log(`${pc.magenta("✿")} ${pc.bold("React Grab")} ${pc.gray(VERSION$3)}`);
|
|
1808
1804
|
console.log();
|
|
1809
1805
|
try {
|
|
@@ -1817,12 +1813,12 @@ const init = new Command().name("init").alias("setup").description("initialize R
|
|
|
1817
1813
|
}
|
|
1818
1814
|
const preflightSpinner = spinner("Preflight checks.").start();
|
|
1819
1815
|
const projectInfo = await detectProject(cwd);
|
|
1820
|
-
if (projectInfo.
|
|
1816
|
+
if (projectInfo.isReactGrabConfigured && !opts.force) {
|
|
1821
1817
|
preflightSpinner.succeed();
|
|
1822
1818
|
if (isNonInteractive) {
|
|
1823
1819
|
logger.break();
|
|
1824
1820
|
logger.warn("React Grab is already installed.");
|
|
1825
|
-
logger.log(`Use ${highlighter.info("--force")} to
|
|
1821
|
+
logger.log(`Use ${highlighter.info("--force")} to re-run setup checks, or remove ${highlighter.info("--yes")} for interactive mode.`);
|
|
1826
1822
|
logger.break();
|
|
1827
1823
|
process.exit(0);
|
|
1828
1824
|
}
|
|
@@ -1846,12 +1842,12 @@ const init = new Command().name("init").alias("setup").description("initialize R
|
|
|
1846
1842
|
const collectedOptions = {};
|
|
1847
1843
|
if (opts.key) {
|
|
1848
1844
|
collectedOptions.activationKey = opts.key;
|
|
1849
|
-
logger.log(`
|
|
1845
|
+
logger.log(` Shortcut: ${highlighter.info(formatActivationKeyDisplay(collectedOptions.activationKey))}`);
|
|
1850
1846
|
} else {
|
|
1851
1847
|
const { wantActivationKey } = await prompts({
|
|
1852
1848
|
type: "confirm",
|
|
1853
1849
|
name: "wantActivationKey",
|
|
1854
|
-
message: `Configure ${highlighter.info("
|
|
1850
|
+
message: `Configure ${highlighter.info("shortcut")}?`,
|
|
1855
1851
|
initial: false
|
|
1856
1852
|
});
|
|
1857
1853
|
if (wantActivationKey === void 0) {
|
|
@@ -1862,7 +1858,7 @@ const init = new Command().name("init").alias("setup").description("initialize R
|
|
|
1862
1858
|
const { key } = await prompts({
|
|
1863
1859
|
type: "text",
|
|
1864
1860
|
name: "key",
|
|
1865
|
-
message: "Enter the
|
|
1861
|
+
message: "Enter the shortcut (e.g., g, k, space):",
|
|
1866
1862
|
initial: ""
|
|
1867
1863
|
});
|
|
1868
1864
|
if (key === void 0) {
|
|
@@ -1870,7 +1866,7 @@ const init = new Command().name("init").alias("setup").description("initialize R
|
|
|
1870
1866
|
process.exit(1);
|
|
1871
1867
|
}
|
|
1872
1868
|
collectedOptions.activationKey = key ? key.toLowerCase() : void 0;
|
|
1873
|
-
logger.log(`
|
|
1869
|
+
logger.log(` Shortcut: ${highlighter.info(formatActivationKeyDisplay(collectedOptions.activationKey))}`);
|
|
1874
1870
|
}
|
|
1875
1871
|
}
|
|
1876
1872
|
const { activationMode } = await prompts({
|
|
@@ -2037,7 +2033,7 @@ const init = new Command().name("init").alias("setup").description("initialize R
|
|
|
2037
2033
|
cwd
|
|
2038
2034
|
});
|
|
2039
2035
|
}
|
|
2040
|
-
const result = previewTransform(projectInfo.projectRoot, finalFramework, finalNextRouterType,
|
|
2036
|
+
const result = previewTransform(projectInfo.projectRoot, finalFramework, finalNextRouterType, projectInfo.isReactGrabConfigured);
|
|
2041
2037
|
if (!result.success) {
|
|
2042
2038
|
logger.break();
|
|
2043
2039
|
logger.error(result.message);
|
|
@@ -2072,7 +2068,8 @@ const init = new Command().name("init").alias("setup").description("initialize R
|
|
|
2072
2068
|
if (!opts.skipInstall && shouldInstallReactGrab) await installPackagesWithFeedback(getPackagesToInstall(shouldInstallReactGrab), finalPackageManager, projectInfo.projectRoot);
|
|
2073
2069
|
if (hasLayoutChanges) applyTransformWithFeedback(result);
|
|
2074
2070
|
logger.break();
|
|
2075
|
-
logger.log(`${highlighter.success("Success!")} React Grab has been installed.`);
|
|
2071
|
+
if (hasLayoutChanges) logger.log(`${highlighter.success("Success!")} React Grab has been installed.`);
|
|
2072
|
+
else logger.log(`${highlighter.success("Success!")} ${result.message}.`);
|
|
2076
2073
|
logger.log("You may now start your development server.");
|
|
2077
2074
|
logger.break();
|
|
2078
2075
|
reportToCli("completed", {
|
|
@@ -2685,7 +2682,7 @@ const pull = new Command().name("pull").description("start the watcher if needed
|
|
|
2685
2682
|
});
|
|
2686
2683
|
//#endregion
|
|
2687
2684
|
//#region src/commands/remove.ts
|
|
2688
|
-
const VERSION$2 = "0.1.
|
|
2685
|
+
const VERSION$2 = "0.1.45-dev.b85b9b1";
|
|
2689
2686
|
const remove = new Command().name("remove").description("uninstall the React Grab skill from your agent").option("-c, --cwd <cwd>", "working directory (defaults to current directory)", process.cwd()).option("-g, --global", "remove the globally-installed skill instead of the project's", false).action(async (opts) => {
|
|
2690
2687
|
console.log(`${pc.magenta("✿")} ${pc.bold("React Grab")} ${pc.gray(VERSION$2)}`);
|
|
2691
2688
|
console.log();
|
|
@@ -2713,7 +2710,7 @@ const stop = new Command().name("stop").description("stop the React Grab watcher
|
|
|
2713
2710
|
});
|
|
2714
2711
|
//#endregion
|
|
2715
2712
|
//#region src/commands/upgrade.ts
|
|
2716
|
-
const VERSION$1 = "0.1.
|
|
2713
|
+
const VERSION$1 = "0.1.45-dev.b85b9b1";
|
|
2717
2714
|
const NPM_REGISTRY_URL = "https://registry.npmjs.org/react-grab/latest";
|
|
2718
2715
|
const fetchLatestVersion = async () => {
|
|
2719
2716
|
try {
|
|
@@ -2825,7 +2822,7 @@ const watch = new Command().name("watch").description("run the React Grab captur
|
|
|
2825
2822
|
});
|
|
2826
2823
|
//#endregion
|
|
2827
2824
|
//#region src/cli.ts
|
|
2828
|
-
const VERSION = "0.1.
|
|
2825
|
+
const VERSION = "0.1.45-dev.b85b9b1";
|
|
2829
2826
|
const VERSION_API_URL = "https://www.react-grab.com/api/version";
|
|
2830
2827
|
process.on("SIGINT", () => process.exit(0));
|
|
2831
2828
|
process.on("SIGTERM", () => process.exit(0));
|