chrome-devtools-frontend 1.0.1674545 → 1.0.1675430

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 (45) hide show
  1. package/.agents/skills/devtools-ux-writing-refactor/SKILL.md +26 -9
  2. package/front_end/core/common/ParsedURL.ts +5 -1
  3. package/front_end/core/common/SettingRegistration.ts +29 -8
  4. package/front_end/core/common/Settings.ts +0 -11
  5. package/front_end/core/root/Runtime.ts +4 -0
  6. package/front_end/core/sdk/TargetManager.ts +18 -0
  7. package/front_end/entrypoints/main/MainImpl.ts +1 -0
  8. package/front_end/foundation/Universe.ts +44 -29
  9. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +15 -5
  10. package/front_end/models/emulation/DeviceModeModel.ts +60 -71
  11. package/front_end/models/emulation/EmulatedDevices.ts +18 -66
  12. package/front_end/models/persistence/AutomaticFileSystemManager.ts +2 -2
  13. package/front_end/models/persistence/IsolatedFileSystemManager.ts +20 -29
  14. package/front_end/models/workspace/FileManager.ts +13 -6
  15. package/front_end/panels/application/WebMCPView.ts +13 -5
  16. package/front_end/panels/application/components/AdsView.ts +24 -1
  17. package/front_end/panels/application/components/adsView.css +27 -21
  18. package/front_end/panels/autofill/AutofillView.ts +12 -12
  19. package/front_end/panels/autofill/autofill-meta.ts +2 -2
  20. package/front_end/panels/elements/ElementsTreeElement.ts +550 -327
  21. package/front_end/panels/elements/ElementsTreeOutline.ts +1 -1
  22. package/front_end/panels/js_timeline/js_timeline-meta.ts +8 -8
  23. package/front_end/panels/layer_viewer/LayerDetailsView.ts +30 -30
  24. package/front_end/panels/layer_viewer/LayerTreeOutline.ts +6 -6
  25. package/front_end/panels/layer_viewer/LayerViewHost.ts +1 -1
  26. package/front_end/panels/layer_viewer/Layers3DView.ts +11 -11
  27. package/front_end/panels/layer_viewer/PaintProfilerView.ts +8 -8
  28. package/front_end/panels/layer_viewer/TransformController.ts +3 -3
  29. package/front_end/panels/layer_viewer/layer_viewer-meta.ts +11 -11
  30. package/front_end/panels/mobile_throttling/ThrottlingManager.ts +1 -58
  31. package/front_end/panels/mobile_throttling/mobile_throttling.ts +0 -10
  32. package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +7 -0
  33. package/front_end/panels/settings/emulation/DevicesSettingsTab.ts +1 -2
  34. package/front_end/third_party/chromium/README.chromium +1 -1
  35. package/front_end/ui/comments/CommentAnchorResolver.ts +132 -0
  36. package/front_end/ui/comments/comments.ts +9 -0
  37. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +40 -0
  38. package/front_end/ui/legacy/components/utils/Linkifier.ts +1 -0
  39. package/front_end/ui/settings/SettingUIRegistration.ts +4 -0
  40. package/front_end/ui/visual_logging/Debugging.ts +1 -5
  41. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  42. package/front_end/ui/visual_logging/LoggingConfig.ts +21 -0
  43. package/front_end/ui/visual_logging/visual_logging.ts +9 -0
  44. package/package.json +1 -1
  45. package/front_end/panels/mobile_throttling/MobileThrottlingSelector.ts +0 -92
@@ -59,14 +59,16 @@ Locate all TypeScript files in the target folder that define `const UIStrings =
59
59
  * For panel names that consist of two words, capitalize only the first word (for example, `Developer resources panel`).
60
60
  * When you use the panel name in combination with another word, capitalize the panel name but not the other word, unless it is a proper noun (for example, `Console view` or `DevTools Console`).
61
61
  * In some cases, ambiguity exists whether a word refers to a UX element in DevTools (such as a panel name) or a concept (such as developer terminology). For example, this occurs with `console`, `issue`, or `network`. Decide based on the surrounding context and code (for example, `Console view`, `Console sidebar`, and `Console prompt` versus `console message`, `console warning`, `console log`, `copy console`, `clear console`, and `console history`; `Show Network` versus `network log` and `network filter`).
62
+ * **Casing in `@description` comments:** Apply the same capitalization rules to `@description` comments: ONLY panel names use sentence case (for example, `Memory panel`, `Console panel`, `Performance panel`). Feature names, view names, tool names, and sub-components MUST be all lowercase unless they appear at the very start of the description sentence or phrase (for example, `heap profiler`, `heap snapshot view`, `isolate selector`, `allocation sampling`, `command menu`, `summary view`).
62
63
  6. **Punctuation and actionability:** Remove trailing periods from single-sentence labels or titles. Ensure that error messages instruct the user how to recover (for example, `Shorten filename to 64 characters or less` instead of `Invalid filename`). Ensure that ARIA labels and multi-sentence tooltips have consistent terminal punctuation.
63
64
  7. **Terminology (glossary):** Strictly follow standard DevTools UI terminology and letter casing (`panel`, `tab`, `drawer`, `sidebar`, `datagrid` or `table`, `action bar`, `status bar`, and `live expressions section`). Never use `pane` or call tabs `panes` in UI strings or localization (L10n) comments.
64
65
  8. **Localization (L10n) comments:** Ensure that every string in `UIStrings` has a preceding `@description` comment that explains where and when it appears. This information is used for translators who need to understand the context in which the string is used.
66
+ * **Research usage sites:** Before modifying or writing `@description` comments, always research where the string key (for example, `UIStrings.keyName`) is used in the codebase (`grep_search` or view surrounding code). Determine the exact UI element type (for example, button label, tooltip, table column header, context menu item, checkbox label, aria label, status bar message, or dropdown option) and location (panel, view, sidebar, or dialog).
67
+ * **Avoid redundancy and repetition:** Do not simply repeat or restate the UI string value in the description (for example, avoid `@description Text for clear all profiles` for `'Clear all profiles'`). Instead, describe the UI role, element type, and location (for example, `@description Tooltip text for the clear button in the profiles sidebar of the Memory panel.`).
68
+ * **Consistency across similar descriptions:** Ensure consistent phrasing structure across descriptions of similar UI strings in the same module and throughout DevTools (for example, use uniform patterns like `Tooltip text for the <action> button in <location>.` or `Column header in <table_name> datagrid for <purpose>.`).
69
+ * **Casing in descriptions:** Strictly follow the rule that ONLY panel names use sentence case (for example, `Memory panel`, `Console panel`, `Profiles panel`), while feature names, views, tools, and sub-components are ALL LOWERCASE (for example, `heap profiler`, `heap snapshot view`, `isolate selector`, `allocation sampling`, `summary view`), unless appearing at the start of the description sentence or phrase.
65
70
  * **Straight apostrophes in comments:** Always use straight apostrophes (`'`) in code comments (such as `@description` comments and L10n annotations), even if the UI string itself uses curly apostrophes (`’`).
66
- * Use precise terminology and correct letter casing (see rule 7). Ensure that the description is easy to understand and provides enough context for translators. For descriptions that are underspecified or
67
- ambiguous, figure out the context by looking at the use site of the
68
- string and come up with a better description.
69
- * You must explicitly document all standard placeholders (`{PH1}`, `{url}`, `{index}`) with runtime data examples (for example, `@example {https://example.com} url`).
71
+ * **Placeholders:** You must explicitly document all standard placeholders (`{PH1}`, `{url}`, `{index}`) with runtime data examples (for example, `@example {https://example.com} url`).
70
72
  * *ICU plural variables:* The i18n tool automatically parses variables in ICU plural format (such as `n` in `{n, plural, =0 {No issues} ...}`) as numeric counts, so they don’t require an `@example` tag in the `@description` comment.
71
73
  * *Terminal punctuation:* Every `@description` comment must end with a period (`.`), even if it is a single phrase or sentence.
72
74
 
@@ -74,11 +76,26 @@ Locate all TypeScript files in the target folder that define `const UIStrings =
74
76
 
75
77
  Also consult the style guides at `google3/experimental/users/rachelandrew/tools/chrome_writing/knowledge/style/` for applicable guidelines.
76
78
 
77
- ## 5. Pause for confirmation
79
+ ## 5. Subagent critique of proposed changes
80
+
81
+ Before running tests or pausing for user review, enter an iterative critique loop with a subagent:
82
+ 1. **Invoke subagent:** Use `invoke_subagent` with `TypeName: "self"` and `Role: "UX Writing Reviewer"`.
83
+ 2. **Prompt instructions:** Provide the subagent with the `git diff` of your changes and instruct it to critique the refactoring against the **8-point UX writing checklist**:
84
+ - Are `@description` comments specific, informative, and non-redundant (not restating string values)?
85
+ - Are usage sites researched so the UI element type and location are accurately described?
86
+ - Do `@description` comments and string values strictly follow the casing rule (ONLY panel names in sentence case, feature/view names in all lowercase unless starting a phrase)?
87
+ - Are contractions, curly apostrophes, ellipses, and placeholders (`{PH1}`) correctly formatted?
88
+ - Were all references in sibling code/tests properly updated?
89
+ 3. **Address feedback and loop:**
90
+ - If the subagent raises any feedback, concerns, or suggested fixes, apply the necessary code changes.
91
+ - Re-invoke the subagent with the updated `git diff` to re-critique the changes.
92
+ - **Repeat this loop continuously as long as the subagent has feedback, until the subagent explicitly approves the diff with no remaining issues.**
93
+
94
+ ## 6. Pause for confirmation
78
95
 
79
96
  Ask the user for a preliminary review of the proposed changes before proceeding. If the user has feedback, address feedback and pause again for confirmation.
80
97
 
81
- ## 6. Mandatory verification and testing
98
+ ## 7. Mandatory verification and testing
82
99
 
83
100
  Don’t finish an edit without running the linter and test suite. In DevTools, i18n placeholder changes or string edits can easily break tests or linter rules.
84
101
 
@@ -89,18 +106,18 @@ Don’t finish an edit without running the linter and test suite. In DevTools, i
89
106
  npm run lint -- <folder_path>
90
107
  ```
91
108
  3. **Run unit tests**
92
- Run unit tests for the target folder first for fast feedback. Then, run the full test suite to verify that no cross-module regressions or snapshot failures occurred:
109
+ You MUST run the full test suite using `npm run test` to verify that no cross-module regressions, e2e test failures, or snapshot regressions occurred. Do not only run a subset of tests:
93
110
  ```bash
94
- npm run test -- <folder_path>
95
111
  npm run test
96
112
  ```
113
+ *(Optionally, you may run `npm run test -- <folder_path>` first for rapid initial feedback during iterative development, but running `npm run test` for full test suite coverage is required before completing the task.)*
97
114
  4. **Run presubmit checks**
98
115
  Ensure that you commit or stage all changes before you run presubmit checks:
99
116
  ```bash
100
117
  git cl presubmit -u
101
118
  ```
102
119
 
103
- ## 7. Summarize changes and upload the CL
120
+ ## 8. Summarize changes and upload the CL
104
121
 
105
122
  When all tests and presubmit checks pass, commit your changes and upload the CL to Gerrit. Don’t use `[uxw]` as a prefix.
106
123
 
@@ -533,7 +533,11 @@ export class ParsedURL {
533
533
  return 'data:' as Platform.DevToolsPath.UrlString;
534
534
  }
535
535
  const scheme = this.isBlobURL() ? this.blobInnerScheme : this.scheme;
536
- return scheme + '://' + this.domain() as Platform.DevToolsPath.UrlString;
536
+ const domain = this.domain();
537
+ if (!scheme && !domain) {
538
+ return '' as Platform.DevToolsPath.UrlString;
539
+ }
540
+ return scheme + '://' + domain as Platform.DevToolsPath.UrlString;
537
541
  }
538
542
 
539
543
  urlWithoutScheme(): string {
@@ -82,12 +82,34 @@ const str_ = i18n.i18n.registerUIStrings('core/common/SettingRegistration.ts', U
82
82
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
83
83
  let registeredSettings: SettingRegistration[] = [];
84
84
  const settingNameSet = new Set<string>();
85
+ const orderValuesBySettingCategory = new Map<SettingCategory, Set<number>>();
86
+
87
+ export function registerCategoryOrder(category?: SettingCategory, order?: number): void {
88
+ if (category && typeof order === 'number') {
89
+ let orderValues = orderValuesBySettingCategory.get(category);
90
+ if (!orderValues) {
91
+ orderValues = new Set();
92
+ orderValuesBySettingCategory.set(category, orderValues);
93
+ }
94
+ if (orderValues.has(order)) {
95
+ throw new Error(`Duplicate order value '${order}' for settings category '${category}'`);
96
+ }
97
+ orderValues.add(order);
98
+ }
99
+ }
100
+
101
+ export function removeCategoryOrder(category?: SettingCategory, order?: number): void {
102
+ if (category && typeof order === 'number') {
103
+ orderValuesBySettingCategory.get(category)?.delete(order);
104
+ }
105
+ }
85
106
 
86
107
  export function registerSettingExtension(registration: SettingRegistration): void {
87
108
  const settingName = registration.settingName;
88
109
  if (settingNameSet.has(settingName)) {
89
110
  throw new Error(`Duplicate setting name '${settingName}'`);
90
111
  }
112
+ registerCategoryOrder(registration.category, registration.order);
91
113
  settingNameSet.add(settingName);
92
114
  registeredSettings.push(registration);
93
115
  }
@@ -98,19 +120,17 @@ export function getRegisteredSettings(): SettingRegistration[] {
98
120
 
99
121
  export function registerSettingsForTest(settings: SettingRegistration[], forceReset = false): void {
100
122
  if (registeredSettings.length === 0 || forceReset) {
101
- registeredSettings = settings;
102
- settingNameSet.clear();
123
+ resetSettings();
103
124
  for (const setting of settings) {
104
- const settingName = setting.settingName;
105
- if (settingNameSet.has(settingName)) {
106
- throw new Error(`Duplicate setting name '${settingName}'`);
107
- }
108
- settingNameSet.add(settingName);
125
+ registerSettingExtension(setting);
109
126
  }
110
127
  }
111
128
  }
112
129
 
113
130
  export function resetSettings(): void {
131
+ for (const setting of registeredSettings) {
132
+ removeCategoryOrder(setting.category, setting.order);
133
+ }
114
134
  registeredSettings = [];
115
135
  settingNameSet.clear();
116
136
  }
@@ -120,7 +140,8 @@ export function maybeRemoveSettingExtension(settingName: string): boolean {
120
140
  if (settingIndex < 0 || !settingNameSet.delete(settingName)) {
121
141
  return false;
122
142
  }
123
- registeredSettings.splice(settingIndex, 1);
143
+ const [removed] = registeredSettings.splice(settingIndex, 1);
144
+ removeCategoryOrder(removed.category, removed.order);
124
145
  return true;
125
146
  }
126
147
 
@@ -112,7 +112,6 @@ export class Settings {
112
112
  readonly #settingRegistrations: SettingRegistration[];
113
113
  readonly #sessionStorage = new SettingsStorage({});
114
114
  settingNameSet = new Set<string>();
115
- orderValuesBySettingCategory = new Map<SettingCategory, Set<number>>();
116
115
  #eventSupport = new ObjectWrapper<GenericEvents>();
117
116
  #registry = new Map<string, Setting<unknown>>();
118
117
  readonly moduleSettings = new Map<string, Setting<unknown>>();
@@ -215,19 +214,9 @@ export class Settings {
215
214
 
216
215
  private registerModuleSetting(setting: Setting<unknown>): void {
217
216
  const settingName = setting.name;
218
- const category = setting.category();
219
- const order = setting.order();
220
217
  if (this.settingNameSet.has(settingName)) {
221
218
  throw new Error(`Duplicate Setting name '${settingName}'`);
222
219
  }
223
- if (category && order) {
224
- const orderValues = this.orderValuesBySettingCategory.get(category) || new Set();
225
- if (orderValues.has(order)) {
226
- throw new Error(`Duplicate order value '${order}' for settings category '${category}'`);
227
- }
228
- orderValues.add(order);
229
- this.orderValuesBySettingCategory.set(category, orderValues);
230
- }
231
220
  this.settingNameSet.add(settingName);
232
221
  this.moduleSettings.set(setting.name, setting);
233
222
  }
@@ -540,6 +540,9 @@ interface DevToolsPlusButton {
540
540
  interface DevToolsInstrumentationBreakpoints {
541
541
  enabled: boolean;
542
542
  }
543
+ interface HostConfigDevToolsComments {
544
+ enabled: boolean;
545
+ }
543
546
 
544
547
  /**
545
548
  * The host configuration that we expect from the DevTools back-end.
@@ -599,6 +602,7 @@ export type HostConfig = Platform.TypeScriptUtilities.RecursivePartial<{
599
602
  devToolsPlusButton: DevToolsPlusButton,
600
603
  devToolsInstrumentationBreakpoints: DevToolsInstrumentationBreakpoints,
601
604
  extensionsOnChromeUrls: ExtensionsOnChromeUrls,
605
+ devToolsComments: HostConfigDevToolsComments,
602
606
  }>;
603
607
 
604
608
  /**
@@ -122,6 +122,24 @@ export class TargetManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes
122
122
  Root.DevToolsContext.globalInstance().delete(TargetManager);
123
123
  }
124
124
 
125
+ // TODO(crbug.com/542394587): Should be `Symbol.dispose`
126
+ dispose(): void {
127
+ for (const target of this.targets()) {
128
+ target.dispose('TargetManager disposed');
129
+ }
130
+ if (this.#browserTarget) {
131
+ this.#browserTarget.dispose('TargetManager disposed');
132
+ this.#browserTarget = null;
133
+ }
134
+ this.#targets.clear();
135
+ this.#observers.clear();
136
+ this.#modelObservers.clear();
137
+ this.#modelListeners.clear();
138
+ this.#scopeChangeListeners.clear();
139
+ this.#scopeTarget = null;
140
+ this.#scopedObservers = new WeakSet();
141
+ }
142
+
125
143
  onInspectedURLChange(target: Target): void {
126
144
  if (target !== this.#scopeTarget) {
127
145
  return;
@@ -209,6 +209,7 @@ export class MainImpl {
209
209
  hostConfig: Root.Runtime.hostConfig,
210
210
  inspectorFrontendHost: Host.InspectorFrontendHost.InspectorFrontendHostInstance,
211
211
  supportsEmulation: this.#supportsEmulation,
212
+ initAutomaticFilesystem: true,
212
213
  };
213
214
  this.#universe = new Foundation.Universe.Universe(creationOptions);
214
215
  Root.DevToolsContext.setGlobalInstance(this.#universe.context as Root.DevToolsContext.WritableDevToolsContext);
@@ -28,6 +28,7 @@ export interface CreationOptions {
28
28
  hostConfig: Root.Runtime.HostConfig;
29
29
  inspectorFrontendHost: Host.InspectorFrontendHostAPI.InspectorFrontendHostAPI;
30
30
  supportsEmulation: boolean;
31
+ initAutomaticFilesystem?: boolean;
31
32
  }
32
33
 
33
34
  export class Universe {
@@ -37,6 +38,7 @@ export class Universe {
37
38
  readonly context: Root.DevToolsContext.DevToolsContext;
38
39
  readonly autofillManager: AutofillManager.AutofillManager.AutofillManager;
39
40
  readonly supportsEmulation: boolean;
41
+ readonly initAutomaticFilesystem: boolean;
40
42
  readonly fileSystemWorkspaceBinding: Persistence.FileSystemWorkspaceBinding.FileSystemWorkspaceBinding;
41
43
 
42
44
  constructor(options: CreationOptions) {
@@ -78,11 +80,17 @@ export class Universe {
78
80
  const multitargetNetworkManager = new SDK.NetworkManager.MultitargetNetworkManager(targetManager);
79
81
  context.set(SDK.NetworkManager.MultitargetNetworkManager, multitargetNetworkManager);
80
82
 
83
+ const workspace = new Workspace.Workspace.WorkspaceImpl();
84
+ context.set(Workspace.Workspace.WorkspaceImpl, workspace);
85
+
86
+ const fileManager = new Workspace.FileManager.FileManager();
87
+ context.set(Workspace.FileManager.FileManager, fileManager);
88
+
81
89
  this.supportsEmulation = options.supportsEmulation;
82
90
  let deviceModeModel = null;
83
91
  if (options.supportsEmulation) {
84
- deviceModeModel =
85
- new Emulation.DeviceModeModel.DeviceModeModel(targetManager, settings, multitargetNetworkManager);
92
+ deviceModeModel = new Emulation.DeviceModeModel.DeviceModeModel(targetManager, settings,
93
+ multitargetNetworkManager, fileManager);
86
94
  context.set(Emulation.DeviceModeModel.DeviceModeModel, deviceModeModel);
87
95
  }
88
96
 
@@ -90,15 +98,20 @@ export class Universe {
90
98
  new SDK.PageResourceLoader.PageResourceLoader(targetManager, settings, multitargetNetworkManager, null);
91
99
  context.set(SDK.PageResourceLoader.PageResourceLoader, pageResourceLoader);
92
100
 
93
- const projectSettingsModel = new ProjectSettings.ProjectSettingsModel.ProjectSettingsModel(
94
- pageResourceLoader,
95
- targetManager,
96
- );
97
- context.set(ProjectSettings.ProjectSettingsModel.ProjectSettingsModel, projectSettingsModel);
98
-
99
- const automaticFileSystemManager = new Persistence.AutomaticFileSystemManager.AutomaticFileSystemManager(
100
- options.inspectorFrontendHost, projectSettingsModel);
101
- context.set(Persistence.AutomaticFileSystemManager.AutomaticFileSystemManager, automaticFileSystemManager);
101
+ this.initAutomaticFilesystem = options.initAutomaticFilesystem ?? false;
102
+ let automaticFileSystemManager = null;
103
+ let projectSettingsModel = null;
104
+ if (this.initAutomaticFilesystem) {
105
+ projectSettingsModel = new ProjectSettings.ProjectSettingsModel.ProjectSettingsModel(
106
+ pageResourceLoader,
107
+ targetManager,
108
+ );
109
+ context.set(ProjectSettings.ProjectSettingsModel.ProjectSettingsModel, projectSettingsModel);
110
+
111
+ automaticFileSystemManager = new Persistence.AutomaticFileSystemManager.AutomaticFileSystemManager(
112
+ options.inspectorFrontendHost, projectSettingsModel);
113
+ context.set(Persistence.AutomaticFileSystemManager.AutomaticFileSystemManager, automaticFileSystemManager);
114
+ }
102
115
 
103
116
  const cpuThrottlingManager = new SDK.CPUThrottlingManager.CPUThrottlingManager(settings, targetManager);
104
117
  context.set(SDK.CPUThrottlingManager.CPUThrottlingManager, cpuThrottlingManager);
@@ -117,22 +130,18 @@ export class Universe {
117
130
  const domModelUndoStack = new SDK.DOMModel.DOMModelUndoStack();
118
131
  context.set(SDK.DOMModel.DOMModelUndoStack, domModelUndoStack);
119
132
 
120
- const workspace = new Workspace.Workspace.WorkspaceImpl();
121
- context.set(Workspace.Workspace.WorkspaceImpl, workspace);
122
-
123
- const fileManager = new Workspace.FileManager.FileManager();
124
- context.set(Workspace.FileManager.FileManager, fileManager);
125
-
126
- const automaticFileSystemWorkspaceBinding =
127
- new Persistence.AutomaticFileSystemWorkspaceBinding.AutomaticFileSystemWorkspaceBinding(
128
- automaticFileSystemManager,
129
- isolatedFileSystemManager,
130
- workspace,
131
- );
132
- context.set(
133
- Persistence.AutomaticFileSystemWorkspaceBinding.AutomaticFileSystemWorkspaceBinding,
134
- automaticFileSystemWorkspaceBinding,
135
- );
133
+ if (automaticFileSystemManager) {
134
+ const automaticFileSystemWorkspaceBinding =
135
+ new Persistence.AutomaticFileSystemWorkspaceBinding.AutomaticFileSystemWorkspaceBinding(
136
+ automaticFileSystemManager,
137
+ isolatedFileSystemManager,
138
+ workspace,
139
+ );
140
+ context.set(
141
+ Persistence.AutomaticFileSystemWorkspaceBinding.AutomaticFileSystemWorkspaceBinding,
142
+ automaticFileSystemWorkspaceBinding,
143
+ );
144
+ }
136
145
 
137
146
  this.fileSystemWorkspaceBinding =
138
147
  new Persistence.FileSystemWorkspaceBinding.FileSystemWorkspaceBinding(isolatedFileSystemManager, workspace);
@@ -226,6 +235,11 @@ export class Universe {
226
235
  dispose(): void {
227
236
  // TODO(crbug.com/542394587): Track these in a DisposableStack.
228
237
  this.context.get(Persistence.IsolatedFileSystemManager.IsolatedFileSystemManager).dispose();
238
+ if (this.initAutomaticFilesystem) {
239
+ this.context.get(Persistence.AutomaticFileSystemManager.AutomaticFileSystemManager).dispose();
240
+ }
241
+ this.context.get(Workspace.FileManager.FileManager).dispose();
242
+ this.context.get(SDK.TargetManager.TargetManager).dispose();
229
243
  }
230
244
 
231
245
  get automaticFileSystemManager(): Persistence.AutomaticFileSystemManager.AutomaticFileSystemManager {
@@ -338,8 +352,9 @@ export class Universe {
338
352
  return this.context.get(Bindings.PresentationConsoleMessageHelper.PresentationConsoleMessageManager);
339
353
  }
340
354
 
341
- get projectSettingsModel(): ProjectSettings.ProjectSettingsModel.ProjectSettingsModel {
342
- return this.context.get(ProjectSettings.ProjectSettingsModel.ProjectSettingsModel);
355
+ get projectSettingsModel(): ProjectSettings.ProjectSettingsModel.ProjectSettingsModel|null {
356
+ return this.initAutomaticFilesystem ? this.context.get(ProjectSettings.ProjectSettingsModel.ProjectSettingsModel) :
357
+ null;
343
358
  }
344
359
 
345
360
  get settings(): Common.Settings.Settings {
@@ -204,12 +204,22 @@ const STATIC_LABEL_NAMES: Record<string, string> = {
204
204
  NO_NAVIGATION: 'the period before the first navigation',
205
205
  };
206
206
 
207
+ function getInsightModel(
208
+ model: Trace.Insights.Types.InsightModels,
209
+ key: string,
210
+ ): Trace.Insights.Types.InsightModels[keyof Trace.Insights.Types.InsightModels]|undefined {
211
+ if (Object.prototype.hasOwnProperty.call(model, key)) {
212
+ return model[key as keyof Trace.Insights.Types.InsightModels];
213
+ }
214
+ return undefined;
215
+ }
216
+
207
217
  /**
208
218
  * Converts the label name we use in the code to a human readable one that is
209
219
  * shown to the user.
210
220
  */
211
221
  export function getLabelName(label: MainThreadSectionLabel, focus: AgentFocus): string {
212
- if (STATIC_LABEL_NAMES[label]) {
222
+ if (Object.prototype.hasOwnProperty.call(STATIC_LABEL_NAMES, label)) {
213
223
  return STATIC_LABEL_NAMES[label];
214
224
  }
215
225
 
@@ -222,7 +232,7 @@ export function getLabelName(label: MainThreadSectionLabel, focus: AgentFocus):
222
232
  // Go through all the insights we have to find the first one that matches to find the title.
223
233
  // TODO(b/505291090): make it easier to look up Insight titles from a key.
224
234
  for (const insightSet of parsedTrace.insights?.values() ?? []) {
225
- const model = insightSet.model[label as keyof Trace.Insights.Types.InsightModels];
235
+ const model = getInsightModel(insightSet.model, label);
226
236
  if (model) {
227
237
  return `${model.title} insight`;
228
238
  }
@@ -813,7 +823,7 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
813
823
  return {error: `Invalid insight set id. Valid insight set ids are: ${valid}`};
814
824
  }
815
825
 
816
- const insight = insightSet.model[params.insightName as keyof Trace.Insights.Types.InsightModels];
826
+ const insight = getInsightModel(insightSet.model, params.insightName);
817
827
  if (!insight) {
818
828
  const valid = Object.keys(insightSet.model).join(', ');
819
829
  return {error: `No insight available. Valid insight names are: ${valid}`};
@@ -1361,14 +1371,14 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
1361
1371
  }
1362
1372
 
1363
1373
  if (insightSet) {
1364
- const model = insightSet.model[label as keyof Trace.Insights.Types.InsightModels];
1374
+ const model = getInsightModel(insightSet.model, label);
1365
1375
  if (model) {
1366
1376
  return Trace.Insights.Common.insightBounds(model, insightSet.bounds);
1367
1377
  }
1368
1378
  }
1369
1379
 
1370
1380
  for (const is of parsedTrace.insights?.values() ?? []) {
1371
- const model = is.model[label as keyof Trace.Insights.Types.InsightModels];
1381
+ const model = getInsightModel(is.model, label);
1372
1382
  if (model) {
1373
1383
  return Trace.Insights.Common.insightBounds(model, is.bounds);
1374
1384
  }