@react-grab/cli 0.1.0-beta.7 → 0.1.0-beta.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -19
- package/dist/cli.cjs +231 -150
- package/dist/cli.js +231 -150
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -127,18 +127,18 @@ var MCP_CLIENTS = [
|
|
|
127
127
|
// "claude",
|
|
128
128
|
];
|
|
129
129
|
var MCP_CLIENT_NAMES = {
|
|
130
|
-
|
|
130
|
+
cursor: "Cursor",
|
|
131
131
|
"claude-code": "Claude Code",
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
vscode: "VSCode",
|
|
133
|
+
opencode: "OpenCode",
|
|
134
|
+
codex: "Codex",
|
|
135
135
|
"gemini-cli": "Gemini CLI",
|
|
136
136
|
// "cline": "Cline",
|
|
137
137
|
// "roo-cline": "Roo Cline",
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
windsurf: "Windsurf",
|
|
139
|
+
zed: "Zed",
|
|
140
140
|
// "warp": "Warp",
|
|
141
|
-
|
|
141
|
+
droid: "Droid"
|
|
142
142
|
// "claude": "Claude Desktop",
|
|
143
143
|
};
|
|
144
144
|
var SKILL_AGENTS = [
|
|
@@ -1258,7 +1258,9 @@ var findSkillAgent = (id) => {
|
|
|
1258
1258
|
};
|
|
1259
1259
|
var formatInstalledAgentNames = (agents) => agents.map((agent) => AGENT_NAMES[agent] ?? agent).join(", ");
|
|
1260
1260
|
var applyTransformWithFeedback = (result, message) => {
|
|
1261
|
-
const writeSpinner = spinner(
|
|
1261
|
+
const writeSpinner = spinner(
|
|
1262
|
+
message ?? `Applying changes to ${result.filePath}.`
|
|
1263
|
+
).start();
|
|
1262
1264
|
const writeResult = applyTransform(result);
|
|
1263
1265
|
if (!writeResult.success) {
|
|
1264
1266
|
writeSpinner.fail();
|
|
@@ -1270,7 +1272,9 @@ var applyTransformWithFeedback = (result, message) => {
|
|
|
1270
1272
|
writeSpinner.succeed();
|
|
1271
1273
|
};
|
|
1272
1274
|
var applyPackageJsonWithFeedback = (result, message) => {
|
|
1273
|
-
const writeSpinner = spinner(
|
|
1275
|
+
const writeSpinner = spinner(
|
|
1276
|
+
message ?? `Applying changes to ${result.filePath}.`
|
|
1277
|
+
).start();
|
|
1274
1278
|
const writeResult = applyPackageJsonTransform(result);
|
|
1275
1279
|
if (!writeResult.success) {
|
|
1276
1280
|
writeSpinner.fail();
|
|
@@ -1702,21 +1706,29 @@ ${BOLD}File: ${filePath}${RESET}`);
|
|
|
1702
1706
|
console.log(formatDiff(diff));
|
|
1703
1707
|
console.log("\u2500".repeat(60));
|
|
1704
1708
|
};
|
|
1705
|
-
var VERSION = "0.1.0-beta.
|
|
1709
|
+
var VERSION = "0.1.0-beta.8";
|
|
1706
1710
|
var configureMcp = (mcpClient, cwd, customPkg) => {
|
|
1707
|
-
const mcpCommand = customPkg ? `npx -y ${customPkg} browser mcp` : `npx -y
|
|
1708
|
-
const mcpSpinner = spinner(
|
|
1711
|
+
const mcpCommand = customPkg ? `npx -y ${customPkg} browser mcp` : `npx -y grab browser mcp`;
|
|
1712
|
+
const mcpSpinner = spinner(
|
|
1713
|
+
`Installing MCP server for ${MCP_CLIENT_NAMES[mcpClient]}`
|
|
1714
|
+
).start();
|
|
1709
1715
|
try {
|
|
1710
|
-
execSync(
|
|
1711
|
-
|
|
1712
|
-
|
|
1716
|
+
execSync(`npx -y install-mcp '${mcpCommand}' --client ${mcpClient} --yes`, {
|
|
1717
|
+
stdio: "ignore",
|
|
1718
|
+
cwd
|
|
1719
|
+
});
|
|
1720
|
+
mcpSpinner.succeed(
|
|
1721
|
+
`MCP server installed for ${MCP_CLIENT_NAMES[mcpClient]}`
|
|
1713
1722
|
);
|
|
1714
|
-
mcpSpinner.succeed(`MCP server installed for ${MCP_CLIENT_NAMES[mcpClient]}`);
|
|
1715
1723
|
logger.break();
|
|
1716
1724
|
process.exit(0);
|
|
1717
1725
|
} catch {
|
|
1718
|
-
mcpSpinner.fail(
|
|
1719
|
-
|
|
1726
|
+
mcpSpinner.fail(
|
|
1727
|
+
`Failed to configure MCP for ${MCP_CLIENT_NAMES[mcpClient]}`
|
|
1728
|
+
);
|
|
1729
|
+
logger.dim(
|
|
1730
|
+
`Try manually: npx -y install-mcp '${mcpCommand}' --client ${mcpClient}`
|
|
1731
|
+
);
|
|
1720
1732
|
logger.break();
|
|
1721
1733
|
process.exit(1);
|
|
1722
1734
|
}
|
|
@@ -1734,21 +1746,17 @@ var installSkill = (agent, cwd) => {
|
|
|
1734
1746
|
process.exit(0);
|
|
1735
1747
|
} catch {
|
|
1736
1748
|
skillSpinner.fail(`Failed to install skill for ${agent.name}`);
|
|
1737
|
-
logger.warn(
|
|
1749
|
+
logger.warn(
|
|
1750
|
+
`Try manually: npx -y add-skill aidenybai/react-grab --agent ${agent.id}`
|
|
1751
|
+
);
|
|
1738
1752
|
logger.break();
|
|
1739
1753
|
process.exit(1);
|
|
1740
1754
|
}
|
|
1741
1755
|
};
|
|
1742
|
-
var add = new Command().name("add").alias("install").description("add browser automation for your AI agent").argument(
|
|
1743
|
-
"[agent]",
|
|
1744
|
-
`agent to add (${AGENTS.join(", ")}, mcp, skill)`
|
|
1745
|
-
).option("-y, --yes", "skip confirmation prompts", false).option(
|
|
1756
|
+
var add = new Command().name("add").alias("install").description("add browser automation for your AI agent").argument("[agent]", `agent to add (${AGENTS.join(", ")}, mcp, skill)`).option("-y, --yes", "skip confirmation prompts", false).option(
|
|
1746
1757
|
"--client <client>",
|
|
1747
1758
|
"MCP client to configure (cursor, claude-code, vscode, etc.)"
|
|
1748
|
-
).option(
|
|
1749
|
-
"--pkg <pkg>",
|
|
1750
|
-
"custom package URL for CLI (e.g., @react-grab/cli)"
|
|
1751
|
-
).option(
|
|
1759
|
+
).option("--pkg <pkg>", "custom package URL for CLI (e.g., grab)").option(
|
|
1752
1760
|
"-c, --cwd <cwd>",
|
|
1753
1761
|
"working directory (defaults to current directory)",
|
|
1754
1762
|
process.cwd()
|
|
@@ -1805,7 +1813,9 @@ var add = new Command().name("add").alias("install").description("add browser au
|
|
|
1805
1813
|
if (clientArg && !selectedAgent) {
|
|
1806
1814
|
logger.break();
|
|
1807
1815
|
logger.error(`Invalid skill agent: ${clientArg}`);
|
|
1808
|
-
logger.error(
|
|
1816
|
+
logger.error(
|
|
1817
|
+
`Available agents: ${SKILL_AGENTS.map((a) => a.id).join(", ")}`
|
|
1818
|
+
);
|
|
1809
1819
|
logger.break();
|
|
1810
1820
|
process.exit(1);
|
|
1811
1821
|
}
|
|
@@ -1813,7 +1823,9 @@ var add = new Command().name("add").alias("install").description("add browser au
|
|
|
1813
1823
|
if (detectedAgents.length === 0) {
|
|
1814
1824
|
logger.break();
|
|
1815
1825
|
logger.warn("No supported agent folders detected.");
|
|
1816
|
-
logger.log(
|
|
1826
|
+
logger.log(
|
|
1827
|
+
"Supported agents: " + SKILL_AGENTS.map((a) => a.id).join(", ")
|
|
1828
|
+
);
|
|
1817
1829
|
logger.break();
|
|
1818
1830
|
process.exit(0);
|
|
1819
1831
|
}
|
|
@@ -1839,7 +1851,9 @@ var add = new Command().name("add").alias("install").description("add browser au
|
|
|
1839
1851
|
if (!selectedAgent) {
|
|
1840
1852
|
logger.break();
|
|
1841
1853
|
logger.error("Please specify an agent with --client");
|
|
1842
|
-
logger.error(
|
|
1854
|
+
logger.error(
|
|
1855
|
+
`Available agents: ${SKILL_AGENTS.map((a) => a.id).join(", ")}`
|
|
1856
|
+
);
|
|
1843
1857
|
logger.break();
|
|
1844
1858
|
process.exit(1);
|
|
1845
1859
|
}
|
|
@@ -1887,14 +1901,20 @@ var add = new Command().name("add").alias("install").description("add browser au
|
|
|
1887
1901
|
logger.break();
|
|
1888
1902
|
process.exit(1);
|
|
1889
1903
|
}
|
|
1890
|
-
configureMcp(
|
|
1904
|
+
configureMcp(
|
|
1905
|
+
client,
|
|
1906
|
+
cwd,
|
|
1907
|
+
opts2.pkg
|
|
1908
|
+
);
|
|
1891
1909
|
}
|
|
1892
1910
|
if (addType === "skill") {
|
|
1893
1911
|
const detectedAgents = detectSkillAgents(cwd);
|
|
1894
1912
|
if (detectedAgents.length === 0) {
|
|
1895
1913
|
logger.break();
|
|
1896
1914
|
logger.warn("No supported agent folders detected.");
|
|
1897
|
-
logger.log(
|
|
1915
|
+
logger.log(
|
|
1916
|
+
"Supported agents: " + SKILL_AGENTS.map((a) => a.id).join(", ")
|
|
1917
|
+
);
|
|
1898
1918
|
logger.break();
|
|
1899
1919
|
process.exit(0);
|
|
1900
1920
|
}
|
|
@@ -2451,9 +2471,14 @@ var createComponentHelper = (getActivePage2) => {
|
|
|
2451
2471
|
async (args) => {
|
|
2452
2472
|
const g2 = globalThis;
|
|
2453
2473
|
if (!g2.__REACT_GRAB_FIND_BY_COMPONENT__) {
|
|
2454
|
-
throw new Error(
|
|
2474
|
+
throw new Error(
|
|
2475
|
+
"React introspection not available. Make sure react-grab is installed."
|
|
2476
|
+
);
|
|
2455
2477
|
}
|
|
2456
|
-
const result = await g2.__REACT_GRAB_FIND_BY_COMPONENT__(
|
|
2478
|
+
const result = await g2.__REACT_GRAB_FIND_BY_COMPONENT__(
|
|
2479
|
+
args.name,
|
|
2480
|
+
args.nth !== void 0 ? { nth: args.nth } : void 0
|
|
2481
|
+
);
|
|
2457
2482
|
if (!result) return null;
|
|
2458
2483
|
if (args.nth !== void 0) {
|
|
2459
2484
|
const single = result;
|
|
@@ -2464,7 +2489,10 @@ var createComponentHelper = (getActivePage2) => {
|
|
|
2464
2489
|
},
|
|
2465
2490
|
{ name: componentName, nth }
|
|
2466
2491
|
);
|
|
2467
|
-
const isNull = await currentPage2.evaluate(
|
|
2492
|
+
const isNull = await currentPage2.evaluate(
|
|
2493
|
+
(value) => value === null,
|
|
2494
|
+
elementHandles
|
|
2495
|
+
);
|
|
2468
2496
|
if (isNull) {
|
|
2469
2497
|
await elementHandles.dispose();
|
|
2470
2498
|
return null;
|
|
@@ -2512,7 +2540,8 @@ var createDragHelper = (getActivePage2) => {
|
|
|
2512
2540
|
}) => {
|
|
2513
2541
|
const fromElement = document.querySelector(fromSel);
|
|
2514
2542
|
const toElement = document.querySelector(toSel);
|
|
2515
|
-
if (!fromElement)
|
|
2543
|
+
if (!fromElement)
|
|
2544
|
+
throw new Error(`Source element not found: ${fromSel}`);
|
|
2516
2545
|
if (!toElement) throw new Error(`Target element not found: ${toSel}`);
|
|
2517
2546
|
const dataTransferObject = new DataTransfer();
|
|
2518
2547
|
for (const [type, value] of Object.entries(data)) {
|
|
@@ -2574,16 +2603,26 @@ var createDispatchHelper = (getActivePage2) => {
|
|
|
2574
2603
|
for (const [type, value] of Object.entries(opts2.dataTransfer)) {
|
|
2575
2604
|
dataTransferObject.setData(type, value);
|
|
2576
2605
|
}
|
|
2577
|
-
return new DragEvent(eventType, {
|
|
2606
|
+
return new DragEvent(eventType, {
|
|
2607
|
+
...baseOpts,
|
|
2608
|
+
dataTransfer: dataTransferObject
|
|
2609
|
+
});
|
|
2578
2610
|
}
|
|
2579
2611
|
if (opts2.detail !== void 0) {
|
|
2580
|
-
return new CustomEvent(eventType, {
|
|
2612
|
+
return new CustomEvent(eventType, {
|
|
2613
|
+
...baseOpts,
|
|
2614
|
+
detail: opts2.detail
|
|
2615
|
+
});
|
|
2581
2616
|
}
|
|
2582
2617
|
return new Event(eventType, baseOpts);
|
|
2583
2618
|
};
|
|
2584
2619
|
return element.dispatchEvent(createEvent());
|
|
2585
2620
|
},
|
|
2586
|
-
{
|
|
2621
|
+
{
|
|
2622
|
+
sel: selector,
|
|
2623
|
+
eventType: event,
|
|
2624
|
+
opts: { bubbles, cancelable, dataTransfer, detail }
|
|
2625
|
+
}
|
|
2587
2626
|
);
|
|
2588
2627
|
};
|
|
2589
2628
|
};
|
|
@@ -2632,11 +2671,16 @@ var createWaitForHelper = (getActivePage2) => {
|
|
|
2632
2671
|
const currentPage2 = getActivePage2();
|
|
2633
2672
|
const timeout = options2?.timeout;
|
|
2634
2673
|
if (LOAD_STATES.has(selectorOrState)) {
|
|
2635
|
-
await currentPage2.waitForLoadState(
|
|
2674
|
+
await currentPage2.waitForLoadState(
|
|
2675
|
+
selectorOrState,
|
|
2676
|
+
{ timeout }
|
|
2677
|
+
);
|
|
2636
2678
|
return;
|
|
2637
2679
|
}
|
|
2638
2680
|
if (/^e\d+$/.test(selectorOrState)) {
|
|
2639
|
-
await currentPage2.waitForSelector(`[aria-ref="${selectorOrState}"]`, {
|
|
2681
|
+
await currentPage2.waitForSelector(`[aria-ref="${selectorOrState}"]`, {
|
|
2682
|
+
timeout
|
|
2683
|
+
});
|
|
2640
2684
|
return;
|
|
2641
2685
|
}
|
|
2642
2686
|
await currentPage2.waitForSelector(selectorOrState, { timeout });
|
|
@@ -16473,7 +16517,9 @@ After getting refs, use browser_execute with: getRef('e1').click()`,
|
|
|
16473
16517
|
screenshot: external_exports.boolean().optional().default(false).describe(
|
|
16474
16518
|
"Viewport screenshot. For element screenshots (PREFERRED), use browser_execute: getRef('eX').screenshot()"
|
|
16475
16519
|
),
|
|
16476
|
-
reactTree: external_exports.boolean().optional().default(false).describe(
|
|
16520
|
+
reactTree: external_exports.boolean().optional().default(false).describe(
|
|
16521
|
+
"(Experimental) React tree view. Note: Regular snapshot already includes [component=X] and [source=X] - prefer that."
|
|
16522
|
+
),
|
|
16477
16523
|
includeProps: external_exports.boolean().optional().default(false).describe("Include props when reactTree=true")
|
|
16478
16524
|
}
|
|
16479
16525
|
},
|
|
@@ -16502,7 +16548,10 @@ After getting refs, use browser_execute with: getRef('e1').click()`,
|
|
|
16502
16548
|
}
|
|
16503
16549
|
return g2.__REACT_GRAB_GET_COMPONENT_TREE__(opts2);
|
|
16504
16550
|
},
|
|
16505
|
-
{
|
|
16551
|
+
{
|
|
16552
|
+
maxDepth: maxDepth ?? DEFAULT_COMPONENT_TREE_MAX_DEPTH,
|
|
16553
|
+
includeProps: includeProps ?? false
|
|
16554
|
+
}
|
|
16506
16555
|
);
|
|
16507
16556
|
const renderTree = (nodes) => {
|
|
16508
16557
|
const lines = [];
|
|
@@ -16523,7 +16572,9 @@ After getting refs, use browser_execute with: getRef('e1').click()`,
|
|
|
16523
16572
|
};
|
|
16524
16573
|
textResult = renderTree(componentTree) || "No React components found. Make sure react-grab is installed and the page uses React.";
|
|
16525
16574
|
} else {
|
|
16526
|
-
textResult = await createSnapshotHelper(() => activePage)({
|
|
16575
|
+
textResult = await createSnapshotHelper(() => activePage)({
|
|
16576
|
+
maxDepth
|
|
16577
|
+
});
|
|
16527
16578
|
}
|
|
16528
16579
|
if (screenshot) {
|
|
16529
16580
|
const screenshotBuffer = await activePage.screenshot({
|
|
@@ -16691,7 +16742,7 @@ PERFORMANCE: Batch multiple actions in one execute call.`,
|
|
|
16691
16742
|
};
|
|
16692
16743
|
|
|
16693
16744
|
// src/commands/browser.ts
|
|
16694
|
-
var VERSION2 = "0.1.0-beta.
|
|
16745
|
+
var VERSION2 = "0.1.0-beta.8";
|
|
16695
16746
|
var printHeader = () => {
|
|
16696
16747
|
console.log(
|
|
16697
16748
|
`${pc.magenta("\u273F")} ${pc.bold("React Grab")} ${pc.gray(VERSION2)}`
|
|
@@ -16757,7 +16808,10 @@ var dump = new Command().name("dump").description("dump cookies from a browser")
|
|
|
16757
16808
|
exitWithError(error48);
|
|
16758
16809
|
}
|
|
16759
16810
|
});
|
|
16760
|
-
var start = new Command().name("start").description("start browser server manually (auto-starts on first execute)").option("-p, --port <port>", "HTTP API port", String(DEFAULT_SERVER_PORT)).option("--headed", "show browser window (default is headless)").option(
|
|
16811
|
+
var start = new Command().name("start").description("start browser server manually (auto-starts on first execute)").option("-p, --port <port>", "HTTP API port", String(DEFAULT_SERVER_PORT)).option("--headed", "show browser window (default is headless)").option(
|
|
16812
|
+
"-b, --browser <browser>",
|
|
16813
|
+
"source browser for cookies (chrome, edge, brave, arc)"
|
|
16814
|
+
).option("-d, --domain <domain>", "only load cookies matching this domain").option("--foreground", "run in foreground instead of detaching").action(async (options2) => {
|
|
16761
16815
|
const isForeground = options2.foreground;
|
|
16762
16816
|
if (!isForeground) {
|
|
16763
16817
|
printHeader();
|
|
@@ -16817,7 +16871,9 @@ var start = new Command().name("start").description("start browser server manual
|
|
|
16817
16871
|
await new Promise(() => {
|
|
16818
16872
|
});
|
|
16819
16873
|
} catch (error48) {
|
|
16820
|
-
console.error(
|
|
16874
|
+
console.error(
|
|
16875
|
+
error48 instanceof Error ? error48.message : "Failed to start server"
|
|
16876
|
+
);
|
|
16821
16877
|
process.exit(1);
|
|
16822
16878
|
}
|
|
16823
16879
|
});
|
|
@@ -16844,17 +16900,21 @@ var status = new Command().name("status").description("check server status").opt
|
|
|
16844
16900
|
const info = getServerInfo();
|
|
16845
16901
|
let pagesData = [];
|
|
16846
16902
|
try {
|
|
16847
|
-
const pagesResponse = await fetch(
|
|
16903
|
+
const pagesResponse = await fetch(
|
|
16904
|
+
`http://127.0.0.1:${info?.port}/pages`
|
|
16905
|
+
);
|
|
16848
16906
|
const pagesResult = await pagesResponse.json();
|
|
16849
16907
|
pagesData = pagesResult.pages;
|
|
16850
16908
|
} catch {
|
|
16851
16909
|
}
|
|
16852
16910
|
if (jsonMode) {
|
|
16853
|
-
console.log(
|
|
16854
|
-
|
|
16855
|
-
|
|
16856
|
-
|
|
16857
|
-
|
|
16911
|
+
console.log(
|
|
16912
|
+
JSON.stringify({
|
|
16913
|
+
running: true,
|
|
16914
|
+
port: info?.port,
|
|
16915
|
+
pages: pagesData
|
|
16916
|
+
})
|
|
16917
|
+
);
|
|
16858
16918
|
} else {
|
|
16859
16919
|
logger.success(`Server running on port ${info?.port}`);
|
|
16860
16920
|
if (pagesData.length > 0) {
|
|
@@ -16867,17 +16927,30 @@ var status = new Command().name("status").description("check server status").opt
|
|
|
16867
16927
|
}
|
|
16868
16928
|
} else {
|
|
16869
16929
|
if (jsonMode) {
|
|
16870
|
-
console.log(
|
|
16871
|
-
|
|
16872
|
-
|
|
16873
|
-
|
|
16874
|
-
|
|
16930
|
+
console.log(
|
|
16931
|
+
JSON.stringify({
|
|
16932
|
+
running: false,
|
|
16933
|
+
port: null,
|
|
16934
|
+
pages: []
|
|
16935
|
+
})
|
|
16936
|
+
);
|
|
16875
16937
|
} else {
|
|
16876
16938
|
logger.log("Server not running");
|
|
16877
16939
|
}
|
|
16878
16940
|
}
|
|
16879
16941
|
});
|
|
16880
|
-
var execute = new Command().name("execute").description("run Playwright code with 'page' variable available").argument(
|
|
16942
|
+
var execute = new Command().name("execute").description("run Playwright code with 'page' variable available").argument(
|
|
16943
|
+
"<code>",
|
|
16944
|
+
"JavaScript code to execute (use 'page' for Playwright Page, 'return' for output)"
|
|
16945
|
+
).option("-b, --browser <browser>", "source browser for cookies").option("-d, --domain <domain>", "filter cookies by domain").option("-u, --url <url>", "navigate to URL before executing").option(
|
|
16946
|
+
"-p, --page <name>",
|
|
16947
|
+
"named page context for multi-turn sessions",
|
|
16948
|
+
"default"
|
|
16949
|
+
).option(
|
|
16950
|
+
"-t, --timeout <ms>",
|
|
16951
|
+
`navigation timeout in milliseconds (default: ${DEFAULT_NAVIGATION_TIMEOUT_MS})`,
|
|
16952
|
+
String(DEFAULT_NAVIGATION_TIMEOUT_MS)
|
|
16953
|
+
).action(async (code, options2) => {
|
|
16881
16954
|
const pageName = options2.page;
|
|
16882
16955
|
const navigationTimeout = parseInt(options2.timeout, 10);
|
|
16883
16956
|
let activePage = null;
|
|
@@ -16943,7 +17016,15 @@ var execute = new Command().name("execute").description("run Playwright code wit
|
|
|
16943
17016
|
);
|
|
16944
17017
|
console.log(JSON.stringify(await outputJson(true, result)));
|
|
16945
17018
|
} catch (error48) {
|
|
16946
|
-
console.log(
|
|
17019
|
+
console.log(
|
|
17020
|
+
JSON.stringify(
|
|
17021
|
+
await outputJson(
|
|
17022
|
+
false,
|
|
17023
|
+
void 0,
|
|
17024
|
+
error48 instanceof Error ? error48.message : "Failed"
|
|
17025
|
+
)
|
|
17026
|
+
)
|
|
17027
|
+
);
|
|
16947
17028
|
exitCode = 1;
|
|
16948
17029
|
} finally {
|
|
16949
17030
|
if (activePage && pageOpenHandler) {
|
|
@@ -16965,13 +17046,19 @@ var pages = new Command().name("pages").description("manage server pages").optio
|
|
|
16965
17046
|
const pagesResponse2 = await fetch(`${serverUrl}/pages`);
|
|
16966
17047
|
const pagesResult2 = await pagesResponse2.json();
|
|
16967
17048
|
for (const pageEntry of pagesResult2.pages) {
|
|
16968
|
-
await fetch(
|
|
17049
|
+
await fetch(
|
|
17050
|
+
`${serverUrl}/pages/${encodeURIComponent(pageEntry.name)}`,
|
|
17051
|
+
{ method: "DELETE" }
|
|
17052
|
+
);
|
|
16969
17053
|
logger.success(`Unregistered ${pageEntry.name}`);
|
|
16970
17054
|
}
|
|
16971
17055
|
return;
|
|
16972
17056
|
}
|
|
16973
17057
|
if (options2.kill) {
|
|
16974
|
-
const deleteResponse = await fetch(
|
|
17058
|
+
const deleteResponse = await fetch(
|
|
17059
|
+
`${serverUrl}/pages/${encodeURIComponent(options2.kill)}`,
|
|
17060
|
+
{ method: "DELETE" }
|
|
17061
|
+
);
|
|
16975
17062
|
if (deleteResponse.ok) {
|
|
16976
17063
|
logger.success(`Unregistered ${options2.kill}`);
|
|
16977
17064
|
} else {
|
|
@@ -17111,7 +17198,9 @@ MULTI-PAGE SESSIONS
|
|
|
17111
17198
|
|
|
17112
17199
|
PLAYWRIGHT DOCS: https://playwright.dev/docs/api/class-page
|
|
17113
17200
|
`;
|
|
17114
|
-
var browser = new Command().name("browser").description(
|
|
17201
|
+
var browser = new Command().name("browser").description(
|
|
17202
|
+
"browser automation with persistent page state and real cookie injection"
|
|
17203
|
+
).addHelpText("after", BROWSER_HELP).action(() => {
|
|
17115
17204
|
browser.help();
|
|
17116
17205
|
});
|
|
17117
17206
|
var mcp = new Command().name("mcp").description("start MCP server for browser automation (stdio transport)").action(async () => {
|
|
@@ -17161,7 +17250,7 @@ browser.addCommand(status);
|
|
|
17161
17250
|
browser.addCommand(execute);
|
|
17162
17251
|
browser.addCommand(pages);
|
|
17163
17252
|
browser.addCommand(mcp);
|
|
17164
|
-
var VERSION3 = "0.1.0-beta.
|
|
17253
|
+
var VERSION3 = "0.1.0-beta.8";
|
|
17165
17254
|
var isMac = process.platform === "darwin";
|
|
17166
17255
|
var META_LABEL = isMac ? "Cmd" : "Win";
|
|
17167
17256
|
var ALT_LABEL = isMac ? "Option" : "Alt";
|
|
@@ -17359,19 +17448,13 @@ var comboToString = (combo) => {
|
|
|
17359
17448
|
var configure = new Command().name("configure").alias("config").description("configure React Grab options").option("-y, --yes", "skip confirmation prompts", false).option(
|
|
17360
17449
|
"-k, --key <key>",
|
|
17361
17450
|
"activation key (e.g., Meta+K, Ctrl+Shift+G, Space)"
|
|
17362
|
-
).option(
|
|
17363
|
-
"-m, --mode <mode>",
|
|
17364
|
-
"activation mode (toggle, hold)"
|
|
17365
|
-
).option(
|
|
17451
|
+
).option("-m, --mode <mode>", "activation mode (toggle, hold)").option(
|
|
17366
17452
|
"--hold-duration <ms>",
|
|
17367
17453
|
"key hold duration in milliseconds (for hold mode)"
|
|
17368
17454
|
).option(
|
|
17369
17455
|
"--allow-input <boolean>",
|
|
17370
17456
|
"allow activation inside input fields (true/false)"
|
|
17371
|
-
).option(
|
|
17372
|
-
"--context-lines <lines>",
|
|
17373
|
-
"max context lines to include"
|
|
17374
|
-
).option(
|
|
17457
|
+
).option("--context-lines <lines>", "max context lines to include").option(
|
|
17375
17458
|
"-c, --cwd <cwd>",
|
|
17376
17459
|
"working directory (defaults to current directory)",
|
|
17377
17460
|
process.cwd()
|
|
@@ -17418,22 +17501,30 @@ var configure = new Command().name("configure").alias("config").description("con
|
|
|
17418
17501
|
if (opts2.holdDuration) {
|
|
17419
17502
|
const duration3 = parseInt(opts2.holdDuration, 10);
|
|
17420
17503
|
if (isNaN(duration3) || duration3 < 0 || duration3 > MAX_KEY_HOLD_DURATION_MS) {
|
|
17421
|
-
logger.error(
|
|
17504
|
+
logger.error(
|
|
17505
|
+
`Invalid hold duration. Must be 0-${MAX_KEY_HOLD_DURATION_MS}ms.`
|
|
17506
|
+
);
|
|
17422
17507
|
logger.break();
|
|
17423
17508
|
process.exit(1);
|
|
17424
17509
|
}
|
|
17425
17510
|
collectedOptions.keyHoldDuration = duration3;
|
|
17426
|
-
logger.log(
|
|
17511
|
+
logger.log(
|
|
17512
|
+
` Key hold duration: ${highlighter.info(`${duration3}ms`)}`
|
|
17513
|
+
);
|
|
17427
17514
|
}
|
|
17428
17515
|
if (opts2.allowInput !== void 0) {
|
|
17429
17516
|
const allowInput = opts2.allowInput === "true" || opts2.allowInput === true;
|
|
17430
17517
|
collectedOptions.allowActivationInsideInput = allowInput;
|
|
17431
|
-
logger.log(
|
|
17518
|
+
logger.log(
|
|
17519
|
+
` Allow activation inside input: ${highlighter.info(String(allowInput))}`
|
|
17520
|
+
);
|
|
17432
17521
|
}
|
|
17433
17522
|
if (opts2.contextLines) {
|
|
17434
17523
|
const lines = parseInt(opts2.contextLines, 10);
|
|
17435
17524
|
if (isNaN(lines) || lines < 0 || lines > MAX_CONTEXT_LINES) {
|
|
17436
|
-
logger.error(
|
|
17525
|
+
logger.error(
|
|
17526
|
+
`Invalid context lines. Must be 0-${MAX_CONTEXT_LINES}.`
|
|
17527
|
+
);
|
|
17437
17528
|
logger.break();
|
|
17438
17529
|
process.exit(1);
|
|
17439
17530
|
}
|
|
@@ -17483,7 +17574,10 @@ var configure = new Command().name("configure").alias("config").description("con
|
|
|
17483
17574
|
name: "activationMode",
|
|
17484
17575
|
message: `Select ${highlighter.info("activation mode")}:`,
|
|
17485
17576
|
choices: [
|
|
17486
|
-
{
|
|
17577
|
+
{
|
|
17578
|
+
title: "Toggle (press to activate/deactivate)",
|
|
17579
|
+
value: "toggle"
|
|
17580
|
+
},
|
|
17487
17581
|
{ title: "Hold (hold key to keep active)", value: "hold" }
|
|
17488
17582
|
],
|
|
17489
17583
|
initial: 0
|
|
@@ -17549,7 +17643,9 @@ var configure = new Command().name("configure").alias("config").description("con
|
|
|
17549
17643
|
logger.warn(result.message);
|
|
17550
17644
|
logger.break();
|
|
17551
17645
|
const configJson = JSON.stringify(collectedOptions);
|
|
17552
|
-
logger.log(
|
|
17646
|
+
logger.log(
|
|
17647
|
+
`Add this to your ${highlighter.info("init()")} call or ${highlighter.info("data-options")} attribute:`
|
|
17648
|
+
);
|
|
17553
17649
|
logger.break();
|
|
17554
17650
|
console.log(` ${pc.cyan(configJson)}`);
|
|
17555
17651
|
logger.break();
|
|
@@ -17599,7 +17695,7 @@ var configure = new Command().name("configure").alias("config").description("con
|
|
|
17599
17695
|
handleError(error48);
|
|
17600
17696
|
}
|
|
17601
17697
|
});
|
|
17602
|
-
var VERSION4 = "0.1.0-beta.
|
|
17698
|
+
var VERSION4 = "0.1.0-beta.8";
|
|
17603
17699
|
var REPORT_URL = "https://react-grab.com/api/report-cli";
|
|
17604
17700
|
var DOCS_URL = "https://github.com/aidenybai/react-grab";
|
|
17605
17701
|
var promptSkillInstall = async (cwd) => {
|
|
@@ -17607,7 +17703,9 @@ var promptSkillInstall = async (cwd) => {
|
|
|
17607
17703
|
if (detectedAgents.length === 0) {
|
|
17608
17704
|
return;
|
|
17609
17705
|
}
|
|
17610
|
-
logger.log(
|
|
17706
|
+
logger.log(
|
|
17707
|
+
`The ${highlighter.info("React Grab skill")} gives your agent access to the browser.`
|
|
17708
|
+
);
|
|
17611
17709
|
logger.log(`Learn more at ${highlighter.info("https://skill.md")}`);
|
|
17612
17710
|
logger.break();
|
|
17613
17711
|
const { wantSkill } = await prompts3({
|
|
@@ -17631,16 +17729,23 @@ var promptSkillInstall = async (cwd) => {
|
|
|
17631
17729
|
});
|
|
17632
17730
|
if (selectedAgent) {
|
|
17633
17731
|
logger.break();
|
|
17634
|
-
const skillSpinner = spinner(
|
|
17732
|
+
const skillSpinner = spinner(
|
|
17733
|
+
`Installing skill for ${selectedAgent.name}`
|
|
17734
|
+
).start();
|
|
17635
17735
|
try {
|
|
17636
|
-
execSync(
|
|
17637
|
-
|
|
17638
|
-
|
|
17639
|
-
|
|
17736
|
+
execSync(
|
|
17737
|
+
`npx -y add-skill aidenybai/react-grab -y --agent ${selectedAgent.id}`,
|
|
17738
|
+
{
|
|
17739
|
+
stdio: "ignore",
|
|
17740
|
+
cwd
|
|
17741
|
+
}
|
|
17742
|
+
);
|
|
17640
17743
|
skillSpinner.succeed(`Skill installed for ${selectedAgent.name}.`);
|
|
17641
17744
|
} catch {
|
|
17642
17745
|
skillSpinner.fail(`Failed to install skill for ${selectedAgent.name}.`);
|
|
17643
|
-
logger.warn(
|
|
17746
|
+
logger.warn(
|
|
17747
|
+
`Try manually: npx -y add-skill aidenybai/react-grab --agent ${selectedAgent.id}`
|
|
17748
|
+
);
|
|
17644
17749
|
}
|
|
17645
17750
|
}
|
|
17646
17751
|
logger.break();
|
|
@@ -17701,10 +17806,7 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
17701
17806
|
).option(
|
|
17702
17807
|
"-k, --key <key>",
|
|
17703
17808
|
"activation key (e.g., Meta+K, Ctrl+Shift+G, Space)"
|
|
17704
|
-
).option("--skip-install", "skip package installation", false).option(
|
|
17705
|
-
"--pkg <pkg>",
|
|
17706
|
-
"custom package URL for CLI (e.g., @react-grab/cli)"
|
|
17707
|
-
).option(
|
|
17809
|
+
).option("--skip-install", "skip package installation", false).option("--pkg <pkg>", "custom package URL for CLI (e.g., grab)").option(
|
|
17708
17810
|
"-c, --cwd <cwd>",
|
|
17709
17811
|
"working directory (defaults to current directory)",
|
|
17710
17812
|
process.cwd()
|
|
@@ -17952,7 +18054,9 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
17952
18054
|
const agentIntegration2 = agent;
|
|
17953
18055
|
let agentsToRemove2 = [];
|
|
17954
18056
|
if (projectInfo.installedAgents.length > 0) {
|
|
17955
|
-
const installedNames = formatInstalledAgentNames(
|
|
18057
|
+
const installedNames = formatInstalledAgentNames(
|
|
18058
|
+
projectInfo.installedAgents
|
|
18059
|
+
);
|
|
17956
18060
|
const { action } = await prompts3({
|
|
17957
18061
|
type: "select",
|
|
17958
18062
|
name: "action",
|
|
@@ -18280,7 +18384,7 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
18280
18384
|
reportToCli("error", void 0, error48);
|
|
18281
18385
|
}
|
|
18282
18386
|
});
|
|
18283
|
-
var VERSION5 = "0.1.0-beta.
|
|
18387
|
+
var VERSION5 = "0.1.0-beta.8";
|
|
18284
18388
|
var remove = new Command().name("remove").description("remove an agent integration").argument(
|
|
18285
18389
|
"[agent]",
|
|
18286
18390
|
"agent to remove (claude-code, cursor, opencode, codex, gemini, amp, ami, visual-edit)"
|
|
@@ -18457,22 +18561,21 @@ var remove = new Command().name("remove").description("remove an agent integrati
|
|
|
18457
18561
|
handleError(error48);
|
|
18458
18562
|
}
|
|
18459
18563
|
});
|
|
18460
|
-
var
|
|
18461
|
-
|
|
18462
|
-
|
|
18463
|
-
|
|
18464
|
-
|
|
18465
|
-
|
|
18466
|
-
|
|
18467
|
-
|
|
18468
|
-
|
|
18469
|
-
|
|
18470
|
-
|
|
18471
|
-
|
|
18472
|
-
|
|
18473
|
-
var execSilent = (command) => {
|
|
18564
|
+
var uninstall = new Command().name("uninstall").description("uninstall React Grab CLI globally").action(() => {
|
|
18565
|
+
console.log("Uninstalling React Grab CLI...");
|
|
18566
|
+
try {
|
|
18567
|
+
execSync("npm uninstall -g grab", { stdio: "inherit" });
|
|
18568
|
+
console.log("React Grab CLI has been uninstalled.");
|
|
18569
|
+
} catch {
|
|
18570
|
+
console.error("Failed to uninstall. Please try: npm uninstall -g grab");
|
|
18571
|
+
process.exit(1);
|
|
18572
|
+
}
|
|
18573
|
+
});
|
|
18574
|
+
var VERSION6 = "0.1.0-beta.8";
|
|
18575
|
+
var UPDATE_COMMAND = "npm install -g grab@latest";
|
|
18576
|
+
var getLatestVersion = () => {
|
|
18474
18577
|
try {
|
|
18475
|
-
return execSync(
|
|
18578
|
+
return execSync("npm view grab version", {
|
|
18476
18579
|
encoding: "utf-8",
|
|
18477
18580
|
stdio: ["pipe", "pipe", "pipe"]
|
|
18478
18581
|
}).trim();
|
|
@@ -18480,47 +18583,24 @@ var execSilent = (command) => {
|
|
|
18480
18583
|
return null;
|
|
18481
18584
|
}
|
|
18482
18585
|
};
|
|
18483
|
-
var
|
|
18484
|
-
const output = execSilent("grab --version");
|
|
18485
|
-
if (!output) return null;
|
|
18486
|
-
const match = output.match(/(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)/);
|
|
18487
|
-
return match ? match[1] : null;
|
|
18488
|
-
};
|
|
18489
|
-
var getLatestVersion = () => execSilent("npm view grab version");
|
|
18490
|
-
var isPackageManagerInstalled = (manager) => execSilent(`${manager} --version`) !== null;
|
|
18491
|
-
var detectGlobalPackageManager = () => {
|
|
18492
|
-
const managers = ["pnpm", "yarn", "bun"];
|
|
18493
|
-
for (const manager of managers) {
|
|
18494
|
-
if (isPackageManagerInstalled(manager)) {
|
|
18495
|
-
return manager;
|
|
18496
|
-
}
|
|
18497
|
-
}
|
|
18498
|
-
return "npm";
|
|
18499
|
-
};
|
|
18500
|
-
var update = new Command().name("update").alias("upgrade").description("update grab to the latest version").option("-y, --yes", "skip confirmation prompts", false).option("--check", "only check for updates, don't install", false).action(async (opts2) => {
|
|
18586
|
+
var update = new Command().name("update").alias("upgrade").description("update React Grab CLI to the latest version").option("-y, --yes", "skip confirmation prompts", false).option("--check", "only check for updates, don't install", false).action(async (opts2) => {
|
|
18501
18587
|
console.log(
|
|
18502
18588
|
`${pc.magenta("\u273F")} ${pc.bold("React Grab")} ${pc.gray(VERSION6)}`
|
|
18503
18589
|
);
|
|
18504
18590
|
console.log();
|
|
18505
18591
|
const checkSpinner = spinner("Checking for updates").start();
|
|
18506
|
-
const installedVersion = getInstalledVersion();
|
|
18507
18592
|
const latestVersion = getLatestVersion();
|
|
18508
18593
|
if (!latestVersion) {
|
|
18509
|
-
checkSpinner.fail("Failed to fetch latest version
|
|
18510
|
-
logger.break();
|
|
18511
|
-
logger.error("Could not reach npm registry. Check your network connection.");
|
|
18512
|
-
logger.break();
|
|
18513
|
-
process.exit(1);
|
|
18514
|
-
}
|
|
18515
|
-
if (!installedVersion) {
|
|
18516
|
-
checkSpinner.fail("grab is not installed globally");
|
|
18594
|
+
checkSpinner.fail("Failed to fetch latest version");
|
|
18517
18595
|
logger.break();
|
|
18518
|
-
logger.
|
|
18596
|
+
logger.error(
|
|
18597
|
+
"Could not reach npm registry. Check your network connection."
|
|
18598
|
+
);
|
|
18519
18599
|
logger.break();
|
|
18520
18600
|
process.exit(1);
|
|
18521
18601
|
}
|
|
18522
|
-
checkSpinner.succeed(`Current version: ${highlighter.info(
|
|
18523
|
-
if (
|
|
18602
|
+
checkSpinner.succeed(`Current version: ${highlighter.info(VERSION6)}`);
|
|
18603
|
+
if (VERSION6 === latestVersion) {
|
|
18524
18604
|
logger.break();
|
|
18525
18605
|
logger.success(`You're already on the latest version (${latestVersion})`);
|
|
18526
18606
|
logger.break();
|
|
@@ -18529,17 +18609,18 @@ var update = new Command().name("update").alias("upgrade").description("update g
|
|
|
18529
18609
|
logger.log(`Latest version: ${highlighter.success(latestVersion)}`);
|
|
18530
18610
|
logger.break();
|
|
18531
18611
|
if (opts2.check) {
|
|
18532
|
-
logger.log(`Update available: ${
|
|
18533
|
-
logger.log(
|
|
18612
|
+
logger.log(`Update available: ${VERSION6} \u2192 ${latestVersion}`);
|
|
18613
|
+
logger.log(
|
|
18614
|
+
`Run ${highlighter.info("grab update")} to install the update.`
|
|
18615
|
+
);
|
|
18534
18616
|
logger.break();
|
|
18535
18617
|
process.exit(0);
|
|
18536
18618
|
}
|
|
18537
|
-
const packageManager = detectGlobalPackageManager();
|
|
18538
18619
|
if (!opts2.yes) {
|
|
18539
18620
|
const { shouldProceed } = await prompts3({
|
|
18540
18621
|
type: "confirm",
|
|
18541
18622
|
name: "shouldProceed",
|
|
18542
|
-
message: `Update
|
|
18623
|
+
message: `Update from ${VERSION6} to ${latestVersion}?`,
|
|
18543
18624
|
initial: true
|
|
18544
18625
|
});
|
|
18545
18626
|
if (!shouldProceed) {
|
|
@@ -18550,20 +18631,19 @@ var update = new Command().name("update").alias("upgrade").description("update g
|
|
|
18550
18631
|
}
|
|
18551
18632
|
}
|
|
18552
18633
|
logger.break();
|
|
18553
|
-
const updateSpinner = spinner(`Updating
|
|
18634
|
+
const updateSpinner = spinner(`Updating to ${latestVersion}`).start();
|
|
18554
18635
|
try {
|
|
18555
|
-
|
|
18556
|
-
|
|
18557
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
18558
|
-
});
|
|
18559
|
-
updateSpinner.succeed(`Updated grab to ${latestVersion}`);
|
|
18636
|
+
execSync(UPDATE_COMMAND, { stdio: ["pipe", "pipe", "pipe"] });
|
|
18637
|
+
updateSpinner.succeed(`Updated to ${latestVersion}`);
|
|
18560
18638
|
logger.break();
|
|
18561
18639
|
logger.success("Update complete!");
|
|
18562
18640
|
logger.break();
|
|
18563
18641
|
} catch (error48) {
|
|
18564
|
-
updateSpinner.fail("Failed to update
|
|
18642
|
+
updateSpinner.fail("Failed to update");
|
|
18565
18643
|
logger.break();
|
|
18566
|
-
logger.error(
|
|
18644
|
+
logger.error(
|
|
18645
|
+
`Update failed. Try manually: ${highlighter.info(UPDATE_COMMAND)}`
|
|
18646
|
+
);
|
|
18567
18647
|
if (error48 instanceof Error && error48.message) {
|
|
18568
18648
|
logger.dim(error48.message);
|
|
18569
18649
|
}
|
|
@@ -18573,7 +18653,7 @@ var update = new Command().name("update").alias("upgrade").description("update g
|
|
|
18573
18653
|
});
|
|
18574
18654
|
|
|
18575
18655
|
// src/cli.ts
|
|
18576
|
-
var VERSION7 = "0.1.0-beta.
|
|
18656
|
+
var VERSION7 = "0.1.0-beta.8";
|
|
18577
18657
|
var VERSION_API_URL = "https://www.react-grab.com/api/version";
|
|
18578
18658
|
process.on("SIGINT", () => process.exit(0));
|
|
18579
18659
|
process.on("SIGTERM", () => process.exit(0));
|
|
@@ -18589,4 +18669,5 @@ program.addCommand(remove);
|
|
|
18589
18669
|
program.addCommand(configure);
|
|
18590
18670
|
program.addCommand(browser);
|
|
18591
18671
|
program.addCommand(update);
|
|
18672
|
+
program.addCommand(uninstall);
|
|
18592
18673
|
program.parse();
|