chrome-devtools-frontend 1.0.1698733 → 1.0.1699061
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/devtools-verification/SKILL.md +19 -0
- package/.agents/skills/{repro-flaky-tests → fix-tests}/SKILL.md +2 -2
- package/front_end/core/sdk/DOMModel.ts +3 -5
- package/front_end/core/sdk/NetworkManager.ts +2 -2
- package/front_end/core/sdk/OverlayModel.ts +11 -12
- package/front_end/core/sdk/SourceMapScopeChainEntry.ts +84 -32
- package/front_end/models/emulation/DeviceModeModel.ts +1 -1
- package/front_end/models/issues_manager/CookieIssue.ts +0 -13
- package/front_end/models/source_map_scopes/NamesResolver.ts +11 -3
- package/front_end/models/source_map_scopes/ScopeChainModel.ts +10 -6
- package/front_end/panels/accessibility/AccessibilityAnnouncementRecordingView.ts +281 -3
- package/front_end/panels/accessibility/accessibilityAnnouncementRecordingView.css +85 -0
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +1 -2
- package/front_end/panels/animation/AnimationTimeline.ts +1 -1
- package/front_end/panels/application/CrashReportContextView.ts +1 -1
- package/front_end/panels/application/IndexedDBViews.ts +1 -1
- package/front_end/panels/application/KeyValueStorageItemsView.ts +1 -0
- package/front_end/panels/application/components/AdsView.ts +63 -1
- package/front_end/panels/application/components/adsView.css +11 -1
- package/front_end/panels/common/CommentThreadWidget.ts +1 -16
- package/front_end/panels/common/commentThreadWidget.css +0 -12
- package/front_end/panels/elements/CSSRuleValidator.ts +1 -1
- package/front_end/panels/elements/ElementsPanel.ts +4 -4
- package/front_end/panels/elements/ElementsTreeElement.ts +7 -2
- package/front_end/panels/elements/ElementsTreeOutline.ts +14 -26
- package/front_end/panels/elements/elementsTreeOutline.css +4 -4
- package/front_end/panels/lighthouse/LighthouseController.ts +1 -1
- package/front_end/panels/mobile_throttling/NetworkPanelIndicator.ts +1 -1
- package/front_end/panels/mobile_throttling/ThrottlingManager.ts +1 -1
- package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +1 -1
- package/front_end/panels/recorder/StepView.ts +19 -4
- package/front_end/panels/recorder/TimelineSection.ts +1 -1
- package/front_end/panels/settings/BackendLinkingSettingsTab.ts +2 -1
- package/front_end/panels/settings/EditFileSystemView.ts +1 -1
- package/front_end/panels/sources/CallStackSidebarPane.ts +1 -1
- package/front_end/panels/sources/DebuggerPlugin.ts +1 -1
- package/front_end/panels/timeline/components/DetailsView.ts +3 -3
- package/front_end/panels/timeline/components/OriginMap.ts +1 -1
- package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +2 -3
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/components/buttons/Button.ts +19 -1
- package/front_end/ui/legacy/ContextMenu.ts +16 -1
- package/front_end/ui/legacy/PlusButton.ts +5 -6
- package/front_end/ui/legacy/Treeoutline.ts +2 -0
- package/front_end/ui/legacy/Widget.ts +33 -0
- package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +3 -0
- package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +14 -4
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +22 -25
- package/front_end/ui/visual_logging/KnownContextValues.ts +3 -0
- package/package.json +1 -1
- package/.agents/skills/devtools-ci/SKILL.md +0 -65
- package/.agents/skills/evaluate-ai-css-completion/SKILL.md +0 -143
- package/.agents/skills/evaluate-ai-css-completion/scripts/evaluate.js +0 -104
- package/.agents/skills/fixing-skipped-tests/SKILL.md +0 -32
- package/.agents/skills/gerrit-cli/SKILL.md +0 -74
- package/.agents/skills/gerrit-cli/references/commands.md +0 -169
- package/.agents/skills/gerrit-cli/references/workflows.md +0 -63
- package/.agents/skills/gerrit-cli/scripts/import_upstream.py +0 -85
- package/front_end/models/issues_manager/descriptions/cookieExcludeBlockedWithinRelatedWebsiteSet.md +0 -4
|
@@ -1454,3 +1454,36 @@ Node.prototype.removeChildren = function(): void {
|
|
|
1454
1454
|
}
|
|
1455
1455
|
return originalRemoveChildren.call(this);
|
|
1456
1456
|
};
|
|
1457
|
+
|
|
1458
|
+
export interface WrapperWidgetParams {
|
|
1459
|
+
widget: Widget;
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
export class WrapperWidget extends Widget {
|
|
1463
|
+
#widget: Widget|null = null;
|
|
1464
|
+
constructor(element: HTMLElement, _deps: never[], params?: WrapperWidgetParams) {
|
|
1465
|
+
super(element);
|
|
1466
|
+
this.element.style.setProperty('display', 'contents');
|
|
1467
|
+
if (params?.widget) {
|
|
1468
|
+
this.widget = params.widget;
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
set widget(widget: Widget|null) {
|
|
1473
|
+
if (this.#widget === widget) {
|
|
1474
|
+
return;
|
|
1475
|
+
}
|
|
1476
|
+
if (this.#widget) {
|
|
1477
|
+
this.#widget.detach();
|
|
1478
|
+
}
|
|
1479
|
+
this.#widget = widget;
|
|
1480
|
+
if (this.#widget) {
|
|
1481
|
+
this.#widget.show(this.element, undefined, /* suppressOrphanWidgetError */ true);
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
override focus(): void {
|
|
1485
|
+
if (this.#widget) {
|
|
1486
|
+
this.#widget.focus();
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
@@ -54,6 +54,7 @@ export interface ViewInput {
|
|
|
54
54
|
data: CookieData[];
|
|
55
55
|
selectedKey?: string;
|
|
56
56
|
editable?: boolean;
|
|
57
|
+
deletable?: boolean;
|
|
57
58
|
renderInline?: boolean;
|
|
58
59
|
portBindingEnabled?: boolean;
|
|
59
60
|
schemeBindingEnabled?: boolean;
|
|
@@ -233,6 +234,7 @@ export class CookiesTable extends UI.Widget.VBox {
|
|
|
233
234
|
id="cookies-table"
|
|
234
235
|
striped
|
|
235
236
|
?inline=${input.renderInline}
|
|
237
|
+
?deletable=${input.deletable}
|
|
236
238
|
@create=${(e: CustomEvent<CookieData>) => input.onCreate(e.detail)}
|
|
237
239
|
@refresh=${input.onRefresh}
|
|
238
240
|
@deselect=${() => input.onSelect(undefined)}
|
|
@@ -448,6 +450,7 @@ export class CookiesTable extends UI.Widget.VBox {
|
|
|
448
450
|
data: this.data,
|
|
449
451
|
selectedKey: this.selectedKey,
|
|
450
452
|
editable: this.#editable,
|
|
453
|
+
deletable: Boolean(this.#deleteCallback),
|
|
451
454
|
renderInline: this.renderInline,
|
|
452
455
|
schemeBindingEnabled: this.schemeBindingEnabled,
|
|
453
456
|
portBindingEnabled: this.portBindingEnabled,
|
|
@@ -48,6 +48,8 @@ const DUMMY_COLUMN_ID = 'dummy'; // SortableDataGrid.create requires at least o
|
|
|
48
48
|
* visible rows are layed out and sorting is provided out of the box.
|
|
49
49
|
*
|
|
50
50
|
* @property filters Set of text filters to be applied to the data grid.
|
|
51
|
+
* @attribute deletable If true, rows can be deleted through the context menu or the Delete
|
|
52
|
+
* key, which dispatches a `delete` event on the corresponding <tr> element.
|
|
51
53
|
* @attribute inline If true, the data grid will render inline instead of taking a full container height.
|
|
52
54
|
* @attribute resize Column resize method, one of 'nearest' (default), 'first' or 'last'.
|
|
53
55
|
* @attribute striped If true, the data grid will have striped rows.
|
|
@@ -58,7 +60,7 @@ type DataGridElementNode = SortableNode|DynamicHeightNode;
|
|
|
58
60
|
const elementToNode = new WeakMap<Element, DataGridElementNode>();
|
|
59
61
|
|
|
60
62
|
export class DataGridElement extends UI.UIUtils.HTMLElementWithLightDOMTemplate {
|
|
61
|
-
static readonly observedAttributes: string[] = ['striped', 'name', 'inline', 'resize', 'highlight'];
|
|
63
|
+
static readonly observedAttributes: string[] = ['striped', 'name', 'inline', 'resize', 'highlight', 'deletable'];
|
|
62
64
|
|
|
63
65
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
64
66
|
#dataGrid!: DataGridImpl<any>;
|
|
@@ -220,6 +222,9 @@ export class DataGridElement extends UI.UIUtils.HTMLElementWithLightDOMTemplate
|
|
|
220
222
|
this.#revealHighlightedNode(Number(newValue));
|
|
221
223
|
});
|
|
222
224
|
break;
|
|
225
|
+
case 'deletable':
|
|
226
|
+
this.#dataGrid.deleteCallback = this.deletable ? this.#deleteCallback.bind(this) : undefined;
|
|
227
|
+
break;
|
|
223
228
|
}
|
|
224
229
|
}
|
|
225
230
|
|
|
@@ -231,6 +236,14 @@ export class DataGridElement extends UI.UIUtils.HTMLElementWithLightDOMTemplate
|
|
|
231
236
|
return hasBooleanAttribute(this, 'striped');
|
|
232
237
|
}
|
|
233
238
|
|
|
239
|
+
set deletable(deletable: boolean) {
|
|
240
|
+
this.toggleAttribute('deletable', deletable);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
get deletable(): boolean {
|
|
244
|
+
return hasBooleanAttribute(this, 'deletable');
|
|
245
|
+
}
|
|
246
|
+
|
|
234
247
|
set inline(striped: boolean) {
|
|
235
248
|
this.toggleAttribute('inline', striped);
|
|
236
249
|
}
|
|
@@ -584,9 +597,6 @@ export class DataGridElement extends UI.UIUtils.HTMLElementWithLightDOMTemplate
|
|
|
584
597
|
if (args[0] === 'refresh') {
|
|
585
598
|
this.#dataGrid.refreshCallback = this.#refreshCallback.bind(this);
|
|
586
599
|
}
|
|
587
|
-
if (args[0] === 'delete') {
|
|
588
|
-
this.#dataGrid.deleteCallback = this.#deleteCallback.bind(this);
|
|
589
|
-
}
|
|
590
600
|
}
|
|
591
601
|
|
|
592
602
|
#refreshCallback(): void {
|
|
@@ -388,6 +388,10 @@ export class ObjectTreeExpansionTracker {
|
|
|
388
388
|
}
|
|
389
389
|
}
|
|
390
390
|
|
|
391
|
+
const ARRAY_LOAD_THRESHOLD = 100;
|
|
392
|
+
const ARRAY_BUCKET_THRESHOLD = 100;
|
|
393
|
+
const ARRAY_SPARSE_ITERATION_THRESHOLD = 250000;
|
|
394
|
+
|
|
391
395
|
export abstract class ObjectTreeNodeBase extends Common.ObjectWrapper.ObjectWrapper<ObjectTreeNodeBase.EventTypes> {
|
|
392
396
|
#children?: NodeChildren;
|
|
393
397
|
protected readonly options: ObjectTreeOptions;
|
|
@@ -715,7 +719,7 @@ class ArrayGroupTreeNode extends ObjectTreeNodeBase {
|
|
|
715
719
|
}
|
|
716
720
|
|
|
717
721
|
override async populateChildrenIfNeededImpl(): Promise<NodeChildren> {
|
|
718
|
-
if (this.#range.count >
|
|
722
|
+
if (this.#range.count > ARRAY_BUCKET_THRESHOLD) {
|
|
719
723
|
const ranges = await arrayRangeGroups(this.object, this.#range.fromIndex, this.#range.toIndex);
|
|
720
724
|
const arrayRanges = ranges?.ranges.map(
|
|
721
725
|
([fromIndex, toIndex, count]) => new ArrayGroupTreeNode(this.object, {fromIndex, toIndex, count}, this, {
|
|
@@ -729,7 +733,7 @@ class ArrayGroupTreeNode extends ObjectTreeNodeBase {
|
|
|
729
733
|
const result = await this.#object.callFunction(buildArrayFragment, [
|
|
730
734
|
{value: this.#range.fromIndex},
|
|
731
735
|
{value: this.#range.toIndex},
|
|
732
|
-
{value:
|
|
736
|
+
{value: ARRAY_SPARSE_ITERATION_THRESHOLD},
|
|
733
737
|
]);
|
|
734
738
|
if (!result.object || result.wasThrown) {
|
|
735
739
|
return {};
|
|
@@ -1240,9 +1244,6 @@ export class ObjectPropertiesSectionWidget extends UI.Widget.Widget {
|
|
|
1240
1244
|
};
|
|
1241
1245
|
}
|
|
1242
1246
|
|
|
1243
|
-
/** @constant */
|
|
1244
|
-
const ARRAY_LOAD_THRESHOLD = 100;
|
|
1245
|
-
|
|
1246
1247
|
const maxRenderableStringLength = 10000;
|
|
1247
1248
|
|
|
1248
1249
|
export const enum ObjectPropertiesMode {
|
|
@@ -1289,7 +1290,7 @@ export function populateObjectTreeContextMenu(
|
|
|
1289
1290
|
{checked: object.includeNullOrUndefinedValues, jslogContext: 'show-all'});
|
|
1290
1291
|
}
|
|
1291
1292
|
|
|
1292
|
-
|
|
1293
|
+
interface ObjectTreeViewInput {
|
|
1293
1294
|
renderAsSubtree: boolean;
|
|
1294
1295
|
objectTree?: ObjectTree;
|
|
1295
1296
|
linkifier?: Components.Linkifier.Linkifier;
|
|
@@ -1298,8 +1299,8 @@ export interface ObjectTreeViewInput {
|
|
|
1298
1299
|
skipGettersAndSetters: boolean;
|
|
1299
1300
|
onExpand: (expanded: boolean) => void;
|
|
1300
1301
|
}
|
|
1301
|
-
|
|
1302
|
-
|
|
1302
|
+
type ObjectTreeView = (input: ObjectTreeViewInput, output: object, target: HTMLElement) => void;
|
|
1303
|
+
const OBJECT_TREE_DEFAULT_VIEW: ObjectTreeView = (input, output, target) => {
|
|
1303
1304
|
const objectTree = input.objectTree;
|
|
1304
1305
|
if (!objectTree) {
|
|
1305
1306
|
render(nothing, target);
|
|
@@ -1454,7 +1455,7 @@ export function renderObjectTree(
|
|
|
1454
1455
|
widgetRef(ObjectTreeWidget, () => {})}></ul>`;
|
|
1455
1456
|
}
|
|
1456
1457
|
|
|
1457
|
-
|
|
1458
|
+
interface ObjectPropertiesSectionViewInput {
|
|
1458
1459
|
objectTree: ObjectTree;
|
|
1459
1460
|
title?: Element|TemplateResult;
|
|
1460
1461
|
linkifier?: Components.Linkifier.Linkifier;
|
|
@@ -1464,8 +1465,8 @@ export interface ObjectPropertiesSectionViewInput {
|
|
|
1464
1465
|
onExpand: (expanded: boolean) => void;
|
|
1465
1466
|
}
|
|
1466
1467
|
|
|
1467
|
-
|
|
1468
|
-
|
|
1468
|
+
type ObjectPropertiesSectionView = (input: ObjectPropertiesSectionViewInput, output: object, target: HTMLElement) =>
|
|
1469
|
+
void;
|
|
1469
1470
|
|
|
1470
1471
|
export const OBJECT_PROPERTIES_SECTION_DEFAULT_VIEW: ObjectPropertiesSectionView = (input, _output, target) => {
|
|
1471
1472
|
|
|
@@ -1674,9 +1675,9 @@ export interface ObjectPropertyViewInput {
|
|
|
1674
1675
|
node: ObjectTreeNode;
|
|
1675
1676
|
search?: UI.TreeOutline.TreeSearch<ObjectTreeNodeBase>;
|
|
1676
1677
|
}
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1678
|
+
type ObjectPropertyViewOutput = undefined;
|
|
1679
|
+
type ObjectPropertyView = (input: ObjectPropertyViewInput, output: ObjectPropertyViewOutput, target: HTMLElement) =>
|
|
1680
|
+
void;
|
|
1680
1681
|
export const OBJECT_PROPERTY_DEFAULT_VIEW: ObjectPropertyView = (input, _output, target) => {
|
|
1681
1682
|
const {property} = input.node;
|
|
1682
1683
|
const isInternalEntries = property.synthetic && input.node.name === '[[Entries]]';
|
|
@@ -1897,7 +1898,7 @@ export class ObjectPropertyWidget extends UI.Widget.Widget {
|
|
|
1897
1898
|
}
|
|
1898
1899
|
}
|
|
1899
1900
|
|
|
1900
|
-
|
|
1901
|
+
class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
1901
1902
|
property: ObjectTreeNode;
|
|
1902
1903
|
override toggleOnClick: boolean;
|
|
1903
1904
|
private linkifier: Components.Linkifier.Linkifier|undefined;
|
|
@@ -2232,8 +2233,8 @@ async function arrayRangeGroups(object: SDK.RemoteObject.RemoteObject, fromIndex
|
|
|
2232
2233
|
return await object.callFunctionJSON(packArrayRanges, [
|
|
2233
2234
|
{value: fromIndex},
|
|
2234
2235
|
{value: toIndex},
|
|
2235
|
-
{value:
|
|
2236
|
-
{value:
|
|
2236
|
+
{value: ARRAY_BUCKET_THRESHOLD},
|
|
2237
|
+
{value: ARRAY_SPARSE_ITERATION_THRESHOLD},
|
|
2237
2238
|
]);
|
|
2238
2239
|
|
|
2239
2240
|
/**
|
|
@@ -2361,7 +2362,7 @@ function buildArrayFragment(
|
|
|
2361
2362
|
return result;
|
|
2362
2363
|
}
|
|
2363
2364
|
|
|
2364
|
-
|
|
2365
|
+
class ArrayGroupingTreeElement extends UI.TreeOutline.TreeElement {
|
|
2365
2366
|
override toggleOnClick: boolean;
|
|
2366
2367
|
private readonly linkifier: Components.Linkifier.Linkifier|undefined;
|
|
2367
2368
|
readonly #child: ArrayGroupTreeNode;
|
|
@@ -2442,13 +2443,9 @@ export class ArrayGroupingTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
2442
2443
|
override onattach(): void {
|
|
2443
2444
|
this.listItemElement.classList.add('object-properties-section-name');
|
|
2444
2445
|
}
|
|
2445
|
-
|
|
2446
|
-
// These should be module constants but they are modified by layout tests.
|
|
2447
|
-
static bucketThreshold = 100;
|
|
2448
|
-
static sparseIterationThreshold = 250000;
|
|
2449
2446
|
}
|
|
2450
2447
|
|
|
2451
|
-
|
|
2448
|
+
interface ExpandableTextViewInput {
|
|
2452
2449
|
copyText: () => void;
|
|
2453
2450
|
expandText: () => void;
|
|
2454
2451
|
expanded: boolean;
|
|
@@ -2456,8 +2453,8 @@ export interface ExpandableTextViewInput {
|
|
|
2456
2453
|
byteCount: number;
|
|
2457
2454
|
text: string;
|
|
2458
2455
|
}
|
|
2459
|
-
|
|
2460
|
-
|
|
2456
|
+
type ExpandableTextView = (input: ExpandableTextViewInput, output: object, target: HTMLElement) => void;
|
|
2457
|
+
const EXPANDABLE_TEXT_DEFAULT_VIEW: ExpandableTextView = (input, output, target) => {
|
|
2461
2458
|
const totalBytesText = i18n.ByteUtilities.bytesToString(input.byteCount);
|
|
2462
2459
|
const canExpand = input.text.length < ExpandableTextPropertyValue.MAX_DISPLAYABLE_TEXT_LENGTH;
|
|
2463
2460
|
const onContextMenu = (e: Event): void => {
|
|
@@ -283,8 +283,11 @@ export const knownContextValues: Set<string> = new Set([
|
|
|
283
283
|
'accept',
|
|
284
284
|
'accept-execute-code',
|
|
285
285
|
'access-control-allow-origin',
|
|
286
|
+
'accessibility-announcements.filter-by-type',
|
|
286
287
|
'accessibility-default',
|
|
287
288
|
'accessibility-tree',
|
|
289
|
+
'accessibility.clear-announcements',
|
|
290
|
+
'accessibility.toggle-recording',
|
|
288
291
|
'accessibility.view',
|
|
289
292
|
'accuracy',
|
|
290
293
|
'achromatopsia',
|
package/package.json
CHANGED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: devtools-ci
|
|
3
|
-
description: >-
|
|
4
|
-
Triage and analyze Chromium/DevTools LUCI build results and trybot failures,
|
|
5
|
-
including high-level builder status, compile errors, and detailed test
|
|
6
|
-
failures. Use this to inspect trybot buildbucket (bb) results for a patchset
|
|
7
|
-
overview or to query ResultDB directly for comprehensive, actionable information
|
|
8
|
-
about specific test regressions and infrastructure issues.
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
# LUCI Build Triage & Analysis
|
|
12
|
-
|
|
13
|
-
This skill provides access to specialized triage tools maintained within the
|
|
14
|
-
`depot_tools` repository. These tools are used to inspect Buildbucket results
|
|
15
|
-
and ResultDB test failures.
|
|
16
|
-
|
|
17
|
-
## Environment & Auth Discovery
|
|
18
|
-
|
|
19
|
-
- **Environment**: Always execute these scripts using **`vpython3`** instead
|
|
20
|
-
of `python3` to ensure all hermetic dependencies (like `httplib2`) are
|
|
21
|
-
satisfied.
|
|
22
|
-
- **Authentication**: Use `bb auth-info` to proactively check if you are
|
|
23
|
-
logged into Buildbucket. If not, inform the user they must run `bb auth-login`.
|
|
24
|
-
|
|
25
|
-
## Locating the Tools
|
|
26
|
-
|
|
27
|
-
The triage scripts and their detailed documentation are located relative to
|
|
28
|
-
the `depot_tools` installation:
|
|
29
|
-
|
|
30
|
-
1. **Locate Depot Tools**: Run `which gerrit_client.py` to find your local
|
|
31
|
-
`depot_tools` root.
|
|
32
|
-
2. **Navigation**:
|
|
33
|
-
- **Buildbucket (`bb_wrapper.py`)**: Found in `<DEPOT_TOOLS_ROOT>/agents/skills/buildbucket/`
|
|
34
|
-
- *Strengths*: High-level Build info (is it failing? what steps failed?),
|
|
35
|
-
compile errors, and infra issues.
|
|
36
|
-
- **Test Results (`luci_triage.py`)**: Found in `<DEPOT_TOOLS_ROOT>/agents/skills/luci-test-results/`
|
|
37
|
-
- *Strengths*: Detailed Test info (specific test case failures in
|
|
38
|
-
ResultDB).
|
|
39
|
-
|
|
40
|
-
## Troubleshooting
|
|
41
|
-
|
|
42
|
-
- **"No Artifacts Found"**: This usually occurs if:
|
|
43
|
-
1. The build failed so early (e.g., bot setup) that no artifacts were produced.
|
|
44
|
-
2. The build is too old and logs have been purged.
|
|
45
|
-
3. There is an authentication issue.
|
|
46
|
-
- **Fallback**: Try `bb log <build_id> <step_name>` to see the raw output
|
|
47
|
-
for the failed step.
|
|
48
|
-
|
|
49
|
-
## Available Skills in Depot Tools
|
|
50
|
-
|
|
51
|
-
Once you have located the `depot_tools` directory, read the following files
|
|
52
|
-
to understand how to use each tool:
|
|
53
|
-
|
|
54
|
-
- **`buildbucket`**: Used for high-level builder status and compile failures.
|
|
55
|
-
- Read: `<DEPOT_TOOLS_ROOT>/agents/skills/buildbucket/SKILL.md`
|
|
56
|
-
- **`luci-test-results`**: Used for detailed ResultDB test failure analysis.
|
|
57
|
-
- Read: `<DEPOT_TOOLS_ROOT>/agents/skills/luci-test-results/SKILL.md`
|
|
58
|
-
|
|
59
|
-
## Usage at Runtime
|
|
60
|
-
|
|
61
|
-
When you need to triage a build:
|
|
62
|
-
1. Locate `depot_tools` as described above.
|
|
63
|
-
2. Read the relevant `SKILL.md` file from `depot_tools`.
|
|
64
|
-
3. Follow the instructions in that file to execute the Python scripts (e.g.,
|
|
65
|
-
`bb_wrapper.py` or `luci_triage.py`) using their absolute paths.
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: evaluate-ai-css-completion
|
|
3
|
-
description: Expose a temporary evaluation hook in DevTools and run a Puppeteer script to validate CSS code completion trigger rates.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Evaluate CSS Completion Skill
|
|
7
|
-
|
|
8
|
-
This skill allows you to temporarily expose an evaluation hook in DevTools to measure CSS code completion trigger rates using a Puppeteer script.
|
|
9
|
-
|
|
10
|
-
> [!WARNING]
|
|
11
|
-
> **NEVER commit the `devtools_app.ts` patch.** It is only for local evaluation. Always revert it before uploading your CL.
|
|
12
|
-
|
|
13
|
-
## Step 1: Apply the Temporary Patch
|
|
14
|
-
|
|
15
|
-
Modify `front_end/entrypoints/devtools_app/devtools_app.ts` to expose the global `testCssCompletion` hook.
|
|
16
|
-
|
|
17
|
-
Add the following code at the end of `front_end/entrypoints/devtools_app/devtools_app.ts`:
|
|
18
|
-
|
|
19
|
-
```typescript
|
|
20
|
-
// --- TEMPORARY EVALUATION HOOK ---
|
|
21
|
-
// TEMPORARY PATCH - REMOVE BEFORE COMMIT
|
|
22
|
-
|
|
23
|
-
import * as Host from '../../core/host/host.js';
|
|
24
|
-
import * as AiCodeCompletion from '../../models/ai_code_completion/ai_code_completion.js';
|
|
25
|
-
|
|
26
|
-
(self as any).testCss = {
|
|
27
|
-
getCases() {
|
|
28
|
-
return [
|
|
29
|
-
{
|
|
30
|
-
name: 'Generic CSS Test Case',
|
|
31
|
-
url: null,
|
|
32
|
-
prefix: 'h1 { font-s',
|
|
33
|
-
suffix: ' }',
|
|
34
|
-
},
|
|
35
|
-
// Add more test cases here
|
|
36
|
-
];
|
|
37
|
-
},
|
|
38
|
-
|
|
39
|
-
async evaluate(uiSourceCodeUrl: string | null, prefix: string, suffix: string, additionalFiles?: any[]) {
|
|
40
|
-
const aidaClient = new Host.AidaClient.AidaClient();
|
|
41
|
-
const completion = new AiCodeCompletion.AiCodeCompletion.AiCodeCompletion(
|
|
42
|
-
{aidaClient},
|
|
43
|
-
AiCodeCompletion.AiCodeCompletion.ContextFlavor.STYLES
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
const formattedAdditionalFiles = additionalFiles?.map(f => ({
|
|
47
|
-
path: f.path || f.name,
|
|
48
|
-
content: f.content || f.text,
|
|
49
|
-
included_reason: f.included_reason ?? Host.AidaClient.Reason.RELATED_FILE,
|
|
50
|
-
}));
|
|
51
|
-
|
|
52
|
-
const result = await completion.completeCode(
|
|
53
|
-
prefix,
|
|
54
|
-
suffix,
|
|
55
|
-
prefix.length,
|
|
56
|
-
Host.AidaClient.AidaInferenceLanguage.CSS,
|
|
57
|
-
formattedAdditionalFiles
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
return {
|
|
61
|
-
hasSuggestion: result.response !== null && result.response.generatedSamples.length > 0,
|
|
62
|
-
suggestions: result.response?.generatedSamples.map(s => s.generationString) ?? [],
|
|
63
|
-
injectedFiles: formattedAdditionalFiles?.map(f => f.path) ?? [],
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
// ----------------------------------
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
## Step 2: Launch Chrome with Local DevTools
|
|
71
|
-
|
|
72
|
-
Use the `npm start` script to build DevTools, launch Chrome Canary with remote debugging, and disable watch mode (so we build manually instead).
|
|
73
|
-
|
|
74
|
-
You must specify a persistent user data directory so you can log in once and reuse the session:
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
npm start -- --no-watch --browser=canary --remote-debugging-port=9222 --user-data-dir=/tmp/devtools-ai-evaluate-css-completion
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
> [!IMPORTANT]
|
|
81
|
-
> **Instructions for the Agent:**
|
|
82
|
-
> After launching Chrome, you MUST print the following checklist to the user and wait for their explicit confirmation before running the evaluation script:
|
|
83
|
-
> 1. Sign in to Chrome with your corporate account in the new window.
|
|
84
|
-
> 2. Open DevTools, go to **Settings** (gear icon) > **AI Innovations**, and ensure **Code Completions** is enabled.
|
|
85
|
-
> 3. Focus the DevTools window and press `Cmd + Option + I` (on macOS) or `Ctrl + Shift + I` (on Windows/Linux) to open DevTools-on-DevTools (inspecting DevTools itself). Go to the Network tab of the second DevTools instance and check the **Disable cache** checkbox. This ensures your local builds are loaded instead of cached versions when reloaded.
|
|
86
|
-
> 4. Ask the user to reply when they are ready.
|
|
87
|
-
|
|
88
|
-
## Step 3: Configure Test Cases
|
|
89
|
-
|
|
90
|
-
Before running the evaluation, configure your test cases directly in `front_end/entrypoints/devtools_app/devtools_app.ts` inside the `getCases()` method of the patch you applied in Step 1.
|
|
91
|
-
|
|
92
|
-
After modifying the test cases, manually run a build to compile the changes:
|
|
93
|
-
```bash
|
|
94
|
-
autoninja -C out/Default
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
For example, to test spacing sensitivity, update the returned array:
|
|
98
|
-
```typescript
|
|
99
|
-
getCases() {
|
|
100
|
-
return [
|
|
101
|
-
{
|
|
102
|
-
name: 'With CSS Context',
|
|
103
|
-
url: null,
|
|
104
|
-
prefix: 'h1 { font-s',
|
|
105
|
-
suffix: ' }',
|
|
106
|
-
additionalFiles: [
|
|
107
|
-
{
|
|
108
|
-
path: 'other.css',
|
|
109
|
-
content: 'body { color: red; }',
|
|
110
|
-
}
|
|
111
|
-
]
|
|
112
|
-
}
|
|
113
|
-
];
|
|
114
|
-
}
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
## Step 4: Run the Evaluation Script
|
|
118
|
-
|
|
119
|
-
Run the Puppeteer script to execute the evaluation:
|
|
120
|
-
|
|
121
|
-
```bash
|
|
122
|
-
node .agents/skills/evaluate-ai-css-completion/scripts/evaluate.js
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
The script will connect to the DevTools instance, trigger completions, and output the results.
|
|
126
|
-
|
|
127
|
-
### Debugging and Diagnostics
|
|
128
|
-
|
|
129
|
-
If you get 0% trigger rate or unexpected errors, check the following:
|
|
130
|
-
|
|
131
|
-
1. **Browser Logs:** The evaluation script forwards browser console logs (prefixed with `BROWSER LOG:`). Look for these in your terminal.
|
|
132
|
-
2. **Host Config:** The script prints the DevTools `Host Config` at the start. Verify that `"devToolsAiCodeCompletionStyles": { "enabled": true }` is present.
|
|
133
|
-
3. **GCA/AIDA Logs:** The script automatically enables verbose AIDA logging. Look for `GCA request succeeded:` in the logs:
|
|
134
|
-
* If the response has `"usageMetadata": { "candidatesTokenCount": X }` (where X > 0) but the `candidates` array is missing or empty, the backend generated tokens but they were filtered out (e.g., due to safety classifiers or recitation blocks).
|
|
135
|
-
4. **Context Requirement:** The CSS model is sensitive to context. A minimal prompt like `h1 { font-s` might not trigger AIDA. Ensure your test cases have enough context in the `prefix` (e.g., several preceding CSS rules) or pass them via `additionalFiles` to simulate a larger stylesheet.
|
|
136
|
-
|
|
137
|
-
## Step 5: Revert the Patch
|
|
138
|
-
|
|
139
|
-
Once the evaluation is complete and you have recorded the results, revert the patch in `devtools_app.ts`:
|
|
140
|
-
|
|
141
|
-
```bash
|
|
142
|
-
git checkout front_end/entrypoints/devtools_app/devtools_app.ts
|
|
143
|
-
```
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
// Copyright 2026 The Chromium Authors
|
|
2
|
-
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
-
// found in the LICENSE file.
|
|
4
|
-
|
|
5
|
-
/* eslint-disable no-console */
|
|
6
|
-
|
|
7
|
-
const puppeteer = require('puppeteer-core');
|
|
8
|
-
|
|
9
|
-
async function runEvaluation() {
|
|
10
|
-
console.log('Connecting to Chrome...');
|
|
11
|
-
const browser = await puppeteer.connect({browserURL: 'http://127.0.0.1:9222', defaultViewport: null});
|
|
12
|
-
|
|
13
|
-
try {
|
|
14
|
-
console.log('Opening test page (example.com)...');
|
|
15
|
-
const testPage = await browser.newPage();
|
|
16
|
-
await testPage.goto('https://example.com');
|
|
17
|
-
|
|
18
|
-
console.log('Waiting for DevTools target...');
|
|
19
|
-
const devtoolsTarget = await browser.waitForTarget(t => {
|
|
20
|
-
return t.url().startsWith('devtools://') || t.url().includes('inspector.html');
|
|
21
|
-
}, {timeout: 10000});
|
|
22
|
-
|
|
23
|
-
console.log('Connecting to DevTools page...');
|
|
24
|
-
const devtoolsPage = await devtoolsTarget.page();
|
|
25
|
-
if (!devtoolsPage) {
|
|
26
|
-
throw new Error('Could not get DevTools page object. Make sure DevTools is undocked or opened in a tab.');
|
|
27
|
-
}
|
|
28
|
-
console.log('DevTools URL:', devtoolsPage.url());
|
|
29
|
-
|
|
30
|
-
devtoolsPage.on('console', msg => console.log('BROWSER LOG:', msg.text()));
|
|
31
|
-
|
|
32
|
-
console.log('Reloading DevTools to ensure patch is loaded...');
|
|
33
|
-
try {
|
|
34
|
-
await devtoolsPage.setCacheEnabled(false);
|
|
35
|
-
await devtoolsPage.reload({waitUntil: 'domcontentloaded', timeout: 10000});
|
|
36
|
-
} catch (e) {
|
|
37
|
-
console.log('Reload warning (proceeding anyway):', e.message);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
await devtoolsPage.evaluate(() => localStorage.setItem('debugAiCodeCompletionEnabled', 'true'));
|
|
41
|
-
await devtoolsPage.evaluate(() => localStorage.setItem('debugAiServicesEnabled', 'true'));
|
|
42
|
-
await devtoolsPage.evaluate(() => localStorage.setItem('debugAiAssistancePanelEnabled', 'true'));
|
|
43
|
-
await devtoolsPage.evaluate(() => localStorage.setItem('aiAssistanceStructuredLogEnabled', 'true'));
|
|
44
|
-
|
|
45
|
-
console.log('Waiting for DevTools to initialize and hook to be available...');
|
|
46
|
-
try {
|
|
47
|
-
await devtoolsPage.waitForFunction(() => typeof self.testCss?.getCases === 'function', {timeout: 15000});
|
|
48
|
-
} catch {
|
|
49
|
-
throw new Error('testCss.getCases hook not found. Did you apply the patch and build? Is this the local build?');
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
console.log('Fetching test cases from DevTools...');
|
|
53
|
-
const hostConfig = await devtoolsPage.evaluate(() => self.testCss.getHostConfig());
|
|
54
|
-
console.log('Host Config:', JSON.stringify(hostConfig, null, 2));
|
|
55
|
-
const testCases = await devtoolsPage.evaluate(() => self.testCss.getCases());
|
|
56
|
-
console.log(`Found ${testCases.length} test cases. Running each case 5 times.`);
|
|
57
|
-
|
|
58
|
-
let totalQueries = 0;
|
|
59
|
-
for (const tc of testCases) {
|
|
60
|
-
console.log(`\nRunning: ${tc.name}`);
|
|
61
|
-
let successCount = 0;
|
|
62
|
-
const suggestions = new Set();
|
|
63
|
-
|
|
64
|
-
for (let run = 1; run <= 5; run++) {
|
|
65
|
-
// Delay to avoid rate limiting
|
|
66
|
-
await new Promise(resolve => setTimeout(resolve, 1200));
|
|
67
|
-
try {
|
|
68
|
-
const result = await devtoolsPage.evaluate(async (url, prefix, suffix, additionalFiles) => {
|
|
69
|
-
return await self.testCss.evaluate(url, prefix, suffix, additionalFiles);
|
|
70
|
-
}, tc.url, tc.prefix, tc.suffix, tc.additionalFiles);
|
|
71
|
-
|
|
72
|
-
if (result.hasSuggestion) {
|
|
73
|
-
successCount++;
|
|
74
|
-
for (const s of result.suggestions) {
|
|
75
|
-
suggestions.add(s);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
} catch (e) {
|
|
79
|
-
console.error(` [Run ${run}] Failed:`, e.message);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
totalQueries++;
|
|
83
|
-
if (totalQueries % 20 === 0) {
|
|
84
|
-
console.log('[INFO] Pausing for 8 seconds to prevent rate limiting...');
|
|
85
|
-
await new Promise(resolve => setTimeout(resolve, 8000));
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
console.log(` Result: [Success Rate: ${successCount}/5]`);
|
|
90
|
-
if (suggestions.size > 0) {
|
|
91
|
-
console.log(' Unique Suggestions:', Array.from(suggestions));
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Cleanup tabs
|
|
96
|
-
await devtoolsPage.close();
|
|
97
|
-
await testPage.close();
|
|
98
|
-
} finally {
|
|
99
|
-
console.log('Disconnecting from Chrome...');
|
|
100
|
-
await browser.disconnect();
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
runEvaluation().catch(console.error);
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: fixing-skipped-tests
|
|
3
|
-
description: Use this skill when unskipping a test that was previously skipped.
|
|
4
|
-
---
|
|
5
|
-
# Fixing Skipped Tests
|
|
6
|
-
|
|
7
|
-
This skill outlines the workflow for fixing skipped tests in the DevTools codebase, typically given a Chromium bug link (e.g., `crbug.com/1234567`).
|
|
8
|
-
|
|
9
|
-
## Workflow
|
|
10
|
-
|
|
11
|
-
1. **Extract the Bug ID**
|
|
12
|
-
- The input is typically a bug link like `crbug.com/<bugid>`. Extract the `<bugid>` from the link.
|
|
13
|
-
|
|
14
|
-
2. **Create a Branch**
|
|
15
|
-
- Create a new branch named `fixed-<bugid>`.
|
|
16
|
-
- Ensure you use the instructions from the `devtools-version-control` skill to create and switch branches appropriately.
|
|
17
|
-
|
|
18
|
-
3. **Search for the Skipped Tests**
|
|
19
|
-
- Search the `test/TestExpectations` file for the `<bugid>` to find skipped tests.
|
|
20
|
-
- Tests are no longer skipped using `.skip` in the code, but rather by having a `[ Skip ]` expectation in `test/TestExpectations`.
|
|
21
|
-
|
|
22
|
-
4. **Iterative Fix Process**
|
|
23
|
-
- **Step 1:** Remove the `[ Skip ]` expectation for *one* of the tests associated with the bug in `test/TestExpectations` (or change it to `[ Pass Failure ]` if you are investigating flakiness).
|
|
24
|
-
- **Step 2:** Re-run the specific test using its exact test ID (e.g., `npm run test path/to/foo.test.ts:test_name`) using the guidelines from the `devtools-verification` skill. If you are dealing with flaky tests, you can use the `--repeat=x` flag (e.g. `npm run test -- --repeat=20 path/to/foo.test.ts:test_name`) to run the test multiple times to reproduce the flakiness. This flag works for both E2E and unit tests.
|
|
25
|
-
- **Step 3:** Analyze the test failure and make the necessary fixes to the code or the test itself.
|
|
26
|
-
- **Step 4:** Re-run the test to ensure the fix is correct.
|
|
27
|
-
- **Step 5:** Remove the `[crbug.com/<bugid>]` prefix from the test name string in the code if it is present.
|
|
28
|
-
- **Step 6:** Remove any comments directly above the test in the code that explain the reason why the test was skipped (e.g., `// TODO(crbug...): Flaky`).
|
|
29
|
-
- **Step 7:** Apply the fix to the remaining tests, un-skipping them one by one or in batches by modifying `test/TestExpectations`, and verifying until all are passing.
|
|
30
|
-
|
|
31
|
-
5. **Verify Full Build**
|
|
32
|
-
- Before finishing, run the full verification process (TypeScript checks, linters, full test run) as required by the repository best practices.
|