@react-grab/cli 0.1.0-beta.4 → 0.1.0-beta.5
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 +127 -73
- package/dist/cli.js +127 -73
- package/package.json +2 -2
package/dist/cli.cjs
CHANGED
|
@@ -2707,7 +2707,7 @@ var previewPackageJsonAgentRemoval = (projectRoot, agent) => {
|
|
|
2707
2707
|
};
|
|
2708
2708
|
|
|
2709
2709
|
// src/commands/add.ts
|
|
2710
|
-
var VERSION = "0.1.0-beta.
|
|
2710
|
+
var VERSION = "0.1.0-beta.4";
|
|
2711
2711
|
var add = new commander.Command().name("add").alias("install").description("add an agent integration or MCP server").argument(
|
|
2712
2712
|
"[agent]",
|
|
2713
2713
|
`agent to add (${AGENTS.join(", ")}, mcp, skill)`
|
|
@@ -3385,30 +3385,42 @@ var createRefHelper = (getActivePage2) => {
|
|
|
3385
3385
|
};
|
|
3386
3386
|
const getSource = async (refId) => {
|
|
3387
3387
|
const element = await getElement(refId);
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3388
|
+
try {
|
|
3389
|
+
const currentPage2 = getActivePage2();
|
|
3390
|
+
return await currentPage2.evaluate((el) => {
|
|
3391
|
+
const g2 = globalThis;
|
|
3392
|
+
if (!g2.__REACT_GRAB__) return null;
|
|
3393
|
+
return g2.__REACT_GRAB__.getSource(el);
|
|
3394
|
+
}, element);
|
|
3395
|
+
} finally {
|
|
3396
|
+
await element.dispose();
|
|
3397
|
+
}
|
|
3394
3398
|
};
|
|
3395
3399
|
const getProps = async (refId) => {
|
|
3396
3400
|
const element = await getElement(refId);
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3401
|
+
try {
|
|
3402
|
+
const currentPage2 = getActivePage2();
|
|
3403
|
+
return await currentPage2.evaluate((el) => {
|
|
3404
|
+
const g2 = globalThis;
|
|
3405
|
+
if (!g2.__REACT_GRAB_GET_PROPS__) return null;
|
|
3406
|
+
return g2.__REACT_GRAB_GET_PROPS__(el);
|
|
3407
|
+
}, element);
|
|
3408
|
+
} finally {
|
|
3409
|
+
await element.dispose();
|
|
3410
|
+
}
|
|
3403
3411
|
};
|
|
3404
3412
|
const getState = async (refId) => {
|
|
3405
3413
|
const element = await getElement(refId);
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3414
|
+
try {
|
|
3415
|
+
const currentPage2 = getActivePage2();
|
|
3416
|
+
return await currentPage2.evaluate((el) => {
|
|
3417
|
+
const g2 = globalThis;
|
|
3418
|
+
if (!g2.__REACT_GRAB_GET_STATE__) return null;
|
|
3419
|
+
return g2.__REACT_GRAB_GET_STATE__(el);
|
|
3420
|
+
}, element);
|
|
3421
|
+
} finally {
|
|
3422
|
+
await element.dispose();
|
|
3423
|
+
}
|
|
3412
3424
|
};
|
|
3413
3425
|
return (refId) => {
|
|
3414
3426
|
return new Proxy(
|
|
@@ -3428,13 +3440,23 @@ var createRefHelper = (getActivePage2) => {
|
|
|
3428
3440
|
return () => getState(refId);
|
|
3429
3441
|
}
|
|
3430
3442
|
if (prop === "screenshot") {
|
|
3431
|
-
return (options2) =>
|
|
3432
|
-
|
|
3433
|
-
|
|
3443
|
+
return async (options2) => {
|
|
3444
|
+
const el = await getElement(refId);
|
|
3445
|
+
try {
|
|
3446
|
+
return await el.screenshot({ scale: "css", ...options2 });
|
|
3447
|
+
} finally {
|
|
3448
|
+
await el.dispose();
|
|
3449
|
+
}
|
|
3450
|
+
};
|
|
3434
3451
|
}
|
|
3435
|
-
return (...args) =>
|
|
3436
|
-
|
|
3437
|
-
|
|
3452
|
+
return async (...args) => {
|
|
3453
|
+
const el = await getElement(refId);
|
|
3454
|
+
try {
|
|
3455
|
+
return await el[prop](...args);
|
|
3456
|
+
} finally {
|
|
3457
|
+
await el.dispose();
|
|
3458
|
+
}
|
|
3459
|
+
};
|
|
3438
3460
|
}
|
|
3439
3461
|
}
|
|
3440
3462
|
);
|
|
@@ -3461,8 +3483,8 @@ var createComponentHelper = (getActivePage2) => {
|
|
|
3461
3483
|
},
|
|
3462
3484
|
{ name: componentName, nth }
|
|
3463
3485
|
);
|
|
3464
|
-
const
|
|
3465
|
-
if (
|
|
3486
|
+
const isNull = await currentPage2.evaluate((value) => value === null, elementHandles);
|
|
3487
|
+
if (isNull) {
|
|
3466
3488
|
await elementHandles.dispose();
|
|
3467
3489
|
return null;
|
|
3468
3490
|
}
|
|
@@ -3604,11 +3626,15 @@ var createGrabHelper = (ref, getActivePage2) => {
|
|
|
3604
3626
|
copyElement: async (refId) => {
|
|
3605
3627
|
const element = await ref(refId);
|
|
3606
3628
|
if (!element) return false;
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3629
|
+
try {
|
|
3630
|
+
const currentPage2 = getActivePage2();
|
|
3631
|
+
return await currentPage2.evaluate((el) => {
|
|
3632
|
+
const g2 = globalThis;
|
|
3633
|
+
return g2.__REACT_GRAB__?.copyElement([el]) ?? false;
|
|
3634
|
+
}, element);
|
|
3635
|
+
} finally {
|
|
3636
|
+
await element.dispose();
|
|
3637
|
+
}
|
|
3612
3638
|
}
|
|
3613
3639
|
};
|
|
3614
3640
|
};
|
|
@@ -17455,7 +17481,6 @@ USE VIEWPORT screenshot=true ONLY FOR:
|
|
|
17455
17481
|
|
|
17456
17482
|
PERFORMANCE:
|
|
17457
17483
|
- interactableOnly:true = much smaller output (recommended)
|
|
17458
|
-
- format:'compact' = minimal ref:role:name@Component output
|
|
17459
17484
|
- maxDepth = limit tree depth
|
|
17460
17485
|
|
|
17461
17486
|
After getting refs, use browser_execute with: ref('e1').click()`,
|
|
@@ -17463,7 +17488,6 @@ After getting refs, use browser_execute with: ref('e1').click()`,
|
|
|
17463
17488
|
page: external_exports.string().optional().default("default").describe("Named page context"),
|
|
17464
17489
|
maxDepth: external_exports.number().optional().describe("Limit tree depth"),
|
|
17465
17490
|
interactableOnly: external_exports.boolean().optional().describe("Only clickable/input elements (recommended)"),
|
|
17466
|
-
format: external_exports.enum(["yaml", "compact"]).optional().default("yaml").describe("'yaml' or 'compact'"),
|
|
17467
17491
|
screenshot: external_exports.boolean().optional().default(false).describe(
|
|
17468
17492
|
"Viewport screenshot. For element screenshots (PREFERRED), use browser_execute: ref('eX').screenshot()"
|
|
17469
17493
|
)
|
|
@@ -17473,7 +17497,6 @@ After getting refs, use browser_execute with: ref('e1').click()`,
|
|
|
17473
17497
|
page: pageName,
|
|
17474
17498
|
maxDepth,
|
|
17475
17499
|
interactableOnly,
|
|
17476
|
-
format,
|
|
17477
17500
|
screenshot
|
|
17478
17501
|
}) => {
|
|
17479
17502
|
let browser2 = null;
|
|
@@ -17483,7 +17506,7 @@ After getting refs, use browser_execute with: ref('e1').click()`,
|
|
|
17483
17506
|
const activePage = connection.page;
|
|
17484
17507
|
const getActivePage2 = () => activePage;
|
|
17485
17508
|
const snapshot = createSnapshotHelper(getActivePage2);
|
|
17486
|
-
const snapshotResult = await snapshot({ maxDepth, interactableOnly
|
|
17509
|
+
const snapshotResult = await snapshot({ maxDepth, interactableOnly });
|
|
17487
17510
|
if (screenshot) {
|
|
17488
17511
|
const screenshotBuffer = await activePage.screenshot({
|
|
17489
17512
|
fullPage: false,
|
|
@@ -17519,7 +17542,7 @@ IMPORTANT: Always call snapshot() first to get element refs from the a11y tree (
|
|
|
17519
17542
|
|
|
17520
17543
|
AVAILABLE HELPERS:
|
|
17521
17544
|
- page: Playwright Page object (https://playwright.dev/docs/api/class-page)
|
|
17522
|
-
- snapshot(opts?): Get ARIA tree with React component info. opts: {maxDepth, interactableOnly
|
|
17545
|
+
- snapshot(opts?): Get ARIA tree with React component info. opts: {maxDepth, interactableOnly}
|
|
17523
17546
|
- ref(id): Get element by ref ID, chainable with all ElementHandle methods
|
|
17524
17547
|
- ref(id).source(): Get React component source {filePath, lineNumber, componentName}
|
|
17525
17548
|
- ref(id).props(): Get React component props (serialized)
|
|
@@ -17722,7 +17745,7 @@ For interacting with elements, use browser_snapshot to get refs first.`,
|
|
|
17722
17745
|
};
|
|
17723
17746
|
|
|
17724
17747
|
// src/commands/browser.ts
|
|
17725
|
-
var VERSION2 = "0.1.0-beta.
|
|
17748
|
+
var VERSION2 = "0.1.0-beta.4";
|
|
17726
17749
|
var printHeader = () => {
|
|
17727
17750
|
console.log(
|
|
17728
17751
|
`${pc__default.default.magenta("\u273F")} ${pc__default.default.bold("React Grab")} ${pc__default.default.gray(VERSION2)}`
|
|
@@ -17745,6 +17768,10 @@ var rebuildNativeModuleAndRestart = async (browserPkgDir) => {
|
|
|
17745
17768
|
stdio: "inherit",
|
|
17746
17769
|
detached: false
|
|
17747
17770
|
});
|
|
17771
|
+
child.on("error", (error48) => {
|
|
17772
|
+
console.error(`Failed to restart: ${error48.message}`);
|
|
17773
|
+
process.exit(1);
|
|
17774
|
+
});
|
|
17748
17775
|
child.on("exit", (code) => process.exit(code ?? 0));
|
|
17749
17776
|
};
|
|
17750
17777
|
var isSupportedBrowser = (value) => {
|
|
@@ -17843,8 +17870,10 @@ var start = new commander.Command().name("start").description("start browser ser
|
|
|
17843
17870
|
const playwrightCookies = browser$1.toPlaywrightCookies(cookies);
|
|
17844
17871
|
const browser2 = await playwrightCore.chromium.connectOverCDP(browserServer.wsEndpoint);
|
|
17845
17872
|
const contexts = browser2.contexts();
|
|
17846
|
-
if (contexts.length > 0
|
|
17847
|
-
|
|
17873
|
+
if (contexts.length > 0) {
|
|
17874
|
+
if (playwrightCookies.length > 0) {
|
|
17875
|
+
await contexts[0].addCookies(playwrightCookies);
|
|
17876
|
+
}
|
|
17848
17877
|
await browser$1.applyStealthScripts(contexts[0]);
|
|
17849
17878
|
}
|
|
17850
17879
|
await browser2.close();
|
|
@@ -17976,6 +18005,7 @@ var execute = new commander.Command().name("execute").description("run Playwrigh
|
|
|
17976
18005
|
const dispatch = createDispatchHelper(getActivePage2);
|
|
17977
18006
|
const grab = createGrabHelper(ref, getActivePage2);
|
|
17978
18007
|
const waitFor = createWaitForHelper(getActivePage2);
|
|
18008
|
+
const component = createComponentHelper(getActivePage2);
|
|
17979
18009
|
const executeFunction = new Function(
|
|
17980
18010
|
"page",
|
|
17981
18011
|
"getActivePage",
|
|
@@ -17986,9 +18016,10 @@ var execute = new commander.Command().name("execute").description("run Playwrigh
|
|
|
17986
18016
|
"dispatch",
|
|
17987
18017
|
"grab",
|
|
17988
18018
|
"waitFor",
|
|
18019
|
+
"component",
|
|
17989
18020
|
`return (async () => { ${code} })();`
|
|
17990
18021
|
);
|
|
17991
|
-
const result = await executeFunction(getActivePage2(), getActivePage2, snapshot, ref, fill, drag, dispatch, grab, waitFor);
|
|
18022
|
+
const result = await executeFunction(getActivePage2(), getActivePage2, snapshot, ref, fill, drag, dispatch, grab, waitFor, component);
|
|
17992
18023
|
console.log(JSON.stringify(await buildOutput(true, result)));
|
|
17993
18024
|
} catch (error48) {
|
|
17994
18025
|
console.log(JSON.stringify(await buildOutput(false, void 0, error48 instanceof Error ? error48.message : "Failed")));
|
|
@@ -18046,8 +18077,7 @@ PERFORMANCE TIPS
|
|
|
18046
18077
|
1. Batch multiple actions in a single execute call to minimize round-trips.
|
|
18047
18078
|
Each execute spawns a new connection, so combining actions is 3-5x faster.
|
|
18048
18079
|
|
|
18049
|
-
2. Use
|
|
18050
|
-
- snapshot({format: 'compact'}) -> minimal ref:role:name output
|
|
18080
|
+
2. Use interactableOnly or limit depth for smaller snapshots (faster, fewer tokens).
|
|
18051
18081
|
- snapshot({interactableOnly: true}) -> only clickable/input elements
|
|
18052
18082
|
- snapshot({maxDepth: 5}) -> limit tree depth
|
|
18053
18083
|
|
|
@@ -18056,22 +18086,28 @@ PERFORMANCE TIPS
|
|
|
18056
18086
|
execute "await ref('e1').click()"
|
|
18057
18087
|
execute "return await snapshot()"
|
|
18058
18088
|
|
|
18059
|
-
# FAST: 1 round-trip,
|
|
18089
|
+
# FAST: 1 round-trip, interactable only
|
|
18060
18090
|
execute "
|
|
18061
18091
|
await page.goto('https://example.com');
|
|
18062
18092
|
await ref('e1').click();
|
|
18063
|
-
return await snapshot({
|
|
18093
|
+
return await snapshot({interactableOnly: true});
|
|
18064
18094
|
"
|
|
18065
18095
|
|
|
18066
18096
|
HELPERS
|
|
18067
18097
|
page - Playwright Page object
|
|
18068
18098
|
snapshot(opts?) - Get ARIA accessibility tree with refs
|
|
18069
18099
|
opts.maxDepth: limit tree depth (e.g., 5)
|
|
18070
|
-
opts.interactableOnly: only
|
|
18071
|
-
opts.format: "yaml" (default) or "compact"
|
|
18100
|
+
opts.interactableOnly: only clickable/input elements
|
|
18072
18101
|
ref(id) - Get element by ref ID (chainable - supports all ElementHandle methods)
|
|
18073
18102
|
Example: await ref('e1').click()
|
|
18074
18103
|
Example: await ref('e1').getAttribute('data-foo')
|
|
18104
|
+
ref(id).source() - Get React component source file info for element
|
|
18105
|
+
Returns { filePath, lineNumber, componentName } or null
|
|
18106
|
+
ref(id).props() - Get React component props (serialized)
|
|
18107
|
+
ref(id).state() - Get React component state/hooks (serialized)
|
|
18108
|
+
component(name, opts?) - Find elements by React component name
|
|
18109
|
+
opts.nth: get the nth matching element (0-indexed)
|
|
18110
|
+
Example: await component('Button', {nth: 0})
|
|
18075
18111
|
fill(id, text) - Clear and fill input (works with rich text editors)
|
|
18076
18112
|
drag(opts) - Drag with custom MIME types
|
|
18077
18113
|
opts.from: source selector or ref ID (e.g., "e1" or "text=src")
|
|
@@ -18087,21 +18123,16 @@ HELPERS
|
|
|
18087
18123
|
await waitFor('.btn') - wait for selector
|
|
18088
18124
|
await waitFor('networkidle') - wait for network idle
|
|
18089
18125
|
await waitFor('load') - wait for page load
|
|
18090
|
-
ref(id).source() - Get React component source file info for element
|
|
18091
|
-
Returns { filePath, lineNumber, componentName } or null
|
|
18092
18126
|
grab - React Grab client API (activate, copyElement, etc)
|
|
18093
18127
|
|
|
18094
|
-
SNAPSHOT
|
|
18128
|
+
SNAPSHOT OPTIONS
|
|
18095
18129
|
# Full YAML tree (default, can be large)
|
|
18096
18130
|
execute "return await snapshot()"
|
|
18097
18131
|
|
|
18098
18132
|
# Interactable only (recommended - much smaller!)
|
|
18099
18133
|
execute "return await snapshot({interactableOnly: true})"
|
|
18100
18134
|
|
|
18101
|
-
#
|
|
18102
|
-
execute "return await snapshot({format: 'compact'})"
|
|
18103
|
-
|
|
18104
|
-
# Combined options
|
|
18135
|
+
# With depth limit
|
|
18105
18136
|
execute "return await snapshot({interactableOnly: true, maxDepth: 6})"
|
|
18106
18137
|
|
|
18107
18138
|
SCREENSHOTS - PREFER ELEMENT OVER FULL PAGE
|
|
@@ -18145,15 +18176,28 @@ COMMON PATTERNS
|
|
|
18145
18176
|
dataTransfer: { 'application/x-custom': 'data' }
|
|
18146
18177
|
})"
|
|
18147
18178
|
|
|
18148
|
-
# Get React component source file
|
|
18149
|
-
execute "return await ref('e1').source()"
|
|
18150
|
-
|
|
18151
18179
|
# Get page info
|
|
18152
18180
|
execute "return {url: page.url(), title: await page.title()}"
|
|
18153
18181
|
|
|
18154
18182
|
# CSS selector fallback (refs are now in DOM as aria-ref)
|
|
18155
18183
|
execute "await page.click('[aria-ref="e1"]')"
|
|
18156
18184
|
|
|
18185
|
+
REACT-SPECIFIC PATTERNS
|
|
18186
|
+
# Get React component source file
|
|
18187
|
+
execute "return await ref('e1').source()"
|
|
18188
|
+
|
|
18189
|
+
# Get component props
|
|
18190
|
+
execute "return await ref('e1').props()"
|
|
18191
|
+
|
|
18192
|
+
# Get component state
|
|
18193
|
+
execute "return await ref('e1').state()"
|
|
18194
|
+
|
|
18195
|
+
# Find elements by React component name
|
|
18196
|
+
execute "const buttons = await component('Button'); return buttons.length"
|
|
18197
|
+
|
|
18198
|
+
# Get the first Button component and click it
|
|
18199
|
+
execute "const btn = await component('Button', {nth: 0}); await btn.click()"
|
|
18200
|
+
|
|
18157
18201
|
MULTI-PAGE SESSIONS
|
|
18158
18202
|
execute "await page.goto('https://github.com')" --page github
|
|
18159
18203
|
execute "return await snapshot({interactableOnly: true})" --page github
|
|
@@ -18210,7 +18254,7 @@ browser.addCommand(status);
|
|
|
18210
18254
|
browser.addCommand(execute);
|
|
18211
18255
|
browser.addCommand(pages);
|
|
18212
18256
|
browser.addCommand(mcp);
|
|
18213
|
-
var VERSION3 = "0.1.0-beta.
|
|
18257
|
+
var VERSION3 = "0.1.0-beta.4";
|
|
18214
18258
|
var isMac = process.platform === "darwin";
|
|
18215
18259
|
var META_LABEL = isMac ? "Cmd" : "Win";
|
|
18216
18260
|
var ALT_LABEL = isMac ? "Option" : "Alt";
|
|
@@ -18697,7 +18741,7 @@ var uninstallPackagesWithFeedback = (packages, packageManager, projectRoot) => {
|
|
|
18697
18741
|
handleError(error48);
|
|
18698
18742
|
}
|
|
18699
18743
|
};
|
|
18700
|
-
var VERSION4 = "0.1.0-beta.
|
|
18744
|
+
var VERSION4 = "0.1.0-beta.4";
|
|
18701
18745
|
var REPORT_URL = "https://react-grab.com/api/report-cli";
|
|
18702
18746
|
var DOCS_URL = "https://github.com/aidenybai/react-grab";
|
|
18703
18747
|
var promptAgentIntegration = async (cwd, customPkg) => {
|
|
@@ -18741,19 +18785,29 @@ var promptAgentIntegration = async (cwd, customPkg) => {
|
|
|
18741
18785
|
}
|
|
18742
18786
|
}
|
|
18743
18787
|
if (integrationType === "skill" || integrationType === "both") {
|
|
18744
|
-
|
|
18745
|
-
|
|
18746
|
-
|
|
18747
|
-
|
|
18748
|
-
|
|
18749
|
-
|
|
18750
|
-
|
|
18751
|
-
|
|
18752
|
-
|
|
18753
|
-
|
|
18788
|
+
const { skillTarget } = await prompts3__default.default({
|
|
18789
|
+
type: "select",
|
|
18790
|
+
name: "skillTarget",
|
|
18791
|
+
message: `Which ${highlighter.info("agent")} would you like to install the skill for?`,
|
|
18792
|
+
choices: SUPPORTED_TARGETS.map((target) => ({
|
|
18793
|
+
title: target,
|
|
18794
|
+
value: target
|
|
18795
|
+
}))
|
|
18796
|
+
});
|
|
18797
|
+
if (skillTarget) {
|
|
18754
18798
|
logger.break();
|
|
18755
|
-
skillSpinner
|
|
18756
|
-
|
|
18799
|
+
const skillSpinner = spinner("Installing browser automation skill").start();
|
|
18800
|
+
try {
|
|
18801
|
+
const skill = await fetchSkillFile();
|
|
18802
|
+
const skillDir = path.join(cwd, AGENT_TARGETS[skillTarget]);
|
|
18803
|
+
fs.rmSync(skillDir, { recursive: true, force: true });
|
|
18804
|
+
fs.mkdirSync(skillDir, { recursive: true });
|
|
18805
|
+
fs.writeFileSync(path.join(skillDir, "SKILL.md"), skill);
|
|
18806
|
+
skillSpinner.succeed(`Skill installed to ${AGENT_TARGETS[skillTarget]}/`);
|
|
18807
|
+
} catch {
|
|
18808
|
+
skillSpinner.fail("Failed to install skill");
|
|
18809
|
+
logger.dim("Try manually: npx -y openskills install aidenybai/react-grab");
|
|
18810
|
+
}
|
|
18757
18811
|
}
|
|
18758
18812
|
}
|
|
18759
18813
|
logger.break();
|
|
@@ -19389,7 +19443,7 @@ var init = new commander.Command().name("init").description("initialize React Gr
|
|
|
19389
19443
|
await reportToCli("error", void 0, error48);
|
|
19390
19444
|
}
|
|
19391
19445
|
});
|
|
19392
|
-
var VERSION5 = "0.1.0-beta.
|
|
19446
|
+
var VERSION5 = "0.1.0-beta.4";
|
|
19393
19447
|
var remove = new commander.Command().name("remove").description("remove an agent integration").argument(
|
|
19394
19448
|
"[agent]",
|
|
19395
19449
|
"agent to remove (claude-code, cursor, opencode, codex, gemini, amp, ami, visual-edit)"
|
|
@@ -19568,7 +19622,7 @@ var remove = new commander.Command().name("remove").description("remove an agent
|
|
|
19568
19622
|
});
|
|
19569
19623
|
|
|
19570
19624
|
// src/cli.ts
|
|
19571
|
-
var VERSION6 = "0.1.0-beta.
|
|
19625
|
+
var VERSION6 = "0.1.0-beta.4";
|
|
19572
19626
|
var VERSION_API_URL = "https://www.react-grab.com/api/version";
|
|
19573
19627
|
process.on("SIGINT", () => process.exit(0));
|
|
19574
19628
|
process.on("SIGTERM", () => process.exit(0));
|
package/dist/cli.js
CHANGED
|
@@ -2697,7 +2697,7 @@ var previewPackageJsonAgentRemoval = (projectRoot, agent) => {
|
|
|
2697
2697
|
};
|
|
2698
2698
|
|
|
2699
2699
|
// src/commands/add.ts
|
|
2700
|
-
var VERSION = "0.1.0-beta.
|
|
2700
|
+
var VERSION = "0.1.0-beta.4";
|
|
2701
2701
|
var add = new Command().name("add").alias("install").description("add an agent integration or MCP server").argument(
|
|
2702
2702
|
"[agent]",
|
|
2703
2703
|
`agent to add (${AGENTS.join(", ")}, mcp, skill)`
|
|
@@ -3375,30 +3375,42 @@ var createRefHelper = (getActivePage2) => {
|
|
|
3375
3375
|
};
|
|
3376
3376
|
const getSource = async (refId) => {
|
|
3377
3377
|
const element = await getElement(refId);
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3378
|
+
try {
|
|
3379
|
+
const currentPage2 = getActivePage2();
|
|
3380
|
+
return await currentPage2.evaluate((el) => {
|
|
3381
|
+
const g2 = globalThis;
|
|
3382
|
+
if (!g2.__REACT_GRAB__) return null;
|
|
3383
|
+
return g2.__REACT_GRAB__.getSource(el);
|
|
3384
|
+
}, element);
|
|
3385
|
+
} finally {
|
|
3386
|
+
await element.dispose();
|
|
3387
|
+
}
|
|
3384
3388
|
};
|
|
3385
3389
|
const getProps = async (refId) => {
|
|
3386
3390
|
const element = await getElement(refId);
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3391
|
+
try {
|
|
3392
|
+
const currentPage2 = getActivePage2();
|
|
3393
|
+
return await currentPage2.evaluate((el) => {
|
|
3394
|
+
const g2 = globalThis;
|
|
3395
|
+
if (!g2.__REACT_GRAB_GET_PROPS__) return null;
|
|
3396
|
+
return g2.__REACT_GRAB_GET_PROPS__(el);
|
|
3397
|
+
}, element);
|
|
3398
|
+
} finally {
|
|
3399
|
+
await element.dispose();
|
|
3400
|
+
}
|
|
3393
3401
|
};
|
|
3394
3402
|
const getState = async (refId) => {
|
|
3395
3403
|
const element = await getElement(refId);
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3404
|
+
try {
|
|
3405
|
+
const currentPage2 = getActivePage2();
|
|
3406
|
+
return await currentPage2.evaluate((el) => {
|
|
3407
|
+
const g2 = globalThis;
|
|
3408
|
+
if (!g2.__REACT_GRAB_GET_STATE__) return null;
|
|
3409
|
+
return g2.__REACT_GRAB_GET_STATE__(el);
|
|
3410
|
+
}, element);
|
|
3411
|
+
} finally {
|
|
3412
|
+
await element.dispose();
|
|
3413
|
+
}
|
|
3402
3414
|
};
|
|
3403
3415
|
return (refId) => {
|
|
3404
3416
|
return new Proxy(
|
|
@@ -3418,13 +3430,23 @@ var createRefHelper = (getActivePage2) => {
|
|
|
3418
3430
|
return () => getState(refId);
|
|
3419
3431
|
}
|
|
3420
3432
|
if (prop === "screenshot") {
|
|
3421
|
-
return (options2) =>
|
|
3422
|
-
|
|
3423
|
-
|
|
3433
|
+
return async (options2) => {
|
|
3434
|
+
const el = await getElement(refId);
|
|
3435
|
+
try {
|
|
3436
|
+
return await el.screenshot({ scale: "css", ...options2 });
|
|
3437
|
+
} finally {
|
|
3438
|
+
await el.dispose();
|
|
3439
|
+
}
|
|
3440
|
+
};
|
|
3424
3441
|
}
|
|
3425
|
-
return (...args) =>
|
|
3426
|
-
|
|
3427
|
-
|
|
3442
|
+
return async (...args) => {
|
|
3443
|
+
const el = await getElement(refId);
|
|
3444
|
+
try {
|
|
3445
|
+
return await el[prop](...args);
|
|
3446
|
+
} finally {
|
|
3447
|
+
await el.dispose();
|
|
3448
|
+
}
|
|
3449
|
+
};
|
|
3428
3450
|
}
|
|
3429
3451
|
}
|
|
3430
3452
|
);
|
|
@@ -3451,8 +3473,8 @@ var createComponentHelper = (getActivePage2) => {
|
|
|
3451
3473
|
},
|
|
3452
3474
|
{ name: componentName, nth }
|
|
3453
3475
|
);
|
|
3454
|
-
const
|
|
3455
|
-
if (
|
|
3476
|
+
const isNull = await currentPage2.evaluate((value) => value === null, elementHandles);
|
|
3477
|
+
if (isNull) {
|
|
3456
3478
|
await elementHandles.dispose();
|
|
3457
3479
|
return null;
|
|
3458
3480
|
}
|
|
@@ -3594,11 +3616,15 @@ var createGrabHelper = (ref, getActivePage2) => {
|
|
|
3594
3616
|
copyElement: async (refId) => {
|
|
3595
3617
|
const element = await ref(refId);
|
|
3596
3618
|
if (!element) return false;
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3619
|
+
try {
|
|
3620
|
+
const currentPage2 = getActivePage2();
|
|
3621
|
+
return await currentPage2.evaluate((el) => {
|
|
3622
|
+
const g2 = globalThis;
|
|
3623
|
+
return g2.__REACT_GRAB__?.copyElement([el]) ?? false;
|
|
3624
|
+
}, element);
|
|
3625
|
+
} finally {
|
|
3626
|
+
await element.dispose();
|
|
3627
|
+
}
|
|
3602
3628
|
}
|
|
3603
3629
|
};
|
|
3604
3630
|
};
|
|
@@ -17445,7 +17471,6 @@ USE VIEWPORT screenshot=true ONLY FOR:
|
|
|
17445
17471
|
|
|
17446
17472
|
PERFORMANCE:
|
|
17447
17473
|
- interactableOnly:true = much smaller output (recommended)
|
|
17448
|
-
- format:'compact' = minimal ref:role:name@Component output
|
|
17449
17474
|
- maxDepth = limit tree depth
|
|
17450
17475
|
|
|
17451
17476
|
After getting refs, use browser_execute with: ref('e1').click()`,
|
|
@@ -17453,7 +17478,6 @@ After getting refs, use browser_execute with: ref('e1').click()`,
|
|
|
17453
17478
|
page: external_exports.string().optional().default("default").describe("Named page context"),
|
|
17454
17479
|
maxDepth: external_exports.number().optional().describe("Limit tree depth"),
|
|
17455
17480
|
interactableOnly: external_exports.boolean().optional().describe("Only clickable/input elements (recommended)"),
|
|
17456
|
-
format: external_exports.enum(["yaml", "compact"]).optional().default("yaml").describe("'yaml' or 'compact'"),
|
|
17457
17481
|
screenshot: external_exports.boolean().optional().default(false).describe(
|
|
17458
17482
|
"Viewport screenshot. For element screenshots (PREFERRED), use browser_execute: ref('eX').screenshot()"
|
|
17459
17483
|
)
|
|
@@ -17463,7 +17487,6 @@ After getting refs, use browser_execute with: ref('e1').click()`,
|
|
|
17463
17487
|
page: pageName,
|
|
17464
17488
|
maxDepth,
|
|
17465
17489
|
interactableOnly,
|
|
17466
|
-
format,
|
|
17467
17490
|
screenshot
|
|
17468
17491
|
}) => {
|
|
17469
17492
|
let browser2 = null;
|
|
@@ -17473,7 +17496,7 @@ After getting refs, use browser_execute with: ref('e1').click()`,
|
|
|
17473
17496
|
const activePage = connection.page;
|
|
17474
17497
|
const getActivePage2 = () => activePage;
|
|
17475
17498
|
const snapshot = createSnapshotHelper(getActivePage2);
|
|
17476
|
-
const snapshotResult = await snapshot({ maxDepth, interactableOnly
|
|
17499
|
+
const snapshotResult = await snapshot({ maxDepth, interactableOnly });
|
|
17477
17500
|
if (screenshot) {
|
|
17478
17501
|
const screenshotBuffer = await activePage.screenshot({
|
|
17479
17502
|
fullPage: false,
|
|
@@ -17509,7 +17532,7 @@ IMPORTANT: Always call snapshot() first to get element refs from the a11y tree (
|
|
|
17509
17532
|
|
|
17510
17533
|
AVAILABLE HELPERS:
|
|
17511
17534
|
- page: Playwright Page object (https://playwright.dev/docs/api/class-page)
|
|
17512
|
-
- snapshot(opts?): Get ARIA tree with React component info. opts: {maxDepth, interactableOnly
|
|
17535
|
+
- snapshot(opts?): Get ARIA tree with React component info. opts: {maxDepth, interactableOnly}
|
|
17513
17536
|
- ref(id): Get element by ref ID, chainable with all ElementHandle methods
|
|
17514
17537
|
- ref(id).source(): Get React component source {filePath, lineNumber, componentName}
|
|
17515
17538
|
- ref(id).props(): Get React component props (serialized)
|
|
@@ -17712,7 +17735,7 @@ For interacting with elements, use browser_snapshot to get refs first.`,
|
|
|
17712
17735
|
};
|
|
17713
17736
|
|
|
17714
17737
|
// src/commands/browser.ts
|
|
17715
|
-
var VERSION2 = "0.1.0-beta.
|
|
17738
|
+
var VERSION2 = "0.1.0-beta.4";
|
|
17716
17739
|
var printHeader = () => {
|
|
17717
17740
|
console.log(
|
|
17718
17741
|
`${pc.magenta("\u273F")} ${pc.bold("React Grab")} ${pc.gray(VERSION2)}`
|
|
@@ -17735,6 +17758,10 @@ var rebuildNativeModuleAndRestart = async (browserPkgDir) => {
|
|
|
17735
17758
|
stdio: "inherit",
|
|
17736
17759
|
detached: false
|
|
17737
17760
|
});
|
|
17761
|
+
child.on("error", (error48) => {
|
|
17762
|
+
console.error(`Failed to restart: ${error48.message}`);
|
|
17763
|
+
process.exit(1);
|
|
17764
|
+
});
|
|
17738
17765
|
child.on("exit", (code) => process.exit(code ?? 0));
|
|
17739
17766
|
};
|
|
17740
17767
|
var isSupportedBrowser = (value) => {
|
|
@@ -17833,8 +17860,10 @@ var start = new Command().name("start").description("start browser server manual
|
|
|
17833
17860
|
const playwrightCookies = toPlaywrightCookies(cookies);
|
|
17834
17861
|
const browser2 = await chromium.connectOverCDP(browserServer.wsEndpoint);
|
|
17835
17862
|
const contexts = browser2.contexts();
|
|
17836
|
-
if (contexts.length > 0
|
|
17837
|
-
|
|
17863
|
+
if (contexts.length > 0) {
|
|
17864
|
+
if (playwrightCookies.length > 0) {
|
|
17865
|
+
await contexts[0].addCookies(playwrightCookies);
|
|
17866
|
+
}
|
|
17838
17867
|
await applyStealthScripts(contexts[0]);
|
|
17839
17868
|
}
|
|
17840
17869
|
await browser2.close();
|
|
@@ -17966,6 +17995,7 @@ var execute = new Command().name("execute").description("run Playwright code wit
|
|
|
17966
17995
|
const dispatch = createDispatchHelper(getActivePage2);
|
|
17967
17996
|
const grab = createGrabHelper(ref, getActivePage2);
|
|
17968
17997
|
const waitFor = createWaitForHelper(getActivePage2);
|
|
17998
|
+
const component = createComponentHelper(getActivePage2);
|
|
17969
17999
|
const executeFunction = new Function(
|
|
17970
18000
|
"page",
|
|
17971
18001
|
"getActivePage",
|
|
@@ -17976,9 +18006,10 @@ var execute = new Command().name("execute").description("run Playwright code wit
|
|
|
17976
18006
|
"dispatch",
|
|
17977
18007
|
"grab",
|
|
17978
18008
|
"waitFor",
|
|
18009
|
+
"component",
|
|
17979
18010
|
`return (async () => { ${code} })();`
|
|
17980
18011
|
);
|
|
17981
|
-
const result = await executeFunction(getActivePage2(), getActivePage2, snapshot, ref, fill, drag, dispatch, grab, waitFor);
|
|
18012
|
+
const result = await executeFunction(getActivePage2(), getActivePage2, snapshot, ref, fill, drag, dispatch, grab, waitFor, component);
|
|
17982
18013
|
console.log(JSON.stringify(await buildOutput(true, result)));
|
|
17983
18014
|
} catch (error48) {
|
|
17984
18015
|
console.log(JSON.stringify(await buildOutput(false, void 0, error48 instanceof Error ? error48.message : "Failed")));
|
|
@@ -18036,8 +18067,7 @@ PERFORMANCE TIPS
|
|
|
18036
18067
|
1. Batch multiple actions in a single execute call to minimize round-trips.
|
|
18037
18068
|
Each execute spawns a new connection, so combining actions is 3-5x faster.
|
|
18038
18069
|
|
|
18039
|
-
2. Use
|
|
18040
|
-
- snapshot({format: 'compact'}) -> minimal ref:role:name output
|
|
18070
|
+
2. Use interactableOnly or limit depth for smaller snapshots (faster, fewer tokens).
|
|
18041
18071
|
- snapshot({interactableOnly: true}) -> only clickable/input elements
|
|
18042
18072
|
- snapshot({maxDepth: 5}) -> limit tree depth
|
|
18043
18073
|
|
|
@@ -18046,22 +18076,28 @@ PERFORMANCE TIPS
|
|
|
18046
18076
|
execute "await ref('e1').click()"
|
|
18047
18077
|
execute "return await snapshot()"
|
|
18048
18078
|
|
|
18049
|
-
# FAST: 1 round-trip,
|
|
18079
|
+
# FAST: 1 round-trip, interactable only
|
|
18050
18080
|
execute "
|
|
18051
18081
|
await page.goto('https://example.com');
|
|
18052
18082
|
await ref('e1').click();
|
|
18053
|
-
return await snapshot({
|
|
18083
|
+
return await snapshot({interactableOnly: true});
|
|
18054
18084
|
"
|
|
18055
18085
|
|
|
18056
18086
|
HELPERS
|
|
18057
18087
|
page - Playwright Page object
|
|
18058
18088
|
snapshot(opts?) - Get ARIA accessibility tree with refs
|
|
18059
18089
|
opts.maxDepth: limit tree depth (e.g., 5)
|
|
18060
|
-
opts.interactableOnly: only
|
|
18061
|
-
opts.format: "yaml" (default) or "compact"
|
|
18090
|
+
opts.interactableOnly: only clickable/input elements
|
|
18062
18091
|
ref(id) - Get element by ref ID (chainable - supports all ElementHandle methods)
|
|
18063
18092
|
Example: await ref('e1').click()
|
|
18064
18093
|
Example: await ref('e1').getAttribute('data-foo')
|
|
18094
|
+
ref(id).source() - Get React component source file info for element
|
|
18095
|
+
Returns { filePath, lineNumber, componentName } or null
|
|
18096
|
+
ref(id).props() - Get React component props (serialized)
|
|
18097
|
+
ref(id).state() - Get React component state/hooks (serialized)
|
|
18098
|
+
component(name, opts?) - Find elements by React component name
|
|
18099
|
+
opts.nth: get the nth matching element (0-indexed)
|
|
18100
|
+
Example: await component('Button', {nth: 0})
|
|
18065
18101
|
fill(id, text) - Clear and fill input (works with rich text editors)
|
|
18066
18102
|
drag(opts) - Drag with custom MIME types
|
|
18067
18103
|
opts.from: source selector or ref ID (e.g., "e1" or "text=src")
|
|
@@ -18077,21 +18113,16 @@ HELPERS
|
|
|
18077
18113
|
await waitFor('.btn') - wait for selector
|
|
18078
18114
|
await waitFor('networkidle') - wait for network idle
|
|
18079
18115
|
await waitFor('load') - wait for page load
|
|
18080
|
-
ref(id).source() - Get React component source file info for element
|
|
18081
|
-
Returns { filePath, lineNumber, componentName } or null
|
|
18082
18116
|
grab - React Grab client API (activate, copyElement, etc)
|
|
18083
18117
|
|
|
18084
|
-
SNAPSHOT
|
|
18118
|
+
SNAPSHOT OPTIONS
|
|
18085
18119
|
# Full YAML tree (default, can be large)
|
|
18086
18120
|
execute "return await snapshot()"
|
|
18087
18121
|
|
|
18088
18122
|
# Interactable only (recommended - much smaller!)
|
|
18089
18123
|
execute "return await snapshot({interactableOnly: true})"
|
|
18090
18124
|
|
|
18091
|
-
#
|
|
18092
|
-
execute "return await snapshot({format: 'compact'})"
|
|
18093
|
-
|
|
18094
|
-
# Combined options
|
|
18125
|
+
# With depth limit
|
|
18095
18126
|
execute "return await snapshot({interactableOnly: true, maxDepth: 6})"
|
|
18096
18127
|
|
|
18097
18128
|
SCREENSHOTS - PREFER ELEMENT OVER FULL PAGE
|
|
@@ -18135,15 +18166,28 @@ COMMON PATTERNS
|
|
|
18135
18166
|
dataTransfer: { 'application/x-custom': 'data' }
|
|
18136
18167
|
})"
|
|
18137
18168
|
|
|
18138
|
-
# Get React component source file
|
|
18139
|
-
execute "return await ref('e1').source()"
|
|
18140
|
-
|
|
18141
18169
|
# Get page info
|
|
18142
18170
|
execute "return {url: page.url(), title: await page.title()}"
|
|
18143
18171
|
|
|
18144
18172
|
# CSS selector fallback (refs are now in DOM as aria-ref)
|
|
18145
18173
|
execute "await page.click('[aria-ref="e1"]')"
|
|
18146
18174
|
|
|
18175
|
+
REACT-SPECIFIC PATTERNS
|
|
18176
|
+
# Get React component source file
|
|
18177
|
+
execute "return await ref('e1').source()"
|
|
18178
|
+
|
|
18179
|
+
# Get component props
|
|
18180
|
+
execute "return await ref('e1').props()"
|
|
18181
|
+
|
|
18182
|
+
# Get component state
|
|
18183
|
+
execute "return await ref('e1').state()"
|
|
18184
|
+
|
|
18185
|
+
# Find elements by React component name
|
|
18186
|
+
execute "const buttons = await component('Button'); return buttons.length"
|
|
18187
|
+
|
|
18188
|
+
# Get the first Button component and click it
|
|
18189
|
+
execute "const btn = await component('Button', {nth: 0}); await btn.click()"
|
|
18190
|
+
|
|
18147
18191
|
MULTI-PAGE SESSIONS
|
|
18148
18192
|
execute "await page.goto('https://github.com')" --page github
|
|
18149
18193
|
execute "return await snapshot({interactableOnly: true})" --page github
|
|
@@ -18200,7 +18244,7 @@ browser.addCommand(status);
|
|
|
18200
18244
|
browser.addCommand(execute);
|
|
18201
18245
|
browser.addCommand(pages);
|
|
18202
18246
|
browser.addCommand(mcp);
|
|
18203
|
-
var VERSION3 = "0.1.0-beta.
|
|
18247
|
+
var VERSION3 = "0.1.0-beta.4";
|
|
18204
18248
|
var isMac = process.platform === "darwin";
|
|
18205
18249
|
var META_LABEL = isMac ? "Cmd" : "Win";
|
|
18206
18250
|
var ALT_LABEL = isMac ? "Option" : "Alt";
|
|
@@ -18687,7 +18731,7 @@ var uninstallPackagesWithFeedback = (packages, packageManager, projectRoot) => {
|
|
|
18687
18731
|
handleError(error48);
|
|
18688
18732
|
}
|
|
18689
18733
|
};
|
|
18690
|
-
var VERSION4 = "0.1.0-beta.
|
|
18734
|
+
var VERSION4 = "0.1.0-beta.4";
|
|
18691
18735
|
var REPORT_URL = "https://react-grab.com/api/report-cli";
|
|
18692
18736
|
var DOCS_URL = "https://github.com/aidenybai/react-grab";
|
|
18693
18737
|
var promptAgentIntegration = async (cwd, customPkg) => {
|
|
@@ -18731,19 +18775,29 @@ var promptAgentIntegration = async (cwd, customPkg) => {
|
|
|
18731
18775
|
}
|
|
18732
18776
|
}
|
|
18733
18777
|
if (integrationType === "skill" || integrationType === "both") {
|
|
18734
|
-
|
|
18735
|
-
|
|
18736
|
-
|
|
18737
|
-
|
|
18738
|
-
|
|
18739
|
-
|
|
18740
|
-
|
|
18741
|
-
|
|
18742
|
-
|
|
18743
|
-
|
|
18778
|
+
const { skillTarget } = await prompts3({
|
|
18779
|
+
type: "select",
|
|
18780
|
+
name: "skillTarget",
|
|
18781
|
+
message: `Which ${highlighter.info("agent")} would you like to install the skill for?`,
|
|
18782
|
+
choices: SUPPORTED_TARGETS.map((target) => ({
|
|
18783
|
+
title: target,
|
|
18784
|
+
value: target
|
|
18785
|
+
}))
|
|
18786
|
+
});
|
|
18787
|
+
if (skillTarget) {
|
|
18744
18788
|
logger.break();
|
|
18745
|
-
skillSpinner
|
|
18746
|
-
|
|
18789
|
+
const skillSpinner = spinner("Installing browser automation skill").start();
|
|
18790
|
+
try {
|
|
18791
|
+
const skill = await fetchSkillFile();
|
|
18792
|
+
const skillDir = join(cwd, AGENT_TARGETS[skillTarget]);
|
|
18793
|
+
rmSync(skillDir, { recursive: true, force: true });
|
|
18794
|
+
mkdirSync(skillDir, { recursive: true });
|
|
18795
|
+
writeFileSync(join(skillDir, "SKILL.md"), skill);
|
|
18796
|
+
skillSpinner.succeed(`Skill installed to ${AGENT_TARGETS[skillTarget]}/`);
|
|
18797
|
+
} catch {
|
|
18798
|
+
skillSpinner.fail("Failed to install skill");
|
|
18799
|
+
logger.dim("Try manually: npx -y openskills install aidenybai/react-grab");
|
|
18800
|
+
}
|
|
18747
18801
|
}
|
|
18748
18802
|
}
|
|
18749
18803
|
logger.break();
|
|
@@ -19379,7 +19433,7 @@ var init = new Command().name("init").description("initialize React Grab in your
|
|
|
19379
19433
|
await reportToCli("error", void 0, error48);
|
|
19380
19434
|
}
|
|
19381
19435
|
});
|
|
19382
|
-
var VERSION5 = "0.1.0-beta.
|
|
19436
|
+
var VERSION5 = "0.1.0-beta.4";
|
|
19383
19437
|
var remove = new Command().name("remove").description("remove an agent integration").argument(
|
|
19384
19438
|
"[agent]",
|
|
19385
19439
|
"agent to remove (claude-code, cursor, opencode, codex, gemini, amp, ami, visual-edit)"
|
|
@@ -19558,7 +19612,7 @@ var remove = new Command().name("remove").description("remove an agent integrati
|
|
|
19558
19612
|
});
|
|
19559
19613
|
|
|
19560
19614
|
// src/cli.ts
|
|
19561
|
-
var VERSION6 = "0.1.0-beta.
|
|
19615
|
+
var VERSION6 = "0.1.0-beta.4";
|
|
19562
19616
|
var VERSION_API_URL = "https://www.react-grab.com/api/version";
|
|
19563
19617
|
process.on("SIGINT", () => process.exit(0));
|
|
19564
19618
|
process.on("SIGTERM", () => process.exit(0));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-grab/cli",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"react-grab": "./dist/cli.js"
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"playwright-core": "^1.50.0",
|
|
33
33
|
"prompts": "^2.4.2",
|
|
34
34
|
"zod": "^4.3.5",
|
|
35
|
-
"@react-grab/browser": "0.1.0-beta.
|
|
35
|
+
"@react-grab/browser": "0.1.0-beta.5"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
38
|
"dev": "tsup --watch",
|