brave-mcp 1.11.0 → 1.12.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 (382) hide show
  1. package/README.md +69 -1
  2. package/{build → out/Default/gen}/src/BrowserManager.js +28 -18
  3. package/out/Default/gen/src/LogpointManager.js +307 -0
  4. package/{build → out/Default/gen}/src/McpContext.js +435 -87
  5. package/{build → out/Default/gen}/src/McpPage.js +326 -58
  6. package/{build → out/Default/gen}/src/McpResponse.js +89 -46
  7. package/{build → out/Default/gen}/src/TextSnapshot.js +37 -18
  8. package/out/Default/gen/src/ToolHandler.js +492 -0
  9. package/{build → out/Default/gen}/src/bin/brave-devtools-mcp-main.js +6 -4
  10. package/{build → out/Default/gen}/src/bin/brave-devtools.js +4 -4
  11. package/{build → out/Default/gen}/src/collectors/PageCollector.js +28 -12
  12. package/{build → out/Default/gen}/src/collectors/ServiceWorkerCollector.js +2 -2
  13. package/out/Default/gen/src/collectors/constants.js +7 -0
  14. package/out/Default/gen/src/config/ConfigParser.js +162 -0
  15. package/{build → out/Default/gen}/src/config/ConfigWatcher.js +3 -2
  16. package/out/Default/gen/src/config/ServerConfig.js +251 -0
  17. package/{build → out/Default/gen}/src/config/browser-options.js +13 -4
  18. package/{build → out/Default/gen}/src/config/category-options.js +4 -0
  19. package/{build → out/Default/gen}/src/config/cli-options.js +113 -20
  20. package/{build → out/Default/gen}/src/config/mcp-options.js +62 -36
  21. package/{build → out/Default/gen}/src/config/puppeteer-options.js +4 -2
  22. package/{build → out/Default/gen}/src/daemon/client.js +3 -3
  23. package/{build → out/Default/gen}/src/daemon/daemon.js +7 -3
  24. package/{build → out/Default/gen}/src/daemon/utils.js +2 -1
  25. package/{build → out/Default/gen}/src/devtools/DevToolsCommentBridge.js +28 -5
  26. package/{build → out/Default/gen}/src/devtools/DevtoolsUtils.js +94 -20
  27. package/{build → out/Default/gen}/src/formatters/ConsoleFormatter.js +28 -1
  28. package/{build → out/Default/gen}/src/formatters/HeapSnapshotFormatter.js +14 -18
  29. package/out/Default/gen/src/formatters/LogpointFormatter.js +62 -0
  30. package/{build → out/Default/gen}/src/formatters/NetworkFormatter.js +70 -17
  31. package/out/Default/gen/src/formatters/RemoteObjectFormatter.js +231 -0
  32. package/{build → out/Default/gen}/src/formatters/SnapshotFormatter.js +13 -3
  33. package/out/Default/gen/src/formatters/WebAuthnFormatter.js +56 -0
  34. package/out/Default/gen/src/index.js +434 -0
  35. package/out/Default/gen/src/processors/HeapSnapshotManager.js +569 -0
  36. package/{build → out/Default/gen}/src/telemetry/transformation.js +1 -1
  37. package/{build → out/Default/gen}/src/third_party/THIRD_PARTY_NOTICES +752 -716
  38. package/out/Default/gen/src/third_party/bundled-packages.json +11 -0
  39. package/out/Default/gen/src/third_party/cli.js +9239 -0
  40. package/out/Default/gen/src/third_party/devtools-formatter-worker.js +17825 -0
  41. package/out/Default/gen/src/third_party/devtools-heap-snapshot-worker.js +12575 -0
  42. package/{build → out/Default/gen}/src/third_party/index.js +70243 -60439
  43. package/out/Default/gen/src/third_party/lighthouse-devtools-mcp-bundle.js +60395 -0
  44. package/out/Default/gen/src/tools/ToolDefinition.js +180 -0
  45. package/{build → out/Default/gen}/src/tools/categories.js +2 -0
  46. package/{build → out/Default/gen}/src/tools/comments.js +42 -3
  47. package/{build → out/Default/gen}/src/tools/console.js +8 -6
  48. package/{build → out/Default/gen}/src/tools/css.js +1 -0
  49. package/{build → out/Default/gen}/src/tools/emulation.js +5 -4
  50. package/{build → out/Default/gen}/src/tools/extensions.js +5 -0
  51. package/{build → out/Default/gen}/src/tools/input.js +22 -10
  52. package/{build → out/Default/gen}/src/tools/lighthouse.js +23 -7
  53. package/out/Default/gen/src/tools/logpoints.js +51 -0
  54. package/{build → out/Default/gen}/src/tools/memory.js +59 -53
  55. package/{build → out/Default/gen}/src/tools/network.js +5 -4
  56. package/{build → out/Default/gen}/src/tools/pages.js +48 -6
  57. package/{build → out/Default/gen}/src/tools/performance.js +21 -5
  58. package/{build → out/Default/gen}/src/tools/pwa.js +7 -0
  59. package/{build → out/Default/gen}/src/tools/screencast.js +3 -1
  60. package/{build → out/Default/gen}/src/tools/screenshot.js +23 -7
  61. package/{build → out/Default/gen}/src/tools/script.js +38 -6
  62. package/{build → out/Default/gen}/src/tools/slim/tools.js +21 -5
  63. package/{build → out/Default/gen}/src/tools/snapshot.js +29 -5
  64. package/{build → out/Default/gen}/src/tools/thirdPartyDeveloper.js +6 -20
  65. package/out/Default/gen/src/tools/toolNames.js +10 -0
  66. package/{build → out/Default/gen}/src/tools/tools.js +4 -0
  67. package/out/Default/gen/src/tools/webauthn.js +51 -0
  68. package/{build → out/Default/gen}/src/tools/webmcp.js +5 -19
  69. package/out/Default/gen/src/utils/TaskRunner.js +136 -0
  70. package/{build → out/Default/gen}/src/utils/WaitForHelper.js +1 -1
  71. package/{build → out/Default/gen}/src/utils/bytes.js +2 -12
  72. package/{build → out/Default/gen}/src/utils/check-for-updates.js +1 -1
  73. package/out/Default/gen/src/utils/disclaimers.js +25 -0
  74. package/{build → out/Default/gen}/src/utils/errorHandling.js +3 -0
  75. package/{build → out/Default/gen}/src/utils/keyboard.js +15 -5
  76. package/out/Default/gen/src/utils/logger.js +131 -0
  77. package/out/Default/gen/src/utils/resourceType.js +27 -0
  78. package/out/Default/gen/src/utils/text.js +44 -0
  79. package/out/Default/gen/src/utils/timeout.js +14 -0
  80. package/{build → out/Default/gen}/src/utils/url.js +41 -0
  81. package/{build → out/Default/gen}/src/version.js +1 -1
  82. package/package.json +26 -21
  83. package/skills/a11y-debugging/SKILL.md +3 -8
  84. package/skills/brave-devtools/SKILL.md +1 -0
  85. package/build/src/ToolHandler.js +0 -369
  86. package/build/src/config/ConfigParser.js +0 -264
  87. package/build/src/index.js +0 -276
  88. package/build/src/processors/HeapSnapshotManager.js +0 -307
  89. package/build/src/third_party/bundled-packages.json +0 -11
  90. package/build/src/third_party/devtools-formatter-worker.js +0 -16625
  91. package/build/src/third_party/devtools-heap-snapshot-worker.js +0 -12084
  92. package/build/src/third_party/lighthouse-devtools-mcp-bundle.js +0 -58435
  93. package/build/src/tools/ToolDefinition.js +0 -90
  94. package/build/src/utils/logger.js +0 -62
  95. package/build/src/utils/text.js +0 -15
  96. /package/{build → out/Default/gen}/src/McpWorker.js +0 -0
  97. /package/{build → out/Default/gen}/src/SlimMcpResponse.js +0 -0
  98. /package/{build → out/Default/gen}/src/bin/brave-devtools-mcp.js +0 -0
  99. /package/{build → out/Default/gen}/src/bin/check-latest-version.js +0 -0
  100. /package/{build → out/Default/gen}/src/config/ConfigLocator.js +0 -0
  101. /package/{build → out/Default/gen}/src/config/cli-commands.js +0 -0
  102. /package/{build → out/Default/gen}/src/config/tool-options.js +0 -0
  103. /package/{build → out/Default/gen}/src/daemon/types.js +0 -0
  104. /package/{build → out/Default/gen}/src/devtools/McpHostBindingAdapter.js +0 -0
  105. /package/{build → out/Default/gen}/src/devtools/issueDescriptions.js +0 -0
  106. /package/{build → out/Default/gen}/src/formatters/CommentFormatter.js +0 -0
  107. /package/{build → out/Default/gen}/src/formatters/CssFormatter.js +0 -0
  108. /package/{build → out/Default/gen}/src/formatters/IssueFormatter.js +0 -0
  109. /package/{build → out/Default/gen}/src/processors/ChunkedTraceParser.js +0 -0
  110. /package/{build → out/Default/gen}/src/processors/PerformanceTrace.js +0 -0
  111. /package/{build → out/Default/gen}/src/telemetry/ClearcutLogger.js +0 -0
  112. /package/{build → out/Default/gen}/src/telemetry/WatchdogClient.js +0 -0
  113. /package/{build → out/Default/gen}/src/telemetry/errors.js +0 -0
  114. /package/{build → out/Default/gen}/src/telemetry/flagUtils.js +0 -0
  115. /package/{build → out/Default/gen}/src/telemetry/metricsRegistry.js +0 -0
  116. /package/{build → out/Default/gen}/src/telemetry/persistence.js +0 -0
  117. /package/{build → out/Default/gen}/src/telemetry/types.js +0 -0
  118. /package/{build → out/Default/gen}/src/telemetry/watchdog/ClearcutSender.js +0 -0
  119. /package/{build → out/Default/gen}/src/telemetry/watchdog/main.js +0 -0
  120. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/CoepCoopSandboxedIframeCannotNavigateToCoopPage.md +0 -0
  121. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/CoepCorpNotSameOrigin.md +0 -0
  122. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/CoepCorpNotSameOriginAfterDefaultedToSameOriginByCoep.md +0 -0
  123. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/CoepCorpNotSameSite.md +0 -0
  124. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/CoepFrameResourceNeedsCoepHeader.md +0 -0
  125. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/CompatibilityModeQuirks.md +0 -0
  126. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/CookieAttributeValueExceedsMaxSize.md +0 -0
  127. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/LowTextContrast.md +0 -0
  128. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/SameSiteNoneInsecureErrorRead.md +0 -0
  129. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/SameSiteNoneInsecureErrorSet.md +0 -0
  130. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/SameSiteNoneInsecureWarnRead.md +0 -0
  131. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/SameSiteNoneInsecureWarnSet.md +0 -0
  132. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/SameSiteUnspecifiedLaxAllowUnsafeRead.md +0 -0
  133. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/SameSiteUnspecifiedLaxAllowUnsafeSet.md +0 -0
  134. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/bounceTrackingMitigations.md +0 -0
  135. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/clientHintMetaTagAllowListInvalidOrigin.md +0 -0
  136. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/clientHintMetaTagModifiedHTML.md +0 -0
  137. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/connectionAllowlistEmbeddingRequirementNotSatisfied.md +0 -0
  138. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/connectionAllowlistIFrameAttributeLoosensEmbeddingRequirement.md +0 -0
  139. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/connectionAllowlistInvalidAllowConnectionAllowlistFrom.md +0 -0
  140. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/connectionAllowlistInvalidAllowlistItemType.md +0 -0
  141. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/connectionAllowlistInvalidHeader.md +0 -0
  142. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/connectionAllowlistInvalidUrlPattern.md +0 -0
  143. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/connectionAllowlistItemNotInnerList.md +0 -0
  144. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/connectionAllowlistMoreThanOneList.md +0 -0
  145. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/connectionAllowlistReportingEndpointNotToken.md +0 -0
  146. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/cookieCrossSiteRedirectDowngrade.md +0 -0
  147. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/cookieExcludeDomainNonAscii.md +0 -0
  148. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/cookieExcludePortMismatch.md +0 -0
  149. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/cookieExcludeSchemeMismatch.md +0 -0
  150. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/cookieExcludeThirdPartyPhaseoutRead.md +0 -0
  151. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/cookieExcludeThirdPartyPhaseoutSet.md +0 -0
  152. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/cookieWarnDomainNonAscii.md +0 -0
  153. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/cookieWarnMetadataGrantRead.md +0 -0
  154. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/cookieWarnMetadataGrantReadOptOut.md +0 -0
  155. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/cookieWarnMetadataGrantSet.md +0 -0
  156. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/cookieWarnMetadataGrantSetOptOut.md +0 -0
  157. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/cookieWarnThirdPartyPhaseoutRead.md +0 -0
  158. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/cookieWarnThirdPartyPhaseoutSet.md +0 -0
  159. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/corsAllowCredentialsRequired.md +0 -0
  160. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/corsDisabledScheme.md +0 -0
  161. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/corsDisallowedByMode.md +0 -0
  162. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/corsHeaderDisallowedByPreflightResponse.md +0 -0
  163. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/corsInvalidHeaderValues.md +0 -0
  164. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/corsLocalNetworkAccessPermissionDenied.md +0 -0
  165. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/corsMethodDisallowedByPreflightResponse.md +0 -0
  166. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/corsNoCorsRedirectModeNotFollow.md +0 -0
  167. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/corsOriginMismatch.md +0 -0
  168. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/corsPreflightResponseInvalid.md +0 -0
  169. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/corsRedirectContainsCredentials.md +0 -0
  170. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/corsWildcardOriginNotAllowed.md +0 -0
  171. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/cspEvalViolation.md +0 -0
  172. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/cspInlineViolation.md +0 -0
  173. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/cspTrustedTypesPolicyViolation.md +0 -0
  174. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/cspTrustedTypesSinkViolation.md +0 -0
  175. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/cspURLViolation.md +0 -0
  176. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/deprecation.md +0 -0
  177. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestAccountsEmptyList.md +0 -0
  178. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestAccountsHttpNotFound.md +0 -0
  179. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestAccountsInvalidContentType.md +0 -0
  180. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestAccountsInvalidResponse.md +0 -0
  181. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestAccountsNoResponse.md +0 -0
  182. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestDnsFetchFailed.md +0 -0
  183. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestDnsInvalidRecord.md +0 -0
  184. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownHttpNotFound.md +0 -0
  185. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownInvalidContentType.md +0 -0
  186. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownInvalidResponse.md +0 -0
  187. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownNoResponse.md +0 -0
  188. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestInvalidEmail.md +0 -0
  189. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestJwksHttpNotFound.md +0 -0
  190. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestJwksInvalidResponse.md +0 -0
  191. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestKeyBindingSigningFailed.md +0 -0
  192. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestRpOriginIsOpaque.md +0 -0
  193. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenHttpNotFound.md +0 -0
  194. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidContentType.md +0 -0
  195. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidResponse.md +0 -0
  196. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidSdJwt.md +0 -0
  197. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenMalformedSdJwt.md +0 -0
  198. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenNoResponse.md +0 -0
  199. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidAudience.md +0 -0
  200. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidIssuedAt.md +0 -0
  201. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidNonce.md +0 -0
  202. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidSdHash.md +0 -0
  203. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidTyp.md +0 -0
  204. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingAud.md +0 -0
  205. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingCnf.md +0 -0
  206. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingIat.md +0 -0
  207. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingNonce.md +0 -0
  208. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingSdHash.md +0 -0
  209. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbSignatureFailed.md +0 -0
  210. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidEmail.md +0 -0
  211. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidEmailVerified.md +0 -0
  212. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidHolderKey.md +0 -0
  213. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidIssuedAt.md +0 -0
  214. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidIssuer.md +0 -0
  215. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtJwksMissingKeys.md +0 -0
  216. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingCnf.md +0 -0
  217. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingEmail.md +0 -0
  218. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingIat.md +0 -0
  219. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingIss.md +0 -0
  220. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtSignatureFailed.md +0 -0
  221. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtUnsupportedHeaderAlg.md +0 -0
  222. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestUserLoggedOut.md +0 -0
  223. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestWellKnownAccountsEndpointCrossOrigin.md +0 -0
  224. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestWellKnownHttpNotFound.md +0 -0
  225. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestWellKnownInvalidContentType.md +0 -0
  226. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestWellKnownInvalidResponse.md +0 -0
  227. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestWellKnownIssuanceEndpointCrossOrigin.md +0 -0
  228. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestWellKnownListEmpty.md +0 -0
  229. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestWellKnownMissingAccountsEndpoint.md +0 -0
  230. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestWellKnownMissingIssuanceEndpoint.md +0 -0
  231. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestWellKnownNoResponse.md +0 -0
  232. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/emailVerificationRequestWellKnownUnsupportedSigningAlgorithm.md +0 -0
  233. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthRequestAccountsBlockedByConnectionAllowlist.md +0 -0
  234. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthRequestAccountsHttpNotFound.md +0 -0
  235. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthRequestAccountsInvalidResponse.md +0 -0
  236. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthRequestAccountsNoResponse.md +0 -0
  237. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthRequestApprovalDeclined.md +0 -0
  238. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthRequestCanceled.md +0 -0
  239. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthRequestConfigBlockedByConnectionAllowlist.md +0 -0
  240. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthRequestErrorFetchingSignin.md +0 -0
  241. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthRequestErrorIdToken.md +0 -0
  242. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthRequestIdTokenBlockedByConnectionAllowlist.md +0 -0
  243. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthRequestIdTokenHttpNotFound.md +0 -0
  244. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthRequestIdTokenInvalidRequest.md +0 -0
  245. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthRequestIdTokenInvalidResponse.md +0 -0
  246. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthRequestIdTokenNoResponse.md +0 -0
  247. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthRequestInvalidSigninResponse.md +0 -0
  248. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthRequestManifestHttpNotFound.md +0 -0
  249. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthRequestManifestInvalidResponse.md +0 -0
  250. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthRequestManifestNoResponse.md +0 -0
  251. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthRequestTooManyRequests.md +0 -0
  252. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthRequestWellKnownBlockedByConnectionAllowlist.md +0 -0
  253. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthUserInfoRequestInvalidAccountsResponse.md +0 -0
  254. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthUserInfoRequestInvalidConfigOrWellKnown.md +0 -0
  255. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoAccountSharingPermission.md +0 -0
  256. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoApiPermission.md +0 -0
  257. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoReturningUserFromFetchedAccounts.md +0 -0
  258. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotIframe.md +0 -0
  259. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotPotentiallyTrustworthy.md +0 -0
  260. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotSameOrigin.md +0 -0
  261. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotSignedInWithIdp.md +0 -0
  262. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/fetchingPartitionedBlobURL.md +0 -0
  263. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/genericBackUINavigationWouldSkipAd.md +0 -0
  264. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/genericFormAriaLabelledByToNonExistingIdError.md +0 -0
  265. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/genericFormAutocompleteAttributeEmptyError.md +0 -0
  266. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/genericFormDuplicateIdForInputError.md +0 -0
  267. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/genericFormEmptyIdAndNameAttributesForInputError.md +0 -0
  268. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/genericFormInputAssignedAutocompleteValueToIdOrNameAttributeError.md +0 -0
  269. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/genericFormInputHasWrongButWellIntendedAutocompleteValueError.md +0 -0
  270. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/genericFormInputWithNoLabelError.md +0 -0
  271. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/genericFormLabelForMatchesNonExistingIdError.md +0 -0
  272. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/genericFormLabelForNameError.md +0 -0
  273. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/genericFormLabelHasNeitherForNorNestedInputError.md +0 -0
  274. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/genericFormModelContextMissingToolDescription.md +0 -0
  275. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/genericFormModelContextMissingToolName.md +0 -0
  276. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/genericFormModelContextParameterMissingName.md +0 -0
  277. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/genericFormModelContextParameterMissingTitleAndDescription.md +0 -0
  278. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/genericFormModelContextRequiredParameterMissingName.md +0 -0
  279. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/genericGeolocationPromptWithoutUserGesture.md +0 -0
  280. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/genericNavigationEntryMarkedSkippable.md +0 -0
  281. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/genericResponseWasBlockedByORB.md +0 -0
  282. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/heavyAd.md +0 -0
  283. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/lazyLoadImageZeroSize.md +0 -0
  284. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/mixedContent.md +0 -0
  285. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/navigatingPartitionedBlobURL.md +0 -0
  286. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementActivationDisabled.md +0 -0
  287. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementActivationDisabledWithOccluder.md +0 -0
  288. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementActivationDisabledWithOccluderParent.md +0 -0
  289. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementCspFrameAncestorsMissing.md +0 -0
  290. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementFencedFrameDisallowed.md +0 -0
  291. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementFontSizeTooLarge.md +0 -0
  292. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementFontSizeTooSmall.md +0 -0
  293. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementGeolocationDeprecated.md +0 -0
  294. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementInsetBoxShadowUnsupported.md +0 -0
  295. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementInvalidDisplayStyle.md +0 -0
  296. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementInvalidSizeValue.md +0 -0
  297. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementInvalidType.md +0 -0
  298. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementInvalidTypeActivation.md +0 -0
  299. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementLowContrast.md +0 -0
  300. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementNonOpaqueColor.md +0 -0
  301. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementPaddingBottomUnsupported.md +0 -0
  302. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementPaddingRightUnsupported.md +0 -0
  303. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementPermissionsPolicyBlocked.md +0 -0
  304. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementRegistrationFailed.md +0 -0
  305. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementRequestInProgress.md +0 -0
  306. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementSecurityChecksFailed.md +0 -0
  307. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementTypeNotSupported.md +0 -0
  308. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/permissionElementUntrustedEvent.md +0 -0
  309. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/placeholderDescriptionForInvisibleIssues.md +0 -0
  310. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/propertyRuleInvalidNameIssue.md +0 -0
  311. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/propertyRuleIssue.md +0 -0
  312. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/selectElementAccessibilityDisallowedOptGroupChild.md +0 -0
  313. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/selectElementAccessibilityDisallowedSelectChild.md +0 -0
  314. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentAttributesSelectDescendant.md +0 -0
  315. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentLegendChild.md +0 -0
  316. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentOptionChild.md +0 -0
  317. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/selectElementAccessibilityNonPhrasingContentOptionChild.md +0 -0
  318. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/selectivePermissionsIntervention.md +0 -0
  319. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedArrayBuffer.md +0 -0
  320. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryUseErrorCrossOriginNoCorsRequest.md +0 -0
  321. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryUseErrorDictionaryLoadFailure.md +0 -0
  322. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryUseErrorMatchingDictionaryNotUsed.md +0 -0
  323. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryUseErrorUnexpectedContentDictionaryHeader.md +0 -0
  324. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryWriteErrorCossOriginNoCorsRequest.md +0 -0
  325. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryWriteErrorDisallowedBySettings.md +0 -0
  326. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryWriteErrorExpiredResponse.md +0 -0
  327. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryWriteErrorFeatureDisabled.md +0 -0
  328. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInsufficientResources.md +0 -0
  329. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInvalidMatchField.md +0 -0
  330. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInvalidStructuredHeader.md +0 -0
  331. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInvalidTTLField.md +0 -0
  332. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNavigationRequest.md +0 -0
  333. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNoMatchField.md +0 -0
  334. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonIntegerTTLField.md +0 -0
  335. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonListMatchDestField.md +0 -0
  336. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonSecureContext.md +0 -0
  337. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonStringIdField.md +0 -0
  338. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonStringInMatchDestList.md +0 -0
  339. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonStringMatchField.md +0 -0
  340. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonTokenTypeField.md +0 -0
  341. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryWriteErrorRequestAborted.md +0 -0
  342. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryWriteErrorShuttingDown.md +0 -0
  343. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryWriteErrorTooLongIdField.md +0 -0
  344. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sharedDictionaryWriteErrorUnsupportedType.md +0 -0
  345. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sriInvalidSignatureHeader.md +0 -0
  346. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sriInvalidSignatureInputHeader.md +0 -0
  347. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sriMissingSignatureHeader.md +0 -0
  348. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sriMissingSignatureInputHeader.md +0 -0
  349. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sriSignatureHeaderValueIsIncorrectLength.md +0 -0
  350. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sriSignatureHeaderValueIsNotByteSequence.md +0 -0
  351. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sriSignatureHeaderValueIsParameterized.md +0 -0
  352. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidComponentName.md +0 -0
  353. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidComponentType.md +0 -0
  354. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidDerivedComponentParameter.md +0 -0
  355. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidHeaderComponentParameter.md +0 -0
  356. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidParameter.md +0 -0
  357. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sriSignatureInputHeaderKeyIdLength.md +0 -0
  358. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sriSignatureInputHeaderMissingLabel.md +0 -0
  359. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sriSignatureInputHeaderMissingRequiredParameters.md +0 -0
  360. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sriSignatureInputHeaderValueMissingComponents.md +0 -0
  361. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sriSignatureInputHeaderValueNotInnerList.md +0 -0
  362. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sriValidationFailedIntegrityMismatch.md +0 -0
  363. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sriValidationFailedInvalidLength.md +0 -0
  364. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sriValidationFailedSignatureExpired.md +0 -0
  365. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/sriValidationFailedSignatureMismatch.md +0 -0
  366. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/stylesheetLateImport.md +0 -0
  367. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/stylesheetRequestFailed.md +0 -0
  368. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/summaryElementAccessibilityInteractiveContentSummaryDescendant.md +0 -0
  369. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/unencodedDigestIncorrectDigestLength.md +0 -0
  370. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/unencodedDigestIncorrectDigestType.md +0 -0
  371. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/unencodedDigestMalformedDictionary.md +0 -0
  372. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/unencodedDigestUnknownAlgorithm.md +0 -0
  373. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/webInstallManifestMissingId.md +0 -0
  374. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/webInstallManifestMissingNameOrShortName.md +0 -0
  375. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/webInstallManifestParsingOrNetworkError.md +0 -0
  376. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/webInstallNoManifest.md +0 -0
  377. /package/{build → out/Default/gen}/src/third_party/issue-descriptions/webInstallStartUrlInvalid.md +0 -0
  378. /package/{build → out/Default/gen}/src/types.js +0 -0
  379. /package/{build → out/Default/gen}/src/utils/files.js +0 -0
  380. /package/{build → out/Default/gen}/src/utils/id.js +0 -0
  381. /package/{build → out/Default/gen}/src/utils/pagination.js +0 -0
  382. /package/{build → out/Default/gen}/src/utils/polyfill.js +0 -0
package/README.md CHANGED
@@ -62,7 +62,7 @@ When the agent connects, Brave asks for permission. Click **Allow**.
62
62
 
63
63
  Use [Chrome DevTools MCP](https://github.com/ChromeDevTools/chrome-devtools-mcp) when your target browser is Chrome. Use `brave-mcp` when your target browser is Brave and you want Brave-native discovery, profiles, channels, naming, and privacy defaults without giving up upstream features.
64
64
 
65
- ## [Tool reference](./docs/tool-reference.md) | [Changelog](./CHANGELOG.md) | [Contributing](./CONTRIBUTING.md) | [Troubleshooting](./docs/troubleshooting.md) | [Design principles](./docs/design-principles.md)
65
+ ## [Tool reference](./docs/tool-reference.md) | [CLI](./docs/cli.md) | [Skills](#skills) | [Changelog](./CHANGELOG.md) | [Contributing](./CONTRIBUTING.md) | [Troubleshooting](./docs/troubleshooting.md) | [Design principles](./docs/design-principles.md)
66
66
 
67
67
  ## Key features
68
68
 
@@ -163,6 +163,70 @@ Brave asks you to allow the connection. After you click **Allow**, your MCP clie
163
163
  > [!NOTE]
164
164
  > The MCP server connects to Brave only when the MCP client first uses a tool that needs a browser, not when the client starts. Without `--autoConnect`, that is when the server launches its own Brave.
165
165
 
166
+ ## CLI
167
+
168
+ The package also includes the `brave-devtools` CLI. Use it to control the browser from your terminal without MCP:
169
+
170
+ ```sh
171
+ npm i brave-mcp@latest -g
172
+ brave-devtools navigate_page 1 --url "https://brave.com"
173
+ brave-devtools take_screenshot 1 --filePath screenshot.png
174
+ brave-devtools stop
175
+ ```
176
+
177
+ See the [CLI guide][cli] for all commands and options.
178
+
179
+ ## Skills
180
+
181
+ The package includes [skills](./skills) that teach your agent how to use Brave DevTools:
182
+
183
+ | Skill | Use it to |
184
+ | --------------------------------------------------------- | ---------------------------------------------- |
185
+ | [`brave-devtools`](./skills/brave-devtools) | Debug and automate pages with the MCP tools. |
186
+ | [`brave-devtools-cli`](./skills/brave-devtools-cli) | Run the CLI and write shell scripts with it. |
187
+ | [`a11y-debugging`](./skills/a11y-debugging) | Audit and fix accessibility issues. |
188
+ | [`cookie-debugging`](./skills/cookie-debugging) | Debug cookies, sessions, and authentication. |
189
+ | [`debug-optimize-lcp`](./skills/debug-optimize-lcp) | Debug and improve Largest Contentful Paint. |
190
+ | [`memory-leak-debugging`](./skills/memory-leak-debugging) | Find and fix memory leaks. |
191
+ | [`troubleshooting`](./skills/troubleshooting) | Fix connection problems between MCP and Brave. |
192
+
193
+ ### Install skills as a plugin
194
+
195
+ A plugin installs the MCP server and all skills, including the CLI skill:
196
+
197
+ - **Claude Code:** Run `/plugin marketplace add triuzzi/brave-devtools-mcp`, then `/plugin install brave-devtools-mcp@brave-devtools-plugins`.
198
+ - **Copilot / VS Code:** Run **Chat: Install Plugin From Source** and enter `triuzzi/brave-devtools-mcp`.
199
+ - **Gemini CLI:** Run `gemini extensions install --auto-update https://github.com/triuzzi/brave-devtools-mcp`.
200
+
201
+ See the [Client Configurations Guide][client-configurations-guide] for more information.
202
+
203
+ ### Install skills manually
204
+
205
+ If your agent does not support plugins, copy the skill folders into the skills directory of your agent. The npm package contains the skills:
206
+
207
+ ```sh
208
+ npm i brave-mcp@latest -g
209
+ # Example for Claude Code. Use the skills directory of your agent.
210
+ mkdir -p ~/.claude/skills
211
+ cp -R "$(npm root -g)/brave-mcp/skills/brave-devtools-cli" ~/.claude/skills/
212
+ ```
213
+
214
+ > [!IMPORTANT]
215
+ > The `brave-devtools-cli` skill requires the CLI. Install the package globally before you use the skill.
216
+
217
+ ### Keep skills up to date
218
+
219
+ Skills describe the tools of a specific version. Update the skills each time you update the MCP server or the CLI. Outdated skills can tell your agent to use tools or parameters that changed.
220
+
221
+ - **Plugins:** Use the update command of the plugin manager of your agent. The Gemini CLI command above enables automatic updates with `--auto-update`.
222
+ - **Manual installs:** Update the package, then copy the skill folders again:
223
+
224
+ ```sh
225
+ npm i brave-mcp@latest -g
226
+ mkdir -p ~/.claude/skills
227
+ cp -R "$(npm root -g)/brave-mcp/skills/brave-devtools-cli" ~/.claude/skills/
228
+ ```
229
+
166
230
  ## Tools
167
231
 
168
232
  If you run into any issues, checkout our [troubleshooting guide][troubleshooting].
@@ -172,6 +236,8 @@ See the full [Tool reference][tool-reference] for a complete list of all support
172
236
 
173
237
  Find the complete list of server parameters (e.g., `--headless`, `--isolated`, `--slim`) and how to configure WebSocket connections in the [Configuration Guide][configuration-guide].
174
238
 
239
+ For basic browser tasks only, the `--slim` flag exposes a reduced set of tools. See the [Slim tool reference](./docs/slim-tool-reference.md).
240
+
175
241
  ## Advanced usage
176
242
 
177
243
  For advanced features such as handling concurrent sessions, persistent user data directories, connecting to a running Brave instance instead of starting a new one, or debugging on Android, see our [Advanced Usage Guide][advanced-usage-guide].
@@ -187,6 +253,8 @@ If you are developing agentic tooling and want to provide an integrated browser
187
253
  For a reference implementation, see the [Gemini CLI browser agent documentation](https://geminicli.com/docs/core/subagents/#browser-agent).
188
254
 
189
255
  [advanced-usage-guide]: ./docs/advanced-usage.md
256
+ [cli]: ./docs/cli.md
257
+ [skills]: #skills
190
258
  [client-configurations-guide]: ./docs/client-configurations.md
191
259
  [configuration-guide]: ./docs/configuration.md
192
260
  [tool-reference]: ./docs/tool-reference.md
@@ -60,8 +60,8 @@ import { execSync } from 'node:child_process';
60
60
  import fs from 'node:fs';
61
61
  import os from 'node:os';
62
62
  import path from 'node:path';
63
- import { Mutex, puppeteer } from './third_party/index.js';
64
- import { logger, puppeteerLogger } from './utils/logger.js';
63
+ import { Mutex, puppeteer, } from './third_party/index.js';
64
+ import { logger, puppeteerLogger, redactConnectOptionsForLogging, } from './utils/logger.js';
65
65
  import { isAllowedUrl } from './utils/url.js';
66
66
  // Node runs a timer whose delay exceeds 2^31-1 ms after 1 ms instead, which
67
67
  // would make every CDP call and tool call time out at once.
@@ -177,11 +177,11 @@ export class BrowserManager {
177
177
  #initPromise;
178
178
  #mutex = new Mutex();
179
179
  #closingCount = 0;
180
- #serverArgs;
180
+ #config;
181
181
  #options;
182
182
  #browserAttempt = new BrowserAttempt();
183
- constructor(serverArgs, options = {}) {
184
- this.#serverArgs = serverArgs;
183
+ constructor(config, options = {}) {
184
+ this.#config = config;
185
185
  this.#options = options;
186
186
  }
187
187
  static makeTargetFilter(enableExtensions = false) {
@@ -308,8 +308,9 @@ export class BrowserManager {
308
308
  * McpContext initialization built on it — if ensureBrowser() already
309
309
  * resolved and it's that later step hanging (e.g. a dead CDP transport),
310
310
  * the token rotation alone does nothing, since #browser is already
311
- * cached. Safe to forget unconditionally here: the tool mutex serializes
312
- * every call, so there's no concurrent caller to disrupt.
311
+ * cached. Safe to forget unconditionally here: a tool call that already
312
+ * received a Browser keeps using it, so forgetting the cached value only
313
+ * makes the next ensureBrowser() reconnect.
313
314
  */
314
315
  abandonPendingAttempt() {
315
316
  this.#browserAttempt = new BrowserAttempt();
@@ -317,27 +318,30 @@ export class BrowserManager {
317
318
  this.#forgetCurrentBrowser();
318
319
  }
319
320
  async #initBrowser() {
320
- if (this.#serverArgs.browserUrl ||
321
- this.#serverArgs.wsEndpoint ||
322
- this.#serverArgs.autoConnect) {
321
+ if (this.#config.resolved.browserUrl ||
322
+ this.#config.resolved.wsEndpoint ||
323
+ this.#config.resolved.autoConnect) {
323
324
  return await this.#connect();
324
325
  }
325
326
  return await this.#launch();
326
327
  }
327
328
  async #launch() {
328
- const { channel, headless, isolated = false, categoryExtensions: enableExtensions, viaCli, viewport, acceptInsecureCerts, experimentalDevtools: devtools = false, blockedUrlPattern: blocklist, allowedUrlPattern: allowlist, ignoreDefaultBraveArg, proxyServer, } = this.#serverArgs;
329
+ const { channel, headless, isolated = false, categoryExtensions: enableExtensions, viaCli, viewport, acceptInsecureCerts, experimentalDevtools: devtools = false, blockedUrlPattern: blocklist, allowedUrlPattern: allowlist, ignoreDefaultBraveArg, proxyServer, } = this.#config.resolved;
329
330
  const profileDirName = channel && channel !== 'release'
330
331
  ? `brave-profile-${channel}`
331
332
  : 'brave-profile';
332
- const executablePath = this.#serverArgs.executablePath ?? resolveBraveExecutablePath(channel);
333
- let userDataDir = this.#serverArgs.userDataDir;
333
+ const executablePath = this.#config.resolved.executablePath ??
334
+ resolveBraveExecutablePath(channel);
335
+ let userDataDir = this.#config.resolved.userDataDir;
334
336
  if (!isolated && !userDataDir) {
335
337
  userDataDir = path.join(os.homedir(), '.cache', viaCli ? 'brave-devtools-mcp-cli' : 'brave-devtools-mcp', profileDirName);
336
338
  await fs.promises.mkdir(userDataDir, {
337
339
  recursive: true,
338
340
  });
339
341
  }
340
- const args = [...(this.#serverArgs.braveArg ?? [])];
342
+ const args = [
343
+ ...(this.#config.resolved.braveArg ?? []),
344
+ ];
341
345
  if (proxyServer) {
342
346
  args.push(`--proxy-server=${proxyServer}`);
343
347
  }
@@ -370,6 +374,12 @@ export class BrowserManager {
370
374
  blocklist,
371
375
  allowlist,
372
376
  logger: puppeteerLogger,
377
+ // The entry points own signal handling and call close(), which
378
+ // closes the browser gracefully. Puppeteer's handlers would SIGKILL
379
+ // Chrome synchronously on the same signal and win the race.
380
+ handleSIGINT: false,
381
+ handleSIGTERM: false,
382
+ handleSIGHUP: false,
373
383
  });
374
384
  if (this.#options.logFile) {
375
385
  // FIXME: we are probably subscribing too late to catch startup logs. We
@@ -411,9 +421,9 @@ export class BrowserManager {
411
421
  }
412
422
  }
413
423
  async #connect() {
414
- const { browserUrl: browserURL, wsEndpoint, wsHeaders, autoConnect: isAutoConnect, userDataDir, blockedUrlPattern: blocklist, allowedUrlPattern: allowlist, categoryExtensions: enableExtensions, } = this.#serverArgs;
424
+ const { browserUrl: browserURL, wsEndpoint, wsHeaders, autoConnect: isAutoConnect, userDataDir, blockedUrlPattern: blocklist, allowedUrlPattern: allowlist, categoryExtensions: enableExtensions, } = this.#config.resolved;
415
425
  // Important: only pass channel, if autoConnect is true.
416
- const channel = isAutoConnect ? this.#serverArgs.channel : undefined;
426
+ const channel = isAutoConnect ? this.#config.resolved.channel : undefined;
417
427
  const connectOptions = {
418
428
  targetFilter: _a.makeTargetFilter(enableExtensions),
419
429
  defaultViewport: null,
@@ -427,7 +437,7 @@ export class BrowserManager {
427
437
  // periodically and terminates it on a missed pong, which rejects the
428
438
  // in-flight CDP calls and fires `disconnected` so #evictIfCurrent()
429
439
  // drops the stale handle. Without this, such a call would hang until
430
- // protocolTimeout while holding the tool mutex.
440
+ // protocolTimeout inside the context queue.
431
441
  wsOptions: {
432
442
  keepAlive: true,
433
443
  headers: wsHeaders,
@@ -475,7 +485,7 @@ export class BrowserManager {
475
485
  else {
476
486
  throw new Error('Either browserURL, wsEndpoint, channel or userDataDir must be provided');
477
487
  }
478
- logger?.('Connecting Puppeteer to ', JSON.stringify(connectOptions));
488
+ logger?.('Connecting Puppeteer to ', JSON.stringify(redactConnectOptionsForLogging(connectOptions)));
479
489
  try {
480
490
  const connected = await puppeteer.connect(connectOptions);
481
491
  logger?.('Connected Puppeteer');
@@ -0,0 +1,307 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { Script } from 'node:vm';
7
+ import { waitForSourceMaps, } from './devtools/DevtoolsUtils.js';
8
+ import { DevTools } from './third_party/index.js';
9
+ /**
10
+ * Thrown by {@link LogpointManager.setLogpoints} when some locations could
11
+ * not be bound. The other logpoints were applied; `logpoints` holds the
12
+ * resulting state.
13
+ */
14
+ export class LogpointError extends Error {
15
+ logpoints;
16
+ constructor(message, logpoints) {
17
+ super(message);
18
+ this.name = 'LogpointError';
19
+ this.logpoints = logpoints;
20
+ }
21
+ }
22
+ export const LOGPOINT_FORMAT = '<url>:<lineNumber>[:<columnNumber>] <expression>';
23
+ /**
24
+ * Parses a logpoint given as `<url>:<lineNumber>[:<columnNumber>] <expression>`.
25
+ * The url may itself contain colons (for example a port), so the location is
26
+ * the shortest prefix that ends in one or two numbers followed by whitespace.
27
+ */
28
+ export function parseLogpoint(text) {
29
+ const match = /^(\S+?):(\d+)(?::(\d+))?\s+(\S.*)$/s.exec(text.trim());
30
+ if (!match) {
31
+ throw new Error(`Invalid logpoint "${text}". Expected the format ${LOGPOINT_FORMAT}, for example "src/app.ts:42 'total', cart.total".`);
32
+ }
33
+ const [, url, lineNumber, columnNumber, expression] = match;
34
+ const logpoint = {
35
+ url,
36
+ lineNumber: Number(lineNumber),
37
+ expression,
38
+ };
39
+ if (columnNumber !== undefined) {
40
+ logpoint.columnNumber = Number(columnNumber);
41
+ }
42
+ if (logpoint.lineNumber < 1 || logpoint.columnNumber === 0) {
43
+ throw new Error(`Invalid logpoint "${text}": line and column numbers are 1-based.`);
44
+ }
45
+ return logpoint;
46
+ }
47
+ /**
48
+ * Checks that the expression parses as `console.log()` arguments. V8 is used
49
+ * for parsing both here and in the browser, so an expression that is rejected
50
+ * here would also be rejected as a breakpoint condition. The script is only
51
+ * compiled, never run.
52
+ */
53
+ export function validateExpression(expression) {
54
+ try {
55
+ new Script(`console.log(${expression})`);
56
+ }
57
+ catch (error) {
58
+ throw new Error(`The logpoint expression \`${expression}\` does not compile: ${error instanceof Error ? error.message : String(error)}. Provide the expression like arguments to console.log(...).`);
59
+ }
60
+ }
61
+ function toUserCondition(expression) {
62
+ return expression;
63
+ }
64
+ function isFromSourceMap(uiSourceCode) {
65
+ return uiSourceCode.contentType().isFromSourceMap();
66
+ }
67
+ function locationKey(url, lineNumber, columnNumber) {
68
+ return `${url}:${lineNumber}${columnNumber === undefined ? '' : `:${columnNumber}`}`;
69
+ }
70
+ function baseName(url) {
71
+ return url.slice(url.lastIndexOf('/') + 1).toLowerCase();
72
+ }
73
+ /**
74
+ * How long to wait for the source maps of the page to load before an original
75
+ * source URL is reported as unknown. Loads still pending then continue in the
76
+ * background, so a retry finds the source.
77
+ */
78
+ const SOURCE_MAP_LOAD_TIMEOUT_MS = 5_000;
79
+ /**
80
+ * Manages logpoints for a single page on top of the `BreakpointManager` of
81
+ * the page's DevTools universe.
82
+ *
83
+ * A logpoint is a DevTools breakpoint with `isLogpoint` set: its condition
84
+ * logs the expression and never pauses. The breakpoint manager resolves the
85
+ * location through source maps, substitutes minified variable names in the
86
+ * expression and keeps the breakpoint bound across reloads and rebuilt
87
+ * bundles. This class only maps the tool API (URLs and 1-based positions)
88
+ * onto workspace source codes.
89
+ */
90
+ export class LogpointManager {
91
+ #universe;
92
+ #target;
93
+ /**
94
+ * The breakpoints that are logpoints of this page. The breakpoint manager
95
+ * keeps one `Breakpoint` per normalized location, so two requested
96
+ * locations can share one entry.
97
+ */
98
+ #records = new Set();
99
+ constructor(devTools) {
100
+ this.#universe = devTools.universe;
101
+ this.#target = devTools.target;
102
+ }
103
+ get #debuggerModel() {
104
+ const model = this.#target.model(DevTools.DebuggerModel);
105
+ if (!model) {
106
+ throw new Error('The DevTools debugger model is not available.');
107
+ }
108
+ return model;
109
+ }
110
+ /**
111
+ * Makes the given logpoints the complete set of logpoints on the page:
112
+ * logpoints not in the list are removed, new ones are added and the
113
+ * expression of an existing logpoint at the same location is replaced.
114
+ * Expressions and locations are validated before anything is changed.
115
+ * Throws a {@link LogpointError} when a location has no executable code;
116
+ * the other logpoints are applied regardless.
117
+ */
118
+ async setLogpoints(desired) {
119
+ for (const options of desired) {
120
+ validateExpression(options.expression);
121
+ }
122
+ const resolved = new Map();
123
+ for (const options of desired) {
124
+ const uiSourceCode = await this.#findUISourceCode(options.url);
125
+ const key = locationKey(uiSourceCode.url(), options.lineNumber, options.columnNumber);
126
+ // The last entry for a location wins, like setting it twice would.
127
+ resolved.set(key, { options, uiSourceCode, key });
128
+ }
129
+ const kept = new Set();
130
+ const unbound = [];
131
+ for (const { options, uiSourceCode, key } of resolved.values()) {
132
+ const breakpoint = await this.#universe.breakpointManager.setBreakpoint(uiSourceCode,
133
+ // The tool API is 1-based like the DevTools UI; the model is 0-based.
134
+ options.lineNumber - 1, options.columnNumber === undefined
135
+ ? undefined
136
+ : options.columnNumber - 1, toUserCondition(options.expression),
137
+ /* enabled */ true,
138
+ /* isLogpoint */ true, "USER_ACTION" /* DevTools.BreakpointManager.BreakpointOrigin.USER_ACTION */);
139
+ if (!breakpoint) {
140
+ unbound.push(key);
141
+ continue;
142
+ }
143
+ // Wait for the breakpoint to be set in the backend so that the result
144
+ // reports whether the location resolved.
145
+ await breakpoint.updateBreakpoint();
146
+ if (!this.#records.has(breakpoint) && !breakpoint.bound()) {
147
+ await breakpoint.remove(/* keepInStorage */ false);
148
+ unbound.push(key);
149
+ continue;
150
+ }
151
+ this.#records.add(breakpoint);
152
+ kept.add(breakpoint);
153
+ }
154
+ for (const breakpoint of [...this.#records]) {
155
+ if (!kept.has(breakpoint)) {
156
+ this.#records.delete(breakpoint);
157
+ await breakpoint.remove(/* keepInStorage */ false);
158
+ }
159
+ }
160
+ this.#setLazySourceMapLoading(this.#records.size === 0);
161
+ const logpoints = this.#currentLogpoints();
162
+ if (unbound.length) {
163
+ throw new LogpointError(`No executable code at ${unbound.join(', ')} (for example a comment, type annotation or empty line, or a line not mapped to the generated script). Pick lines containing executable code. The other logpoints were applied.`, logpoints);
164
+ }
165
+ return logpoints;
166
+ }
167
+ /**
168
+ * Releases the records. The breakpoints are not removed from the backend:
169
+ * the universe is being disposed and its session detaches, which removes
170
+ * them along with the page.
171
+ */
172
+ dispose() {
173
+ this.#records.clear();
174
+ }
175
+ #currentLogpoints() {
176
+ return [...this.#records].map(breakpoint => this.#snapshot(breakpoint));
177
+ }
178
+ /**
179
+ * Reads the current state of a breakpoint, so that the result reflects
180
+ * the normalized location and the re-binding done by the breakpoint
181
+ * manager after reloads. The breakpoint manager may have moved a
182
+ * generated location to its original source, so whether the logpoint is
183
+ * source-mapped follows from the breakpoint, not from the request.
184
+ */
185
+ #snapshot(breakpoint) {
186
+ const sourceMapped = [...breakpoint.getUiSourceCodes()].some(isFromSourceMap);
187
+ const modelBreakpoint = breakpoint.modelBreakpoint(this.#debuggerModel);
188
+ const generatedLocations = [];
189
+ if (breakpoint.bound()) {
190
+ for (const position of modelBreakpoint?.currentState ?? []) {
191
+ generatedLocations.push({
192
+ url: position.url,
193
+ lineNumber: position.lineNumber + 1,
194
+ columnNumber: (position.columnNumber ?? 0) + 1,
195
+ });
196
+ }
197
+ }
198
+ const columnNumber = breakpoint.columnNumber();
199
+ return {
200
+ url: breakpoint.url(),
201
+ lineNumber: breakpoint.lineNumber() + 1,
202
+ columnNumber: columnNumber === undefined ? undefined : columnNumber + 1,
203
+ expression: breakpoint.condition(),
204
+ sourceMapped,
205
+ generatedLocations,
206
+ };
207
+ }
208
+ /**
209
+ * Source maps load lazily by default, so after a reload the original
210
+ * sources of a rebuilt bundle would not re-appear in the workspace and a
211
+ * logpoint on an original source file could not be re-bound to the new
212
+ * generated location. While logpoints exist, source maps are loaded
213
+ * eagerly instead, like DevTools does with the Sources panel open.
214
+ */
215
+ #setLazySourceMapLoading(lazy) {
216
+ this.#universe.settings
217
+ .resolve(DevTools.SourceMapManager.lazyLoadingSettingDescriptor)
218
+ .set(lazy);
219
+ }
220
+ /**
221
+ * Finds the workspace source code for a script or original source URL,
222
+ * loading source maps if needed. Throws a descriptive error, including
223
+ * sources with the same file name, when nothing matches.
224
+ */
225
+ async #findUISourceCode(url) {
226
+ // Source maps are loaded lazily in the DevTools universe and original
227
+ // sources only appear in the workspace once their source map has loaded.
228
+ let match = this.#matchUISourceCode(url);
229
+ let timedOut = false;
230
+ if (match && !isFromSourceMap(match)) {
231
+ // The script may be a transpiled file served at the URL of its original
232
+ // source (see #matchUISourceCode); its source map decides.
233
+ const matchedUrl = match.url();
234
+ const scripts = this.#debuggerModel
235
+ .scripts()
236
+ .filter(script => script.sourceURL === matchedUrl);
237
+ if (scripts.some(script => script.sourceMapURL)) {
238
+ const signal = AbortSignal.timeout(SOURCE_MAP_LOAD_TIMEOUT_MS);
239
+ await waitForSourceMaps(this.#debuggerModel, scripts, signal);
240
+ match = this.#matchUISourceCode(url);
241
+ if (signal.aborted && (!match || !isFromSourceMap(match))) {
242
+ // Setting the logpoint on the served script would use its line
243
+ // numbers instead of those of the original source.
244
+ throw new Error(`The source map of ${matchedUrl} was still loading after ${SOURCE_MAP_LOAD_TIMEOUT_MS / 1000} seconds; retry.`);
245
+ }
246
+ }
247
+ }
248
+ else if (!match) {
249
+ const signal = AbortSignal.timeout(SOURCE_MAP_LOAD_TIMEOUT_MS);
250
+ await waitForSourceMaps(this.#debuggerModel, this.#debuggerModel.scripts(), signal);
251
+ timedOut = signal.aborted;
252
+ match = this.#matchUISourceCode(url);
253
+ }
254
+ if (match) {
255
+ return match;
256
+ }
257
+ const name = baseName(url);
258
+ const similar = [...this.#pageSourceCodes()]
259
+ .map(uiSourceCode => uiSourceCode.url())
260
+ .filter(candidate => baseName(candidate) === name)
261
+ .slice(0, 5);
262
+ throw new Error(`No parsed script or original source file matches "${url}". The url must match the URL of a script as served to the browser or an original source file from a source map, exactly or as a path suffix.${timedOut ? ` Some source maps were still loading after ${SOURCE_MAP_LOAD_TIMEOUT_MS / 1000} seconds; retry if the file comes from a source map.` : ''}${similar.length ? ` Sources with the same file name: ${similar.join(', ')}.` : ''}`);
263
+ }
264
+ /** The scripts and source-map sources of the page in the workspace. */
265
+ *#pageSourceCodes() {
266
+ for (const uiSourceCode of this.#universe.workspace.uiSourceCodes()) {
267
+ const projectType = uiSourceCode.project().type();
268
+ // Content scripts of extensions are left out: they are not part of the
269
+ // page under development and would make path-suffix matches ambiguous.
270
+ if (projectType === DevTools.Workspace.Workspace.projectTypes.Network) {
271
+ yield uiSourceCode;
272
+ }
273
+ }
274
+ }
275
+ /**
276
+ * Finds the workspace source code for a script or original source URL.
277
+ * An exact URL match wins; otherwise the URL is matched as a path suffix so
278
+ * that users can pass "src/app.ts" without knowing the bundler's URL
279
+ * scheme. An ambiguous suffix match is reported as an error.
280
+ */
281
+ #matchUISourceCode(url) {
282
+ const candidates = new Map();
283
+ for (const uiSourceCode of this.#pageSourceCodes()) {
284
+ const candidateUrl = uiSourceCode.url();
285
+ if (candidateUrl !== url && !candidateUrl.endsWith('/' + url)) {
286
+ continue;
287
+ }
288
+ // Dev servers like Vite serve a transpiled file at the URL of its
289
+ // original source, with a source map pointing back at that same URL.
290
+ // The original source then has the line numbers of the file on disk,
291
+ // so it wins over the script served at the same URL.
292
+ const existing = candidates.get(candidateUrl);
293
+ if (!existing || isFromSourceMap(uiSourceCode)) {
294
+ candidates.set(candidateUrl, uiSourceCode);
295
+ }
296
+ }
297
+ const exact = candidates.get(url);
298
+ if (exact) {
299
+ return exact;
300
+ }
301
+ if (candidates.size > 1) {
302
+ throw new Error(`"${url}" matches multiple sources: ${[...candidates.keys()].join(', ')}. Specify a longer path.`);
303
+ }
304
+ return candidates.values().next().value ?? null;
305
+ }
306
+ }
307
+ //# sourceMappingURL=LogpointManager.js.map