@react-grab/cli 0.1.43 → 0.1.44-dev.0b82e39
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 +188 -184
- package/dist/cli.js +188 -184
- package/dist/cli.js.map +1 -1
- package/package.json +1 -3
- package/skills/react-grab/SKILL.md +31 -10
package/dist/cli.cjs
CHANGED
|
@@ -53,6 +53,71 @@ const AGENT_ENVIRONMENT_VARIABLES = [
|
|
|
53
53
|
const isEnvironmentVariableSet = (variable) => Boolean(process.env[variable]);
|
|
54
54
|
const detectNonInteractive = (yesFlag) => yesFlag || AGENT_ENVIRONMENT_VARIABLES.some(isEnvironmentVariableSet) || !process.stdin.isTTY;
|
|
55
55
|
//#endregion
|
|
56
|
+
//#region src/utils/react-grab-code.ts
|
|
57
|
+
const REACT_GRAB_SPECIFIER_PATTERN = String.raw`react-grab(?:\/[^"']+)?`;
|
|
58
|
+
const stripComments = (content) => content.replace(/<!--[\s\S]*?-->/g, "").replace(/\{\/\*[\s\S]*?\*\/\}/g, "").replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|\s)\/\/.*$/gm, "$1");
|
|
59
|
+
const stripTypeOnlyReactGrabImports = (content) => {
|
|
60
|
+
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"), "");
|
|
61
|
+
};
|
|
62
|
+
const hasReactGrabSetupCode = (content) => {
|
|
63
|
+
const setupCandidateContent = stripTypeOnlyReactGrabImports(stripComments(content));
|
|
64
|
+
return [
|
|
65
|
+
new RegExp(String.raw`import\s*\(\s*["']${REACT_GRAB_SPECIFIER_PATTERN}["']\s*\)`),
|
|
66
|
+
new RegExp(String.raw`import\s+(?!type\b)(?:[^"';]+from\s+)?["']${REACT_GRAB_SPECIFIER_PATTERN}["']`),
|
|
67
|
+
new RegExp(String.raw`require\s*\(\s*["']${REACT_GRAB_SPECIFIER_PATTERN}["']\s*\)`),
|
|
68
|
+
/<Script[\s\S]*?src\s*=\s*(?:["'][^"']*react-grab[^"']*["']|\{(?:["'][^"']*react-grab[^"']*["']|`[^`]*react-grab[^`]*`)\})/i,
|
|
69
|
+
/<script[\s\S]*?src\s*=\s*["'][^"']*react-grab[^"']*["']/i
|
|
70
|
+
].some((pattern) => pattern.test(setupCandidateContent));
|
|
71
|
+
};
|
|
72
|
+
//#endregion
|
|
73
|
+
//#region src/utils/react-grab-setup-files.ts
|
|
74
|
+
const COMPONENT_EXTENSIONS = [
|
|
75
|
+
"tsx",
|
|
76
|
+
"jsx",
|
|
77
|
+
"ts",
|
|
78
|
+
"js"
|
|
79
|
+
];
|
|
80
|
+
const INSTRUMENTATION_EXTENSIONS = [
|
|
81
|
+
"ts",
|
|
82
|
+
"tsx",
|
|
83
|
+
"js",
|
|
84
|
+
"jsx",
|
|
85
|
+
"mts",
|
|
86
|
+
"cts",
|
|
87
|
+
"mjs",
|
|
88
|
+
"cjs"
|
|
89
|
+
];
|
|
90
|
+
const ROUTE_EXTENSIONS = ["tsx", "jsx"];
|
|
91
|
+
const createFileCandidates = (projectRoot, directories, baseName, extensions) => {
|
|
92
|
+
const fileCandidates = [];
|
|
93
|
+
for (const directory of directories) for (const extension of extensions) fileCandidates.push((0, node_path.join)(projectRoot, directory, `${baseName}.${extension}`));
|
|
94
|
+
return fileCandidates;
|
|
95
|
+
};
|
|
96
|
+
const findExistingFile = (fileCandidates) => {
|
|
97
|
+
for (const filePath of fileCandidates) if ((0, node_fs.existsSync)(filePath)) return filePath;
|
|
98
|
+
return null;
|
|
99
|
+
};
|
|
100
|
+
const getLayoutFileCandidates = (projectRoot) => createFileCandidates(projectRoot, ["app", "src/app"], "layout", COMPONENT_EXTENSIONS);
|
|
101
|
+
const getDocumentFileCandidates = (projectRoot) => createFileCandidates(projectRoot, ["pages", "src/pages"], "_document", COMPONENT_EXTENSIONS);
|
|
102
|
+
const getInstrumentationFileCandidates = (projectRoot) => createFileCandidates(projectRoot, ["", "src"], "instrumentation-client", INSTRUMENTATION_EXTENSIONS);
|
|
103
|
+
const getIndexHtmlCandidates = (projectRoot) => [(0, node_path.join)(projectRoot, "index.html"), (0, node_path.join)(projectRoot, "public", "index.html")];
|
|
104
|
+
const getEntryFileCandidates = (projectRoot) => [...createFileCandidates(projectRoot, ["src"], "index", COMPONENT_EXTENSIONS), ...createFileCandidates(projectRoot, ["src"], "main", COMPONENT_EXTENSIONS)];
|
|
105
|
+
const getTanStackRootFileCandidates = (projectRoot) => createFileCandidates(projectRoot, ["src/routes", "app/routes"], "__root", ROUTE_EXTENSIONS);
|
|
106
|
+
const getReactGrabSetupFileCandidates = (projectRoot) => [
|
|
107
|
+
...getLayoutFileCandidates(projectRoot),
|
|
108
|
+
...getDocumentFileCandidates(projectRoot),
|
|
109
|
+
...getInstrumentationFileCandidates(projectRoot),
|
|
110
|
+
...getIndexHtmlCandidates(projectRoot),
|
|
111
|
+
...getEntryFileCandidates(projectRoot),
|
|
112
|
+
...getTanStackRootFileCandidates(projectRoot)
|
|
113
|
+
];
|
|
114
|
+
const findLayoutFile = (projectRoot) => findExistingFile(getLayoutFileCandidates(projectRoot));
|
|
115
|
+
const findDocumentFile = (projectRoot) => findExistingFile(getDocumentFileCandidates(projectRoot));
|
|
116
|
+
const findIndexHtml = (projectRoot) => findExistingFile(getIndexHtmlCandidates(projectRoot));
|
|
117
|
+
const findEntryFile = (projectRoot) => findExistingFile(getEntryFileCandidates(projectRoot));
|
|
118
|
+
const findTanStackRootFile = (projectRoot) => findExistingFile(getTanStackRootFileCandidates(projectRoot));
|
|
119
|
+
const isInstrumentationFile = (filePath) => /(?:^|[/\\])instrumentation-client\.[cm]?[jt]sx?$/.test(filePath);
|
|
120
|
+
//#endregion
|
|
56
121
|
//#region src/utils/detect.ts
|
|
57
122
|
const VALID_PACKAGE_MANAGERS = new Set([
|
|
58
123
|
"npm",
|
|
@@ -266,10 +331,14 @@ const scanDirectoryForProjects = (rootDirectory, ignorer, maxDepth, currentDepth
|
|
|
266
331
|
return projects;
|
|
267
332
|
};
|
|
268
333
|
const MAX_SCAN_DEPTH = 2;
|
|
334
|
+
const normalizePathForComparison = (filePath) => filePath.replace(/\\/g, "/");
|
|
269
335
|
const findReactProjects = (projectRoot) => {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
336
|
+
const monorepoRoot = detectMonorepo(projectRoot) ? projectRoot : findEnclosingMonorepoRoot(projectRoot);
|
|
337
|
+
if (monorepoRoot) {
|
|
338
|
+
const workspaceProjects = findWorkspaceProjects(monorepoRoot);
|
|
339
|
+
const localProject = projectRoot === monorepoRoot ? null : buildReactProject(projectRoot);
|
|
340
|
+
const projects = localProject ? [localProject, ...workspaceProjects.filter((project) => normalizePathForComparison(project.path) !== normalizePathForComparison(localProject.path))] : workspaceProjects;
|
|
341
|
+
if (projects.length > 0) return projects;
|
|
273
342
|
}
|
|
274
343
|
const scannedProjects = scanDirectoryForProjects(projectRoot, loadGitignore(projectRoot), MAX_SCAN_DEPTH);
|
|
275
344
|
if (scannedProjects.length > 0) return scannedProjects;
|
|
@@ -281,47 +350,20 @@ const findReactProjects = (projectRoot) => {
|
|
|
281
350
|
}
|
|
282
351
|
return [];
|
|
283
352
|
};
|
|
284
|
-
const
|
|
353
|
+
const hasReactGrabSetupInFile = (filePath) => {
|
|
285
354
|
if (!(0, node_fs.existsSync)(filePath)) return false;
|
|
286
355
|
try {
|
|
287
|
-
|
|
288
|
-
return [
|
|
289
|
-
/["'`][^"'`]*react-grab/,
|
|
290
|
-
/react-grab[^"'`]*["'`]/,
|
|
291
|
-
/<[^>]*react-grab/i,
|
|
292
|
-
/import[^;]*react-grab/i,
|
|
293
|
-
/require[^)]*react-grab/i,
|
|
294
|
-
/from\s+[^;]*react-grab/i,
|
|
295
|
-
/src[^>]*react-grab/i
|
|
296
|
-
].some((pattern) => pattern.test(content));
|
|
356
|
+
return hasReactGrabSetupCode((0, node_fs.readFileSync)(filePath, "utf-8"));
|
|
297
357
|
} catch {
|
|
298
358
|
return false;
|
|
299
359
|
}
|
|
300
360
|
};
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
return [
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
(0, node_path.join)(projectRoot, "src", "app", "layout.jsx"),
|
|
308
|
-
(0, node_path.join)(projectRoot, "pages", "_document.tsx"),
|
|
309
|
-
(0, node_path.join)(projectRoot, "pages", "_document.jsx"),
|
|
310
|
-
(0, node_path.join)(projectRoot, "instrumentation-client.ts"),
|
|
311
|
-
(0, node_path.join)(projectRoot, "instrumentation-client.js"),
|
|
312
|
-
(0, node_path.join)(projectRoot, "src", "instrumentation-client.ts"),
|
|
313
|
-
(0, node_path.join)(projectRoot, "src", "instrumentation-client.js"),
|
|
314
|
-
(0, node_path.join)(projectRoot, "index.html"),
|
|
315
|
-
(0, node_path.join)(projectRoot, "public", "index.html"),
|
|
316
|
-
(0, node_path.join)(projectRoot, "src", "index.tsx"),
|
|
317
|
-
(0, node_path.join)(projectRoot, "src", "index.ts"),
|
|
318
|
-
(0, node_path.join)(projectRoot, "src", "main.tsx"),
|
|
319
|
-
(0, node_path.join)(projectRoot, "src", "main.ts"),
|
|
320
|
-
(0, node_path.join)(projectRoot, "src", "routes", "__root.tsx"),
|
|
321
|
-
(0, node_path.join)(projectRoot, "src", "routes", "__root.jsx"),
|
|
322
|
-
(0, node_path.join)(projectRoot, "app", "routes", "__root.tsx"),
|
|
323
|
-
(0, node_path.join)(projectRoot, "app", "routes", "__root.jsx")
|
|
324
|
-
].some(hasReactGrabInFile);
|
|
361
|
+
const detectReactGrabDependency = (projectRoot) => {
|
|
362
|
+
const dependencies = readMergedDependencies(projectRoot);
|
|
363
|
+
return Boolean(dependencies?.["react-grab"]);
|
|
364
|
+
};
|
|
365
|
+
const detectReactGrabConfigured = (projectRoot) => {
|
|
366
|
+
return getReactGrabSetupFileCandidates(projectRoot).some(hasReactGrabSetupInFile);
|
|
325
367
|
};
|
|
326
368
|
const detectUnsupportedFramework = (projectRoot) => {
|
|
327
369
|
const dependencies = readMergedDependencies(projectRoot);
|
|
@@ -342,13 +384,17 @@ const detectReactGrabVersion = (projectRoot) => {
|
|
|
342
384
|
const detectProject = async (projectRoot = process.cwd()) => {
|
|
343
385
|
const localFramework = detectFramework(projectRoot);
|
|
344
386
|
const framework = localFramework === "unknown" ? detectFrameworkFromMonorepoRoot(projectRoot) : localFramework;
|
|
387
|
+
const packageManager = await detectPackageManager(projectRoot);
|
|
388
|
+
const isMonorepo = detectMonorepo(projectRoot) || findEnclosingMonorepoRoot(projectRoot) !== null;
|
|
389
|
+
const isReactGrabConfigured = detectReactGrabConfigured(projectRoot);
|
|
345
390
|
return {
|
|
346
|
-
packageManager
|
|
391
|
+
packageManager,
|
|
347
392
|
framework,
|
|
348
393
|
nextRouterType: framework === "next" ? detectNextRouterType(projectRoot) : "unknown",
|
|
349
|
-
isMonorepo
|
|
394
|
+
isMonorepo,
|
|
350
395
|
projectRoot,
|
|
351
|
-
hasReactGrab:
|
|
396
|
+
hasReactGrab: detectReactGrabDependency(projectRoot) || isReactGrabConfigured,
|
|
397
|
+
isReactGrabConfigured,
|
|
352
398
|
reactGrabVersion: detectReactGrabVersion(projectRoot),
|
|
353
399
|
unsupportedFramework: detectUnsupportedFramework(projectRoot)
|
|
354
400
|
};
|
|
@@ -462,6 +508,13 @@ const promptSkillInstall = async ({ yes = false, global = false, cwd = process.c
|
|
|
462
508
|
}
|
|
463
509
|
let selectedAgents = detectedAgents;
|
|
464
510
|
if (!yes) {
|
|
511
|
+
const { confirmed } = await prompts$1({
|
|
512
|
+
type: "confirm",
|
|
513
|
+
name: "confirmed",
|
|
514
|
+
message: `Install the React Grab skill (${global ? "global" : "this project"})?`,
|
|
515
|
+
initial: true
|
|
516
|
+
});
|
|
517
|
+
if (!confirmed) return false;
|
|
465
518
|
const { agents } = await prompts$1({
|
|
466
519
|
type: "multiselect",
|
|
467
520
|
name: "agents",
|
|
@@ -512,7 +565,7 @@ const removeSkill = async ({ cwd = process.cwd(), global = false } = {}) => {
|
|
|
512
565
|
};
|
|
513
566
|
//#endregion
|
|
514
567
|
//#region src/commands/add.ts
|
|
515
|
-
const VERSION$5 = "0.1.
|
|
568
|
+
const VERSION$5 = "0.1.44-dev.0b82e39";
|
|
516
569
|
const add = new commander.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) => {
|
|
517
570
|
console.log(`${picocolors.default.magenta("✿")} ${picocolors.default.bold("React Grab")} ${picocolors.default.gray(VERSION$5)}`);
|
|
518
571
|
console.log();
|
|
@@ -667,80 +720,14 @@ const TANSTACK_EFFECT = `useEffect(() => {
|
|
|
667
720
|
const SCRIPT_IMPORT = "import Script from \"next/script\";";
|
|
668
721
|
//#endregion
|
|
669
722
|
//#region src/utils/transform.ts
|
|
670
|
-
const hasReactGrabCode = (content) => {
|
|
671
|
-
return [
|
|
672
|
-
/["'`][^"'`]*react-grab/,
|
|
673
|
-
/react-grab[^"'`]*["'`]/,
|
|
674
|
-
/<[^>]*react-grab/i,
|
|
675
|
-
/import[^;]*react-grab/i,
|
|
676
|
-
/require[^)]*react-grab/i,
|
|
677
|
-
/from\s+[^;]*react-grab/i,
|
|
678
|
-
/src[^>]*react-grab/i,
|
|
679
|
-
/href[^>]*react-grab/i
|
|
680
|
-
].some((pattern) => pattern.test(content));
|
|
681
|
-
};
|
|
682
|
-
const findLayoutFile = (projectRoot) => {
|
|
683
|
-
const possiblePaths = [
|
|
684
|
-
(0, node_path.join)(projectRoot, "app", "layout.tsx"),
|
|
685
|
-
(0, node_path.join)(projectRoot, "app", "layout.jsx"),
|
|
686
|
-
(0, node_path.join)(projectRoot, "src", "app", "layout.tsx"),
|
|
687
|
-
(0, node_path.join)(projectRoot, "src", "app", "layout.jsx")
|
|
688
|
-
];
|
|
689
|
-
for (const filePath of possiblePaths) if ((0, node_fs.existsSync)(filePath)) return filePath;
|
|
690
|
-
return null;
|
|
691
|
-
};
|
|
692
|
-
const findInstrumentationFile = (projectRoot) => {
|
|
693
|
-
const possiblePaths = [
|
|
694
|
-
(0, node_path.join)(projectRoot, "instrumentation-client.ts"),
|
|
695
|
-
(0, node_path.join)(projectRoot, "instrumentation-client.js"),
|
|
696
|
-
(0, node_path.join)(projectRoot, "src", "instrumentation-client.ts"),
|
|
697
|
-
(0, node_path.join)(projectRoot, "src", "instrumentation-client.js")
|
|
698
|
-
];
|
|
699
|
-
for (const filePath of possiblePaths) if ((0, node_fs.existsSync)(filePath)) return filePath;
|
|
700
|
-
return null;
|
|
701
|
-
};
|
|
702
723
|
const hasReactGrabInInstrumentation = (projectRoot) => {
|
|
703
|
-
|
|
704
|
-
if (!instrumentationPath) return false;
|
|
705
|
-
return hasReactGrabCode((0, node_fs.readFileSync)(instrumentationPath, "utf-8"));
|
|
706
|
-
};
|
|
707
|
-
const findDocumentFile = (projectRoot) => {
|
|
708
|
-
const possiblePaths = [
|
|
709
|
-
(0, node_path.join)(projectRoot, "pages", "_document.tsx"),
|
|
710
|
-
(0, node_path.join)(projectRoot, "pages", "_document.jsx"),
|
|
711
|
-
(0, node_path.join)(projectRoot, "src", "pages", "_document.tsx"),
|
|
712
|
-
(0, node_path.join)(projectRoot, "src", "pages", "_document.jsx")
|
|
713
|
-
];
|
|
714
|
-
for (const filePath of possiblePaths) if ((0, node_fs.existsSync)(filePath)) return filePath;
|
|
715
|
-
return null;
|
|
724
|
+
return findFileWithReactGrabSetup(getInstrumentationFileCandidates(projectRoot)) !== null;
|
|
716
725
|
};
|
|
717
|
-
const
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
}
|
|
722
|
-
const findEntryFile = (projectRoot) => {
|
|
723
|
-
const possiblePaths = [
|
|
724
|
-
(0, node_path.join)(projectRoot, "src", "index.tsx"),
|
|
725
|
-
(0, node_path.join)(projectRoot, "src", "index.jsx"),
|
|
726
|
-
(0, node_path.join)(projectRoot, "src", "index.ts"),
|
|
727
|
-
(0, node_path.join)(projectRoot, "src", "index.js"),
|
|
728
|
-
(0, node_path.join)(projectRoot, "src", "main.tsx"),
|
|
729
|
-
(0, node_path.join)(projectRoot, "src", "main.jsx"),
|
|
730
|
-
(0, node_path.join)(projectRoot, "src", "main.ts"),
|
|
731
|
-
(0, node_path.join)(projectRoot, "src", "main.js")
|
|
732
|
-
];
|
|
733
|
-
for (const filePath of possiblePaths) if ((0, node_fs.existsSync)(filePath)) return filePath;
|
|
734
|
-
return null;
|
|
735
|
-
};
|
|
736
|
-
const findTanStackRootFile = (projectRoot) => {
|
|
737
|
-
const possiblePaths = [
|
|
738
|
-
(0, node_path.join)(projectRoot, "src", "routes", "__root.tsx"),
|
|
739
|
-
(0, node_path.join)(projectRoot, "src", "routes", "__root.jsx"),
|
|
740
|
-
(0, node_path.join)(projectRoot, "app", "routes", "__root.tsx"),
|
|
741
|
-
(0, node_path.join)(projectRoot, "app", "routes", "__root.jsx")
|
|
742
|
-
];
|
|
743
|
-
for (const filePath of possiblePaths) if ((0, node_fs.existsSync)(filePath)) return filePath;
|
|
726
|
+
const findFileWithReactGrabSetup = (fileCandidates) => {
|
|
727
|
+
for (const filePath of fileCandidates) {
|
|
728
|
+
if (!(0, node_fs.existsSync)(filePath)) continue;
|
|
729
|
+
if (hasReactGrabSetupCode((0, node_fs.readFileSync)(filePath, "utf-8"))) return filePath;
|
|
730
|
+
}
|
|
744
731
|
return null;
|
|
745
732
|
};
|
|
746
733
|
const alreadyConfiguredResult = (filePath) => ({
|
|
@@ -749,19 +736,19 @@ const alreadyConfiguredResult = (filePath) => ({
|
|
|
749
736
|
message: "React Grab is already configured",
|
|
750
737
|
noChanges: true
|
|
751
738
|
});
|
|
752
|
-
const transformNextAppRouter = (projectRoot, reactGrabAlreadyConfigured
|
|
739
|
+
const transformNextAppRouter = (projectRoot, reactGrabAlreadyConfigured) => {
|
|
753
740
|
const layoutPath = findLayoutFile(projectRoot);
|
|
754
741
|
if (!layoutPath) return {
|
|
755
742
|
success: false,
|
|
756
743
|
filePath: "",
|
|
757
|
-
message: "Could not find app/layout.tsx or app/layout.
|
|
744
|
+
message: "Could not find app/layout.tsx, app/layout.jsx, app/layout.ts, or app/layout.js"
|
|
758
745
|
};
|
|
759
746
|
const originalContent = (0, node_fs.readFileSync)(layoutPath, "utf-8");
|
|
760
747
|
let newContent = originalContent;
|
|
761
|
-
const hasReactGrabInFile =
|
|
748
|
+
const hasReactGrabInFile = hasReactGrabSetupCode(originalContent);
|
|
762
749
|
const hasReactGrabInInstrumentationFile = hasReactGrabInInstrumentation(projectRoot);
|
|
763
|
-
if (
|
|
764
|
-
if (
|
|
750
|
+
if (hasReactGrabInFile && reactGrabAlreadyConfigured) return alreadyConfiguredResult(layoutPath);
|
|
751
|
+
if (hasReactGrabInFile || hasReactGrabInInstrumentationFile) return {
|
|
765
752
|
success: true,
|
|
766
753
|
filePath: layoutPath,
|
|
767
754
|
message: "React Grab is already installed" + (hasReactGrabInInstrumentationFile ? " in instrumentation-client" : " in this file"),
|
|
@@ -786,19 +773,19 @@ const transformNextAppRouter = (projectRoot, reactGrabAlreadyConfigured, force =
|
|
|
786
773
|
newContent
|
|
787
774
|
};
|
|
788
775
|
};
|
|
789
|
-
const transformNextPagesRouter = (projectRoot, reactGrabAlreadyConfigured
|
|
776
|
+
const transformNextPagesRouter = (projectRoot, reactGrabAlreadyConfigured) => {
|
|
790
777
|
const documentPath = findDocumentFile(projectRoot);
|
|
791
778
|
if (!documentPath) return {
|
|
792
779
|
success: false,
|
|
793
780
|
filePath: "",
|
|
794
|
-
message: "Could not find pages/_document.tsx or pages/_document.
|
|
781
|
+
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 }"
|
|
795
782
|
};
|
|
796
783
|
const originalContent = (0, node_fs.readFileSync)(documentPath, "utf-8");
|
|
797
784
|
let newContent = originalContent;
|
|
798
|
-
const hasReactGrabInFile =
|
|
785
|
+
const hasReactGrabInFile = hasReactGrabSetupCode(originalContent);
|
|
799
786
|
const hasReactGrabInInstrumentationFile = hasReactGrabInInstrumentation(projectRoot);
|
|
800
|
-
if (
|
|
801
|
-
if (
|
|
787
|
+
if (hasReactGrabInFile && reactGrabAlreadyConfigured) return alreadyConfiguredResult(documentPath);
|
|
788
|
+
if (hasReactGrabInFile || hasReactGrabInInstrumentationFile) return {
|
|
802
789
|
success: true,
|
|
803
790
|
filePath: documentPath,
|
|
804
791
|
message: "React Grab is already installed" + (hasReactGrabInInstrumentationFile ? " in instrumentation-client" : " in this file"),
|
|
@@ -819,7 +806,7 @@ const transformNextPagesRouter = (projectRoot, reactGrabAlreadyConfigured, force
|
|
|
819
806
|
};
|
|
820
807
|
};
|
|
821
808
|
const checkExistingInstallation = (filePath, reactGrabAlreadyConfigured) => {
|
|
822
|
-
if (!
|
|
809
|
+
if (!hasReactGrabSetupCode((0, node_fs.readFileSync)(filePath, "utf-8"))) return null;
|
|
823
810
|
return {
|
|
824
811
|
success: true,
|
|
825
812
|
filePath,
|
|
@@ -827,24 +814,20 @@ const checkExistingInstallation = (filePath, reactGrabAlreadyConfigured) => {
|
|
|
827
814
|
noChanges: true
|
|
828
815
|
};
|
|
829
816
|
};
|
|
830
|
-
const transformVite = (projectRoot, reactGrabAlreadyConfigured
|
|
817
|
+
const transformVite = (projectRoot, reactGrabAlreadyConfigured) => {
|
|
831
818
|
const entryPath = findEntryFile(projectRoot);
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
if (existingResult) return existingResult;
|
|
837
|
-
}
|
|
819
|
+
const indexPath = findIndexHtml(projectRoot);
|
|
820
|
+
if (indexPath) {
|
|
821
|
+
const existingResult = checkExistingInstallation(indexPath, reactGrabAlreadyConfigured);
|
|
822
|
+
if (existingResult) return existingResult;
|
|
838
823
|
}
|
|
839
824
|
if (!entryPath) return {
|
|
840
825
|
success: false,
|
|
841
826
|
filePath: "",
|
|
842
827
|
message: "Could not find entry file (src/index.tsx, src/main.tsx, etc.)"
|
|
843
828
|
};
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
if (existingResult) return existingResult;
|
|
847
|
-
}
|
|
829
|
+
const existingResult = checkExistingInstallation(entryPath, reactGrabAlreadyConfigured);
|
|
830
|
+
if (existingResult) return existingResult;
|
|
848
831
|
const originalContent = (0, node_fs.readFileSync)(entryPath, "utf-8");
|
|
849
832
|
return {
|
|
850
833
|
success: true,
|
|
@@ -854,17 +837,15 @@ const transformVite = (projectRoot, reactGrabAlreadyConfigured, force = false) =
|
|
|
854
837
|
newContent: `${VITE_IMPORT}\n\n${originalContent}`
|
|
855
838
|
};
|
|
856
839
|
};
|
|
857
|
-
const transformWebpack = (projectRoot, reactGrabAlreadyConfigured
|
|
840
|
+
const transformWebpack = (projectRoot, reactGrabAlreadyConfigured) => {
|
|
858
841
|
const entryPath = findEntryFile(projectRoot);
|
|
859
842
|
if (!entryPath) return {
|
|
860
843
|
success: false,
|
|
861
844
|
filePath: "",
|
|
862
845
|
message: "Could not find entry file (src/index.tsx, src/main.tsx, etc.)"
|
|
863
846
|
};
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
if (existingResult) return existingResult;
|
|
867
|
-
}
|
|
847
|
+
const existingResult = checkExistingInstallation(entryPath, reactGrabAlreadyConfigured);
|
|
848
|
+
if (existingResult) return existingResult;
|
|
868
849
|
const originalContent = (0, node_fs.readFileSync)(entryPath, "utf-8");
|
|
869
850
|
return {
|
|
870
851
|
success: true,
|
|
@@ -874,7 +855,7 @@ const transformWebpack = (projectRoot, reactGrabAlreadyConfigured, force = false
|
|
|
874
855
|
newContent: `${WEBPACK_IMPORT}\n\n${originalContent}`
|
|
875
856
|
};
|
|
876
857
|
};
|
|
877
|
-
const transformTanStack = (projectRoot, reactGrabAlreadyConfigured
|
|
858
|
+
const transformTanStack = (projectRoot, reactGrabAlreadyConfigured) => {
|
|
878
859
|
const rootPath = findTanStackRootFile(projectRoot);
|
|
879
860
|
if (!rootPath) return {
|
|
880
861
|
success: false,
|
|
@@ -883,9 +864,9 @@ const transformTanStack = (projectRoot, reactGrabAlreadyConfigured, force = fals
|
|
|
883
864
|
};
|
|
884
865
|
const originalContent = (0, node_fs.readFileSync)(rootPath, "utf-8");
|
|
885
866
|
let newContent = originalContent;
|
|
886
|
-
const hasReactGrabInFile =
|
|
887
|
-
if (
|
|
888
|
-
if (
|
|
867
|
+
const hasReactGrabInFile = hasReactGrabSetupCode(originalContent);
|
|
868
|
+
if (hasReactGrabInFile && reactGrabAlreadyConfigured) return alreadyConfiguredResult(rootPath);
|
|
869
|
+
if (hasReactGrabInFile) return {
|
|
889
870
|
success: true,
|
|
890
871
|
filePath: rootPath,
|
|
891
872
|
message: "React Grab is already installed in this file",
|
|
@@ -928,14 +909,14 @@ const hasFrameworkEntryPoint = (projectRoot, framework, nextRouterType) => {
|
|
|
928
909
|
default: return false;
|
|
929
910
|
}
|
|
930
911
|
};
|
|
931
|
-
const previewTransform = (projectRoot, framework, nextRouterType, reactGrabAlreadyConfigured = false
|
|
912
|
+
const previewTransform = (projectRoot, framework, nextRouterType, reactGrabAlreadyConfigured = false) => {
|
|
932
913
|
switch (framework) {
|
|
933
914
|
case "next":
|
|
934
|
-
if (nextRouterType === "app") return transformNextAppRouter(projectRoot, reactGrabAlreadyConfigured
|
|
935
|
-
return transformNextPagesRouter(projectRoot, reactGrabAlreadyConfigured
|
|
936
|
-
case "vite": return transformVite(projectRoot, reactGrabAlreadyConfigured
|
|
937
|
-
case "tanstack": return transformTanStack(projectRoot, reactGrabAlreadyConfigured
|
|
938
|
-
case "webpack": return transformWebpack(projectRoot, reactGrabAlreadyConfigured
|
|
915
|
+
if (nextRouterType === "app") return transformNextAppRouter(projectRoot, reactGrabAlreadyConfigured);
|
|
916
|
+
return transformNextPagesRouter(projectRoot, reactGrabAlreadyConfigured);
|
|
917
|
+
case "vite": return transformVite(projectRoot, reactGrabAlreadyConfigured);
|
|
918
|
+
case "tanstack": return transformTanStack(projectRoot, reactGrabAlreadyConfigured);
|
|
919
|
+
case "webpack": return transformWebpack(projectRoot, reactGrabAlreadyConfigured);
|
|
939
920
|
default: return {
|
|
940
921
|
success: false,
|
|
941
922
|
filePath: "",
|
|
@@ -989,18 +970,24 @@ const formatOptionsAsJson = (options) => {
|
|
|
989
970
|
};
|
|
990
971
|
const findReactGrabFile = (projectRoot, framework, nextRouterType) => {
|
|
991
972
|
switch (framework) {
|
|
992
|
-
case "next":
|
|
993
|
-
|
|
994
|
-
|
|
973
|
+
case "next": {
|
|
974
|
+
const primaryFile = nextRouterType === "app" ? findLayoutFile(projectRoot) : findDocumentFile(projectRoot);
|
|
975
|
+
const primarySetupFile = findFileWithReactGrabSetup(nextRouterType === "app" ? getLayoutFileCandidates(projectRoot) : getDocumentFileCandidates(projectRoot));
|
|
976
|
+
if (primarySetupFile) return primarySetupFile;
|
|
977
|
+
const instrumentationFile = findFileWithReactGrabSetup(getInstrumentationFileCandidates(projectRoot));
|
|
978
|
+
if (instrumentationFile) return instrumentationFile;
|
|
979
|
+
return primaryFile;
|
|
980
|
+
}
|
|
995
981
|
case "vite": {
|
|
996
982
|
const entryFile = findEntryFile(projectRoot);
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
983
|
+
const entrySetupFile = findFileWithReactGrabSetup(getEntryFileCandidates(projectRoot));
|
|
984
|
+
if (entrySetupFile) return entrySetupFile;
|
|
985
|
+
const indexHtml = findFileWithReactGrabSetup(getIndexHtmlCandidates(projectRoot));
|
|
986
|
+
if (indexHtml) return indexHtml;
|
|
1000
987
|
return entryFile;
|
|
1001
988
|
}
|
|
1002
|
-
case "tanstack": return findTanStackRootFile(projectRoot);
|
|
1003
|
-
case "webpack": return findEntryFile(projectRoot);
|
|
989
|
+
case "tanstack": return findFileWithReactGrabSetup(getTanStackRootFileCandidates(projectRoot)) ?? findTanStackRootFile(projectRoot);
|
|
990
|
+
case "webpack": return findFileWithReactGrabSetup(getEntryFileCandidates(projectRoot)) ?? findEntryFile(projectRoot);
|
|
1004
991
|
default: return null;
|
|
1005
992
|
}
|
|
1006
993
|
};
|
|
@@ -1028,13 +1015,14 @@ const addOptionsToNextScript = (originalContent, options, filePath) => {
|
|
|
1028
1015
|
};
|
|
1029
1016
|
};
|
|
1030
1017
|
const addOptionsToDynamicImport = (originalContent, options, filePath) => {
|
|
1031
|
-
const reactGrabImportWithInitMatch = originalContent.match(/import\s*\(\s*["']react-grab["']\s*\)(?:\.then\s*\(\s
|
|
1018
|
+
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*\))?/);
|
|
1032
1019
|
if (!reactGrabImportWithInitMatch) return {
|
|
1033
1020
|
success: false,
|
|
1034
1021
|
filePath,
|
|
1035
1022
|
message: "Could not find React Grab import"
|
|
1036
1023
|
};
|
|
1037
|
-
const
|
|
1024
|
+
const optionsJson = formatOptionsAsJson(options);
|
|
1025
|
+
const newImport = `${reactGrabImportWithInitMatch[1] ?? ""}import("react-grab").then((m) => m.init(${optionsJson}))`;
|
|
1038
1026
|
return {
|
|
1039
1027
|
success: true,
|
|
1040
1028
|
filePath,
|
|
@@ -1044,13 +1032,14 @@ const addOptionsToDynamicImport = (originalContent, options, filePath) => {
|
|
|
1044
1032
|
};
|
|
1045
1033
|
};
|
|
1046
1034
|
const addOptionsToTanStackImport = (originalContent, options, filePath) => {
|
|
1047
|
-
const reactGrabImportWithInitMatch = originalContent.match(/(?:void\s+
|
|
1035
|
+
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*\))/);
|
|
1048
1036
|
if (!reactGrabImportWithInitMatch) return {
|
|
1049
1037
|
success: false,
|
|
1050
1038
|
filePath,
|
|
1051
1039
|
message: "Could not find React Grab import"
|
|
1052
1040
|
};
|
|
1053
|
-
const
|
|
1041
|
+
const optionsJson = formatOptionsAsJson(options);
|
|
1042
|
+
const newImport = `${reactGrabImportWithInitMatch[1] ?? reactGrabImportWithInitMatch[2] ?? ""}import("react-grab/core").then(({ init }) => init(${optionsJson}))`;
|
|
1054
1043
|
return {
|
|
1055
1044
|
success: true,
|
|
1056
1045
|
filePath,
|
|
@@ -1059,6 +1048,11 @@ const addOptionsToTanStackImport = (originalContent, options, filePath) => {
|
|
|
1059
1048
|
newContent: originalContent.replace(reactGrabImportWithInitMatch[0], newImport)
|
|
1060
1049
|
};
|
|
1061
1050
|
};
|
|
1051
|
+
const addOptionsToAnyImport = (originalContent, options, filePath) => {
|
|
1052
|
+
const dynamicImportResult = addOptionsToDynamicImport(originalContent, options, filePath);
|
|
1053
|
+
if (dynamicImportResult.success) return dynamicImportResult;
|
|
1054
|
+
return addOptionsToTanStackImport(originalContent, options, filePath);
|
|
1055
|
+
};
|
|
1062
1056
|
const previewOptionsTransform = (projectRoot, framework, nextRouterType, options) => {
|
|
1063
1057
|
const filePath = findReactGrabFile(projectRoot, framework, nextRouterType);
|
|
1064
1058
|
if (!filePath) return {
|
|
@@ -1067,13 +1061,15 @@ const previewOptionsTransform = (projectRoot, framework, nextRouterType, options
|
|
|
1067
1061
|
message: "Could not find file containing React Grab configuration"
|
|
1068
1062
|
};
|
|
1069
1063
|
const originalContent = (0, node_fs.readFileSync)(filePath, "utf-8");
|
|
1070
|
-
if (!
|
|
1064
|
+
if (!hasReactGrabSetupCode(originalContent)) return {
|
|
1071
1065
|
success: false,
|
|
1072
1066
|
filePath,
|
|
1073
1067
|
message: "Could not find React Grab code in the file"
|
|
1074
1068
|
};
|
|
1075
1069
|
switch (framework) {
|
|
1076
|
-
case "next":
|
|
1070
|
+
case "next":
|
|
1071
|
+
if (isInstrumentationFile(filePath)) return addOptionsToAnyImport(originalContent, options, filePath);
|
|
1072
|
+
return addOptionsToNextScript(originalContent, options, filePath);
|
|
1077
1073
|
case "vite": return addOptionsToDynamicImport(originalContent, options, filePath);
|
|
1078
1074
|
case "tanstack": return addOptionsToTanStackImport(originalContent, options, filePath);
|
|
1079
1075
|
case "webpack": return addOptionsToDynamicImport(originalContent, options, filePath);
|
|
@@ -1131,7 +1127,7 @@ const formatActivationKeyDisplay = (activationKey) => {
|
|
|
1131
1127
|
};
|
|
1132
1128
|
//#endregion
|
|
1133
1129
|
//#region src/commands/configure.ts
|
|
1134
|
-
const VERSION$4 = "0.1.
|
|
1130
|
+
const VERSION$4 = "0.1.44-dev.0b82e39";
|
|
1135
1131
|
const isMac = process.platform === "darwin";
|
|
1136
1132
|
const META_LABEL = isMac ? "Cmd" : "Win";
|
|
1137
1133
|
const ALT_LABEL = isMac ? "Option" : "Alt";
|
|
@@ -1401,8 +1397,8 @@ const generateSuggestions = (input) => {
|
|
|
1401
1397
|
const CONFIG_OPTIONS = [
|
|
1402
1398
|
{
|
|
1403
1399
|
id: "activationKey",
|
|
1404
|
-
title: "
|
|
1405
|
-
description: "The
|
|
1400
|
+
title: "Shortcut",
|
|
1401
|
+
description: "The shortcut used to activate React Grab (e.g., g, k, space)"
|
|
1406
1402
|
},
|
|
1407
1403
|
{
|
|
1408
1404
|
id: "activationMode",
|
|
@@ -1437,7 +1433,7 @@ const comboToString = (combo) => {
|
|
|
1437
1433
|
}
|
|
1438
1434
|
return parts.join("+");
|
|
1439
1435
|
};
|
|
1440
|
-
const configure = new commander.Command().name("configure").alias("config").description("configure React Grab options").option("-y, --yes", "skip confirmation prompts", false).option("-k, --key <key>", "
|
|
1436
|
+
const configure = new commander.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) => {
|
|
1441
1437
|
console.log(`${picocolors.default.magenta("✿")} ${picocolors.default.bold("React Grab")} ${picocolors.default.gray(VERSION$4)}`);
|
|
1442
1438
|
console.log();
|
|
1443
1439
|
try {
|
|
@@ -1451,6 +1447,13 @@ const configure = new commander.Command().name("configure").alias("config").desc
|
|
|
1451
1447
|
logger.break();
|
|
1452
1448
|
process.exit(1);
|
|
1453
1449
|
}
|
|
1450
|
+
if (!projectInfo.isReactGrabConfigured) {
|
|
1451
|
+
preflightSpinner.fail("React Grab is installed, but setup is missing.");
|
|
1452
|
+
logger.break();
|
|
1453
|
+
logger.error(`Run ${highlighter.info("react-grab init")} to add the setup script/import before configuring options.`);
|
|
1454
|
+
logger.break();
|
|
1455
|
+
process.exit(1);
|
|
1456
|
+
}
|
|
1454
1457
|
preflightSpinner.succeed();
|
|
1455
1458
|
if (opts.cdn) {
|
|
1456
1459
|
const result = previewCdnTransform(projectInfo.projectRoot, projectInfo.framework, projectInfo.nextRouterType, opts.cdn);
|
|
@@ -1506,7 +1509,7 @@ const configure = new commander.Command().name("configure").alias("config").desc
|
|
|
1506
1509
|
if (hasFlags) {
|
|
1507
1510
|
if (opts.key) {
|
|
1508
1511
|
collectedOptions.activationKey = opts.key;
|
|
1509
|
-
logger.log(`
|
|
1512
|
+
logger.log(` Shortcut: ${highlighter.info(formatActivationKeyDisplay(collectedOptions.activationKey))}`);
|
|
1510
1513
|
}
|
|
1511
1514
|
if (opts.mode) {
|
|
1512
1515
|
if (opts.mode !== "toggle" && opts.mode !== "hold") {
|
|
@@ -1571,7 +1574,7 @@ const configure = new commander.Command().name("configure").alias("config").desc
|
|
|
1571
1574
|
process.exit(1);
|
|
1572
1575
|
}
|
|
1573
1576
|
collectedOptions.activationKey = comboToString(selectedCombo);
|
|
1574
|
-
logger.log(`
|
|
1577
|
+
logger.log(` Shortcut: ${highlighter.info(formatActivationKeyDisplay(collectedOptions.activationKey))}`);
|
|
1575
1578
|
}
|
|
1576
1579
|
if (selectedOption === "activationMode") {
|
|
1577
1580
|
const { activationMode } = await prompts$1({
|
|
@@ -1756,7 +1759,7 @@ const isTelemetryEnabled = () => {
|
|
|
1756
1759
|
};
|
|
1757
1760
|
//#endregion
|
|
1758
1761
|
//#region src/commands/init.ts
|
|
1759
|
-
const VERSION$3 = "0.1.
|
|
1762
|
+
const VERSION$3 = "0.1.44-dev.0b82e39";
|
|
1760
1763
|
const REPORT_URL = "https://react-grab.com/api/report-cli";
|
|
1761
1764
|
const DOCS_URL = "https://github.com/aidenybai/react-grab";
|
|
1762
1765
|
const reportToCli = (type, config, error) => {
|
|
@@ -1824,7 +1827,7 @@ const failWithManualSetup = (failingSpinner, message, { listSupportedFrameworks
|
|
|
1824
1827
|
logger.break();
|
|
1825
1828
|
process.exit(1);
|
|
1826
1829
|
};
|
|
1827
|
-
const init = new commander.Command().name("init").alias("setup").description("initialize React Grab in your project").option("-y, --yes", "skip confirmation prompts", false).option("-f, --force", "
|
|
1830
|
+
const init = new commander.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) => {
|
|
1828
1831
|
console.log(`${picocolors.default.magenta("✿")} ${picocolors.default.bold("React Grab")} ${picocolors.default.gray(VERSION$3)}`);
|
|
1829
1832
|
console.log();
|
|
1830
1833
|
try {
|
|
@@ -1838,12 +1841,12 @@ const init = new commander.Command().name("init").alias("setup").description("in
|
|
|
1838
1841
|
}
|
|
1839
1842
|
const preflightSpinner = spinner("Preflight checks.").start();
|
|
1840
1843
|
const projectInfo = await detectProject(cwd);
|
|
1841
|
-
if (projectInfo.
|
|
1844
|
+
if (projectInfo.isReactGrabConfigured && !opts.force) {
|
|
1842
1845
|
preflightSpinner.succeed();
|
|
1843
1846
|
if (isNonInteractive) {
|
|
1844
1847
|
logger.break();
|
|
1845
1848
|
logger.warn("React Grab is already installed.");
|
|
1846
|
-
logger.log(`Use ${highlighter.info("--force")} to
|
|
1849
|
+
logger.log(`Use ${highlighter.info("--force")} to re-run setup checks, or remove ${highlighter.info("--yes")} for interactive mode.`);
|
|
1847
1850
|
logger.break();
|
|
1848
1851
|
process.exit(0);
|
|
1849
1852
|
}
|
|
@@ -1867,12 +1870,12 @@ const init = new commander.Command().name("init").alias("setup").description("in
|
|
|
1867
1870
|
const collectedOptions = {};
|
|
1868
1871
|
if (opts.key) {
|
|
1869
1872
|
collectedOptions.activationKey = opts.key;
|
|
1870
|
-
logger.log(`
|
|
1873
|
+
logger.log(` Shortcut: ${highlighter.info(formatActivationKeyDisplay(collectedOptions.activationKey))}`);
|
|
1871
1874
|
} else {
|
|
1872
1875
|
const { wantActivationKey } = await prompts$1({
|
|
1873
1876
|
type: "confirm",
|
|
1874
1877
|
name: "wantActivationKey",
|
|
1875
|
-
message: `Configure ${highlighter.info("
|
|
1878
|
+
message: `Configure ${highlighter.info("shortcut")}?`,
|
|
1876
1879
|
initial: false
|
|
1877
1880
|
});
|
|
1878
1881
|
if (wantActivationKey === void 0) {
|
|
@@ -1883,7 +1886,7 @@ const init = new commander.Command().name("init").alias("setup").description("in
|
|
|
1883
1886
|
const { key } = await prompts$1({
|
|
1884
1887
|
type: "text",
|
|
1885
1888
|
name: "key",
|
|
1886
|
-
message: "Enter the
|
|
1889
|
+
message: "Enter the shortcut (e.g., g, k, space):",
|
|
1887
1890
|
initial: ""
|
|
1888
1891
|
});
|
|
1889
1892
|
if (key === void 0) {
|
|
@@ -1891,7 +1894,7 @@ const init = new commander.Command().name("init").alias("setup").description("in
|
|
|
1891
1894
|
process.exit(1);
|
|
1892
1895
|
}
|
|
1893
1896
|
collectedOptions.activationKey = key ? key.toLowerCase() : void 0;
|
|
1894
|
-
logger.log(`
|
|
1897
|
+
logger.log(` Shortcut: ${highlighter.info(formatActivationKeyDisplay(collectedOptions.activationKey))}`);
|
|
1895
1898
|
}
|
|
1896
1899
|
}
|
|
1897
1900
|
const { activationMode } = await prompts$1({
|
|
@@ -2058,7 +2061,7 @@ const init = new commander.Command().name("init").alias("setup").description("in
|
|
|
2058
2061
|
cwd
|
|
2059
2062
|
});
|
|
2060
2063
|
}
|
|
2061
|
-
const result = previewTransform(projectInfo.projectRoot, finalFramework, finalNextRouterType,
|
|
2064
|
+
const result = previewTransform(projectInfo.projectRoot, finalFramework, finalNextRouterType, projectInfo.isReactGrabConfigured);
|
|
2062
2065
|
if (!result.success) {
|
|
2063
2066
|
logger.break();
|
|
2064
2067
|
logger.error(result.message);
|
|
@@ -2093,7 +2096,8 @@ const init = new commander.Command().name("init").alias("setup").description("in
|
|
|
2093
2096
|
if (!opts.skipInstall && shouldInstallReactGrab) await installPackagesWithFeedback(getPackagesToInstall(shouldInstallReactGrab), finalPackageManager, projectInfo.projectRoot);
|
|
2094
2097
|
if (hasLayoutChanges) applyTransformWithFeedback(result);
|
|
2095
2098
|
logger.break();
|
|
2096
|
-
logger.log(`${highlighter.success("Success!")} React Grab has been installed.`);
|
|
2099
|
+
if (hasLayoutChanges) logger.log(`${highlighter.success("Success!")} React Grab has been installed.`);
|
|
2100
|
+
else logger.log(`${highlighter.success("Success!")} ${result.message}.`);
|
|
2097
2101
|
logger.log("You may now start your development server.");
|
|
2098
2102
|
logger.break();
|
|
2099
2103
|
reportToCli("completed", {
|
|
@@ -2706,7 +2710,7 @@ const pull = new commander.Command().name("pull").description("start the watcher
|
|
|
2706
2710
|
});
|
|
2707
2711
|
//#endregion
|
|
2708
2712
|
//#region src/commands/remove.ts
|
|
2709
|
-
const VERSION$2 = "0.1.
|
|
2713
|
+
const VERSION$2 = "0.1.44-dev.0b82e39";
|
|
2710
2714
|
const remove = new commander.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) => {
|
|
2711
2715
|
console.log(`${picocolors.default.magenta("✿")} ${picocolors.default.bold("React Grab")} ${picocolors.default.gray(VERSION$2)}`);
|
|
2712
2716
|
console.log();
|
|
@@ -2734,7 +2738,7 @@ const stop = new commander.Command().name("stop").description("stop the React Gr
|
|
|
2734
2738
|
});
|
|
2735
2739
|
//#endregion
|
|
2736
2740
|
//#region src/commands/upgrade.ts
|
|
2737
|
-
const VERSION$1 = "0.1.
|
|
2741
|
+
const VERSION$1 = "0.1.44-dev.0b82e39";
|
|
2738
2742
|
const NPM_REGISTRY_URL = "https://registry.npmjs.org/react-grab/latest";
|
|
2739
2743
|
const fetchLatestVersion = async () => {
|
|
2740
2744
|
try {
|
|
@@ -2846,7 +2850,7 @@ const watch = new commander.Command().name("watch").description("run the React G
|
|
|
2846
2850
|
});
|
|
2847
2851
|
//#endregion
|
|
2848
2852
|
//#region src/cli.ts
|
|
2849
|
-
const VERSION = "0.1.
|
|
2853
|
+
const VERSION = "0.1.44-dev.0b82e39";
|
|
2850
2854
|
const VERSION_API_URL = "https://www.react-grab.com/api/version";
|
|
2851
2855
|
process.on("SIGINT", () => process.exit(0));
|
|
2852
2856
|
process.on("SIGTERM", () => process.exit(0));
|