@react-grab/cli 0.1.11 → 0.1.13
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 +527 -87
- package/dist/cli.js +525 -89
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3,9 +3,11 @@ 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 { readFileSync, existsSync, writeFileSync, accessSync, constants, readdirSync } from 'fs';
|
|
7
|
-
import { join, basename } from 'path';
|
|
6
|
+
import fs, { readFileSync, existsSync, writeFileSync, accessSync, constants, readdirSync } from 'fs';
|
|
7
|
+
import path, { join, basename } from 'path';
|
|
8
8
|
import { detect } from '@antfu/ni';
|
|
9
|
+
import os from 'os';
|
|
10
|
+
import process2 from 'process';
|
|
9
11
|
import ora from 'ora';
|
|
10
12
|
|
|
11
13
|
var highlighter = {
|
|
@@ -294,7 +296,8 @@ var AGENT_PACKAGES = [
|
|
|
294
296
|
"@react-grab/codex",
|
|
295
297
|
"@react-grab/gemini",
|
|
296
298
|
"@react-grab/amp",
|
|
297
|
-
"@react-grab/ami"
|
|
299
|
+
"@react-grab/ami",
|
|
300
|
+
"@react-grab/mcp"
|
|
298
301
|
];
|
|
299
302
|
var detectUnsupportedFramework = (projectRoot) => {
|
|
300
303
|
const packageJsonPath = join(projectRoot, "package.json");
|
|
@@ -525,6 +528,301 @@ var getPackagesToUninstall = (agent) => {
|
|
|
525
528
|
};
|
|
526
529
|
var spinner = (text, options) => ora({ text, isSilent: options?.silent });
|
|
527
530
|
|
|
531
|
+
// src/utils/install-mcp.ts
|
|
532
|
+
var SERVER_NAME = "react-grab-mcp";
|
|
533
|
+
var PACKAGE_NAME = "@react-grab/mcp";
|
|
534
|
+
var getBaseDir = () => {
|
|
535
|
+
const homeDir = os.homedir();
|
|
536
|
+
if (process2.platform === "win32") {
|
|
537
|
+
return process2.env.APPDATA || path.join(homeDir, "AppData", "Roaming");
|
|
538
|
+
}
|
|
539
|
+
if (process2.platform === "darwin") {
|
|
540
|
+
return path.join(homeDir, "Library", "Application Support");
|
|
541
|
+
}
|
|
542
|
+
return process2.env.XDG_CONFIG_HOME || path.join(homeDir, ".config");
|
|
543
|
+
};
|
|
544
|
+
var getZedConfigPath = () => {
|
|
545
|
+
const homeDir = os.homedir();
|
|
546
|
+
if (process2.platform === "win32") {
|
|
547
|
+
const appData = process2.env.APPDATA || path.join(homeDir, "AppData", "Roaming");
|
|
548
|
+
return path.join(appData, "Zed", "settings.json");
|
|
549
|
+
}
|
|
550
|
+
return path.join(homeDir, ".config", "zed", "settings.json");
|
|
551
|
+
};
|
|
552
|
+
var getClients = () => {
|
|
553
|
+
const homeDir = os.homedir();
|
|
554
|
+
const baseDir = getBaseDir();
|
|
555
|
+
const stdioConfig = {
|
|
556
|
+
command: "npx",
|
|
557
|
+
args: ["-y", PACKAGE_NAME, "--stdio"]
|
|
558
|
+
};
|
|
559
|
+
return [
|
|
560
|
+
{
|
|
561
|
+
name: "Cursor",
|
|
562
|
+
configPath: path.join(homeDir, ".cursor", "mcp.json"),
|
|
563
|
+
configKey: "mcpServers",
|
|
564
|
+
format: "json",
|
|
565
|
+
serverConfig: stdioConfig
|
|
566
|
+
},
|
|
567
|
+
{
|
|
568
|
+
name: "VS Code",
|
|
569
|
+
configPath: path.join(baseDir, "Code", "User", "mcp.json"),
|
|
570
|
+
configKey: "servers",
|
|
571
|
+
format: "json",
|
|
572
|
+
serverConfig: { type: "stdio", ...stdioConfig }
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
name: "Claude Code",
|
|
576
|
+
configPath: path.join(homeDir, ".claude.json"),
|
|
577
|
+
configKey: "mcpServers",
|
|
578
|
+
format: "json",
|
|
579
|
+
serverConfig: stdioConfig
|
|
580
|
+
},
|
|
581
|
+
{
|
|
582
|
+
name: "Amp",
|
|
583
|
+
configPath: path.join(homeDir, ".config", "amp", "settings.json"),
|
|
584
|
+
configKey: "amp.mcpServers",
|
|
585
|
+
format: "json",
|
|
586
|
+
serverConfig: stdioConfig
|
|
587
|
+
},
|
|
588
|
+
{
|
|
589
|
+
name: "Droid",
|
|
590
|
+
configPath: path.join(homeDir, ".factory", "mcp.json"),
|
|
591
|
+
configKey: "mcpServers",
|
|
592
|
+
format: "json",
|
|
593
|
+
serverConfig: { type: "stdio", ...stdioConfig }
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
name: "Codex",
|
|
597
|
+
configPath: path.join(
|
|
598
|
+
process2.env.CODEX_HOME || path.join(homeDir, ".codex"),
|
|
599
|
+
"config.toml"
|
|
600
|
+
),
|
|
601
|
+
configKey: "mcp_servers",
|
|
602
|
+
format: "toml",
|
|
603
|
+
serverConfig: stdioConfig
|
|
604
|
+
},
|
|
605
|
+
{
|
|
606
|
+
name: "Zed",
|
|
607
|
+
configPath: getZedConfigPath(),
|
|
608
|
+
configKey: "context_servers",
|
|
609
|
+
format: "json",
|
|
610
|
+
serverConfig: { source: "custom", ...stdioConfig, env: {} }
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
name: "Windsurf",
|
|
614
|
+
configPath: path.join(homeDir, ".codeium", "windsurf", "mcp_config.json"),
|
|
615
|
+
configKey: "mcpServers",
|
|
616
|
+
format: "json",
|
|
617
|
+
serverConfig: stdioConfig
|
|
618
|
+
}
|
|
619
|
+
];
|
|
620
|
+
};
|
|
621
|
+
var ensureDirectory = (filePath) => {
|
|
622
|
+
const directory = path.dirname(filePath);
|
|
623
|
+
if (!fs.existsSync(directory)) {
|
|
624
|
+
fs.mkdirSync(directory, { recursive: true });
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
var indentJson = (json, baseIndent) => json.split("\n").map((line, index) => index === 0 ? line : baseIndent + line).join("\n");
|
|
628
|
+
var insertIntoJsonc = (filePath, content, configKey, serverName, serverConfig) => {
|
|
629
|
+
if (content.includes(`"${serverName}"`)) return;
|
|
630
|
+
const serverJson = indentJson(
|
|
631
|
+
JSON.stringify(serverConfig, null, 2),
|
|
632
|
+
" "
|
|
633
|
+
);
|
|
634
|
+
const escapedConfigKey = configKey.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
635
|
+
const keyPattern = new RegExp(`"${escapedConfigKey}"\\s*:\\s*\\{`);
|
|
636
|
+
const keyMatch = keyPattern.exec(content);
|
|
637
|
+
if (keyMatch) {
|
|
638
|
+
const insertPosition = keyMatch.index + keyMatch[0].length;
|
|
639
|
+
const entry = `
|
|
640
|
+
"${serverName}": ${serverJson},`;
|
|
641
|
+
fs.writeFileSync(
|
|
642
|
+
filePath,
|
|
643
|
+
content.slice(0, insertPosition) + entry + content.slice(insertPosition)
|
|
644
|
+
);
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
const lastBrace = content.lastIndexOf("}");
|
|
648
|
+
if (lastBrace === -1) return;
|
|
649
|
+
const beforeBrace = content.slice(0, lastBrace).trimEnd();
|
|
650
|
+
const withoutComments = beforeBrace.replace(/\/\/.*$/, "").trimEnd();
|
|
651
|
+
const lastChar = withoutComments[withoutComments.length - 1];
|
|
652
|
+
const needsComma = lastChar !== void 0 && lastChar !== "{" && lastChar !== ",";
|
|
653
|
+
const section = `${needsComma ? "," : ""}
|
|
654
|
+
"${configKey}": {
|
|
655
|
+
"${serverName}": ${serverJson}
|
|
656
|
+
}`;
|
|
657
|
+
fs.writeFileSync(filePath, beforeBrace + section + "\n}\n");
|
|
658
|
+
};
|
|
659
|
+
var installJsonClient = (client) => {
|
|
660
|
+
ensureDirectory(client.configPath);
|
|
661
|
+
if (!fs.existsSync(client.configPath)) {
|
|
662
|
+
const config = {
|
|
663
|
+
[client.configKey]: { [SERVER_NAME]: client.serverConfig }
|
|
664
|
+
};
|
|
665
|
+
fs.writeFileSync(client.configPath, JSON.stringify(config, null, 2) + "\n");
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
const content = fs.readFileSync(client.configPath, "utf8");
|
|
669
|
+
try {
|
|
670
|
+
const config = JSON.parse(content);
|
|
671
|
+
const servers = config[client.configKey] ?? {};
|
|
672
|
+
servers[SERVER_NAME] = client.serverConfig;
|
|
673
|
+
config[client.configKey] = servers;
|
|
674
|
+
fs.writeFileSync(client.configPath, JSON.stringify(config, null, 2) + "\n");
|
|
675
|
+
} catch {
|
|
676
|
+
insertIntoJsonc(
|
|
677
|
+
client.configPath,
|
|
678
|
+
content,
|
|
679
|
+
client.configKey,
|
|
680
|
+
SERVER_NAME,
|
|
681
|
+
client.serverConfig
|
|
682
|
+
);
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
var buildTomlSection = (configKey, serverConfig) => {
|
|
686
|
+
const lines = [`[${configKey}.${SERVER_NAME}]`];
|
|
687
|
+
for (const [key, value] of Object.entries(serverConfig)) {
|
|
688
|
+
if (typeof value === "string") {
|
|
689
|
+
lines.push(`${key} = "${value}"`);
|
|
690
|
+
} else if (Array.isArray(value)) {
|
|
691
|
+
const items = value.map((item) => `"${item}"`).join(", ");
|
|
692
|
+
lines.push(`${key} = [${items}]`);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
return lines.join("\n");
|
|
696
|
+
};
|
|
697
|
+
var installTomlClient = (client) => {
|
|
698
|
+
ensureDirectory(client.configPath);
|
|
699
|
+
const sectionHeader = `[${client.configKey}.${SERVER_NAME}]`;
|
|
700
|
+
const newSection = buildTomlSection(client.configKey, client.serverConfig);
|
|
701
|
+
if (!fs.existsSync(client.configPath)) {
|
|
702
|
+
fs.writeFileSync(client.configPath, newSection + "\n");
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
const content = fs.readFileSync(client.configPath, "utf8");
|
|
706
|
+
if (!content.includes(sectionHeader)) {
|
|
707
|
+
fs.writeFileSync(
|
|
708
|
+
client.configPath,
|
|
709
|
+
content.trimEnd() + "\n\n" + newSection + "\n"
|
|
710
|
+
);
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
const lines = content.split("\n");
|
|
714
|
+
const resultLines = [];
|
|
715
|
+
let isInsideOurSection = false;
|
|
716
|
+
let didInsertReplacement = false;
|
|
717
|
+
for (const line of lines) {
|
|
718
|
+
if (line.trim() === sectionHeader) {
|
|
719
|
+
isInsideOurSection = true;
|
|
720
|
+
if (!didInsertReplacement) {
|
|
721
|
+
resultLines.push(newSection);
|
|
722
|
+
didInsertReplacement = true;
|
|
723
|
+
}
|
|
724
|
+
continue;
|
|
725
|
+
}
|
|
726
|
+
if (isInsideOurSection && line.startsWith("[")) {
|
|
727
|
+
isInsideOurSection = false;
|
|
728
|
+
}
|
|
729
|
+
if (!isInsideOurSection) {
|
|
730
|
+
resultLines.push(line);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
fs.writeFileSync(client.configPath, resultLines.join("\n"));
|
|
734
|
+
};
|
|
735
|
+
var getMcpClientNames = () => getClients().map((client) => client.name);
|
|
736
|
+
var installMcpServers = (selectedClients) => {
|
|
737
|
+
const allClients = getClients();
|
|
738
|
+
const clients = selectedClients ? allClients.filter((client) => selectedClients.includes(client.name)) : allClients;
|
|
739
|
+
const results = [];
|
|
740
|
+
const installSpinner = spinner("Installing MCP server.").start();
|
|
741
|
+
for (const client of clients) {
|
|
742
|
+
try {
|
|
743
|
+
if (client.format === "toml") {
|
|
744
|
+
installTomlClient(client);
|
|
745
|
+
} else {
|
|
746
|
+
installJsonClient(client);
|
|
747
|
+
}
|
|
748
|
+
results.push({
|
|
749
|
+
client: client.name,
|
|
750
|
+
configPath: client.configPath,
|
|
751
|
+
success: true
|
|
752
|
+
});
|
|
753
|
+
} catch (error) {
|
|
754
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
755
|
+
results.push({
|
|
756
|
+
client: client.name,
|
|
757
|
+
configPath: client.configPath,
|
|
758
|
+
success: false,
|
|
759
|
+
error: message
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
const successCount = results.filter((result) => result.success).length;
|
|
764
|
+
const failedCount = results.length - successCount;
|
|
765
|
+
if (failedCount > 0) {
|
|
766
|
+
installSpinner.warn(
|
|
767
|
+
`Installed to ${successCount}/${results.length} agents.`
|
|
768
|
+
);
|
|
769
|
+
} else {
|
|
770
|
+
installSpinner.succeed(`Installed to ${successCount} agents.`);
|
|
771
|
+
}
|
|
772
|
+
for (const result of results) {
|
|
773
|
+
if (result.success) {
|
|
774
|
+
logger.log(
|
|
775
|
+
` ${highlighter.success("\u2713")} ${result.client} ${highlighter.dim("\u2192")} ${highlighter.dim(result.configPath)}`
|
|
776
|
+
);
|
|
777
|
+
} else {
|
|
778
|
+
logger.log(
|
|
779
|
+
` ${highlighter.error("\u2717")} ${result.client} ${highlighter.dim("\u2192")} ${result.error}`
|
|
780
|
+
);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
return results;
|
|
784
|
+
};
|
|
785
|
+
var promptConnectionMode = async () => {
|
|
786
|
+
const { connectionMode } = await prompts({
|
|
787
|
+
type: "select",
|
|
788
|
+
name: "connectionMode",
|
|
789
|
+
message: "How would you like to connect?",
|
|
790
|
+
choices: [
|
|
791
|
+
{
|
|
792
|
+
title: `MCP ${highlighter.dim("(recommended)")}`,
|
|
793
|
+
description: "Installs to all supported agents at once",
|
|
794
|
+
value: "mcp"
|
|
795
|
+
},
|
|
796
|
+
{
|
|
797
|
+
title: "Legacy",
|
|
798
|
+
description: "Install a per-project agent package",
|
|
799
|
+
value: "legacy"
|
|
800
|
+
}
|
|
801
|
+
]
|
|
802
|
+
});
|
|
803
|
+
return connectionMode;
|
|
804
|
+
};
|
|
805
|
+
var promptMcpInstall = async () => {
|
|
806
|
+
const clientNames = getMcpClientNames();
|
|
807
|
+
const { selectedAgents } = await prompts({
|
|
808
|
+
type: "multiselect",
|
|
809
|
+
name: "selectedAgents",
|
|
810
|
+
message: "Select agents to install MCP server for:",
|
|
811
|
+
choices: clientNames.map((name) => ({
|
|
812
|
+
title: name,
|
|
813
|
+
value: name,
|
|
814
|
+
selected: true
|
|
815
|
+
}))
|
|
816
|
+
});
|
|
817
|
+
if (selectedAgents === void 0 || selectedAgents.length === 0) {
|
|
818
|
+
return false;
|
|
819
|
+
}
|
|
820
|
+
logger.break();
|
|
821
|
+
const results = installMcpServers(selectedAgents);
|
|
822
|
+
const hasSuccess = results.some((result) => result.success);
|
|
823
|
+
return hasSuccess;
|
|
824
|
+
};
|
|
825
|
+
|
|
528
826
|
// src/utils/templates.ts
|
|
529
827
|
var AGENTS = [
|
|
530
828
|
"claude-code",
|
|
@@ -546,6 +844,13 @@ var AGENT_NAMES = {
|
|
|
546
844
|
ami: "Ami",
|
|
547
845
|
droid: "Droid"
|
|
548
846
|
};
|
|
847
|
+
var getAgentDisplayName = (agent) => {
|
|
848
|
+
if (agent === "mcp") return "MCP";
|
|
849
|
+
if (agent in AGENT_NAMES) {
|
|
850
|
+
return AGENT_NAMES[agent];
|
|
851
|
+
}
|
|
852
|
+
return agent;
|
|
853
|
+
};
|
|
549
854
|
var NEXT_APP_ROUTER_SCRIPT = `{process.env.NODE_ENV === "development" && (
|
|
550
855
|
<Script
|
|
551
856
|
src="//unpkg.com/react-grab/dist/index.global.js"
|
|
@@ -1299,6 +1604,14 @@ var previewPackageJsonTransform = (projectRoot, agent, installedAgents, packageM
|
|
|
1299
1604
|
noChanges: true
|
|
1300
1605
|
};
|
|
1301
1606
|
}
|
|
1607
|
+
if (agent === "mcp") {
|
|
1608
|
+
return {
|
|
1609
|
+
success: true,
|
|
1610
|
+
filePath: "",
|
|
1611
|
+
message: "MCP does not use package.json dev script",
|
|
1612
|
+
noChanges: true
|
|
1613
|
+
};
|
|
1614
|
+
}
|
|
1302
1615
|
const packageJsonPath = join(projectRoot, "package.json");
|
|
1303
1616
|
if (!existsSync(packageJsonPath)) {
|
|
1304
1617
|
return {
|
|
@@ -1860,9 +2173,9 @@ var previewCdnTransform = (projectRoot, framework, nextRouterType, targetCdnDoma
|
|
|
1860
2173
|
};
|
|
1861
2174
|
|
|
1862
2175
|
// src/commands/add.ts
|
|
1863
|
-
var VERSION = "0.1.
|
|
2176
|
+
var VERSION = "0.1.13";
|
|
1864
2177
|
var formatInstalledAgentNames = (agents) => agents.map((agent) => AGENT_NAMES[agent] || agent).join(", ");
|
|
1865
|
-
var add = new Command().name("add").alias("install").description("
|
|
2178
|
+
var add = new Command().name("add").alias("install").description("connect React Grab to your agent").argument("[agent]", `agent to add (${AGENTS.join(", ")})`).option("-y, --yes", "skip confirmation prompts", false).option(
|
|
1866
2179
|
"-c, --cwd <cwd>",
|
|
1867
2180
|
"working directory (defaults to current directory)",
|
|
1868
2181
|
process.cwd()
|
|
@@ -1889,9 +2202,10 @@ var add = new Command().name("add").alias("install").description("add an agent i
|
|
|
1889
2202
|
const availableAgents = AGENTS.filter(
|
|
1890
2203
|
(agent) => !projectInfo.installedAgents.includes(agent)
|
|
1891
2204
|
);
|
|
1892
|
-
if (availableAgents.length === 0) {
|
|
2205
|
+
if (availableAgents.length === 0 && isNonInteractive && !agentArg) {
|
|
1893
2206
|
logger.break();
|
|
1894
|
-
logger.success("All
|
|
2207
|
+
logger.success("All legacy agents are already installed.");
|
|
2208
|
+
logger.log("Run without -y to add MCP.");
|
|
1895
2209
|
logger.break();
|
|
1896
2210
|
process.exit(0);
|
|
1897
2211
|
}
|
|
@@ -1925,11 +2239,11 @@ var add = new Command().name("add").alias("install").description("add an agent i
|
|
|
1925
2239
|
message: "How would you like to proceed?",
|
|
1926
2240
|
choices: [
|
|
1927
2241
|
{
|
|
1928
|
-
title: `Replace with ${
|
|
2242
|
+
title: `Replace with ${getAgentDisplayName(agentIntegration)}`,
|
|
1929
2243
|
value: "replace"
|
|
1930
2244
|
},
|
|
1931
2245
|
{
|
|
1932
|
-
title: `Add ${
|
|
2246
|
+
title: `Add ${getAgentDisplayName(agentIntegration)} alongside existing`,
|
|
1933
2247
|
value: "add"
|
|
1934
2248
|
},
|
|
1935
2249
|
{ title: "Cancel", value: "cancel" }
|
|
@@ -1953,48 +2267,72 @@ var add = new Command().name("add").alias("install").description("add an agent i
|
|
|
1953
2267
|
logger.warn(`Currently installed: ${installedNames}`);
|
|
1954
2268
|
logger.break();
|
|
1955
2269
|
}
|
|
1956
|
-
const
|
|
1957
|
-
|
|
1958
|
-
name: "agent",
|
|
1959
|
-
message: `Which ${highlighter.info("coding agent")} would you like to connect?`,
|
|
1960
|
-
choices: availableAgents.map((availableAgent) => ({
|
|
1961
|
-
title: AGENT_NAMES[availableAgent],
|
|
1962
|
-
value: availableAgent
|
|
1963
|
-
}))
|
|
1964
|
-
});
|
|
1965
|
-
if (!agent) {
|
|
2270
|
+
const connectionMode = await promptConnectionMode();
|
|
2271
|
+
if (connectionMode === void 0) {
|
|
1966
2272
|
logger.break();
|
|
1967
2273
|
process.exit(1);
|
|
1968
2274
|
}
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
2275
|
+
if (connectionMode === "mcp") {
|
|
2276
|
+
const didInstall = await promptMcpInstall();
|
|
2277
|
+
if (!didInstall) {
|
|
2278
|
+
logger.break();
|
|
2279
|
+
process.exit(0);
|
|
2280
|
+
}
|
|
2281
|
+
logger.break();
|
|
2282
|
+
logger.log(
|
|
2283
|
+
`${highlighter.success("Success!")} MCP server has been configured.`
|
|
1973
2284
|
);
|
|
1974
|
-
|
|
2285
|
+
logger.log("Restart your agents to activate.");
|
|
2286
|
+
logger.break();
|
|
2287
|
+
agentIntegration = "mcp";
|
|
2288
|
+
projectInfo.installedAgents = [...projectInfo.installedAgents, "mcp"];
|
|
2289
|
+
} else {
|
|
2290
|
+
const { agent } = await prompts({
|
|
1975
2291
|
type: "select",
|
|
1976
|
-
name: "
|
|
1977
|
-
message: "
|
|
2292
|
+
name: "agent",
|
|
2293
|
+
message: `Which ${highlighter.info("agent")} would you like to connect?`,
|
|
1978
2294
|
choices: [
|
|
1979
|
-
{
|
|
1980
|
-
title:
|
|
1981
|
-
value:
|
|
1982
|
-
},
|
|
1983
|
-
{
|
|
1984
|
-
title: `Add ${AGENT_NAMES[agentIntegration]} alongside existing`,
|
|
1985
|
-
value: "add"
|
|
1986
|
-
},
|
|
1987
|
-
{ title: "Cancel", value: "cancel" }
|
|
2295
|
+
...availableAgents.map((availableAgent) => ({
|
|
2296
|
+
title: AGENT_NAMES[availableAgent],
|
|
2297
|
+
value: availableAgent
|
|
2298
|
+
})),
|
|
2299
|
+
{ title: "Skip", value: "skip" }
|
|
1988
2300
|
]
|
|
1989
2301
|
});
|
|
1990
|
-
if (!
|
|
1991
|
-
logger.break();
|
|
1992
|
-
logger.log("Changes cancelled.");
|
|
2302
|
+
if (!agent || agent === "skip") {
|
|
1993
2303
|
logger.break();
|
|
1994
2304
|
process.exit(0);
|
|
1995
2305
|
}
|
|
1996
|
-
|
|
1997
|
-
|
|
2306
|
+
agentIntegration = agent;
|
|
2307
|
+
if (projectInfo.installedAgents.length > 0) {
|
|
2308
|
+
const installedNames = formatInstalledAgentNames(
|
|
2309
|
+
projectInfo.installedAgents
|
|
2310
|
+
);
|
|
2311
|
+
const { action } = await prompts({
|
|
2312
|
+
type: "select",
|
|
2313
|
+
name: "action",
|
|
2314
|
+
message: "How would you like to proceed?",
|
|
2315
|
+
choices: [
|
|
2316
|
+
{
|
|
2317
|
+
title: `Replace ${installedNames} with ${getAgentDisplayName(agentIntegration)}`,
|
|
2318
|
+
value: "replace"
|
|
2319
|
+
},
|
|
2320
|
+
{
|
|
2321
|
+
title: `Add ${getAgentDisplayName(agentIntegration)} alongside existing`,
|
|
2322
|
+
value: "add"
|
|
2323
|
+
},
|
|
2324
|
+
{ title: "Cancel", value: "cancel" }
|
|
2325
|
+
]
|
|
2326
|
+
});
|
|
2327
|
+
if (!action || action === "cancel") {
|
|
2328
|
+
logger.break();
|
|
2329
|
+
logger.log("Changes cancelled.");
|
|
2330
|
+
logger.break();
|
|
2331
|
+
process.exit(0);
|
|
2332
|
+
}
|
|
2333
|
+
if (action === "replace") {
|
|
2334
|
+
agentsToRemove = [...projectInfo.installedAgents];
|
|
2335
|
+
}
|
|
1998
2336
|
}
|
|
1999
2337
|
}
|
|
2000
2338
|
} else {
|
|
@@ -2071,7 +2409,7 @@ var add = new Command().name("add").alias("install").description("add an agent i
|
|
|
2071
2409
|
);
|
|
2072
2410
|
}
|
|
2073
2411
|
const addingSpinner = spinner(
|
|
2074
|
-
`Adding ${
|
|
2412
|
+
`Adding ${getAgentDisplayName(agentIntegration)}.`
|
|
2075
2413
|
).start();
|
|
2076
2414
|
addingSpinner.succeed();
|
|
2077
2415
|
const result = previewTransform(
|
|
@@ -2177,7 +2515,7 @@ var add = new Command().name("add").alias("install").description("add an agent i
|
|
|
2177
2515
|
}
|
|
2178
2516
|
logger.break();
|
|
2179
2517
|
logger.log(
|
|
2180
|
-
`${highlighter.success("Success!")} ${
|
|
2518
|
+
`${highlighter.success("Success!")} ${getAgentDisplayName(agentIntegration)} has been added.`
|
|
2181
2519
|
);
|
|
2182
2520
|
if (packageJsonResult.warning) {
|
|
2183
2521
|
logger.warn(packageJsonResult.warning);
|
|
@@ -2196,7 +2534,7 @@ var MAX_KEY_HOLD_DURATION_MS = 2e3;
|
|
|
2196
2534
|
var MAX_CONTEXT_LINES = 50;
|
|
2197
2535
|
|
|
2198
2536
|
// src/commands/configure.ts
|
|
2199
|
-
var VERSION2 = "0.1.
|
|
2537
|
+
var VERSION2 = "0.1.13";
|
|
2200
2538
|
var isMac = process.platform === "darwin";
|
|
2201
2539
|
var META_LABEL = isMac ? "Cmd" : "Win";
|
|
2202
2540
|
var ALT_LABEL = isMac ? "Option" : "Alt";
|
|
@@ -2699,7 +3037,7 @@ var configure = new Command().name("configure").alias("config").description("con
|
|
|
2699
3037
|
});
|
|
2700
3038
|
|
|
2701
3039
|
// src/utils/cli-helpers.ts
|
|
2702
|
-
var formatInstalledAgentNames2 = (agents) => agents.map(
|
|
3040
|
+
var formatInstalledAgentNames2 = (agents) => agents.map(getAgentDisplayName).join(", ");
|
|
2703
3041
|
var applyTransformWithFeedback = (result, message) => {
|
|
2704
3042
|
const writeSpinner = spinner(
|
|
2705
3043
|
message ?? `Applying changes to ${result.filePath}.`
|
|
@@ -2752,7 +3090,7 @@ var uninstallPackagesWithFeedback = (packages, packageManager, projectRoot) => {
|
|
|
2752
3090
|
};
|
|
2753
3091
|
|
|
2754
3092
|
// src/commands/init.ts
|
|
2755
|
-
var VERSION3 = "0.1.
|
|
3093
|
+
var VERSION3 = "0.1.13";
|
|
2756
3094
|
var REPORT_URL = "https://react-grab.com/api/report-cli";
|
|
2757
3095
|
var DOCS_URL = "https://github.com/aidenybai/react-grab";
|
|
2758
3096
|
var reportToCli = (type, config, error) => {
|
|
@@ -2788,12 +3126,7 @@ var UNSUPPORTED_FRAMEWORK_NAMES = {
|
|
|
2788
3126
|
sveltekit: "SvelteKit",
|
|
2789
3127
|
gatsby: "Gatsby"
|
|
2790
3128
|
};
|
|
2791
|
-
var getAgentName =
|
|
2792
|
-
if (agent in AGENT_NAMES) {
|
|
2793
|
-
return AGENT_NAMES[agent];
|
|
2794
|
-
}
|
|
2795
|
-
return agent;
|
|
2796
|
-
};
|
|
3129
|
+
var getAgentName = getAgentDisplayName;
|
|
2797
3130
|
var formatActivationKeyDisplay2 = (activationKey) => {
|
|
2798
3131
|
if (!activationKey) return "Default (Option/Alt)";
|
|
2799
3132
|
return activationKey.split("+").map((part) => {
|
|
@@ -2808,7 +3141,7 @@ var formatActivationKeyDisplay2 = (activationKey) => {
|
|
|
2808
3141
|
};
|
|
2809
3142
|
var init = new Command().name("init").description("initialize React Grab in your project").option("-y, --yes", "skip confirmation prompts", false).option("-f, --force", "force overwrite existing config", false).option(
|
|
2810
3143
|
"-a, --agent <agent>",
|
|
2811
|
-
"agent
|
|
3144
|
+
"connect to your agent (claude-code, cursor, opencode, codex, gemini, amp, mcp)"
|
|
2812
3145
|
).option(
|
|
2813
3146
|
"-k, --key <key>",
|
|
2814
3147
|
"activation key (e.g., Meta+K, Ctrl+Shift+G, Space)"
|
|
@@ -3027,23 +3360,108 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
3027
3360
|
const availableAgents = AGENTS.filter(
|
|
3028
3361
|
(agent) => !projectInfo.installedAgents.includes(agent)
|
|
3029
3362
|
);
|
|
3030
|
-
|
|
3363
|
+
logger.break();
|
|
3364
|
+
const { wantAddAgent } = await prompts({
|
|
3365
|
+
type: "confirm",
|
|
3366
|
+
name: "wantAddAgent",
|
|
3367
|
+
message: `Would you like to ${highlighter.info("connect it to your agent")}?`,
|
|
3368
|
+
initial: false
|
|
3369
|
+
});
|
|
3370
|
+
if (wantAddAgent === void 0) {
|
|
3031
3371
|
logger.break();
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
});
|
|
3038
|
-
if (wantAddAgent === void 0) {
|
|
3372
|
+
process.exit(1);
|
|
3373
|
+
}
|
|
3374
|
+
if (wantAddAgent) {
|
|
3375
|
+
const connectionMode = await promptConnectionMode();
|
|
3376
|
+
if (connectionMode === void 0) {
|
|
3039
3377
|
logger.break();
|
|
3040
3378
|
process.exit(1);
|
|
3041
3379
|
}
|
|
3042
|
-
|
|
3380
|
+
let agentIntegration2;
|
|
3381
|
+
if (connectionMode === "mcp") {
|
|
3382
|
+
const didInstall = await promptMcpInstall();
|
|
3383
|
+
if (!didInstall) {
|
|
3384
|
+
logger.break();
|
|
3385
|
+
process.exit(0);
|
|
3386
|
+
}
|
|
3387
|
+
logger.break();
|
|
3388
|
+
logger.success("MCP server has been configured.");
|
|
3389
|
+
logger.log("Restart your agents to activate.");
|
|
3390
|
+
agentIntegration2 = "mcp";
|
|
3391
|
+
projectInfo.installedAgents = ["mcp"];
|
|
3392
|
+
const result2 = previewTransform(
|
|
3393
|
+
projectInfo.projectRoot,
|
|
3394
|
+
projectInfo.framework,
|
|
3395
|
+
projectInfo.nextRouterType,
|
|
3396
|
+
agentIntegration2,
|
|
3397
|
+
true
|
|
3398
|
+
);
|
|
3399
|
+
const packageJsonResult2 = previewPackageJsonTransform(
|
|
3400
|
+
projectInfo.projectRoot,
|
|
3401
|
+
agentIntegration2,
|
|
3402
|
+
projectInfo.installedAgents,
|
|
3403
|
+
projectInfo.packageManager
|
|
3404
|
+
);
|
|
3405
|
+
if (!result2.success) {
|
|
3406
|
+
logger.break();
|
|
3407
|
+
logger.error(result2.message);
|
|
3408
|
+
logger.break();
|
|
3409
|
+
process.exit(1);
|
|
3410
|
+
}
|
|
3411
|
+
const hasLayoutChanges2 = !result2.noChanges && result2.originalContent && result2.newContent;
|
|
3412
|
+
const hasPackageJsonChanges2 = packageJsonResult2.success && !packageJsonResult2.noChanges && packageJsonResult2.originalContent && packageJsonResult2.newContent;
|
|
3413
|
+
if (hasLayoutChanges2 || hasPackageJsonChanges2) {
|
|
3414
|
+
logger.break();
|
|
3415
|
+
if (hasLayoutChanges2) {
|
|
3416
|
+
printDiff(
|
|
3417
|
+
result2.filePath,
|
|
3418
|
+
result2.originalContent,
|
|
3419
|
+
result2.newContent
|
|
3420
|
+
);
|
|
3421
|
+
}
|
|
3422
|
+
if (hasPackageJsonChanges2) {
|
|
3423
|
+
if (hasLayoutChanges2) {
|
|
3424
|
+
logger.break();
|
|
3425
|
+
}
|
|
3426
|
+
printDiff(
|
|
3427
|
+
packageJsonResult2.filePath,
|
|
3428
|
+
packageJsonResult2.originalContent,
|
|
3429
|
+
packageJsonResult2.newContent
|
|
3430
|
+
);
|
|
3431
|
+
}
|
|
3432
|
+
logger.break();
|
|
3433
|
+
const { proceed } = await prompts({
|
|
3434
|
+
type: "confirm",
|
|
3435
|
+
name: "proceed",
|
|
3436
|
+
message: "Apply these changes?",
|
|
3437
|
+
initial: true
|
|
3438
|
+
});
|
|
3439
|
+
if (!proceed) {
|
|
3440
|
+
logger.break();
|
|
3441
|
+
logger.log("Agent addition cancelled.");
|
|
3442
|
+
} else {
|
|
3443
|
+
installPackagesWithFeedback(
|
|
3444
|
+
getPackagesToInstall(agentIntegration2, false),
|
|
3445
|
+
projectInfo.packageManager,
|
|
3446
|
+
projectInfo.projectRoot
|
|
3447
|
+
);
|
|
3448
|
+
if (hasLayoutChanges2) {
|
|
3449
|
+
applyTransformWithFeedback(result2);
|
|
3450
|
+
}
|
|
3451
|
+
if (hasPackageJsonChanges2) {
|
|
3452
|
+
applyPackageJsonWithFeedback(packageJsonResult2);
|
|
3453
|
+
}
|
|
3454
|
+
logger.break();
|
|
3455
|
+
logger.success(
|
|
3456
|
+
`${getAgentName(agentIntegration2)} has been added.`
|
|
3457
|
+
);
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3460
|
+
} else {
|
|
3043
3461
|
const { agent } = await prompts({
|
|
3044
3462
|
type: "select",
|
|
3045
3463
|
name: "agent",
|
|
3046
|
-
message: `Which ${highlighter.info("
|
|
3464
|
+
message: `Which ${highlighter.info("agent")} would you like to connect?`,
|
|
3047
3465
|
choices: [
|
|
3048
3466
|
...availableAgents.map((innerAgent) => ({
|
|
3049
3467
|
title: getAgentName(innerAgent),
|
|
@@ -3056,7 +3474,7 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
3056
3474
|
logger.break();
|
|
3057
3475
|
process.exit(0);
|
|
3058
3476
|
}
|
|
3059
|
-
|
|
3477
|
+
agentIntegration2 = agent;
|
|
3060
3478
|
let agentsToRemove2 = [];
|
|
3061
3479
|
if (projectInfo.installedAgents.length > 0) {
|
|
3062
3480
|
const installedNames = formatInstalledAgentNames2(
|
|
@@ -3354,7 +3772,7 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
3354
3772
|
const { wantAddAgent } = await prompts({
|
|
3355
3773
|
type: "confirm",
|
|
3356
3774
|
name: "wantAddAgent",
|
|
3357
|
-
message: `Would you like to
|
|
3775
|
+
message: `Would you like to ${highlighter.info("connect it to your agent")}?`,
|
|
3358
3776
|
initial: false
|
|
3359
3777
|
});
|
|
3360
3778
|
if (wantAddAgent === void 0) {
|
|
@@ -3362,24 +3780,42 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
3362
3780
|
process.exit(1);
|
|
3363
3781
|
}
|
|
3364
3782
|
if (wantAddAgent) {
|
|
3365
|
-
const
|
|
3366
|
-
|
|
3367
|
-
name: "agent",
|
|
3368
|
-
message: `Which ${highlighter.info("coding agent")} would you like to connect?`,
|
|
3369
|
-
choices: [
|
|
3370
|
-
...AGENTS.map((innerAgent) => ({
|
|
3371
|
-
title: getAgentName(innerAgent),
|
|
3372
|
-
value: innerAgent
|
|
3373
|
-
})),
|
|
3374
|
-
{ title: "Skip", value: "skip" }
|
|
3375
|
-
]
|
|
3376
|
-
});
|
|
3377
|
-
if (agent === void 0) {
|
|
3783
|
+
const connectionMode = await promptConnectionMode();
|
|
3784
|
+
if (connectionMode === void 0) {
|
|
3378
3785
|
logger.break();
|
|
3379
3786
|
process.exit(1);
|
|
3380
3787
|
}
|
|
3381
|
-
if (
|
|
3382
|
-
|
|
3788
|
+
if (connectionMode === "mcp") {
|
|
3789
|
+
const didInstall = await promptMcpInstall();
|
|
3790
|
+
if (!didInstall) {
|
|
3791
|
+
logger.break();
|
|
3792
|
+
process.exit(0);
|
|
3793
|
+
}
|
|
3794
|
+
logger.break();
|
|
3795
|
+
logger.success("MCP server has been configured.");
|
|
3796
|
+
logger.log("Continuing with React Grab installation...");
|
|
3797
|
+
logger.break();
|
|
3798
|
+
agentIntegration = "mcp";
|
|
3799
|
+
} else {
|
|
3800
|
+
const { agent } = await prompts({
|
|
3801
|
+
type: "select",
|
|
3802
|
+
name: "agent",
|
|
3803
|
+
message: `Which ${highlighter.info("agent")} would you like to connect?`,
|
|
3804
|
+
choices: [
|
|
3805
|
+
...AGENTS.map((innerAgent) => ({
|
|
3806
|
+
title: getAgentName(innerAgent),
|
|
3807
|
+
value: innerAgent
|
|
3808
|
+
})),
|
|
3809
|
+
{ title: "Skip", value: "skip" }
|
|
3810
|
+
]
|
|
3811
|
+
});
|
|
3812
|
+
if (agent === void 0) {
|
|
3813
|
+
logger.break();
|
|
3814
|
+
process.exit(1);
|
|
3815
|
+
}
|
|
3816
|
+
if (agent !== "skip") {
|
|
3817
|
+
agentIntegration = agent;
|
|
3818
|
+
}
|
|
3383
3819
|
}
|
|
3384
3820
|
}
|
|
3385
3821
|
}
|
|
@@ -3488,10 +3924,10 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
3488
3924
|
reportToCli("error", void 0, error);
|
|
3489
3925
|
}
|
|
3490
3926
|
});
|
|
3491
|
-
var VERSION4 = "0.1.
|
|
3492
|
-
var remove = new Command().name("remove").description("
|
|
3927
|
+
var VERSION4 = "0.1.13";
|
|
3928
|
+
var remove = new Command().name("remove").description("disconnect React Grab from your agent").argument(
|
|
3493
3929
|
"[agent]",
|
|
3494
|
-
"agent to remove (claude-code, cursor, opencode, codex, gemini, amp, ami)"
|
|
3930
|
+
"agent to remove (claude-code, cursor, opencode, codex, gemini, amp, ami, mcp)"
|
|
3495
3931
|
).option("-y, --yes", "skip confirmation prompts", false).option(
|
|
3496
3932
|
"-c, --cwd <cwd>",
|
|
3497
3933
|
"working directory (defaults to current directory)",
|
|
@@ -3518,7 +3954,7 @@ var remove = new Command().name("remove").description("remove an agent integrati
|
|
|
3518
3954
|
if (projectInfo.installedAgents.length === 0) {
|
|
3519
3955
|
preflightSpinner.succeed();
|
|
3520
3956
|
logger.break();
|
|
3521
|
-
logger.warn("No agent
|
|
3957
|
+
logger.warn("No agent connections are installed.");
|
|
3522
3958
|
logger.break();
|
|
3523
3959
|
process.exit(0);
|
|
3524
3960
|
}
|
|
@@ -3529,7 +3965,7 @@ var remove = new Command().name("remove").description("remove an agent integrati
|
|
|
3529
3965
|
logger.break();
|
|
3530
3966
|
logger.error(`Agent ${highlighter.info(agentArg)} is not installed.`);
|
|
3531
3967
|
logger.log(
|
|
3532
|
-
`Installed agents: ${projectInfo.installedAgents.map(
|
|
3968
|
+
`Installed agents: ${projectInfo.installedAgents.map(getAgentDisplayName).join(", ")}`
|
|
3533
3969
|
);
|
|
3534
3970
|
logger.break();
|
|
3535
3971
|
process.exit(1);
|
|
@@ -3540,9 +3976,9 @@ var remove = new Command().name("remove").description("remove an agent integrati
|
|
|
3540
3976
|
const { agent } = await prompts({
|
|
3541
3977
|
type: "select",
|
|
3542
3978
|
name: "agent",
|
|
3543
|
-
message: `Which ${highlighter.info("agent
|
|
3979
|
+
message: `Which ${highlighter.info("agent")} would you like to disconnect?`,
|
|
3544
3980
|
choices: projectInfo.installedAgents.map((innerAgent) => ({
|
|
3545
|
-
title:
|
|
3981
|
+
title: getAgentDisplayName(innerAgent),
|
|
3546
3982
|
value: innerAgent
|
|
3547
3983
|
}))
|
|
3548
3984
|
});
|
|
@@ -3561,7 +3997,7 @@ var remove = new Command().name("remove").description("remove an agent integrati
|
|
|
3561
3997
|
process.exit(1);
|
|
3562
3998
|
}
|
|
3563
3999
|
const removingSpinner = spinner(
|
|
3564
|
-
`Preparing to remove ${
|
|
4000
|
+
`Preparing to remove ${getAgentDisplayName(agentToRemove)}.`
|
|
3565
4001
|
).start();
|
|
3566
4002
|
removingSpinner.succeed();
|
|
3567
4003
|
const result = previewAgentRemoval(
|
|
@@ -3658,7 +4094,7 @@ var remove = new Command().name("remove").description("remove an agent integrati
|
|
|
3658
4094
|
}
|
|
3659
4095
|
logger.break();
|
|
3660
4096
|
logger.log(
|
|
3661
|
-
`${highlighter.success("Success!")} ${
|
|
4097
|
+
`${highlighter.success("Success!")} ${getAgentDisplayName(agentToRemove)} has been removed.`
|
|
3662
4098
|
);
|
|
3663
4099
|
logger.break();
|
|
3664
4100
|
} catch (error) {
|
|
@@ -3667,7 +4103,7 @@ var remove = new Command().name("remove").description("remove an agent integrati
|
|
|
3667
4103
|
});
|
|
3668
4104
|
|
|
3669
4105
|
// src/cli.ts
|
|
3670
|
-
var VERSION5 = "0.1.
|
|
4106
|
+
var VERSION5 = "0.1.13";
|
|
3671
4107
|
var VERSION_API_URL = "https://www.react-grab.com/api/version";
|
|
3672
4108
|
process.on("SIGINT", () => process.exit(0));
|
|
3673
4109
|
process.on("SIGTERM", () => process.exit(0));
|