browser-debugger-cli 0.8.0 → 0.9.0
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 +4 -1
- package/dist/cdp/schema.d.ts +4 -1
- package/dist/cdp/schema.js +48 -7
- package/dist/commands/cdp.js +3 -2
- package/dist/commands/cleanup.d.ts +11 -0
- package/dist/commands/cleanup.js +161 -57
- package/dist/commands/console.d.ts +20 -1
- package/dist/commands/console.js +57 -17
- package/dist/commands/details.js +3 -2
- package/dist/commands/dom/DomElementResolver.d.ts +10 -3
- package/dist/commands/dom/DomElementResolver.js +35 -17
- package/dist/commands/dom/a11y.d.ts +10 -0
- package/dist/commands/dom/a11y.js +27 -5
- package/dist/commands/dom/eval.d.ts +3 -1
- package/dist/commands/dom/eval.js +29 -4
- package/dist/commands/dom/form.js +16 -62
- package/dist/commands/dom/formInteraction.js +152 -113
- package/dist/commands/dom/formSummary.d.ts +49 -0
- package/dist/commands/dom/formSummary.js +180 -0
- package/dist/commands/dom/frames.d.ts +2 -1
- package/dist/commands/dom/frames.js +17 -2
- package/dist/commands/dom/get.d.ts +6 -5
- package/dist/commands/dom/get.js +92 -82
- package/dist/commands/dom/helpers/index.d.ts +1 -1
- package/dist/commands/dom/helpers/index.js +1 -1
- package/dist/commands/dom/helpers/query.d.ts +44 -17
- package/dist/commands/dom/helpers/query.js +244 -97
- package/dist/commands/dom/helpers/runElementCommand.d.ts +10 -2
- package/dist/commands/dom/helpers/runElementCommand.js +97 -30
- package/dist/commands/dom/helpers/screenshot.d.ts +4 -1
- package/dist/commands/dom/helpers/screenshot.js +164 -49
- package/dist/commands/dom/index.d.ts +3 -1
- package/dist/commands/dom/index.js +16 -6
- package/dist/commands/dom/layout.d.ts +14 -0
- package/dist/commands/dom/layout.js +54 -0
- package/dist/commands/dom/listeners.d.ts +5 -1
- package/dist/commands/dom/listeners.js +13 -3
- package/dist/commands/dom/query.js +2 -3
- package/dist/commands/dom/screenshot.d.ts +12 -2
- package/dist/commands/dom/screenshot.js +27 -3
- package/dist/commands/dom/semanticUtils.d.ts +6 -13
- package/dist/commands/dom/semanticUtils.js +15 -19
- package/dist/commands/dom/wait.d.ts +13 -0
- package/dist/commands/dom/wait.js +83 -0
- package/dist/commands/helpJson.js +2 -2
- package/dist/commands/network/list.js +4 -11
- package/dist/commands/optionBehaviors.js +112 -21
- package/dist/commands/page.d.ts +2 -1
- package/dist/commands/page.js +41 -5
- package/dist/commands/peek.js +4 -11
- package/dist/commands/sessions.d.ts +8 -0
- package/dist/commands/sessions.js +19 -0
- package/dist/commands/shared/CommandRunner.js +4 -4
- package/dist/commands/shared/dataFetcher.js +2 -2
- package/dist/commands/shared/followMode.d.ts +21 -1
- package/dist/commands/shared/followMode.js +29 -2
- package/dist/commands/shared/handleValidationError.d.ts +2 -2
- package/dist/commands/shared/handleValidationError.js +12 -3
- package/dist/commands/shared/optionTypes.d.ts +40 -5
- package/dist/commands/shared/startHelpers.js +12 -3
- package/dist/commands/shared/validation.d.ts +3 -2
- package/dist/commands/shared/validation.js +4 -3
- package/dist/commands/start.d.ts +63 -0
- package/dist/commands/start.js +115 -15
- package/dist/commands/status.js +29 -7
- package/dist/commands/stop.js +7 -6
- package/dist/commands/tail.js +4 -11
- package/dist/commands/types.d.ts +2 -0
- package/dist/commands.js +2 -0
- package/dist/connection/chromeIdentity.d.ts +65 -0
- package/dist/connection/chromeIdentity.js +143 -0
- package/dist/connection/launcher/profilePreferences.d.ts +47 -0
- package/dist/connection/launcher/profilePreferences.js +151 -0
- package/dist/connection/launcher.d.ts +21 -2
- package/dist/connection/launcher.js +42 -16
- package/dist/connection/portReservation.d.ts +14 -4
- package/dist/connection/portReservation.js +21 -6
- package/dist/connection/startupExit.d.ts +8 -0
- package/dist/connection/startupExit.js +15 -6
- package/dist/constants.d.ts +6 -2
- package/dist/constants.js +9 -2
- package/dist/daemon/SessionController.js +23 -7
- package/dist/daemon/errors.d.ts +1 -1
- package/dist/daemon/errors.js +1 -1
- package/dist/daemon/launcher.d.ts +2 -1
- package/dist/daemon/launcher.js +5 -6
- package/dist/daemon/server/SocketServer.js +1 -2
- package/dist/daemon/session/Session.d.ts +13 -0
- package/dist/daemon/session/Session.js +57 -8
- package/dist/daemon/session/chromeConnection.d.ts +9 -0
- package/dist/daemon/session/chromeConnection.js +45 -8
- package/dist/daemon/session/commandRegistry.js +52 -62
- package/dist/daemon/session/interactions.d.ts +35 -9
- package/dist/daemon/session/interactions.js +36 -9
- package/dist/daemon/session/triggeredRequests.d.ts +67 -0
- package/dist/daemon/session/triggeredRequests.js +157 -0
- package/dist/daemon/session/types.d.ts +5 -1
- package/dist/daemon.js +5393 -1600
- package/dist/errors/messages.d.ts +387 -24
- package/dist/errors/messages.js +761 -67
- package/dist/index.js +3976 -1558
- package/dist/ipc/client.d.ts +12 -1
- package/dist/ipc/client.js +22 -3
- package/dist/ipc/protocol/commands.d.ts +89 -4
- package/dist/ipc/protocol/commands.js +2 -0
- package/dist/ipc/protocol/domTypes.d.ts +258 -7
- package/dist/ipc/session/lifecycle.d.ts +8 -1
- package/dist/ipc/session/queries.d.ts +5 -1
- package/dist/ipc/session/types.d.ts +5 -0
- package/dist/ipc/transport/index.d.ts +2 -1
- package/dist/ipc/transport/index.js +2 -2
- package/dist/runtime/dom/actionEffects.d.ts +106 -0
- package/dist/runtime/dom/actionEffects.js +256 -0
- package/dist/runtime/dom/actionEffectsScripts.d.ts +52 -0
- package/dist/runtime/dom/actionEffectsScripts.js +234 -0
- package/dist/runtime/dom/elementGeometry.d.ts +170 -0
- package/dist/runtime/dom/elementGeometry.js +553 -0
- package/dist/runtime/dom/elementInfo.d.ts +77 -0
- package/dist/runtime/dom/elementInfo.js +191 -0
- package/dist/runtime/dom/evalHelpers.d.ts +51 -6
- package/dist/runtime/dom/evalHelpers.js +136 -26
- package/dist/runtime/dom/eventListeners.d.ts +2 -1
- package/dist/runtime/dom/eventListeners.js +174 -47
- package/dist/runtime/dom/formDiscovery.d.ts +1 -1
- package/dist/runtime/dom/formDiscovery.js +116 -16
- package/dist/runtime/dom/formFillHelpers/fill.d.ts +10 -0
- package/dist/runtime/dom/formFillHelpers/fill.js +125 -10
- package/dist/runtime/dom/formFillHelpers/index.d.ts +2 -2
- package/dist/runtime/dom/formFillHelpers/index.js +2 -2
- package/dist/runtime/dom/formFillHelpers/pressKey.js +14 -3
- package/dist/runtime/dom/formFillHelpers/scroll.d.ts +3 -0
- package/dist/runtime/dom/formFillHelpers/scroll.js +60 -18
- package/dist/runtime/dom/formFillHelpers/shared.d.ts +17 -0
- package/dist/runtime/dom/formFillHelpers/shared.js +25 -1
- package/dist/runtime/dom/formFillHelpers/stability.d.ts +20 -6
- package/dist/runtime/dom/formFillHelpers/stability.js +50 -19
- package/dist/runtime/dom/formSubmitHelpers.d.ts +3 -0
- package/dist/runtime/dom/formSubmitHelpers.js +89 -15
- package/dist/runtime/dom/frameLayout.d.ts +60 -0
- package/dist/runtime/dom/frameLayout.js +140 -0
- package/dist/runtime/dom/frameOrigin.d.ts +50 -0
- package/dist/runtime/dom/frameOrigin.js +62 -0
- package/dist/runtime/dom/frameScopedConnection.d.ts +92 -0
- package/dist/runtime/dom/frameScopedConnection.js +252 -0
- package/dist/runtime/dom/frameSelection.d.ts +1 -1
- package/dist/runtime/dom/frameSelection.js +2 -2
- package/dist/runtime/dom/frames.d.ts +25 -2
- package/dist/runtime/dom/frames.js +202 -63
- package/dist/runtime/dom/layout.d.ts +67 -0
- package/dist/runtime/dom/layout.js +333 -0
- package/dist/runtime/dom/listenerPageScripts.d.ts +66 -0
- package/dist/runtime/dom/listenerPageScripts.js +279 -0
- package/dist/runtime/dom/listenerSummary.d.ts +132 -11
- package/dist/runtime/dom/listenerSummary.js +344 -22
- package/dist/runtime/dom/pageActivity.d.ts +41 -0
- package/dist/runtime/dom/pageActivity.js +123 -0
- package/dist/runtime/dom/reactEventHelpers.d.ts +58 -2
- package/dist/runtime/dom/reactEventHelpers.js +212 -41
- package/dist/runtime/dom/targetNode.d.ts +80 -27
- package/dist/runtime/dom/targetNode.js +249 -33
- package/dist/runtime/dom/wait.d.ts +25 -0
- package/dist/runtime/dom/wait.js +199 -0
- package/dist/runtime/dom/waitCondition.d.ts +71 -0
- package/dist/runtime/dom/waitCondition.js +75 -0
- package/dist/runtime/page/emulation.d.ts +51 -0
- package/dist/runtime/page/emulation.js +80 -0
- package/dist/runtime/page/loadingState.d.ts +36 -0
- package/dist/runtime/page/loadingState.js +86 -0
- package/dist/runtime/page/navigation.d.ts +46 -2
- package/dist/runtime/page/navigation.js +69 -33
- package/dist/session/QueryCacheManager.d.ts +11 -1
- package/dist/session/QueryCacheManager.js +25 -3
- package/dist/session/chromeOwners.d.ts +34 -0
- package/dist/session/chromeOwners.js +51 -0
- package/dist/session/cleanup/staleSession.d.ts +11 -1
- package/dist/session/cleanup/staleSession.js +17 -6
- package/dist/session/cleanup/userCommands.js +2 -4
- package/dist/session/metadata.d.ts +5 -1
- package/dist/session/metadata.js +2 -1
- package/dist/session/paths.d.ts +77 -3
- package/dist/session/paths.js +111 -5
- package/dist/session/port.d.ts +31 -7
- package/dist/session/port.js +50 -43
- package/dist/session/portClaims.d.ts +66 -0
- package/dist/session/portClaims.js +284 -0
- package/dist/session/sessionList.d.ts +58 -0
- package/dist/session/sessionList.js +199 -0
- package/dist/session/sessionName.d.ts +46 -0
- package/dist/session/sessionName.js +97 -0
- package/dist/telemetry/a11y.d.ts +8 -3
- package/dist/telemetry/a11y.js +92 -28
- package/dist/telemetry/requestKinds.d.ts +32 -0
- package/dist/telemetry/requestKinds.js +61 -0
- package/dist/telemetry/requestState.d.ts +31 -0
- package/dist/telemetry/requestState.js +38 -0
- package/dist/types.d.ts +80 -3
- package/dist/ui/formatters/a11y.js +3 -0
- package/dist/ui/formatters/console/chronological.d.ts +8 -0
- package/dist/ui/formatters/console/chronological.js +17 -4
- package/dist/ui/formatters/console/json.js +3 -4
- package/dist/ui/formatters/console/shared.d.ts +12 -0
- package/dist/ui/formatters/console.d.ts +2 -2
- package/dist/ui/formatters/console.js +1 -1
- package/dist/ui/formatters/details.js +2 -1
- package/dist/ui/formatters/dom.d.ts +26 -14
- package/dist/ui/formatters/dom.js +65 -52
- package/dist/ui/formatters/form.js +29 -18
- package/dist/ui/formatters/layout.d.ts +31 -0
- package/dist/ui/formatters/layout.js +53 -0
- package/dist/ui/formatters/listeners.d.ts +3 -2
- package/dist/ui/formatters/listeners.js +73 -9
- package/dist/ui/formatters/networkHeaders.js +13 -0
- package/dist/ui/formatters/preview.js +2 -1
- package/dist/ui/formatters/requestStatus.d.ts +1 -17
- package/dist/ui/formatters/requestStatus.js +2 -30
- package/dist/ui/formatters/sessions.d.ts +12 -0
- package/dist/ui/formatters/sessions.js +40 -0
- package/dist/ui/formatters/status.d.ts +21 -2
- package/dist/ui/formatters/status.js +47 -10
- package/dist/ui/formatters/triggeredRequests.d.ts +36 -0
- package/dist/ui/formatters/triggeredRequests.js +65 -0
- package/dist/ui/formatting.d.ts +10 -0
- package/dist/ui/formatting.js +28 -36
- package/dist/ui/messages/chrome.d.ts +9 -0
- package/dist/ui/messages/chrome.js +17 -5
- package/dist/ui/messages/commands.d.ts +388 -14
- package/dist/ui/messages/commands.js +664 -21
- package/dist/ui/messages/consoleMessages.d.ts +10 -0
- package/dist/ui/messages/consoleMessages.js +17 -0
- package/dist/ui/messages/hints.js +2 -1
- package/dist/ui/messages/preview.js +5 -4
- package/dist/ui/messages/session.d.ts +16 -21
- package/dist/ui/messages/session.js +28 -26
- package/dist/ui/messages/sessionCommand.d.ts +43 -0
- package/dist/ui/messages/sessionCommand.js +52 -0
- package/dist/utils/async.d.ts +8 -0
- package/dist/utils/async.js +19 -0
- package/dist/utils/http.d.ts +22 -1
- package/dist/utils/http.js +28 -9
- package/dist/utils/selectorFilters.d.ts +36 -8
- package/dist/utils/selectorFilters.js +267 -53
- package/dist/utils/shellDetection.d.ts +8 -2
- package/dist/utils/shellDetection.js +120 -33
- package/dist/utils/suggestions.d.ts +26 -0
- package/dist/utils/suggestions.js +73 -0
- package/dist/utils/taskMappings.js +10 -0
- package/dist/utils/url.d.ts +12 -2
- package/dist/utils/url.js +69 -7
- package/package.json +1 -1
- package/dist/ui/formatters/sessionFormatters.d.ts +0 -58
- package/dist/ui/formatters/sessionFormatters.js +0 -121
|
@@ -11,17 +11,17 @@
|
|
|
11
11
|
* ```typescript
|
|
12
12
|
* const resolver = DomElementResolver.getInstance();
|
|
13
13
|
*
|
|
14
|
-
* const target = await resolver.resolve('0');
|
|
14
|
+
* const target = await resolver.resolve('0', undefined, 'click');
|
|
15
15
|
* // { success: true, selector: '.cached-selector', backendNodeId: 42 }
|
|
16
16
|
*
|
|
17
|
-
* const target = await resolver.resolve('button.submit');
|
|
17
|
+
* const target = await resolver.resolve('button.submit', undefined, 'click');
|
|
18
18
|
* // { success: true, selector: 'button.submit' }
|
|
19
19
|
* ```
|
|
20
20
|
*/
|
|
21
21
|
import { noActiveSessionError } from '../shared/CommandRunner.js';
|
|
22
22
|
import { CommandError } from '../../errors/index.js';
|
|
23
|
-
import {
|
|
24
|
-
import { QueryCacheManager } from '../../session/QueryCacheManager.js';
|
|
23
|
+
import { cachedIndexOutOfRangeError, indexWithIndexOptionError, staleNodeError, } from '../../errors/messages.js';
|
|
24
|
+
import { QueryCacheManager, indexSourceOf, } from '../../session/QueryCacheManager.js';
|
|
25
25
|
import { isDaemonAlive } from '../../session/daemonSocket.js';
|
|
26
26
|
import { EXIT_CODES } from '../../utils/exitCodes.js';
|
|
27
27
|
/**
|
|
@@ -58,14 +58,15 @@ export class DomElementResolver {
|
|
|
58
58
|
*
|
|
59
59
|
* @param selectorOrIndex - CSS selector or numeric index from query results
|
|
60
60
|
* @param explicitIndex - Optional explicit --index flag value (0-based, selectors only)
|
|
61
|
+
* @param command - `bdg dom` subcommand being run, e.g. "click" (for suggestions)
|
|
61
62
|
* @returns Resolution result
|
|
62
63
|
*/
|
|
63
|
-
async resolve(selectorOrIndex, explicitIndex) {
|
|
64
|
+
async resolve(selectorOrIndex, explicitIndex, command) {
|
|
64
65
|
if (!this.isNumericIndex(selectorOrIndex)) {
|
|
65
66
|
return { success: true, selector: selectorOrIndex, index: explicitIndex };
|
|
66
67
|
}
|
|
67
68
|
if (explicitIndex !== undefined) {
|
|
68
|
-
const err = indexWithIndexOptionError(selectorOrIndex);
|
|
69
|
+
const err = indexWithIndexOptionError(selectorOrIndex, command);
|
|
69
70
|
return {
|
|
70
71
|
success: false,
|
|
71
72
|
error: err.message,
|
|
@@ -74,10 +75,9 @@ export class DomElementResolver {
|
|
|
74
75
|
};
|
|
75
76
|
}
|
|
76
77
|
try {
|
|
77
|
-
const
|
|
78
|
-
const { node, selector } = await this.lookup(index);
|
|
78
|
+
const { node, selector, source } = await this.lookup(parseInt(selectorOrIndex, 10));
|
|
79
79
|
if (node.nodeId <= 0) {
|
|
80
|
-
const err = staleNodeError(index);
|
|
80
|
+
const err = staleNodeError(source.index, source);
|
|
81
81
|
return {
|
|
82
82
|
success: false,
|
|
83
83
|
error: err.message,
|
|
@@ -85,7 +85,13 @@ export class DomElementResolver {
|
|
|
85
85
|
suggestion: err.suggestion,
|
|
86
86
|
};
|
|
87
87
|
}
|
|
88
|
-
return {
|
|
88
|
+
return {
|
|
89
|
+
success: true,
|
|
90
|
+
selector: node.selector ?? selector,
|
|
91
|
+
backendNodeId: node.nodeId,
|
|
92
|
+
source,
|
|
93
|
+
preview: cachedNodePreview(node),
|
|
94
|
+
};
|
|
89
95
|
}
|
|
90
96
|
catch (error) {
|
|
91
97
|
if (!(error instanceof CommandError))
|
|
@@ -107,14 +113,14 @@ export class DomElementResolver {
|
|
|
107
113
|
* or the element is no longer in the page (87)
|
|
108
114
|
*/
|
|
109
115
|
async getNodeIdForIndex(index) {
|
|
110
|
-
const { node } = await this.lookup(index);
|
|
116
|
+
const { node, source } = await this.lookup(index);
|
|
111
117
|
if (node.nodeId <= 0) {
|
|
112
|
-
const err = staleNodeError(index);
|
|
118
|
+
const err = staleNodeError(index, source);
|
|
113
119
|
throw new CommandError(err.message, { suggestion: err.suggestion }, EXIT_CODES.STALE_CACHE);
|
|
114
120
|
}
|
|
115
121
|
const { assertNodeAttached } = await import('./helpers/index.js');
|
|
116
|
-
await assertNodeAttached(node.nodeId,
|
|
117
|
-
return node;
|
|
122
|
+
await assertNodeAttached(node.nodeId, source);
|
|
123
|
+
return { nodeId: node.nodeId, source };
|
|
118
124
|
}
|
|
119
125
|
/**
|
|
120
126
|
* Check if the argument is a numeric index.
|
|
@@ -140,12 +146,24 @@ export class DomElementResolver {
|
|
|
140
146
|
throw new CommandError(validation.error ?? 'No cached query results found', validation.suggestion ? { suggestion: validation.suggestion } : {}, EXIT_CODES.INVALID_ARGUMENTS);
|
|
141
147
|
}
|
|
142
148
|
const { nodes, selector } = validation.cache;
|
|
149
|
+
const source = indexSourceOf(index, selector);
|
|
143
150
|
const node = nodes.find((n) => n.index === index);
|
|
144
151
|
if (!node) {
|
|
145
|
-
const err =
|
|
146
|
-
throw new CommandError(
|
|
152
|
+
const err = cachedIndexOutOfRangeError(source, nodes.length);
|
|
153
|
+
throw new CommandError(err.message, { suggestion: err.suggestion }, EXIT_CODES.STALE_CACHE);
|
|
147
154
|
}
|
|
148
|
-
return { node, selector };
|
|
155
|
+
return { node, selector, source };
|
|
149
156
|
}
|
|
150
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* What a cached element was when it was listed.
|
|
160
|
+
*
|
|
161
|
+
* @param node - Cached node
|
|
162
|
+
* @returns e.g. `h3 "Welcome"`, `button`; undefined without a tag
|
|
163
|
+
*/
|
|
164
|
+
function cachedNodePreview(node) {
|
|
165
|
+
if (!node.tag)
|
|
166
|
+
return undefined;
|
|
167
|
+
return node.preview ? `${node.tag} "${node.preview}"` : node.tag;
|
|
168
|
+
}
|
|
151
169
|
//# sourceMappingURL=DomElementResolver.js.map
|
|
@@ -9,6 +9,16 @@
|
|
|
9
9
|
* Uses IPC/callCDP pattern for consistency with other DOM commands.
|
|
10
10
|
*/
|
|
11
11
|
import type { Command } from 'commander';
|
|
12
|
+
import type { A11yQueryResult } from '../../types.js';
|
|
13
|
+
/**
|
|
14
|
+
* The matches to list: the first `limit` (all with 0), counting the rest as
|
|
15
|
+
* omitted. All of them are cached, so their indices work either way.
|
|
16
|
+
*
|
|
17
|
+
* @param result - Query result
|
|
18
|
+
* @param limit - Matches to list (0 = all)
|
|
19
|
+
* @returns The result with the listed matches
|
|
20
|
+
*/
|
|
21
|
+
export declare function limitMatches(result: A11yQueryResult, limit: number): A11yQueryResult;
|
|
12
22
|
/**
|
|
13
23
|
* Register accessibility commands under 'bdg dom a11y'
|
|
14
24
|
*
|
|
@@ -12,12 +12,15 @@ import { DomElementResolver } from './DomElementResolver.js';
|
|
|
12
12
|
import { getDomContext, resolveBackendNodeIds } from './helpers/index.js';
|
|
13
13
|
import { runCommand, runJsonCommand } from '../shared/CommandRunner.js';
|
|
14
14
|
import { jsonOption } from '../shared/commonOptions.js';
|
|
15
|
+
import { integerOption } from '../shared/validation.js';
|
|
15
16
|
import { CommandError } from '../../errors/index.js';
|
|
16
17
|
import { elementNotFoundError, invalidQueryPatternError, noA11yNodesFoundError, notInAccessibilityTreeError, } from '../../errors/messages.js';
|
|
17
|
-
import { QueryCacheManager } from '../../session/QueryCacheManager.js';
|
|
18
|
+
import { A11Y_CACHE_SELECTOR_PREFIX, QueryCacheManager } from '../../session/QueryCacheManager.js';
|
|
18
19
|
import { a11yIgnoredReasons, collectA11yTree, queryA11yTree, parseQueryPattern, resolveA11yNode, } from '../../telemetry/a11y.js';
|
|
19
20
|
import { formatA11yTree, formatA11yQueryResult, formatA11yNodeWithContext, } from '../../ui/formatters/a11y.js';
|
|
20
21
|
import { EXIT_CODES } from '../../utils/exitCodes.js';
|
|
22
|
+
/** Matches `dom a11y query` lists by default in human output (a page can have hundreds of links; JSON lists all) */
|
|
23
|
+
const A11Y_QUERY_LIMIT = 50;
|
|
21
24
|
/**
|
|
22
25
|
* Handle bdg dom a11y tree command
|
|
23
26
|
*
|
|
@@ -61,7 +64,8 @@ function quoteQueryValue(text) {
|
|
|
61
64
|
* Handle bdg dom a11y query <pattern> command
|
|
62
65
|
*
|
|
63
66
|
* Queries the accessibility tree using role/name/description patterns via IPC.
|
|
64
|
-
* Pattern format: "role:button name:Submit" (
|
|
67
|
+
* Pattern format: "role:button name:Submit" (key:value or key=value pairs; a
|
|
68
|
+
* name or description may contain spaces and colons)
|
|
65
69
|
*
|
|
66
70
|
* @param pattern - Query pattern string
|
|
67
71
|
* @param options - Command options
|
|
@@ -88,17 +92,34 @@ async function handleA11yQuery(pattern, options) {
|
|
|
88
92
|
}
|
|
89
93
|
const indexed = { ...result, nodes: result.nodes.map((node, index) => ({ ...node, index })) };
|
|
90
94
|
await QueryCacheManager.getInstance().set({
|
|
91
|
-
selector:
|
|
95
|
+
selector: `${A11Y_CACHE_SELECTOR_PREFIX}${pattern}`,
|
|
92
96
|
count: indexed.count,
|
|
93
97
|
nodes: indexed.nodes.map((node) => ({
|
|
94
98
|
index: node.index,
|
|
95
99
|
nodeId: node.backendDOMNodeId ?? 0,
|
|
96
100
|
tag: node.role,
|
|
101
|
+
...(node.name && { preview: node.name }),
|
|
97
102
|
})),
|
|
98
103
|
});
|
|
99
|
-
return {
|
|
104
|
+
return {
|
|
105
|
+
success: true,
|
|
106
|
+
data: limitMatches(indexed, options.limit ?? (options.json ? 0 : A11Y_QUERY_LIMIT)),
|
|
107
|
+
};
|
|
100
108
|
}, options, formatA11yQueryResult);
|
|
101
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* The matches to list: the first `limit` (all with 0), counting the rest as
|
|
112
|
+
* omitted. All of them are cached, so their indices work either way.
|
|
113
|
+
*
|
|
114
|
+
* @param result - Query result
|
|
115
|
+
* @param limit - Matches to list (0 = all)
|
|
116
|
+
* @returns The result with the listed matches
|
|
117
|
+
*/
|
|
118
|
+
export function limitMatches(result, limit) {
|
|
119
|
+
if (limit === 0 || result.nodes.length <= limit)
|
|
120
|
+
return result;
|
|
121
|
+
return { ...result, nodes: result.nodes.slice(0, limit), omitted: result.nodes.length - limit };
|
|
122
|
+
}
|
|
102
123
|
/**
|
|
103
124
|
* Handle bdg dom a11y describe <selectorOrIndex> command
|
|
104
125
|
*
|
|
@@ -192,7 +213,8 @@ export function registerA11yCommands(domCmd) {
|
|
|
192
213
|
a11y
|
|
193
214
|
.command('query')
|
|
194
215
|
.description('Query elements by accessibility properties (e.g., "role:button", "name:Submit")')
|
|
195
|
-
.argument('<pattern>',
|
|
216
|
+
.argument('<pattern>', "Fields role, name, description as key:value or key=value, separated by spaces or commas; * is a wildcard. A name or description runs to the next field or the end, so it may contain spaces and colons; quote the whole pattern (e.g. 'role=button name=Sign in', 'name=E-mail address:')")
|
|
217
|
+
.option('--limit <n>', `Matches to list (default: ${A11Y_QUERY_LIMIT}, all with --json; 0 = all); all are indexed`, integerOption(0))
|
|
196
218
|
.addOption(jsonOption())
|
|
197
219
|
.action(async (pattern, options) => {
|
|
198
220
|
await handleA11yQuery(pattern, options);
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { DomEvalCommandOptions } from '../shared/optionTypes.js';
|
|
9
9
|
/**
|
|
10
|
-
* Handle `bdg dom eval <script> [--frame <frame>]`.
|
|
10
|
+
* Handle `bdg dom eval <script> [--frame <frame>]`. With `--frame`, the
|
|
11
|
+
* frame the script ran in is a `Frame:` line on stderr (JSON: `frame`), so
|
|
12
|
+
* stdout stays the bare value for pipes.
|
|
11
13
|
*/
|
|
12
14
|
export declare function handleDomEval(script: string, options: DomEvalCommandOptions): Promise<void>;
|
|
13
15
|
//# sourceMappingURL=eval.d.ts.map
|
|
@@ -5,13 +5,17 @@
|
|
|
5
5
|
* CLI-side handler. Actual evaluation happens in the daemon via the
|
|
6
6
|
* `dom_eval` IPC command so the session's persistent CDP connection is reused.
|
|
7
7
|
*/
|
|
8
|
+
import { documentReadyState } from './helpers/query.js';
|
|
8
9
|
import { runCommand } from '../shared/CommandRunner.js';
|
|
9
|
-
import { emptyScriptError } from '../../errors/messages.js';
|
|
10
|
+
import { emptyScriptError, withLoadingHint } from '../../errors/messages.js';
|
|
10
11
|
import { domEval } from '../../ipc/client.js';
|
|
11
12
|
import { formatDomEval } from '../../ui/formatters/dom.js';
|
|
13
|
+
import { evalFrameLine } from '../../ui/messages/commands.js';
|
|
12
14
|
import { EXIT_CODES } from '../../utils/exitCodes.js';
|
|
13
15
|
/**
|
|
14
|
-
* Handle `bdg dom eval <script> [--frame <frame>]`.
|
|
16
|
+
* Handle `bdg dom eval <script> [--frame <frame>]`. With `--frame`, the
|
|
17
|
+
* frame the script ran in is a `Frame:` line on stderr (JSON: `frame`), so
|
|
18
|
+
* stdout stays the bare value for pipes.
|
|
15
19
|
*/
|
|
16
20
|
export async function handleDomEval(script, options) {
|
|
17
21
|
await runCommand(async () => {
|
|
@@ -26,18 +30,39 @@ export async function handleDomEval(script, options) {
|
|
|
26
30
|
}
|
|
27
31
|
const response = await domEval(script, options.frame);
|
|
28
32
|
if (response.status === 'error' || !response.data) {
|
|
33
|
+
const suggestion = await frameErrorSuggestion(response, options.frame);
|
|
29
34
|
return {
|
|
30
35
|
success: false,
|
|
31
36
|
error: response.error ?? 'Failed to evaluate script',
|
|
32
37
|
exitCode: response.exitCode ?? EXIT_CODES.CDP_CONNECTION_FAILURE,
|
|
33
|
-
...(
|
|
38
|
+
...(suggestion && { errorContext: { suggestion } }),
|
|
34
39
|
};
|
|
35
40
|
}
|
|
36
41
|
const { value, type, subtype, frame } = response.data;
|
|
37
42
|
return {
|
|
38
43
|
success: true,
|
|
39
|
-
data: {
|
|
44
|
+
data: {
|
|
45
|
+
result: value,
|
|
46
|
+
type,
|
|
47
|
+
...(subtype && { subtype }),
|
|
48
|
+
...(frame !== undefined && { frame }),
|
|
49
|
+
},
|
|
50
|
+
...(frame !== undefined && !options.json && { hint: evalFrameLine(frame) }),
|
|
40
51
|
};
|
|
41
52
|
}, options, formatDomEval);
|
|
42
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Suggestion of a failed eval; a frame not found (83) while the page is
|
|
56
|
+
* still loading says so (its iframes may not exist yet).
|
|
57
|
+
*
|
|
58
|
+
* @param response - Error response
|
|
59
|
+
* @param frame - The --frame given, if any
|
|
60
|
+
* @returns Suggestion, if any
|
|
61
|
+
*/
|
|
62
|
+
async function frameErrorSuggestion(response, frame) {
|
|
63
|
+
if (frame === undefined || response.exitCode !== EXIT_CODES.RESOURCE_NOT_FOUND) {
|
|
64
|
+
return response.suggestion;
|
|
65
|
+
}
|
|
66
|
+
return withLoadingHint(response.suggestion ?? '', await documentReadyState()) || undefined;
|
|
67
|
+
}
|
|
43
68
|
//# sourceMappingURL=eval.js.map
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Discovers forms on the page with semantic labels, current values,
|
|
5
5
|
* validation state, and suggested commands for agent consumption.
|
|
6
6
|
*/
|
|
7
|
+
import { calculateSummary, orderForms, primaryButtonIndex } from './formSummary.js';
|
|
7
8
|
import { resolveBackendNodeIds } from './helpers/index.js';
|
|
8
9
|
import { runCommand } from '../shared/CommandRunner.js';
|
|
9
10
|
import { jsonOption } from '../shared/commonOptions.js';
|
|
@@ -177,6 +178,7 @@ function transformField(raw) {
|
|
|
177
178
|
name: raw.name,
|
|
178
179
|
placeholder: raw.placeholder,
|
|
179
180
|
required: raw.required,
|
|
181
|
+
groupLabel: raw.groupLabel,
|
|
180
182
|
disabled: raw.disabled,
|
|
181
183
|
readOnly: raw.readOnly,
|
|
182
184
|
hidden: raw.hidden,
|
|
@@ -195,76 +197,21 @@ function transformField(raw) {
|
|
|
195
197
|
* Transform raw button to structured FormButton.
|
|
196
198
|
*
|
|
197
199
|
* @param raw - Raw button data
|
|
200
|
+
* @param primaryIndex - Index of the form's primary button, if any
|
|
198
201
|
* @returns Structured FormButton
|
|
199
202
|
*/
|
|
200
|
-
function transformButton(raw) {
|
|
203
|
+
function transformButton(raw, primaryIndex) {
|
|
201
204
|
return {
|
|
202
205
|
index: raw.index,
|
|
203
206
|
selector: raw.selector,
|
|
204
207
|
label: raw.label,
|
|
205
208
|
type: raw.type,
|
|
206
|
-
primary: raw.
|
|
209
|
+
primary: raw.index === primaryIndex,
|
|
207
210
|
enabled: !raw.disabled,
|
|
208
211
|
disabledReason: raw.disabled ? 'Button is disabled' : undefined,
|
|
209
212
|
command: `bdg dom click ${raw.index}`,
|
|
210
213
|
};
|
|
211
214
|
}
|
|
212
|
-
/**
|
|
213
|
-
* Calculate form summary statistics.
|
|
214
|
-
*
|
|
215
|
-
* @param fields - Transformed form fields
|
|
216
|
-
* @param buttons - Transformed form buttons
|
|
217
|
-
* @returns Form summary
|
|
218
|
-
*/
|
|
219
|
-
function calculateSummary(fields, buttons) {
|
|
220
|
-
const visibleFields = fields.filter((f) => !f.hidden);
|
|
221
|
-
const editableFields = visibleFields.filter((f) => !f.disabled && !f.readOnly);
|
|
222
|
-
const requiredFields = editableFields.filter((f) => f.required);
|
|
223
|
-
const filledFields = editableFields.filter((f) => f.state === 'filled' || f.state === 'checked');
|
|
224
|
-
const validFields = editableFields.filter((f) => f.validation.valid);
|
|
225
|
-
const invalidFields = editableFields.filter((f) => !f.validation.valid);
|
|
226
|
-
const emptyRequired = requiredFields.filter((f) => f.state === 'empty' || f.state === 'unchecked');
|
|
227
|
-
const blockers = [];
|
|
228
|
-
for (const field of emptyRequired) {
|
|
229
|
-
blockers.push({
|
|
230
|
-
index: field.index,
|
|
231
|
-
label: field.label,
|
|
232
|
-
reason: 'Required field is empty',
|
|
233
|
-
command: field.command,
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
for (const field of invalidFields) {
|
|
237
|
-
if (!emptyRequired.includes(field)) {
|
|
238
|
-
blockers.push({
|
|
239
|
-
index: field.index,
|
|
240
|
-
label: field.label,
|
|
241
|
-
reason: field.validation.message ?? 'Validation failed',
|
|
242
|
-
command: field.command,
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
const submitButton = buttons.find((b) => b.type === 'submit' && b.primary);
|
|
247
|
-
if (submitButton && !submitButton.enabled) {
|
|
248
|
-
blockers.push({
|
|
249
|
-
index: submitButton.index,
|
|
250
|
-
label: submitButton.label,
|
|
251
|
-
reason: submitButton.disabledReason ?? 'Submit button is disabled',
|
|
252
|
-
command: submitButton.command,
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
return {
|
|
256
|
-
totalFields: editableFields.length,
|
|
257
|
-
filledFields: filledFields.length,
|
|
258
|
-
emptyFields: editableFields.length - filledFields.length,
|
|
259
|
-
validFields: validFields.length,
|
|
260
|
-
invalidFields: invalidFields.length,
|
|
261
|
-
requiredTotal: requiredFields.length,
|
|
262
|
-
requiredFilled: requiredFields.length - emptyRequired.length,
|
|
263
|
-
requiredRemaining: emptyRequired.length,
|
|
264
|
-
readyToSubmit: blockers.length === 0,
|
|
265
|
-
blockers,
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
215
|
/**
|
|
269
216
|
* Transform raw form to structured DiscoveredForm.
|
|
270
217
|
*
|
|
@@ -273,7 +220,8 @@ function calculateSummary(fields, buttons) {
|
|
|
273
220
|
*/
|
|
274
221
|
function transformForm(raw) {
|
|
275
222
|
const fields = raw.fields.map(transformField);
|
|
276
|
-
const
|
|
223
|
+
const primaryIndex = primaryButtonIndex(raw.buttons);
|
|
224
|
+
const buttons = raw.buttons.map((button) => transformButton(button, primaryIndex));
|
|
277
225
|
return {
|
|
278
226
|
index: raw.index,
|
|
279
227
|
name: raw.name,
|
|
@@ -281,6 +229,8 @@ function transformForm(raw) {
|
|
|
281
229
|
method: raw.method,
|
|
282
230
|
step: raw.step ?? undefined,
|
|
283
231
|
relevanceScore: raw.relevanceScore,
|
|
232
|
+
hidden: raw.hidden === true,
|
|
233
|
+
inDialog: raw.inDialog === true,
|
|
284
234
|
fields,
|
|
285
235
|
buttons,
|
|
286
236
|
summary: calculateSummary(fields, buttons),
|
|
@@ -340,7 +290,7 @@ async function handleFormCommand(options) {
|
|
|
340
290
|
};
|
|
341
291
|
}
|
|
342
292
|
if (rawData.forms.length === 0) {
|
|
343
|
-
const err = noFormsFoundError();
|
|
293
|
+
const err = noFormsFoundError(rawData.readyState);
|
|
344
294
|
return {
|
|
345
295
|
success: false,
|
|
346
296
|
error: err.message,
|
|
@@ -358,7 +308,7 @@ async function handleFormCommand(options) {
|
|
|
358
308
|
errorContext: { suggestion: err.suggestion },
|
|
359
309
|
};
|
|
360
310
|
}
|
|
361
|
-
const allForms = rawData.forms.map(transformForm);
|
|
311
|
+
const allForms = orderForms(rawData.forms).map(transformForm);
|
|
362
312
|
const forms = options.all ? allForms : [allForms[0]];
|
|
363
313
|
// Cache ALL forms so global indices work with bdg dom fill/click
|
|
364
314
|
await cacheFormElements(allForms);
|
|
@@ -370,7 +320,11 @@ async function handleFormCommand(options) {
|
|
|
370
320
|
otherForms: allForms.slice(1).map((form) => ({
|
|
371
321
|
index: form.index,
|
|
372
322
|
name: form.name,
|
|
373
|
-
fieldCount: form.
|
|
323
|
+
fieldCount: form.hidden
|
|
324
|
+
? form.fields.length
|
|
325
|
+
: form.fields.filter((field) => !field.hidden).length,
|
|
326
|
+
hidden: form.hidden,
|
|
327
|
+
inDialog: form.inDialog,
|
|
374
328
|
})),
|
|
375
329
|
}),
|
|
376
330
|
brief: options.brief,
|