chrome-devtools-frontend 1.0.1724140 → 1.0.1726686

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 (95) hide show
  1. package/.agents/skills/review-ui-widgets/SKILL.md +7 -7
  2. package/.agents/skills/ui-eng-vision-local-lit-renderer/SKILL.md +12 -0
  3. package/.agents/skills/ui-eng-vision-widget-promoter/SKILL.md +3 -3
  4. package/.agents/skills/ui-widgets/SKILL.md +2 -1
  5. package/docs/cookbook/dependencies.md +6 -4
  6. package/front_end/core/i18n/i18nImpl.ts +1 -1
  7. package/front_end/core/root/Runtime.ts +1 -1
  8. package/front_end/core/sdk/ResourceTreeModel.ts +16 -0
  9. package/front_end/entrypoints/js_app/js_app.ts +2 -5
  10. package/front_end/entrypoints/node_app/node_app.ts +2 -3
  11. package/front_end/generated/InspectorBackendCommands.ts +1 -1
  12. package/front_end/generated/protocol.ts +1 -0
  13. package/front_end/models/ai_assistance/skills/lighthouse.md +2 -1
  14. package/front_end/models/ai_assistance/skills/network.md +1 -0
  15. package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +26 -2
  16. package/front_end/models/ai_assistance/tools/GetLighthouseAudits.ts +1 -1
  17. package/front_end/models/ai_assistance/tools/ListNetworkRequests.ts +2 -7
  18. package/front_end/models/ai_assistance/tools/RunLighthouse.ts +2 -2
  19. package/front_end/models/comment_manager/CommentManager.ts +0 -6
  20. package/front_end/models/comment_manager/CommentThread.ts +23 -19
  21. package/front_end/models/elements/StyleChanges.ts +66 -0
  22. package/front_end/models/trace/EventsSerializer.ts +2 -7
  23. package/front_end/models/trace/ModelImpl.ts +0 -2
  24. package/front_end/models/trace/handlers/FlowsHandler.ts +37 -29
  25. package/front_end/models/trace/helpers/SyntheticEvents.ts +10 -37
  26. package/front_end/models/trace/insights/RenderBlocking.ts +3 -1
  27. package/front_end/models/trace/lantern/simulation/Simulator.ts +4 -0
  28. package/front_end/models/trace/lantern/types/Lantern.ts +1 -0
  29. package/front_end/panels/accessibility/SourceOrderView.ts +1 -1
  30. package/front_end/panels/application/ApplicationPanelSidebar.ts +90 -0
  31. package/front_end/panels/application/StorageView.ts +196 -174
  32. package/front_end/panels/application/SubAppsView.ts +2 -2
  33. package/front_end/panels/application/preloading/PreloadingView.ts +360 -336
  34. package/front_end/panels/application/preloading/components/PreloadingDisabledInfobar.ts +2 -2
  35. package/front_end/panels/application/preloading/components/PreloadingGrid.ts +6 -3
  36. package/front_end/panels/application/preloading/components/RuleSetGrid.ts +17 -17
  37. package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +2 -2
  38. package/front_end/panels/application/preloading/preloadingView.css +12 -4
  39. package/front_end/panels/application/preloading/preloadingViewDropDown.css +1 -1
  40. package/front_end/panels/application/storageView.css +16 -21
  41. package/front_end/panels/browser_debugger/CategorizedBreakpointsSidebarPane.ts +2 -2
  42. package/front_end/panels/browser_debugger/browser_debugger-meta.ts +6 -8
  43. package/front_end/panels/comments/CommentsPane.ts +26 -9
  44. package/front_end/panels/comments/commentsPane.css +25 -6
  45. package/front_end/panels/common/CommentThreadWidget.ts +2 -2
  46. package/front_end/panels/common/CommentsOverlayWidget.ts +94 -35
  47. package/front_end/panels/common/commentThreadWidget.css +17 -0
  48. package/front_end/panels/common/commentsOverlay.css +5 -10
  49. package/front_end/panels/common/common-meta.ts +11 -1
  50. package/front_end/panels/elements/ClassesPaneWidget.ts +130 -88
  51. package/front_end/panels/elements/ColorSwatchPopoverIcon.ts +7 -33
  52. package/front_end/panels/elements/DOMTreeWidget.ts +7 -3
  53. package/front_end/panels/elements/ElementStatePaneWidget.ts +11 -1
  54. package/front_end/panels/elements/PropertyRenderer.ts +3 -2
  55. package/front_end/panels/elements/StyleEditorWidget.ts +60 -41
  56. package/front_end/panels/elements/StylePropertiesSection.ts +32 -5
  57. package/front_end/panels/elements/StylePropertyTreeElement.ts +227 -162
  58. package/front_end/panels/event_listeners/EventListenersView.ts +11 -8
  59. package/front_end/panels/linear_memory_inspector/components/ValueInterpreterSettings.ts +1 -1
  60. package/front_end/panels/network/NetworkDataGridNode.ts +3 -1
  61. package/front_end/panels/network/RequestConditionsDrawer.ts +1 -1
  62. package/front_end/panels/network/RequestPayloadView.ts +12 -5
  63. package/front_end/panels/profiler/HeapProfileView.ts +28 -6
  64. package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +7 -3
  65. package/front_end/panels/protocol_monitor/JSONEditor.ts +0 -1
  66. package/front_end/panels/recorder/RecorderPanel.ts +2 -2
  67. package/front_end/panels/settings/SettingsScreen.ts +1 -1
  68. package/front_end/panels/sources/NavigatorView.ts +105 -45
  69. package/front_end/panels/sources/ScopeChainSidebarPane.ts +8 -5
  70. package/front_end/panels/sources/SourcesNavigator.ts +421 -213
  71. package/front_end/panels/sources/SourcesPanel.ts +6 -4
  72. package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +10 -5
  73. package/front_end/panels/sources/sources-meta.ts +4 -15
  74. package/front_end/panels/sources/sourcesNavigator.css +5 -0
  75. package/front_end/panels/timeline/ModificationsManager.ts +0 -2
  76. package/front_end/panels/timeline/README.md +2 -0
  77. package/front_end/panels/timeline/TimelineCommentController.ts +132 -30
  78. package/front_end/panels/timeline/TimelinePanel.ts +4 -0
  79. package/front_end/panels/timeline/components/IgnoreListSetting.ts +1 -1
  80. package/front_end/panels/timeline/utils/Treemap.ts +8 -0
  81. package/front_end/third_party/chromium/README.chromium +1 -1
  82. package/front_end/ui/comments/CommentAnchorResolver.ts +3 -0
  83. package/front_end/ui/comments/CommentOverlayManager.ts +2 -4
  84. package/front_end/ui/components/lists/List.ts +14 -1
  85. package/front_end/ui/components/panel_feedback/PreviewToggle.ts +1 -1
  86. package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +23 -14
  87. package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +3 -0
  88. package/front_end/ui/legacy/Toolbar.ts +0 -1
  89. package/front_end/ui/legacy/Treeoutline.ts +7 -2
  90. package/front_end/ui/legacy/UIUtils.ts +4 -1
  91. package/front_end/ui/legacy/components/inline_editor/Swatches.ts +19 -6
  92. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +20 -11
  93. package/front_end/ui/legacy/components/source_frame/XMLView.ts +27 -7
  94. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  95. package/package.json +1 -1
@@ -78,10 +78,10 @@ This skill provides review guidance for Chrome DevTools frontend changes matchin
78
78
  - **Look for**: Unscoped generic selectors in light-DOM `.css` files (or `:host` inside `@scope` blocks instead of `:scope`), or CSS rules combining `vertical-align`, negative `margin-top`, and pixel offsets to center icons and buttons.
79
79
  - **Do not flag**: Shadow DOM component stylesheets where `:host` scoping is native.
80
80
 
81
- ### `UI_VIEW_OUTPUT_AND_CALLBACK_CONTRACTS`: Encapsulate imperative DOM actions in ViewOutput callbacks and pass user actions via semantic ViewInput callbacks instead of raw DOM references
81
+ ### `UI_VIEW_OUTPUT_AND_CALLBACK_CONTRACTS`: Encapsulate imperative DOM and child widget actions in ViewOutput callbacks and pass user actions via semantic ViewInput callbacks instead of raw DOM or Widget references
82
82
  - **Severity**: WARNING
83
- - **Why**: Exposing raw `HTMLElement` references on `ViewOutput` or passing raw `MouseEvent`/`KeyboardEvent` objects to presenter callbacks leaks DOM details into presenters. Views should populate narrow functional closures on `ViewOutput` (e.g. `output.focusInput = () => ...`) and unpack event values before calling `input.onSelect(value)`.
84
- - **Look for**: `ViewOutput` interfaces containing `HTMLElement` or `Element` properties, or `ViewInput` callbacks typed as `(event: Event) => void` instead of semantic domain values.
83
+ - **Why**: Exposing raw `HTMLElement` or `UI.Widget` references on `ViewOutput` (e.g. `output.childWidget = w`) or passing raw `MouseEvent`/`KeyboardEvent` objects to presenter callbacks leaks view implementation details into presenters. Supply all configuration through setters/inputs on the child widget, or if imperative calls are strictly necessary, populate narrow functional closures on `ViewOutput` (e.g. `output.focusInput = () => ...`, `output.scrollWidgetToSomething = () => widgetRef.scrollToSomething()`), and unpack event values before calling `input.onSelect(value)`.
84
+ - **Look for**: `ViewOutput` interfaces containing `HTMLElement`, `Element`, or `UI.Widget` subclass properties (other than temporary intermediate CL bridges), `get*ForTest()` presenter methods backed by `ViewOutput` widget references, or `ViewInput` callbacks typed as `(event: Event) => void` instead of semantic domain values.
85
85
  - **Do not flag**: Third-party editor or canvas host containers that require a raw mount `HTMLElement`.
86
86
 
87
87
  ### `UI_PANEL_AND_META_REGISTRATION`: Follow DevTools panel directory conventions and register settings and views in the appropriate *-meta.ts scope
@@ -102,11 +102,11 @@ This skill provides review guidance for Chrome DevTools frontend changes matchin
102
102
  - **Look for**: Raw string interpolation in `querySelector('[attr="' + val + '"]')` without `CSS.escape`, `href` attribute bindings with unvalidated `javascript:` URLs, Markdown table cell serialization without escaping `|*_<>\`, or raw HTML snippet generation without HTML escaping.
103
103
  - **Do not flag**: Standard Lit `html` text bindings (`${text}`), which escape HTML entities automatically.
104
104
 
105
- ### `UI_DECLARATIVE_CHILD_WIDGET_COMPOSITION`: Compose child UI.Widget instances declaratively in Lit templates using the two-argument widget(ChildWidget, {...}) directive instead of imperative show() calls or single-argument factory callbacks
105
+ ### `UI_DECLARATIVE_CHILD_WIDGET_COMPOSITION`: Compose child UI.Widget instances declaratively in Lit templates using ${widget(ChildWidget, {...})} instead of imperative show() calls, single-argument factory callbacks, or bare <devtools-widget> tags
106
106
  - **Severity**: WARNING
107
- - **Why**: Imperatively instantiating child widgets and calling `child.show(container)` inside presenters or views bypasses Lit reconciliation, complicates lifecycle management, and recreates widgets unnecessarily across renders. Similarly, single-argument factory callbacks `widget(element => ...)` only run on initial creation and fail to propagate updated properties on subsequent re-renders; strongly prefer the two-argument `widget(ChildWidget, {...})` form (converting `setFoo()` methods on the child widget into `set foo()` setters if needed).
108
- - **Look for**: `new ChildWidget()` followed by `.show(...)` or `.appendChild(child.element)` inside Lit view functions or migrated `performUpdate()` methods, or `widget(element => ...)` factory callbacks configuring child widget properties imperatively instead of `<devtools-widget ${widget(ChildWidget, {...})}></devtools-widget>` (or `${widget(ChildWidget, {...})}`).
109
- - **Do not flag**: Top-level legacy split widgets or tabbed panes that have not migrated to Lit views.
107
+ - **Why**: Imperatively instantiating child widgets and calling `child.show(container)` inside presenters or views bypasses Lit reconciliation, complicates lifecycle management, and recreates widgets unnecessarily across renders. Similarly, single-argument factory callbacks `widget(element => ...)` only run on initial creation and fail to propagate updated properties on subsequent re-renders; strongly prefer the two-argument `widget(ChildWidget, {...})` form (converting `setFoo()` methods on the child widget into `set foo()` setters if needed). Prefer `${widget(ChildWidget, {...})}` directly as a child expression over `<devtools-widget ${widget(ChildWidget, {...})}></devtools-widget>`; only use an explicit `<devtools-widget>` tag when setting other attributes, applying other directives (such as `widgetRef` or `ref`), or providing child nodes.
108
+ - **Look for**: `new ChildWidget()` followed by `.show(...)` or `.appendChild(child.element)` inside Lit view functions or migrated `performUpdate()` methods, `widget(element => ...)` factory callbacks configuring child widget properties imperatively instead of `${widget(ChildWidget, {...})}`, or `<devtools-widget ${widget(ChildWidget, {...})}></devtools-widget>` tags that have no other attributes, directives, or child nodes.
109
+ - **Do not flag**: Top-level legacy split widgets or tabbed panes that have not migrated to Lit views, or `<devtools-widget>` tags that set other attributes, use additional directives (e.g. `widgetRef`), or contain child nodes.
110
110
 
111
111
  ### `UI_AWAIT_UPDATE_COMPLETE_POST_RENDER`: Await this.updateComplete before executing post-render DOM measurements, focus changes, or scroll adjustments
112
112
  - **Severity**: ERROR
@@ -126,6 +126,12 @@ existing element containers.
126
126
 
127
127
  12. **Composing Child `UI.Widget`s & Pre-Existing Instances**:
128
128
 
129
+ * **Prefer `${widget(ChildWidgetClass, {params})}` Over `<devtools-widget>`**:
130
+ Prefer `${widget(ChildWidgetClass, {params})}` directly as a child
131
+ expression instead of `<devtools-widget ${widget(ChildWidgetClass, {params})}></devtools-widget>`.
132
+ Only use an explicit `<devtools-widget>` tag when you need to set other
133
+ HTML attributes/classes, apply additional directives (such as `widgetRef`
134
+ or `ref`), or provide child nodes.
129
135
  * **Strongly Prefer Two-Argument `widget(ChildWidgetClass, {params})`**:
130
136
  When instantiating child widgets in a Lit template, strongly prefer the
131
137
  two-argument form `widget(ChildWidgetClass, {propA: input.a, propB: input.b})`
@@ -136,6 +142,12 @@ existing element containers.
136
142
  `setFoo()` methods instead of setters, convert them into `set foo()`
137
143
  setters on the child widget so you can use the two-argument `widget()`
138
144
  directive.
145
+ * **No Widget References on `ViewOutput`**: Do not store child widget
146
+ references on `ViewOutput` (e.g., `output.childWidget = w`) as a final
147
+ result (only acceptable temporarily in intermediate CLs). Supply all
148
+ configuration through setters on the child widget, or if imperative
149
+ actions are strictly required, expose individual functions on `ViewOutput`
150
+ (e.g., `output.doLayout = () => w.doLayout()`).
139
151
  * **Pre-Existing Widget Instances (`UI.Widget.WrapperWidget`)**: Use
140
152
  `${widget(UI.Widget.WrapperWidget, {widget: input.childWidget})}` when
141
153
  embedding widgets owned by `UI.ViewManager`
@@ -66,14 +66,14 @@ clean `UI.Widget` classes that use native update rendering delegates.
66
66
  3. **Clean Up Legacy Wrappers**:
67
67
 
68
68
  * Remove any `LegacyWrapper` bindings or custom wrappable custom elements.
69
- * Replace old panel instantiations with standard `<devtools-widget>`
70
- declarative entries (using `const {widget} = UI.Widget;`):
69
+ * Replace old panel instantiations with declarative `widget` entries (using `const {widget} = UI.Widget;`). Prefer `${widget(MyWidgetClass, {params})}` directly as a child expression over `<devtools-widget ${widget(MyWidgetClass, {params})}></devtools-widget>`; only use an explicit `<devtools-widget>` tag when setting other attributes, applying other directives (such as `widgetRef` or `ref`), or providing child nodes:
71
70
 
72
71
  ```typescript
73
- html`<devtools-widget ${widget(MyWidgetClass, {params})}></devtools-widget>`
72
+ html`${widget(MyWidgetClass, {params})}`
74
73
  ```
75
74
 
76
75
  * **Strongly prefer the two-argument `widget(MyWidgetClass, {params})` form** over the single-argument factory callback `widget(element => new MyWidgetClass(element, ...))`. The single-argument factory only runs on initial creation and does not update properties on subsequent re-renders. If the child widget only exposes `setFoo(...)` methods, convert them into `set foo(...)` setters so they can be passed via the second argument of `widget()`.
76
+ * **No Widget References on `ViewOutput`**: Keeping child `UI.Widget` instances on `ViewOutput` (e.g., `output.childWidget = w`) is not a good practice and must not remain in the final result (it is only acceptable temporarily in intermediate CLs). Either supply all configuration through setters on the child widget, or if imperative action calls are strictly needed, expose individual functions on `ViewOutput` (such as `output.doLayout = () => w.doLayout()` or `output.scrollWidgetToSomething = () => w.scrollToSomething()`). Remove legacy `get*ForTest()` methods that were only used to grab child widgets from `ViewOutput` and update tests to query the DOM (`view.contentElement.querySelector(...)?.getWidget()`) or inspect `ViewInput`.
77
77
  * Inspect instantiator files (e.g., `ApplicationPanelSidebar.ts`) and
78
78
  decouple any direct accesses to `.element`.
79
79
 
@@ -59,6 +59,7 @@ const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLElement)
59
59
  ### Composition
60
60
 
61
61
  * To render a child widget, the parent's View MUST use the lit-html directive `UI.Widget.widget`.
62
+ * **Prefer `${widget(WidgetClass, {params})}` directly as a child expression** over `<devtools-widget ${widget(WidgetClass, {params})}></devtools-widget>`. Only use an explicit `<devtools-widget>` tag when you need to set other HTML attributes/classes, apply additional directives (such as `widgetRef` or `ref`), or provide child nodes.
62
63
  * **Strongly prefer the two-argument `widget(WidgetClass, {params})` form** over the single-argument factory callback `widget(element => new WidgetClass(element, ...))`. The two-argument form automatically updates properties and calls `requestUpdate()` on subsequent renders, whereas a factory callback only runs once on initial instantiation.
63
64
  * If a child widget currently exposes imperative setter methods (e.g., `setStorageKey(key)` or `setStorageBucket(bucket)`) instead of public properties/setters, convert them into standard TypeScript setters (`set storageKey(key)`, `set storageBucket(bucket)`) on the child widget so it can be instantiated and updated declaratively via the two-argument `widget(WidgetClass, {params})` directive.
64
65
  * Configuration is passed via the parameters.
@@ -110,7 +111,7 @@ render(html`
110
111
 
111
112
  ### Legacy Interop & Refs
112
113
  * **Raw Elements:** Use `Directives.ref` (from `ui/lit/lit.js`) to obtain a reference to a raw `HTMLElement` if needed for imperative APIs (e.g., `splitWidget.installResizer(element)`).
113
- * **Child Widgets:** Use `UI.Widget.widgetRef` to obtain the class instance of a child widget if you need to call methods on it directly (though declarative data flow is preferred).
114
+ * **Child Widgets:** Use `UI.Widget.widgetRef` to obtain the class instance of a child widget inside the view function if you need to call imperative methods on it. **Do NOT store child widget instances on `ViewOutput` as a final result** (doing so is only acceptable temporarily in intermediate migration CLs). Instead, either supply all needed configuration declaratively through setters/inputs on the child widget, or if imperative calls are strictly necessary, expose narrow action functions on `ViewOutput` (e.g., `output.doLayout = () => splitWidget.doLayout()`, `output.revealPosition = pos => childWidget.revealPosition(pos)`). Do not keep `get*ForTest()` methods that return child widget instances via `ViewOutput`; tests should query rendered `<devtools-widget>` elements via `.getWidget()` or assert on `ViewInput` via `createViewFunctionStub`.
114
115
 
115
116
  ### Dependencies
116
117
 
@@ -111,10 +111,12 @@ that shared dependencies are deduplicated and thus result in a smaller archive.
111
111
  `scripts/deps/npm_exclude.txt` holds rsync filter rules that drop files the
112
112
  build and tests don't need (tests, docs, source maps, non-declaration
113
113
  TypeScript sources, dotfiles, ...) before the archive is built. Keep rules come
114
- first and the first matching rule wins. Stick to generic patterns: anything
115
- package-specific must be measured and verified with a full build and test run,
116
- because the reference check only knows about paths mentioned in GN and Python
117
- files, not about what Node resolves at runtime.
114
+ first and the first matching rule wins. Prefer generic patterns. A
115
+ package-specific rule goes into the "package-specific drops" section with a
116
+ comment saying why the files are unused, and must be measured and verified
117
+ with a full build, test and lint run, because the reference check only knows
118
+ about paths mentioned in GN and Python files, not about what Node resolves at
119
+ runtime. Check such rules again when the package in question is updated.
118
120
 
119
121
  > **WARNING:** Updating tools such as Rollup and TypeScript will cause all build
120
122
  > cache output to be purged, as they are part of all DevTools modules. Whenever
@@ -49,7 +49,7 @@ export function getAllSupportedDevToolsLocales(): string[] {
49
49
  function getLocaleFetchUrl(locale: Intl.UnicodeBCP47LocaleIdentifier, location: string): string {
50
50
  const remoteBase = Root.Runtime.getRemoteBase(location);
51
51
  if (remoteBase?.version && !BUNDLED_LOCALES.has(locale)) {
52
- return REMOTE_FETCH_PATTERN.replace('@HOST@', 'devtools://devtools')
52
+ return REMOTE_FETCH_PATTERN.replace('@HOST@', 'devtools://devtools-remote')
53
53
  .replace('@VERSION@', remoteBase.version)
54
54
  .replace('@LOCALE@', locale);
55
55
  }
@@ -47,7 +47,7 @@ export function getRemoteBase(location: string = globalObject.self?.location?.to
47
47
  return null;
48
48
  }
49
49
 
50
- return {base: `devtools://devtools/remote/serve_file/${version[1]}/`, version: version[1]};
50
+ return {base: `devtools://devtools-remote/remote/serve_file/${version[1]}/`, version: version[1]};
51
51
  }
52
52
 
53
53
  export function getPathName(): string {
@@ -529,6 +529,22 @@ export class ResourceTreeModel extends SDKModel<EventTypes> {
529
529
  return await this.agent.invoke_getAppId();
530
530
  }
531
531
 
532
+ async getSubApps(): Promise<Protocol.Page.SubApp[]> {
533
+ const response = await this.agent.invoke_getSubApps();
534
+ if (response.getError()) {
535
+ return [];
536
+ }
537
+ return response.subApps ?? [];
538
+ }
539
+
540
+ async getSiblingSubApps(): Promise<Protocol.Page.SubApp[]> {
541
+ const response = await this.agent.invoke_getSiblingSubApps();
542
+ if (response.getError()) {
543
+ return [];
544
+ }
545
+ return response.subApps ?? [];
546
+ }
547
+
532
548
  private executionContextComparator(a: ExecutionContext, b: ExecutionContext): number {
533
549
  function framePath(frame: ResourceTreeFrame|null): ResourceTreeFrame[] {
534
550
  let currentFrame: (ResourceTreeFrame|null) = frame;
@@ -85,12 +85,9 @@ UI.ViewManager.registerViewExtension({
85
85
  commandPrompt: i18nLazyString(UIStrings.showNode),
86
86
  order: 2,
87
87
  persistence: UI.ViewManager.ViewPersistence.PERMANENT,
88
- async loadView(universe) {
88
+ async loadView() {
89
89
  const Sources = await loadSourcesModule();
90
- return Sources.SourcesNavigator.NetworkNavigatorView.instance({
91
- forceNew: null,
92
- networkProjectManager: universe.networkProjectManager,
93
- });
90
+ return Sources.SourcesNavigator.NetworkNavigatorView.instance();
94
91
  },
95
92
  });
96
93
 
@@ -81,10 +81,9 @@ UI.ViewManager.registerViewExtension({
81
81
  commandPrompt: i18nLazyString(UIStrings.showNode),
82
82
  order: 2,
83
83
  persistence: UI.ViewManager.ViewPersistence.PERMANENT,
84
- async loadView(universe) {
84
+ async loadView() {
85
85
  const Sources = await loadSourcesModule();
86
- return Sources.SourcesNavigator.NetworkNavigatorView.instance(
87
- {forceNew: null, networkProjectManager: universe.networkProjectManager});
86
+ return Sources.SourcesNavigator.NetworkNavigatorView.instance();
88
87
  },
89
88
  });
90
89
 
@@ -838,7 +838,7 @@ inspectorBackend.registerEnum("Network.ContentSecurityPolicySource", {HTTP: "HTT
838
838
  inspectorBackend.registerEnum("Network.ReportStatus", {Queued: "Queued", Pending: "Pending", MarkedForRemoval: "MarkedForRemoval", Success: "Success"});
839
839
  inspectorBackend.registerEnum("Network.DeviceBoundSessionWithUsageUsage", {NotInScope: "NotInScope", InScopeRefreshNotYetNeeded: "InScopeRefreshNotYetNeeded", InScopeRefreshNotAllowed: "InScopeRefreshNotAllowed", ProactiveRefreshNotPossible: "ProactiveRefreshNotPossible", ProactiveRefreshAttempted: "ProactiveRefreshAttempted", Deferred: "Deferred"});
840
840
  inspectorBackend.registerEnum("Network.DeviceBoundSessionUrlRuleRuleType", {Exclude: "Exclude", Include: "Include"});
841
- inspectorBackend.registerEnum("Network.DeviceBoundSessionFetchResult", {Success: "Success", SigningKeyGenerationError: "SigningKeyGenerationError", AttestationKeyGenerationError: "AttestationKeyGenerationError", SigningError: "SigningError", TransientSigningError: "TransientSigningError", ServerRequestedTermination: "ServerRequestedTermination", InvalidSessionId: "InvalidSessionId", InvalidChallenge: "InvalidChallenge", TooManyChallenges: "TooManyChallenges", InvalidFetcherUrl: "InvalidFetcherUrl", InvalidRefreshUrl: "InvalidRefreshUrl", TransientHttpError: "TransientHttpError", ScopeOriginSameSiteMismatch: "ScopeOriginSameSiteMismatch", RefreshUrlSameSiteMismatch: "RefreshUrlSameSiteMismatch", MismatchedSessionId: "MismatchedSessionId", MissingScope: "MissingScope", NoCredentials: "NoCredentials", SubdomainRegistrationWellKnownUnavailable: "SubdomainRegistrationWellKnownUnavailable", SubdomainRegistrationUnauthorized: "SubdomainRegistrationUnauthorized", SubdomainRegistrationWellKnownMalformed: "SubdomainRegistrationWellKnownMalformed", SessionProviderWellKnownUnavailable: "SessionProviderWellKnownUnavailable", RelyingPartyWellKnownUnavailable: "RelyingPartyWellKnownUnavailable", FederatedKeyThumbprintMismatch: "FederatedKeyThumbprintMismatch", InvalidFederatedSessionUrl: "InvalidFederatedSessionUrl", InvalidFederatedKey: "InvalidFederatedKey", TooManyRelyingOriginLabels: "TooManyRelyingOriginLabels", BoundCookieSetForbidden: "BoundCookieSetForbidden", NetError: "NetError", ProxyError: "ProxyError", EmptySessionConfig: "EmptySessionConfig", InvalidCredentialsConfig: "InvalidCredentialsConfig", InvalidCredentialsType: "InvalidCredentialsType", InvalidCredentialsEmptyName: "InvalidCredentialsEmptyName", InvalidCredentialsCookie: "InvalidCredentialsCookie", PersistentHttpError: "PersistentHttpError", RegistrationAttemptedChallenge: "RegistrationAttemptedChallenge", InvalidScopeOrigin: "InvalidScopeOrigin", ScopeOriginContainsPath: "ScopeOriginContainsPath", RefreshInitiatorNotString: "RefreshInitiatorNotString", RefreshInitiatorInvalidHostPattern: "RefreshInitiatorInvalidHostPattern", InvalidScopeSpecification: "InvalidScopeSpecification", MissingScopeSpecificationType: "MissingScopeSpecificationType", EmptyScopeSpecificationDomain: "EmptyScopeSpecificationDomain", EmptyScopeSpecificationPath: "EmptyScopeSpecificationPath", InvalidScopeSpecificationType: "InvalidScopeSpecificationType", InvalidScopeIncludeSite: "InvalidScopeIncludeSite", MissingScopeIncludeSite: "MissingScopeIncludeSite", FederatedNotAuthorizedByProvider: "FederatedNotAuthorizedByProvider", FederatedNotAuthorizedByRelyingParty: "FederatedNotAuthorizedByRelyingParty", SessionProviderWellKnownMalformed: "SessionProviderWellKnownMalformed", SessionProviderWellKnownHasProviderOrigin: "SessionProviderWellKnownHasProviderOrigin", RelyingPartyWellKnownMalformed: "RelyingPartyWellKnownMalformed", RelyingPartyWellKnownHasRelyingOrigins: "RelyingPartyWellKnownHasRelyingOrigins", InvalidFederatedSessionProviderSessionMissing: "InvalidFederatedSessionProviderSessionMissing", InvalidFederatedSessionWrongProviderOrigin: "InvalidFederatedSessionWrongProviderOrigin", InvalidCredentialsCookieCreationTime: "InvalidCredentialsCookieCreationTime", InvalidCredentialsCookieName: "InvalidCredentialsCookieName", InvalidCredentialsCookieParsing: "InvalidCredentialsCookieParsing", InvalidCredentialsCookieUnpermittedAttribute: "InvalidCredentialsCookieUnpermittedAttribute", InvalidCredentialsCookieInvalidDomain: "InvalidCredentialsCookieInvalidDomain", InvalidCredentialsCookiePrefix: "InvalidCredentialsCookiePrefix", InvalidScopeRulePath: "InvalidScopeRulePath", InvalidScopeRuleHostPattern: "InvalidScopeRuleHostPattern", ScopeRuleOriginScopedHostPatternMismatch: "ScopeRuleOriginScopedHostPatternMismatch", ScopeRuleSiteScopedHostPatternMismatch: "ScopeRuleSiteScopedHostPatternMismatch", SigningQuotaExceeded: "SigningQuotaExceeded", InvalidConfigJson: "InvalidConfigJson", InvalidFederatedSessionProviderFailedToRestoreKey: "InvalidFederatedSessionProviderFailedToRestoreKey", FailedToUnwrapKey: "FailedToUnwrapKey", SessionDeletedDuringRefresh: "SessionDeletedDuringRefresh", CrossOriginRegistrationSiteNotIncluded: "CrossOriginRegistrationSiteNotIncluded", InvalidPreProvisionedKeyInitiatorMissing: "InvalidPreProvisionedKeyInitiatorMissing", PreProvisionedKeyAccessNotGranted: "PreProvisionedKeyAccessNotGranted", PreProvisionedKeyNotFound: "PreProvisionedKeyNotFound", AttestationCertificationError: "AttestationCertificationError", AttestationSigningError: "AttestationSigningError"});
841
+ inspectorBackend.registerEnum("Network.DeviceBoundSessionFetchResult", {Success: "Success", SigningKeyGenerationError: "SigningKeyGenerationError", AttestationKeyGenerationError: "AttestationKeyGenerationError", SigningError: "SigningError", TransientSigningError: "TransientSigningError", ServerRequestedTermination: "ServerRequestedTermination", InvalidSessionId: "InvalidSessionId", InvalidChallenge: "InvalidChallenge", TooManyChallenges: "TooManyChallenges", InvalidFetcherUrl: "InvalidFetcherUrl", InvalidRefreshUrl: "InvalidRefreshUrl", TransientHttpError: "TransientHttpError", ScopeOriginSameSiteMismatch: "ScopeOriginSameSiteMismatch", RefreshUrlSameSiteMismatch: "RefreshUrlSameSiteMismatch", MismatchedSessionId: "MismatchedSessionId", MissingScope: "MissingScope", NoCredentials: "NoCredentials", SubdomainRegistrationWellKnownUnavailable: "SubdomainRegistrationWellKnownUnavailable", SubdomainRegistrationUnauthorized: "SubdomainRegistrationUnauthorized", SubdomainRegistrationWellKnownMalformed: "SubdomainRegistrationWellKnownMalformed", SessionProviderWellKnownUnavailable: "SessionProviderWellKnownUnavailable", RelyingPartyWellKnownUnavailable: "RelyingPartyWellKnownUnavailable", FederatedKeyThumbprintMismatch: "FederatedKeyThumbprintMismatch", InvalidFederatedSessionUrl: "InvalidFederatedSessionUrl", InvalidFederatedKey: "InvalidFederatedKey", TooManyRelyingOriginLabels: "TooManyRelyingOriginLabels", BoundCookieSetForbidden: "BoundCookieSetForbidden", NetError: "NetError", ProxyError: "ProxyError", EmptySessionConfig: "EmptySessionConfig", InvalidCredentialsConfig: "InvalidCredentialsConfig", InvalidCredentialsType: "InvalidCredentialsType", InvalidCredentialsEmptyName: "InvalidCredentialsEmptyName", InvalidCredentialsCookie: "InvalidCredentialsCookie", PersistentHttpError: "PersistentHttpError", RegistrationAttemptedChallenge: "RegistrationAttemptedChallenge", InvalidScopeOrigin: "InvalidScopeOrigin", ScopeOriginContainsPath: "ScopeOriginContainsPath", RefreshInitiatorNotString: "RefreshInitiatorNotString", RefreshInitiatorInvalidHostPattern: "RefreshInitiatorInvalidHostPattern", InvalidScopeSpecification: "InvalidScopeSpecification", MissingScopeSpecificationType: "MissingScopeSpecificationType", EmptyScopeSpecificationDomain: "EmptyScopeSpecificationDomain", EmptyScopeSpecificationPath: "EmptyScopeSpecificationPath", InvalidScopeSpecificationType: "InvalidScopeSpecificationType", InvalidScopeIncludeSite: "InvalidScopeIncludeSite", MissingScopeIncludeSite: "MissingScopeIncludeSite", FederatedNotAuthorizedByProvider: "FederatedNotAuthorizedByProvider", FederatedNotAuthorizedByRelyingParty: "FederatedNotAuthorizedByRelyingParty", SessionProviderWellKnownMalformed: "SessionProviderWellKnownMalformed", SessionProviderWellKnownHasProviderOrigin: "SessionProviderWellKnownHasProviderOrigin", RelyingPartyWellKnownMalformed: "RelyingPartyWellKnownMalformed", RelyingPartyWellKnownHasRelyingOrigins: "RelyingPartyWellKnownHasRelyingOrigins", InvalidFederatedSessionProviderSessionMissing: "InvalidFederatedSessionProviderSessionMissing", InvalidFederatedSessionWrongProviderOrigin: "InvalidFederatedSessionWrongProviderOrigin", InvalidCredentialsCookieCreationTime: "InvalidCredentialsCookieCreationTime", InvalidCredentialsCookieName: "InvalidCredentialsCookieName", InvalidCredentialsCookieParsing: "InvalidCredentialsCookieParsing", InvalidCredentialsCookieUnpermittedAttribute: "InvalidCredentialsCookieUnpermittedAttribute", InvalidCredentialsCookieInvalidDomain: "InvalidCredentialsCookieInvalidDomain", InvalidCredentialsCookiePrefix: "InvalidCredentialsCookiePrefix", InvalidScopeRulePath: "InvalidScopeRulePath", InvalidScopeRuleHostPattern: "InvalidScopeRuleHostPattern", ScopeRuleOriginScopedHostPatternMismatch: "ScopeRuleOriginScopedHostPatternMismatch", ScopeRuleSiteScopedHostPatternMismatch: "ScopeRuleSiteScopedHostPatternMismatch", SigningQuotaExceeded: "SigningQuotaExceeded", InvalidConfigJson: "InvalidConfigJson", InvalidFederatedSessionProviderFailedToRestoreKey: "InvalidFederatedSessionProviderFailedToRestoreKey", FailedToUnwrapKey: "FailedToUnwrapKey", SessionDeletedDuringRefresh: "SessionDeletedDuringRefresh", CrossOriginRegistrationSiteNotIncluded: "CrossOriginRegistrationSiteNotIncluded", InvalidPreProvisionedKeyInitiatorMissing: "InvalidPreProvisionedKeyInitiatorMissing", PreProvisionedKeyAccessNotGranted: "PreProvisionedKeyAccessNotGranted", PreProvisionedKeyNotFound: "PreProvisionedKeyNotFound", AttestationCertificationError: "AttestationCertificationError", AttestationSigningError: "AttestationSigningError", FederatedRegistrationRedirected: "FederatedRegistrationRedirected"});
842
842
  inspectorBackend.registerEnum("Network.RefreshEventDetailsRefreshResult", {Refreshed: "Refreshed", InitializedService: "InitializedService", Unreachable: "Unreachable", ServerError: "ServerError", FatalError: "FatalError", SigningQuotaExceeded: "SigningQuotaExceeded", RefreshedAsWaiter: "RefreshedAsWaiter", TransientSigningError: "TransientSigningError", InScopeRefreshNotYetNeeded: "InScopeRefreshNotYetNeeded", Canceled: "Canceled"});
843
843
  inspectorBackend.registerEnum("Network.TerminationEventDetailsDeletionReason", {Expired: "Expired", FailedToRestoreKey: "FailedToRestoreKey", FailedToUnwrapKey: "FailedToUnwrapKey", StoragePartitionCleared: "StoragePartitionCleared", ClearBrowsingData: "ClearBrowsingData", ServerRequested: "ServerRequested", InvalidSessionParams: "InvalidSessionParams", RefreshFatalError: "RefreshFatalError", DevTools: "DevTools", Replaced: "Replaced"});
844
844
  inspectorBackend.registerEnum("Network.ChallengeEventDetailsChallengeResult", {Success: "Success", NoSessionId: "NoSessionId", NoSessionMatch: "NoSessionMatch", CantSetBoundCookie: "CantSetBoundCookie"});
@@ -12249,6 +12249,7 @@ export namespace Network {
12249
12249
  PreProvisionedKeyNotFound = 'PreProvisionedKeyNotFound',
12250
12250
  AttestationCertificationError = 'AttestationCertificationError',
12251
12251
  AttestationSigningError = 'AttestationSigningError',
12252
+ FederatedRegistrationRedirected = 'FederatedRegistrationRedirected',
12252
12253
  }
12253
12254
 
12254
12255
  /**
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: lighthouse
3
- description: Analyzing an active Lighthouse report context, running Lighthouse reports and audits (performance, accessibility, best practices, Search Engine Optimization (SEO)), accessibility audits, ARIA properties, accessible tree inspection, color contrast, and screen reader semantics. Not for general page performance measurement without a Lighthouse report; use the performance skill for that.
3
+ description: Analyzing an active Lighthouse report context, running Lighthouse reports and audits (performance, accessibility, best practices, Search Engine Optimization (SEO), and agentic browsing when explicitly requested), accessibility audits, ARIA properties, accessible tree inspection, color contrast, and screen reader semantics. Not for general page performance measurement without a Lighthouse report; use the performance skill for that.
4
4
  allowed-tools:
5
5
  - runLighthouse
6
6
  - getLighthouseAudits
@@ -22,6 +22,7 @@ Your role is to evaluate websites using Lighthouse audits across performance, ac
22
22
  - If no active report exists or a fresh audit is requested, call `runLighthouse`:
23
23
  - If the user asks for a general report or multiple categories, use `categoryId: 'all'`.
24
24
  - For a single category, pass that category ID (e.g. `'accessibility'`).
25
+ - Only pass `categoryId: 'agentic-browsing'` when the user explicitly asks for an agentic browsing audit, such as how ready the page is for AI agents to navigate and use it, or WebMCP checks. `'all'` does not include it, so never pick it for general audits, and never substitute another category (such as `'seo'`) when the user asks for it. Use `"navigation"` mode for `'agentic-browsing'` unless the user explicitly asks for another mode, because its WebMCP audits only run in `"navigation"` mode.
25
26
  - Execution mode:
26
27
  - Use `"navigation"` mode for full page-load audits (default for full site reviews).
27
28
  - Use `"snapshot"` mode to re-evaluate live in-page DOM/CSS modifications without reloading.
@@ -20,3 +20,4 @@ You are an expert network request debugging assistant.
20
20
 
21
21
  * **Privacy**: If the request or response payload contains sensitive personal data, authorization tokens, or API secrets, redact or generalize it in your response.
22
22
  * **Origin Lock**: Only requests belonging to the conversation's established origin can be inspected.
23
+ * **Recording**: DevTools only records requests made while DevTools is open and network recording is enabled (and the log has not been cleared). If `listNetworkRequests` reports that no requests have been recorded, ask the user to ensure network recording is enabled, reload the page or repeat the action that triggers the request, and try again.
@@ -31,6 +31,24 @@ const MAX_TOTAL_CHARACTERS = 2500;
31
31
  const MAX_LONG_LINES_REPORTED = 3;
32
32
  const LONG_LINE_PREVIEW_LENGTH = 60;
33
33
 
34
+ /**
35
+ * Matches the error observations for network requests that the isolated
36
+ * world's CSP (`FREESTYLER_WORLD_CSP`) blocks. When code run by this tool calls
37
+ * `fetch()`, Chrome rejects with exactly "Failed to fetch". A synchronous
38
+ * `XMLHttpRequest.send()` throws "Failed to execute 'send' on 'XMLHttpRequest':
39
+ * Failed to load '<url>'.".
40
+ */
41
+ const BLOCKED_NETWORK_ERROR_PATTERN =
42
+ /^Error: (?:Failed to fetch$|Failed to execute 'send' on 'XMLHttpRequest': Failed to load )/;
43
+ const BLOCKED_NETWORK_HINT =
44
+ 'Network access (e.g., fetch, XMLHttpRequest) is blocked for JavaScript run by this tool, so this error does not mean the page\'s own network requests are failing. Do not retry network requests with this tool.';
45
+ /**
46
+ * Only the V2 agent can load the network tools, so V1 agents do not get this
47
+ * part of the hint.
48
+ */
49
+ const NETWORK_TOOLS_HINT =
50
+ 'To inspect the page\'s network requests, load the `network` skill with `learnSkills` if it is not loaded yet, then use `listNetworkRequests` and `getNetworkRequestDetails`.';
51
+
34
52
  /**
35
53
  * Returns one message per size limit that the formatted code exceeds. Each
36
54
  * message states the actual value, the limit, and how to fix it, so the model
@@ -178,7 +196,8 @@ const data = {
178
196
  return {error: 'Error: Cannot execute JavaScript on cross-origin target.'};
179
197
  }
180
198
 
181
- if (Root.Runtime.hostConfig.devToolsAiV2Architecture?.enabled) {
199
+ const isV2Architecture = Root.Runtime.hostConfig.devToolsAiV2Architecture?.enabled;
200
+ if (isV2Architecture) {
182
201
  const validationResult = await ExecuteJavaScriptTool.validateAndFormatCode(params.code);
183
202
  if (validationResult.error) {
184
203
  return {error: validationResult.error};
@@ -199,6 +218,11 @@ const data = {
199
218
  },
200
219
  context.execJs);
201
220
 
202
- return await executor.executeAction(params.code, options);
221
+ const result = await executor.executeAction(params.code, options);
222
+ if ('result' in result && typeof result.result === 'string' && BLOCKED_NETWORK_ERROR_PATTERN.test(result.result)) {
223
+ const hint = isV2Architecture ? `${BLOCKED_NETWORK_HINT} ${NETWORK_TOOLS_HINT}` : BLOCKED_NETWORK_HINT;
224
+ return {...result, result: `${result.result}\n${hint}`};
225
+ }
226
+ return result;
203
227
  }
204
228
  }
@@ -34,7 +34,7 @@ export class GetLighthouseAuditsTool implements
34
34
  categoryId: {
35
35
  type: Host.AidaClient.ParametersTypes.STRING,
36
36
  description:
37
- 'The category of audits to retrieve. Use "all" to retrieve the full report and all categories, or specify a category: "accessibility", "performance", "best-practices", "seo".',
37
+ 'The category of audits to retrieve. Use "all" to retrieve the full report and all categories, or specify a category: "accessibility", "performance", "best-practices", "seo", or "agentic-browsing" (only present when the active report includes an agentic browsing audit).',
38
38
  nullable: false,
39
39
  },
40
40
  },
@@ -114,13 +114,8 @@ export class ListNetworkRequestsTool implements
114
114
  };
115
115
  }
116
116
  return {
117
- result: JSON.stringify([]),
118
- widgets: [{
119
- name: 'NETWORK_REQUESTS_LIST',
120
- data: {
121
- requests: [],
122
- },
123
- }],
117
+ error:
118
+ 'No network requests have been recorded. DevTools only records requests made while DevTools is open and network recording is enabled (and the log has not been cleared). Ask the user to ensure network recording is enabled, reload the page or repeat the action that triggers the request, and try again.',
124
119
  };
125
120
  }
126
121
 
@@ -45,9 +45,9 @@ export class RunLighthouseTool implements
45
45
  },
46
46
  categoryId: {
47
47
  type: Host.AidaClient.ParametersTypes.STRING,
48
- // The experimental 'agentic-browsing' category is intentionally omitted from the prompt description so the agent does not invoke it unprompted. It is also excluded when 'all' is provided.
48
+ // The experimental 'agentic-browsing' category is listed separately from the standard categories and restricted to explicit user requests so the agent does not invoke it unprompted. It is also excluded when 'all' is provided (see `LighthouseController.getCategoryIDs`).
49
49
  description:
50
- 'Lighthouse category. Use "all" to run all categories, or specify a category: "accessibility", "performance", "best-practices", "seo".',
50
+ 'Lighthouse category. Use "all" to run all categories, or specify a category: "accessibility", "performance", "best-practices", "seo". Use "agentic-browsing" only when the user explicitly asks for an agentic browsing audit (how well AI agents can navigate and use the page, including WebMCP). "all" does not include "agentic-browsing". Run "agentic-browsing" in "navigation" mode, because its WebMCP audits only run in "navigation" mode.',
51
51
  nullable: false,
52
52
  },
53
53
  mode: {
@@ -48,11 +48,6 @@ export class CommentManager extends Common.ObjectWrapper.ObjectWrapper<EventType
48
48
  #commentMode = false;
49
49
  #agentAttached = false;
50
50
 
51
- constructor() {
52
- super();
53
- CommentThread.resetIndex();
54
- }
55
-
56
51
  #onThreadChanged(): void {
57
52
  this.dispatchEventToListeners(Events.COMMENT_THREADS_CHANGED, this.getCommentThreads());
58
53
  }
@@ -174,7 +169,6 @@ export class CommentManager extends Common.ObjectWrapper.ObjectWrapper<EventType
174
169
  thread.removeEventListener(CommentThreadEvents.CHANGED, this.#onThreadChanged, this);
175
170
  }
176
171
  this.#commentThreads.clear();
177
- CommentThread.resetIndex();
178
172
  this.dispatchEventToListeners(Events.COMMENT_THREADS_CHANGED, []);
179
173
  }
180
174
  }
@@ -22,7 +22,10 @@ export interface DOMNodeAnchorSignature {
22
22
  export interface TimelineAnchorSignature {
23
23
  /** Identifier of the trace to scope comments to a specific recording */
24
24
  traceId: string;
25
- /** Serializable key from Trace.EventsSerializer (e.g. 'r-123', 'p-1-2-3-4', 's-5') */
25
+ /**
26
+ * Serializable key from Trace.EventsSerializer (e.g. 'r-123', 'p-1-2-3-4', 's-5'), or
27
+ * 'fc-<chartLocation>-<entryIndex>' for flame chart entries that EventsSerializer cannot key.
28
+ */
26
29
  traceEventKey: string;
27
30
  /** Primary event title or category name */
28
31
  entryName: string;
@@ -93,17 +96,11 @@ export interface CommentThreadOptions {
93
96
  }
94
97
 
95
98
  export class CommentThread extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
96
- static #nextIndex = 1;
97
-
98
- static resetIndex(): void {
99
- CommentThread.#nextIndex = 1;
100
- }
101
-
102
99
  readonly id: string = crypto.randomUUID();
103
100
  readonly anchor: CommentAnchorSignature;
104
101
  /** True for comments generated from the change tracker. */
105
102
  readonly isGeneratedComment: boolean;
106
- #savedIndex?: number;
103
+ #isOrphaned = false;
107
104
  comments: Comment[];
108
105
  status: CommentThreadStatus = 'DRAFT';
109
106
  transmitted: boolean = false;
@@ -115,8 +112,16 @@ export class CommentThread extends Common.ObjectWrapper.ObjectWrapper<EventTypes
115
112
  this.isGeneratedComment = Boolean(options.isGeneratedComment);
116
113
  }
117
114
 
118
- get index(): number {
119
- return this.#savedIndex ?? CommentThread.#nextIndex;
115
+ get isOrphaned(): boolean {
116
+ return this.#isOrphaned;
117
+ }
118
+
119
+ setOrphaned(isOrphaned: boolean): void {
120
+ if (this.#isOrphaned === isOrphaned) {
121
+ return;
122
+ }
123
+ this.#isOrphaned = isOrphaned;
124
+ this.dispatchEventToListeners(Events.CHANGED);
120
125
  }
121
126
 
122
127
  /**
@@ -153,9 +158,6 @@ export class CommentThread extends Common.ObjectWrapper.ObjectWrapper<EventTypes
153
158
  let changed = this.#saveText(text, author);
154
159
  if (this.status === 'DRAFT') {
155
160
  this.#recordCommentCreated();
156
- if (this.#savedIndex === undefined) {
157
- this.#savedIndex = CommentThread.#nextIndex++;
158
- }
159
161
  this.status = 'ACTIVE';
160
162
  changed = true;
161
163
  }
@@ -183,9 +185,6 @@ export class CommentThread extends Common.ObjectWrapper.ObjectWrapper<EventTypes
183
185
  this.#recordCommentCreated();
184
186
  }
185
187
  if (this.status === 'DRAFT' || this.status === 'ACTIVE') {
186
- if (this.#savedIndex === undefined) {
187
- this.#savedIndex = CommentThread.#nextIndex++;
188
- }
189
188
  this.status = 'SENT_TO_AGENT';
190
189
  changed = true;
191
190
  }
@@ -202,10 +201,15 @@ export class CommentThread extends Common.ObjectWrapper.ObjectWrapper<EventTypes
202
201
  timestamp: Date.now(),
203
202
  });
204
203
  }
205
- if (this.#savedIndex === undefined) {
206
- this.#savedIndex = CommentThread.#nextIndex++;
207
- }
208
204
  this.status = 'RESOLVED';
209
205
  this.dispatchEventToListeners(Events.CHANGED);
210
206
  }
211
207
  }
208
+
209
+ export class RevealableThread {
210
+ constructor(
211
+ readonly thread: CommentThread,
212
+ readonly position?: {left: number, top: number},
213
+ ) {
214
+ }
215
+ }
@@ -95,3 +95,69 @@ export function trackStylePropertyToggle(
95
95
  }
96
96
  tracker.trackChange(describeStylePropertyToggle(toggle), buildAnchor(STYLES_PANE_VE_PATH, node));
97
97
  }
98
+
99
+ export function trackStyleRuleAdded(
100
+ tracker: ChangeTracker.ChangeTracker.ChangeTracker|undefined,
101
+ node: SDK.DOMModel.DOMNode,
102
+ selector: string,
103
+ ): void {
104
+ if (!tracker?.isTracking) {
105
+ return;
106
+ }
107
+ const trimmedSelector = Platform.StringUtilities.collapseWhitespace(selector.trim());
108
+ if (!trimmedSelector) {
109
+ return;
110
+ }
111
+ tracker.trackChange(
112
+ `Added style rule "${trimValue(trimmedSelector)}"`,
113
+ buildAnchor(STYLES_PANE_VE_PATH, node),
114
+ );
115
+ }
116
+
117
+ function trackRuleHeaderChange(
118
+ tracker: ChangeTracker.ChangeTracker.ChangeTracker|undefined,
119
+ node: SDK.DOMModel.DOMNode,
120
+ headerDescription: string,
121
+ oldText: string,
122
+ newText: string,
123
+ ): void {
124
+ if (!tracker?.isTracking) {
125
+ return;
126
+ }
127
+ const trimmedOld = Platform.StringUtilities.collapseWhitespace(oldText.trim());
128
+ const trimmedNew = Platform.StringUtilities.collapseWhitespace(newText.trim());
129
+ if (!trimmedOld || !trimmedNew || trimmedOld === trimmedNew) {
130
+ return;
131
+ }
132
+ tracker.trackChange(
133
+ `Changed ${headerDescription} from "${trimValue(trimmedOld)}" to "${trimValue(trimmedNew)}"`,
134
+ buildAnchor(STYLES_PANE_VE_PATH, node),
135
+ );
136
+ }
137
+
138
+ export function trackStyleSelectorChange(
139
+ tracker: ChangeTracker.ChangeTracker.ChangeTracker|undefined,
140
+ node: SDK.DOMModel.DOMNode,
141
+ oldSelector: string,
142
+ newSelector: string,
143
+ ): void {
144
+ trackRuleHeaderChange(tracker, node, 'style rule selector', oldSelector, newSelector);
145
+ }
146
+
147
+ export function trackPropertyRuleNameChange(
148
+ tracker: ChangeTracker.ChangeTracker.ChangeTracker|undefined,
149
+ node: SDK.DOMModel.DOMNode,
150
+ oldName: string,
151
+ newName: string,
152
+ ): void {
153
+ trackRuleHeaderChange(tracker, node, '@property rule name', oldName, newName);
154
+ }
155
+
156
+ export function trackKeyframeKeyChange(
157
+ tracker: ChangeTracker.ChangeTracker.ChangeTracker|undefined,
158
+ node: SDK.DOMModel.DOMNode,
159
+ oldKey: string,
160
+ newKey: string,
161
+ ): void {
162
+ trackRuleHeaderChange(tracker, node, 'keyframe key', oldKey, newKey);
163
+ }
@@ -84,13 +84,8 @@ export class EventsSerializer {
84
84
  }
85
85
 
86
86
  if (EventsSerializer.isSyntheticEventKey(eventValues)) {
87
- const syntheticEvents = Helpers.SyntheticEvents.SyntheticEventsManager.getActiveManager().getSyntheticTraces();
88
- const syntheticEvent = syntheticEvents.at(eventValues.rawIndex);
89
- if (!syntheticEvent) {
90
- throw new Error(`Unknown trace event. Attempted to get a synthetic event from an unknown raw event index: ${
91
- eventValues.rawIndex}`);
92
- }
93
- return syntheticEvent;
87
+ return Helpers.SyntheticEvents.SyntheticEventsManager.getActiveManager().syntheticEventForRawEventIndex(
88
+ eventValues.rawIndex);
94
89
  }
95
90
 
96
91
  if (EventsSerializer.isRawEventKey(eventValues)) {
@@ -110,8 +110,6 @@ export class Model extends EventTarget {
110
110
  }
111
111
  const file = this.#storeAndCreateParsedTraceFile(
112
112
  syntheticEventsManager, traceEvents, metadata, this.#processor.data, this.#processor.insights);
113
- // Reclaim memory used by the temporary event-to-index lookup map now that trace parsing is complete.
114
- syntheticEventsManager.clearRegistrationIndex();
115
113
  // We only push the file onto this.#traces here once we know it's valid
116
114
  // and there's been no errors in the parsing.
117
115
  this.#traces.push(file);