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,47 @@
1
+ /**
2
+ * Chrome profile preferences writer.
3
+ *
4
+ * Chrome reads `<user-data-dir>/Default/Preferences` as nested JSON and looks
5
+ * preferences up by path (`profile.password_manager_enabled` is
6
+ * `{"profile": {"password_manager_enabled": ...}}`). bdg's preferences use
7
+ * dotted names, so they are expanded into that structure and deep-merged into
8
+ * the existing file: persistent profiles reused across sessions get them too,
9
+ * and everything else Chrome stored there is kept.
10
+ */
11
+ import type { Logger } from '../types.js';
12
+ /** JSON object as stored in the Preferences file */
13
+ type PrefsObject = Record<string, unknown>;
14
+ /**
15
+ * Merge preferences into an existing Preferences object.
16
+ *
17
+ * Dotted names become nested paths, and a literal dotted top-level key (as
18
+ * earlier bdg versions wrote, which Chrome ignored) is removed.
19
+ *
20
+ * @param existing - Current Preferences content
21
+ * @param prefs - Preferences to apply, dotted or nested
22
+ * @returns Merged Preferences (a new object; `existing` is not modified)
23
+ */
24
+ export declare function mergePreferences(existing: PrefsObject, prefs: PrefsObject): PrefsObject;
25
+ /**
26
+ * Whether a running Chrome has the profile open, judged by its
27
+ * `SingletonLock` symlink (`<host>-<pid>`, macOS and Linux).
28
+ *
29
+ * @param userDataDir - Chrome user data directory
30
+ * @returns True if the lock names a live process on this host
31
+ */
32
+ export declare function profileInUse(userDataDir: string): boolean;
33
+ /**
34
+ * Apply preferences to the default profile in a Chrome user data directory.
35
+ *
36
+ * Failures are logged (visible in daemon.log), not thrown: Chrome still
37
+ * starts, only without them. An unreadable Preferences file and a profile
38
+ * that a running Chrome has open are left alone, and the file is not
39
+ * rewritten when nothing changes.
40
+ *
41
+ * @param userDataDir - Chrome user data directory
42
+ * @param prefs - Preferences to apply, dotted or nested
43
+ * @param logger - Logger for failures
44
+ */
45
+ export declare function writeProfilePreferences(userDataDir: string, prefs: PrefsObject, logger: Logger): void;
46
+ export {};
47
+ //# sourceMappingURL=profilePreferences.d.ts.map
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Chrome profile preferences writer.
3
+ *
4
+ * Chrome reads `<user-data-dir>/Default/Preferences` as nested JSON and looks
5
+ * preferences up by path (`profile.password_manager_enabled` is
6
+ * `{"profile": {"password_manager_enabled": ...}}`). bdg's preferences use
7
+ * dotted names, so they are expanded into that structure and deep-merged into
8
+ * the existing file: persistent profiles reused across sessions get them too,
9
+ * and everything else Chrome stored there is kept.
10
+ */
11
+ import * as fs from 'fs';
12
+ import * as os from 'os';
13
+ import * as path from 'path';
14
+ import { chromePrefsNotAppliedMessage } from '../../ui/messages/chrome.js';
15
+ import { getErrorMessage } from '../../utils/errors.js';
16
+ import { isProcessAlive } from '../../utils/process.js';
17
+ /**
18
+ * Whether a value is a plain JSON object (not an array or null).
19
+ *
20
+ * @param value - Value to check
21
+ * @returns True for objects that can be merged into
22
+ */
23
+ function isPrefsObject(value) {
24
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
25
+ }
26
+ /**
27
+ * Set a preference at a nested path, merging objects with what is there.
28
+ *
29
+ * @param target - Preferences object to modify
30
+ * @param keys - Path segments, e.g. `['profile', 'exit_type']`
31
+ * @param value - Value to set
32
+ */
33
+ function setAtPath(target, keys, value) {
34
+ const [key, ...rest] = keys;
35
+ if (key === undefined)
36
+ return;
37
+ const current = target[key];
38
+ if (rest.length > 0) {
39
+ const child = isPrefsObject(current) ? current : {};
40
+ target[key] = child;
41
+ setAtPath(child, rest, value);
42
+ return;
43
+ }
44
+ if (isPrefsObject(current) && isPrefsObject(value)) {
45
+ for (const [childKey, childValue] of Object.entries(value)) {
46
+ setAtPath(current, [childKey], childValue);
47
+ }
48
+ return;
49
+ }
50
+ target[key] = value;
51
+ }
52
+ /**
53
+ * Merge preferences into an existing Preferences object.
54
+ *
55
+ * Dotted names become nested paths, and a literal dotted top-level key (as
56
+ * earlier bdg versions wrote, which Chrome ignored) is removed.
57
+ *
58
+ * @param existing - Current Preferences content
59
+ * @param prefs - Preferences to apply, dotted or nested
60
+ * @returns Merged Preferences (a new object; `existing` is not modified)
61
+ */
62
+ export function mergePreferences(existing, prefs) {
63
+ const merged = structuredClone(existing);
64
+ for (const [name, value] of Object.entries(prefs)) {
65
+ if (name.includes('.'))
66
+ delete merged[name];
67
+ setAtPath(merged, name.split('.'), value);
68
+ }
69
+ return merged;
70
+ }
71
+ /**
72
+ * Read the profile's Preferences file.
73
+ *
74
+ * @param file - Preferences file path
75
+ * @returns Its content, `{}` if missing
76
+ * @throws Error if it is not valid JSON or not a JSON object
77
+ */
78
+ function readPreferencesFile(file) {
79
+ if (!fs.existsSync(file))
80
+ return {};
81
+ const parsed = JSON.parse(fs.readFileSync(file, 'utf8'));
82
+ if (!isPrefsObject(parsed))
83
+ throw new Error('not a JSON object');
84
+ return parsed;
85
+ }
86
+ /**
87
+ * Whether a running Chrome has the profile open, judged by its
88
+ * `SingletonLock` symlink (`<host>-<pid>`, macOS and Linux).
89
+ *
90
+ * @param userDataDir - Chrome user data directory
91
+ * @returns True if the lock names a live process on this host
92
+ */
93
+ export function profileInUse(userDataDir) {
94
+ let target;
95
+ try {
96
+ target = fs.readlinkSync(path.join(userDataDir, 'SingletonLock'));
97
+ }
98
+ catch {
99
+ return false;
100
+ }
101
+ const separator = target.lastIndexOf('-');
102
+ const pid = Number(target.slice(separator + 1));
103
+ return (target.slice(0, separator) === os.hostname() && Number.isInteger(pid) && isProcessAlive(pid));
104
+ }
105
+ /**
106
+ * Replace a file atomically: write a temporary file next to it, then rename.
107
+ *
108
+ * @param file - File to replace
109
+ * @param content - New content
110
+ */
111
+ function writeFileAtomic(file, content) {
112
+ const temp = `${file}.bdg-${process.pid}.tmp`;
113
+ try {
114
+ fs.writeFileSync(temp, content, 'utf8');
115
+ fs.renameSync(temp, file);
116
+ }
117
+ finally {
118
+ fs.rmSync(temp, { force: true });
119
+ }
120
+ }
121
+ /**
122
+ * Apply preferences to the default profile in a Chrome user data directory.
123
+ *
124
+ * Failures are logged (visible in daemon.log), not thrown: Chrome still
125
+ * starts, only without them. An unreadable Preferences file and a profile
126
+ * that a running Chrome has open are left alone, and the file is not
127
+ * rewritten when nothing changes.
128
+ *
129
+ * @param userDataDir - Chrome user data directory
130
+ * @param prefs - Preferences to apply, dotted or nested
131
+ * @param logger - Logger for failures
132
+ */
133
+ export function writeProfilePreferences(userDataDir, prefs, logger) {
134
+ const file = path.join(userDataDir, 'Default', 'Preferences');
135
+ if (profileInUse(userDataDir)) {
136
+ logger.info(chromePrefsNotAppliedMessage(file, 'the profile is in use by a running Chrome'));
137
+ return;
138
+ }
139
+ try {
140
+ const existing = readPreferencesFile(file);
141
+ const content = JSON.stringify(mergePreferences(existing, prefs));
142
+ if (content === JSON.stringify(existing))
143
+ return;
144
+ fs.mkdirSync(path.dirname(file), { recursive: true });
145
+ writeFileAtomic(file, content);
146
+ }
147
+ catch (error) {
148
+ logger.info(chromePrefsNotAppliedMessage(file, getErrorMessage(error)));
149
+ }
150
+ }
151
+ //# sourceMappingURL=profilePreferences.js.map
@@ -7,7 +7,11 @@ import type { Options as ChromeLaunchOptions } from 'chrome-launcher';
7
7
  export interface LaunchOptions extends Pick<ChromeLaunchOptions, 'logLevel' | 'connectionPollInterval' | 'maxConnectionRetries' | 'portStrictMode' | 'envVars' | 'handleSIGINT' | 'ignoreDefaultFlags' | 'chromeFlags' | 'chromePath'> {
8
8
  /** Remote debugging port (defaults to 9222 when omitted) */
9
9
  port?: number;
10
- /** Directory for Chrome profile data. Falls back to persistent ~/.bdg/chrome-profile directory */
10
+ /**
11
+ * Directory for Chrome profile data, chosen by the user: bdg's default
12
+ * preferences are not written into it. Falls back to the bdg-managed
13
+ * persistent profile in the session directory (~/.bdg/chrome-profile)
14
+ */
11
15
  userDataDir?: string | undefined;
12
16
  /** Base directory for creating user data dir (defaults to OS temp dir, injectable for testing) */
13
17
  baseDir?: string | undefined;
@@ -23,7 +27,7 @@ export interface LaunchOptions extends Pick<ChromeLaunchOptions, 'logLevel' | 'c
23
27
  prefsFile?: string | undefined;
24
28
  /** Override Chrome binary detection with an explicit path */
25
29
  chromePath?: string;
26
- /** bdg session directory, recorded as a marker flag on the Chrome command line */
30
+ /** bdg session directory: recorded as a marker flag on the Chrome command line, and holds the default profile */
27
31
  sessionDir?: string | undefined;
28
32
  }
29
33
  /**
@@ -46,4 +50,19 @@ export interface LaunchOptions extends Pick<ChromeLaunchOptions, 'logLevel' | 'c
46
50
  * Uses chrome-launcher for cross-platform Chrome detection and launching.
47
51
  */
48
52
  export declare function launchChrome(options?: LaunchOptions): Promise<LaunchedChrome>;
53
+ /**
54
+ * Preferences for the launched profile: bdg's defaults (no translate prompt,
55
+ * no password manager or leak check, whose bubbles capture input) for
56
+ * profiles bdg manages, with the caller's preferences on top. A profile the
57
+ * user chose (`--user-data-dir`) gets only preferences the caller passed.
58
+ *
59
+ * File-based preferences take precedence over inline preferences because
60
+ * files allow for complex, reusable configurations that can be version
61
+ * controlled and shared across team members or CI environments.
62
+ *
63
+ * @param options - Launch options containing prefs or prefsFile
64
+ * @returns Merged preferences (empty when there is nothing to apply)
65
+ * @throws ChromeLaunchError if prefs file cannot be read or parsed, or prefs are not JSON
66
+ */
67
+ export declare function resolveChromePrefs(options: LaunchOptions): Record<string, unknown>;
49
68
  //# sourceMappingURL=launcher.d.ts.map
@@ -6,10 +6,12 @@ import { BDG_CHROME_PREFS, DEFAULT_CDP_PORT, CHROME_PROFILE_DIR, DEFAULT_CHROME_
6
6
  import { getErrorMessage } from '../utils/errors.js';
7
7
  import { filterDefined } from '../utils/objects.js';
8
8
  import { isProcessAlive } from '../utils/process.js';
9
+ import { verifyLaunchedChrome } from './chromeIdentity.js';
9
10
  import { ChromeLaunchError } from './errors.js';
10
11
  import { resolveChromeBinary } from './launcher/binaryResolver.js';
11
12
  import { buildChromeFlags } from './launcher/flagsBuilder.js';
12
13
  import { loadChromePrefs, ensureJSONCompatiblePrefs } from './launcher/preferencesLoader.js';
14
+ import { writeProfilePreferences } from './launcher/profilePreferences.js';
13
15
  import { reservePort } from './portReservation.js';
14
16
  import { markStartupLogs, watchStartupExit } from './startupExit.js';
15
17
  /**
@@ -57,7 +59,7 @@ export async function launchChrome(options = {}) {
57
59
  }
58
60
  const reservation = await reservePort(port);
59
61
  reservation.release();
60
- const userDataDir = options.userDataDir ?? getPersistentUserDataDir(options.baseDir);
62
+ const userDataDir = options.userDataDir ?? getPersistentUserDataDir(options.baseDir ?? options.sessionDir);
61
63
  if (!fs.existsSync(userDataDir)) {
62
64
  try {
63
65
  fs.mkdirSync(userDataDir, { recursive: true });
@@ -74,9 +76,11 @@ export async function launchChrome(options = {}) {
74
76
  }
75
77
  logger.info(`Launching Chrome on port ${port}...`);
76
78
  logger.debug(`User data directory: ${userDataDir}`);
77
- const chromeOptions = buildChromeOptions(options);
79
+ applyProfilePreferences(userDataDir, options, logger);
80
+ const chromeOptions = buildChromeOptions({ ...options, port });
78
81
  const launcher = new chromeLauncher.Launcher(chromeOptions);
79
- const startup = watchStartupExit(() => launcher.chromeProcess, markStartupLogs(userDataDir), userDataDir);
82
+ const logs = markStartupLogs(userDataDir);
83
+ const startup = watchStartupExit(() => launcher.chromeProcess, logs, userDataDir);
80
84
  try {
81
85
  const launchStart = Date.now();
82
86
  logger.info('Waiting for Chrome to be ready...');
@@ -96,10 +100,11 @@ export async function launchChrome(options = {}) {
96
100
  },
97
101
  });
98
102
  }
103
+ await verifyLaunchedChrome({ logs, port, pid: chromeProcessPid });
99
104
  logger.info(`Chrome launched successfully (PID: ${chromeProcessPid}, ${launchDurationMs}ms)`);
100
105
  return {
101
106
  pid: chromeProcessPid,
102
- port: launcher.port ?? port,
107
+ port,
103
108
  userDataDir: launcher.userDataDir,
104
109
  kill: async () => {
105
110
  return Promise.resolve().then(() => {
@@ -128,7 +133,9 @@ export async function launchChrome(options = {}) {
128
133
  /**
129
134
  * Get the default persistent user-data-dir path.
130
135
  *
131
- * Uses the session directory ($BDG_SESSION_DIR) to store Chrome profile data,
136
+ * Uses the session directory (`~/.bdg`, `$BDG_SESSION_DIR`, or
137
+ * `<base>/sessions/<name>` for a named session, passed as `sessionDir`) to
138
+ * store Chrome profile data,
132
139
  * ensuring each session has its own isolated Chrome profile. This prevents
133
140
  * SingletonLock conflicts when multiple agents run concurrently.
134
141
  *
@@ -136,7 +143,7 @@ export async function launchChrome(options = {}) {
136
143
  * For shared login state across sessions, use --user-data-dir to specify a
137
144
  * shared location explicitly.
138
145
  *
139
- * @param baseDir - Optional base directory (defaults to session dir). Allows injection for testing or custom locations.
146
+ * @param baseDir - Optional base directory (defaults to `~/.bdg` or `$BDG_SESSION_DIR`). Allows injection for testing or custom locations.
140
147
  * @returns Absolute path to session-isolated user-data-dir
141
148
  * @throws Error if user data directory cannot be created due to permission issues
142
149
  */
@@ -168,32 +175,52 @@ function getPersistentUserDataDir(baseDir) {
168
175
  return userDataDir;
169
176
  }
170
177
  /**
171
- * Load Chrome preferences from options.
178
+ * Preferences for the launched profile: bdg's defaults (no translate prompt,
179
+ * no password manager or leak check, whose bubbles capture input) for
180
+ * profiles bdg manages, with the caller's preferences on top. A profile the
181
+ * user chose (`--user-data-dir`) gets only preferences the caller passed.
172
182
  *
173
183
  * File-based preferences take precedence over inline preferences because
174
184
  * files allow for complex, reusable configurations that can be version
175
185
  * controlled and shared across team members or CI environments.
176
186
  *
177
187
  * @param options - Launch options containing prefs or prefsFile
178
- * @returns Chrome preferences object or undefined if no preferences specified
179
- * @throws ChromeLaunchError if prefs file cannot be read, parsed, or doesn't exist
188
+ * @returns Merged preferences (empty when there is nothing to apply)
189
+ * @throws ChromeLaunchError if prefs file cannot be read or parsed, or prefs are not JSON
180
190
  */
191
+ export function resolveChromePrefs(options) {
192
+ const defaults = options.userDataDir === undefined ? BDG_CHROME_PREFS : {};
193
+ const prefs = { ...defaults, ...loadChromePrefs(options) };
194
+ ensureJSONCompatiblePrefs(prefs);
195
+ return prefs;
196
+ }
197
+ /**
198
+ * Write the launch preferences into the profile, if there are any.
199
+ *
200
+ * @param userDataDir - Chrome user data directory
201
+ * @param options - Launch options
202
+ * @param logger - Logger for failures
203
+ * @throws ChromeLaunchError if prefs file cannot be read or parsed, or prefs are not JSON
204
+ */
205
+ function applyProfilePreferences(userDataDir, options, logger) {
206
+ const prefs = resolveChromePrefs(options);
207
+ if (Object.keys(prefs).length > 0)
208
+ writeProfilePreferences(userDataDir, prefs, logger);
209
+ }
181
210
  /**
182
211
  * Build chrome-launcher options from bdg launch options.
183
212
  *
184
213
  * Maps LaunchOptions to chrome-launcher API format using a clean utility approach
185
- * that filters out undefined values automatically. User preferences override bdg
186
- * defaults to allow customization while maintaining sensible base configuration.
214
+ * that filters out undefined values automatically. Preferences are not passed:
215
+ * chrome-launcher would replace whole nested sections of an existing profile's
216
+ * Preferences, so `writeProfilePreferences` merges them instead.
187
217
  *
188
218
  * @param options - bdg launch options to convert
189
219
  * @returns chrome-launcher compatible options object
190
- * @throws ChromeLaunchError if preference loading fails
191
220
  */
192
221
  function buildChromeOptions(options) {
193
- const userPrefs = loadChromePrefs(options);
194
- const userDataDir = options.userDataDir ?? getPersistentUserDataDir(options.baseDir);
222
+ const userDataDir = options.userDataDir ?? getPersistentUserDataDir(options.baseDir ?? options.sessionDir);
195
223
  const chromePathOverride = resolveChromeBinary(options);
196
- const mergedPrefs = userPrefs ? { ...BDG_CHROME_PREFS, ...userPrefs } : BDG_CHROME_PREFS;
197
224
  return {
198
225
  logLevel: options.logLevel ?? DEFAULT_CHROME_LOG_LEVEL,
199
226
  handleSIGINT: options.handleSIGINT ?? DEFAULT_CHROME_HANDLE_SIGINT,
@@ -206,7 +233,6 @@ function buildChromeOptions(options) {
206
233
  connectionPollInterval: options.connectionPollInterval ?? CHROME_READY_POLL_MS,
207
234
  maxConnectionRetries: options.maxConnectionRetries ?? CHROME_READY_POLL_ATTEMPTS,
208
235
  portStrictMode: options.portStrictMode,
209
- prefs: ensureJSONCompatiblePrefs(mergedPrefs),
210
236
  envVars: options.envVars,
211
237
  chromePath: chromePathOverride,
212
238
  }),
@@ -12,14 +12,24 @@ export interface PortReservation {
12
12
  release: () => void;
13
13
  }
14
14
  /**
15
- * Whether something already accepts connections on 127.0.0.1:port. A
16
- * listener on all interfaces (`0.0.0.0`/`::`) does not stop bdg from binding
17
- * 127.0.0.1 on macOS, but Chrome would then fail to listen, so it is checked
18
- * by connecting.
15
+ * Whether something already accepts connections on host:port.
19
16
  *
20
17
  * @param port - Port to check
18
+ * @param host - Address to connect to
21
19
  * @returns True if a connection was accepted
22
20
  */
21
+ export declare function acceptsConnections(port: number, host: string): Promise<boolean>;
22
+ /**
23
+ * Whether something already accepts connections on the port, on 127.0.0.1 or
24
+ * ::1. A listener on all interfaces (`0.0.0.0`/`::`) does not stop bdg from
25
+ * binding 127.0.0.1 on macOS, but Chrome would then fail to listen; a Chrome
26
+ * on [::1] (one that found 127.0.0.1 taken) does not stop it either, but a
27
+ * second Chrome would be reached through the first one's port. Both are found
28
+ * by connecting.
29
+ *
30
+ * @param port - Port to check
31
+ * @returns True if a connection was accepted on either address
32
+ */
23
33
  export declare function isPortAnswering(port: number): Promise<boolean>;
24
34
  /**
25
35
  * Atomically reserve a port to prevent race conditions during Chrome launch.
@@ -8,18 +8,18 @@ import * as net from 'net';
8
8
  import { ChromeLaunchError } from './errors.js';
9
9
  /** How long a connection attempt may take when checking a port */
10
10
  const CONNECT_CHECK_MS = 500;
11
+ /** Loopback addresses Chrome may listen on (it falls back to IPv6 when IPv4 is taken) */
12
+ const LOOPBACK_HOSTS = ['127.0.0.1', '::1'];
11
13
  /**
12
- * Whether something already accepts connections on 127.0.0.1:port. A
13
- * listener on all interfaces (`0.0.0.0`/`::`) does not stop bdg from binding
14
- * 127.0.0.1 on macOS, but Chrome would then fail to listen, so it is checked
15
- * by connecting.
14
+ * Whether something already accepts connections on host:port.
16
15
  *
17
16
  * @param port - Port to check
17
+ * @param host - Address to connect to
18
18
  * @returns True if a connection was accepted
19
19
  */
20
- export function isPortAnswering(port) {
20
+ export function acceptsConnections(port, host) {
21
21
  return new Promise((resolve) => {
22
- const socket = net.connect({ port, host: '127.0.0.1' });
22
+ const socket = net.connect({ port, host });
23
23
  const finish = (answering) => {
24
24
  socket.destroy();
25
25
  resolve(answering);
@@ -29,6 +29,21 @@ export function isPortAnswering(port) {
29
29
  socket.once('error', () => finish(false));
30
30
  });
31
31
  }
32
+ /**
33
+ * Whether something already accepts connections on the port, on 127.0.0.1 or
34
+ * ::1. A listener on all interfaces (`0.0.0.0`/`::`) does not stop bdg from
35
+ * binding 127.0.0.1 on macOS, but Chrome would then fail to listen; a Chrome
36
+ * on [::1] (one that found 127.0.0.1 taken) does not stop it either, but a
37
+ * second Chrome would be reached through the first one's port. Both are found
38
+ * by connecting.
39
+ *
40
+ * @param port - Port to check
41
+ * @returns True if a connection was accepted on either address
42
+ */
43
+ export async function isPortAnswering(port) {
44
+ const answers = await Promise.all(LOOPBACK_HOSTS.map((host) => acceptsConnections(port, host)));
45
+ return answers.some(Boolean);
46
+ }
32
47
  /**
33
48
  * The error for a port another process uses.
34
49
  *
@@ -22,6 +22,14 @@ export interface StartupLogs {
22
22
  * @returns Log positions
23
23
  */
24
24
  export declare function markStartupLogs(userDataDir: string): StartupLogs;
25
+ /**
26
+ * Chrome's output (stderr, then stdout) since {@link markStartupLogs}. The
27
+ * marked offsets are byte sizes, so the files are cut before decoding.
28
+ *
29
+ * @param logs - Log positions
30
+ * @returns Output lines
31
+ */
32
+ export declare function readStartupLines(logs: StartupLogs): string[];
25
33
  /**
26
34
  * Reject when the launched Chrome exits before it is ready.
27
35
  *
@@ -31,18 +31,27 @@ export function markStartupLogs(userDataDir) {
31
31
  };
32
32
  }
33
33
  /**
34
- * Chrome's output since {@link markStartupLogs}, last lines first trimmed.
34
+ * Chrome's output (stderr, then stdout) since {@link markStartupLogs}. The
35
+ * marked offsets are byte sizes, so the files are cut before decoding.
35
36
  *
36
37
  * @param logs - Log positions
37
- * @returns Up to {@link OUTPUT_LINES} non-empty lines
38
+ * @returns Output lines
38
39
  */
39
- function readStartupOutput(logs) {
40
- const lines = logs.files.flatMap(({ file, offset }) => {
40
+ export function readStartupLines(logs) {
41
+ return logs.files.flatMap(({ file, offset }) => {
41
42
  if (!fs.existsSync(file))
42
43
  return [];
43
- return fs.readFileSync(file, 'utf8').slice(offset).split('\n');
44
+ return fs.readFileSync(file).subarray(offset).toString('utf8').split('\n');
44
45
  });
45
- return lines
46
+ }
47
+ /**
48
+ * Chrome's output since {@link markStartupLogs}, last lines first trimmed.
49
+ *
50
+ * @param logs - Log positions
51
+ * @returns Up to {@link OUTPUT_LINES} non-empty lines
52
+ */
53
+ function readStartupOutput(logs) {
54
+ return readStartupLines(logs)
46
55
  .map((line) => line.trim())
47
56
  .filter(Boolean)
48
57
  .slice(-OUTPUT_LINES);
@@ -46,8 +46,12 @@ export declare const BDG_CHROME_FLAGS: string[];
46
46
  export declare const DOCKER_CHROME_FLAGS: string[];
47
47
  /**
48
48
  * BDG-specific Chrome preferences for automation
49
- * These preferences are automatically merged with user preferences when launching Chrome
50
- * User preferences take precedence over these defaults
49
+ * Written into the launched profile's Default/Preferences (dotted names become nested paths)
50
+ * before every launch, so persistent profiles get them too. User preferences take precedence.
51
+ *
52
+ * The password manager and its leak check are off: after a login their bubble
53
+ * (e.g. "Change your password") captures all input in headless Chrome, so
54
+ * later clicks silently never reach the page.
51
55
  *
52
56
  * Note: Crash/restore popup suppression is handled by Chrome flags (--disable-session-crashed-bubble, --disable-infobars)
53
57
  * which are more reliable than preference-based approaches.
package/dist/constants.js CHANGED
@@ -64,8 +64,12 @@ export const DOCKER_CHROME_FLAGS = [
64
64
  ];
65
65
  /**
66
66
  * BDG-specific Chrome preferences for automation
67
- * These preferences are automatically merged with user preferences when launching Chrome
68
- * User preferences take precedence over these defaults
67
+ * Written into the launched profile's Default/Preferences (dotted names become nested paths)
68
+ * before every launch, so persistent profiles get them too. User preferences take precedence.
69
+ *
70
+ * The password manager and its leak check are off: after a login their bubble
71
+ * (e.g. "Change your password") captures all input in headless Chrome, so
72
+ * later clicks silently never reach the page.
69
73
  *
70
74
  * Note: Crash/restore popup suppression is handled by Chrome flags (--disable-session-crashed-bubble, --disable-infobars)
71
75
  * which are more reliable than preference-based approaches.
@@ -75,6 +79,9 @@ export const BDG_CHROME_PREFS = {
75
79
  'translate.enabled': false, // Disable Google Translate popup
76
80
  translate_site_blacklist: ['*'], // Block translate for all sites
77
81
  'profile.exit_type': 'Normal', // Trick Chrome into thinking it shut down correctly
82
+ credentials_enable_service: false, // No "Save password?" bubble
83
+ 'profile.password_manager_enabled': false, // Password manager off
84
+ 'profile.password_manager_leak_detection': false, // No "Change your password" breach dialog
78
85
  };
79
86
  // ============================================================================
80
87
  // DATA COLLECTION LIMITS
@@ -9,20 +9,36 @@ import { CDPConnectionError, CDPProtocolError, ChromeLaunchError, ConnectionErro
9
9
  import { Session, StartCancelledError } from './session/Session.js';
10
10
  import { detectTargetMismatch } from './session/targetMismatch.js';
11
11
  import { CommandError } from '../errors/index.js';
12
- import { LAUNCHED_CHROME_DESCRIPTION, cdpRequestRejectedError, sessionEndedDuringCommandError, } from '../errors/messages.js';
12
+ import { LAUNCHED_CHROME_DESCRIPTION, cdpRequestRejectedError, sessionAlreadyRunningMessage, sessionEndedDuringCommandError, sessionUnavailableSuggestion, } from '../errors/messages.js';
13
13
  import { IPCErrorCode, } from '../ipc/index.js';
14
14
  import { clearLastSessionEnd, writeLastSessionEnd } from '../session/lastSession.js';
15
15
  import { createLogger } from '../ui/logging/index.js';
16
16
  import { formatChromeIssue } from '../ui/messages/chrome.js';
17
+ import { noActiveSessionMessage } from '../ui/messages/sessionCommand.js';
17
18
  import { getErrorMessage } from '../utils/errors.js';
18
19
  import { EXIT_CODES } from '../utils/exitCodes.js';
19
20
  import { filterDefined } from '../utils/objects.js';
20
21
  const log = createLogger('daemon');
21
- const NO_SESSION_ERROR = 'No active session';
22
22
  /** Error for requests that need the session while `bdg <url>` is still starting it */
23
23
  const STARTING_ERROR = 'The session is still starting';
24
24
  const COMMAND_TIMEOUT_MS = 30000;
25
25
  const QUERY_TIMEOUT_MS = 5000;
26
+ /** Time a `dom wait` gets beyond its own --timeout to report the timeout itself */
27
+ const WAIT_COMMAND_MARGIN_MS = 5000;
28
+ /**
29
+ * How long a session command may run: `dom wait` runs for its own
30
+ * --timeout, everything else gets {@link COMMAND_TIMEOUT_MS}.
31
+ *
32
+ * @param name - Command name
33
+ * @param params - Command parameters
34
+ * @returns Timeout in milliseconds
35
+ */
36
+ function commandTimeoutMs(name, params) {
37
+ if (name !== 'dom_wait')
38
+ return COMMAND_TIMEOUT_MS;
39
+ const { timeout } = params;
40
+ return Math.max(COMMAND_TIMEOUT_MS, (timeout ?? 0) + WAIT_COMMAND_MARGIN_MS);
41
+ }
26
42
  /**
27
43
  * Run a promise with a timeout, clearing the timer either way.
28
44
  *
@@ -139,11 +155,11 @@ export class SessionController {
139
155
  */
140
156
  noSessionError() {
141
157
  if (!this.launching)
142
- return { error: NO_SESSION_ERROR };
158
+ return { error: noActiveSessionMessage() };
143
159
  return {
144
160
  error: STARTING_ERROR,
145
161
  exitCode: EXIT_CODES.RESOURCE_BUSY,
146
- suggestion: 'Wait until "bdg <url>" returns, then retry',
162
+ suggestion: sessionUnavailableSuggestion(EXIT_CODES.RESOURCE_BUSY),
147
163
  };
148
164
  }
149
165
  /**
@@ -270,7 +286,7 @@ export class SessionController {
270
286
  const { sessionId: _sessionId, type: _type, ...params } = request;
271
287
  try {
272
288
  const execute = this.session.execute.bind(this.session);
273
- const data = await withTimeout(execute(name, params), COMMAND_TIMEOUT_MS, 'Command');
289
+ const data = await withTimeout(execute(name, params), commandTimeoutMs(name, params), 'Command');
274
290
  return { ...base, status: 'ok', data };
275
291
  }
276
292
  catch (error) {
@@ -367,7 +383,7 @@ export class SessionController {
367
383
  return {
368
384
  ...base,
369
385
  status: 'error',
370
- message: 'No active session found',
386
+ message: noActiveSessionMessage(),
371
387
  errorCode: IPCErrorCode.NO_SESSION,
372
388
  };
373
389
  }
@@ -430,7 +446,7 @@ export class SessionController {
430
446
  };
431
447
  }
432
448
  return {
433
- message: `Session already running (PID ${process.pid}). Stop it first with: bdg stop`,
449
+ message: sessionAlreadyRunningMessage(process.pid),
434
450
  errorCode: IPCErrorCode.SESSION_ALREADY_RUNNING,
435
451
  existingSession: { ...existingSession, targetUrl },
436
452
  };
@@ -54,7 +54,7 @@ export declare class SessionDirError extends DaemonError {
54
54
  /**
55
55
  * @param message - What is wrong with the directory
56
56
  * @param suggestion - How to fix it
57
- * @param exitCode - 82 for permissions, 103 otherwise
57
+ * @param exitCode - 82 for permissions, 81 for a too-long path, 103 otherwise
58
58
  */
59
59
  constructor(message: string, suggestion: string, exitCode?: number);
60
60
  }
@@ -69,7 +69,7 @@ export class SessionDirError extends DaemonError {
69
69
  /**
70
70
  * @param message - What is wrong with the directory
71
71
  * @param suggestion - How to fix it
72
- * @param exitCode - 82 for permissions, 103 otherwise
72
+ * @param exitCode - 82 for permissions, 81 for a too-long path, 103 otherwise
73
73
  */
74
74
  constructor(message, suggestion, exitCode = EXIT_CODES.SESSION_FILE_ERROR) {
75
75
  super(message, 'SESSION_DIR_UNUSABLE', exitCode);
@@ -17,7 +17,8 @@ export declare function launchDaemon(): Promise<void>;
17
17
  * Check that the session directory can hold the daemon's files before
18
18
  * spawning it (otherwise the daemon dies and only its log says why).
19
19
  *
20
- * @throws SessionDirError (103) for a file or a too-long path, (82) when not writable
20
+ * @throws SessionDirError (103) for a file, (81) for a too-long path like a
21
+ * named session's, (82) when not writable
21
22
  */
22
23
  export declare function assertUsableSessionDir(): void;
23
24
  //# sourceMappingURL=launcher.d.ts.map