chrome-devtools-frontend 1.0.1635876 → 1.0.1636056

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.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: devtools-verification
3
- description: MANDATORY: Activate this skill ANY TIME you need to build the project, run tests, or verify code health in DevTools. You MUST use this skill before executing commands like npm test, npm run build, autoninja, or linters, as it contains critical, repository-specific instructions on how to correctly format these commands, filter test runs, and interpret failures.
3
+ description: "MANDATORY: Activate this skill ANY TIME you need to build the project, run tests, or verify code health in DevTools. You MUST use this skill before executing commands like npm test, npm run build, autoninja, or linters, as it contains critical, repository-specific instructions on how to correctly format these commands, filter test runs, and interpret failures."
4
4
  ---
5
5
 
6
6
  # Instructions on how to verify your changes
@@ -2,7 +2,7 @@
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
4
 
5
- import glob from 'glob';
5
+ import {globSync} from 'node:fs';
6
6
  import * as path from 'node:path';
7
7
  import yargs from 'yargs';
8
8
  import {hideBin} from 'yargs/helpers';
@@ -68,9 +68,9 @@ for (const directory of inputDirectories) {
68
68
  ...collectAllStringsInDir(directory),
69
69
  };
70
70
 
71
- const fs = glob.sync('**/*.{js,ts,gn}', {
71
+ const fs = globSync('**/*.{js,ts,gn}', {
72
72
  cwd: directory,
73
- ignore: IGNORED_PATH_COMPONENTS,
73
+ exclude: IGNORED_PATH_COMPONENTS,
74
74
  });
75
75
  files.push(...fs.map(f => path.join(directory, f)));
76
76
  }
@@ -625,6 +625,10 @@ interface UseGcaApi {
625
625
  enabled: boolean;
626
626
  }
627
627
 
628
+ interface DevToolsAIV2Architecture {
629
+ enabled: boolean;
630
+ }
631
+
628
632
  interface DevToolsProtocolMonitor {
629
633
  enabled: boolean;
630
634
  }
@@ -663,6 +667,7 @@ export type HostConfig = Platform.TypeScriptUtilities.RecursivePartial<{
663
667
  devToolsAiAssistanceAccessibilityAgent: HostConfigAiAssistanceAccessibilityAgent,
664
668
  devToolsAiAssistanceStorageAgent: HostConfigAiAssistanceStorageAgent,
665
669
  devToolsAiAssistanceV2: HostConfigAiAssistanceV2,
670
+ devToolsAIV2Architecture: DevToolsAIV2Architecture,
666
671
  devToolsAiCodeCompletion: HostConfigAiCodeCompletion,
667
672
  devToolsAiCodeGeneration: HostConfigAiCodeGeneration,
668
673
  devToolsAiCodeCompletionStyles: HostConfigAiCodeCompletionStyles,
@@ -29,25 +29,6 @@ import {
29
29
  JavascriptExecutor
30
30
  } from './ExecuteJavascript.js';
31
31
 
32
- /**
33
- * The subset of computed CSS properties relevant to accessibility audits.
34
- * These are used to filter the Computed Styles widget in the AI Chat panel to keep it focused and minimal.
35
- */
36
- const ACCESSIBILITY_CSS_PROPERTIES = [
37
- 'color',
38
- 'background-color',
39
- 'display',
40
- 'visibility',
41
- 'opacity',
42
- 'clip',
43
- 'clip-path',
44
- 'font-size',
45
- 'font-weight',
46
- 'line-height',
47
- 'letter-spacing',
48
- 'text-transform',
49
- ];
50
-
51
32
  /**
52
33
  * WARNING: preamble defined in code is only used when userTier is
53
34
  * TESTERS. Otherwise, a server-side preamble is used (see
@@ -486,20 +467,13 @@ export class AccessibilityAgent extends AiAgent<LHModel.ReporterTypes.ReportJSON
486
467
  };
487
468
 
488
469
  const widgets: AiWidget[] = [];
489
- const cssModel = node.domModel().cssModel();
490
- const styles = await cssModel.getComputedStyle(node.id);
491
- const matchedStyles = await cssModel.getMatchedStyles(node.id);
492
- if (styles && matchedStyles) {
493
- widgets.push({
494
- name: 'COMPUTED_STYLES',
495
- data: {
496
- computedStyles: styles,
497
- backendNodeId: node.backendNodeId(),
498
- matchedCascade: matchedStyles,
499
- properties: ACCESSIBILITY_CSS_PROPERTIES,
500
- },
501
- });
502
- }
470
+ const snapshot = await node.takeSnapshot();
471
+ widgets.push({
472
+ name: 'DOM_TREE',
473
+ data: {
474
+ root: snapshot,
475
+ },
476
+ });
503
477
 
504
478
  return {
505
479
  result: JSON.stringify(result, null, 2),
@@ -330,10 +330,17 @@ export interface LighthouseReportAiWidget {
330
330
  };
331
331
  }
332
332
 
333
- // This type will grow as we add more widgets.
334
- export type AiWidget =
335
- ComputedStyleAiWidget|CoreVitalsAiWidget|StylePropertiesAiWidget|DomTreeAiWidget|PerformanceTraceAiWidget|
336
- PerfInsightAiWidget|TimelineRangeSummaryAiWidget|BottomUpTreeAiWidget|SourceFileAiWidget|LighthouseReportAiWidget;
333
+ export interface TimelineEventSummaryAiWidget {
334
+ name: 'TIMELINE_EVENT_SUMMARY';
335
+ data: {
336
+ event: Trace.Types.Events.Event,
337
+ parsedTrace: Trace.TraceModel.ParsedTrace,
338
+ };
339
+ }
340
+
341
+ export type AiWidget = ComputedStyleAiWidget|CoreVitalsAiWidget|StylePropertiesAiWidget|DomTreeAiWidget|
342
+ PerformanceTraceAiWidget|PerfInsightAiWidget|TimelineRangeSummaryAiWidget|BottomUpTreeAiWidget|SourceFileAiWidget|
343
+ LighthouseReportAiWidget|TimelineEventSummaryAiWidget;
337
344
 
338
345
  export type FunctionCallHandlerResult<Result> = {
339
346
  requiresApproval: true,
@@ -1093,7 +1093,16 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
1093
1093
 
1094
1094
  const key = `getEventByKey('${params.eventKey}')`;
1095
1095
  this.#cacheFunctionResult(focus, key, details);
1096
- return {result: {details}};
1096
+ return {
1097
+ result: {details},
1098
+ widgets: [{
1099
+ name: 'TIMELINE_EVENT_SUMMARY',
1100
+ data: {
1101
+ event,
1102
+ parsedTrace,
1103
+ },
1104
+ }],
1105
+ };
1097
1106
  },
1098
1107
  });
1099
1108
 
@@ -1493,7 +1502,16 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
1493
1502
 
1494
1503
  const revealable = new SDK.TraceObject.RevealableEvent(event);
1495
1504
  await Common.Revealer.reveal(revealable);
1496
- return {result: {success: true}};
1505
+ return {
1506
+ result: {success: true},
1507
+ widgets: [{
1508
+ name: 'TIMELINE_EVENT_SUMMARY',
1509
+ data: {
1510
+ event,
1511
+ parsedTrace,
1512
+ },
1513
+ }],
1514
+ };
1497
1515
  },
1498
1516
  });
1499
1517
  }
@@ -15,7 +15,7 @@ import type * as Protocol from '../../../generated/protocol.js';
15
15
  import type {
16
16
  AiWidget, BottomUpTreeAiWidget, ComputedStyleAiWidget, CoreVitalsAiWidget, DomTreeAiWidget, LighthouseReportAiWidget,
17
17
  PerfInsightAiWidget, PerformanceTraceAiWidget, SourceFileAiWidget, StylePropertiesAiWidget,
18
- TimelineRangeSummaryAiWidget} from '../../../models/ai_assistance/agents/AiAgent.js';
18
+ TimelineEventSummaryAiWidget, TimelineRangeSummaryAiWidget} from '../../../models/ai_assistance/agents/AiAgent.js';
19
19
  import * as AiAssistanceModel from '../../../models/ai_assistance/ai_assistance.js';
20
20
  import * as ComputedStyle from '../../../models/computed_style/computed_style.js';
21
21
  import * as Trace from '../../../models/trace/trace.js';
@@ -248,6 +248,14 @@ const UIStringsNotTranslate = {
248
248
  * @description Accessible label for the reveal button in the Lighthouse report widget.
249
249
  */
250
250
  revealLighthouse: 'Reveal Lighthouse report',
251
+ /**
252
+ * @description Title for the Timeline event summary widget.
253
+ */
254
+ timelineEventSummary: 'Event summary',
255
+ /**
256
+ * @description Accessible label for the reveal button in the Timeline event summary widget.
257
+ */
258
+ revealTimelineEventSummary: 'Reveal event',
251
259
  /**
252
260
  * @description Title for the LCP breakdown widget.
253
261
  */
@@ -1454,6 +1462,8 @@ export function getWidgetSignature(widget: AiWidget): string {
1454
1462
  return `${widget.name}:${widget.data.uiSourceCode.url()}`;
1455
1463
  case 'LIGHTHOUSE_REPORT':
1456
1464
  return `${widget.name}:${widget.data.report.fetchTime}`;
1465
+ case 'TIMELINE_EVENT_SUMMARY':
1466
+ return `${widget.name}:${widget.data.event.ts}:${widget.data.event.name}`;
1457
1467
  default:
1458
1468
  Platform.assertNever(widget, 'Unknown AiWidget name');
1459
1469
  }
@@ -1543,6 +1553,9 @@ async function renderWidgets(
1543
1553
  case 'LIGHTHOUSE_REPORT':
1544
1554
  response = await makeLighthouseReportWidget(widgetData);
1545
1555
  break;
1556
+ case 'TIMELINE_EVENT_SUMMARY':
1557
+ response = await makeTimelineEventSummaryWidget(widgetData);
1558
+ break;
1546
1559
  default:
1547
1560
  Platform.assertNever(widgetData, 'Unknown AiWidget name');
1548
1561
  }
@@ -2100,3 +2113,21 @@ async function makeLighthouseReportWidget(widgetData: LighthouseReportAiWidget):
2100
2113
  jslogContext: snapshotReport ? 'lighthouse-snapshot-report-widget' : 'lighthouse-report-widget',
2101
2114
  };
2102
2115
  }
2116
+
2117
+ async function makeTimelineEventSummaryWidget(widgetData: TimelineEventSummaryAiWidget):
2118
+ Promise<WidgetMakerResponse|null> {
2119
+ const renderedWidget = html`<devtools-widget class="timeline-event-summary-widget" ${widget(() => {
2120
+ return Timeline.TimelineDetailsView.TimelineDetailsPane.makeEventWidget(
2121
+ widgetData.data.event,
2122
+ widgetData.data.parsedTrace,
2123
+ );
2124
+ })}></devtools-widget>`;
2125
+
2126
+ return {
2127
+ renderedWidget,
2128
+ revealable: new SDK.TraceObject.RevealableEvent(widgetData.data.event),
2129
+ accessibleRevealLabel: lockedString(UIStringsNotTranslate.revealTimelineEventSummary),
2130
+ title: lockedString(UIStringsNotTranslate.timelineEventSummary),
2131
+ jslogContext: 'timeline-event-summary-widget',
2132
+ };
2133
+ }
@@ -2534,7 +2534,10 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
2534
2534
  // value tells curl to not set the header at all. To post an empty
2535
2535
  // header, you have to terminate it with a semicolon.
2536
2536
  command.push('-H ' + escapeString(name + ';'));
2537
- } else if (name.toLowerCase() === 'cookie') {
2537
+ } else if (name.toLowerCase() === 'cookie' && value.includes('=')) {
2538
+ // If value contains no '=', curl treats it as a filename to read
2539
+ // cookies from, which would be a security risk. Fall back to -H in
2540
+ // that case.
2538
2541
  command.push('-b ' + escapeString(value));
2539
2542
  } else {
2540
2543
  command.push('-H ' + escapeString(name + ': ' + value));
@@ -115,14 +115,28 @@ export class ContextMenuProvider implements
115
115
  const networkPersistenceManager = Persistence.NetworkPersistenceManager.NetworkPersistenceManager.instance();
116
116
 
117
117
  const binding = uiSourceCode && Persistence.Persistence.PersistenceImpl.instance().binding(uiSourceCode);
118
- const fileURL = binding ? binding.fileSystem.contentURL() : contentProvider.contentURL();
118
+ // If contentProvider is already a FileSystem UISourceCode, there's a small chance that uiSourceCodeForURL
119
+ // might return a Network UISourceCode instead (e.g. if they share the same URL but aren't currently bound
120
+ // and the Network project represents the URL first in the lookup list).
121
+ // In this case, the binding will be null. To ensure "Open in containing folder" is still appended when
122
+ // right-clicking the FileSystem file in the Workspace tree, we fall back to contentProvider.
123
+ const fileSystemUISourceCode = binding ?
124
+ binding.fileSystem :
125
+ (contentProvider instanceof Workspace.UISourceCode.UISourceCode &&
126
+ contentProvider.project().type() === Workspace.Workspace.projectTypes.FileSystem ?
127
+ contentProvider :
128
+ uiSourceCode);
119
129
 
120
- if (Common.ParsedURL.schemeIs(fileURL, 'file:')) {
121
- const path = Common.ParsedURL.ParsedURL.urlToRawPathString(fileURL, Host.Platform.isWin());
122
- contextMenu.revealSection().appendItem(
123
- i18nString(UIStrings.openInContainingFolder),
124
- () => Host.InspectorFrontendHost.InspectorFrontendHostInstance.showItemInFolder(path),
125
- {jslogContext: 'open-in-containing-folder'});
130
+ if (fileSystemUISourceCode &&
131
+ fileSystemUISourceCode.project().type() === Workspace.Workspace.projectTypes.FileSystem) {
132
+ const fileURL = fileSystemUISourceCode.contentURL();
133
+ if (Common.ParsedURL.schemeIs(fileURL, 'file:')) {
134
+ const path = Common.ParsedURL.ParsedURL.urlToRawPathString(fileURL, Host.Platform.isWin());
135
+ contextMenu.revealSection().appendItem(
136
+ i18nString(UIStrings.openInContainingFolder),
137
+ () => Host.InspectorFrontendHost.InspectorFrontendHostInstance.showItemInFolder(path),
138
+ {jslogContext: 'open-in-containing-folder'});
139
+ }
126
140
  }
127
141
 
128
142
  if (contentProvider instanceof Workspace.UISourceCode.UISourceCode &&
@@ -93,6 +93,38 @@ export class TimelineDetailsPane extends
93
93
  #onTraceBoundsChangeBound = this.#onTraceBoundsChange.bind(this);
94
94
  #entityMapper: Trace.EntityMapper.EntityMapper|null = null;
95
95
 
96
+ static makeEventWidget(
97
+ event: Trace.Types.Events.Event,
98
+ parsedTrace: Trace.TraceModel.ParsedTrace,
99
+ ): TimelineDetailsPane {
100
+ // Provide a mock delegate to satisfy the constructor requirements.
101
+ // These delegate interactions are not relevant for an AI assistant widget.
102
+ const mockDelegate = {
103
+ select: () => {},
104
+ zoomEvent: () => {},
105
+ element: document.createElement('div'),
106
+ set3PCheckboxDisabled: () => {},
107
+ selectEntryAtTime: () => {},
108
+ highlightEvent: () => {},
109
+ };
110
+ const pane = new TimelineDetailsPane(mockDelegate);
111
+ pane.hideHeader();
112
+ const entityMapper = new Trace.EntityMapper.EntityMapper(parsedTrace);
113
+ void pane
114
+ .setModel({
115
+ parsedTrace,
116
+ selectedEvents: [event],
117
+ eventToRelatedInsightsMap: null,
118
+ entityMapper,
119
+ })
120
+ .then(() => {
121
+ void pane.setSelection({
122
+ event,
123
+ });
124
+ });
125
+ return pane;
126
+ }
127
+
96
128
  constructor(delegate: TimelineModeViewDelegate) {
97
129
  super();
98
130
  this.registerRequiredCSS(detailsViewStyles);
@@ -343,6 +375,10 @@ export class TimelineDetailsPane extends
343
375
  return this.tabbedPane.headerElement();
344
376
  }
345
377
 
378
+ hideHeader(): void {
379
+ this.tabbedPane.headerElement().classList.add('hidden');
380
+ }
381
+
346
382
  setPreferredTab(tabId: string): void {
347
383
  this.preferredTabId = tabId;
348
384
  }
@@ -1,7 +1,7 @@
1
1
  Name: Dependencies sourced from the upstream `chromium` repository
2
2
  URL: Internal
3
3
  Version: N/A
4
- Revision: 268971579b74f0369f828111e6c8f5bafbacd5ee
4
+ Revision: 59215b2081aea1f087ea0f9e9d428c2eb9b41876
5
5
  Update Mechanism: Manual (https://crbug.com/428069060)
6
6
  License: BSD-3-Clause
7
7
  License File: LICENSE
@@ -130,6 +130,7 @@ export class Dialog extends Common.ObjectWrapper.eventMixin<EventTypes, typeof G
130
130
  iconName: 'cross',
131
131
  accessibleLabel: i18nString(UIStrings.close),
132
132
  jslogContext: 'dialog-close',
133
+ title: i18nString(UIStrings.close),
133
134
  };
134
135
  button.classList.add('dialog-close-button');
135
136
  button.addEventListener('click', this.hide.bind(this));
@@ -382,6 +382,10 @@ export function markBeingEdited(element: Element, value: boolean): boolean {
382
382
  return true;
383
383
  }
384
384
 
385
+ export function resetElementsBeingEditedForTest(): void {
386
+ elementsBeingEdited.clear();
387
+ }
388
+
385
389
  const elementsBeingEdited = new Set<Element>();
386
390
 
387
391
  // Avoids Infinity, NaN, and scientific notation (e.g. 1e20), see crbug.com/81165.
@@ -4037,6 +4037,7 @@ export const knownContextValues = new Set([
4037
4037
  'timeline-dim-unrelated-events',
4038
4038
  'timeline-disable-js-sampling',
4039
4039
  'timeline-enhanced-traces',
4040
+ 'timeline-event-summary-widget',
4040
4041
  'timeline-experimental-insights',
4041
4042
  'timeline-flamechart-main-view-group-expansion',
4042
4043
  'timeline-flamechart-network-view-group-expansion',
package/package.json CHANGED
@@ -41,7 +41,6 @@
41
41
  "@types/emscripten": "1.39.4",
42
42
  "@types/estree": "1.0.8",
43
43
  "@types/filesystem": "0.0.36",
44
- "@types/glob": "7.2.0",
45
44
  "@types/karma-chai-sinon": "0.1.20",
46
45
  "@types/mocha": "10.0.10",
47
46
  "@types/node": "24.10.0",
@@ -62,7 +61,6 @@
62
61
  "eslint-plugin-jsdoc": "61.2.1",
63
62
  "eslint-plugin-lit": "2.1.1",
64
63
  "eslint-plugin-mocha": "10.5.0",
65
- "glob": "7.1.7",
66
64
  "globals": "16.5.0",
67
65
  "js-yaml": "4.1.1",
68
66
  "karma": "6.4.4",
@@ -96,5 +94,5 @@
96
94
  "yargs": "17.7.2",
97
95
  "js-rouge": "3.2.0"
98
96
  },
99
- "version": "1.0.1635876"
97
+ "version": "1.0.1636056"
100
98
  }