@react-grab/cli 0.0.85 → 0.0.87
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 +417 -24
- package/dist/cli.js +417 -24
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -255,7 +255,7 @@ var AGENT_PACKAGES = [
|
|
|
255
255
|
"@react-grab/gemini",
|
|
256
256
|
"@react-grab/amp",
|
|
257
257
|
"@react-grab/ami",
|
|
258
|
-
"@react-grab/
|
|
258
|
+
"@react-grab/visual-edit"
|
|
259
259
|
];
|
|
260
260
|
var detectUnsupportedFramework = (projectRoot) => {
|
|
261
261
|
const packageJsonPath = path.join(projectRoot, "package.json");
|
|
@@ -1046,11 +1046,11 @@ var AGENT_PREFIXES = {
|
|
|
1046
1046
|
amp: "npx @react-grab/amp@latest &&"
|
|
1047
1047
|
};
|
|
1048
1048
|
var previewPackageJsonTransform = (projectRoot, agent, installedAgents) => {
|
|
1049
|
-
if (agent === "none" || agent === "ami" || agent === "
|
|
1049
|
+
if (agent === "none" || agent === "ami" || agent === "visual-edit") {
|
|
1050
1050
|
return {
|
|
1051
1051
|
success: true,
|
|
1052
1052
|
filePath: "",
|
|
1053
|
-
message: agent === "ami" || agent === "
|
|
1053
|
+
message: agent === "ami" || agent === "visual-edit" ? `${agent === "ami" ? "Ami" : "Visual Edit"} does not require package.json modification` : "No agent selected, skipping package.json modification",
|
|
1054
1054
|
noChanges: true
|
|
1055
1055
|
};
|
|
1056
1056
|
}
|
|
@@ -1137,9 +1137,197 @@ var applyPackageJsonTransform = (result) => {
|
|
|
1137
1137
|
}
|
|
1138
1138
|
return { success: true };
|
|
1139
1139
|
};
|
|
1140
|
+
var formatOptionsForNextjs = (options) => {
|
|
1141
|
+
const parts = [];
|
|
1142
|
+
if (options.activationKey) {
|
|
1143
|
+
const keyParts = [];
|
|
1144
|
+
if (options.activationKey.key)
|
|
1145
|
+
keyParts.push(`key: "${options.activationKey.key}"`);
|
|
1146
|
+
if (options.activationKey.metaKey) keyParts.push("metaKey: true");
|
|
1147
|
+
if (options.activationKey.ctrlKey) keyParts.push("ctrlKey: true");
|
|
1148
|
+
if (options.activationKey.shiftKey) keyParts.push("shiftKey: true");
|
|
1149
|
+
if (options.activationKey.altKey) keyParts.push("altKey: true");
|
|
1150
|
+
if (keyParts.length > 0) {
|
|
1151
|
+
parts.push(`activationKey: { ${keyParts.join(", ")} }`);
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
if (options.activationMode) {
|
|
1155
|
+
parts.push(`activationMode: "${options.activationMode}"`);
|
|
1156
|
+
}
|
|
1157
|
+
if (options.keyHoldDuration !== void 0) {
|
|
1158
|
+
parts.push(`keyHoldDuration: ${options.keyHoldDuration}`);
|
|
1159
|
+
}
|
|
1160
|
+
if (options.allowActivationInsideInput !== void 0) {
|
|
1161
|
+
parts.push(
|
|
1162
|
+
`allowActivationInsideInput: ${options.allowActivationInsideInput}`
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
if (options.maxContextLines !== void 0) {
|
|
1166
|
+
parts.push(`maxContextLines: ${options.maxContextLines}`);
|
|
1167
|
+
}
|
|
1168
|
+
return `{ ${parts.join(", ")} }`;
|
|
1169
|
+
};
|
|
1170
|
+
var formatOptionsAsJson = (options) => {
|
|
1171
|
+
const cleanOptions = {};
|
|
1172
|
+
if (options.activationKey) {
|
|
1173
|
+
const activationKey = {};
|
|
1174
|
+
if (options.activationKey.key) activationKey.key = options.activationKey.key;
|
|
1175
|
+
if (options.activationKey.metaKey) activationKey.metaKey = true;
|
|
1176
|
+
if (options.activationKey.ctrlKey) activationKey.ctrlKey = true;
|
|
1177
|
+
if (options.activationKey.shiftKey) activationKey.shiftKey = true;
|
|
1178
|
+
if (options.activationKey.altKey) activationKey.altKey = true;
|
|
1179
|
+
if (Object.keys(activationKey).length > 0) {
|
|
1180
|
+
cleanOptions.activationKey = activationKey;
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
if (options.activationMode) {
|
|
1184
|
+
cleanOptions.activationMode = options.activationMode;
|
|
1185
|
+
}
|
|
1186
|
+
if (options.keyHoldDuration !== void 0) {
|
|
1187
|
+
cleanOptions.keyHoldDuration = options.keyHoldDuration;
|
|
1188
|
+
}
|
|
1189
|
+
if (options.allowActivationInsideInput !== void 0) {
|
|
1190
|
+
cleanOptions.allowActivationInsideInput = options.allowActivationInsideInput;
|
|
1191
|
+
}
|
|
1192
|
+
if (options.maxContextLines !== void 0) {
|
|
1193
|
+
cleanOptions.maxContextLines = options.maxContextLines;
|
|
1194
|
+
}
|
|
1195
|
+
return JSON.stringify(cleanOptions);
|
|
1196
|
+
};
|
|
1197
|
+
var findReactGrabFile = (projectRoot, framework, nextRouterType) => {
|
|
1198
|
+
switch (framework) {
|
|
1199
|
+
case "next":
|
|
1200
|
+
if (nextRouterType === "app") {
|
|
1201
|
+
return findLayoutFile(projectRoot);
|
|
1202
|
+
}
|
|
1203
|
+
return findDocumentFile(projectRoot);
|
|
1204
|
+
case "vite":
|
|
1205
|
+
return findIndexHtml(projectRoot);
|
|
1206
|
+
case "webpack":
|
|
1207
|
+
return findEntryFile(projectRoot);
|
|
1208
|
+
default:
|
|
1209
|
+
return null;
|
|
1210
|
+
}
|
|
1211
|
+
};
|
|
1212
|
+
var addOptionsToNextScript = (originalContent, options, filePath) => {
|
|
1213
|
+
const reactGrabScriptMatch = originalContent.match(
|
|
1214
|
+
/(<Script[^>]*react-grab[^>]*)(\/?>)/is
|
|
1215
|
+
);
|
|
1216
|
+
if (!reactGrabScriptMatch) {
|
|
1217
|
+
return {
|
|
1218
|
+
success: false,
|
|
1219
|
+
filePath,
|
|
1220
|
+
message: "Could not find React Grab Script tag"
|
|
1221
|
+
};
|
|
1222
|
+
}
|
|
1223
|
+
const scriptTag = reactGrabScriptMatch[0];
|
|
1224
|
+
const scriptOpening = reactGrabScriptMatch[1];
|
|
1225
|
+
const scriptClosing = reactGrabScriptMatch[2];
|
|
1226
|
+
const existingDataOptionsMatch = scriptTag.match(
|
|
1227
|
+
/data-options=\{JSON\.stringify\([^)]+\)\}/
|
|
1228
|
+
);
|
|
1229
|
+
const dataOptionsAttr = `data-options={JSON.stringify(
|
|
1230
|
+
${formatOptionsForNextjs(options)}
|
|
1231
|
+
)}`;
|
|
1232
|
+
let newScriptTag;
|
|
1233
|
+
if (existingDataOptionsMatch) {
|
|
1234
|
+
newScriptTag = scriptTag.replace(existingDataOptionsMatch[0], dataOptionsAttr);
|
|
1235
|
+
} else {
|
|
1236
|
+
newScriptTag = `${scriptOpening}
|
|
1237
|
+
${dataOptionsAttr}
|
|
1238
|
+
${scriptClosing}`;
|
|
1239
|
+
}
|
|
1240
|
+
const newContent = originalContent.replace(scriptTag, newScriptTag);
|
|
1241
|
+
return {
|
|
1242
|
+
success: true,
|
|
1243
|
+
filePath,
|
|
1244
|
+
message: "Update React Grab options",
|
|
1245
|
+
originalContent,
|
|
1246
|
+
newContent
|
|
1247
|
+
};
|
|
1248
|
+
};
|
|
1249
|
+
var addOptionsToViteScript = (originalContent, options, filePath) => {
|
|
1250
|
+
const reactGrabImportMatch = originalContent.match(
|
|
1251
|
+
/import\s*\(\s*["']react-grab["']\s*\)/
|
|
1252
|
+
);
|
|
1253
|
+
if (!reactGrabImportMatch) {
|
|
1254
|
+
return {
|
|
1255
|
+
success: false,
|
|
1256
|
+
filePath,
|
|
1257
|
+
message: "Could not find React Grab import"
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1260
|
+
const optionsJson = formatOptionsAsJson(options);
|
|
1261
|
+
const newImport = `import("react-grab").then((m) => m.init(${optionsJson}))`;
|
|
1262
|
+
const newContent = originalContent.replace(reactGrabImportMatch[0], newImport);
|
|
1263
|
+
return {
|
|
1264
|
+
success: true,
|
|
1265
|
+
filePath,
|
|
1266
|
+
message: "Update React Grab options",
|
|
1267
|
+
originalContent,
|
|
1268
|
+
newContent
|
|
1269
|
+
};
|
|
1270
|
+
};
|
|
1271
|
+
var addOptionsToWebpackImport = (originalContent, options, filePath) => {
|
|
1272
|
+
const reactGrabImportMatch = originalContent.match(
|
|
1273
|
+
/import\s*\(\s*["']react-grab["']\s*\)/
|
|
1274
|
+
);
|
|
1275
|
+
if (!reactGrabImportMatch) {
|
|
1276
|
+
return {
|
|
1277
|
+
success: false,
|
|
1278
|
+
filePath,
|
|
1279
|
+
message: "Could not find React Grab import"
|
|
1280
|
+
};
|
|
1281
|
+
}
|
|
1282
|
+
const optionsJson = formatOptionsAsJson(options);
|
|
1283
|
+
const newImport = `import("react-grab").then((m) => m.init(${optionsJson}))`;
|
|
1284
|
+
const newContent = originalContent.replace(reactGrabImportMatch[0], newImport);
|
|
1285
|
+
return {
|
|
1286
|
+
success: true,
|
|
1287
|
+
filePath,
|
|
1288
|
+
message: "Update React Grab options",
|
|
1289
|
+
originalContent,
|
|
1290
|
+
newContent
|
|
1291
|
+
};
|
|
1292
|
+
};
|
|
1293
|
+
var previewOptionsTransform = (projectRoot, framework, nextRouterType, options) => {
|
|
1294
|
+
const filePath = findReactGrabFile(projectRoot, framework, nextRouterType);
|
|
1295
|
+
if (!filePath) {
|
|
1296
|
+
return {
|
|
1297
|
+
success: false,
|
|
1298
|
+
filePath: "",
|
|
1299
|
+
message: "Could not find file containing React Grab configuration"
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1302
|
+
const originalContent = fs.readFileSync(filePath, "utf-8");
|
|
1303
|
+
if (!hasReactGrabCode(originalContent)) {
|
|
1304
|
+
return {
|
|
1305
|
+
success: false,
|
|
1306
|
+
filePath,
|
|
1307
|
+
message: "Could not find React Grab code in the file"
|
|
1308
|
+
};
|
|
1309
|
+
}
|
|
1310
|
+
switch (framework) {
|
|
1311
|
+
case "next":
|
|
1312
|
+
return addOptionsToNextScript(originalContent, options, filePath);
|
|
1313
|
+
case "vite":
|
|
1314
|
+
return addOptionsToViteScript(originalContent, options, filePath);
|
|
1315
|
+
case "webpack":
|
|
1316
|
+
return addOptionsToWebpackImport(originalContent, options, filePath);
|
|
1317
|
+
default:
|
|
1318
|
+
return {
|
|
1319
|
+
success: false,
|
|
1320
|
+
filePath,
|
|
1321
|
+
message: `Unknown framework: ${framework}`
|
|
1322
|
+
};
|
|
1323
|
+
}
|
|
1324
|
+
};
|
|
1325
|
+
var applyOptionsTransform = (result) => {
|
|
1326
|
+
return applyTransform(result);
|
|
1327
|
+
};
|
|
1140
1328
|
|
|
1141
1329
|
// src/commands/add.ts
|
|
1142
|
-
var VERSION = "0.0.
|
|
1330
|
+
var VERSION = "0.0.87";
|
|
1143
1331
|
var AGENT_NAMES = {
|
|
1144
1332
|
"claude-code": "Claude Code",
|
|
1145
1333
|
cursor: "Cursor",
|
|
@@ -1147,19 +1335,18 @@ var AGENT_NAMES = {
|
|
|
1147
1335
|
codex: "Codex",
|
|
1148
1336
|
gemini: "Gemini",
|
|
1149
1337
|
amp: "Amp",
|
|
1150
|
-
|
|
1151
|
-
instant: "Instant"
|
|
1338
|
+
"visual-edit": "Visual Edit"
|
|
1152
1339
|
};
|
|
1153
1340
|
var add = new commander.Command().name("add").description("add an agent integration").argument(
|
|
1154
1341
|
"[agent]",
|
|
1155
|
-
"agent to add (claude-code, cursor, opencode, codex, gemini, amp,
|
|
1342
|
+
"agent to add (claude-code, cursor, opencode, codex, gemini, amp, visual-edit)"
|
|
1156
1343
|
).option("-y, --yes", "skip confirmation prompts", false).option(
|
|
1157
1344
|
"-c, --cwd <cwd>",
|
|
1158
1345
|
"working directory (defaults to current directory)",
|
|
1159
1346
|
process.cwd()
|
|
1160
1347
|
).action(async (agentArg, opts) => {
|
|
1161
1348
|
console.log(
|
|
1162
|
-
`${pc__default.default.magenta("\
|
|
1349
|
+
`${pc__default.default.magenta("\u273F")} ${pc__default.default.bold("React Grab")} ${pc__default.default.gray(VERSION)}`
|
|
1163
1350
|
);
|
|
1164
1351
|
console.log();
|
|
1165
1352
|
try {
|
|
@@ -1184,8 +1371,7 @@ var add = new commander.Command().name("add").description("add an agent integrat
|
|
|
1184
1371
|
"codex",
|
|
1185
1372
|
"gemini",
|
|
1186
1373
|
"amp",
|
|
1187
|
-
"
|
|
1188
|
-
"instant"
|
|
1374
|
+
"visual-edit"
|
|
1189
1375
|
].filter((agent) => !projectInfo.installedAgents.includes(agent));
|
|
1190
1376
|
if (availableAgents.length === 0) {
|
|
1191
1377
|
logger.break();
|
|
@@ -1202,13 +1388,12 @@ var add = new commander.Command().name("add").description("add an agent integrat
|
|
|
1202
1388
|
"codex",
|
|
1203
1389
|
"gemini",
|
|
1204
1390
|
"amp",
|
|
1205
|
-
"
|
|
1206
|
-
"instant"
|
|
1391
|
+
"visual-edit"
|
|
1207
1392
|
].includes(agentArg)) {
|
|
1208
1393
|
logger.break();
|
|
1209
1394
|
logger.error(`Invalid agent: ${agentArg}`);
|
|
1210
1395
|
logger.error(
|
|
1211
|
-
"Available agents: claude-code, cursor, opencode, codex, gemini, amp,
|
|
1396
|
+
"Available agents: claude-code, cursor, opencode, codex, gemini, amp, visual-edit"
|
|
1212
1397
|
);
|
|
1213
1398
|
logger.break();
|
|
1214
1399
|
process.exit(1);
|
|
@@ -1357,7 +1542,215 @@ var add = new commander.Command().name("add").description("add an agent integrat
|
|
|
1357
1542
|
handleError(error);
|
|
1358
1543
|
}
|
|
1359
1544
|
});
|
|
1360
|
-
var VERSION2 = "0.0.
|
|
1545
|
+
var VERSION2 = "0.0.87";
|
|
1546
|
+
var MODIFIER_KEY_NAMES = {
|
|
1547
|
+
metaKey: process.platform === "darwin" ? "\u2318 Command" : "\u229E Windows",
|
|
1548
|
+
ctrlKey: "Ctrl",
|
|
1549
|
+
shiftKey: "Shift",
|
|
1550
|
+
altKey: process.platform === "darwin" ? "\u2325 Option" : "Alt"
|
|
1551
|
+
};
|
|
1552
|
+
var formatActivationKey = (activationKey) => {
|
|
1553
|
+
if (!activationKey) return "Default (Option/Alt)";
|
|
1554
|
+
const parts = [];
|
|
1555
|
+
if (activationKey.metaKey) parts.push(process.platform === "darwin" ? "\u2318" : "Win");
|
|
1556
|
+
if (activationKey.ctrlKey) parts.push("Ctrl");
|
|
1557
|
+
if (activationKey.shiftKey) parts.push("Shift");
|
|
1558
|
+
if (activationKey.altKey) parts.push(process.platform === "darwin" ? "\u2325" : "Alt");
|
|
1559
|
+
if (activationKey.key) parts.push(activationKey.key.toUpperCase());
|
|
1560
|
+
return parts.length > 0 ? parts.join(" + ") : "Default (Option/Alt)";
|
|
1561
|
+
};
|
|
1562
|
+
var configure = new commander.Command().name("configure").alias("config").description("configure React Grab options").option("-y, --yes", "skip confirmation prompts", false).option(
|
|
1563
|
+
"-c, --cwd <cwd>",
|
|
1564
|
+
"working directory (defaults to current directory)",
|
|
1565
|
+
process.cwd()
|
|
1566
|
+
).action(async (opts) => {
|
|
1567
|
+
console.log(
|
|
1568
|
+
`${pc__default.default.magenta("\u273F")} ${pc__default.default.bold("React Grab")} ${pc__default.default.gray(VERSION2)}`
|
|
1569
|
+
);
|
|
1570
|
+
console.log();
|
|
1571
|
+
try {
|
|
1572
|
+
const cwd = opts.cwd;
|
|
1573
|
+
const isNonInteractive = opts.yes;
|
|
1574
|
+
const preflightSpinner = spinner("Preflight checks.").start();
|
|
1575
|
+
const projectInfo = await detectProject(cwd);
|
|
1576
|
+
if (!projectInfo.hasReactGrab) {
|
|
1577
|
+
preflightSpinner.fail("React Grab is not installed.");
|
|
1578
|
+
logger.break();
|
|
1579
|
+
logger.error(
|
|
1580
|
+
`Run ${highlighter.info("react-grab init")} first to install React Grab.`
|
|
1581
|
+
);
|
|
1582
|
+
logger.break();
|
|
1583
|
+
process.exit(1);
|
|
1584
|
+
}
|
|
1585
|
+
preflightSpinner.succeed();
|
|
1586
|
+
if (isNonInteractive) {
|
|
1587
|
+
logger.break();
|
|
1588
|
+
logger.error("Configure command requires interactive mode.");
|
|
1589
|
+
logger.error("Remove the --yes flag to use interactive prompts.");
|
|
1590
|
+
logger.break();
|
|
1591
|
+
process.exit(1);
|
|
1592
|
+
}
|
|
1593
|
+
logger.break();
|
|
1594
|
+
logger.log(`Configure ${highlighter.info("React Grab")} options:`);
|
|
1595
|
+
logger.break();
|
|
1596
|
+
const collectedOptions = {};
|
|
1597
|
+
const { wantActivationKey } = await prompts2__default.default({
|
|
1598
|
+
type: "confirm",
|
|
1599
|
+
name: "wantActivationKey",
|
|
1600
|
+
message: `Configure ${highlighter.info("activation key")}?`,
|
|
1601
|
+
initial: false
|
|
1602
|
+
});
|
|
1603
|
+
if (wantActivationKey === void 0) {
|
|
1604
|
+
logger.break();
|
|
1605
|
+
process.exit(1);
|
|
1606
|
+
}
|
|
1607
|
+
if (wantActivationKey) {
|
|
1608
|
+
const { key } = await prompts2__default.default({
|
|
1609
|
+
type: "text",
|
|
1610
|
+
name: "key",
|
|
1611
|
+
message: "Enter the activation key (e.g., g, k, space):",
|
|
1612
|
+
initial: ""
|
|
1613
|
+
});
|
|
1614
|
+
if (key === void 0) {
|
|
1615
|
+
logger.break();
|
|
1616
|
+
process.exit(1);
|
|
1617
|
+
}
|
|
1618
|
+
const { modifiers } = await prompts2__default.default({
|
|
1619
|
+
type: "multiselect",
|
|
1620
|
+
name: "modifiers",
|
|
1621
|
+
message: "Select modifier keys (space to select, enter to confirm):",
|
|
1622
|
+
choices: [
|
|
1623
|
+
{ title: MODIFIER_KEY_NAMES.metaKey, value: "metaKey" },
|
|
1624
|
+
{ title: MODIFIER_KEY_NAMES.ctrlKey, value: "ctrlKey" },
|
|
1625
|
+
{ title: MODIFIER_KEY_NAMES.shiftKey, value: "shiftKey" },
|
|
1626
|
+
{ title: MODIFIER_KEY_NAMES.altKey, value: "altKey", selected: true }
|
|
1627
|
+
],
|
|
1628
|
+
hint: "- Space to select, Enter to confirm"
|
|
1629
|
+
});
|
|
1630
|
+
if (modifiers === void 0) {
|
|
1631
|
+
logger.break();
|
|
1632
|
+
process.exit(1);
|
|
1633
|
+
}
|
|
1634
|
+
collectedOptions.activationKey = {
|
|
1635
|
+
...key && { key: key.toLowerCase() },
|
|
1636
|
+
...modifiers.includes("metaKey") && { metaKey: true },
|
|
1637
|
+
...modifiers.includes("ctrlKey") && { ctrlKey: true },
|
|
1638
|
+
...modifiers.includes("shiftKey") && { shiftKey: true },
|
|
1639
|
+
...modifiers.includes("altKey") && { altKey: true }
|
|
1640
|
+
};
|
|
1641
|
+
logger.log(
|
|
1642
|
+
` Activation key: ${highlighter.info(formatActivationKey(collectedOptions.activationKey))}`
|
|
1643
|
+
);
|
|
1644
|
+
}
|
|
1645
|
+
const { activationMode } = await prompts2__default.default({
|
|
1646
|
+
type: "select",
|
|
1647
|
+
name: "activationMode",
|
|
1648
|
+
message: `Select ${highlighter.info("activation mode")}:`,
|
|
1649
|
+
choices: [
|
|
1650
|
+
{ title: "Toggle (press to activate/deactivate)", value: "toggle" },
|
|
1651
|
+
{ title: "Hold (hold key to keep active)", value: "hold" }
|
|
1652
|
+
],
|
|
1653
|
+
initial: 0
|
|
1654
|
+
});
|
|
1655
|
+
if (activationMode === void 0) {
|
|
1656
|
+
logger.break();
|
|
1657
|
+
process.exit(1);
|
|
1658
|
+
}
|
|
1659
|
+
collectedOptions.activationMode = activationMode;
|
|
1660
|
+
if (activationMode === "hold") {
|
|
1661
|
+
const { keyHoldDuration } = await prompts2__default.default({
|
|
1662
|
+
type: "number",
|
|
1663
|
+
name: "keyHoldDuration",
|
|
1664
|
+
message: `Enter ${highlighter.info("key hold duration")} in milliseconds:`,
|
|
1665
|
+
initial: 150,
|
|
1666
|
+
min: 0,
|
|
1667
|
+
max: 2e3
|
|
1668
|
+
});
|
|
1669
|
+
if (keyHoldDuration === void 0) {
|
|
1670
|
+
logger.break();
|
|
1671
|
+
process.exit(1);
|
|
1672
|
+
}
|
|
1673
|
+
collectedOptions.keyHoldDuration = keyHoldDuration;
|
|
1674
|
+
}
|
|
1675
|
+
const { allowActivationInsideInput } = await prompts2__default.default({
|
|
1676
|
+
type: "confirm",
|
|
1677
|
+
name: "allowActivationInsideInput",
|
|
1678
|
+
message: `Allow activation ${highlighter.info("inside input fields")}?`,
|
|
1679
|
+
initial: true
|
|
1680
|
+
});
|
|
1681
|
+
if (allowActivationInsideInput === void 0) {
|
|
1682
|
+
logger.break();
|
|
1683
|
+
process.exit(1);
|
|
1684
|
+
}
|
|
1685
|
+
collectedOptions.allowActivationInsideInput = allowActivationInsideInput;
|
|
1686
|
+
const { maxContextLines } = await prompts2__default.default({
|
|
1687
|
+
type: "number",
|
|
1688
|
+
name: "maxContextLines",
|
|
1689
|
+
message: `Enter ${highlighter.info("max context lines")} to include:`,
|
|
1690
|
+
initial: 3,
|
|
1691
|
+
min: 0,
|
|
1692
|
+
max: 50
|
|
1693
|
+
});
|
|
1694
|
+
if (maxContextLines === void 0) {
|
|
1695
|
+
logger.break();
|
|
1696
|
+
process.exit(1);
|
|
1697
|
+
}
|
|
1698
|
+
collectedOptions.maxContextLines = maxContextLines;
|
|
1699
|
+
const result = previewOptionsTransform(
|
|
1700
|
+
projectInfo.projectRoot,
|
|
1701
|
+
projectInfo.framework,
|
|
1702
|
+
projectInfo.nextRouterType,
|
|
1703
|
+
collectedOptions
|
|
1704
|
+
);
|
|
1705
|
+
if (!result.success) {
|
|
1706
|
+
logger.break();
|
|
1707
|
+
logger.error(result.message);
|
|
1708
|
+
logger.break();
|
|
1709
|
+
process.exit(1);
|
|
1710
|
+
}
|
|
1711
|
+
const hasChanges = !result.noChanges && result.originalContent && result.newContent;
|
|
1712
|
+
if (hasChanges) {
|
|
1713
|
+
logger.break();
|
|
1714
|
+
printDiff(result.filePath, result.originalContent, result.newContent);
|
|
1715
|
+
logger.break();
|
|
1716
|
+
const { proceed } = await prompts2__default.default({
|
|
1717
|
+
type: "confirm",
|
|
1718
|
+
name: "proceed",
|
|
1719
|
+
message: "Apply these changes?",
|
|
1720
|
+
initial: true
|
|
1721
|
+
});
|
|
1722
|
+
if (!proceed) {
|
|
1723
|
+
logger.break();
|
|
1724
|
+
logger.log("Changes cancelled.");
|
|
1725
|
+
logger.break();
|
|
1726
|
+
process.exit(0);
|
|
1727
|
+
}
|
|
1728
|
+
const writeSpinner = spinner(
|
|
1729
|
+
`Applying changes to ${result.filePath}.`
|
|
1730
|
+
).start();
|
|
1731
|
+
const writeResult = applyOptionsTransform(result);
|
|
1732
|
+
if (!writeResult.success) {
|
|
1733
|
+
writeSpinner.fail();
|
|
1734
|
+
logger.break();
|
|
1735
|
+
logger.error(writeResult.error || "Failed to write file.");
|
|
1736
|
+
logger.break();
|
|
1737
|
+
process.exit(1);
|
|
1738
|
+
}
|
|
1739
|
+
writeSpinner.succeed();
|
|
1740
|
+
} else {
|
|
1741
|
+
logger.break();
|
|
1742
|
+
logger.log("No changes needed.");
|
|
1743
|
+
}
|
|
1744
|
+
logger.break();
|
|
1745
|
+
logger.log(
|
|
1746
|
+
`${highlighter.success("Success!")} React Grab options have been configured.`
|
|
1747
|
+
);
|
|
1748
|
+
logger.break();
|
|
1749
|
+
} catch (error) {
|
|
1750
|
+
handleError(error);
|
|
1751
|
+
}
|
|
1752
|
+
});
|
|
1753
|
+
var VERSION3 = "0.0.87";
|
|
1361
1754
|
var REPORT_URL = "https://react-grab.com/api/report-cli";
|
|
1362
1755
|
var DOCS_URL = "https://github.com/aidenybai/react-grab";
|
|
1363
1756
|
var reportToCli = async (type, config, error) => {
|
|
@@ -1367,7 +1760,7 @@ var reportToCli = async (type, config, error) => {
|
|
|
1367
1760
|
headers: { "Content-Type": "application/json" },
|
|
1368
1761
|
body: JSON.stringify({
|
|
1369
1762
|
type,
|
|
1370
|
-
version:
|
|
1763
|
+
version: VERSION3,
|
|
1371
1764
|
config,
|
|
1372
1765
|
error: error ? { message: error.message, stack: error.stack } : void 0,
|
|
1373
1766
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -1397,14 +1790,14 @@ var UNSUPPORTED_FRAMEWORK_NAMES = {
|
|
|
1397
1790
|
};
|
|
1398
1791
|
var init = new commander.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(
|
|
1399
1792
|
"-a, --agent <agent>",
|
|
1400
|
-
"agent integration (claude-code, cursor, opencode, codex, gemini, amp,
|
|
1793
|
+
"agent integration (claude-code, cursor, opencode, codex, gemini, amp, visual-edit)"
|
|
1401
1794
|
).option("--skip-install", "skip package installation", false).option(
|
|
1402
1795
|
"-c, --cwd <cwd>",
|
|
1403
1796
|
"working directory (defaults to current directory)",
|
|
1404
1797
|
process.cwd()
|
|
1405
1798
|
).action(async (opts) => {
|
|
1406
1799
|
console.log(
|
|
1407
|
-
`${pc__default.default.magenta("\
|
|
1800
|
+
`${pc__default.default.magenta("\u273F")} ${pc__default.default.bold("React Grab")} ${pc__default.default.gray(VERSION3)}`
|
|
1408
1801
|
);
|
|
1409
1802
|
console.log();
|
|
1410
1803
|
try {
|
|
@@ -1528,8 +1921,7 @@ var init = new commander.Command().name("init").description("initialize React Gr
|
|
|
1528
1921
|
{ title: "Codex", value: "codex" },
|
|
1529
1922
|
{ title: "Gemini", value: "gemini" },
|
|
1530
1923
|
{ title: "Amp", value: "amp" },
|
|
1531
|
-
{ title: "
|
|
1532
|
-
{ title: "Instant", value: "instant" }
|
|
1924
|
+
{ title: "Visual Edit", value: "visual-edit" }
|
|
1533
1925
|
]
|
|
1534
1926
|
});
|
|
1535
1927
|
if (agent === void 0) {
|
|
@@ -1667,7 +2059,7 @@ var init = new commander.Command().name("init").description("initialize React Gr
|
|
|
1667
2059
|
await reportToCli("error", void 0, error);
|
|
1668
2060
|
}
|
|
1669
2061
|
});
|
|
1670
|
-
var
|
|
2062
|
+
var VERSION4 = "0.0.87";
|
|
1671
2063
|
var DEFAULT_PROXY_PORT = 2e3;
|
|
1672
2064
|
var REACT_GRAB_SCRIPT = '<script src="//unpkg.com/react-grab/dist/index.global.js"></script>';
|
|
1673
2065
|
var buildProviderScript = (provider) => `<script src="//unpkg.com/${provider}/dist/client.global.js"></script>`;
|
|
@@ -1712,7 +2104,7 @@ var start = new commander.Command().name("start").alias("proxy").description("st
|
|
|
1712
2104
|
"provider package to run via npx (e.g., @react-grab/cursor)"
|
|
1713
2105
|
).action(async (urlArg, opts) => {
|
|
1714
2106
|
console.log(
|
|
1715
|
-
`${pc__default.default.magenta("\
|
|
2107
|
+
`${pc__default.default.magenta("\u273F")} ${pc__default.default.bold("React Grab")} ${pc__default.default.gray(VERSION4)}`
|
|
1716
2108
|
);
|
|
1717
2109
|
console.log();
|
|
1718
2110
|
let url = urlArg;
|
|
@@ -1742,7 +2134,7 @@ var start = new commander.Command().name("start").alias("proxy").description("st
|
|
|
1742
2134
|
{ title: "Codex", value: "@react-grab/codex" },
|
|
1743
2135
|
{ title: "Gemini", value: "@react-grab/gemini" },
|
|
1744
2136
|
{ title: "Amp", value: "@react-grab/amp" },
|
|
1745
|
-
{ title: "
|
|
2137
|
+
{ title: "Visual Edit", value: "@react-grab/visual-edit" }
|
|
1746
2138
|
]
|
|
1747
2139
|
});
|
|
1748
2140
|
if (selectedProvider === void 0) {
|
|
@@ -1892,7 +2284,7 @@ var start = new commander.Command().name("start").alias("proxy").description("st
|
|
|
1892
2284
|
});
|
|
1893
2285
|
|
|
1894
2286
|
// src/cli.ts
|
|
1895
|
-
var
|
|
2287
|
+
var VERSION5 = "0.0.87";
|
|
1896
2288
|
var VERSION_API_URL = "https://www.react-grab.com/api/version";
|
|
1897
2289
|
process.on("SIGINT", () => process.exit(0));
|
|
1898
2290
|
process.on("SIGTERM", () => process.exit(0));
|
|
@@ -1901,8 +2293,9 @@ try {
|
|
|
1901
2293
|
});
|
|
1902
2294
|
} catch {
|
|
1903
2295
|
}
|
|
1904
|
-
var program = new commander.Command().name("react-grab").description("add React Grab to your project").version(
|
|
2296
|
+
var program = new commander.Command().name("react-grab").description("add React Grab to your project").version(VERSION5, "-v, --version", "display the version number");
|
|
1905
2297
|
program.addCommand(init);
|
|
1906
2298
|
program.addCommand(add);
|
|
2299
|
+
program.addCommand(configure);
|
|
1907
2300
|
program.addCommand(start);
|
|
1908
2301
|
program.parse();
|
package/dist/cli.js
CHANGED
|
@@ -247,7 +247,7 @@ var AGENT_PACKAGES = [
|
|
|
247
247
|
"@react-grab/gemini",
|
|
248
248
|
"@react-grab/amp",
|
|
249
249
|
"@react-grab/ami",
|
|
250
|
-
"@react-grab/
|
|
250
|
+
"@react-grab/visual-edit"
|
|
251
251
|
];
|
|
252
252
|
var detectUnsupportedFramework = (projectRoot) => {
|
|
253
253
|
const packageJsonPath = join(projectRoot, "package.json");
|
|
@@ -1038,11 +1038,11 @@ var AGENT_PREFIXES = {
|
|
|
1038
1038
|
amp: "npx @react-grab/amp@latest &&"
|
|
1039
1039
|
};
|
|
1040
1040
|
var previewPackageJsonTransform = (projectRoot, agent, installedAgents) => {
|
|
1041
|
-
if (agent === "none" || agent === "ami" || agent === "
|
|
1041
|
+
if (agent === "none" || agent === "ami" || agent === "visual-edit") {
|
|
1042
1042
|
return {
|
|
1043
1043
|
success: true,
|
|
1044
1044
|
filePath: "",
|
|
1045
|
-
message: agent === "ami" || agent === "
|
|
1045
|
+
message: agent === "ami" || agent === "visual-edit" ? `${agent === "ami" ? "Ami" : "Visual Edit"} does not require package.json modification` : "No agent selected, skipping package.json modification",
|
|
1046
1046
|
noChanges: true
|
|
1047
1047
|
};
|
|
1048
1048
|
}
|
|
@@ -1129,9 +1129,197 @@ var applyPackageJsonTransform = (result) => {
|
|
|
1129
1129
|
}
|
|
1130
1130
|
return { success: true };
|
|
1131
1131
|
};
|
|
1132
|
+
var formatOptionsForNextjs = (options) => {
|
|
1133
|
+
const parts = [];
|
|
1134
|
+
if (options.activationKey) {
|
|
1135
|
+
const keyParts = [];
|
|
1136
|
+
if (options.activationKey.key)
|
|
1137
|
+
keyParts.push(`key: "${options.activationKey.key}"`);
|
|
1138
|
+
if (options.activationKey.metaKey) keyParts.push("metaKey: true");
|
|
1139
|
+
if (options.activationKey.ctrlKey) keyParts.push("ctrlKey: true");
|
|
1140
|
+
if (options.activationKey.shiftKey) keyParts.push("shiftKey: true");
|
|
1141
|
+
if (options.activationKey.altKey) keyParts.push("altKey: true");
|
|
1142
|
+
if (keyParts.length > 0) {
|
|
1143
|
+
parts.push(`activationKey: { ${keyParts.join(", ")} }`);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
if (options.activationMode) {
|
|
1147
|
+
parts.push(`activationMode: "${options.activationMode}"`);
|
|
1148
|
+
}
|
|
1149
|
+
if (options.keyHoldDuration !== void 0) {
|
|
1150
|
+
parts.push(`keyHoldDuration: ${options.keyHoldDuration}`);
|
|
1151
|
+
}
|
|
1152
|
+
if (options.allowActivationInsideInput !== void 0) {
|
|
1153
|
+
parts.push(
|
|
1154
|
+
`allowActivationInsideInput: ${options.allowActivationInsideInput}`
|
|
1155
|
+
);
|
|
1156
|
+
}
|
|
1157
|
+
if (options.maxContextLines !== void 0) {
|
|
1158
|
+
parts.push(`maxContextLines: ${options.maxContextLines}`);
|
|
1159
|
+
}
|
|
1160
|
+
return `{ ${parts.join(", ")} }`;
|
|
1161
|
+
};
|
|
1162
|
+
var formatOptionsAsJson = (options) => {
|
|
1163
|
+
const cleanOptions = {};
|
|
1164
|
+
if (options.activationKey) {
|
|
1165
|
+
const activationKey = {};
|
|
1166
|
+
if (options.activationKey.key) activationKey.key = options.activationKey.key;
|
|
1167
|
+
if (options.activationKey.metaKey) activationKey.metaKey = true;
|
|
1168
|
+
if (options.activationKey.ctrlKey) activationKey.ctrlKey = true;
|
|
1169
|
+
if (options.activationKey.shiftKey) activationKey.shiftKey = true;
|
|
1170
|
+
if (options.activationKey.altKey) activationKey.altKey = true;
|
|
1171
|
+
if (Object.keys(activationKey).length > 0) {
|
|
1172
|
+
cleanOptions.activationKey = activationKey;
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
if (options.activationMode) {
|
|
1176
|
+
cleanOptions.activationMode = options.activationMode;
|
|
1177
|
+
}
|
|
1178
|
+
if (options.keyHoldDuration !== void 0) {
|
|
1179
|
+
cleanOptions.keyHoldDuration = options.keyHoldDuration;
|
|
1180
|
+
}
|
|
1181
|
+
if (options.allowActivationInsideInput !== void 0) {
|
|
1182
|
+
cleanOptions.allowActivationInsideInput = options.allowActivationInsideInput;
|
|
1183
|
+
}
|
|
1184
|
+
if (options.maxContextLines !== void 0) {
|
|
1185
|
+
cleanOptions.maxContextLines = options.maxContextLines;
|
|
1186
|
+
}
|
|
1187
|
+
return JSON.stringify(cleanOptions);
|
|
1188
|
+
};
|
|
1189
|
+
var findReactGrabFile = (projectRoot, framework, nextRouterType) => {
|
|
1190
|
+
switch (framework) {
|
|
1191
|
+
case "next":
|
|
1192
|
+
if (nextRouterType === "app") {
|
|
1193
|
+
return findLayoutFile(projectRoot);
|
|
1194
|
+
}
|
|
1195
|
+
return findDocumentFile(projectRoot);
|
|
1196
|
+
case "vite":
|
|
1197
|
+
return findIndexHtml(projectRoot);
|
|
1198
|
+
case "webpack":
|
|
1199
|
+
return findEntryFile(projectRoot);
|
|
1200
|
+
default:
|
|
1201
|
+
return null;
|
|
1202
|
+
}
|
|
1203
|
+
};
|
|
1204
|
+
var addOptionsToNextScript = (originalContent, options, filePath) => {
|
|
1205
|
+
const reactGrabScriptMatch = originalContent.match(
|
|
1206
|
+
/(<Script[^>]*react-grab[^>]*)(\/?>)/is
|
|
1207
|
+
);
|
|
1208
|
+
if (!reactGrabScriptMatch) {
|
|
1209
|
+
return {
|
|
1210
|
+
success: false,
|
|
1211
|
+
filePath,
|
|
1212
|
+
message: "Could not find React Grab Script tag"
|
|
1213
|
+
};
|
|
1214
|
+
}
|
|
1215
|
+
const scriptTag = reactGrabScriptMatch[0];
|
|
1216
|
+
const scriptOpening = reactGrabScriptMatch[1];
|
|
1217
|
+
const scriptClosing = reactGrabScriptMatch[2];
|
|
1218
|
+
const existingDataOptionsMatch = scriptTag.match(
|
|
1219
|
+
/data-options=\{JSON\.stringify\([^)]+\)\}/
|
|
1220
|
+
);
|
|
1221
|
+
const dataOptionsAttr = `data-options={JSON.stringify(
|
|
1222
|
+
${formatOptionsForNextjs(options)}
|
|
1223
|
+
)}`;
|
|
1224
|
+
let newScriptTag;
|
|
1225
|
+
if (existingDataOptionsMatch) {
|
|
1226
|
+
newScriptTag = scriptTag.replace(existingDataOptionsMatch[0], dataOptionsAttr);
|
|
1227
|
+
} else {
|
|
1228
|
+
newScriptTag = `${scriptOpening}
|
|
1229
|
+
${dataOptionsAttr}
|
|
1230
|
+
${scriptClosing}`;
|
|
1231
|
+
}
|
|
1232
|
+
const newContent = originalContent.replace(scriptTag, newScriptTag);
|
|
1233
|
+
return {
|
|
1234
|
+
success: true,
|
|
1235
|
+
filePath,
|
|
1236
|
+
message: "Update React Grab options",
|
|
1237
|
+
originalContent,
|
|
1238
|
+
newContent
|
|
1239
|
+
};
|
|
1240
|
+
};
|
|
1241
|
+
var addOptionsToViteScript = (originalContent, options, filePath) => {
|
|
1242
|
+
const reactGrabImportMatch = originalContent.match(
|
|
1243
|
+
/import\s*\(\s*["']react-grab["']\s*\)/
|
|
1244
|
+
);
|
|
1245
|
+
if (!reactGrabImportMatch) {
|
|
1246
|
+
return {
|
|
1247
|
+
success: false,
|
|
1248
|
+
filePath,
|
|
1249
|
+
message: "Could not find React Grab import"
|
|
1250
|
+
};
|
|
1251
|
+
}
|
|
1252
|
+
const optionsJson = formatOptionsAsJson(options);
|
|
1253
|
+
const newImport = `import("react-grab").then((m) => m.init(${optionsJson}))`;
|
|
1254
|
+
const newContent = originalContent.replace(reactGrabImportMatch[0], newImport);
|
|
1255
|
+
return {
|
|
1256
|
+
success: true,
|
|
1257
|
+
filePath,
|
|
1258
|
+
message: "Update React Grab options",
|
|
1259
|
+
originalContent,
|
|
1260
|
+
newContent
|
|
1261
|
+
};
|
|
1262
|
+
};
|
|
1263
|
+
var addOptionsToWebpackImport = (originalContent, options, filePath) => {
|
|
1264
|
+
const reactGrabImportMatch = originalContent.match(
|
|
1265
|
+
/import\s*\(\s*["']react-grab["']\s*\)/
|
|
1266
|
+
);
|
|
1267
|
+
if (!reactGrabImportMatch) {
|
|
1268
|
+
return {
|
|
1269
|
+
success: false,
|
|
1270
|
+
filePath,
|
|
1271
|
+
message: "Could not find React Grab import"
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
const optionsJson = formatOptionsAsJson(options);
|
|
1275
|
+
const newImport = `import("react-grab").then((m) => m.init(${optionsJson}))`;
|
|
1276
|
+
const newContent = originalContent.replace(reactGrabImportMatch[0], newImport);
|
|
1277
|
+
return {
|
|
1278
|
+
success: true,
|
|
1279
|
+
filePath,
|
|
1280
|
+
message: "Update React Grab options",
|
|
1281
|
+
originalContent,
|
|
1282
|
+
newContent
|
|
1283
|
+
};
|
|
1284
|
+
};
|
|
1285
|
+
var previewOptionsTransform = (projectRoot, framework, nextRouterType, options) => {
|
|
1286
|
+
const filePath = findReactGrabFile(projectRoot, framework, nextRouterType);
|
|
1287
|
+
if (!filePath) {
|
|
1288
|
+
return {
|
|
1289
|
+
success: false,
|
|
1290
|
+
filePath: "",
|
|
1291
|
+
message: "Could not find file containing React Grab configuration"
|
|
1292
|
+
};
|
|
1293
|
+
}
|
|
1294
|
+
const originalContent = readFileSync(filePath, "utf-8");
|
|
1295
|
+
if (!hasReactGrabCode(originalContent)) {
|
|
1296
|
+
return {
|
|
1297
|
+
success: false,
|
|
1298
|
+
filePath,
|
|
1299
|
+
message: "Could not find React Grab code in the file"
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1302
|
+
switch (framework) {
|
|
1303
|
+
case "next":
|
|
1304
|
+
return addOptionsToNextScript(originalContent, options, filePath);
|
|
1305
|
+
case "vite":
|
|
1306
|
+
return addOptionsToViteScript(originalContent, options, filePath);
|
|
1307
|
+
case "webpack":
|
|
1308
|
+
return addOptionsToWebpackImport(originalContent, options, filePath);
|
|
1309
|
+
default:
|
|
1310
|
+
return {
|
|
1311
|
+
success: false,
|
|
1312
|
+
filePath,
|
|
1313
|
+
message: `Unknown framework: ${framework}`
|
|
1314
|
+
};
|
|
1315
|
+
}
|
|
1316
|
+
};
|
|
1317
|
+
var applyOptionsTransform = (result) => {
|
|
1318
|
+
return applyTransform(result);
|
|
1319
|
+
};
|
|
1132
1320
|
|
|
1133
1321
|
// src/commands/add.ts
|
|
1134
|
-
var VERSION = "0.0.
|
|
1322
|
+
var VERSION = "0.0.87";
|
|
1135
1323
|
var AGENT_NAMES = {
|
|
1136
1324
|
"claude-code": "Claude Code",
|
|
1137
1325
|
cursor: "Cursor",
|
|
@@ -1139,19 +1327,18 @@ var AGENT_NAMES = {
|
|
|
1139
1327
|
codex: "Codex",
|
|
1140
1328
|
gemini: "Gemini",
|
|
1141
1329
|
amp: "Amp",
|
|
1142
|
-
|
|
1143
|
-
instant: "Instant"
|
|
1330
|
+
"visual-edit": "Visual Edit"
|
|
1144
1331
|
};
|
|
1145
1332
|
var add = new Command().name("add").description("add an agent integration").argument(
|
|
1146
1333
|
"[agent]",
|
|
1147
|
-
"agent to add (claude-code, cursor, opencode, codex, gemini, amp,
|
|
1334
|
+
"agent to add (claude-code, cursor, opencode, codex, gemini, amp, visual-edit)"
|
|
1148
1335
|
).option("-y, --yes", "skip confirmation prompts", false).option(
|
|
1149
1336
|
"-c, --cwd <cwd>",
|
|
1150
1337
|
"working directory (defaults to current directory)",
|
|
1151
1338
|
process.cwd()
|
|
1152
1339
|
).action(async (agentArg, opts) => {
|
|
1153
1340
|
console.log(
|
|
1154
|
-
`${pc.magenta("\
|
|
1341
|
+
`${pc.magenta("\u273F")} ${pc.bold("React Grab")} ${pc.gray(VERSION)}`
|
|
1155
1342
|
);
|
|
1156
1343
|
console.log();
|
|
1157
1344
|
try {
|
|
@@ -1176,8 +1363,7 @@ var add = new Command().name("add").description("add an agent integration").argu
|
|
|
1176
1363
|
"codex",
|
|
1177
1364
|
"gemini",
|
|
1178
1365
|
"amp",
|
|
1179
|
-
"
|
|
1180
|
-
"instant"
|
|
1366
|
+
"visual-edit"
|
|
1181
1367
|
].filter((agent) => !projectInfo.installedAgents.includes(agent));
|
|
1182
1368
|
if (availableAgents.length === 0) {
|
|
1183
1369
|
logger.break();
|
|
@@ -1194,13 +1380,12 @@ var add = new Command().name("add").description("add an agent integration").argu
|
|
|
1194
1380
|
"codex",
|
|
1195
1381
|
"gemini",
|
|
1196
1382
|
"amp",
|
|
1197
|
-
"
|
|
1198
|
-
"instant"
|
|
1383
|
+
"visual-edit"
|
|
1199
1384
|
].includes(agentArg)) {
|
|
1200
1385
|
logger.break();
|
|
1201
1386
|
logger.error(`Invalid agent: ${agentArg}`);
|
|
1202
1387
|
logger.error(
|
|
1203
|
-
"Available agents: claude-code, cursor, opencode, codex, gemini, amp,
|
|
1388
|
+
"Available agents: claude-code, cursor, opencode, codex, gemini, amp, visual-edit"
|
|
1204
1389
|
);
|
|
1205
1390
|
logger.break();
|
|
1206
1391
|
process.exit(1);
|
|
@@ -1349,7 +1534,215 @@ var add = new Command().name("add").description("add an agent integration").argu
|
|
|
1349
1534
|
handleError(error);
|
|
1350
1535
|
}
|
|
1351
1536
|
});
|
|
1352
|
-
var VERSION2 = "0.0.
|
|
1537
|
+
var VERSION2 = "0.0.87";
|
|
1538
|
+
var MODIFIER_KEY_NAMES = {
|
|
1539
|
+
metaKey: process.platform === "darwin" ? "\u2318 Command" : "\u229E Windows",
|
|
1540
|
+
ctrlKey: "Ctrl",
|
|
1541
|
+
shiftKey: "Shift",
|
|
1542
|
+
altKey: process.platform === "darwin" ? "\u2325 Option" : "Alt"
|
|
1543
|
+
};
|
|
1544
|
+
var formatActivationKey = (activationKey) => {
|
|
1545
|
+
if (!activationKey) return "Default (Option/Alt)";
|
|
1546
|
+
const parts = [];
|
|
1547
|
+
if (activationKey.metaKey) parts.push(process.platform === "darwin" ? "\u2318" : "Win");
|
|
1548
|
+
if (activationKey.ctrlKey) parts.push("Ctrl");
|
|
1549
|
+
if (activationKey.shiftKey) parts.push("Shift");
|
|
1550
|
+
if (activationKey.altKey) parts.push(process.platform === "darwin" ? "\u2325" : "Alt");
|
|
1551
|
+
if (activationKey.key) parts.push(activationKey.key.toUpperCase());
|
|
1552
|
+
return parts.length > 0 ? parts.join(" + ") : "Default (Option/Alt)";
|
|
1553
|
+
};
|
|
1554
|
+
var configure = new Command().name("configure").alias("config").description("configure React Grab options").option("-y, --yes", "skip confirmation prompts", false).option(
|
|
1555
|
+
"-c, --cwd <cwd>",
|
|
1556
|
+
"working directory (defaults to current directory)",
|
|
1557
|
+
process.cwd()
|
|
1558
|
+
).action(async (opts) => {
|
|
1559
|
+
console.log(
|
|
1560
|
+
`${pc.magenta("\u273F")} ${pc.bold("React Grab")} ${pc.gray(VERSION2)}`
|
|
1561
|
+
);
|
|
1562
|
+
console.log();
|
|
1563
|
+
try {
|
|
1564
|
+
const cwd = opts.cwd;
|
|
1565
|
+
const isNonInteractive = opts.yes;
|
|
1566
|
+
const preflightSpinner = spinner("Preflight checks.").start();
|
|
1567
|
+
const projectInfo = await detectProject(cwd);
|
|
1568
|
+
if (!projectInfo.hasReactGrab) {
|
|
1569
|
+
preflightSpinner.fail("React Grab is not installed.");
|
|
1570
|
+
logger.break();
|
|
1571
|
+
logger.error(
|
|
1572
|
+
`Run ${highlighter.info("react-grab init")} first to install React Grab.`
|
|
1573
|
+
);
|
|
1574
|
+
logger.break();
|
|
1575
|
+
process.exit(1);
|
|
1576
|
+
}
|
|
1577
|
+
preflightSpinner.succeed();
|
|
1578
|
+
if (isNonInteractive) {
|
|
1579
|
+
logger.break();
|
|
1580
|
+
logger.error("Configure command requires interactive mode.");
|
|
1581
|
+
logger.error("Remove the --yes flag to use interactive prompts.");
|
|
1582
|
+
logger.break();
|
|
1583
|
+
process.exit(1);
|
|
1584
|
+
}
|
|
1585
|
+
logger.break();
|
|
1586
|
+
logger.log(`Configure ${highlighter.info("React Grab")} options:`);
|
|
1587
|
+
logger.break();
|
|
1588
|
+
const collectedOptions = {};
|
|
1589
|
+
const { wantActivationKey } = await prompts2({
|
|
1590
|
+
type: "confirm",
|
|
1591
|
+
name: "wantActivationKey",
|
|
1592
|
+
message: `Configure ${highlighter.info("activation key")}?`,
|
|
1593
|
+
initial: false
|
|
1594
|
+
});
|
|
1595
|
+
if (wantActivationKey === void 0) {
|
|
1596
|
+
logger.break();
|
|
1597
|
+
process.exit(1);
|
|
1598
|
+
}
|
|
1599
|
+
if (wantActivationKey) {
|
|
1600
|
+
const { key } = await prompts2({
|
|
1601
|
+
type: "text",
|
|
1602
|
+
name: "key",
|
|
1603
|
+
message: "Enter the activation key (e.g., g, k, space):",
|
|
1604
|
+
initial: ""
|
|
1605
|
+
});
|
|
1606
|
+
if (key === void 0) {
|
|
1607
|
+
logger.break();
|
|
1608
|
+
process.exit(1);
|
|
1609
|
+
}
|
|
1610
|
+
const { modifiers } = await prompts2({
|
|
1611
|
+
type: "multiselect",
|
|
1612
|
+
name: "modifiers",
|
|
1613
|
+
message: "Select modifier keys (space to select, enter to confirm):",
|
|
1614
|
+
choices: [
|
|
1615
|
+
{ title: MODIFIER_KEY_NAMES.metaKey, value: "metaKey" },
|
|
1616
|
+
{ title: MODIFIER_KEY_NAMES.ctrlKey, value: "ctrlKey" },
|
|
1617
|
+
{ title: MODIFIER_KEY_NAMES.shiftKey, value: "shiftKey" },
|
|
1618
|
+
{ title: MODIFIER_KEY_NAMES.altKey, value: "altKey", selected: true }
|
|
1619
|
+
],
|
|
1620
|
+
hint: "- Space to select, Enter to confirm"
|
|
1621
|
+
});
|
|
1622
|
+
if (modifiers === void 0) {
|
|
1623
|
+
logger.break();
|
|
1624
|
+
process.exit(1);
|
|
1625
|
+
}
|
|
1626
|
+
collectedOptions.activationKey = {
|
|
1627
|
+
...key && { key: key.toLowerCase() },
|
|
1628
|
+
...modifiers.includes("metaKey") && { metaKey: true },
|
|
1629
|
+
...modifiers.includes("ctrlKey") && { ctrlKey: true },
|
|
1630
|
+
...modifiers.includes("shiftKey") && { shiftKey: true },
|
|
1631
|
+
...modifiers.includes("altKey") && { altKey: true }
|
|
1632
|
+
};
|
|
1633
|
+
logger.log(
|
|
1634
|
+
` Activation key: ${highlighter.info(formatActivationKey(collectedOptions.activationKey))}`
|
|
1635
|
+
);
|
|
1636
|
+
}
|
|
1637
|
+
const { activationMode } = await prompts2({
|
|
1638
|
+
type: "select",
|
|
1639
|
+
name: "activationMode",
|
|
1640
|
+
message: `Select ${highlighter.info("activation mode")}:`,
|
|
1641
|
+
choices: [
|
|
1642
|
+
{ title: "Toggle (press to activate/deactivate)", value: "toggle" },
|
|
1643
|
+
{ title: "Hold (hold key to keep active)", value: "hold" }
|
|
1644
|
+
],
|
|
1645
|
+
initial: 0
|
|
1646
|
+
});
|
|
1647
|
+
if (activationMode === void 0) {
|
|
1648
|
+
logger.break();
|
|
1649
|
+
process.exit(1);
|
|
1650
|
+
}
|
|
1651
|
+
collectedOptions.activationMode = activationMode;
|
|
1652
|
+
if (activationMode === "hold") {
|
|
1653
|
+
const { keyHoldDuration } = await prompts2({
|
|
1654
|
+
type: "number",
|
|
1655
|
+
name: "keyHoldDuration",
|
|
1656
|
+
message: `Enter ${highlighter.info("key hold duration")} in milliseconds:`,
|
|
1657
|
+
initial: 150,
|
|
1658
|
+
min: 0,
|
|
1659
|
+
max: 2e3
|
|
1660
|
+
});
|
|
1661
|
+
if (keyHoldDuration === void 0) {
|
|
1662
|
+
logger.break();
|
|
1663
|
+
process.exit(1);
|
|
1664
|
+
}
|
|
1665
|
+
collectedOptions.keyHoldDuration = keyHoldDuration;
|
|
1666
|
+
}
|
|
1667
|
+
const { allowActivationInsideInput } = await prompts2({
|
|
1668
|
+
type: "confirm",
|
|
1669
|
+
name: "allowActivationInsideInput",
|
|
1670
|
+
message: `Allow activation ${highlighter.info("inside input fields")}?`,
|
|
1671
|
+
initial: true
|
|
1672
|
+
});
|
|
1673
|
+
if (allowActivationInsideInput === void 0) {
|
|
1674
|
+
logger.break();
|
|
1675
|
+
process.exit(1);
|
|
1676
|
+
}
|
|
1677
|
+
collectedOptions.allowActivationInsideInput = allowActivationInsideInput;
|
|
1678
|
+
const { maxContextLines } = await prompts2({
|
|
1679
|
+
type: "number",
|
|
1680
|
+
name: "maxContextLines",
|
|
1681
|
+
message: `Enter ${highlighter.info("max context lines")} to include:`,
|
|
1682
|
+
initial: 3,
|
|
1683
|
+
min: 0,
|
|
1684
|
+
max: 50
|
|
1685
|
+
});
|
|
1686
|
+
if (maxContextLines === void 0) {
|
|
1687
|
+
logger.break();
|
|
1688
|
+
process.exit(1);
|
|
1689
|
+
}
|
|
1690
|
+
collectedOptions.maxContextLines = maxContextLines;
|
|
1691
|
+
const result = previewOptionsTransform(
|
|
1692
|
+
projectInfo.projectRoot,
|
|
1693
|
+
projectInfo.framework,
|
|
1694
|
+
projectInfo.nextRouterType,
|
|
1695
|
+
collectedOptions
|
|
1696
|
+
);
|
|
1697
|
+
if (!result.success) {
|
|
1698
|
+
logger.break();
|
|
1699
|
+
logger.error(result.message);
|
|
1700
|
+
logger.break();
|
|
1701
|
+
process.exit(1);
|
|
1702
|
+
}
|
|
1703
|
+
const hasChanges = !result.noChanges && result.originalContent && result.newContent;
|
|
1704
|
+
if (hasChanges) {
|
|
1705
|
+
logger.break();
|
|
1706
|
+
printDiff(result.filePath, result.originalContent, result.newContent);
|
|
1707
|
+
logger.break();
|
|
1708
|
+
const { proceed } = await prompts2({
|
|
1709
|
+
type: "confirm",
|
|
1710
|
+
name: "proceed",
|
|
1711
|
+
message: "Apply these changes?",
|
|
1712
|
+
initial: true
|
|
1713
|
+
});
|
|
1714
|
+
if (!proceed) {
|
|
1715
|
+
logger.break();
|
|
1716
|
+
logger.log("Changes cancelled.");
|
|
1717
|
+
logger.break();
|
|
1718
|
+
process.exit(0);
|
|
1719
|
+
}
|
|
1720
|
+
const writeSpinner = spinner(
|
|
1721
|
+
`Applying changes to ${result.filePath}.`
|
|
1722
|
+
).start();
|
|
1723
|
+
const writeResult = applyOptionsTransform(result);
|
|
1724
|
+
if (!writeResult.success) {
|
|
1725
|
+
writeSpinner.fail();
|
|
1726
|
+
logger.break();
|
|
1727
|
+
logger.error(writeResult.error || "Failed to write file.");
|
|
1728
|
+
logger.break();
|
|
1729
|
+
process.exit(1);
|
|
1730
|
+
}
|
|
1731
|
+
writeSpinner.succeed();
|
|
1732
|
+
} else {
|
|
1733
|
+
logger.break();
|
|
1734
|
+
logger.log("No changes needed.");
|
|
1735
|
+
}
|
|
1736
|
+
logger.break();
|
|
1737
|
+
logger.log(
|
|
1738
|
+
`${highlighter.success("Success!")} React Grab options have been configured.`
|
|
1739
|
+
);
|
|
1740
|
+
logger.break();
|
|
1741
|
+
} catch (error) {
|
|
1742
|
+
handleError(error);
|
|
1743
|
+
}
|
|
1744
|
+
});
|
|
1745
|
+
var VERSION3 = "0.0.87";
|
|
1353
1746
|
var REPORT_URL = "https://react-grab.com/api/report-cli";
|
|
1354
1747
|
var DOCS_URL = "https://github.com/aidenybai/react-grab";
|
|
1355
1748
|
var reportToCli = async (type, config, error) => {
|
|
@@ -1359,7 +1752,7 @@ var reportToCli = async (type, config, error) => {
|
|
|
1359
1752
|
headers: { "Content-Type": "application/json" },
|
|
1360
1753
|
body: JSON.stringify({
|
|
1361
1754
|
type,
|
|
1362
|
-
version:
|
|
1755
|
+
version: VERSION3,
|
|
1363
1756
|
config,
|
|
1364
1757
|
error: error ? { message: error.message, stack: error.stack } : void 0,
|
|
1365
1758
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -1389,14 +1782,14 @@ var UNSUPPORTED_FRAMEWORK_NAMES = {
|
|
|
1389
1782
|
};
|
|
1390
1783
|
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(
|
|
1391
1784
|
"-a, --agent <agent>",
|
|
1392
|
-
"agent integration (claude-code, cursor, opencode, codex, gemini, amp,
|
|
1785
|
+
"agent integration (claude-code, cursor, opencode, codex, gemini, amp, visual-edit)"
|
|
1393
1786
|
).option("--skip-install", "skip package installation", false).option(
|
|
1394
1787
|
"-c, --cwd <cwd>",
|
|
1395
1788
|
"working directory (defaults to current directory)",
|
|
1396
1789
|
process.cwd()
|
|
1397
1790
|
).action(async (opts) => {
|
|
1398
1791
|
console.log(
|
|
1399
|
-
`${pc.magenta("\
|
|
1792
|
+
`${pc.magenta("\u273F")} ${pc.bold("React Grab")} ${pc.gray(VERSION3)}`
|
|
1400
1793
|
);
|
|
1401
1794
|
console.log();
|
|
1402
1795
|
try {
|
|
@@ -1520,8 +1913,7 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
1520
1913
|
{ title: "Codex", value: "codex" },
|
|
1521
1914
|
{ title: "Gemini", value: "gemini" },
|
|
1522
1915
|
{ title: "Amp", value: "amp" },
|
|
1523
|
-
{ title: "
|
|
1524
|
-
{ title: "Instant", value: "instant" }
|
|
1916
|
+
{ title: "Visual Edit", value: "visual-edit" }
|
|
1525
1917
|
]
|
|
1526
1918
|
});
|
|
1527
1919
|
if (agent === void 0) {
|
|
@@ -1659,7 +2051,7 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
1659
2051
|
await reportToCli("error", void 0, error);
|
|
1660
2052
|
}
|
|
1661
2053
|
});
|
|
1662
|
-
var
|
|
2054
|
+
var VERSION4 = "0.0.87";
|
|
1663
2055
|
var DEFAULT_PROXY_PORT = 2e3;
|
|
1664
2056
|
var REACT_GRAB_SCRIPT = '<script src="//unpkg.com/react-grab/dist/index.global.js"></script>';
|
|
1665
2057
|
var buildProviderScript = (provider) => `<script src="//unpkg.com/${provider}/dist/client.global.js"></script>`;
|
|
@@ -1704,7 +2096,7 @@ var start = new Command().name("start").alias("proxy").description("start a prox
|
|
|
1704
2096
|
"provider package to run via npx (e.g., @react-grab/cursor)"
|
|
1705
2097
|
).action(async (urlArg, opts) => {
|
|
1706
2098
|
console.log(
|
|
1707
|
-
`${pc.magenta("\
|
|
2099
|
+
`${pc.magenta("\u273F")} ${pc.bold("React Grab")} ${pc.gray(VERSION4)}`
|
|
1708
2100
|
);
|
|
1709
2101
|
console.log();
|
|
1710
2102
|
let url = urlArg;
|
|
@@ -1734,7 +2126,7 @@ var start = new Command().name("start").alias("proxy").description("start a prox
|
|
|
1734
2126
|
{ title: "Codex", value: "@react-grab/codex" },
|
|
1735
2127
|
{ title: "Gemini", value: "@react-grab/gemini" },
|
|
1736
2128
|
{ title: "Amp", value: "@react-grab/amp" },
|
|
1737
|
-
{ title: "
|
|
2129
|
+
{ title: "Visual Edit", value: "@react-grab/visual-edit" }
|
|
1738
2130
|
]
|
|
1739
2131
|
});
|
|
1740
2132
|
if (selectedProvider === void 0) {
|
|
@@ -1884,7 +2276,7 @@ var start = new Command().name("start").alias("proxy").description("start a prox
|
|
|
1884
2276
|
});
|
|
1885
2277
|
|
|
1886
2278
|
// src/cli.ts
|
|
1887
|
-
var
|
|
2279
|
+
var VERSION5 = "0.0.87";
|
|
1888
2280
|
var VERSION_API_URL = "https://www.react-grab.com/api/version";
|
|
1889
2281
|
process.on("SIGINT", () => process.exit(0));
|
|
1890
2282
|
process.on("SIGTERM", () => process.exit(0));
|
|
@@ -1893,8 +2285,9 @@ try {
|
|
|
1893
2285
|
});
|
|
1894
2286
|
} catch {
|
|
1895
2287
|
}
|
|
1896
|
-
var program = new Command().name("react-grab").description("add React Grab to your project").version(
|
|
2288
|
+
var program = new Command().name("react-grab").description("add React Grab to your project").version(VERSION5, "-v, --version", "display the version number");
|
|
1897
2289
|
program.addCommand(init);
|
|
1898
2290
|
program.addCommand(add);
|
|
2291
|
+
program.addCommand(configure);
|
|
1899
2292
|
program.addCommand(start);
|
|
1900
2293
|
program.parse();
|