chrome-devtools-frontend 1.0.1717196 → 1.0.1717709

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/.agents/skills/devtools-testing-guidance/SKILL.md +4 -2
  2. package/.agents/skills/ui-eng-vision-local-lit-renderer/SKILL.md +57 -9
  3. package/.agents/skills/ui-eng-vision-logic-consolidator/SKILL.md +27 -3
  4. package/.agents/skills/ui-eng-vision-orchestrator/SKILL.md +32 -2
  5. package/.agents/skills/ui-eng-vision-test-scaffolder/SKILL.md +37 -7
  6. package/.agents/skills/ui-eng-vision-widget-promoter/SKILL.md +4 -4
  7. package/.agents/skills/ui-widgets/SKILL.md +8 -8
  8. package/docs/ui_engineering.md +34 -0
  9. package/front_end/core/common/Settings.ts +5 -0
  10. package/front_end/core/host/UserMetricsEnums.ts +1 -0
  11. package/front_end/core/sdk/CSSModel.ts +21 -0
  12. package/front_end/core/sdk/CSSPropertyParser.ts +11 -2
  13. package/front_end/core/sdk/DOMModel.ts +1 -1
  14. package/front_end/core/sdk/DebuggerModel.ts +3 -0
  15. package/front_end/core/sdk/EmulationModel.ts +40 -39
  16. package/front_end/core/sdk/NetworkManager.ts +1 -0
  17. package/front_end/core/sdk/NetworkRequest.ts +21 -0
  18. package/front_end/core/sdk/RuntimeModel.ts +8 -3
  19. package/front_end/devtools_compatibility.js +1 -0
  20. package/front_end/generated/Deprecation.ts +0 -7
  21. package/front_end/generated/InspectorBackendCommands.ts +1 -1
  22. package/front_end/generated/protocol.ts +1 -0
  23. package/front_end/models/ai_assistance/AiAgent2.ts +11 -5
  24. package/front_end/models/ai_assistance/AiConversation.ts +3 -2
  25. package/front_end/models/ai_assistance/AiUtils.ts +5 -2
  26. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +9 -4
  27. package/front_end/models/ai_assistance/agents/AiAgent.ts +247 -121
  28. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +9 -5
  29. package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +2 -9
  30. package/front_end/models/ai_assistance/tools/RunLighthouse.ts +6 -3
  31. package/front_end/models/ai_assistance/tools/Tool.ts +5 -1
  32. package/front_end/models/bindings/CompilerScriptMapping.ts +40 -8
  33. package/front_end/models/bindings/ResourceScriptMapping.ts +1 -1
  34. package/front_end/models/comment_manager/CommentThread.ts +13 -0
  35. package/front_end/models/computed_style/ComputedStyleModel.ts +1 -0
  36. package/front_end/models/issues_manager/GenericIssue.ts +18 -0
  37. package/front_end/models/issues_manager/descriptions/genericGeolocationPromptWithoutUserGesture.md +5 -0
  38. package/front_end/models/javascript_metadata/NativeFunctions.ts +0 -4
  39. package/front_end/models/lighthouse/RunTypes.ts +16 -0
  40. package/front_end/models/stack_trace/StackTraceModel.ts +24 -3
  41. package/front_end/models/trace/extras/TraceTree.ts +2 -7
  42. package/front_end/models/trace/helpers/Timing.ts +11 -22
  43. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +23 -2
  44. package/front_end/panels/ai_assistance/README.md +3 -1
  45. package/front_end/panels/application/AppManifestView.ts +1 -4
  46. package/front_end/panels/comments/CommentsPane.ts +7 -3
  47. package/front_end/panels/comments/comments-meta.ts +1 -1
  48. package/front_end/panels/common/CommentThreadWidget.ts +67 -25
  49. package/front_end/panels/common/CommentsOverlayWidget.ts +13 -0
  50. package/front_end/panels/elements/PropertyRenderer.ts +103 -10
  51. package/front_end/panels/elements/StylePropertyTreeElement.ts +107 -18
  52. package/front_end/panels/elements/stylePropertiesTreeOutline.css +6 -1
  53. package/front_end/panels/emulation/deviceModeView.css +3 -3
  54. package/front_end/panels/lighthouse/LighthouseController.ts +28 -21
  55. package/front_end/panels/lighthouse/LighthousePanel.ts +5 -6
  56. package/front_end/panels/lighthouse/LighthouseProtocolService.ts +24 -16
  57. package/front_end/panels/screencast/ScreencastApp.ts +2 -2
  58. package/front_end/panels/screencast/ScreencastView.ts +76 -45
  59. package/front_end/panels/sources/BreakpointEditDialog.ts +3 -6
  60. package/front_end/panels/timeline/CountersGraph.ts +1 -1
  61. package/front_end/panels/timeline/TimelineFlameChartView.ts +2 -9
  62. package/front_end/panels/timeline/utils/EntryNodes.ts +1 -1
  63. package/front_end/third_party/chromium/README.chromium +1 -1
  64. package/front_end/third_party/puppeteer/README.chromium +2 -2
  65. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +42 -12
  66. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +154 -26
  67. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/HTTPRequest.d.ts +47 -7
  68. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/HTTPRequest.d.ts.map +1 -1
  69. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/HTTPRequest.js +56 -4
  70. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/HTTPRequest.js.map +1 -1
  71. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.d.ts +6 -4
  72. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.d.ts.map +1 -1
  73. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.js +5 -2
  74. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.js.map +1 -1
  75. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/HTTPRequest.d.ts +3 -3
  76. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/HTTPRequest.d.ts.map +1 -1
  77. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/HTTPRequest.js.map +1 -1
  78. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Page.d.ts +2 -1
  79. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Page.d.ts.map +1 -1
  80. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Page.js +23 -11
  81. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Page.js.map +1 -1
  82. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/HTTPRequest.d.ts +3 -3
  83. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/HTTPRequest.d.ts.map +1 -1
  84. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/HTTPRequest.js +1 -2
  85. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/HTTPRequest.js.map +1 -1
  86. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/NetworkManager.d.ts +13 -7
  87. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/NetworkManager.d.ts.map +1 -1
  88. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/NetworkManager.js +26 -11
  89. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/NetworkManager.js.map +1 -1
  90. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Page.d.ts +2 -1
  91. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Page.d.ts.map +1 -1
  92. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Page.js.map +1 -1
  93. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/TargetManager.d.ts.map +1 -1
  94. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/TargetManager.js +69 -13
  95. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/TargetManager.js.map +1 -1
  96. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/ConnectOptions.d.ts +10 -0
  97. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/ConnectOptions.d.ts.map +1 -1
  98. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.d.ts +3 -3
  99. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js +3 -3
  100. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js.map +1 -1
  101. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.d.ts +1 -1
  102. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.js +1 -1
  103. package/front_end/third_party/puppeteer/package/lib/types.d.ts +42 -12
  104. package/front_end/third_party/puppeteer/package/package.json +4 -4
  105. package/front_end/third_party/puppeteer/package/src/api/HTTPRequest.ts +103 -11
  106. package/front_end/third_party/puppeteer/package/src/api/Page.ts +11 -6
  107. package/front_end/third_party/puppeteer/package/src/bidi/HTTPRequest.ts +4 -4
  108. package/front_end/third_party/puppeteer/package/src/bidi/Page.ts +26 -14
  109. package/front_end/third_party/puppeteer/package/src/cdp/HTTPRequest.ts +7 -7
  110. package/front_end/third_party/puppeteer/package/src/cdp/NetworkManager.ts +40 -18
  111. package/front_end/third_party/puppeteer/package/src/cdp/Page.ts +2 -3
  112. package/front_end/third_party/puppeteer/package/src/cdp/TargetManager.ts +87 -14
  113. package/front_end/third_party/puppeteer/package/src/common/ConnectOptions.ts +10 -0
  114. package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
  115. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  116. package/front_end/ui/legacy/SplitWidget.ts +9 -8
  117. package/front_end/ui/visual_logging/KnownContextValues.ts +42 -0
  118. package/package.json +1 -1
  119. package/.agents/skills/devtools-ux-writing-refactor/SKILL.md +0 -142
@@ -37,7 +37,8 @@ Use API tests for integration tests that verify business logic requiring more co
37
37
  - Tests that require extensive CDP mock setup.
38
38
  - Verifying the "foundational layer" of DevTools models against a real browser/web page.
39
39
  - **Location:** Defined in `front_end/` with `.test.api.ts` extension (e.g. `Universe.test.api.ts`).
40
- - **BUILD.gn**: test file should be added to `devtools_api_test_module("api_tests")` target in the corresponding `BUILD.gn` file.
40
+ - **Test functions:** import `describe`, `it` and `setup` from `test/api/mocha-interface.ts`. They are not available as globals.
41
+ - **BUILD.gn**: test file should be added to `devtools_api_test_module("api_tests")` target in the corresponding `BUILD.gn` file, which needs `test/api` in its `ts_deps`.
41
42
 
42
43
  ---
43
44
 
@@ -49,4 +50,5 @@ Use E2E tests to verify real end-to-end user stories and user journeys.
49
50
  - Verifying full user journeys across DevTools panels and drawers.
50
51
  - Complex UI behaviors that require extensive user interaction setup and benefit from a complete DevTools frontend page connected to an inspected target page over CDP.
51
52
  - **Location:** Defined in `test/e2e/` (e.g. `test/e2e/console/console-log.test.ts`).
52
- - **BUILD.gn**: test file should be added to `ts_e2e_library(ts_e2e_library)` target in the corresponding `BUILD.gn` file. And `node_ts_library` in `test/e2e/BUILD.gn` for its dependencies.
53
+ - **Test functions:** import `describe`, `it` and `setup` from `test/e2e/conductor/mocha-interface.ts` (e.g. `import {describe, it} from '../conductor/mocha-interface.js';`). They are not available as globals.
54
+ - **BUILD.gn**: test file should be added to the `node_ts_library` target in the corresponding `BUILD.gn` file, which needs `"../conductor:implementation"` in its `ts_deps`. And `node_ts_library` in `test/e2e/BUILD.gn` for its dependencies.
@@ -34,14 +34,18 @@ existing element containers.
34
34
  that method. **Do not** introduce Widget lifecycle methods
35
35
  (`performUpdate`) on classes that do not inherit them.
36
36
 
37
- 3. **Import Modern Templating**:
37
+ 3. **Import Modern Templating (Named Imports Only)**:
38
38
 
39
- * Import the `Lit` rendering system inside the view module:
39
+ * Always use named imports from `../../ui/lit/lit.js`:
40
40
 
41
41
  ```typescript
42
- import {html, render, nothing} from '../../ui/lit/lit.js';
42
+ import {html, nothing, render, Directives, type LitTemplate} from '../../ui/lit/lit.js';
43
43
  ```
44
44
 
45
+ * **NEVER** use namespace imports like `import * as Lit` or reference
46
+ `Lit.nothing` / `Lit.render`. Named imports enable better tree-shaking and
47
+ maintain consistent codebase style.
48
+
45
49
  4. **Modern Component Mapping**:
46
50
  * **MANDATORY**: You **MUST** read and load [ui_engineering.md](../../../docs/ui_engineering.md) first to understand specific component mappings (e.g., Toolbar vs `devtools-toolbar`). Do not assume standard Lit defaults.
47
51
  * If unsure, also consult the [automatic migration code](../../../scripts/eslint_rules/lib/no-imperative-dom-api.ts)
@@ -115,13 +119,53 @@ existing element containers.
115
119
  * The Gerrit Code Review UI cannot identify moved blocks of unchanged code.
116
120
  * If blocks of code need to be reordered, create a "prefactoring" change that first extracts the code that needs to be reordered into a named helper functions and pause the migration, waiting user confirmation.
117
121
 
118
- 12. **Micro-Commit Strategy**:
122
+ 12. **Embedding Pre-Existing `UI.Widget` Instances via `UI.Widget.WrapperWidget`**:
123
+
124
+ * Use `${widget(UI.Widget.WrapperWidget, {widget: input.childWidget})}` when
125
+ embedding widgets owned by `UI.ViewManager`
126
+ (`TabbedViewLocation.tabbedPane()`, `StackLocation.widget()`) or when
127
+ conditionally moving a shared widget instance between containers
128
+ (`{widget: shouldShow ? this.#sharedWidget : null}`).
129
+ * `WrapperWidget` automatically handles showing and detaching the inner
130
+ widget and forwards calculateConstraints without requiring custom wrapper
131
+ classes.
132
+
133
+ 13. **Declarative `<devtools-split-view>` Guidelines**:
134
+
135
+ * **CSS Sizing**: Ensure `<devtools-split-view>` has `flex: auto; height: 100%;`
136
+ in CSS so it fills available container space and doesn't collapse to 0x0.
137
+ * **Reuse Existing Settings for `showMode`**: When binding `show=${...}`
138
+ declaratively on `<devtools-split-view name="...">`, reuse the existing
139
+ `SplitWidget` setting (`{vertical?: {size, showMode}, horizontal?: {size, showMode}}`)
140
+ for `showMode` rather than creating new boolean settings (which loses user
141
+ preferences and requires `KnownContextValues.ts` updates).
142
+ * **Keep Environment Overrides in Templates**: Keep environment overrides
143
+ (like `!input.isTraceApp`) in the `DEFAULT_VIEW` template (e.g.,
144
+ `show=${!input.isTraceApp && input.isSidebarOpen ? 'both' : 'main'}`)
145
+ rather than baking them into the presenter's setting state.
146
+ * **Clean Up Resizers**: Do not leave unused `resizer-widget` classes in
147
+ templates; `<devtools-split-view>` manages its own built-in splitter
148
+ unless custom elements are explicitly registered with `installResizer`.
149
+
150
+ 14. **Declarative Long-Press Action Buttons (`bindToAction`)**:
151
+
152
+ * Legacy `UI.Toolbar.Toolbar.createLongPressActionButton(action, [subButtons])`
153
+ maps declaratively to nesting option `<devtools-button>` elements directly
154
+ inside `<devtools-button ${bindToAction('action-id')}>...</devtools-button>`.
155
+
156
+ 15. **Audit Removed `UIStrings`**:
157
+
158
+ * If a `UIStrings` entry becomes unused during template migration, verify
159
+ that a conditional UI branch (such as a dynamically shown checkbox, button,
160
+ or tooltip) wasn't accidentally dropped before deleting the string.
161
+
162
+ 16. **Micro-Commit Strategy**:
119
163
 
120
164
  * Do not attempt to convert every helper method and UI component in a single monolithic commit. Break the template extraction into **small, self-contained micro-commits** (e.g., migrating one helper method, toolbar button, or list item render at a time).
121
165
  * Verify with build and run tests after each micro-commit to guarantee zero regressions and 100% visual parity before moving to the next compartment.
122
166
  * Provide the exact list of files and commit message when presenting progress so the change history remains atomic and easy to review.
123
167
 
124
- 13. **Wait for confirmation**:
168
+ 17. **Wait for confirmation**:
125
169
 
126
170
  * Wait for an explicit confirmation from the user (or Parent Orchestrator Agent) before proceeding to the next step.
127
171
 
@@ -130,8 +174,12 @@ existing element containers.
130
174
  ## 🔍 Mental Audit (Internal Self-Correction)
131
175
 
132
176
  *Before reporting back or committing, re-read the instructions and verify:*
133
- 1. ❓ **Tag Parity**: Did I accidentally change any `span` to `div` (or vice versa)?
134
- 2. ❓ **Attribute Drop**: Did I drop any `aria-*`, `role`, or custom data attributes?
135
- 3. ❓ **Clang-Off Boundary**: Is the template wrapped in `// clang-format off`?
136
- 4. ❓ **Build**: Does the code compile and do visual tests pass with 0% diff?
177
+ 1. ❓ **Named Imports**: Did I use named imports `{html, nothing, render}` from `ui/lit/lit.js` (and no `import * as Lit`)?
178
+ 2. ❓ **Tag Parity**: Did I accidentally change any `span` to `div` (or vice versa)?
179
+ 3. ❓ **Attribute Drop**: Did I drop any `aria-*`, `role`, or custom data attributes?
180
+ 4. ❓ **Clang-Off Boundary**: Is the template wrapped in `// clang-format off`?
181
+ 5. ❓ **Split Views**: Does `<devtools-split-view>` have `flex: auto; height: 100%;` CSS and reuse existing split settings?
182
+ 6. ❓ **String Audit**: Did I verify that any removed `UIStrings` weren't from accidentally dropped UI branches?
183
+ 7. ❓ **Build**: Does the code compile and do visual tests pass with 0% diff?
184
+
137
185
 
@@ -76,7 +76,29 @@ consolidating them into private helper methods with explicit data contracts.
76
76
  that first extracts the code that needs to be reordered into named
77
77
  helper functions and pause the migration, waiting for user confirmation.
78
78
 
79
- 6. **Wait for confirmation**:
79
+ 6. **No Write-Only State Fields in Prefactor CLs**:
80
+
81
+ * Do not introduce `#state` fields in a logic-consolidation CL that are only
82
+ written to in that CL and only read in the *next* CL's `DEFAULT_VIEW`.
83
+ * Either read them in the prefactor CL (e.g., inside an extracted imperative
84
+ `#render...` helper) or introduce them in the CL that actually adds
85
+ `DEFAULT_VIEW`.
86
+
87
+ 7. **Extract Imperative `#renderSubtreeContent()` Helpers**:
88
+
89
+ * For complex layouts, extracting an imperative `#renderFooContent()`
90
+ helper in Pass 1 (while keeping the outer container imperative) minimizes
91
+ the Pass 2/3 diff when converting `#renderFooContent()` to
92
+ `renderFooContent(input: ViewInput): LitTemplate`.
93
+
94
+ 8. **Preserve Imperative Cleanup Calls**:
95
+
96
+ * When consolidating DOM/widget references (e.g., replacing
97
+ `#tabbedLocationHeader` with `#debuggerSidebarTabbedLocation`), preserve
98
+ imperative cleanup calls like `splitWidget.uninstallResizer(...)` until the
99
+ imperative container itself is removed.
100
+
101
+ 9. **Wait for confirmation**:
80
102
 
81
103
  * Wait for an explicit confirmation from the user (or Parent Orchestrator Agent) before proceeding to the next step.
82
104
 
@@ -86,6 +108,8 @@ consolidating them into private helper methods with explicit data contracts.
86
108
 
87
109
  *Before reporting back or committing, re-read the instructions and verify:*
88
110
  1. ❓ **Minimal Diffs**: Did I move code blocks around unnecessarily?
89
- 2. ❓ **State Completeness**: Are all imperative DOM updates now backed by state variables?
90
- 3. ❓ **Build**: Does the code still compile?
111
+ 2. ❓ **State Completeness & Utility**: Are all state variables actually read in this CL, with no write-only placeholders?
112
+ 3. ❓ **Cleanup Preserved**: Are resizer/listener uninstallation calls preserved during reference consolidation?
113
+ 4. ❓ **Build**: Does the code still compile?
114
+
91
115
 
@@ -76,6 +76,26 @@ principles.
76
76
  clean and focused on high-level orchestration, prefer delegating intense
77
77
  execution tasks (like running tests, debugging compilations, or processing
78
78
  independent classes in parallel) to specialized subagents.
79
+ 13. **Cross-Repo Runtime Coupling Check (`legacy_test_runner` & `blink/web_tests`)**:
80
+ Before converting TypeScript `private` fields/methods to ES `#private` or
81
+ removing widget properties (e.g., `.tabbedPane`, `.sidebarPaneStack`,
82
+ `.threadsSidebarPane`, `.searchInputElement`), search both
83
+ `front_end/legacy_test_runner/**/*.js` and Chromium's
84
+ `third_party/blink/web_tests/http/tests/devtools/**/*.js` (which run on
85
+ `dtf_linux_rel` CQ via `blink_web_tests` and reflectively access private
86
+ members in untyped JS). Keep accessed members as TypeScript `private` with a
87
+ `// Accessed in web_tests / legacy_test_runner` comment, or migrate the
88
+ web_tests first in a dedicated CL.
89
+ 14. **Strict CL Splitting Rules**:
90
+ * **One Class Per CL for Hybrid Files**: When modernizing files containing
91
+ multiple classes, extract or migrate secondary classes (e.g.,
92
+ `QuickSourceView`) into their own dedicated CLs.
93
+ * **Separate Infrastructure CLs**: Keep shared `ui/legacy` or component
94
+ infrastructure changes (e.g., `bindToAction`, `SplitWidget`,
95
+ `WrapperWidget`) in separate, preceding CLs. Always verify with
96
+ `cog_api.py diff` before uploading that no changes from later commits
97
+ leaked into earlier infrastructure CLs.
98
+
79
99
 
80
100
 
81
101
  --------------------------------------------------------------------------------
@@ -129,6 +149,8 @@ The plan you generate **MUST** follow this structure:
129
149
  ## 🛠️ Passes Checklist
130
150
  - [ ] **Pass 0: Baseline & Safety Scaffolding**
131
151
  - Assigned to: `ui-eng-vision-test-scaffolder`
152
+ - [ ] **Pass 0.5: Privatize & Dead-Code Cleanup**
153
+ - Mechanical prefactor: convert TypeScript `private` to ES `#private` and remove dead code
132
154
  - [ ] **Pass 1: Logic Consolidation**
133
155
  - Assigned to: `ui-eng-vision-logic-consolidator`
134
156
  - [ ] **Pass 2: Lit-HTML Rendering**
@@ -149,10 +171,18 @@ The plan you generate **MUST** follow this structure:
149
171
  regressions.
150
172
  2. Pay extra attention not to skip this step.
151
173
 
174
+ ### Privatize & Dead-Code Cleanup (Pass 0.5)
175
+
176
+ * **Trigger Condition**: Baseline tests green.
177
+ * **Actions**:
178
+ 1. Perform the **Cross-Repo Runtime Coupling Check** against `legacy_test_runner` and `blink_web_tests` first.
179
+ 2. Convert internal TypeScript `private` fields/methods to ES `#private` (except those reflectively accessed by web tests).
180
+ 3. Identify and remove unused dead code, redundant containers, or obsolete split widgets in a dedicated prefactor CL so mechanical renames don't clutter logic and view CLs.
181
+ 4. Verify that all tests and lints pass and stage this prefactor CL before proceeding to logic consolidation.
182
+
152
183
  ### Logic Consolidation
153
184
 
154
- * **Trigger Condition**: Baseline tests green (or respective previous pass
155
- staged).
185
+ * **Trigger Condition**: Pass 0.5 staged (or baseline tests green if 0.5 skipped).
156
186
  * **Subskill to Import/Delegate**: `ui-eng-vision-logic-consolidator` (Delegate to a subagent to maintain focus)
157
187
  * **Actions**:
158
188
  1. Extract manual elements, constructor DOM configurations, and imperative
@@ -65,20 +65,23 @@ logical regressions are introduced during modernization.
65
65
 
66
66
  Always detect the execution environment first to run tests successfully:
67
67
 
68
- ### Scenario A: Google-Internal Cog/Cider Workspaces (PRIMARY PATH for Google Workspaces)
68
+ ### Scenario A: Google-Internal Cog Workspaces (PRIMARY PATH for Google Workspaces)
69
69
 
70
70
  * **Detection**: Triggered if the workspace path starts with `/google/cog/` or
71
71
  `/google/src/`.
72
- * **Why it is required**: Raw commands like `./dt test` or `autoninja` fail
73
- because they lack Google cloudtop/virtualization wrapper configurations.
72
+ * **Execution Guide**: Follow [`devtools-verification`](../devtools-verification/SKILL.md).
74
73
  * **Resolution Steps**:
75
74
 
76
- 1. Do not run `./dt test` or standard `autoninja` directly.
77
- 2. Leverage the Google-specific Cider testing script to compile and run
78
- tests in the cloud workspace:
75
+ 1. Ensure `depot_tools` is at the front of your `PATH`:
79
76
 
80
77
  ```bash
81
- python3 internal/infra/scripts/cider/init_workspace.py test /google/cog/cloud/username/workspace_name --test_filter=front_end/panels/application/IndexedDBViews.test.ts
78
+ export PATH="/path/to/depot_tools:$PATH"
79
+ ```
80
+
81
+ 2. Execute tests using `./dt test` directly from `chromium/third_party/devtools-frontend/src`:
82
+
83
+ ```bash
84
+ ./dt test front_end/panels/application/IndexedDBViews.test.ts
82
85
  ```
83
86
 
84
87
  ### Scenario B: Standard Chromium Environment (Fallback)
@@ -133,6 +136,33 @@ Always detect the execution environment first to run tests successfully:
133
136
  3. If it's a layout shift, check if you replaced a block element with an inline element (e.g. `div` -> `span`).
134
137
  4. If styles are missing, verify if the test wrapper needs `{includeCommonStyles: true}`.
135
138
 
139
+ ### Scenario E: Lightweight Test Hook Gotchas (`describe` vs `describeWithEnvironment`)
140
+
141
+ * Prefer `describe` with lightweight hooks (`setupLocaleHooks()`, `setupSettingsHooks()`) when full `describeWithEnvironment` is unnecessary.
142
+ * **Always reset singleton registries in `afterEach`**:
143
+ When registering actions, shortcuts, or context menus in tests, singleton registries MUST be reset in `afterEach`:
144
+
145
+ ```typescript
146
+ afterEach(() => {
147
+ UI.ActionRegistration.reset();
148
+ UI.ActionRegistry.ActionRegistry.reset();
149
+ UI.ShortcutRegistry.ShortcutRegistry.removeInstance();
150
+ });
151
+ ```
152
+
153
+ Without these resets, repeated runs (such as `--repeat=10` or CQ flake detection) will fail on iteration 2+ with `Duplicate action ID: '...'`.
154
+
155
+ * **GlassPane Container Setup**:
156
+ If testing UI that opens a `GlassPane` or long-press option menu (e.g. `bindToAction` with long-press buttons) in a test suite using `describe` without `describeWithEnvironment`, call:
157
+
158
+ ```typescript
159
+ beforeEach(() => {
160
+ UI.GlassPane.GlassPane.setContainer(document.body);
161
+ });
162
+ ```
163
+
164
+ Otherwise, menu rendering will fail because `GlassPane` lacks an attached container element.
165
+
136
166
  --------------------------------------------------------------------------------
137
167
 
138
168
  ## 🔍 Mental Audit (Internal Self-Correction)
@@ -28,11 +28,11 @@ clean `UI.Widget` classes that use native update rendering delegates.
28
28
  2. **Upgrade View Delegates & Inject View**:
29
29
 
30
30
  * Migrate the local Lit template strings into a formally exported default
31
- view layout:
31
+ view layout (using named imports `import {html, render} from '../../ui/lit/lit.js';`):
32
32
 
33
33
  ```typescript
34
34
  export const DEFAULT_VIEW: View = (input, output, target) => {
35
- Lit.render(html`...`, target);
35
+ render(html`...`, target);
36
36
  };
37
37
  ```
38
38
 
@@ -67,10 +67,10 @@ clean `UI.Widget` classes that use native update rendering delegates.
67
67
 
68
68
  * Remove any `LegacyWrapper` bindings or custom wrappable custom elements.
69
69
  * Replace old panel instantiations with standard `<devtools-widget>`
70
- declarative entries:
70
+ declarative entries (using `const {widget} = UI.Widget;`):
71
71
 
72
72
  ```typescript
73
- html`<devtools-widget .widgetConfig=${widgetConfig(MyWidgetClass, [params])}></devtools-widget>`
73
+ html`<devtools-widget ${widget(MyWidgetClass, {params})}></devtools-widget>`
74
74
  ```
75
75
 
76
76
  * Inspect instantiator files (e.g., `ApplicationPanelSidebar.ts`) and
@@ -43,7 +43,7 @@ Complex views can be broken down using helper functions defined inside `DEFAULT_
43
43
  ```ts
44
44
  // clang-format off
45
45
  const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLElement): void => {
46
- const renderHeader = (): Lit.LitTemplate => {
46
+ const renderHeader = (): LitTemplate => {
47
47
  return html`<h1>${input.title}</h1>`;
48
48
  };
49
49
  // ...
@@ -58,10 +58,11 @@ const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLElement)
58
58
 
59
59
  ### Composition
60
60
 
61
- * To render a child widget, the parent's View MUST use lit-html directive `UI.Widget.wiget`
61
+ * To render a child widget, the parent's View MUST use the lit-html directive `UI.Widget.widget`.
62
62
  * Configuration is passed via the parameters.
63
63
  * Properties passed from a parent MUST be declared as public fields on the child presenter class.
64
64
  * The framework automatically updates these properties and calls `requestUpdate()` on the child when the parent re-renders.
65
+ * **Pre-existing Widget Instances (`WrapperWidget`):** To render an existing `UI.Widget` instance (such as locations created by `UI.ViewManager`: `TabbedViewLocation.tabbedPane()`, `StackLocation.widget()`) declaratively without creating a custom wrapper class, use `${widget(UI.Widget.WrapperWidget, {widget: myWidgetInstance})}`. `WrapperWidget` automatically forwards constraints, handles attach/detach lifecycle, and supports dynamic widget replacement.
65
66
 
66
67
  ## Refactoring Legacy Components
67
68
 
@@ -106,7 +107,7 @@ render(html`
106
107
  **Note:** The `{host: input}` option in `render()` is generally **not required** unless you are using specific Shadow DOM patterns that necessitate it. The `@scope` strategy is the preferred method for style isolation in DevTools widgets.
107
108
 
108
109
  ### Legacy Interop & Refs
109
- * **Raw Elements:** Use `Lit.Directives.ref` to obtain a reference to a raw `HTMLElement` if needed for imperative APIs (e.g., `splitWidget.installResizer(element)`).
110
+ * **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)`).
110
111
  * **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).
111
112
 
112
113
  ### Dependencies
@@ -153,12 +154,12 @@ Example: `front_end/panels/my_example/MyExampleWidget.ts`.
153
154
  ```ts
154
155
  // front_end/panels/my_example/MyExampleWidget.ts
155
156
 
156
- import * as Lit from '../../ui/lit/lit.js';
157
+ import {Directives, html, render} from '../../ui/lit/lit.js';
157
158
  import * as UI from '../../ui/legacy/legacy.js';
158
159
 
159
160
  import myExampleWidgetStyles from './myExampleWidget.css.js';
160
161
 
161
- const {html, render, ref} = Lit;
162
+ const {ref} = Directives;
162
163
 
163
164
  // 1. Define Input data shape. (Assuming Child Widget configuration for completeness)
164
165
  export interface ViewInput {
@@ -241,14 +242,13 @@ Example: `front_end/panels/parent/ParentWidget.ts`. Demonstrates passing state v
241
242
  ```ts
242
243
  // front_end/panels/parent/ParentWidget.ts
243
244
 
244
- import * as Lit from '../../ui/lit/lit.js';
245
+ import {html, render} from '../../ui/lit/lit.js';
245
246
  import * as UI from '../../ui/legacy/legacy.js';
246
247
  import {MyExampleWidget} from '../my_example/MyExampleWidget.ts';
247
248
 
248
249
  import parentWidgetStyles from './parentWidgetStyles.css';
249
250
 
250
- const {html, render} = Lit;
251
- const {widgetConfig} = UI.Widget;
251
+ const {widget} = UI.Widget;
252
252
 
253
253
  interface ViewInput {
254
254
  title: string;
@@ -906,6 +906,34 @@ export const DEFAULT_VIEW = (input, _output, target) => {
906
906
  };
907
907
  ```
908
908
 
909
+ ### Long-press action buttons
910
+
911
+ Imperative long-press action buttons (`UI.Toolbar.Toolbar.createLongPressActionButton`) are migrated declaratively by nesting secondary `<devtools-button>` elements inside `<devtools-button ${bindToAction('...')}>`. The parent button triggers the primary action on click, and holding the button down opens a menu presenting the nested buttons:
912
+
913
+ ```typescript
914
+ export const DEFAULT_VIEW = (input, _output, target) => {
915
+ const {bindToAction} = UI.UIUtils;
916
+ render(html`
917
+ <devtools-toolbar>
918
+ <devtools-button ${bindToAction('debugger.toggle-pause')}>
919
+ <devtools-button
920
+ .iconName=${'stop'}
921
+ .variant=${Buttons.Button.Variant.TOOLBAR}
922
+ .title=${i18nString(UIStrings.terminateCurrentJavascriptCall)}
923
+ @click=${input.onTerminateExecution}>
924
+ </devtools-button>
925
+ <devtools-button
926
+ .iconName=${'play'}
927
+ .variant=${Buttons.Button.Variant.TOOLBAR}
928
+ .title=${i18nString(UIStrings.resumeWithAllPausesBlockedForMs)}
929
+ @click=${input.onLongResume}>
930
+ </devtools-button>
931
+ </devtools-button>
932
+ </devtools-toolbar>`,
933
+ target);
934
+ };
935
+ ```
936
+
909
937
  ## Binding a setting to a checkbox
910
938
 
911
939
  Use the `bindToSetting` directive to bind a boolean setting to a `<devtools-checkbox>` component.
@@ -1244,6 +1272,12 @@ export const DEFAULT_VIEW = (input, _output, target) => {
1244
1272
  };
1245
1273
  ```
1246
1274
 
1275
+ ### Pre-existing Widget Instances (`WrapperWidget`)
1276
+ When embedding pre-existing `UI.Widget` instances that are created elsewhere (such as `UI.ViewManager` locations: `TabbedViewLocation.tabbedPane()`, `StackLocation.widget()`), render them declaratively using `${widget(UI.Widget.WrapperWidget, {widget: myWidgetInstance})}` instead of creating custom wrapper widget classes. `WrapperWidget` automatically forwards constraints and manages child widget attach/detach lifecycles.
1277
+
1278
+ ### Preserving `showMode` Settings
1279
+ When migrating a `SplitWidget` that persists sidebar visibility (e.g. via `splitWidget.showModeSetting()`), bind the setting's value to the `<devtools-split-view show=${input.showMode}>` property (`Both`, `OnlyMain`, or `OnlySidebar`) to preserve user settings and layout state across sessions.
1280
+
1247
1281
  ## Migrating `UI.ARIAUtils` helpers
1248
1282
 
1249
1283
  Replace calls to `UI.ARIAUtils` helper functions with the corresponding ARIA attributes directly in the lit-html template.
@@ -258,6 +258,11 @@ export class Settings {
258
258
  return setting;
259
259
  }
260
260
 
261
+ /** The event target shared by all settings. Change listeners are registered with the setting name as event type. */
262
+ get eventTargetForTest(): ObjectWrapper<GenericEvents> {
263
+ return this.#eventSupport;
264
+ }
265
+
261
266
  /**
262
267
  * Get setting via key, and create a new setting if the requested setting does not exist.
263
268
  * @param key kebab-case string ID
@@ -636,6 +636,7 @@ export enum IssueCreated {
636
636
  'GenericIssue::AutofillAndManualTextPolicyControlledFeaturesInfo' = 114,
637
637
  'GenericIssue::AutofillPolicyControlledFeatureInfo' = 115,
638
638
  'GenericIssue::ManualTextPolicyControlledFeatureInfo' = 116,
639
+ 'GenericIssue::GeolocationPromptWithoutUserGesture' = 117,
639
640
  'CorsIssue::InvalidLocalNetworkAccess' = 118,
640
641
  /* eslint-enable @typescript-eslint/naming-convention */
641
642
  MAX_VALUE = 119,
@@ -537,6 +537,24 @@ export class CSSModel extends SDKModel<EventTypes> {
537
537
  return true;
538
538
  }
539
539
 
540
+ forcePositionTryOption(node: DOMNode, index?: number): boolean {
541
+ const currentForcedIndex = node.marker<number>(PositionTryOptionMarker) ?? undefined;
542
+ if (currentForcedIndex === index) {
543
+ return false;
544
+ }
545
+ node.setMarker(PositionTryOptionMarker, index ?? null);
546
+ if (node.id === undefined) {
547
+ return false;
548
+ }
549
+ void this.agent.invoke_forcePositionTryOption({nodeId: node.id, index});
550
+ this.dispatchEventToListeners(Events.PositionTryOptionForced, node);
551
+ return true;
552
+ }
553
+
554
+ forcedPositionTryOption(node: DOMNode): number|undefined {
555
+ return node.marker<number>(PositionTryOptionMarker) ?? undefined;
556
+ }
557
+
540
558
  forcePseudoState(node: DOMNode, pseudoClass: string, enable: boolean): boolean {
541
559
  const forcedPseudoClasses = node.marker<string[]>(PseudoStateMarker) || [];
542
560
  const hasPseudoClass = forcedPseudoClasses.includes(pseudoClass);
@@ -1058,6 +1076,7 @@ export enum Events {
1058
1076
  MediaQueryResultChanged = 'MediaQueryResultChanged',
1059
1077
  ModelWasEnabled = 'ModelWasEnabled',
1060
1078
  ModelDisposed = 'ModelDisposed',
1079
+ PositionTryOptionForced = 'PositionTryOptionForced',
1061
1080
  PseudoStateForced = 'PseudoStateForced',
1062
1081
  StartingStylesStateForced = 'StartingStylesStateForced',
1063
1082
  StyleSheetAdded = 'StyleSheetAdded',
@@ -1087,6 +1106,7 @@ export interface EventTypes {
1087
1106
  [Events.MediaQueryResultChanged]: void;
1088
1107
  [Events.ModelWasEnabled]: void;
1089
1108
  [Events.ModelDisposed]: CSSModel;
1109
+ [Events.PositionTryOptionForced]: DOMNode;
1090
1110
  [Events.PseudoStateForced]: PseudoStateForcedEvent;
1091
1111
  [Events.StartingStylesStateForced]: DOMNode;
1092
1112
  [Events.StyleSheetAdded]: CSSStyleSheetHeader;
@@ -1096,6 +1116,7 @@ export interface EventTypes {
1096
1116
  }
1097
1117
 
1098
1118
  const PseudoStateMarker = 'pseudo-state-marker';
1119
+ const PositionTryOptionMarker = 'position-try-option-marker';
1099
1120
 
1100
1121
  export class Edit {
1101
1122
  styleSheetId: string;
@@ -341,7 +341,7 @@ class ComputedTextChunk {
341
341
  * original and computed slices as required.
342
342
  **/
343
343
  export class ComputedText {
344
- readonly #chunks: ComputedTextChunk[] = [];
344
+ #chunks: ComputedTextChunk[] = [];
345
345
  readonly text: string;
346
346
  readonly #topLevelValueCounts = new Map<string, number>();
347
347
 
@@ -356,6 +356,7 @@ export class ComputedText {
356
356
  }
357
357
 
358
358
  get chunkCount(): number {
359
+ this.#sortIfNecessary();
359
360
  return this.#chunks.length;
360
361
  }
361
362
 
@@ -363,6 +364,14 @@ export class ComputedText {
363
364
  if (this.#sorted) {
364
365
  return;
365
366
  }
367
+ // A match that was pushed more than once is superseded by its last push.
368
+ const lastPush = new Map<Match, ComputedTextChunk>();
369
+ for (const chunk of this.#chunks) {
370
+ lastPush.set(chunk.match, chunk);
371
+ }
372
+ if (lastPush.size < this.#chunks.length) {
373
+ this.#chunks = this.#chunks.filter(chunk => lastPush.get(chunk.match) === chunk);
374
+ }
366
375
  // Sort intervals by offset, with longer intervals first if the offset is identical.
367
376
  this.#chunks.sort((a, b) => {
368
377
  if (a.offset < b.offset) {
@@ -383,7 +392,7 @@ export class ComputedText {
383
392
  }
384
393
 
385
394
  // Add another substitutable match. The match will either be appended to the list of existing matches or it will
386
- // be substituted for the last match(es) if it encompasses them.
395
+ // be substituted for the last match(es) if it encompasses them. Pushing a match again supersedes its earlier push.
387
396
  push(match: Match, offset: number): void {
388
397
  function hasComputedText(match: Match): match is MatchWithComputedText {
389
398
  return Boolean(match.computedText);
@@ -1188,7 +1188,7 @@ export class DOMNode extends Common.ObjectWrapper.ObjectWrapper<DOMNodeEventType
1188
1188
  }
1189
1189
 
1190
1190
  marker<T>(name: string): T|null {
1191
- return this.#markers.get(name) as T || null;
1191
+ return (this.#markers.get(name) as T) ?? null;
1192
1192
  }
1193
1193
 
1194
1194
  getMarkerKeysForTest(): string[] {
@@ -959,6 +959,9 @@ export class DebuggerModel extends SDKModel<EventTypes> {
959
959
  this.#disableAsyncStackTracesSetting.removeChangeListener(this.asyncStackTracesStateChanged, this);
960
960
  this.#breakpointsActiveSetting.removeChangeListener(this.breakpointsActiveChanged, this);
961
961
  this.#jsSourceMapsEnabledSetting.removeChangeListener(this.jsSourceMapsStateChanged, this);
962
+ // Drop all scripts and their source maps, so they don't outlive the target in case something
963
+ // still holds on to this model (e.g. a console message with "Preserve log" enabled).
964
+ this.reset();
962
965
  }
963
966
 
964
967
  override async suspendModel(): Promise<void> {