opera-devtools-mcp 0.2.3 → 0.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/README.md +104 -7
- package/build/src/McpContext.js +365 -365
- package/build/src/McpPage.js +475 -48
- package/build/src/McpResponse.js +462 -288
- package/build/src/SlimMcpResponse.js +1 -1
- package/build/src/TextSnapshot.js +101 -22
- package/build/src/ToolHandler.js +142 -20
- package/build/src/bin/check-latest-version.js +27 -1
- package/build/src/bin/chrome-devtools-cli-options.js +573 -10
- package/build/src/bin/chrome-devtools-mcp-cli-options.js +119 -32
- package/build/src/bin/chrome-devtools-mcp-main.js +50 -7
- package/build/src/bin/chrome-devtools-mcp.js +7 -4
- package/build/src/bin/chrome-devtools.js +57 -14
- package/build/src/bin/opera-devtools-cli-options.js +3 -829
- package/build/src/bin/opera-devtools-mcp-cli-options.js +3 -348
- package/build/src/bin/opera-devtools-mcp-main.js +3 -37
- package/build/src/bin/opera-devtools-mcp.js +4 -19
- package/build/src/bin/opera-devtools.js +4 -185
- package/build/src/browser.js +45 -5
- package/build/src/{PageCollector.js → collectors/PageCollector.js} +64 -133
- package/build/src/collectors/ServiceWorkerCollector.js +171 -0
- package/build/src/daemon/client.js +75 -17
- package/build/src/daemon/daemon.js +92 -30
- package/build/src/daemon/utils.js +24 -8
- package/build/src/{DevtoolsUtils.js → devtools/DevtoolsUtils.js} +94 -88
- package/build/src/devtools/McpHostBindingAdapter.js +165 -0
- package/build/src/{issue-descriptions.js → devtools/issueDescriptions.js} +8 -6
- package/build/src/formatters/ConsoleFormatter.js +44 -11
- package/build/src/formatters/HeapSnapshotFormatter.js +140 -9
- package/build/src/formatters/IssueFormatter.js +7 -7
- package/build/src/formatters/NetworkFormatter.js +10 -8
- package/build/src/index.js +101 -232
- package/build/src/opera/branding.js +34 -0
- package/build/src/opera/browserFlags.js +85 -0
- package/build/src/opera/browserLaunch.js +52 -0
- package/build/src/opera/policy.js +50 -0
- package/build/src/opera/serviceWorkerRetry.js +37 -0
- package/build/src/opera/toolHandlerHooks.js +39 -0
- package/build/src/{tools → opera/tools}/opera.js +9 -21
- package/build/src/processors/HeapSnapshotManager.js +258 -0
- package/build/src/{trace-processing/parse.js → processors/PerformanceTrace.js} +9 -9
- package/build/src/telemetry/ClearcutLogger.js +12 -119
- package/build/src/telemetry/WatchdogClient.js +5 -5
- package/build/src/telemetry/errors.js +1 -1
- package/build/src/telemetry/flagUtils.js +6 -6
- package/build/src/telemetry/{toolMetricsUtils.js → metricsRegistry.js} +4 -11
- package/build/src/telemetry/persistence.js +3 -3
- package/build/src/telemetry/transformation.js +184 -0
- package/build/src/telemetry/watchdog/ClearcutSender.js +11 -11
- package/build/src/telemetry/watchdog/main.js +6 -6
- package/build/src/third_party/THIRD_PARTY_NOTICES +3493 -0
- package/build/src/third_party/bundled-packages.json +9 -0
- package/build/src/third_party/devtools-formatter-worker.js +15340 -7
- package/build/src/third_party/devtools-heap-snapshot-worker.js +10337 -7
- package/build/src/third_party/index.js +179960 -26
- package/build/src/third_party/issue-descriptions/CoepCorpNotSameOrigin.md +2 -2
- package/build/src/third_party/issue-descriptions/CoepCorpNotSameOriginAfterDefaultedToSameOriginByCoep.md +3 -3
- package/build/src/third_party/issue-descriptions/CoepCorpNotSameSite.md +2 -2
- package/build/src/third_party/issue-descriptions/CoepFrameResourceNeedsCoepHeader.md +1 -1
- package/build/src/third_party/issue-descriptions/CompatibilityModeQuirks.md +1 -1
- package/build/src/third_party/issue-descriptions/CookieAttributeValueExceedsMaxSize.md +2 -2
- package/build/src/third_party/issue-descriptions/LowTextContrast.md +1 -1
- package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureErrorRead.md +1 -1
- package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureErrorSet.md +1 -1
- package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureWarnRead.md +1 -1
- package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureWarnSet.md +1 -1
- package/build/src/third_party/issue-descriptions/SameSiteUnspecifiedLaxAllowUnsafeRead.md +3 -3
- package/build/src/third_party/issue-descriptions/SameSiteUnspecifiedLaxAllowUnsafeSet.md +3 -3
- package/build/src/third_party/issue-descriptions/bounceTrackingMitigations.md +1 -1
- package/build/src/third_party/issue-descriptions/connectionAllowlistEmbeddingRequirementNotSatisfied.md +26 -0
- package/build/src/third_party/issue-descriptions/connectionAllowlistIFrameAttributeLoosensEmbeddingRequirement.md +19 -0
- package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidAllowConnectionAllowlistFrom.md +21 -0
- package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidAllowlistItemType.md +2 -2
- package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidHeader.md +2 -2
- package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidUrlPattern.md +3 -3
- package/build/src/third_party/issue-descriptions/connectionAllowlistItemNotInnerList.md +2 -2
- package/build/src/third_party/issue-descriptions/connectionAllowlistMoreThanOneList.md +2 -2
- package/build/src/third_party/issue-descriptions/connectionAllowlistReportingEndpointNotToken.md +1 -1
- package/build/src/third_party/issue-descriptions/cookieCrossSiteRedirectDowngrade.md +3 -3
- package/build/src/third_party/issue-descriptions/cookieExcludeBlockedWithinRelatedWebsiteSet.md +1 -1
- package/build/src/third_party/issue-descriptions/cookieExcludePortMismatch.md +1 -1
- package/build/src/third_party/issue-descriptions/cookieExcludeSchemeMismatch.md +1 -1
- package/build/src/third_party/issue-descriptions/cookieExcludeThirdPartyPhaseoutSet.md +1 -1
- package/build/src/third_party/issue-descriptions/cookieWarnThirdPartyPhaseoutRead.md +1 -1
- package/build/src/third_party/issue-descriptions/corsAllowCredentialsRequired.md +1 -1
- package/build/src/third_party/issue-descriptions/corsDisabledScheme.md +2 -2
- package/build/src/third_party/issue-descriptions/corsDisallowedByMode.md +2 -2
- package/build/src/third_party/issue-descriptions/corsHeaderDisallowedByPreflightResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/corsInvalidHeaderValues.md +3 -3
- package/build/src/third_party/issue-descriptions/corsLocalNetworkAccessPermissionDenied.md +1 -1
- package/build/src/third_party/issue-descriptions/corsMethodDisallowedByPreflightResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/corsNoCorsRedirectModeNotFollow.md +1 -1
- package/build/src/third_party/issue-descriptions/corsOriginMismatch.md +3 -3
- package/build/src/third_party/issue-descriptions/corsPreflightResponseInvalid.md +2 -2
- package/build/src/third_party/issue-descriptions/corsRedirectContainsCredentials.md +3 -3
- package/build/src/third_party/issue-descriptions/corsWildcardOriginNotAllowed.md +4 -3
- package/build/src/third_party/issue-descriptions/cspEvalViolation.md +4 -4
- package/build/src/third_party/issue-descriptions/cspInlineViolation.md +2 -2
- package/build/src/third_party/issue-descriptions/cspTrustedTypesPolicyViolation.md +2 -2
- package/build/src/third_party/issue-descriptions/cspTrustedTypesSinkViolation.md +4 -4
- package/build/src/third_party/issue-descriptions/cspURLViolation.md +4 -4
- 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 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsInvalidResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsNoResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestApprovalDeclined.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestCanceled.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestErrorFetchingSignin.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestErrorIdToken.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenHttpNotFound.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenInvalidRequest.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenInvalidResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenNoResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestInvalidSigninResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestHttpNotFound.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestInvalidResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestNoResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestTooManyRequests.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestInvalidAccountsResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestInvalidConfigOrWellKnown.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoAccountSharingPermission.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoApiPermission.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoReturningUserFromFetchedAccounts.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotIframe.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotPotentiallyTrustworthy.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotSameOrigin.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotSignedInWithIdp.md +1 -1
- package/build/src/third_party/issue-descriptions/fetchingPartitionedBlobURL.md +2 -2
- package/build/src/third_party/issue-descriptions/genericBackUINavigationWouldSkipAd.md +4 -0
- package/build/src/third_party/issue-descriptions/genericFormAriaLabelledByToNonExistingIdError.md +2 -2
- package/build/src/third_party/issue-descriptions/genericFormAutocompleteAttributeEmptyError.md +1 -1
- package/build/src/third_party/issue-descriptions/genericFormDuplicateIdForInputError.md +1 -1
- package/build/src/third_party/issue-descriptions/genericFormEmptyIdAndNameAttributesForInputError.md +2 -2
- package/build/src/third_party/issue-descriptions/genericFormInputAssignedAutocompleteValueToIdOrNameAttributeError.md +2 -2
- package/build/src/third_party/issue-descriptions/genericFormInputHasWrongButWellIntendedAutocompleteValueError.md +1 -1
- package/build/src/third_party/issue-descriptions/genericFormInputWithNoLabelError.md +1 -1
- package/build/src/third_party/issue-descriptions/genericFormLabelForMatchesNonExistingIdError.md +2 -2
- package/build/src/third_party/issue-descriptions/genericFormLabelForNameError.md +1 -1
- package/build/src/third_party/issue-descriptions/genericFormLabelHasNeitherForNorNestedInputError.md +1 -1
- package/build/src/third_party/issue-descriptions/genericFormModelContextMissingToolName.md +1 -1
- package/build/src/third_party/issue-descriptions/genericFormModelContextParameterMissingName.md +1 -1
- package/build/src/third_party/issue-descriptions/genericFormModelContextRequiredParameterMissingName.md +1 -1
- package/build/src/third_party/issue-descriptions/genericNavigationEntryMarkedSkippable.md +2 -2
- package/build/src/third_party/issue-descriptions/heavyAd.md +1 -1
- package/build/src/third_party/issue-descriptions/lazyLoadImageZeroSize.md +7 -0
- package/build/src/third_party/issue-descriptions/navigatingPartitionedBlobURL.md +3 -3
- package/build/src/third_party/issue-descriptions/permissionElementActivationDisabled.md +1 -1
- package/build/src/third_party/issue-descriptions/permissionElementActivationDisabledWithOccluder.md +1 -1
- package/build/src/third_party/issue-descriptions/permissionElementActivationDisabledWithOccluderParent.md +1 -1
- package/build/src/third_party/issue-descriptions/permissionElementFencedFrameDisallowed.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementFontSizeTooLarge.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementFontSizeTooSmall.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementInsetBoxShadowUnsupported.md +1 -1
- package/build/src/third_party/issue-descriptions/permissionElementInvalidDisplayStyle.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementInvalidSizeValue.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementInvalidType.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementInvalidTypeActivation.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementNonOpaqueColor.md +1 -1
- package/build/src/third_party/issue-descriptions/permissionElementPaddingBottomUnsupported.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementPaddingRightUnsupported.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementRequestInProgress.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementSecurityChecksFailed.md +1 -1
- package/build/src/third_party/issue-descriptions/permissionElementTypeNotSupported.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementUntrustedEvent.md +1 -1
- package/build/src/third_party/issue-descriptions/placeholderDescriptionForInvisibleIssues.md +1 -1
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityDisallowedOptGroupChild.md +1 -1
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityDisallowedSelectChild.md +1 -1
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentAttributesSelectDescendant.md +1 -1
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentLegendChild.md +1 -1
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentOptionChild.md +1 -1
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityNonPhrasingContentOptionChild.md +1 -1
- package/build/src/third_party/issue-descriptions/selectivePermissionsIntervention.md +3 -3
- package/build/src/third_party/issue-descriptions/sharedArrayBuffer.md +1 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorCrossOriginNoCorsRequest.md +1 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorMatchingDictionaryNotUsed.md +1 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorUnexpectedContentDictionaryHeader.md +1 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorCossOriginNoCorsRequest.md +1 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorDisallowedBySettings.md +1 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorExpiredResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorFeatureDisabled.md +2 -2
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInvalidStructuredHeader.md +1 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNavigationRequest.md +2 -2
- package/build/src/third_party/issue-descriptions/sriInvalidSignatureHeader.md +4 -4
- package/build/src/third_party/issue-descriptions/sriInvalidSignatureInputHeader.md +4 -4
- package/build/src/third_party/issue-descriptions/sriMissingSignatureHeader.md +1 -1
- package/build/src/third_party/issue-descriptions/sriMissingSignatureInputHeader.md +2 -2
- package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsIncorrectLength.md +2 -2
- package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsNotByteSequence.md +4 -4
- package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsParameterized.md +4 -4
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidComponentName.md +1 -1
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidComponentType.md +2 -2
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidDerivedComponentParameter.md +1 -1
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidHeaderComponentParameter.md +1 -1
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidParameter.md +2 -2
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderKeyIdLength.md +5 -5
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderMissingLabel.md +3 -3
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderMissingRequiredParameters.md +2 -2
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderValueMissingComponents.md +2 -2
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderValueNotInnerList.md +2 -2
- package/build/src/third_party/issue-descriptions/sriValidationFailedIntegrityMismatch.md +4 -4
- package/build/src/third_party/issue-descriptions/sriValidationFailedInvalidLength.md +3 -3
- package/build/src/third_party/issue-descriptions/sriValidationFailedSignatureExpired.md +2 -2
- package/build/src/third_party/issue-descriptions/sriValidationFailedSignatureMismatch.md +2 -2
- package/build/src/third_party/issue-descriptions/stylesheetLateImport.md +1 -1
- package/build/src/third_party/issue-descriptions/summaryElementAccessibilityInteractiveContentSummaryDescendant.md +1 -1
- package/build/src/third_party/issue-descriptions/unencodedDigestIncorrectDigestLength.md +2 -2
- package/build/src/third_party/issue-descriptions/unencodedDigestIncorrectDigestType.md +3 -3
- package/build/src/third_party/issue-descriptions/unencodedDigestMalformedDictionary.md +2 -2
- package/build/src/third_party/issue-descriptions/unencodedDigestUnknownAlgorithm.md +1 -1
- package/build/src/third_party/lighthouse-devtools-mcp-bundle.js +3177 -6340
- package/build/src/tools/ToolDefinition.js +2 -2
- package/build/src/tools/categories.js +3 -0
- package/build/src/tools/console.js +13 -0
- package/build/src/tools/emulation.js +30 -3
- package/build/src/tools/extensions.js +8 -1
- package/build/src/tools/input.js +246 -128
- package/build/src/tools/lighthouse.js +14 -7
- package/build/src/tools/memory.js +289 -25
- package/build/src/tools/network.js +10 -7
- package/build/src/tools/pages.js +33 -92
- package/build/src/tools/performance.js +67 -52
- package/build/src/tools/pwa.js +128 -0
- package/build/src/tools/screencast.js +35 -12
- package/build/src/tools/screenshot.js +234 -75
- package/build/src/tools/script.js +130 -45
- package/build/src/tools/slim/tools.js +3 -0
- package/build/src/tools/snapshot.js +7 -4
- package/build/src/tools/thirdPartyDeveloper.js +19 -9
- package/build/src/tools/tools.js +3 -1
- package/build/src/tools/webmcp.js +3 -1
- package/build/src/utils/WaitForHelper.js +299 -0
- package/build/src/utils/check-for-updates.js +8 -2
- package/build/src/utils/files.js +42 -3
- package/build/src/utils/logger.js +51 -0
- package/build/src/utils/polyfill.js +11 -0
- package/build/src/utils/url.js +43 -0
- package/build/src/version.js +1 -1
- package/package.json +42 -33
- package/build/src/DevToolsConnectionAdapter.js +0 -70
- package/build/src/HeapSnapshotManager.js +0 -110
- package/build/src/Mutex.js +0 -38
- package/build/src/WaitForHelper.js +0 -195
- package/build/src/bin/cliDefinitions.js +0 -616
- package/build/src/logger.js +0 -37
- package/build/src/polyfill.js +0 -8
- package/build/src/telemetry/metricUtils.js +0 -15
- package/build/src/third_party/issue-descriptions/SameSiteExcludeContextDowngradeRead.md +0 -8
- package/build/src/third_party/issue-descriptions/SameSiteExcludeContextDowngradeSet.md +0 -8
- package/build/src/third_party/issue-descriptions/SameSiteExcludeNavigationContextDowngrade.md +0 -8
- package/build/src/third_party/issue-descriptions/SameSiteWarnCrossDowngradeRead.md +0 -8
- package/build/src/third_party/issue-descriptions/SameSiteWarnCrossDowngradeSet.md +0 -8
- package/build/src/third_party/issue-descriptions/SameSiteWarnStrictLaxDowngradeStrict.md +0 -8
- package/build/src/third_party/issue-descriptions/arInsecureContext.md +0 -7
- package/build/src/third_party/issue-descriptions/arInvalidInfoHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arInvalidRegisterOsSourceHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arInvalidRegisterOsTriggerHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arInvalidRegisterSourceHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arInvalidRegisterTriggerHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arNavigationRegistrationUniqueScopeAlreadySet.md +0 -5
- package/build/src/third_party/issue-descriptions/arNavigationRegistrationWithoutTransientUserActivation.md +0 -6
- package/build/src/third_party/issue-descriptions/arNoRegisterOsSourceHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arNoRegisterOsTriggerHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arNoRegisterSourceHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arNoRegisterTriggerHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arNoWebOrOsSupport.md +0 -4
- package/build/src/third_party/issue-descriptions/arOsSourceIgnored.md +0 -18
- package/build/src/third_party/issue-descriptions/arOsTriggerIgnored.md +0 -19
- package/build/src/third_party/issue-descriptions/arPermissionPolicyDisabled.md +0 -8
- package/build/src/third_party/issue-descriptions/arSourceAndTriggerHeaders.md +0 -9
- package/build/src/third_party/issue-descriptions/arSourceIgnored.md +0 -13
- package/build/src/third_party/issue-descriptions/arTriggerIgnored.md +0 -12
- package/build/src/third_party/issue-descriptions/arUntrustworthyReportingOrigin.md +0 -10
- package/build/src/third_party/issue-descriptions/arWebAndOsHeaders.md +0 -11
- package/build/src/utils/string.js +0 -37
- package/build/src/utils/types.js +0 -7
|
@@ -3,7 +3,59 @@
|
|
|
3
3
|
* Copyright 2025 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
|
|
6
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
7
|
+
if (value !== null && value !== void 0) {
|
|
8
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
9
|
+
var dispose, inner;
|
|
10
|
+
if (async) {
|
|
11
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
12
|
+
dispose = value[Symbol.asyncDispose];
|
|
13
|
+
}
|
|
14
|
+
if (dispose === void 0) {
|
|
15
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
16
|
+
dispose = value[Symbol.dispose];
|
|
17
|
+
if (async) inner = dispose;
|
|
18
|
+
}
|
|
19
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
20
|
+
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
21
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
22
|
+
}
|
|
23
|
+
else if (async) {
|
|
24
|
+
env.stack.push({ async: true });
|
|
25
|
+
}
|
|
26
|
+
return value;
|
|
27
|
+
};
|
|
28
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
29
|
+
return function (env) {
|
|
30
|
+
function fail(e) {
|
|
31
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
32
|
+
env.hasError = true;
|
|
33
|
+
}
|
|
34
|
+
var r, s = 0;
|
|
35
|
+
function next() {
|
|
36
|
+
while (r = env.stack.pop()) {
|
|
37
|
+
try {
|
|
38
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
39
|
+
if (r.dispose) {
|
|
40
|
+
var result = r.dispose.call(r.value);
|
|
41
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
42
|
+
}
|
|
43
|
+
else s |= 1;
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
fail(e);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
50
|
+
if (env.hasError) throw env.error;
|
|
51
|
+
}
|
|
52
|
+
return next();
|
|
53
|
+
};
|
|
54
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
55
|
+
var e = new Error(message);
|
|
56
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
57
|
+
});
|
|
58
|
+
import { logger } from './utils/logger.js';
|
|
7
59
|
export class TextSnapshot {
|
|
8
60
|
static nextSnapshotId = 1;
|
|
9
61
|
static resetCounter() {
|
|
@@ -88,7 +140,7 @@ export class TextSnapshot {
|
|
|
88
140
|
const data = options.devtoolsData ?? (await page.getDevToolsData());
|
|
89
141
|
if (data?.cdpBackendNodeId) {
|
|
90
142
|
snapshot.hasSelectedElement = true;
|
|
91
|
-
snapshot.selectedElementUid =
|
|
143
|
+
snapshot.selectedElementUid = snapshot.resolveCdpElementId(data.cdpBackendNodeId);
|
|
92
144
|
}
|
|
93
145
|
// Clean up unique IDs that we did not see anymore.
|
|
94
146
|
for (const key of uniqueBackendNodeIdToMcpId.keys()) {
|
|
@@ -98,6 +150,24 @@ export class TextSnapshot {
|
|
|
98
150
|
}
|
|
99
151
|
return snapshot;
|
|
100
152
|
}
|
|
153
|
+
resolveCdpElementId(cdpBackendNodeId) {
|
|
154
|
+
if (!cdpBackendNodeId) {
|
|
155
|
+
logger?.('no cdpBackendNodeId');
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
// TODO: index by backendNodeId instead.
|
|
159
|
+
const queue = [this.root];
|
|
160
|
+
while (queue.length) {
|
|
161
|
+
const current = queue.pop();
|
|
162
|
+
if (current.backendNodeId === cdpBackendNodeId) {
|
|
163
|
+
return current.id;
|
|
164
|
+
}
|
|
165
|
+
for (const child of current.children) {
|
|
166
|
+
queue.push(child);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
101
171
|
// ExtraHandles represent DOM nodes which might not be part of the accessibility tree, e.g. DOM nodes
|
|
102
172
|
// returned by third-party developer tools. We insert them into the tree by finding the closest ancestor
|
|
103
173
|
// in the tree and inserting the node as a child. The ancestor's child nodes are re-parented if necessary.
|
|
@@ -135,28 +205,37 @@ export class TextSnapshot {
|
|
|
135
205
|
return extraNode;
|
|
136
206
|
};
|
|
137
207
|
const findAncestorNode = async (handle) => {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
const ancestorNode = idToNode
|
|
148
|
-
.values()
|
|
149
|
-
.find(node => node.backendNodeId === ancestorBackendId);
|
|
150
|
-
if (ancestorNode) {
|
|
151
|
-
await ancestorHandle.dispose();
|
|
152
|
-
return ancestorNode;
|
|
208
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
209
|
+
try {
|
|
210
|
+
let ancestorHandle = await handle.evaluateHandle(el => el.parentElement);
|
|
211
|
+
const stack = __addDisposableResource(env_1, new DisposableStack(), false);
|
|
212
|
+
while (ancestorHandle) {
|
|
213
|
+
stack.use(ancestorHandle);
|
|
214
|
+
const ancestorElement = ancestorHandle.asElement();
|
|
215
|
+
if (!ancestorElement) {
|
|
216
|
+
return null;
|
|
153
217
|
}
|
|
218
|
+
const ancestorBackendId = await ancestorElement.backendNodeId();
|
|
219
|
+
if (ancestorBackendId) {
|
|
220
|
+
const ancestorNode = idToNode
|
|
221
|
+
.values()
|
|
222
|
+
.find(node => node.backendNodeId === ancestorBackendId);
|
|
223
|
+
if (ancestorNode) {
|
|
224
|
+
return ancestorNode;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
const nextHandle = await ancestorElement.evaluateHandle(el => el.parentElement);
|
|
228
|
+
ancestorHandle = nextHandle;
|
|
154
229
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
catch (e_1) {
|
|
233
|
+
env_1.error = e_1;
|
|
234
|
+
env_1.hasError = true;
|
|
235
|
+
}
|
|
236
|
+
finally {
|
|
237
|
+
__disposeResources(env_1);
|
|
158
238
|
}
|
|
159
|
-
return null;
|
|
160
239
|
};
|
|
161
240
|
const findDescendantNodes = async (backendNodeId) => {
|
|
162
241
|
const descendantIds = new Set();
|
|
@@ -186,7 +265,7 @@ export class TextSnapshot {
|
|
|
186
265
|
}
|
|
187
266
|
}
|
|
188
267
|
catch (e) {
|
|
189
|
-
logger(`Failed to collect descendants for backend node ${backendNodeId}`, e);
|
|
268
|
+
logger?.(`Failed to collect descendants for backend node ${backendNodeId}`, e);
|
|
190
269
|
}
|
|
191
270
|
return descendantIds;
|
|
192
271
|
};
|
package/build/src/ToolHandler.js
CHANGED
|
@@ -2,14 +2,22 @@
|
|
|
2
2
|
* @license
|
|
3
3
|
* Copyright 2026 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*
|
|
6
|
+
* Modified by Opera Software AS: optional `hooks` seam (see
|
|
7
|
+
* ./opera/toolHandlerHooks.ts) for mutex bypass, browser relaunch and log
|
|
8
|
+
* streaming. Keep the diff to the three `this.hooks?.` call sites.
|
|
5
9
|
*/
|
|
6
|
-
import { logger } from './logger.js';
|
|
7
10
|
import { McpResponse } from './McpResponse.js';
|
|
11
|
+
import { CLI_BIN_NAME } from './opera/branding.js';
|
|
8
12
|
import { SlimMcpResponse } from './SlimMcpResponse.js';
|
|
9
13
|
import { ClearcutLogger } from './telemetry/ClearcutLogger.js';
|
|
10
|
-
import { bucketizeLatency } from './telemetry/
|
|
14
|
+
import { bucketizeLatency, buildContext } from './telemetry/transformation.js';
|
|
15
|
+
import { zod } from './third_party/index.js';
|
|
11
16
|
import { labels, OFF_BY_DEFAULT_CATEGORIES } from './tools/categories.js';
|
|
12
17
|
import { pageIdSchema } from './tools/ToolDefinition.js';
|
|
18
|
+
import { logger } from './utils/logger.js';
|
|
19
|
+
import { fileURLToPath } from 'node:url';
|
|
20
|
+
import { isLocalhost } from './utils/url.js';
|
|
13
21
|
export function buildFlag(category) {
|
|
14
22
|
return `category${category.charAt(0).toUpperCase() + category.slice(1)}`;
|
|
15
23
|
}
|
|
@@ -17,7 +25,7 @@ function buildDisabledMessage(toolName, flag, categoryLabel) {
|
|
|
17
25
|
const reason = categoryLabel
|
|
18
26
|
? `is in category ${categoryLabel} which`
|
|
19
27
|
: `requires experimental feature ${flag} and`;
|
|
20
|
-
return `Tool ${toolName} ${reason} is currently disabled. Enable it by running
|
|
28
|
+
return `Tool ${toolName} ${reason} is currently disabled. Enable it by running ${CLI_BIN_NAME} start ${flag}=true. For more information check the README.`;
|
|
21
29
|
}
|
|
22
30
|
function getCategoryStatus(category, serverArgs) {
|
|
23
31
|
const categoryFlag = buildFlag(category);
|
|
@@ -70,19 +78,89 @@ function getToolStatusInfo(tool, serverArgs) {
|
|
|
70
78
|
function isPageScopedTool(tool) {
|
|
71
79
|
return 'pageScoped' in tool && tool.pageScoped === true;
|
|
72
80
|
}
|
|
81
|
+
function formatArgumentNames(names) {
|
|
82
|
+
return names.map(name => `"${name}"`).join(', ');
|
|
83
|
+
}
|
|
84
|
+
function buildUnknownArgumentsMessage(toolName, unknownArgumentNames, expectedArgumentNames) {
|
|
85
|
+
const unknownLabel = unknownArgumentNames.length === 1 ? 'argument' : 'arguments';
|
|
86
|
+
const expectedArguments = expectedArgumentNames.length
|
|
87
|
+
? `Expected arguments: ${formatArgumentNames(expectedArgumentNames)}.`
|
|
88
|
+
: 'This tool does not accept any arguments.';
|
|
89
|
+
const correction = unknownArgumentNames.length === 1 ? 'Remove it' : 'Remove them';
|
|
90
|
+
return `Unknown ${unknownLabel} for tool "${toolName}": ${formatArgumentNames(unknownArgumentNames)}. ${expectedArguments} ${correction} and retry.`;
|
|
91
|
+
}
|
|
92
|
+
function extractPaths(value) {
|
|
93
|
+
if (typeof value === 'string') {
|
|
94
|
+
return [value];
|
|
95
|
+
}
|
|
96
|
+
if (Array.isArray(value)) {
|
|
97
|
+
return value.filter(item => typeof item === 'string');
|
|
98
|
+
}
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
101
|
+
function isLocalBrowser(context) {
|
|
102
|
+
if (context.browser.process()) {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
const wsEndpoint = context.browser.wsEndpoint();
|
|
106
|
+
if (wsEndpoint && isLocalhost(wsEndpoint)) {
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
function shouldValidateFile(option, isLocal) {
|
|
112
|
+
if (option === true) {
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
if (typeof option === 'object' && option !== null) {
|
|
116
|
+
if (isLocal) {
|
|
117
|
+
return Boolean(option.local);
|
|
118
|
+
}
|
|
119
|
+
return Boolean(option.remote);
|
|
120
|
+
}
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
async function validateToolFiles(tool, params, context) {
|
|
124
|
+
const isLocal = isLocalBrowser(context);
|
|
125
|
+
const pathsOrUrlsToValidate = [];
|
|
126
|
+
for (const [key, option] of Object.entries(tool.verifyFilesSchema)) {
|
|
127
|
+
if (shouldValidateFile(option, isLocal)) {
|
|
128
|
+
pathsOrUrlsToValidate.push(...extractPaths(params[key]));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
for (const filePathOrUrl of pathsOrUrlsToValidate) {
|
|
132
|
+
let filePath = filePathOrUrl;
|
|
133
|
+
try {
|
|
134
|
+
const url = new URL(filePathOrUrl);
|
|
135
|
+
if (url.protocol === 'file:') {
|
|
136
|
+
filePath = fileURLToPath(url);
|
|
137
|
+
}
|
|
138
|
+
else if (['http:', 'https:', 'ws:', 'wss:'].includes(url.protocol)) {
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// Suppress parsing errors for regular file paths.
|
|
144
|
+
}
|
|
145
|
+
await context.validatePath(filePath);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
73
148
|
export class ToolHandler {
|
|
74
149
|
tool;
|
|
75
150
|
serverArgs;
|
|
76
151
|
getContext;
|
|
77
152
|
toolMutex;
|
|
153
|
+
hooks;
|
|
78
154
|
inputSchema;
|
|
155
|
+
registeredInputSchema;
|
|
79
156
|
shouldRegister;
|
|
80
157
|
disabledReason;
|
|
81
|
-
constructor(tool, serverArgs, getContext, toolMutex) {
|
|
158
|
+
constructor(tool, serverArgs, getContext, toolMutex, hooks) {
|
|
82
159
|
this.tool = tool;
|
|
83
160
|
this.serverArgs = serverArgs;
|
|
84
161
|
this.getContext = getContext;
|
|
85
162
|
this.toolMutex = toolMutex;
|
|
163
|
+
this.hooks = hooks;
|
|
86
164
|
const { disabled, reason } = getToolStatusInfo(tool, serverArgs);
|
|
87
165
|
this.disabledReason = reason;
|
|
88
166
|
this.shouldRegister = !(disabled && !serverArgs.viaCli);
|
|
@@ -91,10 +169,14 @@ export class ToolHandler {
|
|
|
91
169
|
tool.pageScoped &&
|
|
92
170
|
serverArgs.experimentalPageIdRouting &&
|
|
93
171
|
!serverArgs.slim
|
|
94
|
-
? { ...tool.schema
|
|
172
|
+
? { ...pageIdSchema, ...tool.schema }
|
|
95
173
|
: tool.schema;
|
|
174
|
+
this.registeredInputSchema = zod.object(this.inputSchema).passthrough();
|
|
96
175
|
}
|
|
97
|
-
|
|
176
|
+
unknownArgumentNames(params) {
|
|
177
|
+
return Object.keys(params).filter(key => !Object.hasOwn(this.inputSchema, key));
|
|
178
|
+
}
|
|
179
|
+
async handle(params, extra) {
|
|
98
180
|
if (this.disabledReason) {
|
|
99
181
|
return {
|
|
100
182
|
content: [
|
|
@@ -106,26 +188,49 @@ export class ToolHandler {
|
|
|
106
188
|
isError: true,
|
|
107
189
|
};
|
|
108
190
|
}
|
|
109
|
-
const
|
|
191
|
+
const unknownArgumentNames = this.unknownArgumentNames(params);
|
|
192
|
+
if (unknownArgumentNames.length) {
|
|
193
|
+
return {
|
|
194
|
+
content: [
|
|
195
|
+
{
|
|
196
|
+
type: 'text',
|
|
197
|
+
text: buildUnknownArgumentsMessage(this.tool.name, unknownArgumentNames, Object.keys(this.inputSchema)),
|
|
198
|
+
},
|
|
199
|
+
],
|
|
200
|
+
isError: true,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
const guard = this.hooks?.bypassMutex(this.tool)
|
|
204
|
+
? undefined
|
|
205
|
+
: await this.toolMutex.acquire();
|
|
110
206
|
const startTime = Date.now();
|
|
111
207
|
let success = false;
|
|
208
|
+
let devToolsData;
|
|
209
|
+
let pageUrl;
|
|
112
210
|
try {
|
|
113
|
-
logger(`${this.tool.name} request: ${JSON.stringify(params, null, ' ')}`);
|
|
211
|
+
logger?.(`${this.tool.name} request: ${JSON.stringify(params, null, ' ')}`);
|
|
212
|
+
await this.hooks?.beforeInvoke(this.tool);
|
|
114
213
|
const context = await this.getContext();
|
|
115
|
-
logger(`${this.tool.name} context: resolved`);
|
|
116
|
-
|
|
214
|
+
logger?.(`${this.tool.name} context: resolved`);
|
|
215
|
+
const logCallback = this.hooks?.makeLogCallback(extra);
|
|
117
216
|
const response = this.serverArgs.slim
|
|
118
|
-
? new SlimMcpResponse(this.serverArgs)
|
|
119
|
-
: new McpResponse(this.serverArgs);
|
|
217
|
+
? new SlimMcpResponse(this.serverArgs, logCallback)
|
|
218
|
+
: new McpResponse(this.serverArgs, logCallback);
|
|
120
219
|
response.setRedactNetworkHeaders(this.serverArgs.redactNetworkHeaders);
|
|
220
|
+
if (context.consumeReconnectNotice()) {
|
|
221
|
+
response.setReconnectNotice();
|
|
222
|
+
}
|
|
223
|
+
let page;
|
|
121
224
|
try {
|
|
225
|
+
await validateToolFiles(this.tool, params, context);
|
|
122
226
|
if (isPageScopedTool(this.tool)) {
|
|
123
227
|
const pageId = typeof params.pageId === 'number' ? params.pageId : undefined;
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
228
|
+
page =
|
|
229
|
+
this.serverArgs.experimentalPageIdRouting &&
|
|
230
|
+
pageId !== undefined &&
|
|
231
|
+
!this.serverArgs.slim
|
|
232
|
+
? context.getPageById(pageId)
|
|
233
|
+
: context.getSelectedMcpPage();
|
|
129
234
|
response.setPage(page);
|
|
130
235
|
if (this.tool.blockedByDialog) {
|
|
131
236
|
page.throwIfDialogOpen();
|
|
@@ -133,18 +238,33 @@ export class ToolHandler {
|
|
|
133
238
|
await this.tool.handler({
|
|
134
239
|
params,
|
|
135
240
|
page,
|
|
241
|
+
signal: extra?.signal,
|
|
136
242
|
}, response, context);
|
|
137
243
|
}
|
|
138
244
|
else {
|
|
139
245
|
await this.tool.handler({
|
|
140
246
|
params,
|
|
247
|
+
signal: extra?.signal,
|
|
141
248
|
}, response, context);
|
|
142
249
|
}
|
|
143
250
|
}
|
|
144
251
|
catch (err) {
|
|
145
252
|
response.setError(err);
|
|
146
253
|
}
|
|
147
|
-
|
|
254
|
+
devToolsData = await context.getDevToolsData(page);
|
|
255
|
+
const targetPage = page ?? context.getSelectedMcpPage();
|
|
256
|
+
if (targetPage?.pptrPage?.isClosed() === false) {
|
|
257
|
+
pageUrl = targetPage.pptrPage.url();
|
|
258
|
+
}
|
|
259
|
+
// Resolve data format: --experimentalDataFormat takes precedence, fall back to legacy --experimentalToonFormat
|
|
260
|
+
let dataFormat = 'default';
|
|
261
|
+
if (this.serverArgs.experimentalDataFormat) {
|
|
262
|
+
dataFormat = this.serverArgs.experimentalDataFormat;
|
|
263
|
+
}
|
|
264
|
+
else if (this.serverArgs.experimentalToonFormat) {
|
|
265
|
+
dataFormat = 'toon';
|
|
266
|
+
}
|
|
267
|
+
const { content, structuredContent } = await response.handle(context, dataFormat);
|
|
148
268
|
const result = {
|
|
149
269
|
content,
|
|
150
270
|
};
|
|
@@ -158,7 +278,7 @@ export class ToolHandler {
|
|
|
158
278
|
return result;
|
|
159
279
|
}
|
|
160
280
|
catch (err) {
|
|
161
|
-
logger(`${this.tool.name} error:`, err, err?.stack);
|
|
281
|
+
logger?.(`${this.tool.name} error:`, err, err?.stack);
|
|
162
282
|
let errorText = err && 'message' in err ? err.message : String(err);
|
|
163
283
|
if ('cause' in err && err.cause) {
|
|
164
284
|
errorText += `\nCause: ${err.cause.message}`;
|
|
@@ -174,14 +294,16 @@ export class ToolHandler {
|
|
|
174
294
|
};
|
|
175
295
|
}
|
|
176
296
|
finally {
|
|
297
|
+
const context = buildContext(devToolsData, pageUrl);
|
|
177
298
|
void ClearcutLogger.get()?.logToolInvocation({
|
|
178
299
|
toolName: this.tool.name,
|
|
179
300
|
params,
|
|
180
301
|
schema: this.inputSchema,
|
|
181
302
|
success,
|
|
182
303
|
latencyMs: bucketizeLatency(Date.now() - startTime),
|
|
304
|
+
context,
|
|
183
305
|
});
|
|
184
|
-
guard.dispose();
|
|
306
|
+
guard?.[Symbol.dispose]();
|
|
185
307
|
}
|
|
186
308
|
}
|
|
187
309
|
}
|
|
@@ -5,13 +5,39 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Modified by Opera Software AS.
|
|
7
7
|
*/
|
|
8
|
+
import { execSync } from 'node:child_process';
|
|
8
9
|
import fs from 'node:fs/promises';
|
|
9
10
|
import path from 'node:path';
|
|
10
11
|
import process from 'node:process';
|
|
12
|
+
import { PACKAGE_NAME } from '../opera/branding.js';
|
|
13
|
+
const DEFAULT_REGISTRY = 'https://registry.npmjs.org';
|
|
14
|
+
function getRegistry() {
|
|
15
|
+
// Use the user's configured npm registry so update checks work behind
|
|
16
|
+
// corporate proxies and private registries. `npm config get registry`
|
|
17
|
+
// honors .npmrc files at every scope and respects npm_config_registry,
|
|
18
|
+
// so it covers direct CLI invocations as well as `npx` / `npm run`.
|
|
19
|
+
try {
|
|
20
|
+
const registry = execSync('npm config get registry', {
|
|
21
|
+
encoding: 'utf8',
|
|
22
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
23
|
+
timeout: 5000,
|
|
24
|
+
windowsHide: true,
|
|
25
|
+
})
|
|
26
|
+
.trim()
|
|
27
|
+
.replace(/\/$/, '');
|
|
28
|
+
if (registry && registry !== 'undefined' && /^https?:\/\//.test(registry)) {
|
|
29
|
+
return registry;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// npm not on PATH or other errors, fall back to default.
|
|
34
|
+
}
|
|
35
|
+
return DEFAULT_REGISTRY;
|
|
36
|
+
}
|
|
11
37
|
const cachePath = process.argv[2];
|
|
12
38
|
if (cachePath) {
|
|
13
39
|
try {
|
|
14
|
-
const response = await fetch(
|
|
40
|
+
const response = await fetch(`${getRegistry()}/${PACKAGE_NAME}/latest`);
|
|
15
41
|
const data = response.ok ? await response.json() : null;
|
|
16
42
|
if (data &&
|
|
17
43
|
typeof data === 'object' &&
|