@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.
- package/LICENSE +202 -0
- package/README.md +977 -0
- package/build/src/HeapSnapshotManager.js +148 -0
- package/build/src/McpContext.js +737 -0
- package/build/src/McpPage.js +315 -0
- package/build/src/McpResponse.js +990 -0
- package/build/src/Mutex.js +38 -0
- package/build/src/PageCollector.js +297 -0
- package/build/src/ServiceWorkerCollector.js +171 -0
- package/build/src/SlimMcpResponse.js +19 -0
- package/build/src/TextSnapshot.js +236 -0
- package/build/src/ToolHandler.js +223 -0
- package/build/src/WaitForHelper.js +190 -0
- package/build/src/bin/check-latest-version.js +50 -0
- package/build/src/bin/chrome-devtools-cli-options.js +978 -0
- package/build/src/bin/chrome-devtools-mcp-cli-options.js +412 -0
- package/build/src/bin/chrome-devtools-mcp-main.js +72 -0
- package/build/src/bin/chrome-devtools-mcp.js +23 -0
- package/build/src/bin/chrome-devtools.js +189 -0
- package/build/src/browser.js +253 -0
- package/build/src/daemon/client.js +160 -0
- package/build/src/daemon/daemon.js +261 -0
- package/build/src/daemon/types.js +7 -0
- package/build/src/daemon/utils.js +115 -0
- package/build/src/devtools/DevToolsConnectionAdapter.js +70 -0
- package/build/src/devtools/DevtoolsUtils.js +369 -0
- package/build/src/devtools/McpHostBindingAdapter.js +165 -0
- package/build/src/formatters/ConsoleFormatter.js +288 -0
- package/build/src/formatters/HeapSnapshotFormatter.js +97 -0
- package/build/src/formatters/IssueFormatter.js +193 -0
- package/build/src/formatters/NetworkFormatter.js +238 -0
- package/build/src/formatters/SnapshotFormatter.js +135 -0
- package/build/src/index.js +153 -0
- package/build/src/issue-descriptions.js +40 -0
- package/build/src/logger.js +37 -0
- package/build/src/polyfill.js +8 -0
- package/build/src/telemetry/ClearcutLogger.js +169 -0
- package/build/src/telemetry/WatchdogClient.js +61 -0
- package/build/src/telemetry/errors.js +18 -0
- package/build/src/telemetry/flagUtils.js +89 -0
- package/build/src/telemetry/metricsRegistry.js +89 -0
- package/build/src/telemetry/persistence.js +72 -0
- package/build/src/telemetry/transformation.js +134 -0
- package/build/src/telemetry/types.js +31 -0
- package/build/src/telemetry/watchdog/ClearcutSender.js +205 -0
- package/build/src/telemetry/watchdog/main.js +128 -0
- package/build/src/third_party/THIRD_PARTY_NOTICES +3637 -0
- package/build/src/third_party/bundled-packages.json +12 -0
- package/build/src/third_party/devtools-formatter-worker.js +15301 -0
- package/build/src/third_party/devtools-heap-snapshot-worker.js +9870 -0
- package/build/src/third_party/index.js +159597 -0
- package/build/src/third_party/issue-descriptions/CoepCoopSandboxedIframeCannotNavigateToCoopPage.md +4 -0
- package/build/src/third_party/issue-descriptions/CoepCorpNotSameOrigin.md +8 -0
- package/build/src/third_party/issue-descriptions/CoepCorpNotSameOriginAfterDefaultedToSameOriginByCoep.md +18 -0
- package/build/src/third_party/issue-descriptions/CoepCorpNotSameSite.md +7 -0
- package/build/src/third_party/issue-descriptions/CoepFrameResourceNeedsCoepHeader.md +10 -0
- package/build/src/third_party/issue-descriptions/CompatibilityModeQuirks.md +5 -0
- package/build/src/third_party/issue-descriptions/CookieAttributeValueExceedsMaxSize.md +5 -0
- package/build/src/third_party/issue-descriptions/LowTextContrast.md +5 -0
- package/build/src/third_party/issue-descriptions/SameSiteExcludeContextDowngradeRead.md +8 -0
- package/build/src/third_party/issue-descriptions/SameSiteExcludeContextDowngradeSet.md +8 -0
- package/build/src/third_party/issue-descriptions/SameSiteExcludeNavigationContextDowngrade.md +8 -0
- package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureErrorRead.md +8 -0
- package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureErrorSet.md +8 -0
- package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureWarnRead.md +8 -0
- package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureWarnSet.md +8 -0
- package/build/src/third_party/issue-descriptions/SameSiteUnspecifiedLaxAllowUnsafeRead.md +9 -0
- package/build/src/third_party/issue-descriptions/SameSiteUnspecifiedLaxAllowUnsafeSet.md +9 -0
- package/build/src/third_party/issue-descriptions/SameSiteWarnCrossDowngradeRead.md +8 -0
- package/build/src/third_party/issue-descriptions/SameSiteWarnCrossDowngradeSet.md +8 -0
- package/build/src/third_party/issue-descriptions/SameSiteWarnStrictLaxDowngradeStrict.md +8 -0
- package/build/src/third_party/issue-descriptions/arInsecureContext.md +7 -0
- package/build/src/third_party/issue-descriptions/arInvalidInfoHeader.md +5 -0
- package/build/src/third_party/issue-descriptions/arInvalidRegisterOsSourceHeader.md +5 -0
- package/build/src/third_party/issue-descriptions/arInvalidRegisterOsTriggerHeader.md +5 -0
- package/build/src/third_party/issue-descriptions/arInvalidRegisterSourceHeader.md +5 -0
- package/build/src/third_party/issue-descriptions/arInvalidRegisterTriggerHeader.md +5 -0
- package/build/src/third_party/issue-descriptions/arNavigationRegistrationUniqueScopeAlreadySet.md +5 -0
- package/build/src/third_party/issue-descriptions/arNavigationRegistrationWithoutTransientUserActivation.md +6 -0
- package/build/src/third_party/issue-descriptions/arNoRegisterOsSourceHeader.md +5 -0
- package/build/src/third_party/issue-descriptions/arNoRegisterOsTriggerHeader.md +5 -0
- package/build/src/third_party/issue-descriptions/arNoRegisterSourceHeader.md +5 -0
- package/build/src/third_party/issue-descriptions/arNoRegisterTriggerHeader.md +5 -0
- package/build/src/third_party/issue-descriptions/arNoWebOrOsSupport.md +4 -0
- package/build/src/third_party/issue-descriptions/arOsSourceIgnored.md +18 -0
- package/build/src/third_party/issue-descriptions/arOsTriggerIgnored.md +19 -0
- package/build/src/third_party/issue-descriptions/arPermissionPolicyDisabled.md +8 -0
- package/build/src/third_party/issue-descriptions/arSourceAndTriggerHeaders.md +9 -0
- package/build/src/third_party/issue-descriptions/arSourceIgnored.md +13 -0
- package/build/src/third_party/issue-descriptions/arTriggerIgnored.md +12 -0
- package/build/src/third_party/issue-descriptions/arUntrustworthyReportingOrigin.md +10 -0
- package/build/src/third_party/issue-descriptions/arWebAndOsHeaders.md +11 -0
- package/build/src/third_party/issue-descriptions/bounceTrackingMitigations.md +3 -0
- package/build/src/third_party/issue-descriptions/clientHintMetaTagAllowListInvalidOrigin.md +4 -0
- package/build/src/third_party/issue-descriptions/clientHintMetaTagModifiedHTML.md +4 -0
- package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidAllowlistItemType.md +12 -0
- package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidHeader.md +12 -0
- package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidUrlPattern.md +8 -0
- package/build/src/third_party/issue-descriptions/connectionAllowlistItemNotInnerList.md +12 -0
- package/build/src/third_party/issue-descriptions/connectionAllowlistMoreThanOneList.md +7 -0
- package/build/src/third_party/issue-descriptions/connectionAllowlistReportingEndpointNotToken.md +10 -0
- package/build/src/third_party/issue-descriptions/cookieCrossSiteRedirectDowngrade.md +12 -0
- package/build/src/third_party/issue-descriptions/cookieExcludeBlockedWithinRelatedWebsiteSet.md +4 -0
- package/build/src/third_party/issue-descriptions/cookieExcludeDomainNonAscii.md +11 -0
- package/build/src/third_party/issue-descriptions/cookieExcludePortMismatch.md +8 -0
- package/build/src/third_party/issue-descriptions/cookieExcludeSchemeMismatch.md +7 -0
- package/build/src/third_party/issue-descriptions/cookieExcludeThirdPartyPhaseoutRead.md +6 -0
- package/build/src/third_party/issue-descriptions/cookieExcludeThirdPartyPhaseoutSet.md +6 -0
- package/build/src/third_party/issue-descriptions/cookieWarnDomainNonAscii.md +11 -0
- package/build/src/third_party/issue-descriptions/cookieWarnMetadataGrantRead.md +4 -0
- package/build/src/third_party/issue-descriptions/cookieWarnMetadataGrantSet.md +4 -0
- package/build/src/third_party/issue-descriptions/cookieWarnThirdPartyPhaseoutRead.md +6 -0
- package/build/src/third_party/issue-descriptions/cookieWarnThirdPartyPhaseoutSet.md +6 -0
- package/build/src/third_party/issue-descriptions/corsAllowCredentialsRequired.md +6 -0
- package/build/src/third_party/issue-descriptions/corsDisabledScheme.md +7 -0
- package/build/src/third_party/issue-descriptions/corsDisallowedByMode.md +7 -0
- package/build/src/third_party/issue-descriptions/corsHeaderDisallowedByPreflightResponse.md +5 -0
- package/build/src/third_party/issue-descriptions/corsInvalidHeaderValues.md +7 -0
- package/build/src/third_party/issue-descriptions/corsLocalNetworkAccessPermissionDenied.md +19 -0
- package/build/src/third_party/issue-descriptions/corsMethodDisallowedByPreflightResponse.md +5 -0
- package/build/src/third_party/issue-descriptions/corsNoCorsRedirectModeNotFollow.md +5 -0
- package/build/src/third_party/issue-descriptions/corsOriginMismatch.md +6 -0
- package/build/src/third_party/issue-descriptions/corsPreflightResponseInvalid.md +5 -0
- package/build/src/third_party/issue-descriptions/corsRedirectContainsCredentials.md +5 -0
- package/build/src/third_party/issue-descriptions/corsWildcardOriginNotAllowed.md +8 -0
- package/build/src/third_party/issue-descriptions/cspEvalViolation.md +9 -0
- package/build/src/third_party/issue-descriptions/cspInlineViolation.md +10 -0
- package/build/src/third_party/issue-descriptions/cspTrustedTypesPolicyViolation.md +5 -0
- package/build/src/third_party/issue-descriptions/cspTrustedTypesSinkViolation.md +8 -0
- package/build/src/third_party/issue-descriptions/cspURLViolation.md +10 -0
- package/build/src/third_party/issue-descriptions/deprecation.md +3 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsEmptyList.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsHttpNotFound.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsInvalidContentType.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsInvalidResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsNoResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestDnsFetchFailed.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestDnsInvalidRecord.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownHttpNotFound.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownInvalidContentType.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownInvalidResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownNoResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestInvalidEmail.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestJwksHttpNotFound.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestJwksInvalidResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestKeyBindingSigningFailed.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestRpOriginIsOpaque.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenHttpNotFound.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidContentType.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidSdJwt.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenMalformedSdJwt.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenNoResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidAudience.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidIssuedAt.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidNonce.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidSdHash.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidTyp.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingAud.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingCnf.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingIat.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingNonce.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingSdHash.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbSignatureFailed.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidEmail.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidEmailVerified.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidHolderKey.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidIssuedAt.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidIssuer.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtJwksMissingKeys.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingCnf.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingEmail.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingIat.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingIss.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtSignatureFailed.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtUnsupportedHeaderAlg.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestUserLoggedOut.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownAccountsEndpointCrossOrigin.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownHttpNotFound.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownInvalidContentType.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownInvalidResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownIssuanceEndpointCrossOrigin.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownListEmpty.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownMissingAccountsEndpoint.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownMissingIssuanceEndpoint.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownNoResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownUnsupportedSigningAlgorithm.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsHttpNotFound.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsInvalidResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsNoResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthRequestApprovalDeclined.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthRequestCanceled.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthRequestErrorFetchingSignin.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthRequestErrorIdToken.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenHttpNotFound.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenInvalidRequest.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenInvalidResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenNoResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthRequestInvalidSigninResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestHttpNotFound.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestInvalidResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestNoResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthRequestTooManyRequests.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestInvalidAccountsResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestInvalidConfigOrWellKnown.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoAccountSharingPermission.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoApiPermission.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoReturningUserFromFetchedAccounts.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotIframe.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotPotentiallyTrustworthy.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotSameOrigin.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotSignedInWithIdp.md +1 -0
- package/build/src/third_party/issue-descriptions/fetchingPartitionedBlobURL.md +7 -0
- package/build/src/third_party/issue-descriptions/genericBackUINavigationWouldSkipAd.md +4 -0
- package/build/src/third_party/issue-descriptions/genericFormAriaLabelledByToNonExistingIdError.md +8 -0
- package/build/src/third_party/issue-descriptions/genericFormAutocompleteAttributeEmptyError.md +5 -0
- package/build/src/third_party/issue-descriptions/genericFormDuplicateIdForInputError.md +5 -0
- package/build/src/third_party/issue-descriptions/genericFormEmptyIdAndNameAttributesForInputError.md +5 -0
- package/build/src/third_party/issue-descriptions/genericFormInputAssignedAutocompleteValueToIdOrNameAttributeError.md +5 -0
- package/build/src/third_party/issue-descriptions/genericFormInputHasWrongButWellIntendedAutocompleteValueError.md +5 -0
- package/build/src/third_party/issue-descriptions/genericFormInputWithNoLabelError.md +5 -0
- package/build/src/third_party/issue-descriptions/genericFormLabelForMatchesNonExistingIdError.md +5 -0
- package/build/src/third_party/issue-descriptions/genericFormLabelForNameError.md +5 -0
- package/build/src/third_party/issue-descriptions/genericFormLabelHasNeitherForNorNestedInputError.md +5 -0
- package/build/src/third_party/issue-descriptions/genericFormModelContextMissingToolDescription.md +5 -0
- package/build/src/third_party/issue-descriptions/genericFormModelContextMissingToolName.md +5 -0
- package/build/src/third_party/issue-descriptions/genericFormModelContextParameterMissingName.md +5 -0
- package/build/src/third_party/issue-descriptions/genericFormModelContextParameterMissingTitleAndDescription.md +5 -0
- package/build/src/third_party/issue-descriptions/genericFormModelContextRequiredParameterMissingName.md +5 -0
- package/build/src/third_party/issue-descriptions/genericNavigationEntryMarkedSkippable.md +7 -0
- package/build/src/third_party/issue-descriptions/genericResponseWasBlockedByORB.md +4 -0
- package/build/src/third_party/issue-descriptions/heavyAd.md +10 -0
- package/build/src/third_party/issue-descriptions/mixedContent.md +5 -0
- package/build/src/third_party/issue-descriptions/navigatingPartitionedBlobURL.md +5 -0
- package/build/src/third_party/issue-descriptions/permissionElementActivationDisabled.md +7 -0
- package/build/src/third_party/issue-descriptions/permissionElementActivationDisabledWithOccluder.md +9 -0
- package/build/src/third_party/issue-descriptions/permissionElementActivationDisabledWithOccluderParent.md +9 -0
- package/build/src/third_party/issue-descriptions/permissionElementCspFrameAncestorsMissing.md +5 -0
- package/build/src/third_party/issue-descriptions/permissionElementFencedFrameDisallowed.md +5 -0
- package/build/src/third_party/issue-descriptions/permissionElementFontSizeTooLarge.md +5 -0
- package/build/src/third_party/issue-descriptions/permissionElementFontSizeTooSmall.md +5 -0
- package/build/src/third_party/issue-descriptions/permissionElementGeolocationDeprecated.md +5 -0
- package/build/src/third_party/issue-descriptions/permissionElementInsetBoxShadowUnsupported.md +5 -0
- package/build/src/third_party/issue-descriptions/permissionElementInvalidDisplayStyle.md +5 -0
- package/build/src/third_party/issue-descriptions/permissionElementInvalidSizeValue.md +5 -0
- package/build/src/third_party/issue-descriptions/permissionElementInvalidType.md +5 -0
- package/build/src/third_party/issue-descriptions/permissionElementInvalidTypeActivation.md +5 -0
- package/build/src/third_party/issue-descriptions/permissionElementLowContrast.md +5 -0
- package/build/src/third_party/issue-descriptions/permissionElementNonOpaqueColor.md +5 -0
- package/build/src/third_party/issue-descriptions/permissionElementPaddingBottomUnsupported.md +6 -0
- package/build/src/third_party/issue-descriptions/permissionElementPaddingRightUnsupported.md +6 -0
- package/build/src/third_party/issue-descriptions/permissionElementPermissionsPolicyBlocked.md +5 -0
- package/build/src/third_party/issue-descriptions/permissionElementRegistrationFailed.md +5 -0
- package/build/src/third_party/issue-descriptions/permissionElementRequestInProgress.md +5 -0
- package/build/src/third_party/issue-descriptions/permissionElementSecurityChecksFailed.md +5 -0
- package/build/src/third_party/issue-descriptions/permissionElementTypeNotSupported.md +5 -0
- package/build/src/third_party/issue-descriptions/permissionElementUntrustedEvent.md +7 -0
- package/build/src/third_party/issue-descriptions/placeholderDescriptionForInvisibleIssues.md +3 -0
- package/build/src/third_party/issue-descriptions/propertyRuleInvalidNameIssue.md +3 -0
- package/build/src/third_party/issue-descriptions/propertyRuleIssue.md +7 -0
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityDisallowedOptGroupChild.md +7 -0
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityDisallowedSelectChild.md +7 -0
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentAttributesSelectDescendant.md +3 -0
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentLegendChild.md +3 -0
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentOptionChild.md +3 -0
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityNonPhrasingContentOptionChild.md +3 -0
- package/build/src/third_party/issue-descriptions/selectivePermissionsIntervention.md +7 -0
- package/build/src/third_party/issue-descriptions/sharedArrayBuffer.md +7 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorCrossOriginNoCorsRequest.md +1 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorDictionaryLoadFailure.md +3 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorMatchingDictionaryNotUsed.md +3 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorUnexpectedContentDictionaryHeader.md +1 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorCossOriginNoCorsRequest.md +1 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorDisallowedBySettings.md +1 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorExpiredResponse.md +3 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorFeatureDisabled.md +3 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInsufficientResources.md +1 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInvalidMatchField.md +1 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInvalidStructuredHeader.md +1 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInvalidTTLField.md +1 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNavigationRequest.md +3 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNoMatchField.md +1 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonIntegerTTLField.md +1 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonListMatchDestField.md +1 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonSecureContext.md +3 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonStringIdField.md +1 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonStringInMatchDestList.md +1 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonStringMatchField.md +1 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonTokenTypeField.md +1 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorRequestAborted.md +1 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorShuttingDown.md +1 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorTooLongIdField.md +3 -0
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorUnsupportedType.md +3 -0
- package/build/src/third_party/issue-descriptions/sriInvalidSignatureHeader.md +14 -0
- package/build/src/third_party/issue-descriptions/sriInvalidSignatureInputHeader.md +15 -0
- package/build/src/third_party/issue-descriptions/sriMissingSignatureHeader.md +8 -0
- package/build/src/third_party/issue-descriptions/sriMissingSignatureInputHeader.md +7 -0
- package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsIncorrectLength.md +11 -0
- package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsNotByteSequence.md +14 -0
- package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsParameterized.md +15 -0
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidComponentName.md +8 -0
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidComponentType.md +13 -0
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidDerivedComponentParameter.md +4 -0
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidHeaderComponentParameter.md +5 -0
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidParameter.md +11 -0
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderKeyIdLength.md +12 -0
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderMissingLabel.md +6 -0
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderMissingRequiredParameters.md +8 -0
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderValueMissingComponents.md +11 -0
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderValueNotInnerList.md +11 -0
- package/build/src/third_party/issue-descriptions/sriValidationFailedIntegrityMismatch.md +10 -0
- package/build/src/third_party/issue-descriptions/sriValidationFailedInvalidLength.md +5 -0
- package/build/src/third_party/issue-descriptions/sriValidationFailedSignatureExpired.md +6 -0
- package/build/src/third_party/issue-descriptions/sriValidationFailedSignatureMismatch.md +11 -0
- package/build/src/third_party/issue-descriptions/stylesheetLateImport.md +4 -0
- package/build/src/third_party/issue-descriptions/stylesheetRequestFailed.md +3 -0
- package/build/src/third_party/issue-descriptions/summaryElementAccessibilityInteractiveContentSummaryDescendant.md +3 -0
- package/build/src/third_party/issue-descriptions/unencodedDigestIncorrectDigestLength.md +12 -0
- package/build/src/third_party/issue-descriptions/unencodedDigestIncorrectDigestType.md +17 -0
- package/build/src/third_party/issue-descriptions/unencodedDigestMalformedDictionary.md +14 -0
- package/build/src/third_party/issue-descriptions/unencodedDigestUnknownAlgorithm.md +15 -0
- package/build/src/third_party/lighthouse-devtools-mcp-bundle.js +61598 -0
- package/build/src/tools/ToolDefinition.js +73 -0
- package/build/src/tools/categories.js +36 -0
- package/build/src/tools/console.js +98 -0
- package/build/src/tools/emulation.js +84 -0
- package/build/src/tools/extensions.js +101 -0
- package/build/src/tools/input.js +469 -0
- package/build/src/tools/lighthouse.js +136 -0
- package/build/src/tools/memory.js +227 -0
- package/build/src/tools/network.js +125 -0
- package/build/src/tools/pages.js +419 -0
- package/build/src/tools/performance.js +200 -0
- package/build/src/tools/screencast.js +117 -0
- package/build/src/tools/screenshot.js +169 -0
- package/build/src/tools/script.js +151 -0
- package/build/src/tools/slim/tools.js +88 -0
- package/build/src/tools/snapshot.js +61 -0
- package/build/src/tools/thirdPartyDeveloper.js +85 -0
- package/build/src/tools/tools.js +56 -0
- package/build/src/tools/webmcp.js +66 -0
- package/build/src/trace-processing/parse.js +85 -0
- package/build/src/types.js +7 -0
- package/build/src/utils/check-for-updates.js +74 -0
- package/build/src/utils/files.js +61 -0
- package/build/src/utils/id.js +16 -0
- package/build/src/utils/keyboard.js +297 -0
- package/build/src/utils/pagination.js +50 -0
- package/build/src/utils/string.js +37 -0
- package/build/src/utils/types.js +7 -0
- package/build/src/version.js +10 -0
- package/package.json +100 -0
- package/skills/a11y-debugging/SKILL.md +89 -0
- package/skills/a11y-debugging/references/a11y-snippets.md +92 -0
- package/skills/chrome-devtools/SKILL.md +72 -0
- package/skills/chrome-devtools-cli/SKILL.md +153 -0
- package/skills/chrome-devtools-cli/references/installation.md +14 -0
- package/skills/debug-optimize-lcp/SKILL.md +121 -0
- package/skills/debug-optimize-lcp/references/elements-and-size.md +27 -0
- package/skills/debug-optimize-lcp/references/lcp-breakdown.md +23 -0
- package/skills/debug-optimize-lcp/references/lcp-snippets.md +79 -0
- package/skills/debug-optimize-lcp/references/optimization-strategies.md +38 -0
- package/skills/memory-leak-debugging/SKILL.md +50 -0
- package/skills/memory-leak-debugging/references/common-leaks.md +33 -0
- package/skills/memory-leak-debugging/references/compare_snapshots.js +109 -0
- package/skills/memory-leak-debugging/references/memlab.md +29 -0
- package/skills/troubleshooting/SKILL.md +98 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import process from 'node:process';
|
|
7
|
+
import { DAEMON_CLIENT_NAME } from '../daemon/utils.js';
|
|
8
|
+
import { logger } from '../logger.js';
|
|
9
|
+
import { sanitizeParams, stripUnderscoreBeforeNumber } from './transformation.js';
|
|
10
|
+
import { McpClient, WatchdogMessageType, OsType, } from './types.js';
|
|
11
|
+
import { WatchdogClient } from './WatchdogClient.js';
|
|
12
|
+
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
13
|
+
function detectOsType() {
|
|
14
|
+
switch (process.platform) {
|
|
15
|
+
case 'win32':
|
|
16
|
+
return OsType.OS_TYPE_WINDOWS;
|
|
17
|
+
case 'darwin':
|
|
18
|
+
return OsType.OS_TYPE_MACOS;
|
|
19
|
+
case 'linux':
|
|
20
|
+
return OsType.OS_TYPE_LINUX;
|
|
21
|
+
default:
|
|
22
|
+
return OsType.OS_TYPE_UNSPECIFIED;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// Not const to allow resetting the instance for testing purposes.
|
|
26
|
+
let _clearcut_logger_instance;
|
|
27
|
+
export class ClearcutLogger {
|
|
28
|
+
#persistence;
|
|
29
|
+
#watchdog;
|
|
30
|
+
#mcpClient;
|
|
31
|
+
static initialize(options) {
|
|
32
|
+
if (_clearcut_logger_instance) {
|
|
33
|
+
throw new Error('ClearcutLogger is already initialized');
|
|
34
|
+
}
|
|
35
|
+
_clearcut_logger_instance = new ClearcutLogger(options);
|
|
36
|
+
return _clearcut_logger_instance;
|
|
37
|
+
}
|
|
38
|
+
static get() {
|
|
39
|
+
return _clearcut_logger_instance;
|
|
40
|
+
}
|
|
41
|
+
static resetForTesting() {
|
|
42
|
+
_clearcut_logger_instance = undefined;
|
|
43
|
+
}
|
|
44
|
+
constructor(options) {
|
|
45
|
+
this.#persistence = options.persistence;
|
|
46
|
+
this.#watchdog =
|
|
47
|
+
options.watchdogClient ??
|
|
48
|
+
new WatchdogClient({
|
|
49
|
+
parentPid: process.pid,
|
|
50
|
+
appVersion: options.appVersion,
|
|
51
|
+
osType: detectOsType(),
|
|
52
|
+
logFile: options.logFile,
|
|
53
|
+
clearcutEndpoint: options.clearcutEndpoint,
|
|
54
|
+
clearcutForceFlushIntervalMs: options.clearcutForceFlushIntervalMs,
|
|
55
|
+
clearcutIncludePidHeader: options.clearcutIncludePidHeader,
|
|
56
|
+
});
|
|
57
|
+
this.#mcpClient = McpClient.MCP_CLIENT_UNSPECIFIED;
|
|
58
|
+
}
|
|
59
|
+
setClientName(clientName) {
|
|
60
|
+
const lowerName = clientName.toLowerCase();
|
|
61
|
+
if (lowerName.includes('claude')) {
|
|
62
|
+
this.#mcpClient = McpClient.MCP_CLIENT_CLAUDE_CODE;
|
|
63
|
+
}
|
|
64
|
+
else if (lowerName.includes('gemini')) {
|
|
65
|
+
this.#mcpClient = McpClient.MCP_CLIENT_GEMINI_CLI;
|
|
66
|
+
}
|
|
67
|
+
else if (clientName === DAEMON_CLIENT_NAME) {
|
|
68
|
+
this.#mcpClient = McpClient.MCP_CLIENT_DT_MCP_CLI;
|
|
69
|
+
}
|
|
70
|
+
else if (lowerName.includes('openclaw')) {
|
|
71
|
+
this.#mcpClient = McpClient.MCP_CLIENT_OPENCLAW;
|
|
72
|
+
}
|
|
73
|
+
else if (lowerName.includes('codex')) {
|
|
74
|
+
this.#mcpClient = McpClient.MCP_CLIENT_CODEX;
|
|
75
|
+
}
|
|
76
|
+
else if (lowerName.includes('antigravity')) {
|
|
77
|
+
this.#mcpClient = McpClient.MCP_CLIENT_ANTIGRAVITY;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
this.#mcpClient = McpClient.MCP_CLIENT_OTHER;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async logToolInvocation(args) {
|
|
84
|
+
const sanitizedToolName = stripUnderscoreBeforeNumber(args.toolName);
|
|
85
|
+
const tool_invocation = {
|
|
86
|
+
tool_name: sanitizedToolName,
|
|
87
|
+
success: args.success,
|
|
88
|
+
latency_ms: args.latencyMs,
|
|
89
|
+
};
|
|
90
|
+
if (Object.keys(args.params).length > 0) {
|
|
91
|
+
tool_invocation.tool_params = {
|
|
92
|
+
[`${sanitizedToolName}_params`]: sanitizeParams(args.params, args.schema),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
this.#watchdog.send({
|
|
96
|
+
type: WatchdogMessageType.LOG_EVENT,
|
|
97
|
+
payload: {
|
|
98
|
+
mcp_client: this.#mcpClient,
|
|
99
|
+
tool_invocation: tool_invocation,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
async logServerStart(flagUsage) {
|
|
104
|
+
this.#watchdog.send({
|
|
105
|
+
type: WatchdogMessageType.LOG_EVENT,
|
|
106
|
+
payload: {
|
|
107
|
+
mcp_client: this.#mcpClient,
|
|
108
|
+
server_start: {
|
|
109
|
+
flag_usage: flagUsage,
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
async logDailyActiveIfNeeded() {
|
|
115
|
+
try {
|
|
116
|
+
const state = await this.#persistence.loadState();
|
|
117
|
+
if (this.#shouldLogDailyActive(state)) {
|
|
118
|
+
let daysSince = -1;
|
|
119
|
+
if (state.lastActive) {
|
|
120
|
+
const lastActiveDate = new Date(state.lastActive);
|
|
121
|
+
const now = new Date();
|
|
122
|
+
const diffTime = Math.abs(now.getTime() - lastActiveDate.getTime());
|
|
123
|
+
daysSince = Math.ceil(diffTime / MS_PER_DAY);
|
|
124
|
+
}
|
|
125
|
+
this.#watchdog.send({
|
|
126
|
+
type: WatchdogMessageType.LOG_EVENT,
|
|
127
|
+
payload: {
|
|
128
|
+
mcp_client: this.#mcpClient,
|
|
129
|
+
daily_active: {
|
|
130
|
+
days_since_last_active: daysSince,
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
state.lastActive = new Date().toISOString();
|
|
135
|
+
await this.#persistence.saveState(state);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
logger?.('Error in logDailyActiveIfNeeded:', err);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async logServerError(args) {
|
|
143
|
+
this.#watchdog.send({
|
|
144
|
+
type: WatchdogMessageType.LOG_EVENT,
|
|
145
|
+
payload: {
|
|
146
|
+
mcp_client: this.#mcpClient,
|
|
147
|
+
server_error: {
|
|
148
|
+
tool_name: args.toolName
|
|
149
|
+
? stripUnderscoreBeforeNumber(args.toolName)
|
|
150
|
+
: '',
|
|
151
|
+
error_code: args.errorCode,
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
#shouldLogDailyActive(state) {
|
|
157
|
+
if (!state.lastActive) {
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
const lastActiveDate = new Date(state.lastActive);
|
|
161
|
+
const now = new Date();
|
|
162
|
+
// Compare UTC dates
|
|
163
|
+
const isSameDay = lastActiveDate.getUTCFullYear() === now.getUTCFullYear() &&
|
|
164
|
+
lastActiveDate.getUTCMonth() === now.getUTCMonth() &&
|
|
165
|
+
lastActiveDate.getUTCDate() === now.getUTCDate();
|
|
166
|
+
return !isSameDay;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=ClearcutLogger.js.map
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { spawn } from 'node:child_process';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
import { logger } from '../logger.js';
|
|
9
|
+
export class WatchdogClient {
|
|
10
|
+
#childProcess;
|
|
11
|
+
constructor(config, options) {
|
|
12
|
+
const watchdogPath = fileURLToPath(new URL('./watchdog/main.js', import.meta.url));
|
|
13
|
+
const args = [
|
|
14
|
+
watchdogPath,
|
|
15
|
+
`--parent-pid=${config.parentPid}`,
|
|
16
|
+
`--app-version=${config.appVersion}`,
|
|
17
|
+
`--os-type=${config.osType}`,
|
|
18
|
+
];
|
|
19
|
+
if (config.logFile) {
|
|
20
|
+
args.push(`--log-file=${config.logFile}`);
|
|
21
|
+
}
|
|
22
|
+
if (config.clearcutEndpoint) {
|
|
23
|
+
args.push(`--clearcut-endpoint=${config.clearcutEndpoint}`);
|
|
24
|
+
}
|
|
25
|
+
if (config.clearcutForceFlushIntervalMs) {
|
|
26
|
+
args.push(`--clearcut-force-flush-interval-ms=${config.clearcutForceFlushIntervalMs}`);
|
|
27
|
+
}
|
|
28
|
+
if (config.clearcutIncludePidHeader) {
|
|
29
|
+
args.push('--clearcut-include-pid-header');
|
|
30
|
+
}
|
|
31
|
+
const spawner = options?.spawn ?? spawn;
|
|
32
|
+
this.#childProcess = spawner(process.execPath, args, {
|
|
33
|
+
stdio: ['pipe', 'ignore', 'ignore'],
|
|
34
|
+
detached: true,
|
|
35
|
+
});
|
|
36
|
+
this.#childProcess.unref();
|
|
37
|
+
this.#childProcess.on('error', err => {
|
|
38
|
+
logger?.('Watchdog process error:', err);
|
|
39
|
+
});
|
|
40
|
+
this.#childProcess.on('exit', (code, signal) => {
|
|
41
|
+
logger?.(`Watchdog exited with code ${code} and signal ${signal}`);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
send(message) {
|
|
45
|
+
if (this.#childProcess.stdin &&
|
|
46
|
+
!this.#childProcess.stdin.destroyed &&
|
|
47
|
+
this.#childProcess.pid) {
|
|
48
|
+
try {
|
|
49
|
+
const line = JSON.stringify(message) + '\n';
|
|
50
|
+
this.#childProcess.stdin.write(line);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
logger?.('Failed to write to watchdog stdin', err);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
logger?.('Watchdog stdin not available, dropping message');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=WatchdogClient.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*
|
|
6
|
+
* IMPORTANT:
|
|
7
|
+
* 1. this module must only contain ErrorCode.
|
|
8
|
+
* 2. do not refactor ErrorCode to elsewhere.
|
|
9
|
+
* 3. prefix new enum values with "ERROR_CODE_". This makes it easier to
|
|
10
|
+
* programmtically parse this file.
|
|
11
|
+
*/
|
|
12
|
+
export var ErrorCode;
|
|
13
|
+
(function (ErrorCode) {
|
|
14
|
+
ErrorCode[ErrorCode["ERROR_CODE_UNSPECIFIED"] = 0] = "ERROR_CODE_UNSPECIFIED";
|
|
15
|
+
ErrorCode[ErrorCode["ERROR_CODE_PERSISTENCE_FILE_READ_FAILED"] = 1] = "ERROR_CODE_PERSISTENCE_FILE_READ_FAILED";
|
|
16
|
+
ErrorCode[ErrorCode["ERROR_CODE_PERSISTENCE_FILE_SAVE_FAILED"] = 2] = "ERROR_CODE_PERSISTENCE_FILE_SAVE_FAILED";
|
|
17
|
+
})(ErrorCode || (ErrorCode = {}));
|
|
18
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { toSnakeCase } from '../utils/string.js';
|
|
7
|
+
import { stripUnderscoreBeforeNumber } from './transformation.js';
|
|
8
|
+
/**
|
|
9
|
+
* For enums, log the value as uppercase.
|
|
10
|
+
* We're going to have an enum for such flags with choices represented
|
|
11
|
+
* as an `enum` where the keys of the enum will map to the uppercase `choice`.
|
|
12
|
+
*/
|
|
13
|
+
function formatEnumChoice(snakeCaseName, choice) {
|
|
14
|
+
return stripUnderscoreBeforeNumber(`${snakeCaseName}_${choice}`).toUpperCase();
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Computes telemetry flag usage from parsed arguments and CLI options.
|
|
18
|
+
*
|
|
19
|
+
* Iterates over the defined CLI options to construct a payload:
|
|
20
|
+
* - Flag names are converted to snake_case (e.g. `browserUrl` -> `browser_url`).
|
|
21
|
+
* - A flag is logged as `{flag_name}_present` if:
|
|
22
|
+
* - It has no default value, OR
|
|
23
|
+
* - The provided value differs from the default value.
|
|
24
|
+
* - Boolean flags are logged with their literal value.
|
|
25
|
+
* - String flags with defined `choices` (Enums) are logged as their uppercase value.
|
|
26
|
+
*
|
|
27
|
+
* IMPORTANT: keep getPossibleFlagMetrics() in sync with this function.
|
|
28
|
+
*/
|
|
29
|
+
export function computeFlagUsage(args, options) {
|
|
30
|
+
const usage = {};
|
|
31
|
+
for (const [flagName, config] of Object.entries(options)) {
|
|
32
|
+
const value = args[flagName];
|
|
33
|
+
const snakeCaseName = stripUnderscoreBeforeNumber(toSnakeCase(flagName));
|
|
34
|
+
// If there isn't a default value provided for the flag,
|
|
35
|
+
// we're going to log whether it's present on the args user
|
|
36
|
+
// provided or not. If there is a default value, we only log presence
|
|
37
|
+
// if the value differs from the default, implying explicit user intent.
|
|
38
|
+
if (!('default' in config) || value !== config.default) {
|
|
39
|
+
usage[`${snakeCaseName}_present`] = value !== undefined && value !== null;
|
|
40
|
+
}
|
|
41
|
+
if (config.type === 'boolean' && typeof value === 'boolean') {
|
|
42
|
+
// For boolean options, we're going to log the value directly.
|
|
43
|
+
usage[snakeCaseName] = value;
|
|
44
|
+
}
|
|
45
|
+
else if (config.type === 'string' &&
|
|
46
|
+
typeof value === 'string' &&
|
|
47
|
+
'choices' in config &&
|
|
48
|
+
config.choices) {
|
|
49
|
+
usage[snakeCaseName] = formatEnumChoice(snakeCaseName, value);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return usage;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Computes the list of possible flag metrics based on the CLI options.
|
|
56
|
+
*
|
|
57
|
+
* IMPORTANT: keep this function in sync with computeFlagUsage().
|
|
58
|
+
*/
|
|
59
|
+
export function getPossibleFlagMetrics(options) {
|
|
60
|
+
const metrics = [];
|
|
61
|
+
for (const [flagName, config] of Object.entries(options)) {
|
|
62
|
+
const snakeCaseName = stripUnderscoreBeforeNumber(toSnakeCase(flagName));
|
|
63
|
+
// _present is always a possible metric
|
|
64
|
+
metrics.push({
|
|
65
|
+
name: `${snakeCaseName}_present`,
|
|
66
|
+
flagType: 'boolean',
|
|
67
|
+
});
|
|
68
|
+
if (config.type === 'boolean') {
|
|
69
|
+
metrics.push({
|
|
70
|
+
name: snakeCaseName,
|
|
71
|
+
flagType: 'boolean',
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
else if (config.type === 'string' &&
|
|
75
|
+
'choices' in config &&
|
|
76
|
+
config.choices) {
|
|
77
|
+
metrics.push({
|
|
78
|
+
name: snakeCaseName,
|
|
79
|
+
flagType: 'enum',
|
|
80
|
+
choices: [
|
|
81
|
+
`${snakeCaseName.toUpperCase()}_UNSPECIFIED`,
|
|
82
|
+
...config.choices.map(choice => formatEnumChoice(snakeCaseName, choice)),
|
|
83
|
+
],
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return metrics;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=flagUtils.js.map
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { transformArgName, transformArgType, getZodType, PARAM_BLOCKLIST, stripUnderscoreBeforeNumber, } from './transformation.js';
|
|
7
|
+
/**
|
|
8
|
+
* Validates that all values in an enum are of the homogeneous primitive type.
|
|
9
|
+
* Returns the primitive type string. Throws an error if heterogeneous.
|
|
10
|
+
*/
|
|
11
|
+
export function validateEnumHomogeneity(values) {
|
|
12
|
+
const firstType = typeof values[0];
|
|
13
|
+
for (const val of values) {
|
|
14
|
+
if (typeof val !== firstType) {
|
|
15
|
+
throw new Error('Heterogeneous enum types found');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return firstType;
|
|
19
|
+
}
|
|
20
|
+
export function applyToExistingMetrics(existing, update) {
|
|
21
|
+
const updated = applyToExisting(existing, update);
|
|
22
|
+
const existingByName = new Map(existing.map(tool => [tool.name, tool]));
|
|
23
|
+
const updatedByName = new Map(update.map(tool => [tool.name, tool]));
|
|
24
|
+
return updated.map(tool => {
|
|
25
|
+
const existingTool = existingByName.get(tool.name);
|
|
26
|
+
const updatedTool = updatedByName.get(tool.name);
|
|
27
|
+
// If the tool still exists in the update, we will update the args.
|
|
28
|
+
if (existingTool && updatedTool) {
|
|
29
|
+
const updatedArgs = applyToExisting(existingTool.args, updatedTool.args);
|
|
30
|
+
return { ...tool, args: updatedArgs };
|
|
31
|
+
}
|
|
32
|
+
return tool;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
export function applyToExisting(existing, update) {
|
|
36
|
+
const existingNames = new Set(existing.map(item => item.name));
|
|
37
|
+
const updatedNames = new Set(update.map(item => item.name));
|
|
38
|
+
const result = [];
|
|
39
|
+
// Keep the original ordering.
|
|
40
|
+
for (const entry of existing) {
|
|
41
|
+
const toAdd = { ...entry };
|
|
42
|
+
if (!updatedNames.has(entry.name)) {
|
|
43
|
+
toAdd.isDeprecated = true;
|
|
44
|
+
}
|
|
45
|
+
result.push(toAdd);
|
|
46
|
+
}
|
|
47
|
+
// New entries must be added to the very back of the list.
|
|
48
|
+
for (const entry of update) {
|
|
49
|
+
if (!existingNames.has(entry.name)) {
|
|
50
|
+
result.push({ ...entry });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Generates tool metrics from tool definitions.
|
|
57
|
+
*/
|
|
58
|
+
export function generateToolMetrics(tools) {
|
|
59
|
+
return tools.map(tool => {
|
|
60
|
+
const args = [];
|
|
61
|
+
for (const [name, schema] of Object.entries(tool.schema)) {
|
|
62
|
+
if (PARAM_BLOCKLIST.has(name)) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const zodType = getZodType(schema);
|
|
66
|
+
const transformedName = transformArgName(zodType, name);
|
|
67
|
+
let argType = transformArgType(zodType);
|
|
68
|
+
if (argType === 'enum') {
|
|
69
|
+
let values;
|
|
70
|
+
if (schema._def.values?.length > 0) {
|
|
71
|
+
values = schema._def.values;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
values = schema._def.innerType._def.values;
|
|
75
|
+
}
|
|
76
|
+
argType = validateEnumHomogeneity(values);
|
|
77
|
+
}
|
|
78
|
+
args.push({
|
|
79
|
+
name: transformedName,
|
|
80
|
+
argType,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
name: stripUnderscoreBeforeNumber(tool.name),
|
|
85
|
+
args,
|
|
86
|
+
};
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=metricsRegistry.js.map
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import fs from 'node:fs/promises';
|
|
7
|
+
import os from 'node:os';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import process from 'node:process';
|
|
10
|
+
import { logger } from '../logger.js';
|
|
11
|
+
import { ClearcutLogger } from './ClearcutLogger.js';
|
|
12
|
+
import { ErrorCode } from './errors.js';
|
|
13
|
+
const STATE_FILE_NAME = 'telemetry_state.json';
|
|
14
|
+
function getDataFolder() {
|
|
15
|
+
const homedir = os.homedir();
|
|
16
|
+
const { env } = process;
|
|
17
|
+
const name = 'chrome-devtools-mcp';
|
|
18
|
+
if (process.platform === 'darwin') {
|
|
19
|
+
return path.join(homedir, 'Library', 'Application Support', name);
|
|
20
|
+
}
|
|
21
|
+
if (process.platform === 'win32') {
|
|
22
|
+
const localAppData = env.LOCALAPPDATA || path.join(homedir, 'AppData', 'Local');
|
|
23
|
+
return path.join(localAppData, name, 'Data');
|
|
24
|
+
}
|
|
25
|
+
return path.join(env.XDG_DATA_HOME || path.join(homedir, '.local', 'share'), name);
|
|
26
|
+
}
|
|
27
|
+
export class FilePersistence {
|
|
28
|
+
#dataFolder;
|
|
29
|
+
constructor(dataFolderOverride) {
|
|
30
|
+
this.#dataFolder = dataFolderOverride ?? getDataFolder();
|
|
31
|
+
}
|
|
32
|
+
async loadState() {
|
|
33
|
+
const filePath = path.join(this.#dataFolder, STATE_FILE_NAME);
|
|
34
|
+
try {
|
|
35
|
+
await fs.access(filePath);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// File doesn't exist. Not an error because new users do not have the state file.
|
|
39
|
+
return {
|
|
40
|
+
lastActive: '',
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
45
|
+
return JSON.parse(content);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
logger?.(`Failed to read telemetry state from ${filePath}:`, error);
|
|
49
|
+
void ClearcutLogger.get()?.logServerError({
|
|
50
|
+
errorCode: ErrorCode.ERROR_CODE_PERSISTENCE_FILE_READ_FAILED,
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
lastActive: '',
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async saveState(state) {
|
|
58
|
+
const filePath = path.join(this.#dataFolder, STATE_FILE_NAME);
|
|
59
|
+
try {
|
|
60
|
+
await fs.mkdir(this.#dataFolder, { recursive: true });
|
|
61
|
+
await fs.writeFile(filePath, JSON.stringify(state, null, 2), 'utf-8');
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
// Ignore errors during state saving to avoid crashing the server
|
|
65
|
+
logger?.(`Failed to save telemetry state to ${filePath}:`, error);
|
|
66
|
+
void ClearcutLogger.get()?.logServerError({
|
|
67
|
+
errorCode: ErrorCode.ERROR_CODE_PERSISTENCE_FILE_SAVE_FAILED,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=persistence.js.map
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
const LATENCY_BUCKETS = [50, 100, 250, 500, 1000, 2500, 5000, 10000];
|
|
7
|
+
export function bucketizeLatency(latencyMs) {
|
|
8
|
+
for (const bucket of LATENCY_BUCKETS) {
|
|
9
|
+
if (latencyMs <= bucket) {
|
|
10
|
+
return bucket;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return LATENCY_BUCKETS[LATENCY_BUCKETS.length - 1];
|
|
14
|
+
}
|
|
15
|
+
export const PARAM_BLOCKLIST = new Set(['uid', 'reqid', 'msgid']);
|
|
16
|
+
const SUPPORTED_ZOD_TYPES = [
|
|
17
|
+
'ZodString',
|
|
18
|
+
'ZodNumber',
|
|
19
|
+
'ZodBoolean',
|
|
20
|
+
'ZodArray',
|
|
21
|
+
'ZodEnum',
|
|
22
|
+
];
|
|
23
|
+
function isZodType(type) {
|
|
24
|
+
return SUPPORTED_ZOD_TYPES.includes(type);
|
|
25
|
+
}
|
|
26
|
+
export function getZodType(zodType) {
|
|
27
|
+
const def = zodType._def;
|
|
28
|
+
const typeName = def.typeName;
|
|
29
|
+
if (typeName === 'ZodOptional' ||
|
|
30
|
+
typeName === 'ZodDefault' ||
|
|
31
|
+
typeName === 'ZodNullable') {
|
|
32
|
+
return getZodType(def.innerType);
|
|
33
|
+
}
|
|
34
|
+
if (typeName === 'ZodEffects') {
|
|
35
|
+
return getZodType(def.schema);
|
|
36
|
+
}
|
|
37
|
+
if (isZodType(typeName)) {
|
|
38
|
+
return typeName;
|
|
39
|
+
}
|
|
40
|
+
throw new Error(`Unsupported zod type for tool parameter: ${typeName}`);
|
|
41
|
+
}
|
|
42
|
+
export function stripUnderscoreBeforeNumber(name) {
|
|
43
|
+
return name.replace(/_([0-9])/g, '$1');
|
|
44
|
+
}
|
|
45
|
+
export function transformArgName(zodType, name) {
|
|
46
|
+
const snakeCaseName = name.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
|
|
47
|
+
let transformed;
|
|
48
|
+
if (zodType === 'ZodString') {
|
|
49
|
+
transformed = `${snakeCaseName}_length`;
|
|
50
|
+
}
|
|
51
|
+
else if (zodType === 'ZodArray') {
|
|
52
|
+
transformed = `${snakeCaseName}_count`;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
transformed = snakeCaseName;
|
|
56
|
+
}
|
|
57
|
+
return stripUnderscoreBeforeNumber(transformed);
|
|
58
|
+
}
|
|
59
|
+
export function transformArgType(zodType) {
|
|
60
|
+
if (zodType === 'ZodString' || zodType === 'ZodArray') {
|
|
61
|
+
return 'number';
|
|
62
|
+
}
|
|
63
|
+
switch (zodType) {
|
|
64
|
+
case 'ZodNumber':
|
|
65
|
+
return 'number';
|
|
66
|
+
case 'ZodBoolean':
|
|
67
|
+
return 'boolean';
|
|
68
|
+
case 'ZodEnum':
|
|
69
|
+
return 'enum';
|
|
70
|
+
default:
|
|
71
|
+
throw new Error(`Unsupported zod type for tool parameter: ${zodType}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const BUCKETS = [
|
|
75
|
+
0, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000,
|
|
76
|
+
];
|
|
77
|
+
function bucketize(value) {
|
|
78
|
+
for (const bucket of BUCKETS) {
|
|
79
|
+
if (bucket >= value) {
|
|
80
|
+
return bucket;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return BUCKETS[BUCKETS.length - 1];
|
|
84
|
+
}
|
|
85
|
+
function transformValue(zodType, value) {
|
|
86
|
+
if (zodType === 'ZodString') {
|
|
87
|
+
return bucketize(value.length);
|
|
88
|
+
}
|
|
89
|
+
else if (zodType === 'ZodArray') {
|
|
90
|
+
return value.length;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function hasEquivalentType(zodType, value) {
|
|
97
|
+
if (zodType === 'ZodString') {
|
|
98
|
+
return typeof value === 'string';
|
|
99
|
+
}
|
|
100
|
+
else if (zodType === 'ZodArray') {
|
|
101
|
+
return Array.isArray(value);
|
|
102
|
+
}
|
|
103
|
+
else if (zodType === 'ZodNumber') {
|
|
104
|
+
return typeof value === 'number';
|
|
105
|
+
}
|
|
106
|
+
else if (zodType === 'ZodBoolean') {
|
|
107
|
+
return typeof value === 'boolean';
|
|
108
|
+
}
|
|
109
|
+
else if (zodType === 'ZodEnum') {
|
|
110
|
+
return (typeof value === 'string' ||
|
|
111
|
+
typeof value === 'number' ||
|
|
112
|
+
typeof value === 'boolean');
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
export function sanitizeParams(params, schema) {
|
|
119
|
+
const transformed = {};
|
|
120
|
+
for (const [name, value] of Object.entries(params)) {
|
|
121
|
+
if (PARAM_BLOCKLIST.has(name)) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
const zodType = getZodType(schema[name]);
|
|
125
|
+
if (!hasEquivalentType(zodType, value)) {
|
|
126
|
+
throw new Error(`parameter ${name} has type ${zodType} but value ${value} is not of equivalent type`);
|
|
127
|
+
}
|
|
128
|
+
const transformedName = transformArgName(zodType, name);
|
|
129
|
+
const transformedValue = transformValue(zodType, value);
|
|
130
|
+
transformed[transformedName] = transformedValue;
|
|
131
|
+
}
|
|
132
|
+
return transformed;
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=transformation.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
// Enums
|
|
7
|
+
export var OsType;
|
|
8
|
+
(function (OsType) {
|
|
9
|
+
OsType[OsType["OS_TYPE_UNSPECIFIED"] = 0] = "OS_TYPE_UNSPECIFIED";
|
|
10
|
+
OsType[OsType["OS_TYPE_WINDOWS"] = 1] = "OS_TYPE_WINDOWS";
|
|
11
|
+
OsType[OsType["OS_TYPE_MACOS"] = 2] = "OS_TYPE_MACOS";
|
|
12
|
+
OsType[OsType["OS_TYPE_LINUX"] = 3] = "OS_TYPE_LINUX";
|
|
13
|
+
})(OsType || (OsType = {}));
|
|
14
|
+
export var McpClient;
|
|
15
|
+
(function (McpClient) {
|
|
16
|
+
McpClient[McpClient["MCP_CLIENT_UNSPECIFIED"] = 0] = "MCP_CLIENT_UNSPECIFIED";
|
|
17
|
+
McpClient[McpClient["MCP_CLIENT_CLAUDE_CODE"] = 1] = "MCP_CLIENT_CLAUDE_CODE";
|
|
18
|
+
McpClient[McpClient["MCP_CLIENT_GEMINI_CLI"] = 2] = "MCP_CLIENT_GEMINI_CLI";
|
|
19
|
+
McpClient[McpClient["MCP_CLIENT_DT_MCP_CLI"] = 4] = "MCP_CLIENT_DT_MCP_CLI";
|
|
20
|
+
McpClient[McpClient["MCP_CLIENT_OPENCLAW"] = 5] = "MCP_CLIENT_OPENCLAW";
|
|
21
|
+
McpClient[McpClient["MCP_CLIENT_CODEX"] = 6] = "MCP_CLIENT_CODEX";
|
|
22
|
+
McpClient[McpClient["MCP_CLIENT_ANTIGRAVITY"] = 7] = "MCP_CLIENT_ANTIGRAVITY";
|
|
23
|
+
McpClient[McpClient["MCP_CLIENT_OTHER"] = 3] = "MCP_CLIENT_OTHER";
|
|
24
|
+
})(McpClient || (McpClient = {}));
|
|
25
|
+
// IPC types for messages between the main process and the
|
|
26
|
+
// telemetry watchdog process.
|
|
27
|
+
export var WatchdogMessageType;
|
|
28
|
+
(function (WatchdogMessageType) {
|
|
29
|
+
WatchdogMessageType["LOG_EVENT"] = "log-event";
|
|
30
|
+
})(WatchdogMessageType || (WatchdogMessageType = {}));
|
|
31
|
+
//# sourceMappingURL=types.js.map
|