@react-grab/cli 0.1.14 → 0.1.15
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 +180 -84
- package/dist/cli.js +181 -86
- package/package.json +2 -1
package/dist/cli.cjs
CHANGED
|
@@ -8,6 +8,7 @@ var child_process = require('child_process');
|
|
|
8
8
|
var fs = require('fs');
|
|
9
9
|
var path = require('path');
|
|
10
10
|
var ni = require('@antfu/ni');
|
|
11
|
+
var ignore = require('ignore');
|
|
11
12
|
var os = require('os');
|
|
12
13
|
var process2 = require('process');
|
|
13
14
|
var ora = require('ora');
|
|
@@ -18,10 +19,20 @@ var pc__default = /*#__PURE__*/_interopDefault(pc);
|
|
|
18
19
|
var basePrompts__default = /*#__PURE__*/_interopDefault(basePrompts);
|
|
19
20
|
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
20
21
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
22
|
+
var ignore__default = /*#__PURE__*/_interopDefault(ignore);
|
|
21
23
|
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
22
24
|
var process2__default = /*#__PURE__*/_interopDefault(process2);
|
|
23
25
|
var ora__default = /*#__PURE__*/_interopDefault(ora);
|
|
24
26
|
|
|
27
|
+
// src/utils/is-non-interactive.ts
|
|
28
|
+
var NON_INTERACTIVE_ENVIRONMENT_VARIABLES = [
|
|
29
|
+
"CI",
|
|
30
|
+
"CLAUDECODE",
|
|
31
|
+
"AMI"
|
|
32
|
+
];
|
|
33
|
+
var detectNonInteractive = (yesFlag) => yesFlag || NON_INTERACTIVE_ENVIRONMENT_VARIABLES.some(
|
|
34
|
+
(variable) => process.env[variable] === "true"
|
|
35
|
+
) || !process.stdin.isTTY;
|
|
25
36
|
var highlighter = {
|
|
26
37
|
error: pc__default.default.red,
|
|
27
38
|
warn: pc__default.default.yellow,
|
|
@@ -191,18 +202,22 @@ var getWorkspacePatterns = (projectRoot) => {
|
|
|
191
202
|
return [...new Set(patterns)];
|
|
192
203
|
};
|
|
193
204
|
var expandWorkspacePattern = (projectRoot, pattern) => {
|
|
194
|
-
const
|
|
205
|
+
const isGlob = pattern.endsWith("/*");
|
|
195
206
|
const cleanPattern = pattern.replace(/\/\*$/, "");
|
|
196
207
|
const basePath = path.join(projectRoot, cleanPattern);
|
|
197
|
-
if (!fs.existsSync(basePath)) return
|
|
208
|
+
if (!fs.existsSync(basePath)) return [];
|
|
209
|
+
if (!isGlob) {
|
|
210
|
+
const hasPackageJson = fs.existsSync(path.join(basePath, "package.json"));
|
|
211
|
+
return hasPackageJson ? [basePath] : [];
|
|
212
|
+
}
|
|
213
|
+
const results = [];
|
|
198
214
|
try {
|
|
199
215
|
const entries = fs.readdirSync(basePath, { withFileTypes: true });
|
|
200
216
|
for (const entry of entries) {
|
|
201
|
-
if (entry.isDirectory())
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
217
|
+
if (!entry.isDirectory()) continue;
|
|
218
|
+
const packageJsonPath = path.join(basePath, entry.name, "package.json");
|
|
219
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
220
|
+
results.push(path.join(basePath, entry.name));
|
|
206
221
|
}
|
|
207
222
|
}
|
|
208
223
|
} catch {
|
|
@@ -224,35 +239,92 @@ var hasReactDependency = (projectPath) => {
|
|
|
224
239
|
return false;
|
|
225
240
|
}
|
|
226
241
|
};
|
|
242
|
+
var buildReactProject = (projectPath) => {
|
|
243
|
+
const framework = detectFramework(projectPath);
|
|
244
|
+
const hasReact = hasReactDependency(projectPath);
|
|
245
|
+
if (!hasReact && framework === "unknown") return null;
|
|
246
|
+
let name = path.basename(projectPath);
|
|
247
|
+
const packageJsonPath = path.join(projectPath, "package.json");
|
|
248
|
+
try {
|
|
249
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
250
|
+
name = packageJson.name || name;
|
|
251
|
+
} catch {
|
|
252
|
+
}
|
|
253
|
+
return { name, path: projectPath, framework, hasReact };
|
|
254
|
+
};
|
|
227
255
|
var findWorkspaceProjects = (projectRoot) => {
|
|
228
256
|
const patterns = getWorkspacePatterns(projectRoot);
|
|
229
257
|
const projects = [];
|
|
230
258
|
for (const pattern of patterns) {
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
259
|
+
for (const projectPath of expandWorkspacePattern(projectRoot, pattern)) {
|
|
260
|
+
const project = buildReactProject(projectPath);
|
|
261
|
+
if (project) projects.push(project);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return projects;
|
|
265
|
+
};
|
|
266
|
+
var ALWAYS_IGNORED_DIRECTORIES = [
|
|
267
|
+
"node_modules",
|
|
268
|
+
".git",
|
|
269
|
+
".next",
|
|
270
|
+
".cache",
|
|
271
|
+
".turbo",
|
|
272
|
+
"dist",
|
|
273
|
+
"build",
|
|
274
|
+
"coverage",
|
|
275
|
+
"test-results"
|
|
276
|
+
];
|
|
277
|
+
var loadGitignore = (projectRoot) => {
|
|
278
|
+
const ignorer = ignore__default.default().add(ALWAYS_IGNORED_DIRECTORIES);
|
|
279
|
+
const gitignorePath = path.join(projectRoot, ".gitignore");
|
|
280
|
+
if (fs.existsSync(gitignorePath)) {
|
|
281
|
+
try {
|
|
282
|
+
ignorer.add(fs.readFileSync(gitignorePath, "utf-8"));
|
|
283
|
+
} catch {
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return ignorer;
|
|
287
|
+
};
|
|
288
|
+
var scanDirectoryForProjects = (rootDirectory, ignorer, maxDepth, currentDepth = 0) => {
|
|
289
|
+
if (currentDepth >= maxDepth) return [];
|
|
290
|
+
if (!fs.existsSync(rootDirectory)) return [];
|
|
291
|
+
const projects = [];
|
|
292
|
+
try {
|
|
293
|
+
const entries = fs.readdirSync(rootDirectory, { withFileTypes: true });
|
|
294
|
+
for (const entry of entries) {
|
|
295
|
+
if (!entry.isDirectory()) continue;
|
|
296
|
+
if (ignorer.ignores(entry.name)) continue;
|
|
297
|
+
const entryPath = path.join(rootDirectory, entry.name);
|
|
298
|
+
const hasPackageJson = fs.existsSync(path.join(entryPath, "package.json"));
|
|
299
|
+
if (hasPackageJson) {
|
|
300
|
+
const project = buildReactProject(entryPath);
|
|
301
|
+
if (project) {
|
|
302
|
+
projects.push(project);
|
|
303
|
+
continue;
|
|
244
304
|
}
|
|
245
|
-
projects.push({
|
|
246
|
-
name,
|
|
247
|
-
path: projectPath,
|
|
248
|
-
framework,
|
|
249
|
-
hasReact
|
|
250
|
-
});
|
|
251
305
|
}
|
|
306
|
+
projects.push(
|
|
307
|
+
...scanDirectoryForProjects(
|
|
308
|
+
entryPath,
|
|
309
|
+
ignorer,
|
|
310
|
+
maxDepth,
|
|
311
|
+
currentDepth + 1
|
|
312
|
+
)
|
|
313
|
+
);
|
|
252
314
|
}
|
|
315
|
+
} catch {
|
|
316
|
+
return projects;
|
|
253
317
|
}
|
|
254
318
|
return projects;
|
|
255
319
|
};
|
|
320
|
+
var MAX_SCAN_DEPTH = 2;
|
|
321
|
+
var findReactProjects = (projectRoot) => {
|
|
322
|
+
if (detectMonorepo(projectRoot)) {
|
|
323
|
+
return findWorkspaceProjects(projectRoot);
|
|
324
|
+
}
|
|
325
|
+
const ignorer = loadGitignore(projectRoot);
|
|
326
|
+
return scanDirectoryForProjects(projectRoot, ignorer, MAX_SCAN_DEPTH);
|
|
327
|
+
};
|
|
256
328
|
var hasReactGrabInFile = (filePath) => {
|
|
257
329
|
if (!fs.existsSync(filePath)) return false;
|
|
258
330
|
try {
|
|
@@ -2194,7 +2266,7 @@ var previewCdnTransform = (projectRoot, framework, nextRouterType, targetCdnDoma
|
|
|
2194
2266
|
};
|
|
2195
2267
|
|
|
2196
2268
|
// src/commands/add.ts
|
|
2197
|
-
var VERSION = "0.1.
|
|
2269
|
+
var VERSION = "0.1.15";
|
|
2198
2270
|
var formatInstalledAgentNames = (agents) => agents.map((agent) => AGENT_NAMES[agent] || agent).join(", ");
|
|
2199
2271
|
var add = new commander.Command().name("add").alias("install").description("connect React Grab to your agent").argument("[agent]", `agent to connect (${AGENTS.join(", ")}, mcp)`).option("-y, --yes", "skip confirmation prompts", false).option(
|
|
2200
2272
|
"-c, --cwd <cwd>",
|
|
@@ -2207,7 +2279,7 @@ var add = new commander.Command().name("add").alias("install").description("conn
|
|
|
2207
2279
|
console.log();
|
|
2208
2280
|
try {
|
|
2209
2281
|
const cwd = opts.cwd;
|
|
2210
|
-
const isNonInteractive = opts.yes;
|
|
2282
|
+
const isNonInteractive = detectNonInteractive(opts.yes);
|
|
2211
2283
|
const preflightSpinner = spinner("Preflight checks.").start();
|
|
2212
2284
|
const projectInfo = await detectProject(cwd);
|
|
2213
2285
|
if (!projectInfo.hasReactGrab) {
|
|
@@ -2555,7 +2627,7 @@ var MAX_KEY_HOLD_DURATION_MS = 2e3;
|
|
|
2555
2627
|
var MAX_CONTEXT_LINES = 50;
|
|
2556
2628
|
|
|
2557
2629
|
// src/commands/configure.ts
|
|
2558
|
-
var VERSION2 = "0.1.
|
|
2630
|
+
var VERSION2 = "0.1.15";
|
|
2559
2631
|
var isMac = process.platform === "darwin";
|
|
2560
2632
|
var META_LABEL = isMac ? "Cmd" : "Win";
|
|
2561
2633
|
var ALT_LABEL = isMac ? "Option" : "Alt";
|
|
@@ -3111,7 +3183,7 @@ var uninstallPackagesWithFeedback = (packages, packageManager, projectRoot) => {
|
|
|
3111
3183
|
};
|
|
3112
3184
|
|
|
3113
3185
|
// src/commands/init.ts
|
|
3114
|
-
var VERSION3 = "0.1.
|
|
3186
|
+
var VERSION3 = "0.1.15";
|
|
3115
3187
|
var REPORT_URL = "https://react-grab.com/api/report-cli";
|
|
3116
3188
|
var DOCS_URL = "https://github.com/aidenybai/react-grab";
|
|
3117
3189
|
var reportToCli = (type, config, error) => {
|
|
@@ -3148,6 +3220,34 @@ var UNSUPPORTED_FRAMEWORK_NAMES = {
|
|
|
3148
3220
|
gatsby: "Gatsby"
|
|
3149
3221
|
};
|
|
3150
3222
|
var getAgentName = getAgentDisplayName;
|
|
3223
|
+
var sortProjectsByFramework = (projects) => [...projects].sort((projectA, projectB) => {
|
|
3224
|
+
if (projectA.framework === "unknown" && projectB.framework !== "unknown")
|
|
3225
|
+
return 1;
|
|
3226
|
+
if (projectA.framework !== "unknown" && projectB.framework === "unknown")
|
|
3227
|
+
return -1;
|
|
3228
|
+
return 0;
|
|
3229
|
+
});
|
|
3230
|
+
var printSubprojects = (searchRoot, sortedProjects) => {
|
|
3231
|
+
logger.break();
|
|
3232
|
+
logger.log("Found the following projects:");
|
|
3233
|
+
logger.break();
|
|
3234
|
+
for (const project of sortedProjects) {
|
|
3235
|
+
const frameworkLabel = project.framework !== "unknown" ? ` ${highlighter.dim(`(${FRAMEWORK_NAMES[project.framework]})`)}` : "";
|
|
3236
|
+
const relativePath = path.relative(searchRoot, project.path);
|
|
3237
|
+
logger.log(
|
|
3238
|
+
` ${highlighter.info(project.name)}${frameworkLabel} ${highlighter.dim(relativePath)}`
|
|
3239
|
+
);
|
|
3240
|
+
}
|
|
3241
|
+
logger.break();
|
|
3242
|
+
logger.log(
|
|
3243
|
+
`Re-run with ${highlighter.info("-c <path>")} to specify a project:`
|
|
3244
|
+
);
|
|
3245
|
+
logger.break();
|
|
3246
|
+
logger.log(
|
|
3247
|
+
` ${highlighter.dim("$")} npx -y grab@latest init -c ${path.relative(searchRoot, sortedProjects[0].path)}`
|
|
3248
|
+
);
|
|
3249
|
+
logger.break();
|
|
3250
|
+
};
|
|
3151
3251
|
var formatActivationKeyDisplay2 = (activationKey) => {
|
|
3152
3252
|
if (!activationKey) return "Default (Option/Alt)";
|
|
3153
3253
|
return activationKey.split("+").map((part) => {
|
|
@@ -3176,8 +3276,14 @@ var init = new commander.Command().name("init").description("initialize React Gr
|
|
|
3176
3276
|
);
|
|
3177
3277
|
console.log();
|
|
3178
3278
|
try {
|
|
3179
|
-
const cwd = opts.cwd;
|
|
3180
|
-
const isNonInteractive = opts.yes;
|
|
3279
|
+
const cwd = path.resolve(opts.cwd);
|
|
3280
|
+
const isNonInteractive = detectNonInteractive(opts.yes);
|
|
3281
|
+
if (!fs.existsSync(cwd)) {
|
|
3282
|
+
logger.break();
|
|
3283
|
+
logger.error(`Directory does not exist: ${highlighter.info(cwd)}`);
|
|
3284
|
+
logger.break();
|
|
3285
|
+
process.exit(1);
|
|
3286
|
+
}
|
|
3181
3287
|
const preflightSpinner = spinner("Preflight checks.").start();
|
|
3182
3288
|
const projectInfo = await detectProject(cwd);
|
|
3183
3289
|
const removeAgents = async (agentsToRemove2, skipInstall = false) => {
|
|
@@ -3704,58 +3810,48 @@ var init = new commander.Command().name("init").description("initialize React Gr
|
|
|
3704
3810
|
process.exit(1);
|
|
3705
3811
|
}
|
|
3706
3812
|
if (projectInfo.framework === "unknown") {
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
);
|
|
3712
|
-
|
|
3713
|
-
|
|
3813
|
+
let searchRoot = cwd;
|
|
3814
|
+
let reactProjects = findReactProjects(searchRoot);
|
|
3815
|
+
if (reactProjects.length === 0 && cwd !== process.cwd()) {
|
|
3816
|
+
searchRoot = process.cwd();
|
|
3817
|
+
reactProjects = findReactProjects(searchRoot);
|
|
3818
|
+
}
|
|
3819
|
+
if (reactProjects.length > 0) {
|
|
3820
|
+
frameworkSpinner.info(
|
|
3821
|
+
`Verifying framework. Found ${reactProjects.length} project${reactProjects.length === 1 ? "" : "s"}.`
|
|
3714
3822
|
);
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
(projectA, projectB) => {
|
|
3719
|
-
if (projectA.framework === "unknown" && projectB.framework !== "unknown")
|
|
3720
|
-
return 1;
|
|
3721
|
-
if (projectA.framework !== "unknown" && projectB.framework === "unknown")
|
|
3722
|
-
return -1;
|
|
3723
|
-
return 0;
|
|
3724
|
-
}
|
|
3725
|
-
);
|
|
3726
|
-
const { selectedProject } = await prompts({
|
|
3727
|
-
type: "select",
|
|
3728
|
-
name: "selectedProject",
|
|
3729
|
-
message: "Select a project to install React Grab:",
|
|
3730
|
-
choices: [
|
|
3731
|
-
...sortedProjects.map((project) => {
|
|
3732
|
-
const frameworkLabel = project.framework !== "unknown" ? ` ${highlighter.dim(`(${FRAMEWORK_NAMES[project.framework]})`)}` : "";
|
|
3733
|
-
return {
|
|
3734
|
-
title: `${project.name}${frameworkLabel}`,
|
|
3735
|
-
value: project.path
|
|
3736
|
-
};
|
|
3737
|
-
}),
|
|
3738
|
-
{ title: "Skip", value: "skip" }
|
|
3739
|
-
]
|
|
3740
|
-
});
|
|
3741
|
-
if (!selectedProject || selectedProject === "skip") {
|
|
3742
|
-
logger.break();
|
|
3743
|
-
process.exit(0);
|
|
3744
|
-
}
|
|
3745
|
-
process.chdir(selectedProject);
|
|
3746
|
-
const newProjectInfo = await detectProject(selectedProject);
|
|
3747
|
-
Object.assign(projectInfo, newProjectInfo);
|
|
3748
|
-
const newFrameworkSpinner = spinner("Verifying framework.").start();
|
|
3749
|
-
newFrameworkSpinner.succeed(
|
|
3750
|
-
`Verifying framework. Found ${highlighter.info(FRAMEWORK_NAMES[newProjectInfo.framework])}.`
|
|
3751
|
-
);
|
|
3752
|
-
} else {
|
|
3753
|
-
frameworkSpinner.fail("Could not detect a supported framework.");
|
|
3754
|
-
logger.break();
|
|
3755
|
-
logger.log(`Visit ${highlighter.info(DOCS_URL)} for manual setup.`);
|
|
3756
|
-
logger.break();
|
|
3823
|
+
const sortedProjects = sortProjectsByFramework(reactProjects);
|
|
3824
|
+
if (isNonInteractive) {
|
|
3825
|
+
printSubprojects(searchRoot, sortedProjects);
|
|
3757
3826
|
process.exit(1);
|
|
3758
3827
|
}
|
|
3828
|
+
logger.break();
|
|
3829
|
+
const { selectedProject } = await prompts({
|
|
3830
|
+
type: "select",
|
|
3831
|
+
name: "selectedProject",
|
|
3832
|
+
message: "Select a project to install React Grab:",
|
|
3833
|
+
choices: [
|
|
3834
|
+
...sortedProjects.map((project) => {
|
|
3835
|
+
const frameworkLabel = project.framework !== "unknown" ? ` ${highlighter.dim(`(${FRAMEWORK_NAMES[project.framework]})`)}` : "";
|
|
3836
|
+
return {
|
|
3837
|
+
title: `${project.name}${frameworkLabel}`,
|
|
3838
|
+
value: project.path
|
|
3839
|
+
};
|
|
3840
|
+
}),
|
|
3841
|
+
{ title: "Skip", value: "skip" }
|
|
3842
|
+
]
|
|
3843
|
+
});
|
|
3844
|
+
if (!selectedProject || selectedProject === "skip") {
|
|
3845
|
+
logger.break();
|
|
3846
|
+
process.exit(0);
|
|
3847
|
+
}
|
|
3848
|
+
process.chdir(selectedProject);
|
|
3849
|
+
const newProjectInfo = await detectProject(selectedProject);
|
|
3850
|
+
Object.assign(projectInfo, newProjectInfo);
|
|
3851
|
+
const newFrameworkSpinner = spinner("Verifying framework.").start();
|
|
3852
|
+
newFrameworkSpinner.succeed(
|
|
3853
|
+
`Verifying framework. Found ${highlighter.info(FRAMEWORK_NAMES[newProjectInfo.framework])}.`
|
|
3854
|
+
);
|
|
3759
3855
|
} else {
|
|
3760
3856
|
frameworkSpinner.fail("Could not detect a supported framework.");
|
|
3761
3857
|
logger.break();
|
|
@@ -3945,7 +4041,7 @@ var init = new commander.Command().name("init").description("initialize React Gr
|
|
|
3945
4041
|
reportToCli("error", void 0, error);
|
|
3946
4042
|
}
|
|
3947
4043
|
});
|
|
3948
|
-
var VERSION4 = "0.1.
|
|
4044
|
+
var VERSION4 = "0.1.15";
|
|
3949
4045
|
var remove = new commander.Command().name("remove").description("disconnect React Grab from your agent").argument("[agent]", `agent to disconnect (${AGENTS.join(", ")}, mcp)`).option("-y, --yes", "skip confirmation prompts", false).option(
|
|
3950
4046
|
"-c, --cwd <cwd>",
|
|
3951
4047
|
"working directory (defaults to current directory)",
|
|
@@ -3957,7 +4053,7 @@ var remove = new commander.Command().name("remove").description("disconnect Reac
|
|
|
3957
4053
|
console.log();
|
|
3958
4054
|
try {
|
|
3959
4055
|
const cwd = opts.cwd;
|
|
3960
|
-
const isNonInteractive = opts.yes;
|
|
4056
|
+
const isNonInteractive = detectNonInteractive(opts.yes);
|
|
3961
4057
|
const preflightSpinner = spinner("Preflight checks.").start();
|
|
3962
4058
|
const projectInfo = await detectProject(cwd);
|
|
3963
4059
|
if (!projectInfo.hasReactGrab) {
|
|
@@ -4121,7 +4217,7 @@ var remove = new commander.Command().name("remove").description("disconnect Reac
|
|
|
4121
4217
|
});
|
|
4122
4218
|
|
|
4123
4219
|
// src/cli.ts
|
|
4124
|
-
var VERSION5 = "0.1.
|
|
4220
|
+
var VERSION5 = "0.1.15";
|
|
4125
4221
|
var VERSION_API_URL = "https://www.react-grab.com/api/version";
|
|
4126
4222
|
process.on("SIGINT", () => process.exit(0));
|
|
4127
4223
|
process.on("SIGTERM", () => process.exit(0));
|
package/dist/cli.js
CHANGED
|
@@ -3,13 +3,23 @@ import { Command } from 'commander';
|
|
|
3
3
|
import pc from 'picocolors';
|
|
4
4
|
import basePrompts from 'prompts';
|
|
5
5
|
import { execSync } from 'child_process';
|
|
6
|
-
import fs, {
|
|
7
|
-
import path, { join, basename } from 'path';
|
|
6
|
+
import fs, { existsSync, readFileSync, writeFileSync, accessSync, constants, readdirSync } from 'fs';
|
|
7
|
+
import path, { resolve, join, relative, basename } from 'path';
|
|
8
8
|
import { detect } from '@antfu/ni';
|
|
9
|
+
import ignore from 'ignore';
|
|
9
10
|
import os from 'os';
|
|
10
11
|
import process2 from 'process';
|
|
11
12
|
import ora from 'ora';
|
|
12
13
|
|
|
14
|
+
// src/utils/is-non-interactive.ts
|
|
15
|
+
var NON_INTERACTIVE_ENVIRONMENT_VARIABLES = [
|
|
16
|
+
"CI",
|
|
17
|
+
"CLAUDECODE",
|
|
18
|
+
"AMI"
|
|
19
|
+
];
|
|
20
|
+
var detectNonInteractive = (yesFlag) => yesFlag || NON_INTERACTIVE_ENVIRONMENT_VARIABLES.some(
|
|
21
|
+
(variable) => process.env[variable] === "true"
|
|
22
|
+
) || !process.stdin.isTTY;
|
|
13
23
|
var highlighter = {
|
|
14
24
|
error: pc.red,
|
|
15
25
|
warn: pc.yellow,
|
|
@@ -179,18 +189,22 @@ var getWorkspacePatterns = (projectRoot) => {
|
|
|
179
189
|
return [...new Set(patterns)];
|
|
180
190
|
};
|
|
181
191
|
var expandWorkspacePattern = (projectRoot, pattern) => {
|
|
182
|
-
const
|
|
192
|
+
const isGlob = pattern.endsWith("/*");
|
|
183
193
|
const cleanPattern = pattern.replace(/\/\*$/, "");
|
|
184
194
|
const basePath = join(projectRoot, cleanPattern);
|
|
185
|
-
if (!existsSync(basePath)) return
|
|
195
|
+
if (!existsSync(basePath)) return [];
|
|
196
|
+
if (!isGlob) {
|
|
197
|
+
const hasPackageJson = existsSync(join(basePath, "package.json"));
|
|
198
|
+
return hasPackageJson ? [basePath] : [];
|
|
199
|
+
}
|
|
200
|
+
const results = [];
|
|
186
201
|
try {
|
|
187
202
|
const entries = readdirSync(basePath, { withFileTypes: true });
|
|
188
203
|
for (const entry of entries) {
|
|
189
|
-
if (entry.isDirectory())
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
204
|
+
if (!entry.isDirectory()) continue;
|
|
205
|
+
const packageJsonPath = join(basePath, entry.name, "package.json");
|
|
206
|
+
if (existsSync(packageJsonPath)) {
|
|
207
|
+
results.push(join(basePath, entry.name));
|
|
194
208
|
}
|
|
195
209
|
}
|
|
196
210
|
} catch {
|
|
@@ -212,35 +226,92 @@ var hasReactDependency = (projectPath) => {
|
|
|
212
226
|
return false;
|
|
213
227
|
}
|
|
214
228
|
};
|
|
229
|
+
var buildReactProject = (projectPath) => {
|
|
230
|
+
const framework = detectFramework(projectPath);
|
|
231
|
+
const hasReact = hasReactDependency(projectPath);
|
|
232
|
+
if (!hasReact && framework === "unknown") return null;
|
|
233
|
+
let name = basename(projectPath);
|
|
234
|
+
const packageJsonPath = join(projectPath, "package.json");
|
|
235
|
+
try {
|
|
236
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
237
|
+
name = packageJson.name || name;
|
|
238
|
+
} catch {
|
|
239
|
+
}
|
|
240
|
+
return { name, path: projectPath, framework, hasReact };
|
|
241
|
+
};
|
|
215
242
|
var findWorkspaceProjects = (projectRoot) => {
|
|
216
243
|
const patterns = getWorkspacePatterns(projectRoot);
|
|
217
244
|
const projects = [];
|
|
218
245
|
for (const pattern of patterns) {
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
246
|
+
for (const projectPath of expandWorkspacePattern(projectRoot, pattern)) {
|
|
247
|
+
const project = buildReactProject(projectPath);
|
|
248
|
+
if (project) projects.push(project);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return projects;
|
|
252
|
+
};
|
|
253
|
+
var ALWAYS_IGNORED_DIRECTORIES = [
|
|
254
|
+
"node_modules",
|
|
255
|
+
".git",
|
|
256
|
+
".next",
|
|
257
|
+
".cache",
|
|
258
|
+
".turbo",
|
|
259
|
+
"dist",
|
|
260
|
+
"build",
|
|
261
|
+
"coverage",
|
|
262
|
+
"test-results"
|
|
263
|
+
];
|
|
264
|
+
var loadGitignore = (projectRoot) => {
|
|
265
|
+
const ignorer = ignore().add(ALWAYS_IGNORED_DIRECTORIES);
|
|
266
|
+
const gitignorePath = join(projectRoot, ".gitignore");
|
|
267
|
+
if (existsSync(gitignorePath)) {
|
|
268
|
+
try {
|
|
269
|
+
ignorer.add(readFileSync(gitignorePath, "utf-8"));
|
|
270
|
+
} catch {
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return ignorer;
|
|
274
|
+
};
|
|
275
|
+
var scanDirectoryForProjects = (rootDirectory, ignorer, maxDepth, currentDepth = 0) => {
|
|
276
|
+
if (currentDepth >= maxDepth) return [];
|
|
277
|
+
if (!existsSync(rootDirectory)) return [];
|
|
278
|
+
const projects = [];
|
|
279
|
+
try {
|
|
280
|
+
const entries = readdirSync(rootDirectory, { withFileTypes: true });
|
|
281
|
+
for (const entry of entries) {
|
|
282
|
+
if (!entry.isDirectory()) continue;
|
|
283
|
+
if (ignorer.ignores(entry.name)) continue;
|
|
284
|
+
const entryPath = join(rootDirectory, entry.name);
|
|
285
|
+
const hasPackageJson = existsSync(join(entryPath, "package.json"));
|
|
286
|
+
if (hasPackageJson) {
|
|
287
|
+
const project = buildReactProject(entryPath);
|
|
288
|
+
if (project) {
|
|
289
|
+
projects.push(project);
|
|
290
|
+
continue;
|
|
232
291
|
}
|
|
233
|
-
projects.push({
|
|
234
|
-
name,
|
|
235
|
-
path: projectPath,
|
|
236
|
-
framework,
|
|
237
|
-
hasReact
|
|
238
|
-
});
|
|
239
292
|
}
|
|
293
|
+
projects.push(
|
|
294
|
+
...scanDirectoryForProjects(
|
|
295
|
+
entryPath,
|
|
296
|
+
ignorer,
|
|
297
|
+
maxDepth,
|
|
298
|
+
currentDepth + 1
|
|
299
|
+
)
|
|
300
|
+
);
|
|
240
301
|
}
|
|
302
|
+
} catch {
|
|
303
|
+
return projects;
|
|
241
304
|
}
|
|
242
305
|
return projects;
|
|
243
306
|
};
|
|
307
|
+
var MAX_SCAN_DEPTH = 2;
|
|
308
|
+
var findReactProjects = (projectRoot) => {
|
|
309
|
+
if (detectMonorepo(projectRoot)) {
|
|
310
|
+
return findWorkspaceProjects(projectRoot);
|
|
311
|
+
}
|
|
312
|
+
const ignorer = loadGitignore(projectRoot);
|
|
313
|
+
return scanDirectoryForProjects(projectRoot, ignorer, MAX_SCAN_DEPTH);
|
|
314
|
+
};
|
|
244
315
|
var hasReactGrabInFile = (filePath) => {
|
|
245
316
|
if (!existsSync(filePath)) return false;
|
|
246
317
|
try {
|
|
@@ -2182,7 +2253,7 @@ var previewCdnTransform = (projectRoot, framework, nextRouterType, targetCdnDoma
|
|
|
2182
2253
|
};
|
|
2183
2254
|
|
|
2184
2255
|
// src/commands/add.ts
|
|
2185
|
-
var VERSION = "0.1.
|
|
2256
|
+
var VERSION = "0.1.15";
|
|
2186
2257
|
var formatInstalledAgentNames = (agents) => agents.map((agent) => AGENT_NAMES[agent] || agent).join(", ");
|
|
2187
2258
|
var add = new Command().name("add").alias("install").description("connect React Grab to your agent").argument("[agent]", `agent to connect (${AGENTS.join(", ")}, mcp)`).option("-y, --yes", "skip confirmation prompts", false).option(
|
|
2188
2259
|
"-c, --cwd <cwd>",
|
|
@@ -2195,7 +2266,7 @@ var add = new Command().name("add").alias("install").description("connect React
|
|
|
2195
2266
|
console.log();
|
|
2196
2267
|
try {
|
|
2197
2268
|
const cwd = opts.cwd;
|
|
2198
|
-
const isNonInteractive = opts.yes;
|
|
2269
|
+
const isNonInteractive = detectNonInteractive(opts.yes);
|
|
2199
2270
|
const preflightSpinner = spinner("Preflight checks.").start();
|
|
2200
2271
|
const projectInfo = await detectProject(cwd);
|
|
2201
2272
|
if (!projectInfo.hasReactGrab) {
|
|
@@ -2543,7 +2614,7 @@ var MAX_KEY_HOLD_DURATION_MS = 2e3;
|
|
|
2543
2614
|
var MAX_CONTEXT_LINES = 50;
|
|
2544
2615
|
|
|
2545
2616
|
// src/commands/configure.ts
|
|
2546
|
-
var VERSION2 = "0.1.
|
|
2617
|
+
var VERSION2 = "0.1.15";
|
|
2547
2618
|
var isMac = process.platform === "darwin";
|
|
2548
2619
|
var META_LABEL = isMac ? "Cmd" : "Win";
|
|
2549
2620
|
var ALT_LABEL = isMac ? "Option" : "Alt";
|
|
@@ -3099,7 +3170,7 @@ var uninstallPackagesWithFeedback = (packages, packageManager, projectRoot) => {
|
|
|
3099
3170
|
};
|
|
3100
3171
|
|
|
3101
3172
|
// src/commands/init.ts
|
|
3102
|
-
var VERSION3 = "0.1.
|
|
3173
|
+
var VERSION3 = "0.1.15";
|
|
3103
3174
|
var REPORT_URL = "https://react-grab.com/api/report-cli";
|
|
3104
3175
|
var DOCS_URL = "https://github.com/aidenybai/react-grab";
|
|
3105
3176
|
var reportToCli = (type, config, error) => {
|
|
@@ -3136,6 +3207,34 @@ var UNSUPPORTED_FRAMEWORK_NAMES = {
|
|
|
3136
3207
|
gatsby: "Gatsby"
|
|
3137
3208
|
};
|
|
3138
3209
|
var getAgentName = getAgentDisplayName;
|
|
3210
|
+
var sortProjectsByFramework = (projects) => [...projects].sort((projectA, projectB) => {
|
|
3211
|
+
if (projectA.framework === "unknown" && projectB.framework !== "unknown")
|
|
3212
|
+
return 1;
|
|
3213
|
+
if (projectA.framework !== "unknown" && projectB.framework === "unknown")
|
|
3214
|
+
return -1;
|
|
3215
|
+
return 0;
|
|
3216
|
+
});
|
|
3217
|
+
var printSubprojects = (searchRoot, sortedProjects) => {
|
|
3218
|
+
logger.break();
|
|
3219
|
+
logger.log("Found the following projects:");
|
|
3220
|
+
logger.break();
|
|
3221
|
+
for (const project of sortedProjects) {
|
|
3222
|
+
const frameworkLabel = project.framework !== "unknown" ? ` ${highlighter.dim(`(${FRAMEWORK_NAMES[project.framework]})`)}` : "";
|
|
3223
|
+
const relativePath = relative(searchRoot, project.path);
|
|
3224
|
+
logger.log(
|
|
3225
|
+
` ${highlighter.info(project.name)}${frameworkLabel} ${highlighter.dim(relativePath)}`
|
|
3226
|
+
);
|
|
3227
|
+
}
|
|
3228
|
+
logger.break();
|
|
3229
|
+
logger.log(
|
|
3230
|
+
`Re-run with ${highlighter.info("-c <path>")} to specify a project:`
|
|
3231
|
+
);
|
|
3232
|
+
logger.break();
|
|
3233
|
+
logger.log(
|
|
3234
|
+
` ${highlighter.dim("$")} npx -y grab@latest init -c ${relative(searchRoot, sortedProjects[0].path)}`
|
|
3235
|
+
);
|
|
3236
|
+
logger.break();
|
|
3237
|
+
};
|
|
3139
3238
|
var formatActivationKeyDisplay2 = (activationKey) => {
|
|
3140
3239
|
if (!activationKey) return "Default (Option/Alt)";
|
|
3141
3240
|
return activationKey.split("+").map((part) => {
|
|
@@ -3164,8 +3263,14 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
3164
3263
|
);
|
|
3165
3264
|
console.log();
|
|
3166
3265
|
try {
|
|
3167
|
-
const cwd = opts.cwd;
|
|
3168
|
-
const isNonInteractive = opts.yes;
|
|
3266
|
+
const cwd = resolve(opts.cwd);
|
|
3267
|
+
const isNonInteractive = detectNonInteractive(opts.yes);
|
|
3268
|
+
if (!existsSync(cwd)) {
|
|
3269
|
+
logger.break();
|
|
3270
|
+
logger.error(`Directory does not exist: ${highlighter.info(cwd)}`);
|
|
3271
|
+
logger.break();
|
|
3272
|
+
process.exit(1);
|
|
3273
|
+
}
|
|
3169
3274
|
const preflightSpinner = spinner("Preflight checks.").start();
|
|
3170
3275
|
const projectInfo = await detectProject(cwd);
|
|
3171
3276
|
const removeAgents = async (agentsToRemove2, skipInstall = false) => {
|
|
@@ -3692,58 +3797,48 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
3692
3797
|
process.exit(1);
|
|
3693
3798
|
}
|
|
3694
3799
|
if (projectInfo.framework === "unknown") {
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
);
|
|
3700
|
-
|
|
3701
|
-
|
|
3800
|
+
let searchRoot = cwd;
|
|
3801
|
+
let reactProjects = findReactProjects(searchRoot);
|
|
3802
|
+
if (reactProjects.length === 0 && cwd !== process.cwd()) {
|
|
3803
|
+
searchRoot = process.cwd();
|
|
3804
|
+
reactProjects = findReactProjects(searchRoot);
|
|
3805
|
+
}
|
|
3806
|
+
if (reactProjects.length > 0) {
|
|
3807
|
+
frameworkSpinner.info(
|
|
3808
|
+
`Verifying framework. Found ${reactProjects.length} project${reactProjects.length === 1 ? "" : "s"}.`
|
|
3702
3809
|
);
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
(projectA, projectB) => {
|
|
3707
|
-
if (projectA.framework === "unknown" && projectB.framework !== "unknown")
|
|
3708
|
-
return 1;
|
|
3709
|
-
if (projectA.framework !== "unknown" && projectB.framework === "unknown")
|
|
3710
|
-
return -1;
|
|
3711
|
-
return 0;
|
|
3712
|
-
}
|
|
3713
|
-
);
|
|
3714
|
-
const { selectedProject } = await prompts({
|
|
3715
|
-
type: "select",
|
|
3716
|
-
name: "selectedProject",
|
|
3717
|
-
message: "Select a project to install React Grab:",
|
|
3718
|
-
choices: [
|
|
3719
|
-
...sortedProjects.map((project) => {
|
|
3720
|
-
const frameworkLabel = project.framework !== "unknown" ? ` ${highlighter.dim(`(${FRAMEWORK_NAMES[project.framework]})`)}` : "";
|
|
3721
|
-
return {
|
|
3722
|
-
title: `${project.name}${frameworkLabel}`,
|
|
3723
|
-
value: project.path
|
|
3724
|
-
};
|
|
3725
|
-
}),
|
|
3726
|
-
{ title: "Skip", value: "skip" }
|
|
3727
|
-
]
|
|
3728
|
-
});
|
|
3729
|
-
if (!selectedProject || selectedProject === "skip") {
|
|
3730
|
-
logger.break();
|
|
3731
|
-
process.exit(0);
|
|
3732
|
-
}
|
|
3733
|
-
process.chdir(selectedProject);
|
|
3734
|
-
const newProjectInfo = await detectProject(selectedProject);
|
|
3735
|
-
Object.assign(projectInfo, newProjectInfo);
|
|
3736
|
-
const newFrameworkSpinner = spinner("Verifying framework.").start();
|
|
3737
|
-
newFrameworkSpinner.succeed(
|
|
3738
|
-
`Verifying framework. Found ${highlighter.info(FRAMEWORK_NAMES[newProjectInfo.framework])}.`
|
|
3739
|
-
);
|
|
3740
|
-
} else {
|
|
3741
|
-
frameworkSpinner.fail("Could not detect a supported framework.");
|
|
3742
|
-
logger.break();
|
|
3743
|
-
logger.log(`Visit ${highlighter.info(DOCS_URL)} for manual setup.`);
|
|
3744
|
-
logger.break();
|
|
3810
|
+
const sortedProjects = sortProjectsByFramework(reactProjects);
|
|
3811
|
+
if (isNonInteractive) {
|
|
3812
|
+
printSubprojects(searchRoot, sortedProjects);
|
|
3745
3813
|
process.exit(1);
|
|
3746
3814
|
}
|
|
3815
|
+
logger.break();
|
|
3816
|
+
const { selectedProject } = await prompts({
|
|
3817
|
+
type: "select",
|
|
3818
|
+
name: "selectedProject",
|
|
3819
|
+
message: "Select a project to install React Grab:",
|
|
3820
|
+
choices: [
|
|
3821
|
+
...sortedProjects.map((project) => {
|
|
3822
|
+
const frameworkLabel = project.framework !== "unknown" ? ` ${highlighter.dim(`(${FRAMEWORK_NAMES[project.framework]})`)}` : "";
|
|
3823
|
+
return {
|
|
3824
|
+
title: `${project.name}${frameworkLabel}`,
|
|
3825
|
+
value: project.path
|
|
3826
|
+
};
|
|
3827
|
+
}),
|
|
3828
|
+
{ title: "Skip", value: "skip" }
|
|
3829
|
+
]
|
|
3830
|
+
});
|
|
3831
|
+
if (!selectedProject || selectedProject === "skip") {
|
|
3832
|
+
logger.break();
|
|
3833
|
+
process.exit(0);
|
|
3834
|
+
}
|
|
3835
|
+
process.chdir(selectedProject);
|
|
3836
|
+
const newProjectInfo = await detectProject(selectedProject);
|
|
3837
|
+
Object.assign(projectInfo, newProjectInfo);
|
|
3838
|
+
const newFrameworkSpinner = spinner("Verifying framework.").start();
|
|
3839
|
+
newFrameworkSpinner.succeed(
|
|
3840
|
+
`Verifying framework. Found ${highlighter.info(FRAMEWORK_NAMES[newProjectInfo.framework])}.`
|
|
3841
|
+
);
|
|
3747
3842
|
} else {
|
|
3748
3843
|
frameworkSpinner.fail("Could not detect a supported framework.");
|
|
3749
3844
|
logger.break();
|
|
@@ -3933,7 +4028,7 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
3933
4028
|
reportToCli("error", void 0, error);
|
|
3934
4029
|
}
|
|
3935
4030
|
});
|
|
3936
|
-
var VERSION4 = "0.1.
|
|
4031
|
+
var VERSION4 = "0.1.15";
|
|
3937
4032
|
var remove = new Command().name("remove").description("disconnect React Grab from your agent").argument("[agent]", `agent to disconnect (${AGENTS.join(", ")}, mcp)`).option("-y, --yes", "skip confirmation prompts", false).option(
|
|
3938
4033
|
"-c, --cwd <cwd>",
|
|
3939
4034
|
"working directory (defaults to current directory)",
|
|
@@ -3945,7 +4040,7 @@ var remove = new Command().name("remove").description("disconnect React Grab fro
|
|
|
3945
4040
|
console.log();
|
|
3946
4041
|
try {
|
|
3947
4042
|
const cwd = opts.cwd;
|
|
3948
|
-
const isNonInteractive = opts.yes;
|
|
4043
|
+
const isNonInteractive = detectNonInteractive(opts.yes);
|
|
3949
4044
|
const preflightSpinner = spinner("Preflight checks.").start();
|
|
3950
4045
|
const projectInfo = await detectProject(cwd);
|
|
3951
4046
|
if (!projectInfo.hasReactGrab) {
|
|
@@ -4109,7 +4204,7 @@ var remove = new Command().name("remove").description("disconnect React Grab fro
|
|
|
4109
4204
|
});
|
|
4110
4205
|
|
|
4111
4206
|
// src/cli.ts
|
|
4112
|
-
var VERSION5 = "0.1.
|
|
4207
|
+
var VERSION5 = "0.1.15";
|
|
4113
4208
|
var VERSION_API_URL = "https://www.react-grab.com/api/version";
|
|
4114
4209
|
process.on("SIGINT", () => process.exit(0));
|
|
4115
4210
|
process.on("SIGTERM", () => process.exit(0));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-grab/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"bin": {
|
|
5
5
|
"react-grab": "./dist/cli.js"
|
|
6
6
|
},
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@antfu/ni": "^0.23.0",
|
|
20
20
|
"commander": "^14.0.0",
|
|
21
|
+
"ignore": "^7.0.5",
|
|
21
22
|
"ora": "^8.2.0",
|
|
22
23
|
"picocolors": "^1.1.1",
|
|
23
24
|
"prompts": "^2.4.2"
|