browser-debugger-cli 0.14.0 → 0.16.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/.claude/skills/bdg/SKILL.md +3 -2
- package/dist/cdp/methodTarget.d.ts +92 -0
- package/dist/cdp/methodTarget.js +159 -0
- package/dist/cdp/protocol.d.ts +16 -1
- package/dist/cdp/protocol.js +21 -0
- package/dist/cdp/schema.d.ts +55 -1
- package/dist/cdp/schema.js +134 -25
- package/dist/cdp/types.d.ts +3 -1
- package/dist/commands/cdp.d.ts +38 -1
- package/dist/commands/cdp.js +201 -133
- package/dist/commands/cleanup.js +21 -4
- package/dist/commands/dom/eval.d.ts +2 -1
- package/dist/commands/dom/eval.js +6 -21
- package/dist/commands/dom/formInteraction.js +8 -4
- package/dist/commands/dom/helpers/evalResult.d.ts +36 -0
- package/dist/commands/dom/helpers/evalResult.js +59 -0
- package/dist/commands/dom/helpers/index.d.ts +4 -4
- package/dist/commands/dom/helpers/index.js +3 -3
- package/dist/commands/dom/helpers/query.d.ts +2 -2
- package/dist/commands/dom/helpers/query.js +2 -2
- package/dist/commands/dom/helpers/screenshot.d.ts +21 -26
- package/dist/commands/dom/helpers/screenshot.js +50 -668
- package/dist/commands/dom/screenshot.js +56 -36
- package/dist/commands/helpJson.d.ts +1 -1
- package/dist/commands/helpJson.js +3 -3
- package/dist/commands/helpTopic.js +10 -4
- package/dist/commands/network/har.js +18 -14
- package/dist/commands/optionBehaviors.js +24 -9
- package/dist/commands/shared/CommandRunner.d.ts +5 -0
- package/dist/commands/shared/CommandRunner.js +18 -3
- package/dist/commands/shared/interrupt.d.ts +40 -0
- package/dist/commands/shared/interrupt.js +73 -0
- package/dist/commands/shared/optionTypes.d.ts +3 -0
- package/dist/commands/shared/outputFile.d.ts +2 -1
- package/dist/commands/shared/outputFile.js +7 -4
- package/dist/commands/shared/startHelpers.d.ts +26 -3
- package/dist/commands/shared/startHelpers.js +145 -23
- package/dist/commands/status.js +3 -1
- package/dist/commands/stop.js +2 -1
- package/dist/commands/types.d.ts +5 -0
- package/dist/connection/cdp.js +1 -16
- package/dist/connection/chromeIdentity.d.ts +24 -5
- package/dist/connection/chromeIdentity.js +53 -22
- package/dist/connection/launcher/flagsBuilder.d.ts +46 -0
- package/dist/connection/launcher/flagsBuilder.js +107 -23
- package/dist/connection/launcher.d.ts +35 -2
- package/dist/connection/launcher.js +99 -12
- package/dist/connection/typed-cdp.d.ts +3 -2
- package/dist/constants.d.ts +3 -5
- package/dist/constants.js +3 -5
- package/dist/daemon/SessionController.d.ts +10 -5
- package/dist/daemon/SessionController.js +15 -8
- package/dist/daemon/ipcServer.js +1 -1
- package/dist/daemon/launcher.d.ts +22 -3
- package/dist/daemon/launcher.js +45 -8
- package/dist/daemon/session/Session.d.ts +5 -1
- package/dist/daemon/session/Session.js +9 -8
- package/dist/daemon/session/TelemetryStore.d.ts +5 -0
- package/dist/daemon/session/TelemetryStore.js +4 -0
- package/dist/daemon/session/captureGate.d.ts +59 -0
- package/dist/daemon/session/captureGate.js +96 -0
- package/dist/daemon/session/chromeConnection.d.ts +16 -1
- package/dist/daemon/session/chromeConnection.js +34 -4
- package/dist/daemon/session/collectors.d.ts +15 -0
- package/dist/daemon/session/collectors.js +39 -2
- package/dist/daemon/session/commandRegistry.d.ts +14 -1
- package/dist/daemon/session/commandRegistry.js +48 -13
- package/dist/daemon/session/downloads.d.ts +32 -0
- package/dist/daemon/session/downloads.js +96 -0
- package/dist/daemon/session/interactions.d.ts +3 -2
- package/dist/daemon/session/interactions.js +7 -2
- package/dist/daemon/session/plugins.js +6 -0
- package/dist/daemon.js +18520 -17014
- package/dist/errors/CommandError.d.ts +2 -0
- package/dist/errors/issues.d.ts +1 -1
- package/dist/errors/messages.d.ts +81 -0
- package/dist/errors/messages.js +198 -6
- package/dist/index.js +1446 -1078
- package/dist/ipc/client.d.ts +20 -2
- package/dist/ipc/client.js +32 -6
- package/dist/ipc/protocol/commands.d.ts +36 -2
- package/dist/ipc/protocol/commands.js +1 -0
- package/dist/ipc/protocol/domTypes.d.ts +24 -1
- package/dist/ipc/session/queries.d.ts +3 -0
- package/dist/ipc/session/types.d.ts +5 -0
- package/dist/ipc/transport/IPCError.d.ts +9 -0
- package/dist/ipc/transport/IPCError.js +12 -0
- package/dist/ipc/transport/errors.d.ts +2 -1
- package/dist/ipc/transport/errors.js +4 -1
- package/dist/ipc/transport/index.d.ts +10 -2
- package/dist/ipc/transport/index.js +29 -4
- package/dist/runtime/dom/actionEffects.d.ts +48 -9
- package/dist/runtime/dom/actionEffects.js +269 -34
- package/dist/runtime/dom/actionEffectsScripts.d.ts +45 -0
- package/dist/runtime/dom/actionEffectsScripts.js +101 -2
- package/dist/runtime/dom/captureArea.d.ts +35 -0
- package/dist/runtime/dom/captureArea.js +203 -0
- package/dist/runtime/dom/elementInfo.d.ts +13 -4
- package/dist/runtime/dom/elementInfo.js +12 -3
- package/dist/runtime/dom/evalHelpers.d.ts +24 -4
- package/dist/runtime/dom/evalHelpers.js +40 -12
- package/dist/runtime/dom/formDiscovery.d.ts +1 -1
- package/dist/runtime/dom/frames.d.ts +2 -1
- package/dist/runtime/dom/frames.js +3 -1
- package/dist/runtime/page/bdgWorld.d.ts +9 -0
- package/dist/runtime/page/bdgWorld.js +11 -0
- package/dist/runtime/page/captureEmulation.d.ts +119 -0
- package/dist/runtime/page/captureEmulation.js +189 -0
- package/dist/runtime/page/captureScroll.d.ts +24 -0
- package/dist/runtime/page/captureScroll.js +124 -0
- package/dist/runtime/page/emulation.js +6 -5
- package/dist/runtime/page/screenshot.d.ts +41 -0
- package/dist/runtime/page/screenshot.js +394 -0
- package/dist/runtime/page/userAgent.d.ts +86 -2
- package/dist/runtime/page/userAgent.js +154 -33
- package/dist/session/paths.d.ts +52 -3
- package/dist/session/paths.js +179 -7
- package/dist/session/portClaims.d.ts +0 -8
- package/dist/session/portClaims.js +1 -22
- package/dist/session/sessionList.d.ts +5 -1
- package/dist/session/sessionList.js +5 -1
- package/dist/telemetry/downloads.d.ts +127 -0
- package/dist/telemetry/downloads.js +265 -0
- package/dist/telemetry/har/builder.d.ts +12 -1
- package/dist/telemetry/har/builder.js +32 -9
- package/dist/telemetry/har/sanitize.d.ts +28 -0
- package/dist/telemetry/har/sanitize.js +184 -0
- package/dist/telemetry/har/sanitizeBody.d.ts +78 -0
- package/dist/telemetry/har/sanitizeBody.js +541 -0
- package/dist/telemetry/har/types.d.ts +2 -0
- package/dist/telemetry/network.d.ts +4 -4
- package/dist/telemetry/network.js +38 -4
- package/dist/telemetry/networkRetention.d.ts +35 -14
- package/dist/telemetry/networkRetention.js +62 -26
- package/dist/types.d.ts +9 -14
- package/dist/ui/OutputBuilder.d.ts +3 -2
- package/dist/ui/OutputBuilder.js +4 -3
- package/dist/ui/formatters/cdp.d.ts +32 -9
- package/dist/ui/formatters/cdp.js +77 -6
- package/dist/ui/formatters/details.js +7 -15
- package/dist/ui/formatters/preview.d.ts +2 -0
- package/dist/ui/formatters/preview.js +7 -1
- package/dist/ui/formatters/sessions.d.ts +3 -2
- package/dist/ui/formatters/sessions.js +10 -3
- package/dist/ui/formatters/status.js +6 -1
- package/dist/ui/formatting.d.ts +7 -0
- package/dist/ui/formatting.js +13 -0
- package/dist/ui/logging/logger.d.ts +1 -1
- package/dist/ui/messages/chrome.d.ts +27 -6
- package/dist/ui/messages/chrome.js +78 -12
- package/dist/ui/messages/commands.d.ts +71 -3
- package/dist/ui/messages/commands.js +98 -3
- package/dist/ui/messages/networkMessages.d.ts +50 -5
- package/dist/ui/messages/networkMessages.js +50 -6
- package/dist/ui/messages/session.d.ts +8 -0
- package/dist/ui/messages/session.js +10 -0
- package/dist/utils/async.d.ts +3 -2
- package/dist/utils/async.js +16 -3
- package/dist/utils/atomicFile.d.ts +2 -1
- package/dist/utils/atomicFile.js +5 -2
- package/dist/utils/directories.d.ts +41 -0
- package/dist/utils/directories.js +48 -0
- package/dist/utils/http.d.ts +11 -4
- package/dist/utils/http.js +5 -3
- package/package.json +18 -4
- /package/dist/{commands/dom → runtime/page}/screenshotResize.d.ts +0 -0
- /package/dist/{commands/dom → runtime/page}/screenshotResize.js +0 -0
package/dist/commands/cdp.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type Command } from 'commander';
|
|
2
2
|
import { type CommandResult } from './shared/CommandRunner.js';
|
|
3
3
|
import type { CdpCommandOptions } from './shared/optionTypes.js';
|
|
4
|
-
import { type CdpExecuteData } from '../ui/formatters/cdp.js';
|
|
4
|
+
import { type CdpDomainDescription, type CdpExecuteData, type CdpMethodDescription, type CdpTypeDescription } from '../ui/formatters/cdp.js';
|
|
5
5
|
/**
|
|
6
6
|
* Register CDP command with full introspection support.
|
|
7
7
|
*
|
|
@@ -35,4 +35,41 @@ export declare function isBareDomain(method: string, options: CdpCommandOptions)
|
|
|
35
35
|
* @returns Error result, or undefined when the result has no exception
|
|
36
36
|
*/
|
|
37
37
|
export declare function pageExceptionResult(result: unknown): CommandResult<CdpExecuteData> | undefined;
|
|
38
|
+
/** A description `bdg cdp <name> --describe` gives */
|
|
39
|
+
type CdpDescription = CdpMethodDescription | CdpDomainDescription | CdpTypeDescription;
|
|
40
|
+
/**
|
|
41
|
+
* Handle describe mode: show a domain, a method's signature and parameters,
|
|
42
|
+
* or a protocol type's values or properties.
|
|
43
|
+
*
|
|
44
|
+
* @param name - Domain, `Domain.method` or `Domain.Type` (case-insensitive)
|
|
45
|
+
* @returns Success result with the description
|
|
46
|
+
*/
|
|
47
|
+
export declare function handleDescribeMethod(name: string): CommandResult<CdpDescription>;
|
|
48
|
+
/**
|
|
49
|
+
* The method `bdg cdp <name>` sends: a bundled method with its casing, or a
|
|
50
|
+
* well-formed method the bundled protocol lacks, as typed with a warning.
|
|
51
|
+
*
|
|
52
|
+
* @param methodName - Method name as typed
|
|
53
|
+
* @param options - `sendAnyway` sends a close typo of bundled methods as typed
|
|
54
|
+
* @returns Method to send, and the warning for one the bundled protocol lacks
|
|
55
|
+
* @throws CommandError (exit 81) for a blocked method, a type, a close typo
|
|
56
|
+
* of bundled methods (without `sendAnyway`) or a name that is not `Domain.method`
|
|
57
|
+
*/
|
|
58
|
+
export declare function methodToSend(methodName: string, options?: Pick<CdpCommandOptions, 'sendAnyway'>): {
|
|
59
|
+
method: string;
|
|
60
|
+
warning?: string;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* The result of a CDP call: the page exception it reported (exit 91), or its
|
|
64
|
+
* result with the session's and the method's hints; either way with the
|
|
65
|
+
* warning for a method the bundled protocol lacks.
|
|
66
|
+
*
|
|
67
|
+
* @param method - Method called
|
|
68
|
+
* @param cdpResult - What Chrome returned
|
|
69
|
+
* @param warning - Warning for a method the bundled protocol lacks
|
|
70
|
+
* @param ipcHint - Hint the session gave (e.g. a repeated-call pattern)
|
|
71
|
+
* @returns Command result
|
|
72
|
+
*/
|
|
73
|
+
export declare function cdpCallResult(method: string, cdpResult: unknown, warning?: string, ipcHint?: string): CommandResult<CdpExecuteData>;
|
|
74
|
+
export {};
|
|
38
75
|
//# sourceMappingURL=cdp.d.ts.map
|
package/dist/commands/cdp.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { Option } from 'commander';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { resolveMethodTarget } from '../cdp/methodTarget.js';
|
|
3
|
+
import { getBundledProtocolVersion } from '../cdp/protocol.js';
|
|
4
|
+
import { getAllDomainSummaries, getDomainMethods, getProtocolCounts, getDomainSummary, getMethodSchema, getTypeSchema, } from '../cdp/schema.js';
|
|
4
5
|
import { runCommand } from './shared/CommandRunner.js';
|
|
5
6
|
import { jsonOption } from './shared/commonOptions.js';
|
|
6
7
|
import { CommandError } from '../errors/index.js';
|
|
7
|
-
import { emptyCdpSearchError, missingArgumentError, scriptExecutionError, } from '../errors/messages.js';
|
|
8
|
+
import { cdpMethodNotFoundError, cdpMethodNotInBundledProtocolError, cdpMethodTypoError, cdpTypeNotMethodError, emptyCdpSearchError, missingArgumentError, scriptExecutionError, } from '../errors/messages.js';
|
|
8
9
|
import { callCDP } from '../ipc/client.js';
|
|
9
10
|
import { validateIPCResponse } from '../ipc/index.js';
|
|
10
11
|
import { describeException } from '../runtime/dom/evalHelpers.js';
|
|
11
12
|
import { formatCdpDescription, formatCdpDomainMethods, formatCdpDomains, formatCdpResult, formatCdpSearch, isEmptyCdpResult, } from '../ui/formatters/cdp.js';
|
|
13
|
+
import { CDP_EXECUTION_HELP, cdpUnlistedMethodWarning } from '../ui/messages/commands.js';
|
|
12
14
|
import { formatHint } from '../ui/messages/hints.js';
|
|
13
15
|
import { sessionCommand } from '../ui/messages/sessionCommand.js';
|
|
14
16
|
import { getErrorMessage } from '../utils/errors.js';
|
|
@@ -80,9 +82,10 @@ function getMethodHint(methodName, result) {
|
|
|
80
82
|
export function registerCdpCommand(program) {
|
|
81
83
|
program
|
|
82
84
|
.command('cdp')
|
|
85
|
+
.summary('CDP protocol introspection and execution')
|
|
83
86
|
.description('CDP protocol introspection and execution\n' +
|
|
84
87
|
' Discovery: --list, --search, --describe\n' +
|
|
85
|
-
|
|
88
|
+
CDP_EXECUTION_HELP)
|
|
86
89
|
.argument('[method]', 'CDP method name (e.g., Network.getCookies, network.getcookies)')
|
|
87
90
|
.addOption(new Option('--params <json>', 'Method parameters as JSON'))
|
|
88
91
|
.addOption(new Option('--list', 'List all domains or methods in a domain').conflicts([
|
|
@@ -90,6 +93,7 @@ export function registerCdpCommand(program) {
|
|
|
90
93
|
'params',
|
|
91
94
|
]))
|
|
92
95
|
.addOption(new Option('--describe', 'Show method signature and parameters').conflicts('params'))
|
|
96
|
+
.addOption(new Option('--send-anyway', 'Send a Domain.method that looks like a typo of a bundled one as typed').conflicts(['list', 'describe', 'search']))
|
|
93
97
|
.addOption(new Option('--search <query>', 'Search methods by keyword').conflicts([
|
|
94
98
|
'list',
|
|
95
99
|
'describe',
|
|
@@ -122,7 +126,7 @@ async function runCdpCommand(method, options) {
|
|
|
122
126
|
return runCommand(async () => handleDescribeMethod(method), options, formatCdpDescription);
|
|
123
127
|
}
|
|
124
128
|
if (method) {
|
|
125
|
-
return runCommand(async () => handleExecuteMethod(method, options
|
|
129
|
+
return runCommand(async () => handleExecuteMethod(method, options), options, formatCdpResult);
|
|
126
130
|
}
|
|
127
131
|
return runCommand(async () => {
|
|
128
132
|
const err = missingArgumentError(CDP_USAGE);
|
|
@@ -330,99 +334,116 @@ function handleListDomainMethods(domainName) {
|
|
|
330
334
|
};
|
|
331
335
|
}
|
|
332
336
|
/**
|
|
333
|
-
* Handle describe
|
|
337
|
+
* Handle describe mode: show a domain, a method's signature and parameters,
|
|
338
|
+
* or a protocol type's values or properties.
|
|
334
339
|
*
|
|
335
|
-
* @param
|
|
336
|
-
* @returns Success result with
|
|
340
|
+
* @param name - Domain, `Domain.method` or `Domain.Type` (case-insensitive)
|
|
341
|
+
* @returns Success result with the description
|
|
337
342
|
*/
|
|
338
|
-
function handleDescribeMethod(
|
|
339
|
-
const [domainName,
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
events: summary.eventCount,
|
|
370
|
-
experimental: summary.experimental,
|
|
371
|
-
deprecated: summary.deprecated,
|
|
372
|
-
note: domainNote,
|
|
373
|
-
nextStep: `Use: bdg cdp ${summary.name} --list (to see all methods)`,
|
|
374
|
-
},
|
|
375
|
-
};
|
|
376
|
-
}
|
|
377
|
-
const schema = getMethodSchema(domainName, method);
|
|
378
|
-
if (!schema) {
|
|
379
|
-
const similar = findSimilarMethods(methodName, domainName);
|
|
380
|
-
const suggestions = [`Use: bdg cdp ${domainName} --list (to see all ${domainName} methods)`];
|
|
381
|
-
if (similar.length > 0) {
|
|
382
|
-
suggestions.push('');
|
|
383
|
-
suggestions.push('Did you mean:');
|
|
384
|
-
similar.forEach((name) => suggestions.push(` - ${name}`));
|
|
385
|
-
}
|
|
343
|
+
export function handleDescribeMethod(name) {
|
|
344
|
+
const [domainName = '', member] = name.includes('.') ? name.split('.') : [name, undefined];
|
|
345
|
+
if (!member)
|
|
346
|
+
return describeDomain(name);
|
|
347
|
+
const schema = getMethodSchema(domainName, member);
|
|
348
|
+
if (schema)
|
|
349
|
+
return { success: true, data: describeMethod(schema) };
|
|
350
|
+
const type = getTypeSchema(domainName, member);
|
|
351
|
+
if (type)
|
|
352
|
+
return { success: true, data: { type: 'type', ...type } };
|
|
353
|
+
const target = resolveMethodTarget(name);
|
|
354
|
+
const err = target.kind === 'unlisted'
|
|
355
|
+
? cdpMethodNotInBundledProtocolError(target.method, getBundledProtocolVersion())
|
|
356
|
+
: cdpMethodNotFoundError(name, findSimilarMethods(name, domainName), `Use: bdg cdp ${domainName} --list (to see all ${domainName} methods)`);
|
|
357
|
+
return {
|
|
358
|
+
success: false,
|
|
359
|
+
error: err.message,
|
|
360
|
+
exitCode: EXIT_CODES.INVALID_ARGUMENTS,
|
|
361
|
+
errorContext: { suggestion: err.suggestion },
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Describe a domain (`bdg cdp Network --describe`).
|
|
366
|
+
*
|
|
367
|
+
* @param domainName - Domain name (case-insensitive)
|
|
368
|
+
* @returns Domain description, or not found with similar names
|
|
369
|
+
*/
|
|
370
|
+
function describeDomain(domainName) {
|
|
371
|
+
const summary = getDomainSummary(domainName);
|
|
372
|
+
if (!summary) {
|
|
373
|
+
const err = cdpMethodNotFoundError(domainName, findSimilarMethods(domainName), 'Use: bdg cdp --list (to see all domains)');
|
|
386
374
|
return {
|
|
387
375
|
success: false,
|
|
388
|
-
error: `
|
|
376
|
+
error: `Domain or method '${domainName}' not found`,
|
|
389
377
|
exitCode: EXIT_CODES.INVALID_ARGUMENTS,
|
|
390
|
-
errorContext: {
|
|
391
|
-
suggestion: suggestions.join('\n'),
|
|
392
|
-
},
|
|
378
|
+
errorContext: { suggestion: err.suggestion },
|
|
393
379
|
};
|
|
394
380
|
}
|
|
395
|
-
const methodNote = METHOD_NOTES[schema.name] ?? DOMAIN_NOTES[schema.domain];
|
|
396
|
-
const alternative = blockedAlternative(schema.name);
|
|
397
381
|
return {
|
|
398
382
|
success: true,
|
|
399
383
|
data: {
|
|
400
|
-
type: '
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
experimental:
|
|
406
|
-
deprecated:
|
|
407
|
-
note:
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
384
|
+
type: 'domain',
|
|
385
|
+
domain: summary.name,
|
|
386
|
+
description: summary.description,
|
|
387
|
+
commands: summary.commandCount,
|
|
388
|
+
events: summary.eventCount,
|
|
389
|
+
experimental: summary.experimental,
|
|
390
|
+
deprecated: summary.deprecated,
|
|
391
|
+
note: DOMAIN_NOTES[summary.name],
|
|
392
|
+
nextStep: `Use: bdg cdp ${summary.name} --list (to see all methods)`,
|
|
393
|
+
},
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* A parameter as `--describe` shows it.
|
|
398
|
+
*
|
|
399
|
+
* @param p - Parameter schema
|
|
400
|
+
* @returns Described parameter
|
|
401
|
+
*/
|
|
402
|
+
function describeParameter(p) {
|
|
403
|
+
return {
|
|
404
|
+
name: p.name,
|
|
405
|
+
type: p.type,
|
|
406
|
+
required: p.required,
|
|
407
|
+
description: p.description,
|
|
408
|
+
enum: p.enum,
|
|
409
|
+
ref: p.ref,
|
|
410
|
+
refType: p.refType,
|
|
411
|
+
items: p.items,
|
|
412
|
+
experimental: p.experimental,
|
|
413
|
+
deprecated: p.deprecated,
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Describe a method (`bdg cdp Network.getCookies --describe`).
|
|
418
|
+
*
|
|
419
|
+
* @param schema - Method schema
|
|
420
|
+
* @returns Method description with its redirect, note and example
|
|
421
|
+
*/
|
|
422
|
+
function describeMethod(schema) {
|
|
423
|
+
const alternative = blockedAlternative(schema.name);
|
|
424
|
+
return {
|
|
425
|
+
type: 'method',
|
|
426
|
+
name: schema.name,
|
|
427
|
+
domain: schema.domain,
|
|
428
|
+
method: schema.method,
|
|
429
|
+
description: schema.description,
|
|
430
|
+
experimental: schema.experimental,
|
|
431
|
+
deprecated: schema.deprecated,
|
|
432
|
+
note: METHOD_NOTES[schema.name] ?? DOMAIN_NOTES[schema.domain],
|
|
433
|
+
parameters: schema.parameters.map(describeParameter),
|
|
434
|
+
returns: schema.returns.map((r) => ({
|
|
435
|
+
name: r.name,
|
|
436
|
+
type: r.type,
|
|
437
|
+
optional: r.optional,
|
|
438
|
+
description: r.description,
|
|
439
|
+
items: r.items,
|
|
440
|
+
})),
|
|
441
|
+
redirect: schema.redirect && {
|
|
442
|
+
method: schema.redirect.method,
|
|
443
|
+
resolved: schema.redirect.resolved,
|
|
444
|
+
parameters: schema.redirect.parameters.map(describeParameter),
|
|
425
445
|
},
|
|
446
|
+
example: alternative ? { command: alternative } : schema.example,
|
|
426
447
|
};
|
|
427
448
|
}
|
|
428
449
|
/**
|
|
@@ -444,44 +465,78 @@ const BLOCKED_CDP_METHODS = {
|
|
|
444
465
|
},
|
|
445
466
|
};
|
|
446
467
|
/**
|
|
447
|
-
*
|
|
468
|
+
* The method `bdg cdp <name>` sends: a bundled method with its casing, or a
|
|
469
|
+
* well-formed method the bundled protocol lacks, as typed with a warning.
|
|
448
470
|
*
|
|
449
|
-
* @param methodName - Method name
|
|
450
|
-
* @param
|
|
451
|
-
* @returns
|
|
471
|
+
* @param methodName - Method name as typed
|
|
472
|
+
* @param options - `sendAnyway` sends a close typo of bundled methods as typed
|
|
473
|
+
* @returns Method to send, and the warning for one the bundled protocol lacks
|
|
474
|
+
* @throws CommandError (exit 81) for a blocked method, a type, a close typo
|
|
475
|
+
* of bundled methods (without `sendAnyway`) or a name that is not `Domain.method`
|
|
452
476
|
*/
|
|
453
|
-
|
|
454
|
-
const
|
|
455
|
-
if (
|
|
456
|
-
const blocked = BLOCKED_CDP_METHODS[
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
error: `${normalized} is blocked via raw CDP: ${blocked.reason}`,
|
|
460
|
-
exitCode: EXIT_CODES.INVALID_ARGUMENTS,
|
|
461
|
-
errorContext: { suggestion: `Use: ${sessionCommand(blocked.alternative)}` },
|
|
462
|
-
};
|
|
463
|
-
}
|
|
464
|
-
if (!normalized) {
|
|
465
|
-
const similar = findSimilarMethods(methodName);
|
|
466
|
-
const suggestions = ['Use: bdg cdp --search <keyword> (to search for methods)'];
|
|
467
|
-
if (similar.length > 0) {
|
|
468
|
-
suggestions.push('');
|
|
469
|
-
suggestions.push('Did you mean:');
|
|
470
|
-
similar.forEach((name) => suggestions.push(` - ${name}`));
|
|
477
|
+
export function methodToSend(methodName, options = {}) {
|
|
478
|
+
const target = resolveMethodTarget(methodName);
|
|
479
|
+
if (target.kind === 'known') {
|
|
480
|
+
const blocked = BLOCKED_CDP_METHODS[target.method];
|
|
481
|
+
if (blocked) {
|
|
482
|
+
throw new CommandError(`${target.method} is blocked via raw CDP: ${blocked.reason}`, { suggestion: `Use: ${sessionCommand(blocked.alternative)}` }, EXIT_CODES.INVALID_ARGUMENTS);
|
|
471
483
|
}
|
|
484
|
+
return { method: target.method };
|
|
485
|
+
}
|
|
486
|
+
if (target.kind === 'unlisted' || (target.kind === 'typo' && options.sendAnyway)) {
|
|
472
487
|
return {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
exitCode: EXIT_CODES.INVALID_ARGUMENTS,
|
|
476
|
-
errorContext: {
|
|
477
|
-
suggestion: suggestions.join('\n'),
|
|
478
|
-
},
|
|
488
|
+
method: target.method,
|
|
489
|
+
warning: cdpUnlistedMethodWarning(target.method, getBundledProtocolVersion()),
|
|
479
490
|
};
|
|
480
491
|
}
|
|
492
|
+
const err = target.kind === 'type'
|
|
493
|
+
? cdpTypeNotMethodError(target.name)
|
|
494
|
+
: unknownMethodError(methodName, target);
|
|
495
|
+
throw new CommandError(err.message, { suggestion: err.suggestion }, EXIT_CODES.INVALID_ARGUMENTS);
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Not found, for a close typo of bundled methods or domains, or a name that
|
|
499
|
+
* is not `Domain.method`.
|
|
500
|
+
*
|
|
501
|
+
* @param methodName - Method name as typed
|
|
502
|
+
* @param target - Typo with its suggestions, or malformed
|
|
503
|
+
* @returns Message and suggestion
|
|
504
|
+
*/
|
|
505
|
+
function unknownMethodError(methodName, target) {
|
|
506
|
+
if (target.kind === 'malformed') {
|
|
507
|
+
return cdpMethodNotFoundError(methodName, findSimilarMethods(methodName), 'Use: bdg cdp --search <keyword> (to search for methods)');
|
|
508
|
+
}
|
|
509
|
+
const [domainName = ''] = methodName.split('.');
|
|
510
|
+
return target.suggestions.length > 0
|
|
511
|
+
? cdpMethodTypoError(methodName, target.suggestions.slice(0, 3), 'Use: bdg cdp --search <keyword> (to search for methods)')
|
|
512
|
+
: cdpMethodTypoError(methodName, [], domainSuggestion(domainName));
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Add the warning about a method missing from the bundled protocol to the
|
|
516
|
+
* error Chrome gave for it, so a failed call still says it was sent as typed.
|
|
517
|
+
*
|
|
518
|
+
* @param error - Error of the call
|
|
519
|
+
* @param warning - Warning, when the method was not in the bundled protocol
|
|
520
|
+
* @returns The error, with the warning (top-level JSON `warning`) when there is one
|
|
521
|
+
*/
|
|
522
|
+
function withWarning(error, warning) {
|
|
523
|
+
if (!warning || !(error instanceof CommandError))
|
|
524
|
+
return error;
|
|
525
|
+
return new CommandError(error.message, { ...error.metadata, warning }, error.exitCode);
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Handle execute method mode: Call CDP method.
|
|
529
|
+
*
|
|
530
|
+
* @param methodName - Method name (case-insensitive for bundled methods)
|
|
531
|
+
* @param paramsJson - Parameters as JSON string
|
|
532
|
+
* @returns Success result with method response
|
|
533
|
+
*/
|
|
534
|
+
async function handleExecuteMethod(methodName, options) {
|
|
535
|
+
const { method: normalized, warning } = methodToSend(methodName, options);
|
|
481
536
|
let params;
|
|
482
|
-
if (
|
|
537
|
+
if (options.params) {
|
|
483
538
|
try {
|
|
484
|
-
params = JSON.parse(
|
|
539
|
+
params = JSON.parse(options.params);
|
|
485
540
|
}
|
|
486
541
|
catch (error) {
|
|
487
542
|
return {
|
|
@@ -491,29 +546,42 @@ async function handleExecuteMethod(methodName, paramsJson) {
|
|
|
491
546
|
errorContext: {
|
|
492
547
|
suggestion: `Use: bdg cdp ${normalized} --describe (to see parameter schema)`,
|
|
493
548
|
},
|
|
549
|
+
...(warning && { warning }),
|
|
494
550
|
};
|
|
495
551
|
}
|
|
496
552
|
}
|
|
497
553
|
const response = await callCDP(normalized, params);
|
|
498
|
-
|
|
499
|
-
|
|
554
|
+
try {
|
|
555
|
+
validateIPCResponse(response);
|
|
556
|
+
}
|
|
557
|
+
catch (error) {
|
|
558
|
+
throw withWarning(error, warning);
|
|
559
|
+
}
|
|
560
|
+
const ipcHint = response.data?.hint && formatHint(response.data.hint);
|
|
561
|
+
return cdpCallResult(normalized, response.data?.result, warning, ipcHint);
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* The result of a CDP call: the page exception it reported (exit 91), or its
|
|
565
|
+
* result with the session's and the method's hints; either way with the
|
|
566
|
+
* warning for a method the bundled protocol lacks.
|
|
567
|
+
*
|
|
568
|
+
* @param method - Method called
|
|
569
|
+
* @param cdpResult - What Chrome returned
|
|
570
|
+
* @param warning - Warning for a method the bundled protocol lacks
|
|
571
|
+
* @param ipcHint - Hint the session gave (e.g. a repeated-call pattern)
|
|
572
|
+
* @returns Command result
|
|
573
|
+
*/
|
|
574
|
+
export function cdpCallResult(method, cdpResult, warning, ipcHint) {
|
|
575
|
+
const withCallWarning = warning ? { warning } : {};
|
|
500
576
|
const exception = pageExceptionResult(cdpResult);
|
|
501
577
|
if (exception)
|
|
502
|
-
return exception;
|
|
503
|
-
const
|
|
578
|
+
return { ...exception, ...withCallWarning };
|
|
579
|
+
const hints = [ipcHint, getMethodHint(method, cdpResult)].filter(Boolean);
|
|
580
|
+
return {
|
|
504
581
|
success: true,
|
|
505
|
-
data: {
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
},
|
|
582
|
+
data: { method, result: cdpResult },
|
|
583
|
+
...withCallWarning,
|
|
584
|
+
...(hints.length > 0 && { hint: hints.join('\n') }),
|
|
509
585
|
};
|
|
510
|
-
if (response.data?.hint) {
|
|
511
|
-
result.hint = formatHint(response.data.hint);
|
|
512
|
-
}
|
|
513
|
-
const methodHint = getMethodHint(normalized, cdpResult);
|
|
514
|
-
if (methodHint) {
|
|
515
|
-
result.hint = result.hint ? `${result.hint}\n${methodHint}` : methodHint;
|
|
516
|
-
}
|
|
517
|
-
return result;
|
|
518
586
|
}
|
|
519
587
|
//# sourceMappingURL=cdp.js.map
|
package/dist/commands/cleanup.js
CHANGED
|
@@ -5,10 +5,10 @@ import { purgeNeedsNamedSessionError, purgeRefusedError, sessionDirIsFileError,
|
|
|
5
5
|
import { isSessionChrome } from '../session/cleanup/staleSession.js';
|
|
6
6
|
import { performSessionCleanup } from '../session/cleanup/userCommands.js';
|
|
7
7
|
import { isDaemonAlive } from '../session/daemonSocket.js';
|
|
8
|
-
import { getSessionDir, getSessionFilePath, getSessionName } from '../session/paths.js';
|
|
8
|
+
import { getSessionDir, getSessionDownloadsDir, getSessionFilePath, getSessionName, } from '../session/paths.js';
|
|
9
9
|
import { readDaemonPid, readPidFromFile } from '../session/pid.js';
|
|
10
10
|
import { joinLines } from '../ui/formatting.js';
|
|
11
|
-
import { sessionFilesCleanedMessage, sessionOutputRemovedMessage, sessionDirectoryCleanMessage, sessionDirectoryPurgedMessage, noSessionFilesMessage, sessionStillActiveError, sessionStillActiveSuggestion, warningMessage, } from '../ui/messages/commands.js';
|
|
11
|
+
import { downloadsKeptMessage, sessionFilesCleanedMessage, sessionOutputRemovedMessage, sessionDirectoryCleanMessage, sessionDirectoryPurgedMessage, noSessionFilesMessage, sessionStillActiveError, sessionStillActiveSuggestion, warningMessage, } from '../ui/messages/commands.js';
|
|
12
12
|
import { delay } from '../utils/async.js';
|
|
13
13
|
import { EXIT_CODES } from '../utils/exitCodes.js';
|
|
14
14
|
import { isProcessAlive } from '../utils/process.js';
|
|
@@ -19,7 +19,7 @@ import { isProcessAlive } from '../utils/process.js';
|
|
|
19
19
|
*/
|
|
20
20
|
function formatCleanup(data) {
|
|
21
21
|
const { cleaned } = data;
|
|
22
|
-
return joinLines(cleaned.session && sessionFilesCleanedMessage(), cleaned.output && sessionOutputRemovedMessage(), ...(data.warnings ?? []).map((warning) => warningMessage(warning)), '', data.message);
|
|
22
|
+
return joinLines(cleaned.session && sessionFilesCleanedMessage(), cleaned.output && sessionOutputRemovedMessage(), data.downloadsKept && downloadsKeptMessage(data.downloadsKept.dir, data.downloadsKept.files), ...(data.warnings ?? []).map((warning) => warningMessage(warning)), '', data.message);
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
25
|
* Delete the selected named session's directory (Chrome profile, logs, port).
|
|
@@ -136,6 +136,9 @@ async function cleanupBlocker(opts) {
|
|
|
136
136
|
}
|
|
137
137
|
/**
|
|
138
138
|
* Clean up the selected session (and delete its directory with `--purge`).
|
|
139
|
+
* It does not run the session directory trust check (`secureSessionDir`): it
|
|
140
|
+
* sends no command, only probes the socket and signals PIDs verified by
|
|
141
|
+
* their command line, and must still clean up an untrusted directory.
|
|
139
142
|
*
|
|
140
143
|
* @param opts - Cleanup options
|
|
141
144
|
* @returns Command result
|
|
@@ -159,11 +162,13 @@ async function cleanupSession(opts) {
|
|
|
159
162
|
};
|
|
160
163
|
}
|
|
161
164
|
const didCleanup = Object.values(cleaned).some(Boolean) || purged !== undefined;
|
|
165
|
+
const downloadsKept = purged === undefined ? keptDownloads() : undefined;
|
|
162
166
|
return {
|
|
163
167
|
success: true,
|
|
164
168
|
data: {
|
|
165
169
|
cleaned,
|
|
166
170
|
...(purged !== undefined && { purged }),
|
|
171
|
+
...(downloadsKept && { downloadsKept }),
|
|
167
172
|
message: !didCleanup
|
|
168
173
|
? noSessionFilesMessage()
|
|
169
174
|
: purged !== undefined
|
|
@@ -173,6 +178,18 @@ async function cleanupSession(opts) {
|
|
|
173
178
|
},
|
|
174
179
|
};
|
|
175
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* Downloaded files of the session, which cleanup keeps.
|
|
183
|
+
*
|
|
184
|
+
* @returns Their directory and count, or undefined when there are none
|
|
185
|
+
*/
|
|
186
|
+
function keptDownloads() {
|
|
187
|
+
const dir = getSessionDownloadsDir();
|
|
188
|
+
if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory())
|
|
189
|
+
return undefined;
|
|
190
|
+
const files = fs.readdirSync(dir).length;
|
|
191
|
+
return files > 0 ? { dir, files } : undefined;
|
|
192
|
+
}
|
|
176
193
|
/**
|
|
177
194
|
* Register cleanup command
|
|
178
195
|
*
|
|
@@ -181,7 +198,7 @@ async function cleanupSession(opts) {
|
|
|
181
198
|
export function registerCleanupCommand(program) {
|
|
182
199
|
program
|
|
183
200
|
.command('cleanup')
|
|
184
|
-
.description('Clean up stale session files')
|
|
201
|
+
.description('Clean up stale session files (downloaded files are kept)')
|
|
185
202
|
.option('-f, --force', 'Kill a running (possibly hung) session, then clean up', false)
|
|
186
203
|
.option('--remove-output', 'Also remove session.json output file', false)
|
|
187
204
|
.option('--aggressive', 'Alias for --force (kept for compatibility)', false)
|
|
@@ -11,7 +11,8 @@ import type { DomEvalCommandOptions } from '../shared/optionTypes.js';
|
|
|
11
11
|
* frame the script ran in is a `Frame:` line on stderr (JSON: `frame`), and
|
|
12
12
|
* a warning about how the result was copied goes there too (JSON:
|
|
13
13
|
* `warning`), so stdout stays the bare value for pipes. Long values are cut
|
|
14
|
-
*
|
|
14
|
+
* unless `--full`: human output when formatted, JSON results by
|
|
15
|
+
* {@link boundEvalResult}.
|
|
15
16
|
*/
|
|
16
17
|
export declare function handleDomEval(script: string, options: DomEvalCommandOptions): Promise<void>;
|
|
17
18
|
//# sourceMappingURL=eval.d.ts.map
|
|
@@ -5,21 +5,21 @@
|
|
|
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 { boundEvalResult } from './helpers/evalResult.js';
|
|
8
9
|
import { documentReadyState } from './helpers/query.js';
|
|
9
10
|
import { runCommand } from '../shared/CommandRunner.js';
|
|
10
|
-
import { MAX_VALUE_LENGTH } from '../../constants.js';
|
|
11
11
|
import { emptyScriptError, withLoadingHint } from '../../errors/messages.js';
|
|
12
12
|
import { domEval } from '../../ipc/client.js';
|
|
13
13
|
import { formatDomEval } from '../../ui/formatters/dom.js';
|
|
14
14
|
import { evalFrameLine, warningMessage } from '../../ui/messages/commands.js';
|
|
15
15
|
import { EXIT_CODES } from '../../utils/exitCodes.js';
|
|
16
|
-
import { capLength } from '../../utils/strings.js';
|
|
17
16
|
/**
|
|
18
17
|
* Handle `bdg dom eval <script> [--frame <frame>]`. With `--frame`, the
|
|
19
18
|
* frame the script ran in is a `Frame:` line on stderr (JSON: `frame`), and
|
|
20
19
|
* a warning about how the result was copied goes there too (JSON:
|
|
21
20
|
* `warning`), so stdout stays the bare value for pipes. Long values are cut
|
|
22
|
-
*
|
|
21
|
+
* unless `--full`: human output when formatted, JSON results by
|
|
22
|
+
* {@link boundEvalResult}.
|
|
23
23
|
*/
|
|
24
24
|
export async function handleDomEval(script, options) {
|
|
25
25
|
await runCommand(async () => {
|
|
@@ -32,7 +32,7 @@ export async function handleDomEval(script, options) {
|
|
|
32
32
|
errorContext: { suggestion: err.suggestion },
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
|
-
const response = await domEval(script, options.frame);
|
|
35
|
+
const response = await domEval(script, options.frame, options.full);
|
|
36
36
|
if (response.status === 'error' || !response.data) {
|
|
37
37
|
const suggestion = await frameErrorSuggestion(response, options.frame);
|
|
38
38
|
return {
|
|
@@ -42,7 +42,7 @@ export async function handleDomEval(script, options) {
|
|
|
42
42
|
...(suggestion && { errorContext: { suggestion } }),
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
|
-
const { value, type, subtype, frame, warning } = response.data;
|
|
45
|
+
const { value, type, subtype, length, frame, warning } = response.data;
|
|
46
46
|
const hint = [
|
|
47
47
|
...(frame !== undefined ? [evalFrameLine(frame)] : []),
|
|
48
48
|
...(warning ? [warningMessage(warning)] : []),
|
|
@@ -50,7 +50,7 @@ export async function handleDomEval(script, options) {
|
|
|
50
50
|
return {
|
|
51
51
|
success: true,
|
|
52
52
|
data: {
|
|
53
|
-
...
|
|
53
|
+
...(options.json && !options.full ? boundEvalResult(value, length) : { result: value }),
|
|
54
54
|
type,
|
|
55
55
|
...(subtype && { subtype }),
|
|
56
56
|
...(frame !== undefined && { frame }),
|
|
@@ -60,21 +60,6 @@ export async function handleDomEval(script, options) {
|
|
|
60
60
|
};
|
|
61
61
|
}, options, (data) => formatDomEval(data, { full: options.full }));
|
|
62
62
|
}
|
|
63
|
-
/**
|
|
64
|
-
* The result field of the output: a string result in JSON cut to
|
|
65
|
-
* {@link MAX_VALUE_LENGTH} characters with `truncatedFrom`, unless `--full`
|
|
66
|
-
* (human output is cut when formatted).
|
|
67
|
-
*
|
|
68
|
-
* @param value - Evaluated value
|
|
69
|
-
* @param options - `--json`, `--full`
|
|
70
|
-
* @returns `result`, and `truncatedFrom` when cut
|
|
71
|
-
*/
|
|
72
|
-
function jsonResult(value, options) {
|
|
73
|
-
if (!options.json || options.full || typeof value !== 'string')
|
|
74
|
-
return { result: value };
|
|
75
|
-
const { text, truncatedFrom } = capLength(value, MAX_VALUE_LENGTH);
|
|
76
|
-
return { result: text, ...(truncatedFrom !== undefined && { truncatedFrom }) };
|
|
77
|
-
}
|
|
78
63
|
/**
|
|
79
64
|
* Suggestion of a failed eval; a frame not found (83) while the page is
|
|
80
65
|
* still loading says so (its iframes may not exist yet).
|
|
@@ -18,7 +18,7 @@ import { callCDP, domClick, domFill, domPressKey, domScroll, domSubmit } from '.
|
|
|
18
18
|
import { findUnknownModifiers } from '../../runtime/dom/keyMapping.js';
|
|
19
19
|
import { formatTriggeredRequestLines, formatTriggeredRequestsTitle, } from '../../ui/formatters/triggeredRequests.js';
|
|
20
20
|
import { OutputFormatter } from '../../ui/formatting.js';
|
|
21
|
-
import { CLICK_RESULT_WAIT_HELP, HOVER_OFF_DONE, HOVER_USAGE, POINTER_ACTION_DONE, POINTER_ACTION_NOUN, pointerScrollText, actionStatusLine, dialogConsoleText, moreMessagesText, newMessageText, pageNavigationText, shownElementText, stillChangingNote, } from '../../ui/messages/commands.js';
|
|
21
|
+
import { CLICK_RESULT_WAIT_HELP, HOVER_OFF_DONE, HOVER_USAGE, POINTER_ACTION_DONE, POINTER_ACTION_NOUN, pointerScrollText, actionStatusLine, dialogConsoleText, downloadText, moreMessagesText, newMessageText, pageNavigationText, shownElementText, stillChangingNote, } from '../../ui/messages/commands.js';
|
|
22
22
|
import { sessionCommand } from '../../ui/messages/sessionCommand.js';
|
|
23
23
|
import { EXIT_CODES } from '../../utils/exitCodes.js';
|
|
24
24
|
/** Help of `--strict` on click and hover */
|
|
@@ -313,9 +313,9 @@ async function runPointerCommand(selectorOrIndex, options, action) {
|
|
|
313
313
|
* "⚠ Element Clicked (page still changing)" with what it was still working
|
|
314
314
|
* on, or "⚠ Element Clicked (no visible effect: …)"), the details, what
|
|
315
315
|
* changed on the page (`Page:` navigation, `New text:` messages, `Shown:`
|
|
316
|
-
* elements), then the network requests it triggered
|
|
317
|
-
* caused. No request list is shown when there
|
|
318
|
-
* `triggeredRequests` then).
|
|
316
|
+
* elements), then the network requests it triggered, the downloads it
|
|
317
|
+
* started and the dialogs it caused. No request list is shown when there
|
|
318
|
+
* were none (JSON has an empty `triggeredRequests` then).
|
|
319
319
|
*
|
|
320
320
|
* @param done - What was done, e.g. "Element Clicked"
|
|
321
321
|
* @param details - Label/value rows
|
|
@@ -353,6 +353,10 @@ function formatActionOutput(done, details, result, options = {}) {
|
|
|
353
353
|
.blank()
|
|
354
354
|
.section(formatTriggeredRequestsTitle(result.triggeredRequests ?? [], omitted), requests);
|
|
355
355
|
}
|
|
356
|
+
if (result.downloads?.length)
|
|
357
|
+
fmt.blank();
|
|
358
|
+
for (const download of result.downloads ?? [])
|
|
359
|
+
fmt.text(downloadText(download));
|
|
356
360
|
for (const dialog of result.dialogs ?? []) {
|
|
357
361
|
fmt.blank();
|
|
358
362
|
fmt.text(`Dialog: ${dialogConsoleText(dialog)}`);
|