@react-grab/cli 0.1.0 → 0.1.2
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 +495 -18
- package/dist/cli.js +494 -17
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var commander = require('commander');
|
|
5
|
-
var
|
|
5
|
+
var pc5 = require('picocolors');
|
|
6
6
|
var prompts3 = require('prompts');
|
|
7
7
|
var child_process = require('child_process');
|
|
8
8
|
var fs = require('fs');
|
|
@@ -12,7 +12,7 @@ var ora = require('ora');
|
|
|
12
12
|
|
|
13
13
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
14
|
|
|
15
|
-
var
|
|
15
|
+
var pc5__default = /*#__PURE__*/_interopDefault(pc5);
|
|
16
16
|
var prompts3__default = /*#__PURE__*/_interopDefault(prompts3);
|
|
17
17
|
var ora__default = /*#__PURE__*/_interopDefault(ora);
|
|
18
18
|
|
|
@@ -261,6 +261,85 @@ var AGENT_PACKAGES = [
|
|
|
261
261
|
"@react-grab/amp",
|
|
262
262
|
"@react-grab/ami"
|
|
263
263
|
];
|
|
264
|
+
var REACT_SCAN_DETECTION_PATTERNS = [
|
|
265
|
+
/["'`][^"'`]*react-scan/,
|
|
266
|
+
/react-scan[^"'`]*["'`]/,
|
|
267
|
+
/unpkg\.com\/react-scan/,
|
|
268
|
+
/import\s*\(?["']react-scan/,
|
|
269
|
+
/require\s*\(["']react-scan/,
|
|
270
|
+
/from\s+["']react-scan/,
|
|
271
|
+
/<Script[^>]*react-scan/i,
|
|
272
|
+
/<script[^>]*react-scan/i
|
|
273
|
+
];
|
|
274
|
+
var REACT_SCAN_FILE_PATTERNS = [
|
|
275
|
+
["app", "layout"],
|
|
276
|
+
["src", "app", "layout"],
|
|
277
|
+
["pages", "_document"],
|
|
278
|
+
["pages", "_app"],
|
|
279
|
+
["src", "pages", "_document"],
|
|
280
|
+
["src", "pages", "_app"],
|
|
281
|
+
["index"],
|
|
282
|
+
["public", "index"],
|
|
283
|
+
["src", "index"],
|
|
284
|
+
["src", "main"],
|
|
285
|
+
["src", "routes", "__root"],
|
|
286
|
+
["app", "routes", "__root"]
|
|
287
|
+
];
|
|
288
|
+
var SCRIPT_EXTENSIONS = ["tsx", "jsx", "ts", "js"];
|
|
289
|
+
var getReactScanFilesToCheck = (projectRoot) => REACT_SCAN_FILE_PATTERNS.flatMap((segments) => {
|
|
290
|
+
const baseName = segments[segments.length - 1];
|
|
291
|
+
const isHtmlFile = baseName === "index" && segments.length <= 2;
|
|
292
|
+
const extensions = isHtmlFile ? [...SCRIPT_EXTENSIONS, "html"] : SCRIPT_EXTENSIONS;
|
|
293
|
+
return extensions.map(
|
|
294
|
+
(extension) => path.join(projectRoot, ...segments) + `.${extension}`
|
|
295
|
+
);
|
|
296
|
+
});
|
|
297
|
+
var hasReactScanInFile = (filePath) => {
|
|
298
|
+
if (!fs.existsSync(filePath)) return false;
|
|
299
|
+
try {
|
|
300
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
301
|
+
return REACT_SCAN_DETECTION_PATTERNS.some(
|
|
302
|
+
(pattern) => pattern.test(content)
|
|
303
|
+
);
|
|
304
|
+
} catch {
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
var detectReactScan = (projectRoot) => {
|
|
309
|
+
const result = {
|
|
310
|
+
hasReactScan: false,
|
|
311
|
+
hasReactScanMonitoring: false,
|
|
312
|
+
isPackageInstalled: false,
|
|
313
|
+
detectedFiles: []
|
|
314
|
+
};
|
|
315
|
+
const packageJsonPath = path.join(projectRoot, "package.json");
|
|
316
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
317
|
+
try {
|
|
318
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
319
|
+
const allDependencies = {
|
|
320
|
+
...packageJson.dependencies,
|
|
321
|
+
...packageJson.devDependencies
|
|
322
|
+
};
|
|
323
|
+
if (allDependencies["react-scan"]) {
|
|
324
|
+
result.isPackageInstalled = true;
|
|
325
|
+
result.hasReactScan = true;
|
|
326
|
+
}
|
|
327
|
+
if (allDependencies["@react-scan/monitoring"]) {
|
|
328
|
+
result.hasReactScanMonitoring = true;
|
|
329
|
+
result.hasReactScan = true;
|
|
330
|
+
}
|
|
331
|
+
} catch {
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
const filesToCheck = getReactScanFilesToCheck(projectRoot);
|
|
335
|
+
for (const filePath of filesToCheck) {
|
|
336
|
+
if (hasReactScanInFile(filePath)) {
|
|
337
|
+
result.hasReactScan = true;
|
|
338
|
+
result.detectedFiles.push(filePath);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
return result;
|
|
342
|
+
};
|
|
264
343
|
var detectUnsupportedFramework = (projectRoot) => {
|
|
265
344
|
const packageJsonPath = path.join(projectRoot, "package.json");
|
|
266
345
|
if (!fs.existsSync(packageJsonPath)) {
|
|
@@ -422,11 +501,11 @@ ${BOLD}File: ${filePath}${RESET}`);
|
|
|
422
501
|
console.log("\u2500".repeat(60));
|
|
423
502
|
};
|
|
424
503
|
var highlighter = {
|
|
425
|
-
error:
|
|
426
|
-
warn:
|
|
427
|
-
info:
|
|
428
|
-
success:
|
|
429
|
-
dim:
|
|
504
|
+
error: pc5__default.default.red,
|
|
505
|
+
warn: pc5__default.default.yellow,
|
|
506
|
+
info: pc5__default.default.cyan,
|
|
507
|
+
success: pc5__default.default.green,
|
|
508
|
+
dim: pc5__default.default.dim
|
|
430
509
|
};
|
|
431
510
|
|
|
432
511
|
// src/utils/logger.ts
|
|
@@ -1820,9 +1899,120 @@ var previewPackageJsonAgentRemoval = (projectRoot, agent) => {
|
|
|
1820
1899
|
};
|
|
1821
1900
|
}
|
|
1822
1901
|
};
|
|
1902
|
+
var hasReactScanCode = (content) => REACT_SCAN_DETECTION_PATTERNS.some((pattern) => pattern.test(content));
|
|
1903
|
+
var createRemovalTransform = (removalPatterns) => {
|
|
1904
|
+
return (originalContent, filePath) => {
|
|
1905
|
+
if (!hasReactScanCode(originalContent)) {
|
|
1906
|
+
return {
|
|
1907
|
+
success: true,
|
|
1908
|
+
filePath,
|
|
1909
|
+
message: "React Scan is not configured in this file",
|
|
1910
|
+
noChanges: true
|
|
1911
|
+
};
|
|
1912
|
+
}
|
|
1913
|
+
let newContent = originalContent;
|
|
1914
|
+
for (const pattern of removalPatterns) {
|
|
1915
|
+
newContent = newContent.replace(pattern, "");
|
|
1916
|
+
}
|
|
1917
|
+
if (newContent === originalContent) {
|
|
1918
|
+
return {
|
|
1919
|
+
success: true,
|
|
1920
|
+
filePath,
|
|
1921
|
+
message: "Could not remove React Scan code",
|
|
1922
|
+
noChanges: true
|
|
1923
|
+
};
|
|
1924
|
+
}
|
|
1925
|
+
return {
|
|
1926
|
+
success: true,
|
|
1927
|
+
filePath,
|
|
1928
|
+
message: "Remove React Scan",
|
|
1929
|
+
originalContent,
|
|
1930
|
+
newContent
|
|
1931
|
+
};
|
|
1932
|
+
};
|
|
1933
|
+
};
|
|
1934
|
+
var NEXT_APP_REMOVAL_PATTERNS = [
|
|
1935
|
+
/\s*\{process\.env\.NODE_ENV\s*===\s*["']development["']\s*&&\s*\(\s*<Script[^>]*react-scan[^>]*\/>\s*\)\}/gs,
|
|
1936
|
+
/\s*<Script[^>]*react-scan[^>]*\/>/gi,
|
|
1937
|
+
/\s*<script[^>]*>\s*(?:if\s*\([^)]*\)\s*\{)?\s*import\s*\(\s*["']react-scan["']\s*\)[^<]*<\/script>/gi,
|
|
1938
|
+
/\s*<script[^>]*react-scan[^>]*>[^<]*<\/script>/gi,
|
|
1939
|
+
/\s*<script[^>]*react-scan[^>]*\/>/gi
|
|
1940
|
+
];
|
|
1941
|
+
var VITE_REMOVAL_PATTERNS = [
|
|
1942
|
+
/\s*import\s*\(\s*["']react-scan["']\s*\)\s*\.then\s*\([^)]*\)[^;]*;?/g,
|
|
1943
|
+
/\s*import\s*\(\s*["']react-scan["']\s*\);?/g,
|
|
1944
|
+
/^\s*import\s+(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s+from\s+["']react-scan["'];?\s*$/gm,
|
|
1945
|
+
/<script[^>]*type="module"[^>]*>\s*if\s*\(\s*import\.meta\.env\.DEV\s*\)\s*\{\s*\}\s*<\/script>/gi
|
|
1946
|
+
];
|
|
1947
|
+
var WEBPACK_REMOVAL_PATTERNS = [
|
|
1948
|
+
/\s*import\s*\(\s*["']react-scan["']\s*\)\s*\.then\s*\([^)]*\)[^;]*;?/g,
|
|
1949
|
+
/\s*import\s*\(\s*["']react-scan["']\s*\);?/g,
|
|
1950
|
+
/^\s*import\s+(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s+from\s+["']react-scan["'];?\s*$/gm,
|
|
1951
|
+
/if\s*\(\s*process\.env\.NODE_ENV\s*===\s*["']development["']\s*\)\s*\{\s*\}/g
|
|
1952
|
+
];
|
|
1953
|
+
var TANSTACK_REMOVAL_PATTERNS = [
|
|
1954
|
+
/\s*void\s+import\s*\(\s*["']react-scan["']\s*\);?/g,
|
|
1955
|
+
/\s*import\s*\(\s*["']react-scan["']\s*\);?/g,
|
|
1956
|
+
/^\s*import\s+(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s+from\s+["']react-scan["'];?\s*$/gm
|
|
1957
|
+
];
|
|
1958
|
+
var removeReactScanFromNextApp = createRemovalTransform(
|
|
1959
|
+
NEXT_APP_REMOVAL_PATTERNS
|
|
1960
|
+
);
|
|
1961
|
+
var removeReactScanFromVite = createRemovalTransform(VITE_REMOVAL_PATTERNS);
|
|
1962
|
+
var removeReactScanFromWebpack = createRemovalTransform(
|
|
1963
|
+
WEBPACK_REMOVAL_PATTERNS
|
|
1964
|
+
);
|
|
1965
|
+
var removeReactScanFromTanStack = createRemovalTransform(
|
|
1966
|
+
TANSTACK_REMOVAL_PATTERNS
|
|
1967
|
+
);
|
|
1968
|
+
var findReactScanFile = (projectRoot, framework, nextRouterType) => {
|
|
1969
|
+
switch (framework) {
|
|
1970
|
+
case "next":
|
|
1971
|
+
if (nextRouterType === "app") {
|
|
1972
|
+
return findLayoutFile(projectRoot);
|
|
1973
|
+
}
|
|
1974
|
+
return findDocumentFile(projectRoot);
|
|
1975
|
+
case "vite":
|
|
1976
|
+
return findIndexHtml(projectRoot);
|
|
1977
|
+
case "tanstack":
|
|
1978
|
+
return findTanStackRootFile(projectRoot);
|
|
1979
|
+
case "webpack":
|
|
1980
|
+
return findEntryFile(projectRoot);
|
|
1981
|
+
default:
|
|
1982
|
+
return null;
|
|
1983
|
+
}
|
|
1984
|
+
};
|
|
1985
|
+
var previewReactScanRemoval = (projectRoot, framework, nextRouterType) => {
|
|
1986
|
+
const filePath = findReactScanFile(projectRoot, framework, nextRouterType);
|
|
1987
|
+
if (!filePath) {
|
|
1988
|
+
return {
|
|
1989
|
+
success: true,
|
|
1990
|
+
filePath: "",
|
|
1991
|
+
message: "Could not find file containing React Scan configuration",
|
|
1992
|
+
noChanges: true
|
|
1993
|
+
};
|
|
1994
|
+
}
|
|
1995
|
+
const originalContent = fs.readFileSync(filePath, "utf-8");
|
|
1996
|
+
switch (framework) {
|
|
1997
|
+
case "next":
|
|
1998
|
+
return removeReactScanFromNextApp(originalContent, filePath);
|
|
1999
|
+
case "vite":
|
|
2000
|
+
return removeReactScanFromVite(originalContent, filePath);
|
|
2001
|
+
case "tanstack":
|
|
2002
|
+
return removeReactScanFromTanStack(originalContent, filePath);
|
|
2003
|
+
case "webpack":
|
|
2004
|
+
return removeReactScanFromWebpack(originalContent, filePath);
|
|
2005
|
+
default:
|
|
2006
|
+
return {
|
|
2007
|
+
success: false,
|
|
2008
|
+
filePath,
|
|
2009
|
+
message: `Unknown framework: ${framework}`
|
|
2010
|
+
};
|
|
2011
|
+
}
|
|
2012
|
+
};
|
|
1823
2013
|
|
|
1824
2014
|
// src/commands/add.ts
|
|
1825
|
-
var VERSION = "0.1.
|
|
2015
|
+
var VERSION = "0.1.1";
|
|
1826
2016
|
var formatInstalledAgentNames = (agents) => agents.map((agent) => AGENT_NAMES[agent] || agent).join(", ");
|
|
1827
2017
|
var add = new commander.Command().name("add").alias("install").description("add an agent integration").argument("[agent]", `agent to add (${AGENTS.join(", ")})`).option("-y, --yes", "skip confirmation prompts", false).option(
|
|
1828
2018
|
"-c, --cwd <cwd>",
|
|
@@ -1830,7 +2020,7 @@ var add = new commander.Command().name("add").alias("install").description("add
|
|
|
1830
2020
|
process.cwd()
|
|
1831
2021
|
).action(async (agentArg, opts) => {
|
|
1832
2022
|
console.log(
|
|
1833
|
-
`${
|
|
2023
|
+
`${pc5__default.default.magenta("\u273F")} ${pc5__default.default.bold("React Grab")} ${pc5__default.default.gray(VERSION)}`
|
|
1834
2024
|
);
|
|
1835
2025
|
console.log();
|
|
1836
2026
|
try {
|
|
@@ -2158,7 +2348,7 @@ var MAX_KEY_HOLD_DURATION_MS = 2e3;
|
|
|
2158
2348
|
var MAX_CONTEXT_LINES = 50;
|
|
2159
2349
|
|
|
2160
2350
|
// src/commands/configure.ts
|
|
2161
|
-
var VERSION2 = "0.1.
|
|
2351
|
+
var VERSION2 = "0.1.1";
|
|
2162
2352
|
var isMac = process.platform === "darwin";
|
|
2163
2353
|
var META_LABEL = isMac ? "Cmd" : "Win";
|
|
2164
2354
|
var ALT_LABEL = isMac ? "Option" : "Alt";
|
|
@@ -2368,7 +2558,7 @@ var configure = new commander.Command().name("configure").alias("config").descri
|
|
|
2368
2558
|
process.cwd()
|
|
2369
2559
|
).action(async (opts) => {
|
|
2370
2560
|
console.log(
|
|
2371
|
-
`${
|
|
2561
|
+
`${pc5__default.default.magenta("\u273F")} ${pc5__default.default.bold("React Grab")} ${pc5__default.default.gray(VERSION2)}`
|
|
2372
2562
|
);
|
|
2373
2563
|
console.log();
|
|
2374
2564
|
try {
|
|
@@ -2555,7 +2745,7 @@ var configure = new commander.Command().name("configure").alias("config").descri
|
|
|
2555
2745
|
`Add this to your ${highlighter.info("init()")} call or ${highlighter.info("data-options")} attribute:`
|
|
2556
2746
|
);
|
|
2557
2747
|
logger.break();
|
|
2558
|
-
console.log(` ${
|
|
2748
|
+
console.log(` ${pc5__default.default.cyan(configJson)}`);
|
|
2559
2749
|
logger.break();
|
|
2560
2750
|
process.exit(1);
|
|
2561
2751
|
}
|
|
@@ -2658,7 +2848,7 @@ var uninstallPackagesWithFeedback = (packages, packageManager, projectRoot) => {
|
|
|
2658
2848
|
};
|
|
2659
2849
|
|
|
2660
2850
|
// src/commands/init.ts
|
|
2661
|
-
var VERSION3 = "0.1.
|
|
2851
|
+
var VERSION3 = "0.1.1";
|
|
2662
2852
|
var REPORT_URL = "https://react-grab.com/api/report-cli";
|
|
2663
2853
|
var DOCS_URL = "https://github.com/aidenybai/react-grab";
|
|
2664
2854
|
var reportToCli = (type, config, error) => {
|
|
@@ -2724,7 +2914,7 @@ var init = new commander.Command().name("init").description("initialize React Gr
|
|
|
2724
2914
|
process.cwd()
|
|
2725
2915
|
).action(async (opts) => {
|
|
2726
2916
|
console.log(
|
|
2727
|
-
`${
|
|
2917
|
+
`${pc5__default.default.magenta("\u273F")} ${pc5__default.default.bold("React Grab")} ${pc5__default.default.gray(VERSION3)}`
|
|
2728
2918
|
);
|
|
2729
2919
|
console.log();
|
|
2730
2920
|
try {
|
|
@@ -3325,7 +3515,293 @@ var init = new commander.Command().name("init").description("initialize React Gr
|
|
|
3325
3515
|
reportToCli("error", void 0, error);
|
|
3326
3516
|
}
|
|
3327
3517
|
});
|
|
3328
|
-
var VERSION4 = "0.1.
|
|
3518
|
+
var VERSION4 = "0.1.1";
|
|
3519
|
+
var DOCS_URL2 = "https://github.com/aidenybai/react-grab";
|
|
3520
|
+
var exitWithMessage = (message, code = 0) => {
|
|
3521
|
+
if (message) logger.log(message);
|
|
3522
|
+
logger.break();
|
|
3523
|
+
process.exit(code);
|
|
3524
|
+
};
|
|
3525
|
+
var confirmOrExit = async (message, isNonInteractive) => {
|
|
3526
|
+
if (isNonInteractive) return;
|
|
3527
|
+
const { proceed } = await prompts3__default.default({
|
|
3528
|
+
type: "confirm",
|
|
3529
|
+
name: "proceed",
|
|
3530
|
+
message,
|
|
3531
|
+
initial: true
|
|
3532
|
+
});
|
|
3533
|
+
if (!proceed) exitWithMessage("Migration cancelled.");
|
|
3534
|
+
};
|
|
3535
|
+
var hasTransformChanges = (result) => result.success && !result.noChanges && Boolean(result.originalContent) && Boolean(result.newContent);
|
|
3536
|
+
var MIGRATION_SOURCES = ["react-scan"];
|
|
3537
|
+
var MIGRATION_SOURCE_NAMES = {
|
|
3538
|
+
"react-scan": "React Scan"
|
|
3539
|
+
};
|
|
3540
|
+
var FRAMEWORK_NAMES2 = {
|
|
3541
|
+
next: "Next.js",
|
|
3542
|
+
vite: "Vite",
|
|
3543
|
+
tanstack: "TanStack Start",
|
|
3544
|
+
webpack: "Webpack",
|
|
3545
|
+
unknown: "Unknown"
|
|
3546
|
+
};
|
|
3547
|
+
var migrate = new commander.Command().name("migrate").description("migrate to React Grab from another tool").option("-y, --yes", "skip confirmation prompts", false).option("-f, --from <source>", "migration source (react-scan)").option(
|
|
3548
|
+
"-c, --cwd <cwd>",
|
|
3549
|
+
"working directory (defaults to current directory)",
|
|
3550
|
+
process.cwd()
|
|
3551
|
+
).action(async (opts) => {
|
|
3552
|
+
console.log(
|
|
3553
|
+
`${pc5__default.default.magenta("\u273F")} ${pc5__default.default.bold("React Grab")} ${pc5__default.default.gray(VERSION4)}`
|
|
3554
|
+
);
|
|
3555
|
+
console.log();
|
|
3556
|
+
try {
|
|
3557
|
+
const cwd = opts.cwd;
|
|
3558
|
+
const isNonInteractive = opts.yes;
|
|
3559
|
+
let migrationSource = opts.from;
|
|
3560
|
+
if (!migrationSource) {
|
|
3561
|
+
if (isNonInteractive) {
|
|
3562
|
+
logger.error(
|
|
3563
|
+
"Migration source is required in non-interactive mode. Use --from <source>"
|
|
3564
|
+
);
|
|
3565
|
+
logger.log(
|
|
3566
|
+
`Available sources: ${MIGRATION_SOURCES.map((innerSource) => highlighter.info(innerSource)).join(", ")}`
|
|
3567
|
+
);
|
|
3568
|
+
logger.break();
|
|
3569
|
+
process.exit(1);
|
|
3570
|
+
}
|
|
3571
|
+
const { source } = await prompts3__default.default({
|
|
3572
|
+
type: "select",
|
|
3573
|
+
name: "source",
|
|
3574
|
+
message: `What would you like to migrate ${highlighter.info("from")}?`,
|
|
3575
|
+
choices: MIGRATION_SOURCES.map((innerSource) => ({
|
|
3576
|
+
title: MIGRATION_SOURCE_NAMES[innerSource],
|
|
3577
|
+
value: innerSource
|
|
3578
|
+
}))
|
|
3579
|
+
});
|
|
3580
|
+
if (!source) exitWithMessage();
|
|
3581
|
+
migrationSource = source;
|
|
3582
|
+
}
|
|
3583
|
+
if (!MIGRATION_SOURCES.includes(migrationSource)) {
|
|
3584
|
+
logger.error(`Unknown migration source: ${migrationSource}`);
|
|
3585
|
+
logger.log(
|
|
3586
|
+
`Available sources: ${MIGRATION_SOURCES.map((innerSource) => highlighter.info(innerSource)).join(", ")}`
|
|
3587
|
+
);
|
|
3588
|
+
logger.break();
|
|
3589
|
+
process.exit(1);
|
|
3590
|
+
}
|
|
3591
|
+
logger.break();
|
|
3592
|
+
logger.log(
|
|
3593
|
+
`Migrating from ${highlighter.info(MIGRATION_SOURCE_NAMES[migrationSource])} to ${highlighter.info("React Grab")}...`
|
|
3594
|
+
);
|
|
3595
|
+
logger.break();
|
|
3596
|
+
const preflightSpinner = spinner("Preflight checks.").start();
|
|
3597
|
+
const projectInfo = await detectProject(cwd);
|
|
3598
|
+
preflightSpinner.succeed();
|
|
3599
|
+
if (projectInfo.framework === "unknown") {
|
|
3600
|
+
logger.break();
|
|
3601
|
+
logger.error("Could not detect a supported framework.");
|
|
3602
|
+
logger.log(
|
|
3603
|
+
"React Grab supports Next.js, Vite, TanStack Start, and Webpack projects."
|
|
3604
|
+
);
|
|
3605
|
+
logger.log(`Visit ${highlighter.info(DOCS_URL2)} for manual setup.`);
|
|
3606
|
+
logger.break();
|
|
3607
|
+
process.exit(1);
|
|
3608
|
+
}
|
|
3609
|
+
const frameworkSpinner = spinner("Verifying framework.").start();
|
|
3610
|
+
frameworkSpinner.succeed(
|
|
3611
|
+
`Verifying framework. Found ${highlighter.info(FRAMEWORK_NAMES2[projectInfo.framework])}.`
|
|
3612
|
+
);
|
|
3613
|
+
if (projectInfo.framework === "next") {
|
|
3614
|
+
const routerSpinner = spinner("Detecting router type.").start();
|
|
3615
|
+
routerSpinner.succeed(
|
|
3616
|
+
`Detecting router type. Found ${highlighter.info(projectInfo.nextRouterType === "app" ? "App Router" : "Pages Router")}.`
|
|
3617
|
+
);
|
|
3618
|
+
}
|
|
3619
|
+
const sourceSpinner = spinner(
|
|
3620
|
+
`Checking for ${MIGRATION_SOURCE_NAMES[migrationSource]}.`
|
|
3621
|
+
).start();
|
|
3622
|
+
const reactScanInfo = detectReactScan(cwd);
|
|
3623
|
+
const sourceName = MIGRATION_SOURCE_NAMES[migrationSource];
|
|
3624
|
+
if (!reactScanInfo.hasReactScan) {
|
|
3625
|
+
sourceSpinner.fail(`${sourceName} is not installed in this project.`);
|
|
3626
|
+
exitWithMessage(
|
|
3627
|
+
`Use ${highlighter.info("npx grab init")} to install React Grab directly.`
|
|
3628
|
+
);
|
|
3629
|
+
}
|
|
3630
|
+
sourceSpinner.succeed(
|
|
3631
|
+
`Checking for ${sourceName}. Found ${highlighter.info(reactScanInfo.isPackageInstalled ? "npm package" : "script reference")}.`
|
|
3632
|
+
);
|
|
3633
|
+
if (reactScanInfo.hasReactScanMonitoring) {
|
|
3634
|
+
logger.break();
|
|
3635
|
+
logger.warn(
|
|
3636
|
+
`${sourceName} Monitoring (@react-scan/monitoring) detected.`
|
|
3637
|
+
);
|
|
3638
|
+
logger.warn(
|
|
3639
|
+
"Monitoring features are not available in React Grab. You may need to remove it manually."
|
|
3640
|
+
);
|
|
3641
|
+
}
|
|
3642
|
+
if (projectInfo.hasReactGrab) {
|
|
3643
|
+
logger.break();
|
|
3644
|
+
logger.success("React Grab is already installed.");
|
|
3645
|
+
logger.log(
|
|
3646
|
+
`This migration will only remove ${sourceName} from your project.`
|
|
3647
|
+
);
|
|
3648
|
+
logger.break();
|
|
3649
|
+
const removalResult2 = previewReactScanRemoval(
|
|
3650
|
+
projectInfo.projectRoot,
|
|
3651
|
+
projectInfo.framework,
|
|
3652
|
+
projectInfo.nextRouterType
|
|
3653
|
+
);
|
|
3654
|
+
if (removalResult2.noChanges) {
|
|
3655
|
+
logger.log(`No ${sourceName} code found in configuration files.`);
|
|
3656
|
+
logger.break();
|
|
3657
|
+
if (reactScanInfo.isPackageInstalled) {
|
|
3658
|
+
if (reactScanInfo.detectedFiles.length > 0) {
|
|
3659
|
+
logger.warn(
|
|
3660
|
+
`${sourceName} was detected in files that cannot be automatically cleaned:`
|
|
3661
|
+
);
|
|
3662
|
+
for (const file of reactScanInfo.detectedFiles) {
|
|
3663
|
+
logger.log(` - ${file}`);
|
|
3664
|
+
}
|
|
3665
|
+
logger.warn(
|
|
3666
|
+
"Please remove React Scan references manually before uninstalling the package."
|
|
3667
|
+
);
|
|
3668
|
+
logger.break();
|
|
3669
|
+
process.exit(1);
|
|
3670
|
+
}
|
|
3671
|
+
await confirmOrExit(
|
|
3672
|
+
`Uninstall ${migrationSource} package?`,
|
|
3673
|
+
isNonInteractive
|
|
3674
|
+
);
|
|
3675
|
+
uninstallPackagesWithFeedback(
|
|
3676
|
+
[migrationSource],
|
|
3677
|
+
projectInfo.packageManager,
|
|
3678
|
+
projectInfo.projectRoot
|
|
3679
|
+
);
|
|
3680
|
+
logger.break();
|
|
3681
|
+
logger.success(`${sourceName} has been removed.`);
|
|
3682
|
+
}
|
|
3683
|
+
exitWithMessage();
|
|
3684
|
+
}
|
|
3685
|
+
if (hasTransformChanges(removalResult2)) {
|
|
3686
|
+
logger.break();
|
|
3687
|
+
printDiff(
|
|
3688
|
+
removalResult2.filePath,
|
|
3689
|
+
removalResult2.originalContent,
|
|
3690
|
+
removalResult2.newContent
|
|
3691
|
+
);
|
|
3692
|
+
logger.break();
|
|
3693
|
+
await confirmOrExit("Apply these changes?", isNonInteractive);
|
|
3694
|
+
applyTransformWithFeedback(
|
|
3695
|
+
removalResult2,
|
|
3696
|
+
`Removing ${sourceName} from ${removalResult2.filePath}.`
|
|
3697
|
+
);
|
|
3698
|
+
if (reactScanInfo.isPackageInstalled) {
|
|
3699
|
+
uninstallPackagesWithFeedback(
|
|
3700
|
+
[migrationSource],
|
|
3701
|
+
projectInfo.packageManager,
|
|
3702
|
+
projectInfo.projectRoot
|
|
3703
|
+
);
|
|
3704
|
+
}
|
|
3705
|
+
logger.break();
|
|
3706
|
+
logger.success(`Migration complete! ${sourceName} has been removed.`);
|
|
3707
|
+
}
|
|
3708
|
+
exitWithMessage();
|
|
3709
|
+
}
|
|
3710
|
+
const removalResult = previewReactScanRemoval(
|
|
3711
|
+
projectInfo.projectRoot,
|
|
3712
|
+
projectInfo.framework,
|
|
3713
|
+
projectInfo.nextRouterType
|
|
3714
|
+
);
|
|
3715
|
+
const addResult = previewTransform(
|
|
3716
|
+
projectInfo.projectRoot,
|
|
3717
|
+
projectInfo.framework,
|
|
3718
|
+
projectInfo.nextRouterType,
|
|
3719
|
+
"none",
|
|
3720
|
+
false
|
|
3721
|
+
);
|
|
3722
|
+
const hasRemovalChanges = hasTransformChanges(removalResult);
|
|
3723
|
+
const hasAddChanges = hasTransformChanges(addResult);
|
|
3724
|
+
if (!hasRemovalChanges && !hasAddChanges) {
|
|
3725
|
+
exitWithMessage("No changes needed.");
|
|
3726
|
+
}
|
|
3727
|
+
logger.break();
|
|
3728
|
+
logger.log("Migration will perform the following changes:");
|
|
3729
|
+
logger.break();
|
|
3730
|
+
if (hasRemovalChanges) {
|
|
3731
|
+
logger.log(
|
|
3732
|
+
` ${pc5__default.default.red("\u2212")} Remove ${sourceName} from ${removalResult.filePath}`
|
|
3733
|
+
);
|
|
3734
|
+
}
|
|
3735
|
+
if (reactScanInfo.isPackageInstalled) {
|
|
3736
|
+
logger.log(` ${pc5__default.default.red("\u2212")} Uninstall ${migrationSource} package`);
|
|
3737
|
+
}
|
|
3738
|
+
logger.log(` ${pc5__default.default.green("+")} Install react-grab package`);
|
|
3739
|
+
if (hasAddChanges) {
|
|
3740
|
+
logger.log(
|
|
3741
|
+
` ${pc5__default.default.green("+")} Add React Grab to ${addResult.filePath}`
|
|
3742
|
+
);
|
|
3743
|
+
}
|
|
3744
|
+
if (hasRemovalChanges && hasAddChanges && removalResult.filePath === addResult.filePath) {
|
|
3745
|
+
const combinedOriginal = removalResult.originalContent;
|
|
3746
|
+
const combinedNew = addResult.newContent;
|
|
3747
|
+
logger.break();
|
|
3748
|
+
printDiff(removalResult.filePath, combinedOriginal, combinedNew);
|
|
3749
|
+
} else {
|
|
3750
|
+
if (hasRemovalChanges) {
|
|
3751
|
+
logger.break();
|
|
3752
|
+
printDiff(
|
|
3753
|
+
removalResult.filePath,
|
|
3754
|
+
removalResult.originalContent,
|
|
3755
|
+
removalResult.newContent
|
|
3756
|
+
);
|
|
3757
|
+
}
|
|
3758
|
+
if (hasAddChanges) {
|
|
3759
|
+
logger.break();
|
|
3760
|
+
printDiff(
|
|
3761
|
+
addResult.filePath,
|
|
3762
|
+
addResult.originalContent,
|
|
3763
|
+
addResult.newContent
|
|
3764
|
+
);
|
|
3765
|
+
}
|
|
3766
|
+
}
|
|
3767
|
+
logger.break();
|
|
3768
|
+
logger.warn("Auto-detection may not be 100% accurate.");
|
|
3769
|
+
logger.warn("Please verify the changes before committing.");
|
|
3770
|
+
logger.break();
|
|
3771
|
+
await confirmOrExit("Apply these changes?", isNonInteractive);
|
|
3772
|
+
if (reactScanInfo.isPackageInstalled && (hasRemovalChanges || reactScanInfo.detectedFiles.length === 0)) {
|
|
3773
|
+
uninstallPackagesWithFeedback(
|
|
3774
|
+
[migrationSource],
|
|
3775
|
+
projectInfo.packageManager,
|
|
3776
|
+
projectInfo.projectRoot
|
|
3777
|
+
);
|
|
3778
|
+
}
|
|
3779
|
+
installPackagesWithFeedback(
|
|
3780
|
+
getPackagesToInstall("none", true),
|
|
3781
|
+
projectInfo.packageManager,
|
|
3782
|
+
projectInfo.projectRoot
|
|
3783
|
+
);
|
|
3784
|
+
if (hasRemovalChanges) {
|
|
3785
|
+
applyTransformWithFeedback(
|
|
3786
|
+
removalResult,
|
|
3787
|
+
`Removing ${sourceName} from ${removalResult.filePath}.`
|
|
3788
|
+
);
|
|
3789
|
+
}
|
|
3790
|
+
if (hasAddChanges) {
|
|
3791
|
+
applyTransformWithFeedback(
|
|
3792
|
+
addResult,
|
|
3793
|
+
`Adding React Grab to ${addResult.filePath}.`
|
|
3794
|
+
);
|
|
3795
|
+
}
|
|
3796
|
+
logger.break();
|
|
3797
|
+
logger.log(`${highlighter.success("Success!")} Migration complete.`);
|
|
3798
|
+
logger.log("You may now start your development server.");
|
|
3799
|
+
logger.break();
|
|
3800
|
+
} catch (error) {
|
|
3801
|
+
handleError(error);
|
|
3802
|
+
}
|
|
3803
|
+
});
|
|
3804
|
+
var VERSION5 = "0.1.1";
|
|
3329
3805
|
var remove = new commander.Command().name("remove").description("remove an agent integration").argument(
|
|
3330
3806
|
"[agent]",
|
|
3331
3807
|
"agent to remove (claude-code, cursor, opencode, codex, gemini, amp, ami)"
|
|
@@ -3335,7 +3811,7 @@ var remove = new commander.Command().name("remove").description("remove an agent
|
|
|
3335
3811
|
process.cwd()
|
|
3336
3812
|
).action(async (agentArg, opts) => {
|
|
3337
3813
|
console.log(
|
|
3338
|
-
`${
|
|
3814
|
+
`${pc5__default.default.magenta("\u273F")} ${pc5__default.default.bold("React Grab")} ${pc5__default.default.gray(VERSION5)}`
|
|
3339
3815
|
);
|
|
3340
3816
|
console.log();
|
|
3341
3817
|
try {
|
|
@@ -3504,7 +3980,7 @@ var remove = new commander.Command().name("remove").description("remove an agent
|
|
|
3504
3980
|
});
|
|
3505
3981
|
|
|
3506
3982
|
// src/cli.ts
|
|
3507
|
-
var
|
|
3983
|
+
var VERSION6 = "0.1.1";
|
|
3508
3984
|
var VERSION_API_URL = "https://www.react-grab.com/api/version";
|
|
3509
3985
|
process.on("SIGINT", () => process.exit(0));
|
|
3510
3986
|
process.on("SIGTERM", () => process.exit(0));
|
|
@@ -3513,11 +3989,12 @@ try {
|
|
|
3513
3989
|
});
|
|
3514
3990
|
} catch {
|
|
3515
3991
|
}
|
|
3516
|
-
var program = new commander.Command().name("grab").description("add React Grab to your project").version(
|
|
3992
|
+
var program = new commander.Command().name("grab").description("add React Grab to your project").version(VERSION6, "-v, --version", "display the version number");
|
|
3517
3993
|
program.addCommand(init);
|
|
3518
3994
|
program.addCommand(add);
|
|
3519
3995
|
program.addCommand(remove);
|
|
3520
3996
|
program.addCommand(configure);
|
|
3997
|
+
program.addCommand(migrate);
|
|
3521
3998
|
var main = async () => {
|
|
3522
3999
|
await program.parseAsync();
|
|
3523
4000
|
};
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
-
import
|
|
3
|
+
import pc5 from 'picocolors';
|
|
4
4
|
import prompts3 from 'prompts';
|
|
5
5
|
import { execSync } from 'child_process';
|
|
6
6
|
import { readFileSync, existsSync, writeFileSync, accessSync, constants, readdirSync } from 'fs';
|
|
@@ -253,6 +253,85 @@ var AGENT_PACKAGES = [
|
|
|
253
253
|
"@react-grab/amp",
|
|
254
254
|
"@react-grab/ami"
|
|
255
255
|
];
|
|
256
|
+
var REACT_SCAN_DETECTION_PATTERNS = [
|
|
257
|
+
/["'`][^"'`]*react-scan/,
|
|
258
|
+
/react-scan[^"'`]*["'`]/,
|
|
259
|
+
/unpkg\.com\/react-scan/,
|
|
260
|
+
/import\s*\(?["']react-scan/,
|
|
261
|
+
/require\s*\(["']react-scan/,
|
|
262
|
+
/from\s+["']react-scan/,
|
|
263
|
+
/<Script[^>]*react-scan/i,
|
|
264
|
+
/<script[^>]*react-scan/i
|
|
265
|
+
];
|
|
266
|
+
var REACT_SCAN_FILE_PATTERNS = [
|
|
267
|
+
["app", "layout"],
|
|
268
|
+
["src", "app", "layout"],
|
|
269
|
+
["pages", "_document"],
|
|
270
|
+
["pages", "_app"],
|
|
271
|
+
["src", "pages", "_document"],
|
|
272
|
+
["src", "pages", "_app"],
|
|
273
|
+
["index"],
|
|
274
|
+
["public", "index"],
|
|
275
|
+
["src", "index"],
|
|
276
|
+
["src", "main"],
|
|
277
|
+
["src", "routes", "__root"],
|
|
278
|
+
["app", "routes", "__root"]
|
|
279
|
+
];
|
|
280
|
+
var SCRIPT_EXTENSIONS = ["tsx", "jsx", "ts", "js"];
|
|
281
|
+
var getReactScanFilesToCheck = (projectRoot) => REACT_SCAN_FILE_PATTERNS.flatMap((segments) => {
|
|
282
|
+
const baseName = segments[segments.length - 1];
|
|
283
|
+
const isHtmlFile = baseName === "index" && segments.length <= 2;
|
|
284
|
+
const extensions = isHtmlFile ? [...SCRIPT_EXTENSIONS, "html"] : SCRIPT_EXTENSIONS;
|
|
285
|
+
return extensions.map(
|
|
286
|
+
(extension) => join(projectRoot, ...segments) + `.${extension}`
|
|
287
|
+
);
|
|
288
|
+
});
|
|
289
|
+
var hasReactScanInFile = (filePath) => {
|
|
290
|
+
if (!existsSync(filePath)) return false;
|
|
291
|
+
try {
|
|
292
|
+
const content = readFileSync(filePath, "utf-8");
|
|
293
|
+
return REACT_SCAN_DETECTION_PATTERNS.some(
|
|
294
|
+
(pattern) => pattern.test(content)
|
|
295
|
+
);
|
|
296
|
+
} catch {
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
var detectReactScan = (projectRoot) => {
|
|
301
|
+
const result = {
|
|
302
|
+
hasReactScan: false,
|
|
303
|
+
hasReactScanMonitoring: false,
|
|
304
|
+
isPackageInstalled: false,
|
|
305
|
+
detectedFiles: []
|
|
306
|
+
};
|
|
307
|
+
const packageJsonPath = join(projectRoot, "package.json");
|
|
308
|
+
if (existsSync(packageJsonPath)) {
|
|
309
|
+
try {
|
|
310
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
311
|
+
const allDependencies = {
|
|
312
|
+
...packageJson.dependencies,
|
|
313
|
+
...packageJson.devDependencies
|
|
314
|
+
};
|
|
315
|
+
if (allDependencies["react-scan"]) {
|
|
316
|
+
result.isPackageInstalled = true;
|
|
317
|
+
result.hasReactScan = true;
|
|
318
|
+
}
|
|
319
|
+
if (allDependencies["@react-scan/monitoring"]) {
|
|
320
|
+
result.hasReactScanMonitoring = true;
|
|
321
|
+
result.hasReactScan = true;
|
|
322
|
+
}
|
|
323
|
+
} catch {
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
const filesToCheck = getReactScanFilesToCheck(projectRoot);
|
|
327
|
+
for (const filePath of filesToCheck) {
|
|
328
|
+
if (hasReactScanInFile(filePath)) {
|
|
329
|
+
result.hasReactScan = true;
|
|
330
|
+
result.detectedFiles.push(filePath);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return result;
|
|
334
|
+
};
|
|
256
335
|
var detectUnsupportedFramework = (projectRoot) => {
|
|
257
336
|
const packageJsonPath = join(projectRoot, "package.json");
|
|
258
337
|
if (!existsSync(packageJsonPath)) {
|
|
@@ -414,11 +493,11 @@ ${BOLD}File: ${filePath}${RESET}`);
|
|
|
414
493
|
console.log("\u2500".repeat(60));
|
|
415
494
|
};
|
|
416
495
|
var highlighter = {
|
|
417
|
-
error:
|
|
418
|
-
warn:
|
|
419
|
-
info:
|
|
420
|
-
success:
|
|
421
|
-
dim:
|
|
496
|
+
error: pc5.red,
|
|
497
|
+
warn: pc5.yellow,
|
|
498
|
+
info: pc5.cyan,
|
|
499
|
+
success: pc5.green,
|
|
500
|
+
dim: pc5.dim
|
|
422
501
|
};
|
|
423
502
|
|
|
424
503
|
// src/utils/logger.ts
|
|
@@ -1812,9 +1891,120 @@ var previewPackageJsonAgentRemoval = (projectRoot, agent) => {
|
|
|
1812
1891
|
};
|
|
1813
1892
|
}
|
|
1814
1893
|
};
|
|
1894
|
+
var hasReactScanCode = (content) => REACT_SCAN_DETECTION_PATTERNS.some((pattern) => pattern.test(content));
|
|
1895
|
+
var createRemovalTransform = (removalPatterns) => {
|
|
1896
|
+
return (originalContent, filePath) => {
|
|
1897
|
+
if (!hasReactScanCode(originalContent)) {
|
|
1898
|
+
return {
|
|
1899
|
+
success: true,
|
|
1900
|
+
filePath,
|
|
1901
|
+
message: "React Scan is not configured in this file",
|
|
1902
|
+
noChanges: true
|
|
1903
|
+
};
|
|
1904
|
+
}
|
|
1905
|
+
let newContent = originalContent;
|
|
1906
|
+
for (const pattern of removalPatterns) {
|
|
1907
|
+
newContent = newContent.replace(pattern, "");
|
|
1908
|
+
}
|
|
1909
|
+
if (newContent === originalContent) {
|
|
1910
|
+
return {
|
|
1911
|
+
success: true,
|
|
1912
|
+
filePath,
|
|
1913
|
+
message: "Could not remove React Scan code",
|
|
1914
|
+
noChanges: true
|
|
1915
|
+
};
|
|
1916
|
+
}
|
|
1917
|
+
return {
|
|
1918
|
+
success: true,
|
|
1919
|
+
filePath,
|
|
1920
|
+
message: "Remove React Scan",
|
|
1921
|
+
originalContent,
|
|
1922
|
+
newContent
|
|
1923
|
+
};
|
|
1924
|
+
};
|
|
1925
|
+
};
|
|
1926
|
+
var NEXT_APP_REMOVAL_PATTERNS = [
|
|
1927
|
+
/\s*\{process\.env\.NODE_ENV\s*===\s*["']development["']\s*&&\s*\(\s*<Script[^>]*react-scan[^>]*\/>\s*\)\}/gs,
|
|
1928
|
+
/\s*<Script[^>]*react-scan[^>]*\/>/gi,
|
|
1929
|
+
/\s*<script[^>]*>\s*(?:if\s*\([^)]*\)\s*\{)?\s*import\s*\(\s*["']react-scan["']\s*\)[^<]*<\/script>/gi,
|
|
1930
|
+
/\s*<script[^>]*react-scan[^>]*>[^<]*<\/script>/gi,
|
|
1931
|
+
/\s*<script[^>]*react-scan[^>]*\/>/gi
|
|
1932
|
+
];
|
|
1933
|
+
var VITE_REMOVAL_PATTERNS = [
|
|
1934
|
+
/\s*import\s*\(\s*["']react-scan["']\s*\)\s*\.then\s*\([^)]*\)[^;]*;?/g,
|
|
1935
|
+
/\s*import\s*\(\s*["']react-scan["']\s*\);?/g,
|
|
1936
|
+
/^\s*import\s+(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s+from\s+["']react-scan["'];?\s*$/gm,
|
|
1937
|
+
/<script[^>]*type="module"[^>]*>\s*if\s*\(\s*import\.meta\.env\.DEV\s*\)\s*\{\s*\}\s*<\/script>/gi
|
|
1938
|
+
];
|
|
1939
|
+
var WEBPACK_REMOVAL_PATTERNS = [
|
|
1940
|
+
/\s*import\s*\(\s*["']react-scan["']\s*\)\s*\.then\s*\([^)]*\)[^;]*;?/g,
|
|
1941
|
+
/\s*import\s*\(\s*["']react-scan["']\s*\);?/g,
|
|
1942
|
+
/^\s*import\s+(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s+from\s+["']react-scan["'];?\s*$/gm,
|
|
1943
|
+
/if\s*\(\s*process\.env\.NODE_ENV\s*===\s*["']development["']\s*\)\s*\{\s*\}/g
|
|
1944
|
+
];
|
|
1945
|
+
var TANSTACK_REMOVAL_PATTERNS = [
|
|
1946
|
+
/\s*void\s+import\s*\(\s*["']react-scan["']\s*\);?/g,
|
|
1947
|
+
/\s*import\s*\(\s*["']react-scan["']\s*\);?/g,
|
|
1948
|
+
/^\s*import\s+(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s+from\s+["']react-scan["'];?\s*$/gm
|
|
1949
|
+
];
|
|
1950
|
+
var removeReactScanFromNextApp = createRemovalTransform(
|
|
1951
|
+
NEXT_APP_REMOVAL_PATTERNS
|
|
1952
|
+
);
|
|
1953
|
+
var removeReactScanFromVite = createRemovalTransform(VITE_REMOVAL_PATTERNS);
|
|
1954
|
+
var removeReactScanFromWebpack = createRemovalTransform(
|
|
1955
|
+
WEBPACK_REMOVAL_PATTERNS
|
|
1956
|
+
);
|
|
1957
|
+
var removeReactScanFromTanStack = createRemovalTransform(
|
|
1958
|
+
TANSTACK_REMOVAL_PATTERNS
|
|
1959
|
+
);
|
|
1960
|
+
var findReactScanFile = (projectRoot, framework, nextRouterType) => {
|
|
1961
|
+
switch (framework) {
|
|
1962
|
+
case "next":
|
|
1963
|
+
if (nextRouterType === "app") {
|
|
1964
|
+
return findLayoutFile(projectRoot);
|
|
1965
|
+
}
|
|
1966
|
+
return findDocumentFile(projectRoot);
|
|
1967
|
+
case "vite":
|
|
1968
|
+
return findIndexHtml(projectRoot);
|
|
1969
|
+
case "tanstack":
|
|
1970
|
+
return findTanStackRootFile(projectRoot);
|
|
1971
|
+
case "webpack":
|
|
1972
|
+
return findEntryFile(projectRoot);
|
|
1973
|
+
default:
|
|
1974
|
+
return null;
|
|
1975
|
+
}
|
|
1976
|
+
};
|
|
1977
|
+
var previewReactScanRemoval = (projectRoot, framework, nextRouterType) => {
|
|
1978
|
+
const filePath = findReactScanFile(projectRoot, framework, nextRouterType);
|
|
1979
|
+
if (!filePath) {
|
|
1980
|
+
return {
|
|
1981
|
+
success: true,
|
|
1982
|
+
filePath: "",
|
|
1983
|
+
message: "Could not find file containing React Scan configuration",
|
|
1984
|
+
noChanges: true
|
|
1985
|
+
};
|
|
1986
|
+
}
|
|
1987
|
+
const originalContent = readFileSync(filePath, "utf-8");
|
|
1988
|
+
switch (framework) {
|
|
1989
|
+
case "next":
|
|
1990
|
+
return removeReactScanFromNextApp(originalContent, filePath);
|
|
1991
|
+
case "vite":
|
|
1992
|
+
return removeReactScanFromVite(originalContent, filePath);
|
|
1993
|
+
case "tanstack":
|
|
1994
|
+
return removeReactScanFromTanStack(originalContent, filePath);
|
|
1995
|
+
case "webpack":
|
|
1996
|
+
return removeReactScanFromWebpack(originalContent, filePath);
|
|
1997
|
+
default:
|
|
1998
|
+
return {
|
|
1999
|
+
success: false,
|
|
2000
|
+
filePath,
|
|
2001
|
+
message: `Unknown framework: ${framework}`
|
|
2002
|
+
};
|
|
2003
|
+
}
|
|
2004
|
+
};
|
|
1815
2005
|
|
|
1816
2006
|
// src/commands/add.ts
|
|
1817
|
-
var VERSION = "0.1.
|
|
2007
|
+
var VERSION = "0.1.1";
|
|
1818
2008
|
var formatInstalledAgentNames = (agents) => agents.map((agent) => AGENT_NAMES[agent] || agent).join(", ");
|
|
1819
2009
|
var add = new Command().name("add").alias("install").description("add an agent integration").argument("[agent]", `agent to add (${AGENTS.join(", ")})`).option("-y, --yes", "skip confirmation prompts", false).option(
|
|
1820
2010
|
"-c, --cwd <cwd>",
|
|
@@ -1822,7 +2012,7 @@ var add = new Command().name("add").alias("install").description("add an agent i
|
|
|
1822
2012
|
process.cwd()
|
|
1823
2013
|
).action(async (agentArg, opts) => {
|
|
1824
2014
|
console.log(
|
|
1825
|
-
`${
|
|
2015
|
+
`${pc5.magenta("\u273F")} ${pc5.bold("React Grab")} ${pc5.gray(VERSION)}`
|
|
1826
2016
|
);
|
|
1827
2017
|
console.log();
|
|
1828
2018
|
try {
|
|
@@ -2150,7 +2340,7 @@ var MAX_KEY_HOLD_DURATION_MS = 2e3;
|
|
|
2150
2340
|
var MAX_CONTEXT_LINES = 50;
|
|
2151
2341
|
|
|
2152
2342
|
// src/commands/configure.ts
|
|
2153
|
-
var VERSION2 = "0.1.
|
|
2343
|
+
var VERSION2 = "0.1.1";
|
|
2154
2344
|
var isMac = process.platform === "darwin";
|
|
2155
2345
|
var META_LABEL = isMac ? "Cmd" : "Win";
|
|
2156
2346
|
var ALT_LABEL = isMac ? "Option" : "Alt";
|
|
@@ -2360,7 +2550,7 @@ var configure = new Command().name("configure").alias("config").description("con
|
|
|
2360
2550
|
process.cwd()
|
|
2361
2551
|
).action(async (opts) => {
|
|
2362
2552
|
console.log(
|
|
2363
|
-
`${
|
|
2553
|
+
`${pc5.magenta("\u273F")} ${pc5.bold("React Grab")} ${pc5.gray(VERSION2)}`
|
|
2364
2554
|
);
|
|
2365
2555
|
console.log();
|
|
2366
2556
|
try {
|
|
@@ -2547,7 +2737,7 @@ var configure = new Command().name("configure").alias("config").description("con
|
|
|
2547
2737
|
`Add this to your ${highlighter.info("init()")} call or ${highlighter.info("data-options")} attribute:`
|
|
2548
2738
|
);
|
|
2549
2739
|
logger.break();
|
|
2550
|
-
console.log(` ${
|
|
2740
|
+
console.log(` ${pc5.cyan(configJson)}`);
|
|
2551
2741
|
logger.break();
|
|
2552
2742
|
process.exit(1);
|
|
2553
2743
|
}
|
|
@@ -2650,7 +2840,7 @@ var uninstallPackagesWithFeedback = (packages, packageManager, projectRoot) => {
|
|
|
2650
2840
|
};
|
|
2651
2841
|
|
|
2652
2842
|
// src/commands/init.ts
|
|
2653
|
-
var VERSION3 = "0.1.
|
|
2843
|
+
var VERSION3 = "0.1.1";
|
|
2654
2844
|
var REPORT_URL = "https://react-grab.com/api/report-cli";
|
|
2655
2845
|
var DOCS_URL = "https://github.com/aidenybai/react-grab";
|
|
2656
2846
|
var reportToCli = (type, config, error) => {
|
|
@@ -2716,7 +2906,7 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
2716
2906
|
process.cwd()
|
|
2717
2907
|
).action(async (opts) => {
|
|
2718
2908
|
console.log(
|
|
2719
|
-
`${
|
|
2909
|
+
`${pc5.magenta("\u273F")} ${pc5.bold("React Grab")} ${pc5.gray(VERSION3)}`
|
|
2720
2910
|
);
|
|
2721
2911
|
console.log();
|
|
2722
2912
|
try {
|
|
@@ -3317,7 +3507,293 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
3317
3507
|
reportToCli("error", void 0, error);
|
|
3318
3508
|
}
|
|
3319
3509
|
});
|
|
3320
|
-
var VERSION4 = "0.1.
|
|
3510
|
+
var VERSION4 = "0.1.1";
|
|
3511
|
+
var DOCS_URL2 = "https://github.com/aidenybai/react-grab";
|
|
3512
|
+
var exitWithMessage = (message, code = 0) => {
|
|
3513
|
+
if (message) logger.log(message);
|
|
3514
|
+
logger.break();
|
|
3515
|
+
process.exit(code);
|
|
3516
|
+
};
|
|
3517
|
+
var confirmOrExit = async (message, isNonInteractive) => {
|
|
3518
|
+
if (isNonInteractive) return;
|
|
3519
|
+
const { proceed } = await prompts3({
|
|
3520
|
+
type: "confirm",
|
|
3521
|
+
name: "proceed",
|
|
3522
|
+
message,
|
|
3523
|
+
initial: true
|
|
3524
|
+
});
|
|
3525
|
+
if (!proceed) exitWithMessage("Migration cancelled.");
|
|
3526
|
+
};
|
|
3527
|
+
var hasTransformChanges = (result) => result.success && !result.noChanges && Boolean(result.originalContent) && Boolean(result.newContent);
|
|
3528
|
+
var MIGRATION_SOURCES = ["react-scan"];
|
|
3529
|
+
var MIGRATION_SOURCE_NAMES = {
|
|
3530
|
+
"react-scan": "React Scan"
|
|
3531
|
+
};
|
|
3532
|
+
var FRAMEWORK_NAMES2 = {
|
|
3533
|
+
next: "Next.js",
|
|
3534
|
+
vite: "Vite",
|
|
3535
|
+
tanstack: "TanStack Start",
|
|
3536
|
+
webpack: "Webpack",
|
|
3537
|
+
unknown: "Unknown"
|
|
3538
|
+
};
|
|
3539
|
+
var migrate = new Command().name("migrate").description("migrate to React Grab from another tool").option("-y, --yes", "skip confirmation prompts", false).option("-f, --from <source>", "migration source (react-scan)").option(
|
|
3540
|
+
"-c, --cwd <cwd>",
|
|
3541
|
+
"working directory (defaults to current directory)",
|
|
3542
|
+
process.cwd()
|
|
3543
|
+
).action(async (opts) => {
|
|
3544
|
+
console.log(
|
|
3545
|
+
`${pc5.magenta("\u273F")} ${pc5.bold("React Grab")} ${pc5.gray(VERSION4)}`
|
|
3546
|
+
);
|
|
3547
|
+
console.log();
|
|
3548
|
+
try {
|
|
3549
|
+
const cwd = opts.cwd;
|
|
3550
|
+
const isNonInteractive = opts.yes;
|
|
3551
|
+
let migrationSource = opts.from;
|
|
3552
|
+
if (!migrationSource) {
|
|
3553
|
+
if (isNonInteractive) {
|
|
3554
|
+
logger.error(
|
|
3555
|
+
"Migration source is required in non-interactive mode. Use --from <source>"
|
|
3556
|
+
);
|
|
3557
|
+
logger.log(
|
|
3558
|
+
`Available sources: ${MIGRATION_SOURCES.map((innerSource) => highlighter.info(innerSource)).join(", ")}`
|
|
3559
|
+
);
|
|
3560
|
+
logger.break();
|
|
3561
|
+
process.exit(1);
|
|
3562
|
+
}
|
|
3563
|
+
const { source } = await prompts3({
|
|
3564
|
+
type: "select",
|
|
3565
|
+
name: "source",
|
|
3566
|
+
message: `What would you like to migrate ${highlighter.info("from")}?`,
|
|
3567
|
+
choices: MIGRATION_SOURCES.map((innerSource) => ({
|
|
3568
|
+
title: MIGRATION_SOURCE_NAMES[innerSource],
|
|
3569
|
+
value: innerSource
|
|
3570
|
+
}))
|
|
3571
|
+
});
|
|
3572
|
+
if (!source) exitWithMessage();
|
|
3573
|
+
migrationSource = source;
|
|
3574
|
+
}
|
|
3575
|
+
if (!MIGRATION_SOURCES.includes(migrationSource)) {
|
|
3576
|
+
logger.error(`Unknown migration source: ${migrationSource}`);
|
|
3577
|
+
logger.log(
|
|
3578
|
+
`Available sources: ${MIGRATION_SOURCES.map((innerSource) => highlighter.info(innerSource)).join(", ")}`
|
|
3579
|
+
);
|
|
3580
|
+
logger.break();
|
|
3581
|
+
process.exit(1);
|
|
3582
|
+
}
|
|
3583
|
+
logger.break();
|
|
3584
|
+
logger.log(
|
|
3585
|
+
`Migrating from ${highlighter.info(MIGRATION_SOURCE_NAMES[migrationSource])} to ${highlighter.info("React Grab")}...`
|
|
3586
|
+
);
|
|
3587
|
+
logger.break();
|
|
3588
|
+
const preflightSpinner = spinner("Preflight checks.").start();
|
|
3589
|
+
const projectInfo = await detectProject(cwd);
|
|
3590
|
+
preflightSpinner.succeed();
|
|
3591
|
+
if (projectInfo.framework === "unknown") {
|
|
3592
|
+
logger.break();
|
|
3593
|
+
logger.error("Could not detect a supported framework.");
|
|
3594
|
+
logger.log(
|
|
3595
|
+
"React Grab supports Next.js, Vite, TanStack Start, and Webpack projects."
|
|
3596
|
+
);
|
|
3597
|
+
logger.log(`Visit ${highlighter.info(DOCS_URL2)} for manual setup.`);
|
|
3598
|
+
logger.break();
|
|
3599
|
+
process.exit(1);
|
|
3600
|
+
}
|
|
3601
|
+
const frameworkSpinner = spinner("Verifying framework.").start();
|
|
3602
|
+
frameworkSpinner.succeed(
|
|
3603
|
+
`Verifying framework. Found ${highlighter.info(FRAMEWORK_NAMES2[projectInfo.framework])}.`
|
|
3604
|
+
);
|
|
3605
|
+
if (projectInfo.framework === "next") {
|
|
3606
|
+
const routerSpinner = spinner("Detecting router type.").start();
|
|
3607
|
+
routerSpinner.succeed(
|
|
3608
|
+
`Detecting router type. Found ${highlighter.info(projectInfo.nextRouterType === "app" ? "App Router" : "Pages Router")}.`
|
|
3609
|
+
);
|
|
3610
|
+
}
|
|
3611
|
+
const sourceSpinner = spinner(
|
|
3612
|
+
`Checking for ${MIGRATION_SOURCE_NAMES[migrationSource]}.`
|
|
3613
|
+
).start();
|
|
3614
|
+
const reactScanInfo = detectReactScan(cwd);
|
|
3615
|
+
const sourceName = MIGRATION_SOURCE_NAMES[migrationSource];
|
|
3616
|
+
if (!reactScanInfo.hasReactScan) {
|
|
3617
|
+
sourceSpinner.fail(`${sourceName} is not installed in this project.`);
|
|
3618
|
+
exitWithMessage(
|
|
3619
|
+
`Use ${highlighter.info("npx grab init")} to install React Grab directly.`
|
|
3620
|
+
);
|
|
3621
|
+
}
|
|
3622
|
+
sourceSpinner.succeed(
|
|
3623
|
+
`Checking for ${sourceName}. Found ${highlighter.info(reactScanInfo.isPackageInstalled ? "npm package" : "script reference")}.`
|
|
3624
|
+
);
|
|
3625
|
+
if (reactScanInfo.hasReactScanMonitoring) {
|
|
3626
|
+
logger.break();
|
|
3627
|
+
logger.warn(
|
|
3628
|
+
`${sourceName} Monitoring (@react-scan/monitoring) detected.`
|
|
3629
|
+
);
|
|
3630
|
+
logger.warn(
|
|
3631
|
+
"Monitoring features are not available in React Grab. You may need to remove it manually."
|
|
3632
|
+
);
|
|
3633
|
+
}
|
|
3634
|
+
if (projectInfo.hasReactGrab) {
|
|
3635
|
+
logger.break();
|
|
3636
|
+
logger.success("React Grab is already installed.");
|
|
3637
|
+
logger.log(
|
|
3638
|
+
`This migration will only remove ${sourceName} from your project.`
|
|
3639
|
+
);
|
|
3640
|
+
logger.break();
|
|
3641
|
+
const removalResult2 = previewReactScanRemoval(
|
|
3642
|
+
projectInfo.projectRoot,
|
|
3643
|
+
projectInfo.framework,
|
|
3644
|
+
projectInfo.nextRouterType
|
|
3645
|
+
);
|
|
3646
|
+
if (removalResult2.noChanges) {
|
|
3647
|
+
logger.log(`No ${sourceName} code found in configuration files.`);
|
|
3648
|
+
logger.break();
|
|
3649
|
+
if (reactScanInfo.isPackageInstalled) {
|
|
3650
|
+
if (reactScanInfo.detectedFiles.length > 0) {
|
|
3651
|
+
logger.warn(
|
|
3652
|
+
`${sourceName} was detected in files that cannot be automatically cleaned:`
|
|
3653
|
+
);
|
|
3654
|
+
for (const file of reactScanInfo.detectedFiles) {
|
|
3655
|
+
logger.log(` - ${file}`);
|
|
3656
|
+
}
|
|
3657
|
+
logger.warn(
|
|
3658
|
+
"Please remove React Scan references manually before uninstalling the package."
|
|
3659
|
+
);
|
|
3660
|
+
logger.break();
|
|
3661
|
+
process.exit(1);
|
|
3662
|
+
}
|
|
3663
|
+
await confirmOrExit(
|
|
3664
|
+
`Uninstall ${migrationSource} package?`,
|
|
3665
|
+
isNonInteractive
|
|
3666
|
+
);
|
|
3667
|
+
uninstallPackagesWithFeedback(
|
|
3668
|
+
[migrationSource],
|
|
3669
|
+
projectInfo.packageManager,
|
|
3670
|
+
projectInfo.projectRoot
|
|
3671
|
+
);
|
|
3672
|
+
logger.break();
|
|
3673
|
+
logger.success(`${sourceName} has been removed.`);
|
|
3674
|
+
}
|
|
3675
|
+
exitWithMessage();
|
|
3676
|
+
}
|
|
3677
|
+
if (hasTransformChanges(removalResult2)) {
|
|
3678
|
+
logger.break();
|
|
3679
|
+
printDiff(
|
|
3680
|
+
removalResult2.filePath,
|
|
3681
|
+
removalResult2.originalContent,
|
|
3682
|
+
removalResult2.newContent
|
|
3683
|
+
);
|
|
3684
|
+
logger.break();
|
|
3685
|
+
await confirmOrExit("Apply these changes?", isNonInteractive);
|
|
3686
|
+
applyTransformWithFeedback(
|
|
3687
|
+
removalResult2,
|
|
3688
|
+
`Removing ${sourceName} from ${removalResult2.filePath}.`
|
|
3689
|
+
);
|
|
3690
|
+
if (reactScanInfo.isPackageInstalled) {
|
|
3691
|
+
uninstallPackagesWithFeedback(
|
|
3692
|
+
[migrationSource],
|
|
3693
|
+
projectInfo.packageManager,
|
|
3694
|
+
projectInfo.projectRoot
|
|
3695
|
+
);
|
|
3696
|
+
}
|
|
3697
|
+
logger.break();
|
|
3698
|
+
logger.success(`Migration complete! ${sourceName} has been removed.`);
|
|
3699
|
+
}
|
|
3700
|
+
exitWithMessage();
|
|
3701
|
+
}
|
|
3702
|
+
const removalResult = previewReactScanRemoval(
|
|
3703
|
+
projectInfo.projectRoot,
|
|
3704
|
+
projectInfo.framework,
|
|
3705
|
+
projectInfo.nextRouterType
|
|
3706
|
+
);
|
|
3707
|
+
const addResult = previewTransform(
|
|
3708
|
+
projectInfo.projectRoot,
|
|
3709
|
+
projectInfo.framework,
|
|
3710
|
+
projectInfo.nextRouterType,
|
|
3711
|
+
"none",
|
|
3712
|
+
false
|
|
3713
|
+
);
|
|
3714
|
+
const hasRemovalChanges = hasTransformChanges(removalResult);
|
|
3715
|
+
const hasAddChanges = hasTransformChanges(addResult);
|
|
3716
|
+
if (!hasRemovalChanges && !hasAddChanges) {
|
|
3717
|
+
exitWithMessage("No changes needed.");
|
|
3718
|
+
}
|
|
3719
|
+
logger.break();
|
|
3720
|
+
logger.log("Migration will perform the following changes:");
|
|
3721
|
+
logger.break();
|
|
3722
|
+
if (hasRemovalChanges) {
|
|
3723
|
+
logger.log(
|
|
3724
|
+
` ${pc5.red("\u2212")} Remove ${sourceName} from ${removalResult.filePath}`
|
|
3725
|
+
);
|
|
3726
|
+
}
|
|
3727
|
+
if (reactScanInfo.isPackageInstalled) {
|
|
3728
|
+
logger.log(` ${pc5.red("\u2212")} Uninstall ${migrationSource} package`);
|
|
3729
|
+
}
|
|
3730
|
+
logger.log(` ${pc5.green("+")} Install react-grab package`);
|
|
3731
|
+
if (hasAddChanges) {
|
|
3732
|
+
logger.log(
|
|
3733
|
+
` ${pc5.green("+")} Add React Grab to ${addResult.filePath}`
|
|
3734
|
+
);
|
|
3735
|
+
}
|
|
3736
|
+
if (hasRemovalChanges && hasAddChanges && removalResult.filePath === addResult.filePath) {
|
|
3737
|
+
const combinedOriginal = removalResult.originalContent;
|
|
3738
|
+
const combinedNew = addResult.newContent;
|
|
3739
|
+
logger.break();
|
|
3740
|
+
printDiff(removalResult.filePath, combinedOriginal, combinedNew);
|
|
3741
|
+
} else {
|
|
3742
|
+
if (hasRemovalChanges) {
|
|
3743
|
+
logger.break();
|
|
3744
|
+
printDiff(
|
|
3745
|
+
removalResult.filePath,
|
|
3746
|
+
removalResult.originalContent,
|
|
3747
|
+
removalResult.newContent
|
|
3748
|
+
);
|
|
3749
|
+
}
|
|
3750
|
+
if (hasAddChanges) {
|
|
3751
|
+
logger.break();
|
|
3752
|
+
printDiff(
|
|
3753
|
+
addResult.filePath,
|
|
3754
|
+
addResult.originalContent,
|
|
3755
|
+
addResult.newContent
|
|
3756
|
+
);
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
logger.break();
|
|
3760
|
+
logger.warn("Auto-detection may not be 100% accurate.");
|
|
3761
|
+
logger.warn("Please verify the changes before committing.");
|
|
3762
|
+
logger.break();
|
|
3763
|
+
await confirmOrExit("Apply these changes?", isNonInteractive);
|
|
3764
|
+
if (reactScanInfo.isPackageInstalled && (hasRemovalChanges || reactScanInfo.detectedFiles.length === 0)) {
|
|
3765
|
+
uninstallPackagesWithFeedback(
|
|
3766
|
+
[migrationSource],
|
|
3767
|
+
projectInfo.packageManager,
|
|
3768
|
+
projectInfo.projectRoot
|
|
3769
|
+
);
|
|
3770
|
+
}
|
|
3771
|
+
installPackagesWithFeedback(
|
|
3772
|
+
getPackagesToInstall("none", true),
|
|
3773
|
+
projectInfo.packageManager,
|
|
3774
|
+
projectInfo.projectRoot
|
|
3775
|
+
);
|
|
3776
|
+
if (hasRemovalChanges) {
|
|
3777
|
+
applyTransformWithFeedback(
|
|
3778
|
+
removalResult,
|
|
3779
|
+
`Removing ${sourceName} from ${removalResult.filePath}.`
|
|
3780
|
+
);
|
|
3781
|
+
}
|
|
3782
|
+
if (hasAddChanges) {
|
|
3783
|
+
applyTransformWithFeedback(
|
|
3784
|
+
addResult,
|
|
3785
|
+
`Adding React Grab to ${addResult.filePath}.`
|
|
3786
|
+
);
|
|
3787
|
+
}
|
|
3788
|
+
logger.break();
|
|
3789
|
+
logger.log(`${highlighter.success("Success!")} Migration complete.`);
|
|
3790
|
+
logger.log("You may now start your development server.");
|
|
3791
|
+
logger.break();
|
|
3792
|
+
} catch (error) {
|
|
3793
|
+
handleError(error);
|
|
3794
|
+
}
|
|
3795
|
+
});
|
|
3796
|
+
var VERSION5 = "0.1.1";
|
|
3321
3797
|
var remove = new Command().name("remove").description("remove an agent integration").argument(
|
|
3322
3798
|
"[agent]",
|
|
3323
3799
|
"agent to remove (claude-code, cursor, opencode, codex, gemini, amp, ami)"
|
|
@@ -3327,7 +3803,7 @@ var remove = new Command().name("remove").description("remove an agent integrati
|
|
|
3327
3803
|
process.cwd()
|
|
3328
3804
|
).action(async (agentArg, opts) => {
|
|
3329
3805
|
console.log(
|
|
3330
|
-
`${
|
|
3806
|
+
`${pc5.magenta("\u273F")} ${pc5.bold("React Grab")} ${pc5.gray(VERSION5)}`
|
|
3331
3807
|
);
|
|
3332
3808
|
console.log();
|
|
3333
3809
|
try {
|
|
@@ -3496,7 +3972,7 @@ var remove = new Command().name("remove").description("remove an agent integrati
|
|
|
3496
3972
|
});
|
|
3497
3973
|
|
|
3498
3974
|
// src/cli.ts
|
|
3499
|
-
var
|
|
3975
|
+
var VERSION6 = "0.1.1";
|
|
3500
3976
|
var VERSION_API_URL = "https://www.react-grab.com/api/version";
|
|
3501
3977
|
process.on("SIGINT", () => process.exit(0));
|
|
3502
3978
|
process.on("SIGTERM", () => process.exit(0));
|
|
@@ -3505,11 +3981,12 @@ try {
|
|
|
3505
3981
|
});
|
|
3506
3982
|
} catch {
|
|
3507
3983
|
}
|
|
3508
|
-
var program = new Command().name("grab").description("add React Grab to your project").version(
|
|
3984
|
+
var program = new Command().name("grab").description("add React Grab to your project").version(VERSION6, "-v, --version", "display the version number");
|
|
3509
3985
|
program.addCommand(init);
|
|
3510
3986
|
program.addCommand(add);
|
|
3511
3987
|
program.addCommand(remove);
|
|
3512
3988
|
program.addCommand(configure);
|
|
3989
|
+
program.addCommand(migrate);
|
|
3513
3990
|
var main = async () => {
|
|
3514
3991
|
await program.parseAsync();
|
|
3515
3992
|
};
|