@crouton-kit/capture 1.4.1 → 1.4.2
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/bin/capture +28 -17
- package/package.json +1 -1
- package/src/cdp/commands/motion/rec.ts +2 -2
- package/src/cdp/commands/page/click.ts +3 -3
- package/src/cdp/commands/page/index.ts +1 -1
- package/src/cdp/commands/page/scroll.ts +2 -2
- package/src/cdp/commands/page/shot.ts +2 -2
- package/src/cdp/commands/page/type.ts +1 -1
- package/src/cdp/leaf-grammar.ts +2 -2
- package/src/interact.ts +28 -2
package/bin/capture
CHANGED
|
@@ -9080,7 +9080,7 @@ function assertScrollDestination(value) {
|
|
|
9080
9080
|
function parseDoAction(action) {
|
|
9081
9081
|
if (action.startsWith("click:")) {
|
|
9082
9082
|
const target = action.slice("click:".length);
|
|
9083
|
-
if (!target) throw invalidInput("Invalid --do action: click requires a target \u2014 a css selector, ax:<name>, axid:<id>, or backend:<id>.");
|
|
9083
|
+
if (!target) throw invalidInput("Invalid --do action: click requires a target \u2014 a css selector (or exact accessible name when CSS finds none), ax:<name>, axid:<id>, or backend:<id>.");
|
|
9084
9084
|
return { verb: "click", target };
|
|
9085
9085
|
}
|
|
9086
9086
|
if (action.startsWith("scroll:")) {
|
|
@@ -9091,7 +9091,7 @@ function parseDoAction(action) {
|
|
|
9091
9091
|
if (!isScrollDestination(to)) throw invalidInput("Invalid --do action: scroll requires `scroll:<target>,to=<top|bottom|px>`.");
|
|
9092
9092
|
return { verb: "scroll", target: spec.slice(0, comma), to };
|
|
9093
9093
|
}
|
|
9094
|
-
throw invalidInput("Unsupported --do action. Supported actions: click:<target>; scroll:<target>,to=<top|bottom|px> \u2014 target is a css selector, ax:<name>, axid:<id>, or backend:<id>.");
|
|
9094
|
+
throw invalidInput("Unsupported --do action. Supported actions: click:<target>; scroll:<target>,to=<top|bottom|px> \u2014 target is a css selector (or exact accessible name when CSS finds none), ax:<name>, axid:<id>, or backend:<id>.");
|
|
9095
9095
|
}
|
|
9096
9096
|
var SWEEP_NUMERIC_AXES, SWEEP_ENUM_VALUES;
|
|
9097
9097
|
var init_leaf_grammar = __esm({
|
|
@@ -10316,7 +10316,7 @@ function validateHarAppendBatch(value, source) {
|
|
|
10316
10316
|
return { entries, incompleteLifecycles };
|
|
10317
10317
|
}
|
|
10318
10318
|
function captureVersion() {
|
|
10319
|
-
const version = "1.4.
|
|
10319
|
+
const version = "1.4.2";
|
|
10320
10320
|
return typeof version === "string" && version.length > 0 ? version : "development";
|
|
10321
10321
|
}
|
|
10322
10322
|
function token() {
|
|
@@ -12107,7 +12107,7 @@ function wallTime(value) {
|
|
|
12107
12107
|
}
|
|
12108
12108
|
}
|
|
12109
12109
|
function captureVersion2() {
|
|
12110
|
-
const version = "1.4.
|
|
12110
|
+
const version = "1.4.2";
|
|
12111
12111
|
return typeof version === "string" && version.length > 0 ? version : "development";
|
|
12112
12112
|
}
|
|
12113
12113
|
function deepFreeze(value) {
|
|
@@ -16048,7 +16048,7 @@ async function resolveLiveTarget(client, input) {
|
|
|
16048
16048
|
return settleAxMatches("axid", input, matches);
|
|
16049
16049
|
}
|
|
16050
16050
|
case "css":
|
|
16051
|
-
return
|
|
16051
|
+
return resolveBareTarget(client, input, parsed.value);
|
|
16052
16052
|
}
|
|
16053
16053
|
}
|
|
16054
16054
|
function preferActionable(matches) {
|
|
@@ -16081,6 +16081,17 @@ function settleAxMatches(kind, input, rawMatches) {
|
|
|
16081
16081
|
}))
|
|
16082
16082
|
};
|
|
16083
16083
|
}
|
|
16084
|
+
async function resolveBareTarget(client, input, selector) {
|
|
16085
|
+
const css = await resolveLiveCss(client, input, selector);
|
|
16086
|
+
if (css.ok || css.code === "ambiguous") return css;
|
|
16087
|
+
const normalized2 = normalizeAccessibleName(input);
|
|
16088
|
+
if (!normalized2) return css;
|
|
16089
|
+
const matches = (await readFullAXTree(client)).filter(
|
|
16090
|
+
(node) => node.backendDOMNodeId !== void 0 && node.name?.value !== void 0 && normalizeAccessibleName(node.name.value) === normalized2
|
|
16091
|
+
);
|
|
16092
|
+
const ax = settleAxMatches("ax", input, matches);
|
|
16093
|
+
return ax.ok || ax.code === "ambiguous" ? ax : css;
|
|
16094
|
+
}
|
|
16084
16095
|
async function resolveLiveCss(client, input, selector) {
|
|
16085
16096
|
await client.send("DOM.enable");
|
|
16086
16097
|
const { root } = await client.send("DOM.getDocument", { depth: 0 });
|
|
@@ -16308,7 +16319,7 @@ function emitResolutionError(parsed, command, failure) {
|
|
|
16308
16319
|
{
|
|
16309
16320
|
tag: "error",
|
|
16310
16321
|
attrs: { command, code: "unsupported_prefix" },
|
|
16311
|
-
summary: fact`received: target \`${failure.input}\` — the \`text:\` prefix is not accepted by live driving verbs; expected one of: bare CSS selector, ax:<name>, axid:<id>, backend:<id>.`,
|
|
16322
|
+
summary: fact`received: target \`${failure.input}\` — the \`text:\` prefix is not accepted by live driving verbs; expected one of: bare CSS selector (or exact accessible name when CSS finds none), ax:<name>, axid:<id>, backend:<id>.`,
|
|
16312
16323
|
followUp: fact`Retry \`${command}\` with \`ax:<name>\` (accessible-name substring) or a CSS selector; \`text:\` matching exists only on the query leaves.`
|
|
16313
16324
|
},
|
|
16314
16325
|
{ json: parsed.json }
|
|
@@ -16360,7 +16371,7 @@ async function cmdPageClick(parsed, _args) {
|
|
|
16360
16371
|
return emitInvalidInput(
|
|
16361
16372
|
parsed,
|
|
16362
16373
|
"page click",
|
|
16363
|
-
fact`received: ${parsed.positional.length} positional arguments; expected exactly one target (CSS selector, ax:<name>, axid:<id>, or backend:<id>).`
|
|
16374
|
+
fact`received: ${parsed.positional.length} positional arguments; expected exactly one target (CSS selector or exact accessible name, ax:<name>, axid:<id>, or backend:<id>).`
|
|
16364
16375
|
);
|
|
16365
16376
|
}
|
|
16366
16377
|
const settle = effectiveSettle(parsed, { standalone: 1e3, session: 2500 });
|
|
@@ -16411,7 +16422,7 @@ var init_click = __esm({
|
|
|
16411
16422
|
USAGE = `capture page click <target> \u2014 dispatch one real click on exactly one resolved element
|
|
16412
16423
|
|
|
16413
16424
|
input:
|
|
16414
|
-
<target> resolved against the LIVE page: bare CSS selector, ax:<name> (case-insensitive substring over accessible names), axid:<id>, backend:<id>. text: is not accepted. Exactly one match required \u2014 zero or many matches is a structured error listing candidates with backend:<id> retry keys.
|
|
16425
|
+
<target> resolved against the LIVE page: bare CSS selector (takes precedence) or exact accessible name when CSS finds none, ax:<name> (case-insensitive substring over accessible names), axid:<id>, backend:<id>. text: is not accepted. Exactly one match required \u2014 zero or many matches is a structured error listing candidates with backend:<id> retry keys.
|
|
16415
16426
|
--settle <ms> network-settle window applied after the click (default: 1000; 2500 with an active session; 0 disables)
|
|
16416
16427
|
--no-screenshot skip the auto-screenshot
|
|
16417
16428
|
output:
|
|
@@ -16487,7 +16498,7 @@ var init_type = __esm({
|
|
|
16487
16498
|
|
|
16488
16499
|
input:
|
|
16489
16500
|
<text> the text to insert (agent-supplied; echoed back in the result block)
|
|
16490
|
-
--into <target> focus this field first \u2014 resolved against the LIVE page: bare CSS selector, ax:<name> (case-insensitive substring), axid:<id>, backend:<id>; text: is not accepted; exactly one match required
|
|
16501
|
+
--into <target> focus this field first \u2014 resolved against the LIVE page: bare CSS selector (takes precedence) or exact accessible name when CSS finds none, ax:<name> (case-insensitive substring), axid:<id>, backend:<id>; text: is not accepted; exactly one match required
|
|
16491
16502
|
--settle <ms> network-settle window applied after typing (default: 500; 1500 with an active session; 0 disables)
|
|
16492
16503
|
--no-screenshot skip the auto-screenshot
|
|
16493
16504
|
output:
|
|
@@ -16508,7 +16519,7 @@ async function cmdPageScroll(parsed, _args) {
|
|
|
16508
16519
|
return emitInvalidInput(
|
|
16509
16520
|
parsed,
|
|
16510
16521
|
"page scroll",
|
|
16511
|
-
fact`received: ${parsed.positional.length} positional arguments; expected exactly one target (CSS selector, ax:<name>, axid:<id>, or backend:<id>) plus --to <top|bottom|px>.`
|
|
16522
|
+
fact`received: ${parsed.positional.length} positional arguments; expected exactly one target (CSS selector or exact accessible name, ax:<name>, axid:<id>, or backend:<id>) plus --to <top|bottom|px>.`
|
|
16512
16523
|
);
|
|
16513
16524
|
}
|
|
16514
16525
|
if (parsed.to === void 0) {
|
|
@@ -16575,7 +16586,7 @@ var init_scroll = __esm({
|
|
|
16575
16586
|
USAGE3 = `capture page scroll <target> --to <top|bottom|px> \u2014 scroll one resolved container to a position
|
|
16576
16587
|
|
|
16577
16588
|
input:
|
|
16578
|
-
<target> resolved against the LIVE page: bare CSS selector, ax:<name> (case-insensitive substring), axid:<id>, backend:<id>; text: is not accepted; exactly one match required \u2014 zero or many matches is a structured error listing candidates
|
|
16589
|
+
<target> resolved against the LIVE page: bare CSS selector (takes precedence) or exact accessible name when CSS finds none, ax:<name> (case-insensitive substring), axid:<id>, backend:<id>; text: is not accepted; exactly one match required \u2014 zero or many matches is a structured error listing candidates
|
|
16579
16590
|
--to <dest> required destination: top, bottom, or a pixel offset (scrollTop value)
|
|
16580
16591
|
--settle <ms> network-settle window applied after the scroll (default: 1000; 2500 with an active session; 0 disables)
|
|
16581
16592
|
--no-screenshot skip the auto-screenshot
|
|
@@ -228112,7 +228123,7 @@ async function cmdPageShot(parsed, _args) {
|
|
|
228112
228123
|
return;
|
|
228113
228124
|
}
|
|
228114
228125
|
if (parsed.cropSelector !== void 0 && !parsed.cropSelector.trim()) {
|
|
228115
|
-
emitResult({ tag: "error", attrs: { command: "page shot", code: "invalid_crop_selector" }, summary: text`received an empty --crop-selector; expected a bare CSS selector, ax:<name>, axid:<id>, or backend:<id>.` }, { json: parsed.json });
|
|
228126
|
+
emitResult({ tag: "error", attrs: { command: "page shot", code: "invalid_crop_selector" }, summary: text`received an empty --crop-selector; expected a bare CSS selector or exact accessible name, ax:<name>, axid:<id>, or backend:<id>.` }, { json: parsed.json });
|
|
228116
228127
|
process.exitCode = 1;
|
|
228117
228128
|
return;
|
|
228118
228129
|
}
|
|
@@ -228223,7 +228234,7 @@ input:
|
|
|
228223
228234
|
--full-page transient override to the full scrollable content height for this capture
|
|
228224
228235
|
--color-scheme <dark|light> transient prefers-color-scheme override for this capture; cleared afterward
|
|
228225
228236
|
--crop <x,y,w,h> capture this page-coordinate CSS-pixel rect, intersected with the live visual viewport; x/y may be fractional, w/h must be positive
|
|
228226
|
-
--crop-selector <sel> resolve exactly one live target (bare CSS
|
|
228237
|
+
--crop-selector <sel> resolve exactly one live target (bare CSS takes precedence; exact accessible name applies when CSS finds none; ax:<name>, axid:<id>, or backend:<id>), scroll it into view, then crop its border box and surroundings
|
|
228227
228238
|
--pad <px> nonnegative integer CSS pixels added on every side of --crop-selector (default: 0; not accepted with --crop)
|
|
228228
228239
|
--zoom <factor> positive decimal CSS-to-image scale requested for a CSS crop; the 1600px image cap may produce a smaller reported scale
|
|
228229
228240
|
--out <path> destination file; default: the active session's shots/ sequence, or a fresh oneshot-*/page/ dir under the capture root when no session is active
|
|
@@ -228364,7 +228375,7 @@ use when driving or inspecting the tab a session opened or adopted; all verbs au
|
|
|
228364
228375
|
|
|
228365
228376
|
All verbs auto-target the active session tab; --target/--url override. The
|
|
228366
228377
|
driving verbs (click, type, scroll) resolve exactly one element via the
|
|
228367
|
-
unified target grammar \u2014 bare CSS selector, ax:<name>, axid:<id>,
|
|
228378
|
+
unified target grammar \u2014 bare CSS selector (which takes precedence) or exact accessible name when CSS finds none, ax:<name>, axid:<id>,
|
|
228368
228379
|
backend:<id> \u2014 and reject an ambiguous target with the candidate list.
|
|
228369
228380
|
During a live composed recording every verb routes through the recorder.
|
|
228370
228381
|
|
|
@@ -241508,7 +241519,7 @@ function recorderLiveClient(recorder) {
|
|
|
241508
241519
|
function resolutionError(failure) {
|
|
241509
241520
|
if (failure.code === "unsupported-prefix") {
|
|
241510
241521
|
return new DoActionError(
|
|
241511
|
-
`Unsupported --do target prefix in "${failure.input}": text: is query-leaf-only. Accepted prefixes: bare css selector, ax:<name>, axid:<id>, backend:<id>.`,
|
|
241522
|
+
`Unsupported --do target prefix in "${failure.input}": text: is query-leaf-only. Accepted prefixes: bare css selector (or exact accessible name when CSS finds none), ax:<name>, axid:<id>, backend:<id>.`,
|
|
241512
241523
|
"unsupported_target_prefix"
|
|
241513
241524
|
);
|
|
241514
241525
|
}
|
|
@@ -241814,7 +241825,7 @@ var init_rec = __esm({
|
|
|
241814
241825
|
input:
|
|
241815
241826
|
[url] --do <action> one-shot: open <url> (or record the active session tab when <url> is omitted), record one action, finalize
|
|
241816
241827
|
action click:<target> | scroll:<target>,to=<top|bottom|px>
|
|
241817
|
-
target css selector (bare string) | ax:<name> (case-insensitive substring) | axid:<id> | backend:<id>
|
|
241828
|
+
target css selector (takes precedence) or exact accessible name when CSS finds none (bare string) | ax:<name> (case-insensitive substring) | axid:<id> | backend:<id>
|
|
241818
241829
|
must resolve to exactly one live element; text: is not accepted by driving actions
|
|
241819
241830
|
--duration <seconds> keep recording after the action (default: 0)
|
|
241820
241831
|
--viewport <WxH> emulate a viewport for the recording window (restored after); exact <positive-safe-int>x<positive-safe-int> grammar with lowercase x and no whitespace
|
|
@@ -243333,7 +243344,7 @@ precedence: explicit flag > active session > env. \`session start\` adopts only
|
|
|
243333
243344
|
explicit --target.`;
|
|
243334
243345
|
}
|
|
243335
243346
|
function printVersion() {
|
|
243336
|
-
const declared = "1.4.
|
|
243347
|
+
const declared = "1.4.2";
|
|
243337
243348
|
if (declared) {
|
|
243338
243349
|
console.log(declared);
|
|
243339
243350
|
return;
|
package/package.json
CHANGED
|
@@ -72,7 +72,7 @@ const USAGE = `capture motion rec — record the page over time: composed (whate
|
|
|
72
72
|
input:
|
|
73
73
|
[url] --do <action> one-shot: open <url> (or record the active session tab when <url> is omitted), record one action, finalize
|
|
74
74
|
action click:<target> | scroll:<target>,to=<top|bottom|px>
|
|
75
|
-
target css selector (bare string) | ax:<name> (case-insensitive substring) | axid:<id> | backend:<id>
|
|
75
|
+
target css selector (takes precedence) or exact accessible name when CSS finds none (bare string) | ax:<name> (case-insensitive substring) | axid:<id> | backend:<id>
|
|
76
76
|
must resolve to exactly one live element; text: is not accepted by driving actions
|
|
77
77
|
--duration <seconds> keep recording after the action (default: 0)
|
|
78
78
|
--viewport <WxH> emulate a viewport for the recording window (restored after); exact <positive-safe-int>x<positive-safe-int> grammar with lowercase x and no whitespace
|
|
@@ -212,7 +212,7 @@ function recorderLiveClient(recorder: Pick<RecorderSession, 'handleCdp'>): LiveC
|
|
|
212
212
|
function resolutionError(failure: ResolutionFailure): DoActionError {
|
|
213
213
|
if (failure.code === 'unsupported-prefix') {
|
|
214
214
|
return new DoActionError(
|
|
215
|
-
`Unsupported --do target prefix in "${failure.input}": text: is query-leaf-only. Accepted prefixes: bare css selector, ax:<name>, axid:<id>, backend:<id>.`,
|
|
215
|
+
`Unsupported --do target prefix in "${failure.input}": text: is query-leaf-only. Accepted prefixes: bare css selector (or exact accessible name when CSS finds none), ax:<name>, axid:<id>, backend:<id>.`,
|
|
216
216
|
'unsupported_target_prefix',
|
|
217
217
|
);
|
|
218
218
|
}
|
|
@@ -112,7 +112,7 @@ export function emitResolutionError(parsed: ParsedArgs, command: string, failure
|
|
|
112
112
|
{
|
|
113
113
|
tag: 'error',
|
|
114
114
|
attrs: { command, code: 'unsupported_prefix' },
|
|
115
|
-
summary: fact`received: target \`${failure.input}\` — the \`text:\` prefix is not accepted by live driving verbs; expected one of: bare CSS selector, ax:<name>, axid:<id>, backend:<id>.`,
|
|
115
|
+
summary: fact`received: target \`${failure.input}\` — the \`text:\` prefix is not accepted by live driving verbs; expected one of: bare CSS selector (or exact accessible name when CSS finds none), ax:<name>, axid:<id>, backend:<id>.`,
|
|
116
116
|
followUp: fact`Retry \`${command}\` with \`ax:<name>\` (accessible-name substring) or a CSS selector; \`text:\` matching exists only on the query leaves.`,
|
|
117
117
|
},
|
|
118
118
|
{ json: parsed.json },
|
|
@@ -170,7 +170,7 @@ export function emitResolutionError(parsed: ParsedArgs, command: string, failure
|
|
|
170
170
|
const USAGE = `capture page click <target> — dispatch one real click on exactly one resolved element
|
|
171
171
|
|
|
172
172
|
input:
|
|
173
|
-
<target> resolved against the LIVE page: bare CSS selector, ax:<name> (case-insensitive substring over accessible names), axid:<id>, backend:<id>. text: is not accepted. Exactly one match required — zero or many matches is a structured error listing candidates with backend:<id> retry keys.
|
|
173
|
+
<target> resolved against the LIVE page: bare CSS selector (takes precedence) or exact accessible name when CSS finds none, ax:<name> (case-insensitive substring over accessible names), axid:<id>, backend:<id>. text: is not accepted. Exactly one match required — zero or many matches is a structured error listing candidates with backend:<id> retry keys.
|
|
174
174
|
--settle <ms> network-settle window applied after the click (default: 1000; 2500 with an active session; 0 disables)
|
|
175
175
|
--no-screenshot skip the auto-screenshot
|
|
176
176
|
output:
|
|
@@ -188,7 +188,7 @@ export async function cmdPageClick(parsed: ParsedArgs, _args: string[]): Promise
|
|
|
188
188
|
return emitInvalidInput(
|
|
189
189
|
parsed,
|
|
190
190
|
'page click',
|
|
191
|
-
fact`received: ${parsed.positional.length} positional arguments; expected exactly one target (CSS selector, ax:<name>, axid:<id>, or backend:<id>).`,
|
|
191
|
+
fact`received: ${parsed.positional.length} positional arguments; expected exactly one target (CSS selector or exact accessible name, ax:<name>, axid:<id>, or backend:<id>).`,
|
|
192
192
|
);
|
|
193
193
|
}
|
|
194
194
|
|
|
@@ -30,7 +30,7 @@ export const PAGE_USAGE = `capture page — verbs against the live session tab:
|
|
|
30
30
|
|
|
31
31
|
All verbs auto-target the active session tab; --target/--url override. The
|
|
32
32
|
driving verbs (click, type, scroll) resolve exactly one element via the
|
|
33
|
-
unified target grammar — bare CSS selector, ax:<name>, axid:<id>,
|
|
33
|
+
unified target grammar — bare CSS selector (which takes precedence) or exact accessible name when CSS finds none, ax:<name>, axid:<id>,
|
|
34
34
|
backend:<id> — and reject an ambiguous target with the candidate list.
|
|
35
35
|
During a live composed recording every verb routes through the recorder.
|
|
36
36
|
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
const USAGE = `capture page scroll <target> --to <top|bottom|px> — scroll one resolved container to a position
|
|
23
23
|
|
|
24
24
|
input:
|
|
25
|
-
<target> resolved against the LIVE page: bare CSS selector, ax:<name> (case-insensitive substring), axid:<id>, backend:<id>; text: is not accepted; exactly one match required — zero or many matches is a structured error listing candidates
|
|
25
|
+
<target> resolved against the LIVE page: bare CSS selector (takes precedence) or exact accessible name when CSS finds none, ax:<name> (case-insensitive substring), axid:<id>, backend:<id>; text: is not accepted; exactly one match required — zero or many matches is a structured error listing candidates
|
|
26
26
|
--to <dest> required destination: top, bottom, or a pixel offset (scrollTop value)
|
|
27
27
|
--settle <ms> network-settle window applied after the scroll (default: 1000; 2500 with an active session; 0 disables)
|
|
28
28
|
--no-screenshot skip the auto-screenshot
|
|
@@ -41,7 +41,7 @@ export async function cmdPageScroll(parsed: ParsedArgs, _args: string[]): Promis
|
|
|
41
41
|
return emitInvalidInput(
|
|
42
42
|
parsed,
|
|
43
43
|
'page scroll',
|
|
44
|
-
fact`received: ${parsed.positional.length} positional arguments; expected exactly one target (CSS selector, ax:<name>, axid:<id>, or backend:<id>) plus --to <top|bottom|px>.`,
|
|
44
|
+
fact`received: ${parsed.positional.length} positional arguments; expected exactly one target (CSS selector or exact accessible name, ax:<name>, axid:<id>, or backend:<id>) plus --to <top|bottom|px>.`,
|
|
45
45
|
);
|
|
46
46
|
}
|
|
47
47
|
if (parsed.to === undefined) {
|
|
@@ -42,7 +42,7 @@ input:
|
|
|
42
42
|
--full-page transient override to the full scrollable content height for this capture
|
|
43
43
|
--color-scheme <dark|light> transient prefers-color-scheme override for this capture; cleared afterward
|
|
44
44
|
--crop <x,y,w,h> capture this page-coordinate CSS-pixel rect, intersected with the live visual viewport; x/y may be fractional, w/h must be positive
|
|
45
|
-
--crop-selector <sel> resolve exactly one live target (bare CSS
|
|
45
|
+
--crop-selector <sel> resolve exactly one live target (bare CSS takes precedence; exact accessible name applies when CSS finds none; ax:<name>, axid:<id>, or backend:<id>), scroll it into view, then crop its border box and surroundings
|
|
46
46
|
--pad <px> nonnegative integer CSS pixels added on every side of --crop-selector (default: 0; not accepted with --crop)
|
|
47
47
|
--zoom <factor> positive decimal CSS-to-image scale requested for a CSS crop; the 1600px image cap may produce a smaller reported scale
|
|
48
48
|
--out <path> destination file; default: the active session's shots/ sequence, or a fresh oneshot-*/page/ dir under the capture root when no session is active
|
|
@@ -266,7 +266,7 @@ export async function cmdPageShot(parsed: ParsedArgs, _args: string[]): Promise<
|
|
|
266
266
|
return;
|
|
267
267
|
}
|
|
268
268
|
if (parsed.cropSelector !== undefined && !parsed.cropSelector.trim()) {
|
|
269
|
-
emitResult({ tag: 'error', attrs: { command: 'page shot', code: 'invalid_crop_selector' }, summary: text`received an empty --crop-selector; expected a bare CSS selector, ax:<name>, axid:<id>, or backend:<id>.` }, { json: parsed.json });
|
|
269
|
+
emitResult({ tag: 'error', attrs: { command: 'page shot', code: 'invalid_crop_selector' }, summary: text`received an empty --crop-selector; expected a bare CSS selector or exact accessible name, ax:<name>, axid:<id>, or backend:<id>.` }, { json: parsed.json });
|
|
270
270
|
process.exitCode = 1;
|
|
271
271
|
return;
|
|
272
272
|
}
|
|
@@ -28,7 +28,7 @@ const USAGE = `capture page type <text> [--into <target>] — type text into the
|
|
|
28
28
|
|
|
29
29
|
input:
|
|
30
30
|
<text> the text to insert (agent-supplied; echoed back in the result block)
|
|
31
|
-
--into <target> focus this field first — resolved against the LIVE page: bare CSS selector, ax:<name> (case-insensitive substring), axid:<id>, backend:<id>; text: is not accepted; exactly one match required
|
|
31
|
+
--into <target> focus this field first — resolved against the LIVE page: bare CSS selector (takes precedence) or exact accessible name when CSS finds none, ax:<name> (case-insensitive substring), axid:<id>, backend:<id>; text: is not accepted; exactly one match required
|
|
32
32
|
--settle <ms> network-settle window applied after typing (default: 500; 1500 with an active session; 0 disables)
|
|
33
33
|
--no-screenshot skip the auto-screenshot
|
|
34
34
|
output:
|
package/src/cdp/leaf-grammar.ts
CHANGED
|
@@ -84,7 +84,7 @@ export type DoAction =
|
|
|
84
84
|
export function parseDoAction(action: string): DoAction {
|
|
85
85
|
if (action.startsWith('click:')) {
|
|
86
86
|
const target = action.slice('click:'.length);
|
|
87
|
-
if (!target) throw invalidInput('Invalid --do action: click requires a target — a css selector, ax:<name>, axid:<id>, or backend:<id>.');
|
|
87
|
+
if (!target) throw invalidInput('Invalid --do action: click requires a target — a css selector (or exact accessible name when CSS finds none), ax:<name>, axid:<id>, or backend:<id>.');
|
|
88
88
|
return { verb: 'click', target };
|
|
89
89
|
}
|
|
90
90
|
if (action.startsWith('scroll:')) {
|
|
@@ -95,5 +95,5 @@ export function parseDoAction(action: string): DoAction {
|
|
|
95
95
|
if (!isScrollDestination(to)) throw invalidInput('Invalid --do action: scroll requires `scroll:<target>,to=<top|bottom|px>`.');
|
|
96
96
|
return { verb: 'scroll', target: spec.slice(0, comma), to };
|
|
97
97
|
}
|
|
98
|
-
throw invalidInput('Unsupported --do action. Supported actions: click:<target>; scroll:<target>,to=<top|bottom|px> — target is a css selector, ax:<name>, axid:<id>, or backend:<id>.');
|
|
98
|
+
throw invalidInput('Unsupported --do action. Supported actions: click:<target>; scroll:<target>,to=<top|bottom|px> — target is a css selector (or exact accessible name when CSS finds none), ax:<name>, axid:<id>, or backend:<id>.');
|
|
99
99
|
}
|
package/src/interact.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* (`src/output/selector.ts`'s `parseSelectorInput`) and resolves it against
|
|
7
7
|
* the LIVE page (not collector-stored records), per prefix:
|
|
8
8
|
*
|
|
9
|
-
* bare string live CSS query
|
|
9
|
+
* bare string live CSS query, or an exact accessible-name match when CSS finds none
|
|
10
10
|
* backend:<id> identity — the canonical retry key in every resolution failure
|
|
11
11
|
* ax:<name> case-insensitive SUBSTRING over live `Accessibility.getFullAXTree` names
|
|
12
12
|
* axid:<id> AX node id from the same live fetch
|
|
@@ -172,7 +172,7 @@ export async function resolveLiveTarget(
|
|
|
172
172
|
return settleAxMatches('axid', input, matches);
|
|
173
173
|
}
|
|
174
174
|
case 'css':
|
|
175
|
-
return
|
|
175
|
+
return resolveBareTarget(client, input, parsed.value);
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
|
|
@@ -220,6 +220,32 @@ function settleAxMatches(
|
|
|
220
220
|
};
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
+
/**
|
|
224
|
+
* Bare targets preserve CSS behavior when they select one or many elements;
|
|
225
|
+
* when CSS selects none (or rejects the string), an exact accessible-name
|
|
226
|
+
* lookup lets an element name emitted by `page elements` drive directly.
|
|
227
|
+
* `ax:` remains the explicit case-insensitive substring query.
|
|
228
|
+
*/
|
|
229
|
+
async function resolveBareTarget(
|
|
230
|
+
client: LiveClient,
|
|
231
|
+
input: string,
|
|
232
|
+
selector: string,
|
|
233
|
+
): Promise<ResolvedTarget | ResolutionFailure> {
|
|
234
|
+
const css = await resolveLiveCss(client, input, selector);
|
|
235
|
+
if (css.ok || css.code === 'ambiguous') return css;
|
|
236
|
+
|
|
237
|
+
const normalized = normalizeAccessibleName(input);
|
|
238
|
+
if (!normalized) return css;
|
|
239
|
+
const matches = (await readFullAXTree(client)).filter(
|
|
240
|
+
(node) =>
|
|
241
|
+
node.backendDOMNodeId !== undefined &&
|
|
242
|
+
node.name?.value !== undefined &&
|
|
243
|
+
normalizeAccessibleName(node.name.value) === normalized,
|
|
244
|
+
);
|
|
245
|
+
const ax = settleAxMatches('ax', input, matches);
|
|
246
|
+
return ax.ok || ax.code === 'ambiguous' ? ax : css;
|
|
247
|
+
}
|
|
248
|
+
|
|
223
249
|
async function resolveLiveCss(
|
|
224
250
|
client: LiveClient,
|
|
225
251
|
input: string,
|