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.
Files changed (251) hide show
  1. package/README.md +4 -1
  2. package/dist/cdp/schema.d.ts +4 -1
  3. package/dist/cdp/schema.js +48 -7
  4. package/dist/commands/cdp.js +3 -2
  5. package/dist/commands/cleanup.d.ts +11 -0
  6. package/dist/commands/cleanup.js +161 -57
  7. package/dist/commands/console.d.ts +20 -1
  8. package/dist/commands/console.js +57 -17
  9. package/dist/commands/details.js +3 -2
  10. package/dist/commands/dom/DomElementResolver.d.ts +10 -3
  11. package/dist/commands/dom/DomElementResolver.js +35 -17
  12. package/dist/commands/dom/a11y.d.ts +10 -0
  13. package/dist/commands/dom/a11y.js +27 -5
  14. package/dist/commands/dom/eval.d.ts +3 -1
  15. package/dist/commands/dom/eval.js +29 -4
  16. package/dist/commands/dom/form.js +16 -62
  17. package/dist/commands/dom/formInteraction.js +152 -113
  18. package/dist/commands/dom/formSummary.d.ts +49 -0
  19. package/dist/commands/dom/formSummary.js +180 -0
  20. package/dist/commands/dom/frames.d.ts +2 -1
  21. package/dist/commands/dom/frames.js +17 -2
  22. package/dist/commands/dom/get.d.ts +6 -5
  23. package/dist/commands/dom/get.js +92 -82
  24. package/dist/commands/dom/helpers/index.d.ts +1 -1
  25. package/dist/commands/dom/helpers/index.js +1 -1
  26. package/dist/commands/dom/helpers/query.d.ts +44 -17
  27. package/dist/commands/dom/helpers/query.js +244 -97
  28. package/dist/commands/dom/helpers/runElementCommand.d.ts +10 -2
  29. package/dist/commands/dom/helpers/runElementCommand.js +97 -30
  30. package/dist/commands/dom/helpers/screenshot.d.ts +4 -1
  31. package/dist/commands/dom/helpers/screenshot.js +164 -49
  32. package/dist/commands/dom/index.d.ts +3 -1
  33. package/dist/commands/dom/index.js +16 -6
  34. package/dist/commands/dom/layout.d.ts +14 -0
  35. package/dist/commands/dom/layout.js +54 -0
  36. package/dist/commands/dom/listeners.d.ts +5 -1
  37. package/dist/commands/dom/listeners.js +13 -3
  38. package/dist/commands/dom/query.js +2 -3
  39. package/dist/commands/dom/screenshot.d.ts +12 -2
  40. package/dist/commands/dom/screenshot.js +27 -3
  41. package/dist/commands/dom/semanticUtils.d.ts +6 -13
  42. package/dist/commands/dom/semanticUtils.js +15 -19
  43. package/dist/commands/dom/wait.d.ts +13 -0
  44. package/dist/commands/dom/wait.js +83 -0
  45. package/dist/commands/helpJson.js +2 -2
  46. package/dist/commands/network/list.js +4 -11
  47. package/dist/commands/optionBehaviors.js +112 -21
  48. package/dist/commands/page.d.ts +2 -1
  49. package/dist/commands/page.js +41 -5
  50. package/dist/commands/peek.js +4 -11
  51. package/dist/commands/sessions.d.ts +8 -0
  52. package/dist/commands/sessions.js +19 -0
  53. package/dist/commands/shared/CommandRunner.js +4 -4
  54. package/dist/commands/shared/dataFetcher.js +2 -2
  55. package/dist/commands/shared/followMode.d.ts +21 -1
  56. package/dist/commands/shared/followMode.js +29 -2
  57. package/dist/commands/shared/handleValidationError.d.ts +2 -2
  58. package/dist/commands/shared/handleValidationError.js +12 -3
  59. package/dist/commands/shared/optionTypes.d.ts +40 -5
  60. package/dist/commands/shared/startHelpers.js +12 -3
  61. package/dist/commands/shared/validation.d.ts +3 -2
  62. package/dist/commands/shared/validation.js +4 -3
  63. package/dist/commands/start.d.ts +63 -0
  64. package/dist/commands/start.js +115 -15
  65. package/dist/commands/status.js +29 -7
  66. package/dist/commands/stop.js +7 -6
  67. package/dist/commands/tail.js +4 -11
  68. package/dist/commands/types.d.ts +2 -0
  69. package/dist/commands.js +2 -0
  70. package/dist/connection/chromeIdentity.d.ts +65 -0
  71. package/dist/connection/chromeIdentity.js +143 -0
  72. package/dist/connection/launcher/profilePreferences.d.ts +47 -0
  73. package/dist/connection/launcher/profilePreferences.js +151 -0
  74. package/dist/connection/launcher.d.ts +21 -2
  75. package/dist/connection/launcher.js +42 -16
  76. package/dist/connection/portReservation.d.ts +14 -4
  77. package/dist/connection/portReservation.js +21 -6
  78. package/dist/connection/startupExit.d.ts +8 -0
  79. package/dist/connection/startupExit.js +15 -6
  80. package/dist/constants.d.ts +6 -2
  81. package/dist/constants.js +9 -2
  82. package/dist/daemon/SessionController.js +23 -7
  83. package/dist/daemon/errors.d.ts +1 -1
  84. package/dist/daemon/errors.js +1 -1
  85. package/dist/daemon/launcher.d.ts +2 -1
  86. package/dist/daemon/launcher.js +5 -6
  87. package/dist/daemon/server/SocketServer.js +1 -2
  88. package/dist/daemon/session/Session.d.ts +13 -0
  89. package/dist/daemon/session/Session.js +57 -8
  90. package/dist/daemon/session/chromeConnection.d.ts +9 -0
  91. package/dist/daemon/session/chromeConnection.js +45 -8
  92. package/dist/daemon/session/commandRegistry.js +52 -62
  93. package/dist/daemon/session/interactions.d.ts +35 -9
  94. package/dist/daemon/session/interactions.js +36 -9
  95. package/dist/daemon/session/triggeredRequests.d.ts +67 -0
  96. package/dist/daemon/session/triggeredRequests.js +157 -0
  97. package/dist/daemon/session/types.d.ts +5 -1
  98. package/dist/daemon.js +5393 -1600
  99. package/dist/errors/messages.d.ts +387 -24
  100. package/dist/errors/messages.js +761 -67
  101. package/dist/index.js +3976 -1558
  102. package/dist/ipc/client.d.ts +12 -1
  103. package/dist/ipc/client.js +22 -3
  104. package/dist/ipc/protocol/commands.d.ts +89 -4
  105. package/dist/ipc/protocol/commands.js +2 -0
  106. package/dist/ipc/protocol/domTypes.d.ts +258 -7
  107. package/dist/ipc/session/lifecycle.d.ts +8 -1
  108. package/dist/ipc/session/queries.d.ts +5 -1
  109. package/dist/ipc/session/types.d.ts +5 -0
  110. package/dist/ipc/transport/index.d.ts +2 -1
  111. package/dist/ipc/transport/index.js +2 -2
  112. package/dist/runtime/dom/actionEffects.d.ts +106 -0
  113. package/dist/runtime/dom/actionEffects.js +256 -0
  114. package/dist/runtime/dom/actionEffectsScripts.d.ts +52 -0
  115. package/dist/runtime/dom/actionEffectsScripts.js +234 -0
  116. package/dist/runtime/dom/elementGeometry.d.ts +170 -0
  117. package/dist/runtime/dom/elementGeometry.js +553 -0
  118. package/dist/runtime/dom/elementInfo.d.ts +77 -0
  119. package/dist/runtime/dom/elementInfo.js +191 -0
  120. package/dist/runtime/dom/evalHelpers.d.ts +51 -6
  121. package/dist/runtime/dom/evalHelpers.js +136 -26
  122. package/dist/runtime/dom/eventListeners.d.ts +2 -1
  123. package/dist/runtime/dom/eventListeners.js +174 -47
  124. package/dist/runtime/dom/formDiscovery.d.ts +1 -1
  125. package/dist/runtime/dom/formDiscovery.js +116 -16
  126. package/dist/runtime/dom/formFillHelpers/fill.d.ts +10 -0
  127. package/dist/runtime/dom/formFillHelpers/fill.js +125 -10
  128. package/dist/runtime/dom/formFillHelpers/index.d.ts +2 -2
  129. package/dist/runtime/dom/formFillHelpers/index.js +2 -2
  130. package/dist/runtime/dom/formFillHelpers/pressKey.js +14 -3
  131. package/dist/runtime/dom/formFillHelpers/scroll.d.ts +3 -0
  132. package/dist/runtime/dom/formFillHelpers/scroll.js +60 -18
  133. package/dist/runtime/dom/formFillHelpers/shared.d.ts +17 -0
  134. package/dist/runtime/dom/formFillHelpers/shared.js +25 -1
  135. package/dist/runtime/dom/formFillHelpers/stability.d.ts +20 -6
  136. package/dist/runtime/dom/formFillHelpers/stability.js +50 -19
  137. package/dist/runtime/dom/formSubmitHelpers.d.ts +3 -0
  138. package/dist/runtime/dom/formSubmitHelpers.js +89 -15
  139. package/dist/runtime/dom/frameLayout.d.ts +60 -0
  140. package/dist/runtime/dom/frameLayout.js +140 -0
  141. package/dist/runtime/dom/frameOrigin.d.ts +50 -0
  142. package/dist/runtime/dom/frameOrigin.js +62 -0
  143. package/dist/runtime/dom/frameScopedConnection.d.ts +92 -0
  144. package/dist/runtime/dom/frameScopedConnection.js +252 -0
  145. package/dist/runtime/dom/frameSelection.d.ts +1 -1
  146. package/dist/runtime/dom/frameSelection.js +2 -2
  147. package/dist/runtime/dom/frames.d.ts +25 -2
  148. package/dist/runtime/dom/frames.js +202 -63
  149. package/dist/runtime/dom/layout.d.ts +67 -0
  150. package/dist/runtime/dom/layout.js +333 -0
  151. package/dist/runtime/dom/listenerPageScripts.d.ts +66 -0
  152. package/dist/runtime/dom/listenerPageScripts.js +279 -0
  153. package/dist/runtime/dom/listenerSummary.d.ts +132 -11
  154. package/dist/runtime/dom/listenerSummary.js +344 -22
  155. package/dist/runtime/dom/pageActivity.d.ts +41 -0
  156. package/dist/runtime/dom/pageActivity.js +123 -0
  157. package/dist/runtime/dom/reactEventHelpers.d.ts +58 -2
  158. package/dist/runtime/dom/reactEventHelpers.js +212 -41
  159. package/dist/runtime/dom/targetNode.d.ts +80 -27
  160. package/dist/runtime/dom/targetNode.js +249 -33
  161. package/dist/runtime/dom/wait.d.ts +25 -0
  162. package/dist/runtime/dom/wait.js +199 -0
  163. package/dist/runtime/dom/waitCondition.d.ts +71 -0
  164. package/dist/runtime/dom/waitCondition.js +75 -0
  165. package/dist/runtime/page/emulation.d.ts +51 -0
  166. package/dist/runtime/page/emulation.js +80 -0
  167. package/dist/runtime/page/loadingState.d.ts +36 -0
  168. package/dist/runtime/page/loadingState.js +86 -0
  169. package/dist/runtime/page/navigation.d.ts +46 -2
  170. package/dist/runtime/page/navigation.js +69 -33
  171. package/dist/session/QueryCacheManager.d.ts +11 -1
  172. package/dist/session/QueryCacheManager.js +25 -3
  173. package/dist/session/chromeOwners.d.ts +34 -0
  174. package/dist/session/chromeOwners.js +51 -0
  175. package/dist/session/cleanup/staleSession.d.ts +11 -1
  176. package/dist/session/cleanup/staleSession.js +17 -6
  177. package/dist/session/cleanup/userCommands.js +2 -4
  178. package/dist/session/metadata.d.ts +5 -1
  179. package/dist/session/metadata.js +2 -1
  180. package/dist/session/paths.d.ts +77 -3
  181. package/dist/session/paths.js +111 -5
  182. package/dist/session/port.d.ts +31 -7
  183. package/dist/session/port.js +50 -43
  184. package/dist/session/portClaims.d.ts +66 -0
  185. package/dist/session/portClaims.js +284 -0
  186. package/dist/session/sessionList.d.ts +58 -0
  187. package/dist/session/sessionList.js +199 -0
  188. package/dist/session/sessionName.d.ts +46 -0
  189. package/dist/session/sessionName.js +97 -0
  190. package/dist/telemetry/a11y.d.ts +8 -3
  191. package/dist/telemetry/a11y.js +92 -28
  192. package/dist/telemetry/requestKinds.d.ts +32 -0
  193. package/dist/telemetry/requestKinds.js +61 -0
  194. package/dist/telemetry/requestState.d.ts +31 -0
  195. package/dist/telemetry/requestState.js +38 -0
  196. package/dist/types.d.ts +80 -3
  197. package/dist/ui/formatters/a11y.js +3 -0
  198. package/dist/ui/formatters/console/chronological.d.ts +8 -0
  199. package/dist/ui/formatters/console/chronological.js +17 -4
  200. package/dist/ui/formatters/console/json.js +3 -4
  201. package/dist/ui/formatters/console/shared.d.ts +12 -0
  202. package/dist/ui/formatters/console.d.ts +2 -2
  203. package/dist/ui/formatters/console.js +1 -1
  204. package/dist/ui/formatters/details.js +2 -1
  205. package/dist/ui/formatters/dom.d.ts +26 -14
  206. package/dist/ui/formatters/dom.js +65 -52
  207. package/dist/ui/formatters/form.js +29 -18
  208. package/dist/ui/formatters/layout.d.ts +31 -0
  209. package/dist/ui/formatters/layout.js +53 -0
  210. package/dist/ui/formatters/listeners.d.ts +3 -2
  211. package/dist/ui/formatters/listeners.js +73 -9
  212. package/dist/ui/formatters/networkHeaders.js +13 -0
  213. package/dist/ui/formatters/preview.js +2 -1
  214. package/dist/ui/formatters/requestStatus.d.ts +1 -17
  215. package/dist/ui/formatters/requestStatus.js +2 -30
  216. package/dist/ui/formatters/sessions.d.ts +12 -0
  217. package/dist/ui/formatters/sessions.js +40 -0
  218. package/dist/ui/formatters/status.d.ts +21 -2
  219. package/dist/ui/formatters/status.js +47 -10
  220. package/dist/ui/formatters/triggeredRequests.d.ts +36 -0
  221. package/dist/ui/formatters/triggeredRequests.js +65 -0
  222. package/dist/ui/formatting.d.ts +10 -0
  223. package/dist/ui/formatting.js +28 -36
  224. package/dist/ui/messages/chrome.d.ts +9 -0
  225. package/dist/ui/messages/chrome.js +17 -5
  226. package/dist/ui/messages/commands.d.ts +388 -14
  227. package/dist/ui/messages/commands.js +664 -21
  228. package/dist/ui/messages/consoleMessages.d.ts +10 -0
  229. package/dist/ui/messages/consoleMessages.js +17 -0
  230. package/dist/ui/messages/hints.js +2 -1
  231. package/dist/ui/messages/preview.js +5 -4
  232. package/dist/ui/messages/session.d.ts +16 -21
  233. package/dist/ui/messages/session.js +28 -26
  234. package/dist/ui/messages/sessionCommand.d.ts +43 -0
  235. package/dist/ui/messages/sessionCommand.js +52 -0
  236. package/dist/utils/async.d.ts +8 -0
  237. package/dist/utils/async.js +19 -0
  238. package/dist/utils/http.d.ts +22 -1
  239. package/dist/utils/http.js +28 -9
  240. package/dist/utils/selectorFilters.d.ts +36 -8
  241. package/dist/utils/selectorFilters.js +267 -53
  242. package/dist/utils/shellDetection.d.ts +8 -2
  243. package/dist/utils/shellDetection.js +120 -33
  244. package/dist/utils/suggestions.d.ts +26 -0
  245. package/dist/utils/suggestions.js +73 -0
  246. package/dist/utils/taskMappings.js +10 -0
  247. package/dist/utils/url.d.ts +12 -2
  248. package/dist/utils/url.js +69 -7
  249. package/package.json +1 -1
  250. package/dist/ui/formatters/sessionFormatters.d.ts +0 -58
  251. package/dist/ui/formatters/sessionFormatters.js +0 -121
@@ -0,0 +1,40 @@
1
+ import { OutputFormatter } from '../formatting.js';
2
+ /** Label of the default session in the list */
3
+ const DEFAULT_SESSION_LABEL = '(default)';
4
+ /**
5
+ * Format the sessions as a table, followed by the cleanup commands of
6
+ * crashed and stale sessions.
7
+ *
8
+ * @param data - Sessions
9
+ * @returns Human-readable list
10
+ */
11
+ export function formatSessionList(data) {
12
+ const fmt = new OutputFormatter();
13
+ if (data.sessions.length === 0) {
14
+ return fmt
15
+ .text('No running sessions')
16
+ .hints('Suggestions:', ['Start one: bdg <url> [--session <name>]'])
17
+ .build();
18
+ }
19
+ const rows = data.sessions.map((session) => [
20
+ session.name ?? DEFAULT_SESSION_LABEL,
21
+ session.state,
22
+ session.port?.toString() ?? '-',
23
+ session.daemonPid?.toString() ?? '-',
24
+ session.url ?? '-',
25
+ ]);
26
+ const header = ['SESSION', 'STATE', 'PORT', 'PID', 'URL'];
27
+ const widths = header.map((title, column) => Math.max(title.length, ...rows.map((row) => row[column]?.length ?? 0)));
28
+ for (const row of [header, ...rows]) {
29
+ fmt.text(row
30
+ .map((cell, column) => cell.padEnd(widths[column] ?? 0))
31
+ .join(' ')
32
+ .trimEnd());
33
+ }
34
+ const cleanups = data.sessions.flatMap((session) => (session.cleanup ? [session.cleanup] : []));
35
+ if (cleanups.length > 0) {
36
+ fmt.hints('Crashed or stale sessions; clean up with:', cleanups);
37
+ }
38
+ return fmt.build();
39
+ }
40
+ //# sourceMappingURL=sessions.js.map
@@ -2,10 +2,14 @@ import type { SessionActivity, PageState } from '../../ipc/index.js';
2
2
  import { type RunningChromeInfo } from '../../session/chrome.js';
3
3
  import type { LastSessionEnd } from '../../session/lastSession.js';
4
4
  import type { SessionMetadata } from '../../session/metadata.js';
5
+ import type { ColorScheme, ViewportSize } from '../../types.js';
5
6
  export interface StatusData {
7
+ /** Name of the selected session (named sessions only) */
8
+ session?: string;
6
9
  active: boolean;
7
10
  bdgPid?: number;
8
- chromePid?: number | undefined;
11
+ /** Chrome launched by bdg; null for an attached Chrome */
12
+ chromePid?: number | null | undefined;
9
13
  chromeAlive?: boolean;
10
14
  /** Attached to a Chrome bdg did not launch (`--chrome-ws-url`); it has no known PID */
11
15
  externalChrome?: boolean;
@@ -18,6 +22,10 @@ export interface StatusData {
18
22
  telemetry?: string[];
19
23
  /** When `--timeout` stops the session (ISO time) */
20
24
  autoStopAt?: string;
25
+ /** Viewport given with `--viewport` (`pageState.viewport` is the current one) */
26
+ viewport?: ViewportSize;
27
+ /** Color scheme given with `--color-scheme` (`pageState.colorScheme` is the current one) */
28
+ colorScheme?: ColorScheme;
21
29
  stale?: boolean;
22
30
  stalePid?: number;
23
31
  warning?: string;
@@ -44,8 +52,19 @@ export interface StatusData {
44
52
  * @param activity - Live activity metrics from the session
45
53
  * @param pageState - Current page state from the session
46
54
  * @param verbose - Also show the session's Chrome executable, mode and profile
55
+ * @param sessionName - Name of a named session
47
56
  */
48
- export declare function formatSessionStatus(metadata: SessionMetadata, pid: number, activity?: SessionActivity, pageState?: PageState, verbose?: boolean): string;
57
+ export declare function formatSessionStatus(metadata: SessionMetadata, pid: number, activity?: SessionActivity, pageState?: PageState, verbose?: boolean, sessionName?: string): string;
58
+ /**
59
+ * Viewport and color scheme lines of the target: what the page renders with,
60
+ * and whether `--viewport` / `--color-scheme` set it or it is the system's.
61
+ * The color scheme is the `prefers-color-scheme` the page sees, not its theme.
62
+ *
63
+ * @param metadata - Session metadata (the start options)
64
+ * @param pageState - Page state (what the page reported)
65
+ * @returns Key-value pairs (none for what is unknown)
66
+ */
67
+ export declare function appearanceLines(metadata: Pick<SessionMetadata, 'viewport' | 'colorScheme'>, pageState: PageState): Array<[string, string]>;
49
68
  /**
50
69
  * Convert status data to JSON format
51
70
  */
@@ -1,7 +1,9 @@
1
1
  import { describeRunningChrome } from '../../session/chrome.js';
2
2
  import { calculateDuration, formatTimeAgo } from '../../session/statusData.js';
3
3
  import { OutputFormatter } from '../formatting.js';
4
+ import { colorSchemeLabel, sessionActiveLine } from '../messages/commands.js';
4
5
  import { lastSessionEndText } from '../messages/session.js';
6
+ import { noActiveSessionMessage, sessionCommand } from '../messages/sessionCommand.js';
5
7
  import { isProcessAlive } from '../../utils/process.js';
6
8
  /**
7
9
  * Format session status for human-readable output
@@ -10,13 +12,16 @@ import { isProcessAlive } from '../../utils/process.js';
10
12
  * @param activity - Live activity metrics from the session
11
13
  * @param pageState - Current page state from the session
12
14
  * @param verbose - Also show the session's Chrome executable, mode and profile
15
+ * @param sessionName - Name of a named session
13
16
  */
14
- export function formatSessionStatus(metadata, pid, activity, pageState, verbose = false) {
17
+ export function formatSessionStatus(metadata, pid, activity, pageState, verbose = false, sessionName) {
15
18
  const duration = calculateDuration(metadata.startTime);
16
19
  const chromeAlive = metadata.chromePid ? isProcessAlive(metadata.chromePid) : false;
17
20
  const fmt = new OutputFormatter();
21
+ fmt.text(sessionActiveLine(pageState)).blank();
18
22
  fmt.text('Session Status').separator('━', 50);
19
23
  fmt.keyValueList([
24
+ ...(sessionName ? [['Session', sessionName]] : []),
20
25
  ['Status', 'ACTIVE'],
21
26
  ['Duration', duration.formatted],
22
27
  ...(metadata.autoStopAt
@@ -38,6 +43,7 @@ export function formatSessionStatus(metadata, pid, activity, pageState, verbose
38
43
  if (pageState.title) {
39
44
  fmt.keyValue('Title', pageState.title, 18);
40
45
  }
46
+ fmt.keyValueList(appearanceLines(metadata, pageState), 18);
41
47
  }
42
48
  if (activity) {
43
49
  fmt.blank().text('Activity').separator('━', 50);
@@ -69,12 +75,40 @@ export function formatSessionStatus(metadata, pid, activity, pageState, verbose
69
75
  fmt
70
76
  .blank()
71
77
  .section('Commands:', [
72
- 'Peek data: bdg peek',
73
- 'Run JavaScript: bdg dom eval <script>',
74
- 'End session: bdg stop',
78
+ `Peek data: ${sessionCommand('bdg peek', sessionName ?? null)}`,
79
+ `Run JavaScript: ${sessionCommand('bdg dom eval <script>', sessionName ?? null)}`,
80
+ `End session: ${sessionCommand('bdg stop', sessionName ?? null)}`,
75
81
  ]);
76
82
  return fmt.build();
77
83
  }
84
+ /**
85
+ * Viewport and color scheme lines of the target: what the page renders with,
86
+ * and whether `--viewport` / `--color-scheme` set it or it is the system's.
87
+ * The color scheme is the `prefers-color-scheme` the page sees, not its theme.
88
+ *
89
+ * @param metadata - Session metadata (the start options)
90
+ * @param pageState - Page state (what the page reported)
91
+ * @returns Key-value pairs (none for what is unknown)
92
+ */
93
+ export function appearanceLines(metadata, pageState) {
94
+ const viewport = pageState.viewport ?? metadata.viewport;
95
+ const scheme = pageState.colorScheme ?? metadata.colorScheme;
96
+ return [
97
+ ...(viewport
98
+ ? [
99
+ [
100
+ 'Viewport',
101
+ `${viewport.width}×${viewport.height}${metadata.viewport ? ` (--viewport ${metadata.viewport.width}x${metadata.viewport.height})` : ''}`,
102
+ ],
103
+ ]
104
+ : []),
105
+ ...(scheme
106
+ ? [
107
+ ['Color scheme', colorSchemeLabel(scheme, metadata.colorScheme !== undefined)],
108
+ ]
109
+ : []),
110
+ ];
111
+ }
78
112
  /**
79
113
  * Convert status data to JSON format
80
114
  */
@@ -98,13 +132,15 @@ export function formatStatusAsJson(metadata, pid) {
98
132
  return {
99
133
  active: true,
100
134
  bdgPid: pid,
101
- chromePid: metadata.chromePid,
135
+ chromePid: metadata.chromePid !== undefined && metadata.chromePid > 0 ? metadata.chromePid : null,
102
136
  ...(metadata.chromePid ? { chromeAlive } : { externalChrome: true }),
103
137
  startTime: metadata.startTime,
104
138
  duration: duration.durationMs,
105
139
  durationFormatted: duration.formatted,
106
140
  port: metadata.port,
107
141
  ...(metadata.autoStopAt && { autoStopAt: new Date(metadata.autoStopAt).toISOString() }),
142
+ ...(metadata.viewport && { viewport: metadata.viewport }),
143
+ ...(metadata.colorScheme && { colorScheme: metadata.colorScheme }),
108
144
  targetId: metadata.targetId,
109
145
  webSocketDebuggerUrl: metadata.webSocketDebuggerUrl,
110
146
  telemetry: metadata.activeTelemetry ?? ['network', 'console', 'dom'],
@@ -120,13 +156,14 @@ export function formatNoSessionMessage(data = { active: false }) {
120
156
  return fmt
121
157
  .text(`Session starting: ${data.starting.url} (${seconds}s so far)`)
122
158
  .blank()
123
- .text('Commands work once "bdg <url>" returns.')
159
+ .text(`Commands work once "${sessionCommand('bdg <url>', data.session ?? null)}" returns.`)
124
160
  .build();
125
161
  }
126
162
  if (data.ending) {
127
163
  return fmt.text('The session is ending (its Chrome is being closed)').build();
128
164
  }
129
- fmt.text('No active session found');
165
+ const session = data.session ?? null;
166
+ fmt.text(noActiveSessionMessage(session));
130
167
  if (data.lastSession)
131
168
  fmt.text(lastSessionEndText(data.lastSession));
132
169
  if (data.orphanedChromePid) {
@@ -134,10 +171,10 @@ export function formatNoSessionMessage(data = { active: false }) {
134
171
  }
135
172
  return fmt
136
173
  .hints('Suggestions:', [
137
- 'Start a new session: bdg <url>',
174
+ `Start a new session: ${sessionCommand('bdg <url>', session)}`,
138
175
  data.orphanedChromePid
139
- ? 'Close that Chrome: bdg cleanup'
140
- : 'Clean up after a crash: bdg cleanup',
176
+ ? `Close that Chrome: ${sessionCommand('bdg cleanup', session)}`
177
+ : `Clean up after a crash: ${sessionCommand('bdg cleanup', session)}`,
141
178
  ])
142
179
  .build();
143
180
  }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Human output of the network requests a DOM action triggered.
3
+ */
4
+ import type { TriggeredRequest } from '../../ipc/protocol/domTypes.js';
5
+ /** Requests listed in human output (JSON lists up to 50) */
6
+ export declare const MAX_TRIGGERED_REQUESTS_SHOWN = 10;
7
+ /**
8
+ * Title of the list, with how many requests there were in all (the listed
9
+ * rows, the "... and N more" note and the assets line add up to it).
10
+ *
11
+ * @param requests - Triggered requests in the result
12
+ * @param omitted - Requests the result left out
13
+ * @returns e.g. "Requests during the action (18):"
14
+ */
15
+ export declare function formatTriggeredRequestsTitle(requests: TriggeredRequest[], omitted?: number): string;
16
+ /**
17
+ * One request as a line, e.g. `POST 127.0.0.1:8080/api/save → 200 (85ms)`,
18
+ * or `GET 127.0.0.1:8080/events → 200 (loading)` while its body still loads.
19
+ *
20
+ * @param request - Triggered request
21
+ * @returns Line text
22
+ */
23
+ export declare function formatTriggeredRequest(request: TriggeredRequest): string;
24
+ /**
25
+ * Lines listing the triggered requests: the first
26
+ * {@link MAX_TRIGGERED_REQUESTS_SHOWN} notable ones (documents, XHR, fetch,
27
+ * WebSocket, failures; see {@link isNotableRequest}), how many more there
28
+ * are and where to find them (JSON, or the network list when JSON left some
29
+ * out too), then one line counting the static assets that loaded.
30
+ *
31
+ * @param requests - Triggered requests, in start order
32
+ * @param omitted - Requests the result already left out
33
+ * @returns Lines (empty when there are none)
34
+ */
35
+ export declare function formatTriggeredRequestLines(requests: TriggeredRequest[], omitted?: number): string[];
36
+ //# sourceMappingURL=triggeredRequests.d.ts.map
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Human output of the network requests a DOM action triggered.
3
+ */
4
+ import { assetTypeNames, isNotableRequest } from '../../telemetry/requestKinds.js';
5
+ import { formatRequestStatus } from './requestStatus.js';
6
+ import { formatDuration, truncateUrl } from '../formatting.js';
7
+ import { assetRequestsNote, moreMatchesNote, moreRequestsNote, triggeredRequestsTitle, } from '../messages/commands.js';
8
+ /** Requests listed in human output (JSON lists up to 50) */
9
+ export const MAX_TRIGGERED_REQUESTS_SHOWN = 10;
10
+ /** Longest URL shown before it is shortened */
11
+ const URL_MAX_LENGTH = 60;
12
+ /**
13
+ * Title of the list, with how many requests there were in all (the listed
14
+ * rows, the "... and N more" note and the assets line add up to it).
15
+ *
16
+ * @param requests - Triggered requests in the result
17
+ * @param omitted - Requests the result left out
18
+ * @returns e.g. "Requests during the action (18):"
19
+ */
20
+ export function formatTriggeredRequestsTitle(requests, omitted = 0) {
21
+ return triggeredRequestsTitle(requests.length + omitted);
22
+ }
23
+ /**
24
+ * One request as a line, e.g. `POST 127.0.0.1:8080/api/save → 200 (85ms)`,
25
+ * or `GET 127.0.0.1:8080/events → 200 (loading)` while its body still loads.
26
+ *
27
+ * @param request - Triggered request
28
+ * @returns Line text
29
+ */
30
+ export function formatTriggeredRequest(request) {
31
+ const httpStatus = request.failed ? 0 : request.status;
32
+ const status = formatRequestStatus({
33
+ ...(httpStatus !== undefined && { status: httpStatus }),
34
+ ...(request.errorText !== undefined && { errorText: request.errorText }),
35
+ });
36
+ const duration = request.loading
37
+ ? ' (loading)'
38
+ : request.durationMs === undefined
39
+ ? ''
40
+ : ` (${formatDuration(request.durationMs)})`;
41
+ return `${request.method} ${truncateUrl(request.url, URL_MAX_LENGTH)} → ${status}${duration}`;
42
+ }
43
+ /**
44
+ * Lines listing the triggered requests: the first
45
+ * {@link MAX_TRIGGERED_REQUESTS_SHOWN} notable ones (documents, XHR, fetch,
46
+ * WebSocket, failures; see {@link isNotableRequest}), how many more there
47
+ * are and where to find them (JSON, or the network list when JSON left some
48
+ * out too), then one line counting the static assets that loaded.
49
+ *
50
+ * @param requests - Triggered requests, in start order
51
+ * @param omitted - Requests the result already left out
52
+ * @returns Lines (empty when there are none)
53
+ */
54
+ export function formatTriggeredRequestLines(requests, omitted = 0) {
55
+ const notable = requests.filter(isNotableRequest);
56
+ const assets = requests.filter((request) => !isNotableRequest(request));
57
+ const lines = notable.slice(0, MAX_TRIGGERED_REQUESTS_SHOWN).map(formatTriggeredRequest);
58
+ const hidden = notable.length - lines.length + omitted;
59
+ if (hidden > 0)
60
+ lines.push(omitted > 0 ? moreRequestsNote(hidden) : moreMatchesNote(hidden));
61
+ if (assets.length > 0)
62
+ lines.push(assetRequestsNote(assets.length, assetTypeNames(assets)));
63
+ return lines;
64
+ }
65
+ //# sourceMappingURL=triggeredRequests.js.map
@@ -61,6 +61,16 @@ export declare function escapeControlChars(text: string): string;
61
61
  export declare function joinLines(...lines: Array<string | null | undefined | false>): string;
62
62
  export declare function section(title: string, content: string[], indent?: number): string;
63
63
  export declare function truncateText(text: string, maxLines?: number): string;
64
+ /**
65
+ * A URL for one line: host and path without the scheme (`www.example.com`
66
+ * for the root), cut in the middle when too long, keeping the host, the
67
+ * start of the path and the end of the path and query, where requests to
68
+ * one API differ (`api.example.com/v1/users/…/orders?page=2`).
69
+ *
70
+ * @param url - URL
71
+ * @param maxLength - Maximum length
72
+ * @returns Shortened URL; non-web URLs (data:, blob:) cut at the end
73
+ */
64
74
  export declare function truncateUrl(url: string, maxLength?: number): string;
65
75
  export declare function pluralize(count: number, singular: string, plural?: string): string;
66
76
  export declare function formatDuration(ms: number): string;
@@ -138,36 +138,45 @@ export function truncateText(text, maxLines = 3) {
138
138
  const hiddenCount = lines.length - maxLines;
139
139
  return `${truncated}\n ... (${hiddenCount} more lines)`;
140
140
  }
141
+ /**
142
+ * A URL for one line: host and path without the scheme (`www.example.com`
143
+ * for the root), cut in the middle when too long, keeping the host, the
144
+ * start of the path and the end of the path and query, where requests to
145
+ * one API differ (`api.example.com/v1/users/…/orders?page=2`).
146
+ *
147
+ * @param url - URL
148
+ * @param maxLength - Maximum length
149
+ * @returns Shortened URL; non-web URLs (data:, blob:) cut at the end
150
+ */
141
151
  export function truncateUrl(url, maxLength = 60) {
142
152
  const parsed = safeParseUrl(url);
143
153
  if (!parsed || !WEB_PROTOCOLS.has(parsed.protocol)) {
144
154
  return truncateEnd(url, maxLength);
145
155
  }
146
156
  const host = parsed.host;
147
- const path = parsed.pathname.substring(1);
148
- const full = `${host}${path ? `/${path}` : ''}`;
149
- if (`${full}${parsed.search}`.length <= maxLength)
150
- return `${full}${parsed.search}`;
151
- if (!parsed.search)
152
- return shortenPath(host, path, maxLength);
153
- const room = maxLength - full.length;
154
- if (room >= MIN_QUERY_SHOWN)
155
- return `${full}${cutQuery(parsed.search, room)}`;
156
- const query = cutQuery(parsed.search, MIN_QUERY_SHOWN);
157
- return `${shortenPath(host, path, maxLength - query.length)}${query}`;
157
+ const rest = `${parsed.pathname.substring(1)}${parsed.search}`;
158
+ const shown = parsed.pathname.length > 1 ? `${host}/${rest}` : `${host}${parsed.search}`;
159
+ if (shown.length <= maxLength)
160
+ return shown;
161
+ const room = maxLength - host.length - 2;
162
+ if (room < MIN_URL_END_SHOWN)
163
+ return cutMiddle(shown, maxLength);
164
+ const start = Math.floor(room / 3);
165
+ return `${host}/${rest.substring(0, start)}…${rest.substring(rest.length - (room - start))}`;
158
166
  }
167
+ /** Characters of path and query a shortened URL keeps at least besides its host */
168
+ const MIN_URL_END_SHOWN = 12;
159
169
  /**
160
- * A query string cut to a length, marked with "…" when cut.
170
+ * Cut text in the middle, marking the cut with "…".
161
171
  *
162
- * @param search - Query string including "?"
163
- * @param length - Maximum length
164
- * @returns The query, or its start followed by "…"
172
+ * @param text - Text
173
+ * @param maxLength - Maximum length
174
+ * @returns Start and end of the text around "…"
165
175
  */
166
- function cutQuery(search, length) {
167
- return search.length <= length ? search : `${search.substring(0, length - 1)}…`;
176
+ function cutMiddle(text, maxLength) {
177
+ const head = Math.ceil((maxLength - 1) / 2);
178
+ return `${text.substring(0, head)}…${text.substring(text.length - (maxLength - 1 - head))}`;
168
179
  }
169
- /** Characters of a long query string kept, so similar requests stay distinguishable */
170
- const MIN_QUERY_SHOWN = 12;
171
180
  /** Protocols whose URLs are shown as host/path (others, like data: or blob:, verbatim) */
172
181
  const WEB_PROTOCOLS = new Set(['http:', 'https:', 'ws:', 'wss:']);
173
182
  /**
@@ -180,23 +189,6 @@ const WEB_PROTOCOLS = new Set(['http:', 'https:', 'ws:', 'wss:']);
180
189
  function truncateEnd(text, maxLength) {
181
190
  return text.length > maxLength ? text.substring(0, maxLength - 3) + '...' : text;
182
191
  }
183
- /**
184
- * Shorten a long host/path by eliding its middle segments.
185
- *
186
- * @param host - Host (with port)
187
- * @param path - Path without the leading slash
188
- * @param maxLength - Maximum length
189
- * @returns e.g. "example.com/docs/.../page"
190
- */
191
- function shortenPath(host, path, maxLength) {
192
- const parts = path.split('/');
193
- const first = parts[0];
194
- const last = parts[parts.length - 1];
195
- if (parts.length <= 2 || !first || !last)
196
- return truncateEnd(`${host}/${path}`, maxLength);
197
- const elided = `${host}/${first}/.../${last}`;
198
- return elided.length <= maxLength ? elided : `${host}/${first}/.../${last.substring(0, 8)}`;
199
- }
200
192
  export function pluralize(count, singular, plural) {
201
193
  const word = count === 1 ? singular : (plural ?? singular + 's');
202
194
  return `${count} ${word}`;
@@ -161,4 +161,13 @@ export declare function chromeBinaryOverrideIsDirectory(path: string, source: st
161
161
  * @returns Multi-line formatted error message with troubleshooting steps
162
162
  */
163
163
  export declare function portInUseError(port: number): string;
164
+ /**
165
+ * Warning when bdg's Chrome preferences (password manager and leak check
166
+ * off, etc.) could not be written into the profile.
167
+ *
168
+ * @param file - Preferences file
169
+ * @param reason - Why
170
+ * @returns Message
171
+ */
172
+ export declare function chromePrefsNotAppliedMessage(file: string, reason: string): string;
164
173
  //# sourceMappingURL=chrome.d.ts.map
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { getChromeDiagnostics } from '../../connection/diagnostics.js';
7
7
  import { pluralize, joinLines } from '../formatting.js';
8
+ import { sessionCommand } from './sessionCommand.js';
8
9
  /**
9
10
  * Format a structured Chrome-related notice into a user-facing log line.
10
11
  *
@@ -52,7 +53,7 @@ export function formatChromeIssue(issue) {
52
53
  ? chromeLaunchFailedError(reason)
53
54
  : `Chrome failed to launch`;
54
55
  const diagnostics = getFormattedDiagnostics();
55
- return joinLines(header, '', 'Possible causes:', ` - Port ${port} conflict (check: lsof -ti:${port})`, ` - Chrome binary not found`, ` - Insufficient permissions`, ` - Chrome crashed on startup`, '', ...diagnostics, '', 'Try:', ` - bdg cleanup`, ` - See what uses the port: lsof -i :${port}`, ` - Use different port: bdg <url> --port ${port + 1}`, ` - In a container where Chrome's sandbox fails: BDG_NO_SANDBOX=1 bdg <url>`);
56
+ return joinLines(header, '', 'Possible causes:', ` - Port ${port} conflict (check: lsof -ti:${port})`, ` - Chrome binary not found`, ` - Insufficient permissions`, ` - Chrome crashed on startup`, '', ...diagnostics, '', 'Try:', ` - ${sessionCommand('bdg cleanup')}`, ` - See what uses the port: lsof -i :${port}`, ` - Use different port: ${sessionCommand(`bdg <url> --port ${port + 1}`)}`, ` - In a container where Chrome's sandbox fails: BDG_NO_SANDBOX=1 ${sessionCommand('bdg <url>')}`);
56
57
  }
57
58
  case 'CHROME_EXITED_DURING_STARTUP':
58
59
  return chromeExitedDuringStartupError(ctx['exitCode'], ctx['output'] ?? [], ctx['userDataDir'], ctx['profileInUse'] === true);
@@ -90,7 +91,7 @@ export function formatChromeIssue(issue) {
90
91
  */
91
92
  export function chromeExitedDuringStartupError(exitCode, output, userDataDir, profileInUse) {
92
93
  if (profileInUse) {
93
- return joinLines(`The Chrome profile ${userDataDir} is in use by another Chrome`, 'Close that Chrome, or use another profile directory: bdg <url> -u ./other-profile');
94
+ return joinLines(`The Chrome profile ${userDataDir} is in use by another Chrome`, `Close that Chrome, or use another profile directory: ${sessionCommand('bdg <url> -u ./other-profile')}`);
94
95
  }
95
96
  return joinLines(`Chrome exited during startup (exit code ${exitCode ?? 'none'})`, ...(output.length > 0 ? ['Chrome said:', ...output.map((line) => ` ${line}`)] : []), 'Check --chrome-flags and BDG_CHROME_FLAGS (an unknown flag or value can stop Chrome)');
96
97
  }
@@ -197,8 +198,8 @@ export function chromeExternalSkipTerminationMessage() {
197
198
  * @returns Formatted error message with diagnostics and troubleshooting steps
198
199
  */
199
200
  export function noPageTargetFoundError(port, availableTargets) {
200
- return joinLines(`Chrome started but opened no page to attach to (port ${port})`, 'Retry: bdg <url>. If it keeps failing, another program may use the port (lsof -i :' +
201
- `${port}) or a crashed session may be left over: bdg cleanup && bdg <url>`, ...(availableTargets ? ['', `Chrome targets:\n${availableTargets}`] : []));
201
+ return joinLines(`Chrome started but opened no page to attach to (port ${port})`, `Retry: ${sessionCommand('bdg <url>')}. If it keeps failing, another program may use the port (lsof -i :` +
202
+ `${port}) or a crashed session may be left over: ${sessionCommand('bdg cleanup')} && ${sessionCommand('bdg <url>')}`, ...(availableTargets ? ['', `Chrome targets:\n${availableTargets}`] : []));
202
203
  }
203
204
  /**
204
205
  * Generate preferences file not found error.
@@ -276,6 +277,17 @@ export function chromeBinaryOverrideIsDirectory(path, source) {
276
277
  * @returns Multi-line formatted error message with troubleshooting steps
277
278
  */
278
279
  export function portInUseError(port) {
279
- return joinLines(`Port ${port} is already in use.\n`, 'Another program (or a Chrome left from a previous session) is listening on it.\n', 'Try:', ` - Use a different port: bdg <url> --port ${port + 1}`, ` - If a bdg session is stuck: bdg cleanup --force (stops bdg's own daemon and Chrome only)`, ` - See what uses the port: lsof -i :${port}`);
280
+ return joinLines(`Port ${port} is already in use.\n`, 'Another program (or a Chrome left from a previous session) is listening on it.\n', 'Try:', ` - Use a different port: ${sessionCommand(`bdg <url> --port ${port + 1}`)}`, ` - If a bdg session holds it: find it with bdg sessions, then end that one: bdg stop --session <name> (bdg cleanup --force --session <name> if it is stuck)`, ` - See what uses the port: lsof -i :${port}`);
281
+ }
282
+ /**
283
+ * Warning when bdg's Chrome preferences (password manager and leak check
284
+ * off, etc.) could not be written into the profile.
285
+ *
286
+ * @param file - Preferences file
287
+ * @param reason - Why
288
+ * @returns Message
289
+ */
290
+ export function chromePrefsNotAppliedMessage(file, reason) {
291
+ return `Warning: Chrome preferences not applied to ${file} (${reason}); password manager bubbles may capture clicks`;
280
292
  }
281
293
  //# sourceMappingURL=chrome.js.map