brave-mcp 0.1.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 +802 -0
- package/build/src/DevToolsConnectionAdapter.js +69 -0
- package/build/src/DevtoolsUtils.js +294 -0
- package/build/src/McpContext.js +676 -0
- package/build/src/McpPage.js +108 -0
- package/build/src/McpResponse.js +718 -0
- package/build/src/Mutex.js +37 -0
- package/build/src/PageCollector.js +310 -0
- package/build/src/SlimMcpResponse.js +18 -0
- package/build/src/WaitForHelper.js +153 -0
- package/build/src/bin/brave-devtools-cli-options.js +651 -0
- package/build/src/bin/brave-devtools-mcp-cli-options.js +312 -0
- package/build/src/bin/brave-devtools-mcp-main.js +35 -0
- package/build/src/bin/brave-devtools-mcp.js +22 -0
- package/build/src/bin/brave-devtools.js +190 -0
- package/build/src/bin/check-latest-version.js +25 -0
- package/build/src/bin/cliDefinitions.js +615 -0
- package/build/src/browser.js +295 -0
- package/build/src/daemon/client.js +152 -0
- package/build/src/daemon/daemon.js +202 -0
- package/build/src/daemon/types.js +6 -0
- package/build/src/daemon/utils.js +109 -0
- package/build/src/formatters/ConsoleFormatter.js +241 -0
- package/build/src/formatters/IssueFormatter.js +192 -0
- package/build/src/formatters/NetworkFormatter.js +218 -0
- package/build/src/formatters/SnapshotFormatter.js +134 -0
- package/build/src/index.js +216 -0
- package/build/src/issue-descriptions.js +39 -0
- package/build/src/logger.js +36 -0
- package/build/src/polyfill.js +7 -0
- package/build/src/telemetry/ClearcutLogger.js +234 -0
- package/build/src/telemetry/WatchdogClient.js +60 -0
- package/build/src/telemetry/flagUtils.js +45 -0
- package/build/src/telemetry/metricUtils.js +14 -0
- package/build/src/telemetry/persistence.js +53 -0
- package/build/src/telemetry/toolMetricsUtils.js +88 -0
- package/build/src/telemetry/types.js +38 -0
- package/build/src/telemetry/watchdog/ClearcutSender.js +203 -0
- package/build/src/telemetry/watchdog/main.js +127 -0
- package/build/src/third_party/devtools-formatter-worker.js +7 -0
- package/build/src/third_party/index.js +28 -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/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/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/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 +59418 -0
- package/build/src/tools/ToolDefinition.js +72 -0
- package/build/src/tools/categories.js +26 -0
- package/build/src/tools/console.js +85 -0
- package/build/src/tools/emulation.js +55 -0
- package/build/src/tools/extensions.js +96 -0
- package/build/src/tools/inPage.js +105 -0
- package/build/src/tools/input.js +376 -0
- package/build/src/tools/lighthouse.js +123 -0
- package/build/src/tools/memory.js +28 -0
- package/build/src/tools/network.js +120 -0
- package/build/src/tools/pages.js +336 -0
- package/build/src/tools/performance.js +190 -0
- package/build/src/tools/screencast.js +79 -0
- package/build/src/tools/screenshot.js +84 -0
- package/build/src/tools/script.js +125 -0
- package/build/src/tools/slim/tools.js +81 -0
- package/build/src/tools/snapshot.js +56 -0
- package/build/src/tools/tools.js +53 -0
- package/build/src/trace-processing/parse.js +84 -0
- package/build/src/types.js +6 -0
- package/build/src/utils/ExtensionRegistry.js +35 -0
- package/build/src/utils/check-for-updates.js +72 -0
- package/build/src/utils/files.js +19 -0
- package/build/src/utils/keyboard.js +296 -0
- package/build/src/utils/pagination.js +49 -0
- package/build/src/utils/string.js +36 -0
- package/build/src/utils/types.js +6 -0
- package/build/src/version.js +6 -0
- package/package.json +87 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import fs from 'node:fs';
|
|
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
|
+
export const DAEMON_SCRIPT_PATH = path.join(import.meta.dirname, 'daemon.js');
|
|
12
|
+
export const INDEX_SCRIPT_PATH = path.join(import.meta.dirname, '..', 'bin', 'brave-devtools-mcp.js');
|
|
13
|
+
const APP_NAME = 'brave-devtools-mcp';
|
|
14
|
+
export const DAEMON_CLIENT_NAME = 'brave-devtools-cli-daemon';
|
|
15
|
+
// Using these paths due to strict limits on the POSIX socket path length.
|
|
16
|
+
export function getSocketPath() {
|
|
17
|
+
const uid = os.userInfo().uid;
|
|
18
|
+
if (IS_WINDOWS) {
|
|
19
|
+
// Windows uses Named Pipes, not file paths.
|
|
20
|
+
// This format is required for server.listen()
|
|
21
|
+
return path.join('\\\\.\\pipe', APP_NAME, 'server.sock');
|
|
22
|
+
}
|
|
23
|
+
// 1. Try XDG_RUNTIME_DIR (Linux standard, sometimes macOS)
|
|
24
|
+
if (process.env.XDG_RUNTIME_DIR) {
|
|
25
|
+
return path.join(process.env.XDG_RUNTIME_DIR, APP_NAME, 'server.sock');
|
|
26
|
+
}
|
|
27
|
+
// 2. macOS/Unix Fallback: Use /tmp/
|
|
28
|
+
// We use /tmp/ because it is much shorter than ~/Library/Application Support/
|
|
29
|
+
// and keeps us well under the 104-character limit.
|
|
30
|
+
return path.join('/tmp', `${APP_NAME}-${uid}.sock`);
|
|
31
|
+
}
|
|
32
|
+
export function getRuntimeHome() {
|
|
33
|
+
const platform = os.platform();
|
|
34
|
+
const uid = os.userInfo().uid;
|
|
35
|
+
// 1. Check for the modern Unix standard
|
|
36
|
+
if (process.env.XDG_RUNTIME_DIR) {
|
|
37
|
+
return path.join(process.env.XDG_RUNTIME_DIR, APP_NAME);
|
|
38
|
+
}
|
|
39
|
+
// 2. Fallback for macOS and older Linux
|
|
40
|
+
if (platform === 'darwin' || platform === 'linux') {
|
|
41
|
+
// /tmp is cleared on boot, making it perfect for PIDs
|
|
42
|
+
return path.join('/tmp', `${APP_NAME}-${uid}`);
|
|
43
|
+
}
|
|
44
|
+
// 3. Windows Fallback
|
|
45
|
+
return path.join(os.tmpdir(), APP_NAME);
|
|
46
|
+
}
|
|
47
|
+
export const IS_WINDOWS = os.platform() === 'win32';
|
|
48
|
+
export function getPidFilePath() {
|
|
49
|
+
const runtimeDir = getRuntimeHome();
|
|
50
|
+
return path.join(runtimeDir, 'daemon.pid');
|
|
51
|
+
}
|
|
52
|
+
export function getDaemonPid() {
|
|
53
|
+
try {
|
|
54
|
+
const pidFile = getPidFilePath();
|
|
55
|
+
logger(`Daemon pid file ${pidFile}`);
|
|
56
|
+
if (!fs.existsSync(pidFile)) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
const pidContent = fs.readFileSync(pidFile, 'utf-8');
|
|
60
|
+
const pid = parseInt(pidContent.trim(), 10);
|
|
61
|
+
logger(`Daemon pid: ${pid}`);
|
|
62
|
+
if (isNaN(pid)) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
return pid;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
export function isDaemonRunning(pid = getDaemonPid()) {
|
|
72
|
+
if (pid) {
|
|
73
|
+
try {
|
|
74
|
+
process.kill(pid, 0); // Throws if process doesn't exist
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// Process is dead, stale PID file. Proceed with startup.
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
export function serializeArgs(options, argv) {
|
|
84
|
+
const args = [];
|
|
85
|
+
for (const key of Object.keys(options)) {
|
|
86
|
+
if (argv[key] === undefined || argv[key] === null) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const value = argv[key];
|
|
90
|
+
const kebabKey = key.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`);
|
|
91
|
+
if (typeof value === 'boolean') {
|
|
92
|
+
if (value) {
|
|
93
|
+
args.push(`--${kebabKey}`);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
args.push(`--no-${kebabKey}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else if (Array.isArray(value)) {
|
|
100
|
+
for (const item of value) {
|
|
101
|
+
args.push(`--${kebabKey}`, String(item));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
args.push(`--${kebabKey}`, String(value));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return args;
|
|
109
|
+
}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { createStackTraceForConsoleMessage, SymbolizedError, } from '../DevtoolsUtils.js';
|
|
7
|
+
import { UncaughtError } from '../PageCollector.js';
|
|
8
|
+
import * as DevTools from '../third_party/index.js';
|
|
9
|
+
export class ConsoleFormatter {
|
|
10
|
+
#id;
|
|
11
|
+
#type;
|
|
12
|
+
#text;
|
|
13
|
+
#argCount;
|
|
14
|
+
#resolvedArgs;
|
|
15
|
+
#stack;
|
|
16
|
+
#cause;
|
|
17
|
+
isIgnored;
|
|
18
|
+
constructor(params) {
|
|
19
|
+
this.#id = params.id;
|
|
20
|
+
this.#type = params.type;
|
|
21
|
+
this.#text = params.text;
|
|
22
|
+
this.#argCount = params.argCount ?? 0;
|
|
23
|
+
this.#resolvedArgs = params.resolvedArgs ?? [];
|
|
24
|
+
this.#stack = params.stack;
|
|
25
|
+
this.#cause = params.cause;
|
|
26
|
+
this.isIgnored = params.isIgnored;
|
|
27
|
+
}
|
|
28
|
+
static async from(msg, options) {
|
|
29
|
+
const ignoreListManager = options?.devTools?.universe.context.get(DevTools.DevTools.IgnoreListManager);
|
|
30
|
+
const isIgnored = options.isIgnoredForTesting ||
|
|
31
|
+
(frame => {
|
|
32
|
+
if (!ignoreListManager) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
if (frame.uiSourceCode) {
|
|
36
|
+
return ignoreListManager.isUserOrSourceMapIgnoreListedUISourceCode(frame.uiSourceCode);
|
|
37
|
+
}
|
|
38
|
+
if (frame.url) {
|
|
39
|
+
return ignoreListManager.isUserIgnoreListedURL(frame.url);
|
|
40
|
+
}
|
|
41
|
+
return false;
|
|
42
|
+
});
|
|
43
|
+
if (msg instanceof UncaughtError) {
|
|
44
|
+
const error = await SymbolizedError.fromDetails({
|
|
45
|
+
devTools: options?.devTools,
|
|
46
|
+
details: msg.details,
|
|
47
|
+
targetId: msg.targetId,
|
|
48
|
+
includeStackAndCause: options?.fetchDetailedData,
|
|
49
|
+
resolvedStackTraceForTesting: options?.resolvedStackTraceForTesting,
|
|
50
|
+
resolvedCauseForTesting: options?.resolvedCauseForTesting,
|
|
51
|
+
});
|
|
52
|
+
return new ConsoleFormatter({
|
|
53
|
+
id: options.id,
|
|
54
|
+
type: 'error',
|
|
55
|
+
text: error.message,
|
|
56
|
+
stack: error.stackTrace,
|
|
57
|
+
cause: error.cause,
|
|
58
|
+
isIgnored,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
let resolvedArgs = [];
|
|
62
|
+
if (options.resolvedArgsForTesting) {
|
|
63
|
+
resolvedArgs = options.resolvedArgsForTesting;
|
|
64
|
+
}
|
|
65
|
+
else if (options.fetchDetailedData) {
|
|
66
|
+
resolvedArgs = await Promise.all(msg.args().map(async (arg, i) => {
|
|
67
|
+
try {
|
|
68
|
+
const remoteObject = arg.remoteObject();
|
|
69
|
+
if (remoteObject.type === 'object' &&
|
|
70
|
+
remoteObject.subtype === 'error') {
|
|
71
|
+
return await SymbolizedError.fromError({
|
|
72
|
+
devTools: options.devTools,
|
|
73
|
+
error: remoteObject,
|
|
74
|
+
// @ts-expect-error Internal ConsoleMessage API
|
|
75
|
+
targetId: msg._targetId(),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return await arg.jsonValue();
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return `<error: Argument ${i} is no longer available>`;
|
|
82
|
+
}
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
let stack;
|
|
86
|
+
if (options.resolvedStackTraceForTesting) {
|
|
87
|
+
stack = options.resolvedStackTraceForTesting;
|
|
88
|
+
}
|
|
89
|
+
else if (options.fetchDetailedData && options.devTools) {
|
|
90
|
+
try {
|
|
91
|
+
stack = await createStackTraceForConsoleMessage(options.devTools, msg);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// ignore
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return new ConsoleFormatter({
|
|
98
|
+
id: options.id,
|
|
99
|
+
type: msg.type(),
|
|
100
|
+
text: msg.text(),
|
|
101
|
+
argCount: resolvedArgs.length || msg.args().length,
|
|
102
|
+
resolvedArgs,
|
|
103
|
+
stack,
|
|
104
|
+
isIgnored,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
// The short format for a console message.
|
|
108
|
+
toString() {
|
|
109
|
+
return convertConsoleMessageConciseToString(this.toJSON());
|
|
110
|
+
}
|
|
111
|
+
// The verbose format for a console message, including all details.
|
|
112
|
+
toStringDetailed() {
|
|
113
|
+
return convertConsoleMessageConciseDetailedToString(this.toJSONDetailed());
|
|
114
|
+
}
|
|
115
|
+
#getArgs() {
|
|
116
|
+
if (this.#resolvedArgs.length > 0) {
|
|
117
|
+
const args = [...this.#resolvedArgs];
|
|
118
|
+
// If there is no text, the first argument serves as text (see formatMessage).
|
|
119
|
+
if (!this.#text) {
|
|
120
|
+
args.shift();
|
|
121
|
+
}
|
|
122
|
+
return args;
|
|
123
|
+
}
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
toJSON() {
|
|
127
|
+
return {
|
|
128
|
+
type: this.#type,
|
|
129
|
+
text: this.#text,
|
|
130
|
+
argsCount: this.#argCount,
|
|
131
|
+
id: this.#id,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
toJSONDetailed() {
|
|
135
|
+
return {
|
|
136
|
+
id: this.#id,
|
|
137
|
+
type: this.#type,
|
|
138
|
+
text: this.#text,
|
|
139
|
+
argsCount: this.#argCount,
|
|
140
|
+
args: this.#getArgs().map(arg => formatArg(arg, this)),
|
|
141
|
+
stackTrace: this.#stack
|
|
142
|
+
? formatStackTrace(this.#stack, this.#cause, this)
|
|
143
|
+
: undefined,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function convertConsoleMessageConciseToString(msg) {
|
|
148
|
+
return `msgid=${msg.id} [${msg.type}] ${msg.text} (${msg.argsCount} args)`;
|
|
149
|
+
}
|
|
150
|
+
function convertConsoleMessageConciseDetailedToString(msg) {
|
|
151
|
+
const result = [
|
|
152
|
+
`ID: ${msg.id}`,
|
|
153
|
+
`Message: ${msg.type}> ${msg.text}`,
|
|
154
|
+
formatArgs(msg),
|
|
155
|
+
...(msg.stackTrace ? ['### Stack trace', msg.stackTrace] : []),
|
|
156
|
+
].filter(line => !!line);
|
|
157
|
+
return result.join('\n');
|
|
158
|
+
}
|
|
159
|
+
function formatArgs(msg) {
|
|
160
|
+
const args = msg.args;
|
|
161
|
+
if (!args.length) {
|
|
162
|
+
return '';
|
|
163
|
+
}
|
|
164
|
+
const result = ['### Arguments'];
|
|
165
|
+
for (const [key, arg] of args.entries()) {
|
|
166
|
+
result.push(`Arg #${key}: ${arg}`);
|
|
167
|
+
}
|
|
168
|
+
return result.join('\n');
|
|
169
|
+
}
|
|
170
|
+
function formatArg(arg, formatter) {
|
|
171
|
+
if (arg instanceof SymbolizedError) {
|
|
172
|
+
return [
|
|
173
|
+
arg.message,
|
|
174
|
+
arg.stackTrace
|
|
175
|
+
? formatStackTrace(arg.stackTrace, arg.cause, formatter)
|
|
176
|
+
: undefined,
|
|
177
|
+
]
|
|
178
|
+
.filter(line => !!line)
|
|
179
|
+
.join('\n');
|
|
180
|
+
}
|
|
181
|
+
return typeof arg === 'object' ? JSON.stringify(arg) : String(arg);
|
|
182
|
+
}
|
|
183
|
+
const STACK_TRACE_MAX_LINES = 50;
|
|
184
|
+
function formatStackTrace(stackTrace, cause, formatter) {
|
|
185
|
+
const lines = formatStackTraceInner(stackTrace, cause, formatter);
|
|
186
|
+
const includedLines = lines.slice(0, STACK_TRACE_MAX_LINES);
|
|
187
|
+
const reminderCount = lines.length - includedLines.length;
|
|
188
|
+
return [
|
|
189
|
+
...includedLines,
|
|
190
|
+
reminderCount > 0 ? `... and ${reminderCount} more frames` : '',
|
|
191
|
+
'Note: line and column numbers use 1-based indexing',
|
|
192
|
+
]
|
|
193
|
+
.filter(line => !!line)
|
|
194
|
+
.join('\n');
|
|
195
|
+
}
|
|
196
|
+
function formatStackTraceInner(stackTrace, cause, formatter) {
|
|
197
|
+
if (!stackTrace) {
|
|
198
|
+
return [];
|
|
199
|
+
}
|
|
200
|
+
return [
|
|
201
|
+
...formatFragment(stackTrace.syncFragment, formatter),
|
|
202
|
+
...stackTrace.asyncFragments
|
|
203
|
+
.map(item => formatAsyncFragment(item, formatter))
|
|
204
|
+
.flat(),
|
|
205
|
+
...formatCause(cause, formatter),
|
|
206
|
+
];
|
|
207
|
+
}
|
|
208
|
+
function formatFragment(fragment, formatter) {
|
|
209
|
+
const frames = fragment.frames.filter(frame => !formatter.isIgnored(frame));
|
|
210
|
+
return frames.map(formatFrame);
|
|
211
|
+
}
|
|
212
|
+
function formatAsyncFragment(fragment, formatter) {
|
|
213
|
+
const formattedFrames = formatFragment(fragment, formatter);
|
|
214
|
+
if (formattedFrames.length === 0) {
|
|
215
|
+
return [];
|
|
216
|
+
}
|
|
217
|
+
const separatorLineLength = 40;
|
|
218
|
+
const prefix = `--- ${fragment.description || 'async'} `;
|
|
219
|
+
const separator = prefix + '-'.repeat(separatorLineLength - prefix.length);
|
|
220
|
+
return [separator, ...formattedFrames];
|
|
221
|
+
}
|
|
222
|
+
function formatFrame(frame) {
|
|
223
|
+
let result = `at ${frame.name ?? '<anonymous>'}`;
|
|
224
|
+
if (frame.uiSourceCode) {
|
|
225
|
+
const location = frame.uiSourceCode.uiLocation(frame.line, frame.column);
|
|
226
|
+
result += ` (${location.linkText(/* skipTrim */ false, /* showColumnNumber */ true)})`;
|
|
227
|
+
}
|
|
228
|
+
else if (frame.url) {
|
|
229
|
+
result += ` (${frame.url}:${frame.line}:${frame.column})`;
|
|
230
|
+
}
|
|
231
|
+
return result;
|
|
232
|
+
}
|
|
233
|
+
function formatCause(cause, formatter) {
|
|
234
|
+
if (!cause) {
|
|
235
|
+
return [];
|
|
236
|
+
}
|
|
237
|
+
return [
|
|
238
|
+
`Caused by: ${cause.message}`,
|
|
239
|
+
...formatStackTraceInner(cause.stackTrace, cause.cause, formatter),
|
|
240
|
+
];
|
|
241
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { ISSUE_UTILS } from '../issue-descriptions.js';
|
|
7
|
+
import { logger } from '../logger.js';
|
|
8
|
+
import { DevTools } from '../third_party/index.js';
|
|
9
|
+
export class IssueFormatter {
|
|
10
|
+
#issue;
|
|
11
|
+
#options;
|
|
12
|
+
constructor(issue, options) {
|
|
13
|
+
this.#issue = issue;
|
|
14
|
+
this.#options = options;
|
|
15
|
+
}
|
|
16
|
+
toString() {
|
|
17
|
+
return convertIssueConciseToString(this.toJSON());
|
|
18
|
+
}
|
|
19
|
+
toStringDetailed() {
|
|
20
|
+
return convertIssueDetailedToString(this.toJSONDetailed());
|
|
21
|
+
}
|
|
22
|
+
toJSON() {
|
|
23
|
+
return {
|
|
24
|
+
type: 'issue',
|
|
25
|
+
title: this.#getTitle(),
|
|
26
|
+
count: this.#issue.getAggregatedIssuesCount(),
|
|
27
|
+
id: this.#options.id,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
toJSONDetailed() {
|
|
31
|
+
return {
|
|
32
|
+
id: this.#options.id,
|
|
33
|
+
type: 'issue',
|
|
34
|
+
count: this.#issue.getAggregatedIssuesCount(),
|
|
35
|
+
title: this.#getTitle(),
|
|
36
|
+
description: this.#getDescription(),
|
|
37
|
+
links: this.#issue.getDescription()?.links,
|
|
38
|
+
affectedResources: this.#getAffectedResources(),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
#getAffectedResources() {
|
|
42
|
+
const issues = this.#issue.getAllIssues();
|
|
43
|
+
const affectedResources = [];
|
|
44
|
+
for (const singleIssue of issues) {
|
|
45
|
+
const details = singleIssue.details();
|
|
46
|
+
if (!details) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
// We send the remaining details as untyped JSON because the DevTools
|
|
50
|
+
// frontend code is currently not re-usable.
|
|
51
|
+
const data = structuredClone(details);
|
|
52
|
+
let uid;
|
|
53
|
+
let request;
|
|
54
|
+
if ('violatingNodeId' in details &&
|
|
55
|
+
details.violatingNodeId &&
|
|
56
|
+
this.#options.elementIdResolver) {
|
|
57
|
+
uid = this.#options.elementIdResolver(details.violatingNodeId);
|
|
58
|
+
delete data.violatingNodeId;
|
|
59
|
+
}
|
|
60
|
+
if ('nodeId' in details &&
|
|
61
|
+
details.nodeId &&
|
|
62
|
+
this.#options.elementIdResolver) {
|
|
63
|
+
uid = this.#options.elementIdResolver(details.nodeId);
|
|
64
|
+
delete data.nodeId;
|
|
65
|
+
}
|
|
66
|
+
if ('documentNodeId' in details &&
|
|
67
|
+
details.documentNodeId &&
|
|
68
|
+
this.#options.elementIdResolver) {
|
|
69
|
+
uid = this.#options.elementIdResolver(details.documentNodeId);
|
|
70
|
+
delete data.documentNodeId;
|
|
71
|
+
}
|
|
72
|
+
if ('request' in details && details.request) {
|
|
73
|
+
request = details.request.url;
|
|
74
|
+
if (details.request.requestId && this.#options.requestIdResolver) {
|
|
75
|
+
const resolvedId = this.#options.requestIdResolver(details.request.requestId);
|
|
76
|
+
if (resolvedId) {
|
|
77
|
+
request = resolvedId;
|
|
78
|
+
const requestData = data.request;
|
|
79
|
+
delete requestData.requestId;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// These fields has no use for the MCP client (redundant or irrelevant).
|
|
84
|
+
delete data.errorType;
|
|
85
|
+
delete data.frameId;
|
|
86
|
+
affectedResources.push({
|
|
87
|
+
uid,
|
|
88
|
+
data: data,
|
|
89
|
+
request,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return affectedResources;
|
|
93
|
+
}
|
|
94
|
+
isValid() {
|
|
95
|
+
return this.#getTitle() !== undefined;
|
|
96
|
+
}
|
|
97
|
+
// Helper to extract title
|
|
98
|
+
#getTitle() {
|
|
99
|
+
const markdownDescription = this.#issue.getDescription();
|
|
100
|
+
const filename = markdownDescription?.file;
|
|
101
|
+
if (!filename) {
|
|
102
|
+
logger(`no description found for issue:` + this.#issue.code());
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
// We already have the description logic in #getDescription, but title extraction is separate
|
|
106
|
+
// We can reuse the logic or cache it.
|
|
107
|
+
// Ideally we should process markdown once.
|
|
108
|
+
const rawMarkdown = ISSUE_UTILS.getIssueDescription(filename);
|
|
109
|
+
if (!rawMarkdown) {
|
|
110
|
+
logger(`no markdown ${filename} found for issue:` + this.#issue.code());
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
const processedMarkdown = DevTools.MarkdownIssueDescription.substitutePlaceholders(rawMarkdown, markdownDescription?.substitutions);
|
|
115
|
+
const markdownAst = DevTools.Marked.Marked.lexer(processedMarkdown);
|
|
116
|
+
const title = DevTools.MarkdownIssueDescription.findTitleFromMarkdownAst(markdownAst);
|
|
117
|
+
if (!title) {
|
|
118
|
+
logger('cannot read issue title from ' + filename);
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
return title;
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
logger('error parsing markdown for issue ' + this.#issue.code());
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
#getDescription() {
|
|
129
|
+
const markdownDescription = this.#issue.getDescription();
|
|
130
|
+
const filename = markdownDescription?.file;
|
|
131
|
+
if (!filename) {
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
const rawMarkdown = ISSUE_UTILS.getIssueDescription(filename);
|
|
135
|
+
if (!rawMarkdown) {
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
return DevTools.MarkdownIssueDescription.substitutePlaceholders(rawMarkdown, markdownDescription?.substitutions);
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function convertIssueConciseToString(issue) {
|
|
147
|
+
return `msgid=${issue.id} [issue] ${issue.title} (count: ${issue.count})`;
|
|
148
|
+
}
|
|
149
|
+
function convertIssueDetailedToString(issue) {
|
|
150
|
+
const result = [];
|
|
151
|
+
result.push(`ID: ${issue.id}`);
|
|
152
|
+
const bodyParts = [];
|
|
153
|
+
const description = issue.description;
|
|
154
|
+
let processedMarkdown = description?.trim();
|
|
155
|
+
// Remove heading in order not to conflict with the whole console message response markdown
|
|
156
|
+
if (processedMarkdown?.startsWith('# ')) {
|
|
157
|
+
processedMarkdown = processedMarkdown.substring(2).trimStart();
|
|
158
|
+
}
|
|
159
|
+
if (processedMarkdown) {
|
|
160
|
+
bodyParts.push(processedMarkdown);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
bodyParts.push(issue.title ?? 'Unknown Issue');
|
|
164
|
+
}
|
|
165
|
+
const links = issue.links;
|
|
166
|
+
if (links && links.length > 0) {
|
|
167
|
+
bodyParts.push('Learn more:');
|
|
168
|
+
for (const link of links) {
|
|
169
|
+
bodyParts.push(`[${link.linkTitle}](${link.link})`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
const affectedResources = issue.affectedResources;
|
|
173
|
+
if (affectedResources.length) {
|
|
174
|
+
bodyParts.push('### Affected resources');
|
|
175
|
+
bodyParts.push(...affectedResources.map(item => {
|
|
176
|
+
const details = [];
|
|
177
|
+
if (item.uid) {
|
|
178
|
+
details.push(`uid=${item.uid}`);
|
|
179
|
+
}
|
|
180
|
+
if (item.request) {
|
|
181
|
+
details.push((typeof item.request === 'number' ? `reqid=` : 'url=') +
|
|
182
|
+
item.request);
|
|
183
|
+
}
|
|
184
|
+
if (item.data) {
|
|
185
|
+
details.push(`data=${JSON.stringify(item.data)}`);
|
|
186
|
+
}
|
|
187
|
+
return details.join(' ');
|
|
188
|
+
}));
|
|
189
|
+
}
|
|
190
|
+
result.push(`Message: issue> ${bodyParts.join('\n')}`);
|
|
191
|
+
return result.join('\n');
|
|
192
|
+
}
|