@gabrielbryk/arc-devtools-mcp 1.3.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 (367) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +977 -0
  3. package/build/src/HeapSnapshotManager.js +148 -0
  4. package/build/src/McpContext.js +737 -0
  5. package/build/src/McpPage.js +315 -0
  6. package/build/src/McpResponse.js +990 -0
  7. package/build/src/Mutex.js +38 -0
  8. package/build/src/PageCollector.js +297 -0
  9. package/build/src/ServiceWorkerCollector.js +171 -0
  10. package/build/src/SlimMcpResponse.js +19 -0
  11. package/build/src/TextSnapshot.js +236 -0
  12. package/build/src/ToolHandler.js +223 -0
  13. package/build/src/WaitForHelper.js +190 -0
  14. package/build/src/bin/check-latest-version.js +50 -0
  15. package/build/src/bin/chrome-devtools-cli-options.js +978 -0
  16. package/build/src/bin/chrome-devtools-mcp-cli-options.js +412 -0
  17. package/build/src/bin/chrome-devtools-mcp-main.js +72 -0
  18. package/build/src/bin/chrome-devtools-mcp.js +23 -0
  19. package/build/src/bin/chrome-devtools.js +189 -0
  20. package/build/src/browser.js +253 -0
  21. package/build/src/daemon/client.js +160 -0
  22. package/build/src/daemon/daemon.js +261 -0
  23. package/build/src/daemon/types.js +7 -0
  24. package/build/src/daemon/utils.js +115 -0
  25. package/build/src/devtools/DevToolsConnectionAdapter.js +70 -0
  26. package/build/src/devtools/DevtoolsUtils.js +369 -0
  27. package/build/src/devtools/McpHostBindingAdapter.js +165 -0
  28. package/build/src/formatters/ConsoleFormatter.js +288 -0
  29. package/build/src/formatters/HeapSnapshotFormatter.js +97 -0
  30. package/build/src/formatters/IssueFormatter.js +193 -0
  31. package/build/src/formatters/NetworkFormatter.js +238 -0
  32. package/build/src/formatters/SnapshotFormatter.js +135 -0
  33. package/build/src/index.js +153 -0
  34. package/build/src/issue-descriptions.js +40 -0
  35. package/build/src/logger.js +37 -0
  36. package/build/src/polyfill.js +8 -0
  37. package/build/src/telemetry/ClearcutLogger.js +169 -0
  38. package/build/src/telemetry/WatchdogClient.js +61 -0
  39. package/build/src/telemetry/errors.js +18 -0
  40. package/build/src/telemetry/flagUtils.js +89 -0
  41. package/build/src/telemetry/metricsRegistry.js +89 -0
  42. package/build/src/telemetry/persistence.js +72 -0
  43. package/build/src/telemetry/transformation.js +134 -0
  44. package/build/src/telemetry/types.js +31 -0
  45. package/build/src/telemetry/watchdog/ClearcutSender.js +205 -0
  46. package/build/src/telemetry/watchdog/main.js +128 -0
  47. package/build/src/third_party/THIRD_PARTY_NOTICES +3637 -0
  48. package/build/src/third_party/bundled-packages.json +12 -0
  49. package/build/src/third_party/devtools-formatter-worker.js +15301 -0
  50. package/build/src/third_party/devtools-heap-snapshot-worker.js +9870 -0
  51. package/build/src/third_party/index.js +159597 -0
  52. package/build/src/third_party/issue-descriptions/CoepCoopSandboxedIframeCannotNavigateToCoopPage.md +4 -0
  53. package/build/src/third_party/issue-descriptions/CoepCorpNotSameOrigin.md +8 -0
  54. package/build/src/third_party/issue-descriptions/CoepCorpNotSameOriginAfterDefaultedToSameOriginByCoep.md +18 -0
  55. package/build/src/third_party/issue-descriptions/CoepCorpNotSameSite.md +7 -0
  56. package/build/src/third_party/issue-descriptions/CoepFrameResourceNeedsCoepHeader.md +10 -0
  57. package/build/src/third_party/issue-descriptions/CompatibilityModeQuirks.md +5 -0
  58. package/build/src/third_party/issue-descriptions/CookieAttributeValueExceedsMaxSize.md +5 -0
  59. package/build/src/third_party/issue-descriptions/LowTextContrast.md +5 -0
  60. package/build/src/third_party/issue-descriptions/SameSiteExcludeContextDowngradeRead.md +8 -0
  61. package/build/src/third_party/issue-descriptions/SameSiteExcludeContextDowngradeSet.md +8 -0
  62. package/build/src/third_party/issue-descriptions/SameSiteExcludeNavigationContextDowngrade.md +8 -0
  63. package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureErrorRead.md +8 -0
  64. package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureErrorSet.md +8 -0
  65. package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureWarnRead.md +8 -0
  66. package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureWarnSet.md +8 -0
  67. package/build/src/third_party/issue-descriptions/SameSiteUnspecifiedLaxAllowUnsafeRead.md +9 -0
  68. package/build/src/third_party/issue-descriptions/SameSiteUnspecifiedLaxAllowUnsafeSet.md +9 -0
  69. package/build/src/third_party/issue-descriptions/SameSiteWarnCrossDowngradeRead.md +8 -0
  70. package/build/src/third_party/issue-descriptions/SameSiteWarnCrossDowngradeSet.md +8 -0
  71. package/build/src/third_party/issue-descriptions/SameSiteWarnStrictLaxDowngradeStrict.md +8 -0
  72. package/build/src/third_party/issue-descriptions/arInsecureContext.md +7 -0
  73. package/build/src/third_party/issue-descriptions/arInvalidInfoHeader.md +5 -0
  74. package/build/src/third_party/issue-descriptions/arInvalidRegisterOsSourceHeader.md +5 -0
  75. package/build/src/third_party/issue-descriptions/arInvalidRegisterOsTriggerHeader.md +5 -0
  76. package/build/src/third_party/issue-descriptions/arInvalidRegisterSourceHeader.md +5 -0
  77. package/build/src/third_party/issue-descriptions/arInvalidRegisterTriggerHeader.md +5 -0
  78. package/build/src/third_party/issue-descriptions/arNavigationRegistrationUniqueScopeAlreadySet.md +5 -0
  79. package/build/src/third_party/issue-descriptions/arNavigationRegistrationWithoutTransientUserActivation.md +6 -0
  80. package/build/src/third_party/issue-descriptions/arNoRegisterOsSourceHeader.md +5 -0
  81. package/build/src/third_party/issue-descriptions/arNoRegisterOsTriggerHeader.md +5 -0
  82. package/build/src/third_party/issue-descriptions/arNoRegisterSourceHeader.md +5 -0
  83. package/build/src/third_party/issue-descriptions/arNoRegisterTriggerHeader.md +5 -0
  84. package/build/src/third_party/issue-descriptions/arNoWebOrOsSupport.md +4 -0
  85. package/build/src/third_party/issue-descriptions/arOsSourceIgnored.md +18 -0
  86. package/build/src/third_party/issue-descriptions/arOsTriggerIgnored.md +19 -0
  87. package/build/src/third_party/issue-descriptions/arPermissionPolicyDisabled.md +8 -0
  88. package/build/src/third_party/issue-descriptions/arSourceAndTriggerHeaders.md +9 -0
  89. package/build/src/third_party/issue-descriptions/arSourceIgnored.md +13 -0
  90. package/build/src/third_party/issue-descriptions/arTriggerIgnored.md +12 -0
  91. package/build/src/third_party/issue-descriptions/arUntrustworthyReportingOrigin.md +10 -0
  92. package/build/src/third_party/issue-descriptions/arWebAndOsHeaders.md +11 -0
  93. package/build/src/third_party/issue-descriptions/bounceTrackingMitigations.md +3 -0
  94. package/build/src/third_party/issue-descriptions/clientHintMetaTagAllowListInvalidOrigin.md +4 -0
  95. package/build/src/third_party/issue-descriptions/clientHintMetaTagModifiedHTML.md +4 -0
  96. package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidAllowlistItemType.md +12 -0
  97. package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidHeader.md +12 -0
  98. package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidUrlPattern.md +8 -0
  99. package/build/src/third_party/issue-descriptions/connectionAllowlistItemNotInnerList.md +12 -0
  100. package/build/src/third_party/issue-descriptions/connectionAllowlistMoreThanOneList.md +7 -0
  101. package/build/src/third_party/issue-descriptions/connectionAllowlistReportingEndpointNotToken.md +10 -0
  102. package/build/src/third_party/issue-descriptions/cookieCrossSiteRedirectDowngrade.md +12 -0
  103. package/build/src/third_party/issue-descriptions/cookieExcludeBlockedWithinRelatedWebsiteSet.md +4 -0
  104. package/build/src/third_party/issue-descriptions/cookieExcludeDomainNonAscii.md +11 -0
  105. package/build/src/third_party/issue-descriptions/cookieExcludePortMismatch.md +8 -0
  106. package/build/src/third_party/issue-descriptions/cookieExcludeSchemeMismatch.md +7 -0
  107. package/build/src/third_party/issue-descriptions/cookieExcludeThirdPartyPhaseoutRead.md +6 -0
  108. package/build/src/third_party/issue-descriptions/cookieExcludeThirdPartyPhaseoutSet.md +6 -0
  109. package/build/src/third_party/issue-descriptions/cookieWarnDomainNonAscii.md +11 -0
  110. package/build/src/third_party/issue-descriptions/cookieWarnMetadataGrantRead.md +4 -0
  111. package/build/src/third_party/issue-descriptions/cookieWarnMetadataGrantSet.md +4 -0
  112. package/build/src/third_party/issue-descriptions/cookieWarnThirdPartyPhaseoutRead.md +6 -0
  113. package/build/src/third_party/issue-descriptions/cookieWarnThirdPartyPhaseoutSet.md +6 -0
  114. package/build/src/third_party/issue-descriptions/corsAllowCredentialsRequired.md +6 -0
  115. package/build/src/third_party/issue-descriptions/corsDisabledScheme.md +7 -0
  116. package/build/src/third_party/issue-descriptions/corsDisallowedByMode.md +7 -0
  117. package/build/src/third_party/issue-descriptions/corsHeaderDisallowedByPreflightResponse.md +5 -0
  118. package/build/src/third_party/issue-descriptions/corsInvalidHeaderValues.md +7 -0
  119. package/build/src/third_party/issue-descriptions/corsLocalNetworkAccessPermissionDenied.md +19 -0
  120. package/build/src/third_party/issue-descriptions/corsMethodDisallowedByPreflightResponse.md +5 -0
  121. package/build/src/third_party/issue-descriptions/corsNoCorsRedirectModeNotFollow.md +5 -0
  122. package/build/src/third_party/issue-descriptions/corsOriginMismatch.md +6 -0
  123. package/build/src/third_party/issue-descriptions/corsPreflightResponseInvalid.md +5 -0
  124. package/build/src/third_party/issue-descriptions/corsRedirectContainsCredentials.md +5 -0
  125. package/build/src/third_party/issue-descriptions/corsWildcardOriginNotAllowed.md +8 -0
  126. package/build/src/third_party/issue-descriptions/cspEvalViolation.md +9 -0
  127. package/build/src/third_party/issue-descriptions/cspInlineViolation.md +10 -0
  128. package/build/src/third_party/issue-descriptions/cspTrustedTypesPolicyViolation.md +5 -0
  129. package/build/src/third_party/issue-descriptions/cspTrustedTypesSinkViolation.md +8 -0
  130. package/build/src/third_party/issue-descriptions/cspURLViolation.md +10 -0
  131. package/build/src/third_party/issue-descriptions/deprecation.md +3 -0
  132. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsEmptyList.md +1 -0
  133. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsHttpNotFound.md +1 -0
  134. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsInvalidContentType.md +1 -0
  135. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsInvalidResponse.md +1 -0
  136. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsNoResponse.md +1 -0
  137. package/build/src/third_party/issue-descriptions/emailVerificationRequestDnsFetchFailed.md +1 -0
  138. package/build/src/third_party/issue-descriptions/emailVerificationRequestDnsInvalidRecord.md +1 -0
  139. package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownHttpNotFound.md +1 -0
  140. package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownInvalidContentType.md +1 -0
  141. package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownInvalidResponse.md +1 -0
  142. package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownNoResponse.md +1 -0
  143. package/build/src/third_party/issue-descriptions/emailVerificationRequestInvalidEmail.md +1 -0
  144. package/build/src/third_party/issue-descriptions/emailVerificationRequestJwksHttpNotFound.md +1 -0
  145. package/build/src/third_party/issue-descriptions/emailVerificationRequestJwksInvalidResponse.md +1 -0
  146. package/build/src/third_party/issue-descriptions/emailVerificationRequestKeyBindingSigningFailed.md +1 -0
  147. package/build/src/third_party/issue-descriptions/emailVerificationRequestRpOriginIsOpaque.md +1 -0
  148. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenHttpNotFound.md +1 -0
  149. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidContentType.md +1 -0
  150. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidResponse.md +1 -0
  151. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidSdJwt.md +1 -0
  152. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenMalformedSdJwt.md +1 -0
  153. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenNoResponse.md +1 -0
  154. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidAudience.md +1 -0
  155. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidIssuedAt.md +1 -0
  156. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidNonce.md +1 -0
  157. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidSdHash.md +1 -0
  158. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidTyp.md +1 -0
  159. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingAud.md +1 -0
  160. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingCnf.md +1 -0
  161. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingIat.md +1 -0
  162. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingNonce.md +1 -0
  163. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingSdHash.md +1 -0
  164. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbSignatureFailed.md +1 -0
  165. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidEmail.md +1 -0
  166. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidEmailVerified.md +1 -0
  167. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidHolderKey.md +1 -0
  168. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidIssuedAt.md +1 -0
  169. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidIssuer.md +1 -0
  170. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtJwksMissingKeys.md +1 -0
  171. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingCnf.md +1 -0
  172. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingEmail.md +1 -0
  173. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingIat.md +1 -0
  174. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingIss.md +1 -0
  175. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtSignatureFailed.md +1 -0
  176. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtUnsupportedHeaderAlg.md +1 -0
  177. package/build/src/third_party/issue-descriptions/emailVerificationRequestUserLoggedOut.md +1 -0
  178. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownAccountsEndpointCrossOrigin.md +1 -0
  179. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownHttpNotFound.md +1 -0
  180. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownInvalidContentType.md +1 -0
  181. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownInvalidResponse.md +1 -0
  182. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownIssuanceEndpointCrossOrigin.md +1 -0
  183. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownListEmpty.md +1 -0
  184. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownMissingAccountsEndpoint.md +1 -0
  185. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownMissingIssuanceEndpoint.md +1 -0
  186. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownNoResponse.md +1 -0
  187. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownUnsupportedSigningAlgorithm.md +1 -0
  188. package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsHttpNotFound.md +1 -0
  189. package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsInvalidResponse.md +1 -0
  190. package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsNoResponse.md +1 -0
  191. package/build/src/third_party/issue-descriptions/federatedAuthRequestApprovalDeclined.md +1 -0
  192. package/build/src/third_party/issue-descriptions/federatedAuthRequestCanceled.md +1 -0
  193. package/build/src/third_party/issue-descriptions/federatedAuthRequestErrorFetchingSignin.md +1 -0
  194. package/build/src/third_party/issue-descriptions/federatedAuthRequestErrorIdToken.md +1 -0
  195. package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenHttpNotFound.md +1 -0
  196. package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenInvalidRequest.md +1 -0
  197. package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenInvalidResponse.md +1 -0
  198. package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenNoResponse.md +1 -0
  199. package/build/src/third_party/issue-descriptions/federatedAuthRequestInvalidSigninResponse.md +1 -0
  200. package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestHttpNotFound.md +1 -0
  201. package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestInvalidResponse.md +1 -0
  202. package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestNoResponse.md +1 -0
  203. package/build/src/third_party/issue-descriptions/federatedAuthRequestTooManyRequests.md +1 -0
  204. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestInvalidAccountsResponse.md +1 -0
  205. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestInvalidConfigOrWellKnown.md +1 -0
  206. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoAccountSharingPermission.md +1 -0
  207. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoApiPermission.md +1 -0
  208. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoReturningUserFromFetchedAccounts.md +1 -0
  209. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotIframe.md +1 -0
  210. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotPotentiallyTrustworthy.md +1 -0
  211. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotSameOrigin.md +1 -0
  212. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotSignedInWithIdp.md +1 -0
  213. package/build/src/third_party/issue-descriptions/fetchingPartitionedBlobURL.md +7 -0
  214. package/build/src/third_party/issue-descriptions/genericBackUINavigationWouldSkipAd.md +4 -0
  215. package/build/src/third_party/issue-descriptions/genericFormAriaLabelledByToNonExistingIdError.md +8 -0
  216. package/build/src/third_party/issue-descriptions/genericFormAutocompleteAttributeEmptyError.md +5 -0
  217. package/build/src/third_party/issue-descriptions/genericFormDuplicateIdForInputError.md +5 -0
  218. package/build/src/third_party/issue-descriptions/genericFormEmptyIdAndNameAttributesForInputError.md +5 -0
  219. package/build/src/third_party/issue-descriptions/genericFormInputAssignedAutocompleteValueToIdOrNameAttributeError.md +5 -0
  220. package/build/src/third_party/issue-descriptions/genericFormInputHasWrongButWellIntendedAutocompleteValueError.md +5 -0
  221. package/build/src/third_party/issue-descriptions/genericFormInputWithNoLabelError.md +5 -0
  222. package/build/src/third_party/issue-descriptions/genericFormLabelForMatchesNonExistingIdError.md +5 -0
  223. package/build/src/third_party/issue-descriptions/genericFormLabelForNameError.md +5 -0
  224. package/build/src/third_party/issue-descriptions/genericFormLabelHasNeitherForNorNestedInputError.md +5 -0
  225. package/build/src/third_party/issue-descriptions/genericFormModelContextMissingToolDescription.md +5 -0
  226. package/build/src/third_party/issue-descriptions/genericFormModelContextMissingToolName.md +5 -0
  227. package/build/src/third_party/issue-descriptions/genericFormModelContextParameterMissingName.md +5 -0
  228. package/build/src/third_party/issue-descriptions/genericFormModelContextParameterMissingTitleAndDescription.md +5 -0
  229. package/build/src/third_party/issue-descriptions/genericFormModelContextRequiredParameterMissingName.md +5 -0
  230. package/build/src/third_party/issue-descriptions/genericNavigationEntryMarkedSkippable.md +7 -0
  231. package/build/src/third_party/issue-descriptions/genericResponseWasBlockedByORB.md +4 -0
  232. package/build/src/third_party/issue-descriptions/heavyAd.md +10 -0
  233. package/build/src/third_party/issue-descriptions/mixedContent.md +5 -0
  234. package/build/src/third_party/issue-descriptions/navigatingPartitionedBlobURL.md +5 -0
  235. package/build/src/third_party/issue-descriptions/permissionElementActivationDisabled.md +7 -0
  236. package/build/src/third_party/issue-descriptions/permissionElementActivationDisabledWithOccluder.md +9 -0
  237. package/build/src/third_party/issue-descriptions/permissionElementActivationDisabledWithOccluderParent.md +9 -0
  238. package/build/src/third_party/issue-descriptions/permissionElementCspFrameAncestorsMissing.md +5 -0
  239. package/build/src/third_party/issue-descriptions/permissionElementFencedFrameDisallowed.md +5 -0
  240. package/build/src/third_party/issue-descriptions/permissionElementFontSizeTooLarge.md +5 -0
  241. package/build/src/third_party/issue-descriptions/permissionElementFontSizeTooSmall.md +5 -0
  242. package/build/src/third_party/issue-descriptions/permissionElementGeolocationDeprecated.md +5 -0
  243. package/build/src/third_party/issue-descriptions/permissionElementInsetBoxShadowUnsupported.md +5 -0
  244. package/build/src/third_party/issue-descriptions/permissionElementInvalidDisplayStyle.md +5 -0
  245. package/build/src/third_party/issue-descriptions/permissionElementInvalidSizeValue.md +5 -0
  246. package/build/src/third_party/issue-descriptions/permissionElementInvalidType.md +5 -0
  247. package/build/src/third_party/issue-descriptions/permissionElementInvalidTypeActivation.md +5 -0
  248. package/build/src/third_party/issue-descriptions/permissionElementLowContrast.md +5 -0
  249. package/build/src/third_party/issue-descriptions/permissionElementNonOpaqueColor.md +5 -0
  250. package/build/src/third_party/issue-descriptions/permissionElementPaddingBottomUnsupported.md +6 -0
  251. package/build/src/third_party/issue-descriptions/permissionElementPaddingRightUnsupported.md +6 -0
  252. package/build/src/third_party/issue-descriptions/permissionElementPermissionsPolicyBlocked.md +5 -0
  253. package/build/src/third_party/issue-descriptions/permissionElementRegistrationFailed.md +5 -0
  254. package/build/src/third_party/issue-descriptions/permissionElementRequestInProgress.md +5 -0
  255. package/build/src/third_party/issue-descriptions/permissionElementSecurityChecksFailed.md +5 -0
  256. package/build/src/third_party/issue-descriptions/permissionElementTypeNotSupported.md +5 -0
  257. package/build/src/third_party/issue-descriptions/permissionElementUntrustedEvent.md +7 -0
  258. package/build/src/third_party/issue-descriptions/placeholderDescriptionForInvisibleIssues.md +3 -0
  259. package/build/src/third_party/issue-descriptions/propertyRuleInvalidNameIssue.md +3 -0
  260. package/build/src/third_party/issue-descriptions/propertyRuleIssue.md +7 -0
  261. package/build/src/third_party/issue-descriptions/selectElementAccessibilityDisallowedOptGroupChild.md +7 -0
  262. package/build/src/third_party/issue-descriptions/selectElementAccessibilityDisallowedSelectChild.md +7 -0
  263. package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentAttributesSelectDescendant.md +3 -0
  264. package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentLegendChild.md +3 -0
  265. package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentOptionChild.md +3 -0
  266. package/build/src/third_party/issue-descriptions/selectElementAccessibilityNonPhrasingContentOptionChild.md +3 -0
  267. package/build/src/third_party/issue-descriptions/selectivePermissionsIntervention.md +7 -0
  268. package/build/src/third_party/issue-descriptions/sharedArrayBuffer.md +7 -0
  269. package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorCrossOriginNoCorsRequest.md +1 -0
  270. package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorDictionaryLoadFailure.md +3 -0
  271. package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorMatchingDictionaryNotUsed.md +3 -0
  272. package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorUnexpectedContentDictionaryHeader.md +1 -0
  273. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorCossOriginNoCorsRequest.md +1 -0
  274. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorDisallowedBySettings.md +1 -0
  275. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorExpiredResponse.md +3 -0
  276. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorFeatureDisabled.md +3 -0
  277. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInsufficientResources.md +1 -0
  278. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInvalidMatchField.md +1 -0
  279. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInvalidStructuredHeader.md +1 -0
  280. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInvalidTTLField.md +1 -0
  281. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNavigationRequest.md +3 -0
  282. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNoMatchField.md +1 -0
  283. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonIntegerTTLField.md +1 -0
  284. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonListMatchDestField.md +1 -0
  285. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonSecureContext.md +3 -0
  286. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonStringIdField.md +1 -0
  287. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonStringInMatchDestList.md +1 -0
  288. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonStringMatchField.md +1 -0
  289. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonTokenTypeField.md +1 -0
  290. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorRequestAborted.md +1 -0
  291. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorShuttingDown.md +1 -0
  292. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorTooLongIdField.md +3 -0
  293. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorUnsupportedType.md +3 -0
  294. package/build/src/third_party/issue-descriptions/sriInvalidSignatureHeader.md +14 -0
  295. package/build/src/third_party/issue-descriptions/sriInvalidSignatureInputHeader.md +15 -0
  296. package/build/src/third_party/issue-descriptions/sriMissingSignatureHeader.md +8 -0
  297. package/build/src/third_party/issue-descriptions/sriMissingSignatureInputHeader.md +7 -0
  298. package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsIncorrectLength.md +11 -0
  299. package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsNotByteSequence.md +14 -0
  300. package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsParameterized.md +15 -0
  301. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidComponentName.md +8 -0
  302. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidComponentType.md +13 -0
  303. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidDerivedComponentParameter.md +4 -0
  304. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidHeaderComponentParameter.md +5 -0
  305. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidParameter.md +11 -0
  306. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderKeyIdLength.md +12 -0
  307. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderMissingLabel.md +6 -0
  308. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderMissingRequiredParameters.md +8 -0
  309. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderValueMissingComponents.md +11 -0
  310. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderValueNotInnerList.md +11 -0
  311. package/build/src/third_party/issue-descriptions/sriValidationFailedIntegrityMismatch.md +10 -0
  312. package/build/src/third_party/issue-descriptions/sriValidationFailedInvalidLength.md +5 -0
  313. package/build/src/third_party/issue-descriptions/sriValidationFailedSignatureExpired.md +6 -0
  314. package/build/src/third_party/issue-descriptions/sriValidationFailedSignatureMismatch.md +11 -0
  315. package/build/src/third_party/issue-descriptions/stylesheetLateImport.md +4 -0
  316. package/build/src/third_party/issue-descriptions/stylesheetRequestFailed.md +3 -0
  317. package/build/src/third_party/issue-descriptions/summaryElementAccessibilityInteractiveContentSummaryDescendant.md +3 -0
  318. package/build/src/third_party/issue-descriptions/unencodedDigestIncorrectDigestLength.md +12 -0
  319. package/build/src/third_party/issue-descriptions/unencodedDigestIncorrectDigestType.md +17 -0
  320. package/build/src/third_party/issue-descriptions/unencodedDigestMalformedDictionary.md +14 -0
  321. package/build/src/third_party/issue-descriptions/unencodedDigestUnknownAlgorithm.md +15 -0
  322. package/build/src/third_party/lighthouse-devtools-mcp-bundle.js +61598 -0
  323. package/build/src/tools/ToolDefinition.js +73 -0
  324. package/build/src/tools/categories.js +36 -0
  325. package/build/src/tools/console.js +98 -0
  326. package/build/src/tools/emulation.js +84 -0
  327. package/build/src/tools/extensions.js +101 -0
  328. package/build/src/tools/input.js +469 -0
  329. package/build/src/tools/lighthouse.js +136 -0
  330. package/build/src/tools/memory.js +227 -0
  331. package/build/src/tools/network.js +125 -0
  332. package/build/src/tools/pages.js +419 -0
  333. package/build/src/tools/performance.js +200 -0
  334. package/build/src/tools/screencast.js +117 -0
  335. package/build/src/tools/screenshot.js +169 -0
  336. package/build/src/tools/script.js +151 -0
  337. package/build/src/tools/slim/tools.js +88 -0
  338. package/build/src/tools/snapshot.js +61 -0
  339. package/build/src/tools/thirdPartyDeveloper.js +85 -0
  340. package/build/src/tools/tools.js +56 -0
  341. package/build/src/tools/webmcp.js +66 -0
  342. package/build/src/trace-processing/parse.js +85 -0
  343. package/build/src/types.js +7 -0
  344. package/build/src/utils/check-for-updates.js +74 -0
  345. package/build/src/utils/files.js +61 -0
  346. package/build/src/utils/id.js +16 -0
  347. package/build/src/utils/keyboard.js +297 -0
  348. package/build/src/utils/pagination.js +50 -0
  349. package/build/src/utils/string.js +37 -0
  350. package/build/src/utils/types.js +7 -0
  351. package/build/src/version.js +10 -0
  352. package/package.json +100 -0
  353. package/skills/a11y-debugging/SKILL.md +89 -0
  354. package/skills/a11y-debugging/references/a11y-snippets.md +92 -0
  355. package/skills/chrome-devtools/SKILL.md +72 -0
  356. package/skills/chrome-devtools-cli/SKILL.md +153 -0
  357. package/skills/chrome-devtools-cli/references/installation.md +14 -0
  358. package/skills/debug-optimize-lcp/SKILL.md +121 -0
  359. package/skills/debug-optimize-lcp/references/elements-and-size.md +27 -0
  360. package/skills/debug-optimize-lcp/references/lcp-breakdown.md +23 -0
  361. package/skills/debug-optimize-lcp/references/lcp-snippets.md +79 -0
  362. package/skills/debug-optimize-lcp/references/optimization-strategies.md +38 -0
  363. package/skills/memory-leak-debugging/SKILL.md +50 -0
  364. package/skills/memory-leak-debugging/references/common-leaks.md +33 -0
  365. package/skills/memory-leak-debugging/references/compare_snapshots.js +109 -0
  366. package/skills/memory-leak-debugging/references/memlab.md +29 -0
  367. package/skills/troubleshooting/SKILL.md +98 -0
@@ -0,0 +1,236 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { logger } from './logger.js';
7
+ export class TextSnapshot {
8
+ static nextSnapshotId = 1;
9
+ static resetCounter() {
10
+ TextSnapshot.nextSnapshotId = 1;
11
+ }
12
+ root;
13
+ idToNode;
14
+ snapshotId;
15
+ selectedElementUid;
16
+ hasSelectedElement;
17
+ verbose;
18
+ constructor(data) {
19
+ this.root = data.root;
20
+ this.idToNode = data.idToNode;
21
+ this.snapshotId = data.snapshotId;
22
+ this.selectedElementUid = data.selectedElementUid;
23
+ this.hasSelectedElement = data.hasSelectedElement;
24
+ this.verbose = data.verbose;
25
+ }
26
+ static async create(page, options = {}) {
27
+ const verbose = options.verbose ?? false;
28
+ const rootNode = await page.pptrPage.accessibility.snapshot({
29
+ includeIframes: true,
30
+ interestingOnly: !verbose,
31
+ });
32
+ if (!rootNode) {
33
+ throw new Error('Failed to create accessibility snapshot');
34
+ }
35
+ const { uniqueBackendNodeIdToMcpId } = page;
36
+ const snapshotId = TextSnapshot.nextSnapshotId++;
37
+ // Iterate through the whole accessibility node tree and assign node ids that
38
+ // will be used for the tree serialization and mapping ids back to nodes.
39
+ let idCounter = 0;
40
+ const idToNode = new Map();
41
+ const seenUniqueIds = new Set();
42
+ const seenBackendNodeIds = new Set();
43
+ const assignIds = (node) => {
44
+ let id = '';
45
+ // @ts-expect-error untyped backendNodeId.
46
+ const backendNodeId = node.backendNodeId;
47
+ // @ts-expect-error untyped loaderId.
48
+ const uniqueBackendId = `${node.loaderId}_${backendNodeId}`;
49
+ const existingMcpId = uniqueBackendNodeIdToMcpId.get(uniqueBackendId);
50
+ if (existingMcpId !== undefined) {
51
+ // Re-use MCP exposed ID if the uniqueId is the same.
52
+ id = existingMcpId;
53
+ }
54
+ else {
55
+ // Only generate a new ID if we have not seen the node before.
56
+ id = `${snapshotId}_${idCounter++}`;
57
+ uniqueBackendNodeIdToMcpId.set(uniqueBackendId, id);
58
+ }
59
+ seenUniqueIds.add(uniqueBackendId);
60
+ seenBackendNodeIds.add(backendNodeId);
61
+ const nodeWithId = {
62
+ ...node,
63
+ id,
64
+ children: node.children
65
+ ? node.children.map(child => assignIds(child))
66
+ : [],
67
+ };
68
+ // The AXNode for an option doesn't contain its `value`.
69
+ // Therefore, set text content of the option as value.
70
+ if (node.role === 'option') {
71
+ const optionText = node.name;
72
+ if (optionText) {
73
+ nodeWithId.value = optionText.toString();
74
+ }
75
+ }
76
+ idToNode.set(nodeWithId.id, nodeWithId);
77
+ return nodeWithId;
78
+ };
79
+ const rootNodeWithId = assignIds(rootNode);
80
+ await TextSnapshot.insertExtraNodes(page, idToNode, seenUniqueIds, snapshotId, idCounter, rootNodeWithId, seenBackendNodeIds, options.extraHandles ?? []);
81
+ const snapshot = new TextSnapshot({
82
+ root: rootNodeWithId,
83
+ snapshotId: String(snapshotId),
84
+ idToNode,
85
+ hasSelectedElement: false,
86
+ verbose,
87
+ });
88
+ const data = options.devtoolsData ?? (await page.getDevToolsData());
89
+ if (data?.cdpBackendNodeId) {
90
+ snapshot.hasSelectedElement = true;
91
+ snapshot.selectedElementUid = page.resolveCdpElementId(data.cdpBackendNodeId);
92
+ }
93
+ // Clean up unique IDs that we did not see anymore.
94
+ for (const key of uniqueBackendNodeIdToMcpId.keys()) {
95
+ if (!seenUniqueIds.has(key)) {
96
+ uniqueBackendNodeIdToMcpId.delete(key);
97
+ }
98
+ }
99
+ return snapshot;
100
+ }
101
+ // ExtraHandles represent DOM nodes which might not be part of the accessibility tree, e.g. DOM nodes
102
+ // returned by third-party developer tools. We insert them into the tree by finding the closest ancestor
103
+ // in the tree and inserting the node as a child. The ancestor's child nodes are re-parented if necessary.
104
+ static async insertExtraNodes(page, idToNode, seenUniqueIds, snapshotId, idCounter, rootNodeWithId, seenBackendNodeIds, extraHandles) {
105
+ const { uniqueBackendNodeIdToMcpId } = page;
106
+ const createExtraNode = async (handle) => {
107
+ const backendNodeId = await handle.backendNodeId();
108
+ if (!backendNodeId || seenBackendNodeIds.has(backendNodeId)) {
109
+ return null;
110
+ }
111
+ const uniqueBackendId = `custom_${backendNodeId}`;
112
+ if (seenUniqueIds.has(uniqueBackendId)) {
113
+ return null;
114
+ }
115
+ seenBackendNodeIds.add(backendNodeId);
116
+ let id = '';
117
+ const mcpId = uniqueBackendNodeIdToMcpId.get(uniqueBackendId);
118
+ if (mcpId !== undefined) {
119
+ id = mcpId;
120
+ }
121
+ else {
122
+ id = `${snapshotId}_${idCounter++}`;
123
+ uniqueBackendNodeIdToMcpId.set(uniqueBackendId, id);
124
+ }
125
+ seenUniqueIds.add(uniqueBackendId);
126
+ const tagHandle = await handle.getProperty('localName');
127
+ const tagValue = await tagHandle.jsonValue();
128
+ const extraNode = {
129
+ role: tagValue,
130
+ id,
131
+ backendNodeId,
132
+ children: [],
133
+ elementHandle: async () => handle,
134
+ };
135
+ return extraNode;
136
+ };
137
+ const findAncestorNode = async (handle) => {
138
+ let ancestorHandle = await handle.evaluateHandle(el => el.parentElement);
139
+ while (ancestorHandle) {
140
+ const ancestorElement = ancestorHandle.asElement();
141
+ if (!ancestorElement) {
142
+ await ancestorHandle.dispose();
143
+ return null;
144
+ }
145
+ const ancestorBackendId = await ancestorElement.backendNodeId();
146
+ if (ancestorBackendId) {
147
+ const ancestorNode = idToNode
148
+ .values()
149
+ .find(node => node.backendNodeId === ancestorBackendId);
150
+ if (ancestorNode) {
151
+ await ancestorHandle.dispose();
152
+ return ancestorNode;
153
+ }
154
+ }
155
+ const nextHandle = await ancestorElement.evaluateHandle(el => el.parentElement);
156
+ await ancestorHandle.dispose();
157
+ ancestorHandle = nextHandle;
158
+ }
159
+ return null;
160
+ };
161
+ const findDescendantNodes = async (backendNodeId) => {
162
+ const descendantIds = new Set();
163
+ if (!backendNodeId) {
164
+ return descendantIds;
165
+ }
166
+ try {
167
+ // @ts-expect-error internal API
168
+ const client = page.pptrPage._client();
169
+ if (client) {
170
+ const { node } = await client.send('DOM.describeNode', {
171
+ backendNodeId,
172
+ depth: -1,
173
+ pierce: true,
174
+ });
175
+ const collect = (node) => {
176
+ if (node.backendNodeId && node.backendNodeId !== backendNodeId) {
177
+ descendantIds.add(node.backendNodeId);
178
+ }
179
+ if (node.children) {
180
+ for (const child of node.children) {
181
+ collect(child);
182
+ }
183
+ }
184
+ };
185
+ collect(node);
186
+ }
187
+ }
188
+ catch (e) {
189
+ logger?.(`Failed to collect descendants for backend node ${backendNodeId}`, e);
190
+ }
191
+ return descendantIds;
192
+ };
193
+ const moveChildNodes = (attachTarget, extraNode, descendantIds) => {
194
+ let firstMovedIndex = -1;
195
+ if (descendantIds.size > 0 && attachTarget.children) {
196
+ const remainingChildren = [];
197
+ for (const child of attachTarget.children) {
198
+ if (child.backendNodeId && descendantIds.has(child.backendNodeId)) {
199
+ if (firstMovedIndex === -1) {
200
+ firstMovedIndex = remainingChildren.length;
201
+ }
202
+ extraNode.children.push(child);
203
+ }
204
+ else {
205
+ remainingChildren.push(child);
206
+ }
207
+ }
208
+ attachTarget.children = remainingChildren;
209
+ }
210
+ return firstMovedIndex !== -1
211
+ ? firstMovedIndex
212
+ : attachTarget.children
213
+ ? attachTarget.children.length
214
+ : 0;
215
+ };
216
+ if (extraHandles.length) {
217
+ page.extraHandles = extraHandles;
218
+ }
219
+ const reorgInfo = [];
220
+ for (const handle of page.extraHandles) {
221
+ const extraNode = await createExtraNode(handle);
222
+ if (!extraNode) {
223
+ continue;
224
+ }
225
+ idToNode.set(extraNode.id, extraNode);
226
+ const attachTarget = (await findAncestorNode(handle)) || rootNodeWithId;
227
+ const descendantIds = await findDescendantNodes(extraNode.backendNodeId);
228
+ reorgInfo.push({ extraNode, attachTarget, descendantIds });
229
+ }
230
+ for (const { extraNode, attachTarget, descendantIds } of reorgInfo) {
231
+ const index = moveChildNodes(attachTarget, extraNode, descendantIds);
232
+ attachTarget.children.splice(index, 0, extraNode);
233
+ }
234
+ }
235
+ }
236
+ //# sourceMappingURL=TextSnapshot.js.map
@@ -0,0 +1,223 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { logger } from './logger.js';
7
+ import { McpResponse } from './McpResponse.js';
8
+ import { SlimMcpResponse } from './SlimMcpResponse.js';
9
+ import { ClearcutLogger } from './telemetry/ClearcutLogger.js';
10
+ import { bucketizeLatency } from './telemetry/transformation.js';
11
+ import { zod } from './third_party/index.js';
12
+ import { labels, OFF_BY_DEFAULT_CATEGORIES } from './tools/categories.js';
13
+ import { pageIdSchema } from './tools/ToolDefinition.js';
14
+ export function buildFlag(category) {
15
+ return `category${category.charAt(0).toUpperCase() + category.slice(1)}`;
16
+ }
17
+ function buildDisabledMessage(toolName, flag, categoryLabel) {
18
+ const reason = categoryLabel
19
+ ? `is in category ${categoryLabel} which`
20
+ : `requires experimental feature ${flag} and`;
21
+ return `Tool ${toolName} ${reason} is currently disabled. Enable it by running chrome-devtools start ${flag}=true. For more information check the README.`;
22
+ }
23
+ function getCategoryStatus(category, serverArgs) {
24
+ const categoryFlag = buildFlag(category);
25
+ const flagValue = serverArgs[categoryFlag];
26
+ const isDisabled = OFF_BY_DEFAULT_CATEGORIES.includes(category)
27
+ ? !flagValue
28
+ : flagValue === false;
29
+ if (isDisabled) {
30
+ return {
31
+ categoryFlag,
32
+ disabled: true,
33
+ };
34
+ }
35
+ return {
36
+ disabled: false,
37
+ };
38
+ }
39
+ function getConditionStatus(condition, serverArgs) {
40
+ if (condition && !serverArgs[condition]) {
41
+ return { conditionFlag: condition, disabled: true };
42
+ }
43
+ return { disabled: false };
44
+ }
45
+ function getToolStatusInfo(tool, serverArgs) {
46
+ const category = tool.annotations.category;
47
+ const categoryCheck = getCategoryStatus(category, serverArgs);
48
+ if (category && categoryCheck.disabled) {
49
+ if (!categoryCheck.categoryFlag) {
50
+ throw new Error('when the category is disabled there should always be a flag set');
51
+ }
52
+ return {
53
+ disabled: true,
54
+ reason: buildDisabledMessage(tool.name, `--${categoryCheck.categoryFlag}`, labels[category]),
55
+ };
56
+ }
57
+ for (const condition of tool.annotations.conditions || []) {
58
+ const conditionCheck = getConditionStatus(condition, serverArgs);
59
+ if (conditionCheck.disabled) {
60
+ if (!conditionCheck.conditionFlag) {
61
+ throw new Error('when the condition is disabled there should always be a flag set');
62
+ }
63
+ return {
64
+ disabled: true,
65
+ reason: buildDisabledMessage(tool.name, `--${conditionCheck.conditionFlag}`),
66
+ };
67
+ }
68
+ }
69
+ return { disabled: false };
70
+ }
71
+ function isPageScopedTool(tool) {
72
+ return 'pageScoped' in tool && tool.pageScoped === true;
73
+ }
74
+ function formatArgumentNames(names) {
75
+ return names.map(name => `"${name}"`).join(', ');
76
+ }
77
+ function buildUnknownArgumentsMessage(toolName, unknownArgumentNames, expectedArgumentNames) {
78
+ const unknownLabel = unknownArgumentNames.length === 1 ? 'argument' : 'arguments';
79
+ const expectedArguments = expectedArgumentNames.length
80
+ ? `Expected arguments: ${formatArgumentNames(expectedArgumentNames)}.`
81
+ : 'This tool does not accept any arguments.';
82
+ const correction = unknownArgumentNames.length === 1 ? 'Remove it' : 'Remove them';
83
+ return `Unknown ${unknownLabel} for tool "${toolName}": ${formatArgumentNames(unknownArgumentNames)}. ${expectedArguments} ${correction} and retry.`;
84
+ }
85
+ export class ToolHandler {
86
+ tool;
87
+ serverArgs;
88
+ getContext;
89
+ toolMutex;
90
+ inputSchema;
91
+ registeredInputSchema;
92
+ shouldRegister;
93
+ disabledReason;
94
+ constructor(tool, serverArgs, getContext, toolMutex) {
95
+ this.tool = tool;
96
+ this.serverArgs = serverArgs;
97
+ this.getContext = getContext;
98
+ this.toolMutex = toolMutex;
99
+ const { disabled, reason } = getToolStatusInfo(tool, serverArgs);
100
+ this.disabledReason = reason;
101
+ this.shouldRegister = !(disabled && !serverArgs.viaCli);
102
+ this.inputSchema =
103
+ 'pageScoped' in tool &&
104
+ tool.pageScoped &&
105
+ serverArgs.experimentalPageIdRouting &&
106
+ !serverArgs.slim
107
+ ? { ...pageIdSchema, ...tool.schema }
108
+ : tool.schema;
109
+ this.registeredInputSchema = zod.object(this.inputSchema).passthrough();
110
+ }
111
+ unknownArgumentNames(params) {
112
+ return Object.keys(params).filter(key => !Object.hasOwn(this.inputSchema, key));
113
+ }
114
+ async handle(params) {
115
+ if (this.disabledReason) {
116
+ return {
117
+ content: [
118
+ {
119
+ type: 'text',
120
+ text: this.disabledReason,
121
+ },
122
+ ],
123
+ isError: true,
124
+ };
125
+ }
126
+ const unknownArgumentNames = this.unknownArgumentNames(params);
127
+ if (unknownArgumentNames.length) {
128
+ return {
129
+ content: [
130
+ {
131
+ type: 'text',
132
+ text: buildUnknownArgumentsMessage(this.tool.name, unknownArgumentNames, Object.keys(this.inputSchema)),
133
+ },
134
+ ],
135
+ isError: true,
136
+ };
137
+ }
138
+ const guard = await this.toolMutex.acquire();
139
+ const startTime = Date.now();
140
+ let success = false;
141
+ try {
142
+ logger?.(`${this.tool.name} request: ${JSON.stringify(params, null, ' ')}`);
143
+ const context = await this.getContext();
144
+ logger?.(`${this.tool.name} context: resolved`);
145
+ await context.detectOpenDevToolsWindows();
146
+ const response = this.serverArgs.slim
147
+ ? new SlimMcpResponse(this.serverArgs)
148
+ : new McpResponse(this.serverArgs);
149
+ response.setRedactNetworkHeaders(this.serverArgs.redactNetworkHeaders);
150
+ try {
151
+ if (this.tool.verifyFilesSchema) {
152
+ for (const key of this.tool.verifyFilesSchema) {
153
+ const filePath = params[key];
154
+ await context.validatePath(filePath);
155
+ }
156
+ }
157
+ if (isPageScopedTool(this.tool)) {
158
+ const pageId = typeof params.pageId === 'number' ? params.pageId : undefined;
159
+ const page = this.serverArgs.experimentalPageIdRouting &&
160
+ pageId !== undefined &&
161
+ !this.serverArgs.slim
162
+ ? context.getPageById(pageId)
163
+ : context.getSelectedMcpPage();
164
+ response.setPage(page);
165
+ if (this.tool.blockedByDialog) {
166
+ page.throwIfDialogOpen();
167
+ }
168
+ await this.tool.handler({
169
+ params,
170
+ page,
171
+ }, response, context);
172
+ }
173
+ else {
174
+ await this.tool.handler({
175
+ params,
176
+ }, response, context);
177
+ }
178
+ }
179
+ catch (err) {
180
+ response.setError(err);
181
+ }
182
+ const { content, structuredContent } = await response.handle(this.tool.name, context, this.serverArgs.experimentalToonFormat ?? false);
183
+ const result = {
184
+ content,
185
+ };
186
+ if (response.error) {
187
+ result.isError = true;
188
+ }
189
+ success = true;
190
+ if (this.serverArgs.experimentalStructuredContent) {
191
+ result.structuredContent = structuredContent;
192
+ }
193
+ return result;
194
+ }
195
+ catch (err) {
196
+ logger?.(`${this.tool.name} error:`, err, err?.stack);
197
+ let errorText = err && 'message' in err ? err.message : String(err);
198
+ if ('cause' in err && err.cause) {
199
+ errorText += `\nCause: ${err.cause.message}`;
200
+ }
201
+ return {
202
+ content: [
203
+ {
204
+ type: 'text',
205
+ text: errorText,
206
+ },
207
+ ],
208
+ isError: true,
209
+ };
210
+ }
211
+ finally {
212
+ void ClearcutLogger.get()?.logToolInvocation({
213
+ toolName: this.tool.name,
214
+ params,
215
+ schema: this.inputSchema,
216
+ success,
217
+ latencyMs: bucketizeLatency(Date.now() - startTime),
218
+ });
219
+ guard.dispose();
220
+ }
221
+ }
222
+ }
223
+ //# sourceMappingURL=ToolHandler.js.map
@@ -0,0 +1,190 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { logger } from './logger.js';
7
+ export class WaitForHelper {
8
+ #abortController = new AbortController();
9
+ #page;
10
+ #stableDomTimeout;
11
+ #stableDomFor;
12
+ #expectNavigationIn;
13
+ #navigationTimeout;
14
+ #dialogOpened = false;
15
+ #initialUrl;
16
+ constructor(page, cpuTimeoutMultiplier, networkTimeoutMultiplier) {
17
+ this.#stableDomTimeout = 3000 * cpuTimeoutMultiplier;
18
+ this.#stableDomFor = 100 * cpuTimeoutMultiplier;
19
+ this.#expectNavigationIn = 100 * cpuTimeoutMultiplier;
20
+ this.#navigationTimeout = 3000 * networkTimeoutMultiplier;
21
+ this.#page = page;
22
+ this.#initialUrl = page.url();
23
+ }
24
+ /**
25
+ * A wrapper that executes a action and waits for
26
+ * a potential navigation, after which it waits
27
+ * for the DOM to be stable before returning.
28
+ */
29
+ async waitForStableDom() {
30
+ const stableDomObserver = await this.#page.evaluateHandle(timeout => {
31
+ let timeoutId;
32
+ function callback() {
33
+ clearTimeout(timeoutId);
34
+ timeoutId = setTimeout(() => {
35
+ domObserver.resolver.resolve();
36
+ domObserver.observer.disconnect();
37
+ }, timeout);
38
+ }
39
+ const domObserver = {
40
+ resolver: Promise.withResolvers(),
41
+ observer: new MutationObserver(callback),
42
+ };
43
+ // It's possible that the DOM is not gonna change so we
44
+ // need to start the timeout initially.
45
+ callback();
46
+ domObserver.observer.observe(document.body, {
47
+ childList: true,
48
+ subtree: true,
49
+ attributes: true,
50
+ });
51
+ return domObserver;
52
+ }, this.#stableDomFor);
53
+ this.#abortController.signal.addEventListener('abort', async () => {
54
+ try {
55
+ await stableDomObserver.evaluate(observer => {
56
+ observer.observer.disconnect();
57
+ observer.resolver.resolve();
58
+ });
59
+ await stableDomObserver.dispose();
60
+ }
61
+ catch {
62
+ // Ignored cleanup errors
63
+ }
64
+ });
65
+ return Promise.race([
66
+ stableDomObserver.evaluate(async (observer) => {
67
+ return await observer.resolver.promise;
68
+ }),
69
+ this.timeout(this.#stableDomTimeout).then(() => {
70
+ throw new Error('Timeout');
71
+ }),
72
+ ]);
73
+ }
74
+ async waitForNavigationStarted() {
75
+ // Currently Puppeteer does not have API
76
+ // For when a navigation is about to start
77
+ const navigationStartedPromise = new Promise(resolve => {
78
+ const listener = (event) => {
79
+ if ([
80
+ 'historySameDocument',
81
+ 'historyDifferentDocument',
82
+ 'sameDocument',
83
+ ].includes(event.navigationType)) {
84
+ resolve(false);
85
+ return;
86
+ }
87
+ resolve(true);
88
+ };
89
+ this.#page._client().on('Page.frameStartedNavigating', listener);
90
+ this.#abortController.signal.addEventListener('abort', () => {
91
+ resolve(false);
92
+ this.#page._client().off('Page.frameStartedNavigating', listener);
93
+ });
94
+ });
95
+ return await Promise.race([
96
+ navigationStartedPromise,
97
+ this.timeout(this.#expectNavigationIn).then(() => false),
98
+ ]);
99
+ }
100
+ timeout(time) {
101
+ return new Promise(res => {
102
+ const id = setTimeout(res, time);
103
+ this.#abortController.signal.addEventListener('abort', () => {
104
+ res();
105
+ clearTimeout(id);
106
+ });
107
+ });
108
+ }
109
+ async waitForEventsAfterAction(action, options) {
110
+ if (this.#abortController.signal.aborted) {
111
+ throw new Error("Can't re-use a WaitForHelper");
112
+ }
113
+ if (options?.handleDialog) {
114
+ const dialogHandler = (dialog) => {
115
+ this.#dialogOpened = true;
116
+ if (options.handleDialog === 'dismiss') {
117
+ void dialog.dismiss();
118
+ }
119
+ else if (options.handleDialog === 'accept') {
120
+ void dialog.accept();
121
+ }
122
+ else {
123
+ void dialog.accept(options.handleDialog);
124
+ }
125
+ };
126
+ this.#page.on('dialog', dialogHandler);
127
+ this.#abortController.signal.addEventListener('abort', () => {
128
+ this.#page.off('dialog', dialogHandler);
129
+ });
130
+ }
131
+ const navigationFinished = this.waitForNavigationStarted()
132
+ .then(navigationStated => {
133
+ if (navigationStated) {
134
+ return this.#page.waitForNavigation({
135
+ timeout: options?.timeout ?? this.#navigationTimeout,
136
+ signal: this.#abortController.signal,
137
+ });
138
+ }
139
+ return;
140
+ })
141
+ .catch(error => logger?.(error));
142
+ try {
143
+ await action();
144
+ }
145
+ catch (error) {
146
+ // Clear up pending promises
147
+ this.#abortController.abort();
148
+ throw error;
149
+ }
150
+ try {
151
+ await navigationFinished;
152
+ if (this.#dialogOpened) {
153
+ return this.#getResult();
154
+ }
155
+ // Wait for stable dom after navigation so we execute in
156
+ // the correct context
157
+ await this.waitForStableDom();
158
+ }
159
+ catch (error) {
160
+ logger?.(error);
161
+ }
162
+ finally {
163
+ this.#abortController.abort();
164
+ }
165
+ return this.#getResult();
166
+ }
167
+ #getResult() {
168
+ const urlAfterAction = this.#page.url();
169
+ return {
170
+ ...(urlAfterAction !== this.#initialUrl
171
+ ? { navigatedToUrl: urlAfterAction }
172
+ : {}),
173
+ };
174
+ }
175
+ }
176
+ export function getNetworkMultiplierFromString(condition) {
177
+ const puppeteerCondition = condition;
178
+ switch (puppeteerCondition) {
179
+ case 'Fast 4G':
180
+ return 1;
181
+ case 'Slow 4G':
182
+ return 2.5;
183
+ case 'Fast 3G':
184
+ return 5;
185
+ case 'Slow 3G':
186
+ return 10;
187
+ }
188
+ return 1;
189
+ }
190
+ //# sourceMappingURL=WaitForHelper.js.map
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { execSync } from 'node:child_process';
7
+ import fs from 'node:fs/promises';
8
+ import path from 'node:path';
9
+ import process from 'node:process';
10
+ const DEFAULT_REGISTRY = 'https://registry.npmjs.org';
11
+ function getRegistry() {
12
+ // Use the user's configured npm registry so update checks work behind
13
+ // corporate proxies and private registries. `npm config get registry`
14
+ // honors .npmrc files at every scope and respects npm_config_registry,
15
+ // so it covers direct CLI invocations as well as `npx` / `npm run`.
16
+ try {
17
+ const registry = execSync('npm config get registry', {
18
+ encoding: 'utf8',
19
+ stdio: ['ignore', 'pipe', 'ignore'],
20
+ timeout: 5000,
21
+ })
22
+ .trim()
23
+ .replace(/\/$/, '');
24
+ if (registry && registry !== 'undefined' && /^https?:\/\//.test(registry)) {
25
+ return registry;
26
+ }
27
+ }
28
+ catch {
29
+ // npm not on PATH or other errors, fall back to default.
30
+ }
31
+ return DEFAULT_REGISTRY;
32
+ }
33
+ const cachePath = process.argv[2];
34
+ if (cachePath) {
35
+ try {
36
+ const response = await fetch(`${getRegistry()}/chrome-devtools-mcp/latest`);
37
+ const data = response.ok ? await response.json() : null;
38
+ if (data &&
39
+ typeof data === 'object' &&
40
+ 'version' in data &&
41
+ typeof data.version === 'string') {
42
+ await fs.mkdir(path.dirname(cachePath), { recursive: true });
43
+ await fs.writeFile(cachePath, JSON.stringify({ version: data.version }));
44
+ }
45
+ }
46
+ catch {
47
+ // Ignore errors.
48
+ }
49
+ }
50
+ //# sourceMappingURL=check-latest-version.js.map