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
package/README.md
CHANGED
|
@@ -58,12 +58,15 @@ bdg page navigate example.com/about
|
|
|
58
58
|
bdg eval "document.title" # Run JavaScript in the page (--frame for iframes)
|
|
59
59
|
bdg network list --preset errors # Network requests, console: bdg console
|
|
60
60
|
bdg dom listeners "#save" # Which event listeners run for an element
|
|
61
|
+
bdg dom layout "#save" # Where it is, whether it is visible or covered
|
|
62
|
+
bdg dom wait "#result" --visible # Wait for an element instead of sleeping
|
|
63
|
+
bdg example.com --session agent2 --viewport 1280x800 # A second, independent session
|
|
61
64
|
bdg stop # End session
|
|
62
65
|
```
|
|
63
66
|
|
|
64
67
|
## Current State
|
|
65
68
|
|
|
66
|
-
**Raw CDP access is complete.** Every protocol method works now. High-level commands cover the common work: page navigation, DOM queries and interaction (click, fill, hover, keys, forms, shadow DOM and iframes), accessibility tree, screenshots, network requests and HAR export, console messages and event listeners. See the [CLI reference](docs/CLI_REFERENCE.md) for every command, and `bdg --help --json` for the machine-readable version.
|
|
69
|
+
**Raw CDP access is complete.** Every protocol method works now. High-level commands cover the common work: page navigation, DOM queries and interaction (click, fill, hover, keys, forms, shadow DOM and iframes), accessibility tree, screenshots, network requests and HAR export, console messages and event listeners. Actions report what they changed (navigation, new messages, requests, or no visible effect), and several named sessions can run side by side. See the [CLI reference](docs/CLI_REFERENCE.md) for every command, and `bdg --help --json` for the machine-readable version.
|
|
67
70
|
|
|
68
71
|
## Agent Discovery Pattern
|
|
69
72
|
|
package/dist/cdp/schema.d.ts
CHANGED
|
@@ -154,7 +154,9 @@ export declare function getProtocolCounts(): {
|
|
|
154
154
|
/**
|
|
155
155
|
* Search methods by keyword (case-insensitive).
|
|
156
156
|
*
|
|
157
|
-
* Searches
|
|
157
|
+
* Searches method names, extra keywords ({@link SEARCH_KEYWORDS}) and
|
|
158
|
+
* descriptions. Matches by name or keyword come first, then those found only
|
|
159
|
+
* in the description, each in protocol order.
|
|
158
160
|
*
|
|
159
161
|
* @param query - Search query
|
|
160
162
|
* @returns Array of matching method schemas
|
|
@@ -163,6 +165,7 @@ export declare function getProtocolCounts(): {
|
|
|
163
165
|
* ```typescript
|
|
164
166
|
* const cookies = searchMethods('cookie');
|
|
165
167
|
* // Returns: Network.getCookies, Network.setCookie, Network.deleteCookies, etc.
|
|
168
|
+
* searchMethods('viewport')[0]?.name; // 'Emulation.setDeviceMetricsOverride'
|
|
166
169
|
* ```
|
|
167
170
|
*/
|
|
168
171
|
export declare function searchMethods(query: string): MethodSchema[];
|
package/dist/cdp/schema.js
CHANGED
|
@@ -233,10 +233,45 @@ export function getProtocolCounts() {
|
|
|
233
233
|
methodsIn: (domain) => summaries.find((d) => d.name === domain)?.commandCount ?? 0,
|
|
234
234
|
};
|
|
235
235
|
}
|
|
236
|
+
/**
|
|
237
|
+
* Words agents search for that a method's name and description lack, e.g.
|
|
238
|
+
* "viewport" for `Emulation.setDeviceMetricsOverride`.
|
|
239
|
+
*/
|
|
240
|
+
const SEARCH_KEYWORDS = {
|
|
241
|
+
'Emulation.setDeviceMetricsOverride': [
|
|
242
|
+
'viewport',
|
|
243
|
+
'window size',
|
|
244
|
+
'screen size',
|
|
245
|
+
'resize',
|
|
246
|
+
'responsive',
|
|
247
|
+
'mobile',
|
|
248
|
+
],
|
|
249
|
+
'Emulation.setEmulatedMedia': [
|
|
250
|
+
'color scheme',
|
|
251
|
+
'dark mode',
|
|
252
|
+
'light mode',
|
|
253
|
+
'prefers-color-scheme',
|
|
254
|
+
'reduced motion',
|
|
255
|
+
'print',
|
|
256
|
+
],
|
|
257
|
+
'Browser.setWindowBounds': ['window size', 'resize'],
|
|
258
|
+
};
|
|
259
|
+
/**
|
|
260
|
+
* Lower-case text without spaces, hyphens and underscores, so "user agent"
|
|
261
|
+
* finds `setUserAgentOverride`.
|
|
262
|
+
*
|
|
263
|
+
* @param text - Text
|
|
264
|
+
* @returns Normalized text
|
|
265
|
+
*/
|
|
266
|
+
function searchable(text) {
|
|
267
|
+
return text.toLowerCase().replace(/[\s_-]+/g, '');
|
|
268
|
+
}
|
|
236
269
|
/**
|
|
237
270
|
* Search methods by keyword (case-insensitive).
|
|
238
271
|
*
|
|
239
|
-
* Searches
|
|
272
|
+
* Searches method names, extra keywords ({@link SEARCH_KEYWORDS}) and
|
|
273
|
+
* descriptions. Matches by name or keyword come first, then those found only
|
|
274
|
+
* in the description, each in protocol order.
|
|
240
275
|
*
|
|
241
276
|
* @param query - Search query
|
|
242
277
|
* @returns Array of matching method schemas
|
|
@@ -245,23 +280,29 @@ export function getProtocolCounts() {
|
|
|
245
280
|
* ```typescript
|
|
246
281
|
* const cookies = searchMethods('cookie');
|
|
247
282
|
* // Returns: Network.getCookies, Network.setCookie, Network.deleteCookies, etc.
|
|
283
|
+
* searchMethods('viewport')[0]?.name; // 'Emulation.setDeviceMetricsOverride'
|
|
248
284
|
* ```
|
|
249
285
|
*/
|
|
250
286
|
export function searchMethods(query) {
|
|
251
287
|
const protocol = loadProtocol();
|
|
252
|
-
const
|
|
288
|
+
const named = [];
|
|
289
|
+
const described = [];
|
|
253
290
|
const lowerQuery = query.toLowerCase();
|
|
291
|
+
const needle = searchable(query);
|
|
254
292
|
protocol.domains.forEach((domain) => {
|
|
255
293
|
if (!domain.commands)
|
|
256
294
|
return;
|
|
257
295
|
domain.commands.forEach((command) => {
|
|
258
|
-
const
|
|
296
|
+
const keywords = SEARCH_KEYWORDS[`${domain.domain}.${command.name}`] ?? [];
|
|
297
|
+
const nameMatch = searchable(command.name).includes(needle) ||
|
|
298
|
+
keywords.some((keyword) => searchable(keyword).includes(needle));
|
|
259
299
|
const descMatch = command.description?.toLowerCase().includes(lowerQuery) ?? false;
|
|
260
|
-
if (nameMatch
|
|
261
|
-
|
|
262
|
-
|
|
300
|
+
if (nameMatch)
|
|
301
|
+
named.push(buildMethodSchema(domain.domain, command));
|
|
302
|
+
else if (descMatch)
|
|
303
|
+
described.push(buildMethodSchema(domain.domain, command));
|
|
263
304
|
});
|
|
264
305
|
});
|
|
265
|
-
return
|
|
306
|
+
return [...named, ...described];
|
|
266
307
|
}
|
|
267
308
|
//# sourceMappingURL=schema.js.map
|
package/dist/commands/cdp.js
CHANGED
|
@@ -6,6 +6,7 @@ import { CommandError } from '../errors/index.js';
|
|
|
6
6
|
import { callCDP } from '../ipc/client.js';
|
|
7
7
|
import { validateIPCResponse } from '../ipc/index.js';
|
|
8
8
|
import { formatHint } from '../ui/messages/hints.js';
|
|
9
|
+
import { sessionCommand } from '../ui/messages/sessionCommand.js';
|
|
9
10
|
import { getErrorMessage } from '../utils/errors.js';
|
|
10
11
|
import { EXIT_CODES } from '../utils/exitCodes.js';
|
|
11
12
|
import { findSimilar } from '../utils/suggestions.js';
|
|
@@ -166,7 +167,7 @@ function domainSuggestion(domainName) {
|
|
|
166
167
|
*/
|
|
167
168
|
function blockedAlternative(methodName) {
|
|
168
169
|
const blocked = BLOCKED_CDP_METHODS[methodName];
|
|
169
|
-
return blocked && `${blocked.alternative} (raw ${methodName} is blocked)`;
|
|
170
|
+
return blocked && `${sessionCommand(blocked.alternative)} (raw ${methodName} is blocked)`;
|
|
170
171
|
}
|
|
171
172
|
/**
|
|
172
173
|
* Handle search mode: Find methods by keyword.
|
|
@@ -403,7 +404,7 @@ async function handleExecuteMethod(methodName, paramsJson) {
|
|
|
403
404
|
success: false,
|
|
404
405
|
error: `${normalized} is blocked via raw CDP: ${blocked.reason}`,
|
|
405
406
|
exitCode: EXIT_CODES.INVALID_ARGUMENTS,
|
|
406
|
-
errorContext: { suggestion: `Use: ${blocked.alternative}` },
|
|
407
|
+
errorContext: { suggestion: `Use: ${sessionCommand(blocked.alternative)}` },
|
|
407
408
|
};
|
|
408
409
|
}
|
|
409
410
|
if (!normalized) {
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
|
+
import { type ErrorWithSuggestion } from '../errors/messages.js';
|
|
3
|
+
/**
|
|
4
|
+
* Why the session directory must not be deleted after cleanup: its daemon
|
|
5
|
+
* still runs, cleanup reported problems, or its Chrome has not exited.
|
|
6
|
+
*
|
|
7
|
+
* @param chromePid - The session's Chrome as found before cleanup, or null
|
|
8
|
+
* @param warnings - Warnings from cleanup
|
|
9
|
+
* @param exitWaitMs - How long to wait for that Chrome to exit
|
|
10
|
+
* @returns Error and suggestion, or null when the directory may be deleted
|
|
11
|
+
*/
|
|
12
|
+
export declare function purgeBlocker(chromePid: number | null, warnings: string[], exitWaitMs?: number): Promise<ErrorWithSuggestion | null>;
|
|
2
13
|
/**
|
|
3
14
|
* Register cleanup command
|
|
4
15
|
*
|
package/dist/commands/cleanup.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import { runCommand } from './shared/CommandRunner.js';
|
|
3
3
|
import { jsonOption } from './shared/commonOptions.js';
|
|
4
|
-
import { sessionDirIsFileError } from '../errors/messages.js';
|
|
4
|
+
import { purgeNeedsNamedSessionError, purgeRefusedError, sessionDirIsFileError, } from '../errors/messages.js';
|
|
5
|
+
import { isSessionChrome } from '../session/cleanup/staleSession.js';
|
|
5
6
|
import { performSessionCleanup } from '../session/cleanup/userCommands.js';
|
|
6
7
|
import { isDaemonAlive } from '../session/daemonSocket.js';
|
|
7
|
-
import { getSessionDir } from '../session/paths.js';
|
|
8
|
-
import { readDaemonPid } from '../session/pid.js';
|
|
8
|
+
import { getSessionDir, getSessionFilePath, getSessionName } from '../session/paths.js';
|
|
9
|
+
import { readDaemonPid, readPidFromFile } from '../session/pid.js';
|
|
9
10
|
import { joinLines } from '../ui/formatting.js';
|
|
10
|
-
import { sessionFilesCleanedMessage, sessionOutputRemovedMessage, sessionDirectoryCleanMessage, noSessionFilesMessage, sessionStillActiveError, warningMessage, } from '../ui/messages/commands.js';
|
|
11
|
+
import { sessionFilesCleanedMessage, sessionOutputRemovedMessage, sessionDirectoryCleanMessage, sessionDirectoryPurgedMessage, noSessionFilesMessage, sessionStillActiveError, sessionStillActiveSuggestion, warningMessage, } from '../ui/messages/commands.js';
|
|
12
|
+
import { delay } from '../utils/async.js';
|
|
11
13
|
import { EXIT_CODES } from '../utils/exitCodes.js';
|
|
14
|
+
import { isProcessAlive } from '../utils/process.js';
|
|
12
15
|
/**
|
|
13
16
|
* Format cleanup result for human-readable output.
|
|
14
17
|
*
|
|
@@ -18,6 +21,158 @@ function formatCleanup(data) {
|
|
|
18
21
|
const { cleaned } = data;
|
|
19
22
|
return joinLines(cleaned.session && sessionFilesCleanedMessage(), cleaned.output && sessionOutputRemovedMessage(), ...(data.warnings ?? []).map((warning) => warningMessage(warning)), '', data.message);
|
|
20
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Delete the selected named session's directory (Chrome profile, logs, port).
|
|
26
|
+
*
|
|
27
|
+
* @returns The deleted directory, or undefined if there was none
|
|
28
|
+
*/
|
|
29
|
+
function purgeSessionDir() {
|
|
30
|
+
const dir = getSessionDir();
|
|
31
|
+
if (!fs.existsSync(dir))
|
|
32
|
+
return undefined;
|
|
33
|
+
fs.rmSync(dir, { recursive: true, force: true, maxRetries: 3 });
|
|
34
|
+
return dir;
|
|
35
|
+
}
|
|
36
|
+
/** How long `--purge` waits for a killed Chrome to exit */
|
|
37
|
+
const PURGE_CHROME_EXIT_WAIT_MS = 5000;
|
|
38
|
+
/**
|
|
39
|
+
* The running Chrome bdg launched for the selected session (from chrome.pid,
|
|
40
|
+
* verified by its marker flag).
|
|
41
|
+
*
|
|
42
|
+
* @returns Chrome PID, or null
|
|
43
|
+
*/
|
|
44
|
+
function liveSessionChromePid() {
|
|
45
|
+
const pid = readPidFromFile(getSessionFilePath('CHROME_PID'));
|
|
46
|
+
if (pid === null || !isProcessAlive(pid))
|
|
47
|
+
return null;
|
|
48
|
+
return isSessionChrome(pid, getSessionDir()) ? pid : null;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Wait until a process has exited.
|
|
52
|
+
*
|
|
53
|
+
* @param pid - Process ID
|
|
54
|
+
* @param timeoutMs - Longest wait
|
|
55
|
+
* @returns True if it exited
|
|
56
|
+
*/
|
|
57
|
+
async function waitForExit(pid, timeoutMs) {
|
|
58
|
+
const deadline = Date.now() + timeoutMs;
|
|
59
|
+
while (isProcessAlive(pid) && Date.now() < deadline)
|
|
60
|
+
await delay(50);
|
|
61
|
+
return !isProcessAlive(pid);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Why the session directory must not be deleted after cleanup: its daemon
|
|
65
|
+
* still runs, cleanup reported problems, or its Chrome has not exited.
|
|
66
|
+
*
|
|
67
|
+
* @param chromePid - The session's Chrome as found before cleanup, or null
|
|
68
|
+
* @param warnings - Warnings from cleanup
|
|
69
|
+
* @param exitWaitMs - How long to wait for that Chrome to exit
|
|
70
|
+
* @returns Error and suggestion, or null when the directory may be deleted
|
|
71
|
+
*/
|
|
72
|
+
export async function purgeBlocker(chromePid, warnings, exitWaitMs = PURGE_CHROME_EXIT_WAIT_MS) {
|
|
73
|
+
const dir = getSessionDir();
|
|
74
|
+
if (await isDaemonAlive())
|
|
75
|
+
return purgeRefusedError(dir, 'its daemon is still running');
|
|
76
|
+
if (warnings.length > 0)
|
|
77
|
+
return purgeRefusedError(dir, warnings.join('; '));
|
|
78
|
+
if (chromePid !== null && !(await waitForExit(chromePid, exitWaitMs))) {
|
|
79
|
+
return purgeRefusedError(dir, `its Chrome (PID ${chromePid}) is still running`);
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Delete the session directory unless {@link purgeBlocker} objects.
|
|
85
|
+
*
|
|
86
|
+
* @param chromePid - The session's Chrome as found before cleanup, or null
|
|
87
|
+
* @param warnings - Warnings from cleanup
|
|
88
|
+
* @returns The deleted directory (undefined if there was none), or the refusal
|
|
89
|
+
*/
|
|
90
|
+
async function purge(chromePid, warnings) {
|
|
91
|
+
const refusal = await purgeBlocker(chromePid, warnings);
|
|
92
|
+
if (refusal)
|
|
93
|
+
return { refusal };
|
|
94
|
+
const purged = purgeSessionDir();
|
|
95
|
+
return purged === undefined ? {} : { purged };
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Why cleanup cannot run: the session directory is a file, `--purge` lacks a
|
|
99
|
+
* named session, or the session is still running (without `--force`).
|
|
100
|
+
*
|
|
101
|
+
* @param opts - Cleanup options
|
|
102
|
+
* @returns Error result, or null when cleanup may run
|
|
103
|
+
*/
|
|
104
|
+
async function cleanupBlocker(opts) {
|
|
105
|
+
const dir = getSessionDir();
|
|
106
|
+
if (fs.existsSync(dir) && !fs.statSync(dir).isDirectory()) {
|
|
107
|
+
const err = sessionDirIsFileError(dir);
|
|
108
|
+
return {
|
|
109
|
+
success: false,
|
|
110
|
+
error: err.message,
|
|
111
|
+
exitCode: EXIT_CODES.SESSION_FILE_ERROR,
|
|
112
|
+
errorContext: { suggestion: err.suggestion },
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
if (opts.purge && getSessionName() === null) {
|
|
116
|
+
const err = purgeNeedsNamedSessionError();
|
|
117
|
+
return {
|
|
118
|
+
success: false,
|
|
119
|
+
error: err.message,
|
|
120
|
+
exitCode: EXIT_CODES.INVALID_ARGUMENTS,
|
|
121
|
+
errorContext: { suggestion: err.suggestion },
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
if (!opts.force && !opts.aggressive && (await isDaemonAlive())) {
|
|
125
|
+
return {
|
|
126
|
+
success: false,
|
|
127
|
+
error: sessionStillActiveError(readDaemonPid() ?? 0),
|
|
128
|
+
exitCode: EXIT_CODES.RESOURCE_BUSY,
|
|
129
|
+
errorContext: {
|
|
130
|
+
suggestion: sessionStillActiveSuggestion(getSessionName()),
|
|
131
|
+
warning: 'Force cleanup kills the running daemon and its Chrome',
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Clean up the selected session (and delete its directory with `--purge`).
|
|
139
|
+
*
|
|
140
|
+
* @param opts - Cleanup options
|
|
141
|
+
* @returns Command result
|
|
142
|
+
*/
|
|
143
|
+
async function cleanupSession(opts) {
|
|
144
|
+
const blocker = await cleanupBlocker(opts);
|
|
145
|
+
if (blocker)
|
|
146
|
+
return blocker;
|
|
147
|
+
const chromePid = opts.purge ? liveSessionChromePid() : null;
|
|
148
|
+
const { cleaned, warnings } = await performSessionCleanup({
|
|
149
|
+
force: Boolean(opts.force) || Boolean(opts.aggressive),
|
|
150
|
+
removeOutput: opts.removeOutput,
|
|
151
|
+
});
|
|
152
|
+
const { purged, refusal } = opts.purge ? await purge(chromePid, warnings) : {};
|
|
153
|
+
if (refusal) {
|
|
154
|
+
return {
|
|
155
|
+
success: false,
|
|
156
|
+
error: refusal.message,
|
|
157
|
+
exitCode: EXIT_CODES.RESOURCE_CONFLICT,
|
|
158
|
+
errorContext: { suggestion: refusal.suggestion },
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
const didCleanup = Object.values(cleaned).some(Boolean) || purged !== undefined;
|
|
162
|
+
return {
|
|
163
|
+
success: true,
|
|
164
|
+
data: {
|
|
165
|
+
cleaned,
|
|
166
|
+
...(purged !== undefined && { purged }),
|
|
167
|
+
message: !didCleanup
|
|
168
|
+
? noSessionFilesMessage()
|
|
169
|
+
: purged !== undefined
|
|
170
|
+
? sessionDirectoryPurgedMessage(purged)
|
|
171
|
+
: sessionDirectoryCleanMessage(),
|
|
172
|
+
...(warnings.length > 0 && { warnings }),
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
21
176
|
/**
|
|
22
177
|
* Register cleanup command
|
|
23
178
|
*
|
|
@@ -30,61 +185,10 @@ export function registerCleanupCommand(program) {
|
|
|
30
185
|
.option('-f, --force', 'Kill a running (possibly hung) session, then clean up', false)
|
|
31
186
|
.option('--remove-output', 'Also remove session.json output file', false)
|
|
32
187
|
.option('--aggressive', 'Alias for --force (kept for compatibility)', false)
|
|
188
|
+
.option('--purge', "Also delete a named session's directory (Chrome profile, logs, port); needs --session", false)
|
|
33
189
|
.addOption(jsonOption())
|
|
34
190
|
.action(async (options) => {
|
|
35
|
-
await runCommand(
|
|
36
|
-
const dir = getSessionDir();
|
|
37
|
-
if (fs.existsSync(dir) && !fs.statSync(dir).isDirectory()) {
|
|
38
|
-
const err = sessionDirIsFileError(dir);
|
|
39
|
-
return {
|
|
40
|
-
success: false,
|
|
41
|
-
error: err.message,
|
|
42
|
-
exitCode: EXIT_CODES.SESSION_FILE_ERROR,
|
|
43
|
-
errorContext: { suggestion: err.suggestion },
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
if (!opts.force && !opts.aggressive && (await isDaemonAlive())) {
|
|
47
|
-
return {
|
|
48
|
-
success: false,
|
|
49
|
-
error: sessionStillActiveError(readDaemonPid() ?? 0),
|
|
50
|
-
exitCode: EXIT_CODES.RESOURCE_BUSY,
|
|
51
|
-
errorContext: {
|
|
52
|
-
suggestion: 'Stop gracefully: bdg stop\nForce cleanup: bdg cleanup --force',
|
|
53
|
-
warning: 'Force cleanup kills the running daemon and its Chrome',
|
|
54
|
-
},
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
const cleanupResult = await performSessionCleanup({
|
|
58
|
-
force: Boolean(opts.force) || Boolean(opts.aggressive),
|
|
59
|
-
removeOutput: opts.removeOutput,
|
|
60
|
-
});
|
|
61
|
-
const didCleanup = cleanupResult.cleaned.session ||
|
|
62
|
-
cleanupResult.cleaned.chrome ||
|
|
63
|
-
cleanupResult.cleaned.daemons ||
|
|
64
|
-
cleanupResult.cleaned.output;
|
|
65
|
-
if (!didCleanup) {
|
|
66
|
-
return {
|
|
67
|
-
success: true,
|
|
68
|
-
data: {
|
|
69
|
-
cleaned: { session: false, output: false, chrome: false, daemons: false },
|
|
70
|
-
message: noSessionFilesMessage(),
|
|
71
|
-
},
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
return {
|
|
75
|
-
success: true,
|
|
76
|
-
data: {
|
|
77
|
-
cleaned: {
|
|
78
|
-
session: cleanupResult.cleaned.session,
|
|
79
|
-
output: cleanupResult.cleaned.output,
|
|
80
|
-
chrome: cleanupResult.cleaned.chrome,
|
|
81
|
-
daemons: cleanupResult.cleaned.daemons,
|
|
82
|
-
},
|
|
83
|
-
message: sessionDirectoryCleanMessage(),
|
|
84
|
-
...(cleanupResult.warnings.length > 0 && { warnings: cleanupResult.warnings }),
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
|
-
}, options, formatCleanup);
|
|
191
|
+
await runCommand(cleanupSession, options, formatCleanup);
|
|
88
192
|
});
|
|
89
193
|
}
|
|
90
194
|
//# sourceMappingURL=cleanup.js.map
|
|
@@ -2,8 +2,17 @@
|
|
|
2
2
|
* Console command for inspecting and filtering console messages.
|
|
3
3
|
*/
|
|
4
4
|
import { type Command } from 'commander';
|
|
5
|
+
import type { ConsoleCommandOptions } from './shared/optionTypes.js';
|
|
5
6
|
import type { ConsoleMessage } from '../types.js';
|
|
6
|
-
import { type ConsoleLevel } from '../ui/formatters/console.js';
|
|
7
|
+
import { type ConsoleLevel, type ConsoleSkipped } from '../ui/formatters/console.js';
|
|
8
|
+
/**
|
|
9
|
+
* Whether to list the messages instead of summarising them: with `--list`,
|
|
10
|
+
* and when `--last` asks for a number of them.
|
|
11
|
+
*
|
|
12
|
+
* @param options - Command options
|
|
13
|
+
* @returns True to list
|
|
14
|
+
*/
|
|
15
|
+
export declare function listsMessages(options: Pick<ConsoleCommandOptions, 'list' | 'last'>): boolean;
|
|
7
16
|
/**
|
|
8
17
|
* Keep the messages of the page currently loaded.
|
|
9
18
|
*
|
|
@@ -14,6 +23,16 @@ import { type ConsoleLevel } from '../ui/formatters/console.js';
|
|
|
14
23
|
*/
|
|
15
24
|
export declare function filterByCurrentNavigation(messages: ConsoleMessage[], currentNavigationId?: number): ConsoleMessage[];
|
|
16
25
|
export declare function filterByLevel(messages: ConsoleMessage[], level: ConsoleLevel): ConsoleMessage[];
|
|
26
|
+
/**
|
|
27
|
+
* Messages the filters left out between the first and the last listed
|
|
28
|
+
* message (their session indices skip them), by why: logged by another page
|
|
29
|
+
* load, or of another level.
|
|
30
|
+
*
|
|
31
|
+
* @param all - All messages of the session
|
|
32
|
+
* @param listed - Messages listed
|
|
33
|
+
* @returns Counts per reason
|
|
34
|
+
*/
|
|
35
|
+
export declare function skippedMessages(all: ConsoleMessage[], listed: ConsoleMessage[]): ConsoleSkipped;
|
|
17
36
|
/**
|
|
18
37
|
* Identity of each message across polls (its index can shift when an earlier
|
|
19
38
|
* message is inserted late). Identical messages logged in the same
|
package/dist/commands/console.js
CHANGED
|
@@ -4,18 +4,28 @@
|
|
|
4
4
|
import { Option } from 'commander';
|
|
5
5
|
import { runCommand } from './shared/CommandRunner.js';
|
|
6
6
|
import { jsonOption } from './shared/commonOptions.js';
|
|
7
|
-
import {
|
|
7
|
+
import { noteFollowConnected } from './shared/daemonErrorHandler.js';
|
|
8
8
|
import { fetchConsoleMessages, createErrorResult } from './shared/dataFetcher.js';
|
|
9
|
-
import { setupFollowMode } from './shared/followMode.js';
|
|
9
|
+
import { followFetchFailure, setupFollowMode, } from './shared/followMode.js';
|
|
10
10
|
import { handleValidationError } from './shared/handleValidationError.js';
|
|
11
11
|
import { consoleLevelOption, positiveIntRule } from './shared/validation.js';
|
|
12
12
|
import { buildSuccessResponse } from '../ui/OutputBuilder.js';
|
|
13
|
-
import { buildConsoleJsonOutput, formatConsole, formatConsoleFollowLines, LEVEL_MAP, } from '../ui/formatters/console.js';
|
|
13
|
+
import { buildConsoleJsonOutput, formatConsole, formatConsoleFollowLines, LEVEL_MAP, lastMessages, } from '../ui/formatters/console.js';
|
|
14
14
|
import { followingConsoleMessage, stoppedFollowingConsoleMessage, } from '../ui/messages/consoleMessages.js';
|
|
15
15
|
const MIN_LAST = 0;
|
|
16
16
|
const MAX_LAST = 10000;
|
|
17
17
|
const DEFAULT_LAST = 100;
|
|
18
|
-
const consoleLastOption = new Option('--last <n>',
|
|
18
|
+
const consoleLastOption = new Option('--last <n>', `List the last N console messages (0 = all; default: ${DEFAULT_LAST} with --list or --follow)`);
|
|
19
|
+
/**
|
|
20
|
+
* Whether to list the messages instead of summarising them: with `--list`,
|
|
21
|
+
* and when `--last` asks for a number of them.
|
|
22
|
+
*
|
|
23
|
+
* @param options - Command options
|
|
24
|
+
* @returns True to list
|
|
25
|
+
*/
|
|
26
|
+
export function listsMessages(options) {
|
|
27
|
+
return options.list === true || options.last !== undefined;
|
|
28
|
+
}
|
|
19
29
|
/**
|
|
20
30
|
* Keep the messages of the page currently loaded.
|
|
21
31
|
*
|
|
@@ -41,14 +51,50 @@ function applyFilters(messages, options, currentNavigationId) {
|
|
|
41
51
|
filtered = filterByLevel(filtered, options.level);
|
|
42
52
|
return filtered;
|
|
43
53
|
}
|
|
44
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Messages the filters left out between the first and the last listed
|
|
56
|
+
* message (their session indices skip them), by why: logged by another page
|
|
57
|
+
* load, or of another level.
|
|
58
|
+
*
|
|
59
|
+
* @param all - All messages of the session
|
|
60
|
+
* @param listed - Messages listed
|
|
61
|
+
* @returns Counts per reason
|
|
62
|
+
*/
|
|
63
|
+
export function skippedMessages(all, listed) {
|
|
64
|
+
const shown = new Set(listed.map((message) => message.index));
|
|
65
|
+
const indices = listed.map((message) => message.index).filter((index) => index !== undefined);
|
|
66
|
+
const skipped = { otherPages: 0, otherLevels: 0 };
|
|
67
|
+
if (indices.length < 2)
|
|
68
|
+
return skipped;
|
|
69
|
+
const [first, last] = [Math.min(...indices), Math.max(...indices)];
|
|
70
|
+
const pages = new Set(listed.map((message) => message.navigationId));
|
|
71
|
+
for (const { index, navigationId } of all) {
|
|
72
|
+
if (index === undefined || index < first || index > last || shown.has(index))
|
|
73
|
+
continue;
|
|
74
|
+
if (pages.has(navigationId))
|
|
75
|
+
skipped.otherLevels++;
|
|
76
|
+
else
|
|
77
|
+
skipped.otherPages++;
|
|
78
|
+
}
|
|
79
|
+
return skipped;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Formatting options from the command options.
|
|
83
|
+
*
|
|
84
|
+
* @param options - Command options
|
|
85
|
+
* @param lastN - `--last` value
|
|
86
|
+
* @param skipped - Messages the filters left out between the listed ones
|
|
87
|
+
* @returns Formatting options
|
|
88
|
+
*/
|
|
89
|
+
function buildFormatOptions(options, lastN, skipped) {
|
|
45
90
|
return {
|
|
46
91
|
json: options.json,
|
|
47
|
-
list: options
|
|
92
|
+
list: listsMessages(options),
|
|
48
93
|
follow: options.follow,
|
|
49
94
|
last: lastN,
|
|
50
95
|
history: options.history,
|
|
51
96
|
level: options.level,
|
|
97
|
+
skipped,
|
|
52
98
|
};
|
|
53
99
|
}
|
|
54
100
|
/**
|
|
@@ -65,15 +111,7 @@ async function runFollowMode(options, lastN) {
|
|
|
65
111
|
const showConsole = async () => {
|
|
66
112
|
const result = await fetchConsoleMessages();
|
|
67
113
|
if (!result.success) {
|
|
68
|
-
|
|
69
|
-
json: options.json,
|
|
70
|
-
follow: true,
|
|
71
|
-
retryIntervalMs: 1000,
|
|
72
|
-
exitCode: result.exitCode,
|
|
73
|
-
});
|
|
74
|
-
if (errorResult.shouldExit)
|
|
75
|
-
process.exit(errorResult.exitCode);
|
|
76
|
-
return;
|
|
114
|
+
return followFetchFailure(result, { json: options.json, retryIntervalMs: 1000 });
|
|
77
115
|
}
|
|
78
116
|
noteFollowConnected();
|
|
79
117
|
const { messages, currentNavigationId } = result.data;
|
|
@@ -101,6 +139,7 @@ async function runFollowMode(options, lastN) {
|
|
|
101
139
|
console.log(text);
|
|
102
140
|
}
|
|
103
141
|
started = true;
|
|
142
|
+
return undefined;
|
|
104
143
|
};
|
|
105
144
|
await setupFollowMode(showConsole, {
|
|
106
145
|
startMessage: followingConsoleMessage,
|
|
@@ -167,8 +206,9 @@ export function registerConsoleCommand(program) {
|
|
|
167
206
|
}
|
|
168
207
|
return { success: true, data: { messages, filtered } };
|
|
169
208
|
}, options, (data) => {
|
|
170
|
-
const { filtered } = data;
|
|
171
|
-
|
|
209
|
+
const { messages, filtered } = data;
|
|
210
|
+
const skipped = skippedMessages(messages, lastMessages(filtered, lastN));
|
|
211
|
+
return formatConsole(filtered, buildFormatOptions(options, lastN, skipped));
|
|
172
212
|
});
|
|
173
213
|
});
|
|
174
214
|
}
|
package/dist/commands/details.js
CHANGED
|
@@ -3,6 +3,7 @@ import { jsonOption } from './shared/commonOptions.js';
|
|
|
3
3
|
import { getDetails } from '../ipc/client.js';
|
|
4
4
|
import { validateIPCResponse } from '../ipc/index.js';
|
|
5
5
|
import { formatNetworkDetails, formatConsoleDetails } from '../ui/formatters/details.js';
|
|
6
|
+
import { sessionCommand } from '../ui/messages/sessionCommand.js';
|
|
6
7
|
import { EXIT_CODES } from '../utils/exitCodes.js';
|
|
7
8
|
import { validateDetailsItem } from '../utils/typeGuards.js';
|
|
8
9
|
/**
|
|
@@ -65,8 +66,8 @@ export function registerDetailsCommand(program) {
|
|
|
65
66
|
exitCode: EXIT_CODES.RESOURCE_NOT_FOUND,
|
|
66
67
|
errorContext: {
|
|
67
68
|
suggestion: opts.type === 'network'
|
|
68
|
-
?
|
|
69
|
-
:
|
|
69
|
+
? `Use ${sessionCommand('bdg network list')} to see available request IDs`
|
|
70
|
+
: `Use ${sessionCommand('bdg peek --console')} to see available console message indices`,
|
|
70
71
|
},
|
|
71
72
|
};
|
|
72
73
|
}
|
|
@@ -11,14 +11,15 @@
|
|
|
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 { QueryCacheManager } from '../../session/QueryCacheManager.js';
|
|
22
|
+
import type { IndexSource } from '../../types.js';
|
|
22
23
|
/**
|
|
23
24
|
* Successful result of resolving a selector or index argument.
|
|
24
25
|
*/
|
|
@@ -31,6 +32,10 @@ export interface ElementTargetSuccess {
|
|
|
31
32
|
index?: number | undefined;
|
|
32
33
|
/** Exact element from the query cache (index arguments only) */
|
|
33
34
|
backendNodeId?: number | undefined;
|
|
35
|
+
/** The list the index refers to (index arguments only) */
|
|
36
|
+
source?: IndexSource | undefined;
|
|
37
|
+
/** What the cached element was when listed, e.g. `h3 "Welcome"` (index arguments only) */
|
|
38
|
+
preview?: string | undefined;
|
|
34
39
|
}
|
|
35
40
|
/**
|
|
36
41
|
* Failed result of resolving a selector or index argument.
|
|
@@ -76,9 +81,10 @@ export declare class DomElementResolver {
|
|
|
76
81
|
*
|
|
77
82
|
* @param selectorOrIndex - CSS selector or numeric index from query results
|
|
78
83
|
* @param explicitIndex - Optional explicit --index flag value (0-based, selectors only)
|
|
84
|
+
* @param command - `bdg dom` subcommand being run, e.g. "click" (for suggestions)
|
|
79
85
|
* @returns Resolution result
|
|
80
86
|
*/
|
|
81
|
-
resolve(selectorOrIndex: string, explicitIndex
|
|
87
|
+
resolve(selectorOrIndex: string, explicitIndex: number | undefined, command: string): Promise<ElementTargetResult>;
|
|
82
88
|
/**
|
|
83
89
|
* Get the backend node id for a cached index, checking the element still exists.
|
|
84
90
|
*
|
|
@@ -89,6 +95,7 @@ export declare class DomElementResolver {
|
|
|
89
95
|
*/
|
|
90
96
|
getNodeIdForIndex(index: number): Promise<{
|
|
91
97
|
nodeId: number;
|
|
98
|
+
source: IndexSource;
|
|
92
99
|
}>;
|
|
93
100
|
/**
|
|
94
101
|
* Check if the argument is a numeric index.
|