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.
- package/.agents/skills/verification/SKILL.md +1 -1
- package/front_end/core/i18n/collect-ui-strings.js +3 -3
- package/front_end/core/root/Runtime.ts +5 -0
- package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +7 -33
- package/front_end/models/ai_assistance/agents/AiAgent.ts +11 -4
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +20 -2
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +32 -1
- package/front_end/panels/network/NetworkLogView.ts +4 -1
- package/front_end/panels/sources/PersistenceActions.ts +21 -7
- package/front_end/panels/timeline/TimelineDetailsView.ts +36 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/legacy/Dialog.ts +1 -0
- package/front_end/ui/legacy/UIUtils.ts +4 -0
- package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
- package/package.json +1 -3
|
@@ -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
|
|
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 =
|
|
71
|
+
const fs = globSync('**/*.{js,ts,gn}', {
|
|
72
72
|
cwd: directory,
|
|
73
|
-
|
|
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
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
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
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
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 {
|
|
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 {
|
|
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
|
-
|
|
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 (
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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:
|
|
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.
|
|
97
|
+
"version": "1.0.1636056"
|
|
100
98
|
}
|