chrome-devtools-frontend 1.0.1700561 → 1.0.1702515

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/eslint.config.mjs +3 -1
  2. package/front_end/core/host/UserMetricsEnums.ts +2 -1
  3. package/front_end/core/root/ExperimentNames.ts +1 -0
  4. package/front_end/core/root/Runtime.ts +5 -0
  5. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +10 -10
  6. package/front_end/core/sdk/NetworkManager.ts +7 -0
  7. package/front_end/core/sdk/SecurityOrigin.ts +1 -0
  8. package/front_end/core/sdk/SourceMap.ts +12 -1
  9. package/front_end/core/sdk/SourceMapCache.ts +12 -0
  10. package/front_end/core/sdk/SourceMapManager.ts +17 -8
  11. package/front_end/core/sdk/SourceMapScopeChainEntry.ts +2 -19
  12. package/front_end/core/sdk/SourceMapScopesInfo.ts +21 -0
  13. package/front_end/devtools_compatibility.js +2 -1
  14. package/front_end/entrypoints/formatter_worker/ScopeParser.ts +7 -3
  15. package/front_end/entrypoints/formatter_worker/Substitute.ts +90 -26
  16. package/front_end/entrypoints/formatter_worker/formatter_worker-entrypoint.ts +1 -1
  17. package/front_end/entrypoints/main/ExecutionContextSelector.ts +17 -4
  18. package/front_end/entrypoints/main/MainImpl.ts +8 -0
  19. package/front_end/generated/InspectorBackendCommands.ts +4 -6
  20. package/front_end/generated/protocol-mapping.d.ts +0 -8
  21. package/front_end/generated/protocol-proxy-api.d.ts +0 -6
  22. package/front_end/generated/protocol.ts +4 -25
  23. package/front_end/models/ai_assistance/AiAgent2.ts +13 -1
  24. package/front_end/models/ai_assistance/AiConversation.ts +1 -1
  25. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +13 -19
  26. package/front_end/models/ai_assistance/debug.ts +10 -2
  27. package/front_end/models/change_tracker/ChangeTracker.ts +5 -64
  28. package/front_end/models/comment_manager/CD4ABridge.ts +2 -2
  29. package/front_end/models/comment_manager/CommentManager.ts +6 -5
  30. package/front_end/models/comment_manager/CommentThread.ts +30 -13
  31. package/front_end/models/formatter/FormatterWorkerPool.ts +2 -2
  32. package/front_end/models/issues_manager/CookieDeprecationMetadataIssue.ts +6 -7
  33. package/front_end/models/issues_manager/DeprecationIssue.ts +1 -1
  34. package/front_end/models/issues_manager/MarkdownIssueDescription.ts +14 -5
  35. package/front_end/models/issues_manager/SRIMessageSignatureIssue.ts +2 -4
  36. package/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantRead.md +0 -1
  37. package/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantReadOptOut.md +5 -0
  38. package/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantSet.md +0 -1
  39. package/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantSetOptOut.md +5 -0
  40. package/front_end/models/issues_manager/descriptions/deprecation.md +1 -1
  41. package/front_end/models/issues_manager/descriptions/sriValidationFailedIntegrityMismatch.md +2 -0
  42. package/front_end/models/javascript_metadata/NativeFunctions.ts +7 -2
  43. package/front_end/models/persistence/NetworkPersistenceManager.ts +14 -2
  44. package/front_end/models/source_map_scopes/NamesResolver.ts +42 -39
  45. package/front_end/panels/accessibility/AccessibilityAnnouncementRecordingView.ts +70 -1
  46. package/front_end/panels/ai_assistance/components/ChatMessage.ts +1 -1
  47. package/front_end/panels/common/CommentThreadWidget.ts +29 -10
  48. package/front_end/panels/common/CommentsOverlayWidget.ts +77 -14
  49. package/front_end/panels/common/ExtensionServer.ts +18 -8
  50. package/front_end/panels/common/commentThreadWidget.css +11 -0
  51. package/front_end/panels/console/ConsolePrompt.ts +1 -1
  52. package/front_end/panels/console/ConsoleViewMessage.ts +1 -1
  53. package/front_end/panels/elements/ClassesPaneWidget.ts +2 -1
  54. package/front_end/panels/elements/DOMTreeContextMenu.ts +1 -1
  55. package/front_end/panels/elements/{ElementsTreeOutline.ts → DOMTreeWidget.ts} +34 -24
  56. package/front_end/panels/elements/ElementsPanel.ts +1 -1
  57. package/front_end/panels/elements/ElementsTreeElement.ts +1 -1
  58. package/front_end/panels/elements/ShortcutTreeElement.ts +1 -1
  59. package/front_end/panels/elements/StylePropertiesSection.ts +10 -0
  60. package/front_end/panels/elements/StylesSidebarPane.ts +105 -55
  61. package/front_end/panels/elements/TopLayerContainer.ts +1 -1
  62. package/front_end/panels/elements/components/CSSQuery.ts +1 -1
  63. package/front_end/panels/elements/components/cssQuery.css +4 -0
  64. package/front_end/panels/elements/elements.ts +3 -3
  65. package/front_end/panels/elements/stylesSidebarPane.css +6 -0
  66. package/front_end/panels/profiler/HeapDetachedElementsDataGrid.ts +1 -1
  67. package/front_end/panels/profiler/HeapProfileView.ts +8 -6
  68. package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +8 -1
  69. package/front_end/panels/profiler/HeapSnapshotView.ts +6 -4
  70. package/front_end/panels/security/SecurityPanel.ts +87 -99
  71. package/front_end/panels/sensors/SensorsView.ts +87 -0
  72. package/front_end/panels/sensors/sensors-meta.ts +69 -1
  73. package/front_end/panels/settings/keybindsSettingsTab.css +1 -1
  74. package/front_end/panels/sources/ResourceOriginPlugin.ts +8 -3
  75. package/front_end/panels/sources/ScopeChainSidebarPane.ts +3 -4
  76. package/front_end/panels/sources/TabbedEditorContainer.ts +339 -126
  77. package/front_end/panels/sources/UISourceCodeFrame.ts +9 -0
  78. package/front_end/third_party/chromium/README.chromium +1 -1
  79. package/front_end/third_party/chromium/client-variations/ClientVariations.js +25 -96
  80. package/front_end/third_party/codemirror.next/chunk/angular.js +1 -1
  81. package/front_end/third_party/codemirror.next/chunk/codemirror.js +1 -1
  82. package/front_end/third_party/codemirror.next/chunk/codemirror.js.map +1 -1
  83. package/front_end/third_party/codemirror.next/chunk/cpp.js +1 -1
  84. package/front_end/third_party/codemirror.next/chunk/cpp.js.map +1 -1
  85. package/front_end/third_party/codemirror.next/chunk/java.js +1 -1
  86. package/front_end/third_party/codemirror.next/chunk/java.js.map +1 -1
  87. package/front_end/third_party/codemirror.next/chunk/legacy.js +1 -1
  88. package/front_end/third_party/codemirror.next/chunk/less.js +1 -1
  89. package/front_end/third_party/codemirror.next/chunk/less.js.map +1 -1
  90. package/front_end/third_party/codemirror.next/chunk/markdown.js +1 -1
  91. package/front_end/third_party/codemirror.next/chunk/markdown.js.map +1 -1
  92. package/front_end/third_party/codemirror.next/chunk/php.js +1 -1
  93. package/front_end/third_party/codemirror.next/chunk/php.js.map +1 -1
  94. package/front_end/third_party/codemirror.next/chunk/python.js +1 -1
  95. package/front_end/third_party/codemirror.next/chunk/python.js.map +1 -1
  96. package/front_end/third_party/codemirror.next/chunk/sass.js +1 -1
  97. package/front_end/third_party/codemirror.next/chunk/sass.js.map +1 -1
  98. package/front_end/third_party/codemirror.next/chunk/svelte.js +1 -1
  99. package/front_end/third_party/codemirror.next/chunk/svelte.js.map +1 -1
  100. package/front_end/third_party/codemirror.next/chunk/vue.js +1 -1
  101. package/front_end/third_party/codemirror.next/chunk/wast.js +1 -1
  102. package/front_end/third_party/codemirror.next/chunk/wast.js.map +1 -1
  103. package/front_end/third_party/codemirror.next/chunk/xml.js +1 -1
  104. package/front_end/third_party/codemirror.next/chunk/xml.js.map +1 -1
  105. package/front_end/third_party/codemirror.next/codemirror.next.js +1 -1
  106. package/front_end/third_party/codemirror.next/package.json +4 -1
  107. package/front_end/third_party/codemirror.next/rebuild.sh +1 -1
  108. package/front_end/ui/comments/CommentOverlayManager.ts +11 -10
  109. package/front_end/ui/components/markdown_view/MarkdownPlaceholderLitRenderer.ts +117 -0
  110. package/front_end/ui/components/markdown_view/markdown_view.ts +2 -0
  111. package/front_end/ui/legacy/Treeoutline.ts +30 -20
  112. package/front_end/ui/legacy/UIUtils.ts +1 -1
  113. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +1 -1
  114. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +228 -343
  115. package/front_end/ui/legacy/components/object_ui/objectPropertiesSection.css +2 -27
  116. package/front_end/ui/legacy/treeoutline.css +2 -2
  117. package/front_end/ui/visual_logging/KnownContextValues.ts +7 -0
  118. package/mcp/mcp.ts +1 -0
  119. package/package.json +1 -1
@@ -73,7 +73,7 @@ inspectorBackend.registerType("Animation.KeyframesRule", [{"name": "name", "type
73
73
  inspectorBackend.registerType("Animation.KeyframeStyle", [{"name": "offset", "type": "string", "optional": false, "description": "Keyframe's time offset.", "typeRef": null}, {"name": "easing", "type": "string", "optional": false, "description": "`AnimationEffect`'s timing function.", "typeRef": null}]);
74
74
 
75
75
  // Audits.
76
- inspectorBackend.registerEnum("Audits.CookieExclusionReason", {ExcludeSameSiteUnspecifiedTreatedAsLax: "ExcludeSameSiteUnspecifiedTreatedAsLax", ExcludeSameSiteNoneInsecure: "ExcludeSameSiteNoneInsecure", ExcludeSameSiteLax: "ExcludeSameSiteLax", ExcludeSameSiteStrict: "ExcludeSameSiteStrict", ExcludeDomainNonASCII: "ExcludeDomainNonASCII", ExcludeThirdPartyCookieBlockedInFirstPartySet: "ExcludeThirdPartyCookieBlockedInFirstPartySet", ExcludeThirdPartyPhaseout: "ExcludeThirdPartyPhaseout", ExcludePortMismatch: "ExcludePortMismatch", ExcludeSchemeMismatch: "ExcludeSchemeMismatch"});
76
+ inspectorBackend.registerEnum("Audits.CookieExclusionReason", {ExcludeSameSiteUnspecifiedTreatedAsLax: "ExcludeSameSiteUnspecifiedTreatedAsLax", ExcludeSameSiteNoneInsecure: "ExcludeSameSiteNoneInsecure", ExcludeSameSiteLax: "ExcludeSameSiteLax", ExcludeSameSiteStrict: "ExcludeSameSiteStrict", ExcludeDomainNonASCII: "ExcludeDomainNonASCII", ExcludeThirdPartyPhaseout: "ExcludeThirdPartyPhaseout", ExcludePortMismatch: "ExcludePortMismatch", ExcludeSchemeMismatch: "ExcludeSchemeMismatch"});
77
77
  inspectorBackend.registerEnum("Audits.CookieWarningReason", {WarnSameSiteUnspecifiedCrossSiteContext: "WarnSameSiteUnspecifiedCrossSiteContext", WarnSameSiteNoneInsecure: "WarnSameSiteNoneInsecure", WarnSameSiteUnspecifiedLaxAllowUnsafe: "WarnSameSiteUnspecifiedLaxAllowUnsafe", WarnSameSiteStrictLaxDowngradeStrict: "WarnSameSiteStrictLaxDowngradeStrict", WarnSameSiteStrictCrossDowngradeStrict: "WarnSameSiteStrictCrossDowngradeStrict", WarnSameSiteStrictCrossDowngradeLax: "WarnSameSiteStrictCrossDowngradeLax", WarnSameSiteLaxCrossDowngradeStrict: "WarnSameSiteLaxCrossDowngradeStrict", WarnSameSiteLaxCrossDowngradeLax: "WarnSameSiteLaxCrossDowngradeLax", WarnAttributeValueExceedsMaxSize: "WarnAttributeValueExceedsMaxSize", WarnDomainNonASCII: "WarnDomainNonASCII", WarnThirdPartyPhaseout: "WarnThirdPartyPhaseout", WarnCrossSiteRedirectDowngradeChangesInclusion: "WarnCrossSiteRedirectDowngradeChangesInclusion", WarnDeprecationTrialMetadata: "WarnDeprecationTrialMetadata", WarnThirdPartyCookieHeuristic: "WarnThirdPartyCookieHeuristic"});
78
78
  inspectorBackend.registerEnum("Audits.CookieOperation", {SetCookie: "SetCookie", ReadCookie: "ReadCookie"});
79
79
  inspectorBackend.registerEnum("Audits.InsightType", {GitHubResource: "GitHubResource", GracePeriod: "GracePeriod", Heuristics: "Heuristics"});
@@ -815,8 +815,8 @@ inspectorBackend.registerEnum("Network.TrustTokenOperationType", {Issuance: "Iss
815
815
  inspectorBackend.registerEnum("Network.AlternateProtocolUsage", {AlternativeJobWonWithoutRace: "alternativeJobWonWithoutRace", AlternativeJobWonRace: "alternativeJobWonRace", MainJobWonRace: "mainJobWonRace", MappingMissing: "mappingMissing", Broken: "broken", DnsAlpnH3JobWonWithoutRace: "dnsAlpnH3JobWonWithoutRace", DnsAlpnH3JobWonRace: "dnsAlpnH3JobWonRace", UnspecifiedReason: "unspecifiedReason"});
816
816
  inspectorBackend.registerEnum("Network.ServiceWorkerRouterSource", {Network: "network", Cache: "cache", FetchEvent: "fetch-event", RaceNetworkAndFetchHandler: "race-network-and-fetch-handler", RaceNetworkAndCache: "race-network-and-cache"});
817
817
  inspectorBackend.registerEnum("Network.InitiatorType", {Parser: "parser", Script: "script", Preload: "preload", SignedExchange: "SignedExchange", Preflight: "preflight", FedCM: "FedCM", Other: "other"});
818
- inspectorBackend.registerEnum("Network.SetCookieBlockedReason", {SecureOnly: "SecureOnly", SameSiteStrict: "SameSiteStrict", SameSiteLax: "SameSiteLax", SameSiteUnspecifiedTreatedAsLax: "SameSiteUnspecifiedTreatedAsLax", SameSiteNoneInsecure: "SameSiteNoneInsecure", UserPreferences: "UserPreferences", ThirdPartyPhaseout: "ThirdPartyPhaseout", ThirdPartyBlockedInFirstPartySet: "ThirdPartyBlockedInFirstPartySet", SyntaxError: "SyntaxError", SchemeNotSupported: "SchemeNotSupported", OverwriteSecure: "OverwriteSecure", InvalidDomain: "InvalidDomain", InvalidPrefix: "InvalidPrefix", UnknownError: "UnknownError", SchemefulSameSiteStrict: "SchemefulSameSiteStrict", SchemefulSameSiteLax: "SchemefulSameSiteLax", SchemefulSameSiteUnspecifiedTreatedAsLax: "SchemefulSameSiteUnspecifiedTreatedAsLax", NameValuePairExceedsMaxSize: "NameValuePairExceedsMaxSize", DisallowedCharacter: "DisallowedCharacter", NoCookieContent: "NoCookieContent"});
819
- inspectorBackend.registerEnum("Network.CookieBlockedReason", {SecureOnly: "SecureOnly", NotOnPath: "NotOnPath", DomainMismatch: "DomainMismatch", SameSiteStrict: "SameSiteStrict", SameSiteLax: "SameSiteLax", SameSiteUnspecifiedTreatedAsLax: "SameSiteUnspecifiedTreatedAsLax", SameSiteNoneInsecure: "SameSiteNoneInsecure", UserPreferences: "UserPreferences", ThirdPartyPhaseout: "ThirdPartyPhaseout", ThirdPartyBlockedInFirstPartySet: "ThirdPartyBlockedInFirstPartySet", UnknownError: "UnknownError", SchemefulSameSiteStrict: "SchemefulSameSiteStrict", SchemefulSameSiteLax: "SchemefulSameSiteLax", SchemefulSameSiteUnspecifiedTreatedAsLax: "SchemefulSameSiteUnspecifiedTreatedAsLax", NameValuePairExceedsMaxSize: "NameValuePairExceedsMaxSize", PortMismatch: "PortMismatch", SchemeMismatch: "SchemeMismatch", AnonymousContext: "AnonymousContext"});
818
+ inspectorBackend.registerEnum("Network.SetCookieBlockedReason", {SecureOnly: "SecureOnly", SameSiteStrict: "SameSiteStrict", SameSiteLax: "SameSiteLax", SameSiteUnspecifiedTreatedAsLax: "SameSiteUnspecifiedTreatedAsLax", SameSiteNoneInsecure: "SameSiteNoneInsecure", UserPreferences: "UserPreferences", ThirdPartyPhaseout: "ThirdPartyPhaseout", SyntaxError: "SyntaxError", SchemeNotSupported: "SchemeNotSupported", OverwriteSecure: "OverwriteSecure", InvalidDomain: "InvalidDomain", InvalidPrefix: "InvalidPrefix", UnknownError: "UnknownError", SchemefulSameSiteStrict: "SchemefulSameSiteStrict", SchemefulSameSiteLax: "SchemefulSameSiteLax", SchemefulSameSiteUnspecifiedTreatedAsLax: "SchemefulSameSiteUnspecifiedTreatedAsLax", NameValuePairExceedsMaxSize: "NameValuePairExceedsMaxSize", DisallowedCharacter: "DisallowedCharacter", NoCookieContent: "NoCookieContent"});
819
+ inspectorBackend.registerEnum("Network.CookieBlockedReason", {SecureOnly: "SecureOnly", NotOnPath: "NotOnPath", DomainMismatch: "DomainMismatch", SameSiteStrict: "SameSiteStrict", SameSiteLax: "SameSiteLax", SameSiteUnspecifiedTreatedAsLax: "SameSiteUnspecifiedTreatedAsLax", SameSiteNoneInsecure: "SameSiteNoneInsecure", UserPreferences: "UserPreferences", ThirdPartyPhaseout: "ThirdPartyPhaseout", UnknownError: "UnknownError", SchemefulSameSiteStrict: "SchemefulSameSiteStrict", SchemefulSameSiteLax: "SchemefulSameSiteLax", SchemefulSameSiteUnspecifiedTreatedAsLax: "SchemefulSameSiteUnspecifiedTreatedAsLax", NameValuePairExceedsMaxSize: "NameValuePairExceedsMaxSize", PortMismatch: "PortMismatch", SchemeMismatch: "SchemeMismatch", AnonymousContext: "AnonymousContext"});
820
820
  inspectorBackend.registerEnum("Network.CookieExemptionReason", {None: "None", UserSetting: "UserSetting", EnterprisePolicy: "EnterprisePolicy", StorageAccess: "StorageAccess", TopLevelStorageAccess: "TopLevelStorageAccess", Scheme: "Scheme", SameSiteNoneCookiesInSandbox: "SameSiteNoneCookiesInSandbox"});
821
821
  inspectorBackend.registerEnum("Network.AuthChallengeSource", {Server: "Server", Proxy: "Proxy"});
822
822
  inspectorBackend.registerEnum("Network.AuthChallengeResponseResponse", {Default: "Default", CancelAuth: "CancelAuth", ProvideCredentials: "ProvideCredentials"});
@@ -1368,13 +1368,11 @@ inspectorBackend.registerCommand("Storage.setPrivateVerificationTokensTracking",
1368
1368
  inspectorBackend.registerCommand("Storage.setStorageBucketTracking", [{"name": "storageKey", "type": "string", "optional": false, "description": "", "typeRef": null}, {"name": "enable", "type": "boolean", "optional": false, "description": "", "typeRef": null}], [], "Set tracking for a storage key's buckets.");
1369
1369
  inspectorBackend.registerCommand("Storage.deleteStorageBucket", [{"name": "bucket", "type": "object", "optional": false, "description": "", "typeRef": "Storage.StorageBucket"}], [], "Deletes the Storage Bucket with the given storage key and bucket name.");
1370
1370
  inspectorBackend.registerCommand("Storage.runBounceTrackingMitigations", [], ["deletedSites"], "Deletes state for sites identified as potential bounce trackers, immediately.");
1371
- inspectorBackend.registerCommand("Storage.getRelatedWebsiteSets", [], ["sets"], "Returns the effective Related Website Sets in use by this profile for the browser session. The effective Related Website Sets will not change during a browser session.");
1372
1371
  inspectorBackend.registerType("Storage.UsageForType", [{"name": "storageType", "type": "string", "optional": false, "description": "Name of storage type.", "typeRef": "Storage.StorageType"}, {"name": "usage", "type": "number", "optional": false, "description": "Storage usage (bytes).", "typeRef": null}]);
1373
1372
  inspectorBackend.registerType("Storage.TrustTokens", [{"name": "issuerOrigin", "type": "string", "optional": false, "description": "", "typeRef": null}, {"name": "count", "type": "number", "optional": false, "description": "", "typeRef": null}]);
1374
1373
  inspectorBackend.registerType("Storage.PrivateVerificationToken", [{"name": "id", "type": "string", "optional": false, "description": "Unique identifier of the token in the database.", "typeRef": null}, {"name": "issuerOrigin", "type": "string", "optional": false, "description": "Origin of the token issuer.", "typeRef": null}, {"name": "keyId", "type": "number", "optional": false, "description": "Public key ID used to issue the token.", "typeRef": null}, {"name": "expiration", "type": "number", "optional": false, "description": "Expiration timestamp in seconds since the epoch.", "typeRef": "Network.TimeSinceEpoch"}, {"name": "creationTime", "type": "number", "optional": false, "description": "Token creation timestamp in seconds since the epoch.", "typeRef": "Network.TimeSinceEpoch"}, {"name": "version", "type": "number", "optional": false, "description": "Token protocol version.", "typeRef": null}, {"name": "token", "type": "string", "optional": false, "description": "Base64-encoded serialized token.", "typeRef": null}]);
1375
1374
  inspectorBackend.registerType("Storage.StorageBucket", [{"name": "storageKey", "type": "string", "optional": false, "description": "", "typeRef": "Storage.SerializedStorageKey"}, {"name": "name", "type": "string", "optional": true, "description": "If not specified, it is the default bucket of the storageKey.", "typeRef": null}]);
1376
1375
  inspectorBackend.registerType("Storage.StorageBucketInfo", [{"name": "bucket", "type": "object", "optional": false, "description": "", "typeRef": "Storage.StorageBucket"}, {"name": "id", "type": "string", "optional": false, "description": "", "typeRef": null}, {"name": "expiration", "type": "number", "optional": false, "description": "", "typeRef": "Network.TimeSinceEpoch"}, {"name": "quota", "type": "number", "optional": false, "description": "Storage quota (bytes).", "typeRef": null}, {"name": "persistent", "type": "boolean", "optional": false, "description": "", "typeRef": null}, {"name": "durability", "type": "string", "optional": false, "description": "", "typeRef": "Storage.StorageBucketsDurability"}]);
1377
- inspectorBackend.registerType("Storage.RelatedWebsiteSet", [{"name": "primarySites", "type": "array", "optional": false, "description": "The primary site of this set, along with the ccTLDs if there is any.", "typeRef": "string"}, {"name": "associatedSites", "type": "array", "optional": false, "description": "The associated sites of this set, along with the ccTLDs if there is any.", "typeRef": "string"}, {"name": "serviceSites", "type": "array", "optional": false, "description": "The service sites of this set, along with the ccTLDs if there is any.", "typeRef": "string"}]);
1378
1376
 
1379
1377
  // SystemInfo.
1380
1378
  inspectorBackend.registerEnum("SystemInfo.SubsamplingFormat", {Yuv420: "yuv420", Yuv422: "yuv422", Yuv444: "yuv444"});
@@ -1507,7 +1505,7 @@ inspectorBackend.registerCommand("WebMCP.enable", [], [], "Enables the WebMCP do
1507
1505
  inspectorBackend.registerCommand("WebMCP.disable", [], [], "Disables the WebMCP domain.");
1508
1506
  inspectorBackend.registerCommand("WebMCP.invokeTool", [{"name": "frameId", "type": "string", "optional": false, "description": "Frame in which to invoke the tool.", "typeRef": "Page.FrameId"}, {"name": "toolName", "type": "string", "optional": false, "description": "Name of the tool to invoke.", "typeRef": null}, {"name": "input", "type": "object", "optional": false, "description": "Input parameters for the tool, matching the tool's inputSchema.", "typeRef": null}], ["invocationId"], "Invokes a registered tool.");
1509
1507
  inspectorBackend.registerCommand("WebMCP.cancelInvocation", [{"name": "invocationId", "type": "string", "optional": false, "description": "Invocation identifier to cancel.", "typeRef": null}], [], "Cancels a pending tool invocation.");
1510
- inspectorBackend.registerType("WebMCP.Annotation", [{"name": "readOnly", "type": "boolean", "optional": true, "description": "A hint indicating that the tool does not modify any state.", "typeRef": null}, {"name": "untrustedContent", "type": "boolean", "optional": true, "description": "A hint indicating that the tool output may contain untrusted content, ex: UGC, 3rd party data.", "typeRef": null}, {"name": "consequential", "type": "boolean", "optional": true, "description": "A hint indicating that executing the tool will result in consequential actions, ex: booking a flight, transferring money.", "typeRef": null}, {"name": "autosubmit", "type": "boolean", "optional": true, "description": "If the declarative tool was declared with the autosubmit attribute.", "typeRef": null}]);
1508
+ inspectorBackend.registerType("WebMCP.Annotation", [{"name": "readOnly", "type": "boolean", "optional": true, "description": "A hint indicating that the tool does not modify any state.", "typeRef": null}, {"name": "untrustedContent", "type": "boolean", "optional": true, "description": "A hint indicating that the tool output may contain untrusted content, ex: UGC, 3rd party data.", "typeRef": null}, {"name": "consequential", "type": "boolean", "optional": true, "description": "A hint indicating that executing the tool will result in consequential actions, ex: booking a flight, transferring money.", "typeRef": null}, {"name": "debugging", "type": "boolean", "optional": true, "description": "If true, indicates that the tool is intended for debugging and developer tooling rather than end-user interactions.", "typeRef": null}, {"name": "autosubmit", "type": "boolean", "optional": true, "description": "If the declarative tool was declared with the autosubmit attribute.", "typeRef": null}]);
1511
1509
  inspectorBackend.registerType("WebMCP.Tool", [{"name": "name", "type": "string", "optional": false, "description": "Tool name.", "typeRef": null}, {"name": "description", "type": "string", "optional": false, "description": "Tool description.", "typeRef": null}, {"name": "inputSchema", "type": "object", "optional": true, "description": "Schema for the tool's input parameters.", "typeRef": null}, {"name": "annotations", "type": "object", "optional": true, "description": "Optional annotations for the tool.", "typeRef": "WebMCP.Annotation"}, {"name": "frameId", "type": "string", "optional": false, "description": "Frame identifier associated with the tool registration.", "typeRef": "Page.FrameId"}, {"name": "backendNodeId", "type": "number", "optional": true, "description": "Optional node ID for declarative tools.", "typeRef": "DOM.BackendNodeId"}, {"name": "stackTrace", "type": "object", "optional": true, "description": "The stack trace at the time of the registration.", "typeRef": "Runtime.StackTrace"}]);
1512
1510
  inspectorBackend.registerType("WebMCP.RemovedTool", [{"name": "name", "type": "string", "optional": false, "description": "Tool name.", "typeRef": null}, {"name": "frameId", "type": "string", "optional": false, "description": "Frame identifier associated with the tool registration.", "typeRef": "Page.FrameId"}]);
1513
1511
 
@@ -4996,14 +4996,6 @@ export namespace ProtocolMapping {
4996
4996
  paramsType: [];
4997
4997
  returnType: Protocol.Storage.RunBounceTrackingMitigationsResponse;
4998
4998
  };
4999
- /**
5000
- * Returns the effective Related Website Sets in use by this profile for the browser
5001
- * session. The effective Related Website Sets will not change during a browser session.
5002
- */
5003
- 'Storage.getRelatedWebsiteSets': {
5004
- paramsType: [];
5005
- returnType: Protocol.Storage.GetRelatedWebsiteSetsResponse;
5006
- };
5007
4999
  /**
5008
5000
  * Returns information about the system.
5009
5001
  */
@@ -4361,12 +4361,6 @@ declare namespace ProtocolProxyApi {
4361
4361
  */
4362
4362
  invoke_runBounceTrackingMitigations(): Promise<Protocol.Storage.RunBounceTrackingMitigationsResponse>;
4363
4363
 
4364
- /**
4365
- * Returns the effective Related Website Sets in use by this profile for the browser
4366
- * session. The effective Related Website Sets will not change during a browser session.
4367
- */
4368
- invoke_getRelatedWebsiteSets(): Promise<Protocol.Storage.GetRelatedWebsiteSetsResponse>;
4369
-
4370
4364
  }
4371
4365
  export interface StorageDispatcher {
4372
4366
  /**
@@ -875,7 +875,6 @@ export namespace Audits {
875
875
  ExcludeSameSiteLax = 'ExcludeSameSiteLax',
876
876
  ExcludeSameSiteStrict = 'ExcludeSameSiteStrict',
877
877
  ExcludeDomainNonASCII = 'ExcludeDomainNonASCII',
878
- ExcludeThirdPartyCookieBlockedInFirstPartySet = 'ExcludeThirdPartyCookieBlockedInFirstPartySet',
879
878
  ExcludeThirdPartyPhaseout = 'ExcludeThirdPartyPhaseout',
880
879
  ExcludePortMismatch = 'ExcludePortMismatch',
881
880
  ExcludeSchemeMismatch = 'ExcludeSchemeMismatch',
@@ -11318,7 +11317,6 @@ export namespace Network {
11318
11317
  SameSiteNoneInsecure = 'SameSiteNoneInsecure',
11319
11318
  UserPreferences = 'UserPreferences',
11320
11319
  ThirdPartyPhaseout = 'ThirdPartyPhaseout',
11321
- ThirdPartyBlockedInFirstPartySet = 'ThirdPartyBlockedInFirstPartySet',
11322
11320
  SyntaxError = 'SyntaxError',
11323
11321
  SchemeNotSupported = 'SchemeNotSupported',
11324
11322
  OverwriteSecure = 'OverwriteSecure',
@@ -11346,7 +11344,6 @@ export namespace Network {
11346
11344
  SameSiteNoneInsecure = 'SameSiteNoneInsecure',
11347
11345
  UserPreferences = 'UserPreferences',
11348
11346
  ThirdPartyPhaseout = 'ThirdPartyPhaseout',
11349
- ThirdPartyBlockedInFirstPartySet = 'ThirdPartyBlockedInFirstPartySet',
11350
11347
  UnknownError = 'UnknownError',
11351
11348
  SchemefulSameSiteStrict = 'SchemefulSameSiteStrict',
11352
11349
  SchemefulSameSiteLax = 'SchemefulSameSiteLax',
@@ -18532,24 +18529,6 @@ export namespace Storage {
18532
18529
  durability: StorageBucketsDurability;
18533
18530
  }
18534
18531
 
18535
- /**
18536
- * A single Related Website Set object.
18537
- */
18538
- export interface RelatedWebsiteSet {
18539
- /**
18540
- * The primary site of this set, along with the ccTLDs if there is any.
18541
- */
18542
- primarySites: string[];
18543
- /**
18544
- * The associated sites of this set, along with the ccTLDs if there is any.
18545
- */
18546
- associatedSites: string[];
18547
- /**
18548
- * The service sites of this set, along with the ccTLDs if there is any.
18549
- */
18550
- serviceSites: string[];
18551
- }
18552
-
18553
18532
  export interface GetStorageKeyForFrameRequest {
18554
18533
  frameId: Page.FrameId;
18555
18534
  }
@@ -18763,10 +18742,6 @@ export namespace Storage {
18763
18742
  deletedSites: string[];
18764
18743
  }
18765
18744
 
18766
- export interface GetRelatedWebsiteSetsResponse extends ProtocolResponseWithError {
18767
- sets: RelatedWebsiteSet[];
18768
- }
18769
-
18770
18745
  /**
18771
18746
  * A cache's contents have been modified.
18772
18747
  */
@@ -20429,6 +20404,10 @@ export namespace WebMCP {
20429
20404
  * A hint indicating that executing the tool will result in consequential actions, ex: booking a flight, transferring money.
20430
20405
  */
20431
20406
  consequential?: boolean;
20407
+ /**
20408
+ * If true, indicates that the tool is intended for debugging and developer tooling rather than end-user interactions.
20409
+ */
20410
+ debugging?: boolean;
20432
20411
  /**
20433
20412
  * If the declarative tool was declared with the autosubmit attribute.
20434
20413
  */
@@ -141,7 +141,19 @@ export class AiAgent2 extends AiAgent<unknown> {
141
141
  readonly #declaredTools = new Set<string>();
142
142
 
143
143
  constructor(opts: AiAgent2Options) {
144
- super(opts);
144
+ super({
145
+ ...opts,
146
+ allowedOrigin: opts.allowedOrigin ?? (() => {
147
+ const lock = opts.originLock();
148
+ if (lock.status === 'BLOCKED_BY_NAVIGATION') {
149
+ return {blocked: true};
150
+ }
151
+ if (lock.status === 'ESTABLISHED_ORIGIN') {
152
+ return {origin: lock.origin};
153
+ }
154
+ return {origin: undefined};
155
+ }),
156
+ });
145
157
  this.#changes = opts.changeManager ?? new ChangeManager(opts.targetManager);
146
158
  this.#lighthouseRecording = opts.lighthouseRecording;
147
159
  this.#performanceRecordAndReload = opts.performanceRecordAndReload;
@@ -434,7 +434,7 @@ export class AiConversation {
434
434
  } = {},
435
435
  ): AsyncGenerator<ResponseData, void, void> {
436
436
  this.#navigationOccurredDuringRun = false;
437
- const originAtRunStart = getPrimaryPageSecurityOrigin(this.#targetManager);
437
+ const originAtRunStart = this.#origin ?? getPrimaryPageSecurityOrigin(this.#targetManager);
438
438
  const listener = (): void => {
439
439
  // Prevent the agent from executing tools or reading data from an untrusted origin
440
440
  // if the page navigates unexpectedly during execution.
@@ -148,13 +148,12 @@ export class ContextSelectionAgent extends AiAgent<never> {
148
148
  };
149
149
  }
150
150
  const origin = allowedOriginResult.origin;
151
- if (origin?.isOpaque()) {
151
+ if (!origin || origin.isOpaque()) {
152
152
  return {
153
153
  error: 'No requests recorded by DevTools',
154
154
  };
155
155
  }
156
156
 
157
- const allowedSecurityOrigin = origin ?? null;
158
157
  let hasCrossOriginRequest = false;
159
158
  const requestsToShow: NetworkRequest[] = [];
160
159
  for (const request of this.#networkLog.requests()) {
@@ -166,7 +165,7 @@ export class ContextSelectionAgent extends AiAgent<never> {
166
165
  * during the loading of the target page, and do not leak URLs from
167
166
  * other pages.
168
167
  */
169
- if (allowedSecurityOrigin && !request.initiatorSecurityOrigin().isSameOriginWith(allowedSecurityOrigin)) {
168
+ if (!isOriginAllowedByLock({status: 'ESTABLISHED_ORIGIN', origin}, request.initiatorSecurityOrigin())) {
170
169
  hasCrossOriginRequest = true;
171
170
  continue;
172
171
  }
@@ -184,7 +183,7 @@ export class ContextSelectionAgent extends AiAgent<never> {
184
183
  if (requests.length === 0) {
185
184
  return {
186
185
  error: hasCrossOriginRequest ?
187
- `No requests showing with origin ${origin?.siteId() ?? ''}. Tell the user to start a new chat` :
186
+ `No requests showing with origin ${origin.siteId()}. Tell the user to start a new chat` :
188
187
  'No requests recorded by DevTools',
189
188
  };
190
189
  }
@@ -231,18 +230,17 @@ export class ContextSelectionAgent extends AiAgent<never> {
231
230
  };
232
231
  }
233
232
  const origin = allowedOriginResult.origin;
234
- if (origin?.isOpaque()) {
233
+ if (!origin || origin.isOpaque()) {
235
234
  return {
236
235
  error: 'No request found',
237
236
  };
238
237
  }
239
- const allowedSecurityOrigin = origin ?? null;
240
238
  const request = this.#networkLog.requests().find(req => {
241
239
  if (req.requestId() !== id) {
242
240
  return false;
243
241
  }
244
242
 
245
- return !allowedSecurityOrigin || req.initiatorSecurityOrigin().isSameOriginWith(allowedSecurityOrigin);
243
+ return isOriginAllowedByLock({status: 'ESTABLISHED_ORIGIN', origin}, req.initiatorSecurityOrigin());
246
244
  });
247
245
 
248
246
  if (request) {
@@ -288,13 +286,16 @@ export class ContextSelectionAgent extends AiAgent<never> {
288
286
  };
289
287
  }
290
288
  const origin = allowedOriginResult.origin;
289
+ if (!origin || origin.isOpaque()) {
290
+ return {
291
+ result: [],
292
+ };
293
+ }
291
294
 
292
295
  const files: Array<{file: string, id: number | undefined}> = [];
293
296
  const uiSourceCodes: Workspace.UISourceCode.UISourceCode[] = [];
294
297
  for (const file of ContextSelectionAgent.getUISourceCodes(this.#workspace)) {
295
- const fileSecurityOrigin = file.securityOrigin();
296
-
297
- if (origin && !fileSecurityOrigin.isSameOriginWith(origin)) {
298
+ if (!isOriginAllowedByLock({status: 'ESTABLISHED_ORIGIN', origin}, file.securityOrigin())) {
298
299
  continue;
299
300
  }
300
301
 
@@ -347,14 +348,7 @@ export class ContextSelectionAgent extends AiAgent<never> {
347
348
  };
348
349
  }
349
350
  const origin = allowedOriginResult.origin;
350
-
351
- const file = ContextSelectionAgent.getUISourceCodes(this.#workspace).find(file => {
352
- if (ContextSelectionAgent.uiSourceCodeId.get(file) !== params.id) {
353
- return false;
354
- }
355
- const fileSecurityOrigin = file.securityOrigin();
356
- return !origin || fileSecurityOrigin.isSameOriginWith(origin);
357
- });
351
+ const file = ContextSelectionAgent.getSourceById(params.id, origin, this.#workspace);
358
352
 
359
353
  if (!file) {
360
354
  return {
@@ -524,7 +518,7 @@ export class ContextSelectionAgent extends AiAgent<never> {
524
518
  };
525
519
  }
526
520
  const origin = allowedOriginResult.origin;
527
- if (!origin) {
521
+ if (!origin || origin.isOpaque()) {
528
522
  return {
529
523
  error: 'Unable to find page storage.',
530
524
  };
@@ -7,11 +7,19 @@
7
7
  */
8
8
 
9
9
  export function isDebugMode(): boolean {
10
- return Boolean(localStorage.getItem('debugAiAssistancePanelEnabled'));
10
+ try {
11
+ return Boolean(localStorage.getItem('debugAiAssistancePanelEnabled'));
12
+ } catch {
13
+ return false;
14
+ }
11
15
  }
12
16
 
13
17
  export function isStructuredLogEnabled(): boolean {
14
- return Boolean(localStorage.getItem('aiAssistanceStructuredLogEnabled'));
18
+ try {
19
+ return Boolean(localStorage.getItem('aiAssistanceStructuredLogEnabled'));
20
+ } catch {
21
+ return false;
22
+ }
15
23
  }
16
24
 
17
25
  export function debugLog(...log: unknown[]): void {
@@ -5,23 +5,11 @@
5
5
  import * as Root from '../../core/root/root.js';
6
6
  import type * as CommentManager from '../comment_manager/comment_manager.js';
7
7
 
8
- export type ChangeRecord = CommentManager.CommentManager.ChangeRecord;
9
-
10
- export const MAX_RECORDS = 1000;
11
-
12
8
  export class ChangeTracker {
13
- readonly #records = new Map<string, ChangeRecord>();
14
9
  readonly #commentManager: CommentManager.CommentManager.CommentManager;
15
- readonly #maxRecords: number;
16
- #lastRecord?: ChangeRecord;
17
10
 
18
- constructor(commentManager: CommentManager.CommentManager.CommentManager, maxRecords: number = MAX_RECORDS) {
11
+ constructor(commentManager: CommentManager.CommentManager.CommentManager) {
19
12
  this.#commentManager = commentManager;
20
- this.#maxRecords = Math.max(1, maxRecords);
21
- }
22
-
23
- get maxRecords(): number {
24
- return this.#maxRecords;
25
13
  }
26
14
 
27
15
  get isTracking(): boolean {
@@ -31,59 +19,12 @@ export class ChangeTracker {
31
19
  trackChange(
32
20
  description: string,
33
21
  anchor: CommentManager.CommentManager.CommentAnchorSignature,
34
- ): ChangeRecord|null {
22
+ ): void {
35
23
  if (!this.isTracking) {
36
- return null;
37
- }
38
- const record: ChangeRecord = {
39
- id: crypto.randomUUID(),
40
- description,
41
- timestamp: Date.now(),
42
- };
43
- while (this.#records.size >= this.#maxRecords) {
44
- this.#evictOldestRecord();
45
- }
46
-
47
- const thread = this.#commentManager.createCommentThread(anchor, undefined, undefined, [record]);
48
- this.#records.set(thread.id, record);
49
- this.#lastRecord = record;
50
- return record;
51
- }
52
-
53
- #evictOldestRecord(): void {
54
- // Delete the oldest record for which the comment thread has no user comments.
55
- // If all comment threads have user comments, delete the oldest record.
56
- for (const threadId of this.#records.keys()) {
57
- const thread = this.#commentManager.getCommentThread(threadId);
58
- if (!thread || thread.comments.length === 0) {
59
- this.#commentManager.removeCommentThread(threadId);
60
- this.#records.delete(threadId);
61
- return;
62
- }
24
+ return;
63
25
  }
64
26
 
65
- const oldestThreadId = this.#records.keys().next().value;
66
- if (oldestThreadId) {
67
- this.#records.delete(oldestThreadId);
68
- }
69
- }
70
-
71
- getChanges(): ChangeRecord[] {
72
- return Array.from(this.#records.values());
73
- }
74
-
75
- getLastChange(): ChangeRecord|undefined {
76
- return this.#lastRecord;
77
- }
78
-
79
- clear(): void {
80
- for (const threadId of this.#records.keys()) {
81
- const thread = this.#commentManager.getCommentThread(threadId);
82
- if (!thread || thread.comments.length === 0) {
83
- this.#commentManager.removeCommentThread(threadId);
84
- }
85
- }
86
- this.#records.clear();
87
- this.#lastRecord = undefined;
27
+ const thread = this.#commentManager.createCommentThread(anchor, description, 'DEVELOPER', true);
28
+ thread.save();
88
29
  }
89
30
  }
@@ -72,7 +72,7 @@ export class CD4ABridge extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
72
72
  if (!this.#targetManager) {
73
73
  return undefined;
74
74
  }
75
- const target = this.#targetManager.targetById(nodeSignature.targetId) ?? this.#targetManager.primaryPageTarget();
75
+ const target = this.#targetManager.targetById(nodeSignature.targetId);
76
76
  const domModel = target?.model(SDK.DOMModel.DOMModel);
77
77
  if (!domModel) {
78
78
  return undefined;
@@ -156,7 +156,7 @@ export class CD4ABridge extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
156
156
  }
157
157
 
158
158
  if (target?.node && this.#targetManager) {
159
- const sdkTarget = this.#targetManager.targetById(target.node.targetId) ?? this.#targetManager.primaryPageTarget();
159
+ const sdkTarget = this.#targetManager.targetById(target.node.targetId);
160
160
  const domModel = sdkTarget?.model(SDK.DOMModel.DOMModel);
161
161
  if (domModel) {
162
162
  const cdpNodeId = target.node.backendNodeId as Protocol.DOM.BackendNodeId;
@@ -5,7 +5,6 @@
5
5
  import * as Common from '../../core/common/common.js';
6
6
 
7
7
  import {
8
- type ChangeRecord,
9
8
  type Comment,
10
9
  type CommentAnchorSignature,
11
10
  CommentThread,
@@ -18,7 +17,6 @@ import {
18
17
  } from './CommentThread.js';
19
18
 
20
19
  export {
21
- type ChangeRecord,
22
20
  type Comment,
23
21
  type CommentAnchorSignature,
24
22
  CommentThread,
@@ -74,6 +72,9 @@ export class CommentManager extends Common.ObjectWrapper.ObjectWrapper<EventType
74
72
  }
75
73
 
76
74
  setCommentMode(active: boolean): void {
75
+ if (active && !this.#agentAttached) {
76
+ return;
77
+ }
77
78
  if (this.#commentMode === active) {
78
79
  return;
79
80
  }
@@ -89,7 +90,7 @@ export class CommentManager extends Common.ObjectWrapper.ObjectWrapper<EventType
89
90
  anchor: CommentAnchorSignature,
90
91
  text?: string,
91
92
  author: 'DEVELOPER'|'AGENT' = 'DEVELOPER',
92
- changes?: ChangeRecord[],
93
+ isGeneratedComment?: boolean,
93
94
  ): CommentThread {
94
95
  const comments: Comment[] = text ? [{
95
96
  author,
@@ -100,7 +101,7 @@ export class CommentManager extends Common.ObjectWrapper.ObjectWrapper<EventType
100
101
  const thread = new CommentThread({
101
102
  anchor,
102
103
  comments,
103
- changes,
104
+ isGeneratedComment,
104
105
  });
105
106
  thread.addEventListener(CommentThreadEvents.CHANGED, this.#onThreadChanged, this);
106
107
 
@@ -120,7 +121,7 @@ export class CommentManager extends Common.ObjectWrapper.ObjectWrapper<EventType
120
121
  takeComments(): CommentThread[] {
121
122
  const threads: CommentThread[] = [];
122
123
  for (const thread of this.#commentThreads.values()) {
123
- if (thread.status === 'ACTIVE' && !thread.transmitted) {
124
+ if (thread.status === 'SENT_TO_AGENT' && !thread.transmitted) {
124
125
  thread.transmitted = true;
125
126
  threads.push(thread);
126
127
  }
@@ -58,13 +58,7 @@ export interface Comment {
58
58
  timestamp: number;
59
59
  }
60
60
 
61
- export interface ChangeRecord {
62
- id: string;
63
- description: string;
64
- timestamp: number;
65
- }
66
-
67
- export type CommentThreadStatus = 'DRAFT'|'ACTIVE'|'RESOLVED';
61
+ export type CommentThreadStatus = 'DRAFT'|'ACTIVE'|'SENT_TO_AGENT'|'RESOLVED';
68
62
 
69
63
  export const enum Events {
70
64
  CHANGED = 'Changed',
@@ -77,7 +71,8 @@ export interface EventTypes {
77
71
  export interface CommentThreadOptions {
78
72
  anchor: CommentAnchorSignature;
79
73
  comments?: Comment[];
80
- changes?: ChangeRecord[];
74
+ /** True for comments generated from the change tracker. */
75
+ isGeneratedComment?: boolean;
81
76
  }
82
77
 
83
78
  export class CommentThread extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
@@ -89,33 +84,41 @@ export class CommentThread extends Common.ObjectWrapper.ObjectWrapper<EventTypes
89
84
 
90
85
  readonly id: string = crypto.randomUUID();
91
86
  readonly anchor: CommentAnchorSignature;
87
+ /** True for comments generated from the change tracker. */
88
+ readonly isGeneratedComment: boolean;
92
89
  #savedIndex?: number;
93
90
  comments: Comment[];
94
91
  status: CommentThreadStatus = 'DRAFT';
95
92
  transmitted: boolean = false;
96
- changes?: ChangeRecord[];
97
93
 
98
94
  constructor(options: CommentThreadOptions) {
99
95
  super();
100
96
  this.anchor = options.anchor;
101
97
  this.comments = options.comments ?? [];
102
- this.changes = options.changes;
98
+ this.isGeneratedComment = Boolean(options.isGeneratedComment);
103
99
  }
104
100
 
105
101
  get index(): number {
106
102
  return this.#savedIndex ?? CommentThread.#nextIndex;
107
103
  }
108
104
 
109
- save(text?: string, author: 'DEVELOPER'|'AGENT' = 'DEVELOPER'): void {
110
- let changed = false;
105
+ /**
106
+ * Returns whether it was changed.
107
+ */
108
+ #saveText(text?: string, author: 'DEVELOPER'|'AGENT' = 'DEVELOPER'): boolean {
111
109
  if (text && text.trim().length > 0) {
112
110
  this.comments.push({
113
111
  author,
114
112
  text: text.trim(),
115
113
  timestamp: Date.now(),
116
114
  });
117
- changed = true;
115
+ return true;
118
116
  }
117
+ return false;
118
+ }
119
+
120
+ save(text?: string, author: 'DEVELOPER'|'AGENT' = 'DEVELOPER'): void {
121
+ let changed = this.#saveText(text, author);
119
122
  if (this.status === 'DRAFT') {
120
123
  if (this.#savedIndex === undefined) {
121
124
  this.#savedIndex = CommentThread.#nextIndex++;
@@ -128,6 +131,20 @@ export class CommentThread extends Common.ObjectWrapper.ObjectWrapper<EventTypes
128
131
  }
129
132
  }
130
133
 
134
+ sendToAgent(text?: string, author: 'DEVELOPER'|'AGENT' = 'DEVELOPER'): void {
135
+ let changed = this.#saveText(text, author);
136
+ if (this.status === 'DRAFT' || this.status === 'ACTIVE') {
137
+ if (this.#savedIndex === undefined) {
138
+ this.#savedIndex = CommentThread.#nextIndex++;
139
+ }
140
+ this.status = 'SENT_TO_AGENT';
141
+ changed = true;
142
+ }
143
+ if (changed) {
144
+ this.dispatchEventToListeners(Events.CHANGED);
145
+ }
146
+ }
147
+
131
148
  resolve(replyText?: string): void {
132
149
  if (replyText && replyText.trim().length > 0) {
133
150
  this.comments.push({
@@ -134,8 +134,8 @@ export class FormatterWorkerPool {
134
134
  return this.runTask(FormatterActions.FormatterActions.FORMAT, parameters) as Promise<FormatterActions.FormatResult>;
135
135
  }
136
136
 
137
- javaScriptSubstitute(expression: string, mapping: Map<string, string|null>): Promise<string> {
138
- if (mapping.size === 0) {
137
+ javaScriptSubstitute(expression: string, mapping: Array<Map<string, string|null>>): Promise<string> {
138
+ if (mapping.every(m => m.size === 0)) {
139
139
  return Promise.resolve(expression);
140
140
  }
141
141
  return this.runTask(FormatterActions.FormatterActions.JAVASCRIPT_SUBSTITUTE, {content: expression, mapping})
@@ -33,20 +33,19 @@ export class CookieDeprecationMetadataIssue extends Issue<Protocol.Audits.Cookie
33
33
  }
34
34
 
35
35
  getDescription(): MarkdownIssueDescription {
36
- const fileName =
36
+ let fileName =
37
37
  this.details().operation === 'SetCookie' ? 'cookieWarnMetadataGrantSet.md' : 'cookieWarnMetadataGrantRead.md';
38
38
 
39
- let optOutText = '';
39
+ const substitutions = new Map<string, string>();
40
40
  if (this.details().isOptOutTopLevel) {
41
- optOutText = '\n\n (Top level site opt-out: ' + this.details().optOutPercentage +
42
- '% - [learn more](gracePeriodStagedControlExplainer))';
41
+ fileName = this.details().operation === 'SetCookie' ? 'cookieWarnMetadataGrantSetOptOut.md' :
42
+ 'cookieWarnMetadataGrantReadOptOut.md';
43
+ substitutions.set('PLACEHOLDER_optOutPercentage', String(this.details().optOutPercentage));
43
44
  }
44
45
 
45
46
  return {
46
47
  file: fileName,
47
- substitutions: new Map([
48
- ['PLACEHOLDER_topleveloptout', optOutText],
49
- ]),
48
+ substitutions,
50
49
  links: [
51
50
  {
52
51
  link: 'https://goo.gle/changes-to-chrome-browsing',
@@ -71,8 +71,8 @@ export class DeprecationIssue extends Issue<Protocol.Audits.DeprecationIssueDeta
71
71
  }
72
72
  return resolveLazyDescription({
73
73
  file: 'deprecation.md',
74
+ title: i18nLazyString(UIStrings.title),
74
75
  substitutions: new Map([
75
- ['PLACEHOLDER_title', i18nLazyString(UIStrings.title)],
76
76
  ['PLACEHOLDER_message', messageFunction],
77
77
  ]),
78
78
  links,