chrome-devtools-frontend 1.0.1642246 → 1.0.1642899
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/SECURITY.md +1 -0
- package/front_end/core/host/UserMetrics.ts +2 -1
- package/front_end/core/sdk/CSSMatchedStyles.ts +55 -26
- package/front_end/core/sdk/CSSRule.ts +1 -0
- package/front_end/core/sdk/DebuggerModel.ts +5 -0
- package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +4 -3
- package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +4 -3
- package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +11 -0
- package/front_end/models/ai_assistance/AiAgent2.ts +80 -16
- package/front_end/models/ai_assistance/AiConversation.ts +3 -2
- package/front_end/models/ai_assistance/README.md +8 -0
- package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +50 -39
- package/front_end/models/ai_assistance/agents/AiAgent.ts +17 -6
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +2 -2
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +195 -147
- package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +1 -26
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +24 -309
- package/front_end/models/ai_assistance/ai_assistance.ts +8 -0
- package/front_end/models/ai_assistance/contexts/DOMNodeContext.snapshot.txt +51 -0
- package/front_end/models/ai_assistance/contexts/DOMNodeContext.ts +200 -0
- package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +13 -12
- package/front_end/models/ai_assistance/skills/styling.md +36 -2
- package/front_end/models/ai_assistance/tools/GetStyles.ts +137 -0
- package/front_end/models/ai_assistance/tools/Tool.ts +55 -0
- package/front_end/models/ai_assistance/tools/ToolRegistry.ts +34 -0
- package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +4 -0
- package/front_end/models/javascript_metadata/NativeFunctions.js +16 -0
- package/front_end/models/lighthouse/LighthouseReporterTypes.ts +5 -0
- package/front_end/models/live-metrics/LiveMetrics.ts +24 -13
- package/front_end/models/stack_trace/DetailedErrorStackParser.ts +2 -2
- package/front_end/models/stack_trace/StackTrace.ts +4 -1
- package/front_end/models/stack_trace/StackTraceImpl.ts +9 -2
- package/front_end/models/stack_trace/StackTraceModel.ts +17 -4
- package/front_end/models/stack_trace/Trie.ts +1 -1
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +19 -15
- package/front_end/panels/ai_assistance/ai_assistance-meta.ts +16 -0
- package/front_end/panels/ai_assistance/components/ChatInput.ts +2 -2
- package/front_end/panels/application/DOMStorageItemsView.ts +4 -0
- package/front_end/panels/application/KeyValueStorageItemsView.ts +39 -7
- package/front_end/panels/common/ExtensionServer.ts +26 -15
- package/front_end/panels/console/SymbolizedErrorWidget.ts +96 -2
- package/front_end/panels/console/symbolizedErrorWidget.css +48 -0
- package/front_end/panels/elements/StandaloneStylesContainer.ts +1 -1
- package/front_end/panels/elements/StylePropertiesSection.ts +8 -0
- package/front_end/panels/elements/StylePropertyHighlighter.ts +4 -2
- package/front_end/panels/elements/StylePropertyTreeElement.ts +6 -5
- package/front_end/panels/elements/StylesContainer.ts +1 -1
- package/front_end/panels/elements/StylesSidebarPane.ts +4 -4
- package/front_end/panels/layer_viewer/PaintProfilerView.ts +106 -132
- package/front_end/panels/lighthouse/LighthousePanel.ts +4 -3
- package/front_end/panels/network/NetworkLogView.ts +3 -0
- package/front_end/panels/network/networkLogView.css +0 -15
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +36 -3
- package/front_end/ui/legacy/components/data_grid/dataGridAiButton.css +20 -0
- package/front_end/ui/legacy/components/utils/Linkifier.ts +19 -4
- package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
- package/front_end/ui/visual_logging/LoggingDriver.ts +13 -0
- package/package.json +1 -1
|
@@ -2,6 +2,8 @@
|
|
|
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 * as Common from '../../../core/common/common.js';
|
|
6
|
+
import type * as Platform from '../../../core/platform/platform.js';
|
|
5
7
|
import type * as SDK from '../../../core/sdk/sdk.js';
|
|
6
8
|
import * as Protocol from '../../../generated/protocol.js';
|
|
7
9
|
import * as Annotations from '../../annotations/annotations.js';
|
|
@@ -68,17 +70,16 @@ export class NetworkRequestFormatter {
|
|
|
68
70
|
return `${title}\n<binary data>`;
|
|
69
71
|
}
|
|
70
72
|
|
|
71
|
-
static formatInitiatorUrl(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return
|
|
79
|
-
} catch {
|
|
80
|
-
return '<redacted cross-origin initiator URL>';
|
|
73
|
+
static formatInitiatorUrl(
|
|
74
|
+
initiatorUrl: Platform.DevToolsPath.UrlString,
|
|
75
|
+
allowedOrigin: Platform.DevToolsPath.UrlString,
|
|
76
|
+
): string {
|
|
77
|
+
// We extract the origin, and if it is invalid/empty we default to redacting.
|
|
78
|
+
const initiatorOrigin = Common.ParsedURL.ParsedURL.extractOrigin(initiatorUrl);
|
|
79
|
+
if (initiatorOrigin && initiatorOrigin === allowedOrigin) {
|
|
80
|
+
return initiatorUrl;
|
|
81
81
|
}
|
|
82
|
+
return '<redacted cross-origin initiator URL>';
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
static formatStatus(status: {
|
|
@@ -196,7 +197,7 @@ Request initiator chain:\n${this.formatRequestInitiatorChain()}`;
|
|
|
196
197
|
* the request's origin.
|
|
197
198
|
*/
|
|
198
199
|
formatRequestInitiatorChain(): string {
|
|
199
|
-
const allowedOrigin =
|
|
200
|
+
const allowedOrigin = Common.ParsedURL.ParsedURL.extractOrigin(this.#request.url());
|
|
200
201
|
let initiatorChain = '';
|
|
201
202
|
let lineStart = '- URL: ';
|
|
202
203
|
const graph = Logs.NetworkLog.NetworkLog.instance().initiatorGraphForRequest(this.#request);
|
|
@@ -268,7 +269,7 @@ Request initiator chain:\n${this.formatRequestInitiatorChain()}`;
|
|
|
268
269
|
parentRequest: SDK.NetworkRequest.NetworkRequest,
|
|
269
270
|
initiatorChain: string,
|
|
270
271
|
lineStart: string,
|
|
271
|
-
allowedOrigin:
|
|
272
|
+
allowedOrigin: Platform.DevToolsPath.UrlString,
|
|
272
273
|
): string {
|
|
273
274
|
const visited = new Set<SDK.NetworkRequest.NetworkRequest>();
|
|
274
275
|
|
|
@@ -1,6 +1,40 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: styling
|
|
3
3
|
description: Helping with CSS and styling
|
|
4
|
-
allowed-tools:
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- getStyles
|
|
5
6
|
---
|
|
6
|
-
You are a CSS
|
|
7
|
+
You are a CSS/DOM/HTML debugging assistant.
|
|
8
|
+
You always suggest considering the best web development practices and the newest platform features such as view transitions.
|
|
9
|
+
The user selected a DOM element in the browser's DevTools and sends a query about the page or the selected DOM element.
|
|
10
|
+
First, examine the provided context, then use the getStyles function to gather additional context and resolve the user request.
|
|
11
|
+
|
|
12
|
+
# Considerations
|
|
13
|
+
|
|
14
|
+
* Meticulously investigate all potential causes for the observed behavior before moving on. Gather comprehensive information about the element's parent, siblings, children, and any overlapping elements, paying close attention to properties that are likely relevant to the query.
|
|
15
|
+
* Be aware of the different node types (element, text, comment, document fragment, etc.) and their properties. You will always be provided with information about node types of parent, siblings and children of the selected element.
|
|
16
|
+
* Avoid making assumptions without sufficient evidence, and always seek further clarification if needed.
|
|
17
|
+
* Always explore multiple possible explanations for the observed behavior before settling on a conclusion.
|
|
18
|
+
* When presenting solutions, clearly distinguish between the primary cause and contributing factors.
|
|
19
|
+
* Please answer only if you are sure about the answer. Otherwise, explain why you're not able to answer.
|
|
20
|
+
* When answering, always consider MULTIPLE possible solutions.
|
|
21
|
+
* When answering, remember to consider CSS concepts such as the CSS cascade, explicit and implicit stacking contexts and various CSS layout types.
|
|
22
|
+
* Use the getStyles function available to you to investigate and fulfill the user request.
|
|
23
|
+
* ALWAYS OUTPUT a list of follow-up queries at the end of your text response. The format is SUGGESTIONS: ["suggestion1", "suggestion2", "suggestion3"]. Make sure that the array and the `SUGGESTIONS: ` text is in the same line.
|
|
24
|
+
* Use the precision of Strunk & White, the brevity of Hemingway, and the simple clarity of Vonnegut. Don't add repeated information, and keep the whole answer short.
|
|
25
|
+
* **CRITICAL** When answering questions about positioning or layout, ALWAYS inspect `position`, `display` and all other related properties. You MUST provide a specific list of CSS property names when calling getStyles. Do not use generic values like "all" or "*".
|
|
26
|
+
* **CRITICAL** You are a CSS/DOM/HTML debugging assistant. NEVER provide answers to questions of unrelated topics such as legal advice, financial advice, personal opinions, medical advice, religion, race, politics, sexuality, gender, or any other non web-development topics. Answer "Sorry, I can't answer that. I'm best at questions about debugging web pages." to such questions.
|
|
27
|
+
|
|
28
|
+
## Response Structure
|
|
29
|
+
|
|
30
|
+
If the user asks a question that requires an investigation of a problem, use this structure:
|
|
31
|
+
- If available, point out the root cause(s) of the problem.
|
|
32
|
+
- Example: "**Root Cause**: The page is slow because of [reason]."
|
|
33
|
+
- Example: "**Root Causes**:"
|
|
34
|
+
- [Reason 1]
|
|
35
|
+
- [Reason 2]
|
|
36
|
+
- if applicable, list actionable solution suggestion(s) in order of impact:
|
|
37
|
+
- Example: "**Suggestion**: [Suggestion 1]
|
|
38
|
+
- Example: "**Suggestions**:"
|
|
39
|
+
- [Suggestion 1]
|
|
40
|
+
- [Suggestion 2]
|
|
@@ -0,0 +1,137 @@
|
|
|
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
|
+
import * as Host from '../../../core/host/host.js';
|
|
6
|
+
import * as SDK from '../../../core/sdk/sdk.js';
|
|
7
|
+
import type * as Protocol from '../../../generated/protocol.js';
|
|
8
|
+
import type {ComputedStyleAiWidget, FunctionCallHandlerResult} from '../agents/AiAgent.js';
|
|
9
|
+
import {DOMNodeContext} from '../contexts/DOMNodeContext.js';
|
|
10
|
+
import {debugLog} from '../debug.js';
|
|
11
|
+
|
|
12
|
+
import {type Tool, type ToolArgs, type ToolContext, ToolName} from './Tool.js';
|
|
13
|
+
|
|
14
|
+
export interface GetStylesArgs extends ToolArgs {
|
|
15
|
+
elements: number[];
|
|
16
|
+
styleProperties: string[];
|
|
17
|
+
explanation: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class GetStylesTool implements Tool<GetStylesArgs, unknown> {
|
|
21
|
+
readonly name = ToolName.GET_STYLES;
|
|
22
|
+
readonly description =
|
|
23
|
+
`Get computed and source styles for one or multiple elements on the inspected page for multiple elements at once by uid.
|
|
24
|
+
|
|
25
|
+
**CRITICAL** An element uid is a number, not a selector.
|
|
26
|
+
**CRITICAL** Use selectors to refer to elements in the text output. Do not use uids.
|
|
27
|
+
**CRITICAL** Always provide the explanation argument to explain what and why you query.
|
|
28
|
+
**CRITICAL** You MUST provide a specific list of CSS property names. Do not use generic values like "all" or "*".`;
|
|
29
|
+
|
|
30
|
+
readonly parameters: Host.AidaClient.FunctionObjectParam<keyof GetStylesArgs> = {
|
|
31
|
+
type: Host.AidaClient.ParametersTypes.OBJECT,
|
|
32
|
+
description: '',
|
|
33
|
+
nullable: false,
|
|
34
|
+
properties: {
|
|
35
|
+
explanation: {
|
|
36
|
+
type: Host.AidaClient.ParametersTypes.STRING,
|
|
37
|
+
description: 'Explain why you want to get styles',
|
|
38
|
+
nullable: false,
|
|
39
|
+
},
|
|
40
|
+
elements: {
|
|
41
|
+
type: Host.AidaClient.ParametersTypes.ARRAY,
|
|
42
|
+
description: 'A list of element uids to get data for. These are numbers, not selectors.',
|
|
43
|
+
items: {type: Host.AidaClient.ParametersTypes.INTEGER, description: 'An element uid.'},
|
|
44
|
+
nullable: false,
|
|
45
|
+
},
|
|
46
|
+
styleProperties: {
|
|
47
|
+
type: Host.AidaClient.ParametersTypes.ARRAY,
|
|
48
|
+
description:
|
|
49
|
+
'One or more specific CSS style property names to fetch. Generic values like "all" or "*" are not supported.',
|
|
50
|
+
nullable: false,
|
|
51
|
+
items: {
|
|
52
|
+
type: Host.AidaClient.ParametersTypes.STRING,
|
|
53
|
+
description: 'A CSS style property name to retrieve. For example, \'background-color\'.'
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
required: ['explanation', 'elements', 'styleProperties']
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
displayInfoFromArgs(params: GetStylesArgs): {
|
|
61
|
+
title: string,
|
|
62
|
+
thought: string,
|
|
63
|
+
action: string,
|
|
64
|
+
} {
|
|
65
|
+
return {
|
|
66
|
+
title: 'Reading computed and source styles',
|
|
67
|
+
thought: params.explanation,
|
|
68
|
+
action: `getStyles(${JSON.stringify(params.elements)}, ${JSON.stringify(params.styleProperties)})`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async handler(params: GetStylesArgs, context: ToolContext): Promise<FunctionCallHandlerResult<unknown>> {
|
|
73
|
+
const widgets: ComputedStyleAiWidget[] = [];
|
|
74
|
+
const result:
|
|
75
|
+
Record<string, {computed: Record<string, string|undefined>, authored: Record<string, string|undefined>}> = {};
|
|
76
|
+
|
|
77
|
+
const activeContext = context.conversationContext;
|
|
78
|
+
if (!activeContext || !(activeContext instanceof DOMNodeContext)) {
|
|
79
|
+
return {error: 'Error: Could not find the currently selected element.'};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const selectedNode = activeContext.getItem();
|
|
83
|
+
if (!selectedNode) {
|
|
84
|
+
return {error: 'Error: Could not find the currently selected element.'};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
for (const uid of params.elements) {
|
|
88
|
+
result[uid] = {computed: {}, authored: {}};
|
|
89
|
+
debugLog(`Action to execute: uid=${uid}`);
|
|
90
|
+
const node =
|
|
91
|
+
new SDK.DOMModel.DeferredDOMNode(selectedNode.domModel().target(), uid as Protocol.DOM.BackendNodeId);
|
|
92
|
+
const resolved = await node.resolvePromise();
|
|
93
|
+
if (!resolved) {
|
|
94
|
+
return {error: 'Error: Could not find the element with uid=' + uid};
|
|
95
|
+
}
|
|
96
|
+
const newContext = new DOMNodeContext(resolved);
|
|
97
|
+
if (activeContext.getOrigin() !== newContext.getOrigin()) {
|
|
98
|
+
return {error: 'Error: Node does not belong to the current origin.'};
|
|
99
|
+
}
|
|
100
|
+
const styles = await resolved.domModel().cssModel().getComputedStyle(resolved.id);
|
|
101
|
+
if (!styles) {
|
|
102
|
+
return {error: 'Error: Could not get computed styles.'};
|
|
103
|
+
}
|
|
104
|
+
const matchedStyles = await resolved.domModel().cssModel().getMatchedStyles(resolved.id);
|
|
105
|
+
if (!matchedStyles) {
|
|
106
|
+
return {error: 'Error: Could not get authored styles.'};
|
|
107
|
+
}
|
|
108
|
+
widgets.push({
|
|
109
|
+
name: 'COMPUTED_STYLES',
|
|
110
|
+
data: {
|
|
111
|
+
computedStyles: styles,
|
|
112
|
+
backendNodeId: node.backendNodeId(),
|
|
113
|
+
matchedCascade: matchedStyles,
|
|
114
|
+
properties: params.styleProperties,
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
for (const prop of params.styleProperties) {
|
|
118
|
+
result[uid].computed[prop] = styles.get(prop);
|
|
119
|
+
}
|
|
120
|
+
for (const style of matchedStyles.nodeStyles()) {
|
|
121
|
+
for (const property of style.allProperties()) {
|
|
122
|
+
if (!params.styleProperties.includes(property.name)) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const state = matchedStyles.propertyState(property);
|
|
126
|
+
if (state === SDK.CSSMatchedStyles.PropertyState.ACTIVE) {
|
|
127
|
+
result[uid].authored[property.name] = property.value;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
result: JSON.stringify(result, null, 2),
|
|
134
|
+
widgets,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
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
|
+
import type * as Host from '../../../core/host/host.js';
|
|
6
|
+
import type {ConversationContext, FunctionCallHandlerResult,} from '../agents/AiAgent.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Context provided to the tool's handler execution.
|
|
10
|
+
*/
|
|
11
|
+
export interface ToolContext {
|
|
12
|
+
conversationContext: ConversationContext<unknown>|null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Base argument type for AI Tools.
|
|
17
|
+
*/
|
|
18
|
+
export type ToolArgs = Record<string, unknown>;
|
|
19
|
+
|
|
20
|
+
export const enum ToolName {
|
|
21
|
+
GET_STYLES = 'getStyles',
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Non-generic metadata interface for a Tool.
|
|
26
|
+
* Used for storing and retrieving tools generically without type-erasure concerns.
|
|
27
|
+
*/
|
|
28
|
+
export interface BaseTool {
|
|
29
|
+
readonly name: ToolName;
|
|
30
|
+
readonly description: string;
|
|
31
|
+
/**
|
|
32
|
+
* JSON schema representing the parameters this tool accepts.
|
|
33
|
+
*/
|
|
34
|
+
readonly parameters: Host.AidaClient.FunctionObjectParam<string|number|symbol>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Main generic interface for defining a Tool.
|
|
39
|
+
* Binds the parameter schema properties and the handler implementation to a strict `Args` contract.
|
|
40
|
+
*
|
|
41
|
+
* @template Args - The expected object type for tool arguments. Must be an object type.
|
|
42
|
+
* @template ReturnType - The type of data returned by the handler function.
|
|
43
|
+
*/
|
|
44
|
+
export interface Tool<Args extends ToolArgs = ToolArgs, ReturnType = unknown, > extends BaseTool {
|
|
45
|
+
readonly parameters: Host.AidaClient.FunctionObjectParam<keyof Args>;
|
|
46
|
+
readonly displayInfoFromArgs?: (
|
|
47
|
+
args: Args,
|
|
48
|
+
) => {
|
|
49
|
+
title?: string, thought?: string, action?: string, suggestions?: [string, ...string[]],
|
|
50
|
+
};
|
|
51
|
+
handler(
|
|
52
|
+
args: Args,
|
|
53
|
+
context: ToolContext,
|
|
54
|
+
): Promise<FunctionCallHandlerResult<ReturnType>>;
|
|
55
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
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
|
+
import {GetStylesTool} from './GetStyles.js';
|
|
6
|
+
import {type Tool, ToolName} from './Tool.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Plain object registry containing concrete instantiated tools.
|
|
10
|
+
* Keep this type concrete (no type-erasure) to preserve exact tool types.
|
|
11
|
+
*/
|
|
12
|
+
export const TOOLS = {
|
|
13
|
+
[ToolName.GET_STYLES]: new GetStylesTool(),
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Registry class for registering and querying AI Assistance Tools.
|
|
18
|
+
*/
|
|
19
|
+
export class ToolRegistry {
|
|
20
|
+
/**
|
|
21
|
+
* Retrieves a tool by its literal name with 100% type safety.
|
|
22
|
+
*
|
|
23
|
+
* @template K - A key from the `TOOLS` registry.
|
|
24
|
+
* @returns The concrete class type of the requested tool.
|
|
25
|
+
*/
|
|
26
|
+
static get<K extends keyof typeof TOOLS>(name: K): typeof TOOLS[K];
|
|
27
|
+
/**
|
|
28
|
+
* Fallback retrieval signature for general or runtime string lookups.
|
|
29
|
+
*/
|
|
30
|
+
static get(name: string): Tool|undefined;
|
|
31
|
+
static get(name: string): Tool|undefined {
|
|
32
|
+
return Object.prototype.hasOwnProperty.call(TOOLS, name) ? TOOLS[name as keyof typeof TOOLS] as Tool : undefined;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -289,6 +289,10 @@ export class HeapSnapshotProxy extends HeapSnapshotProxyObject {
|
|
|
289
289
|
return this.callMethodPromise('nodeClassKey', snapshotObjectId);
|
|
290
290
|
}
|
|
291
291
|
|
|
292
|
+
nodeIndexForId(nodeId: number): Promise<number|undefined> {
|
|
293
|
+
return this.callMethodPromise('nodeIndexForId', nodeId);
|
|
294
|
+
}
|
|
295
|
+
|
|
292
296
|
createEdgesProvider(nodeIndex: number): HeapSnapshotProviderProxy {
|
|
293
297
|
return this.callFactoryMethod('createEdgesProvider', HeapSnapshotProviderProxy, nodeIndex);
|
|
294
298
|
}
|
|
@@ -6489,6 +6489,22 @@ export const NativeFunctions = [
|
|
|
6489
6489
|
name: "XRLayerEvent",
|
|
6490
6490
|
signatures: [["type","eventInitDict"]]
|
|
6491
6491
|
},
|
|
6492
|
+
{
|
|
6493
|
+
name: "XRMediaBinding",
|
|
6494
|
+
signatures: [["session"]]
|
|
6495
|
+
},
|
|
6496
|
+
{
|
|
6497
|
+
name: "createQuadLayer",
|
|
6498
|
+
signatures: [["video","init"]]
|
|
6499
|
+
},
|
|
6500
|
+
{
|
|
6501
|
+
name: "createCylinderLayer",
|
|
6502
|
+
signatures: [["video","init"]]
|
|
6503
|
+
},
|
|
6504
|
+
{
|
|
6505
|
+
name: "createEquirectLayer",
|
|
6506
|
+
signatures: [["video","init"]]
|
|
6507
|
+
},
|
|
6492
6508
|
{
|
|
6493
6509
|
name: "XRRay",
|
|
6494
6510
|
signatures: [["transform"],["?origin","?direction"]]
|
|
@@ -77,6 +77,11 @@ export interface ReportJSON {
|
|
|
77
77
|
audits: Record<string, AuditResultJSON>;
|
|
78
78
|
categories: Record<CategoryId, CategoryJSON>;
|
|
79
79
|
categoryGroups: Record<string, GroupJSON>;
|
|
80
|
+
/**
|
|
81
|
+
* Identifies if the report was imported from a file (untrusted).
|
|
82
|
+
* Used to disable page-touching AI assistance tools for security.
|
|
83
|
+
*/
|
|
84
|
+
isImported?: boolean;
|
|
80
85
|
}
|
|
81
86
|
|
|
82
87
|
export type DetailsJSON =
|
|
@@ -64,17 +64,22 @@ export class LiveMetrics extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
|
|
|
64
64
|
super();
|
|
65
65
|
const targetManager = SDK.TargetManager.TargetManager.instance();
|
|
66
66
|
targetManager.observeTargets(this, {scoped: true});
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
targetManager.addEventListener(
|
|
71
|
-
SDK.TargetManager.Events.AVAILABLE_TARGETS_CHANGED, this.#onAvailableTargetsChanged, this);
|
|
67
|
+
targetManager.addModelListener(
|
|
68
|
+
SDK.ResourceTreeModel.ResourceTreeModel, SDK.ResourceTreeModel.Events.PrimaryPageChanged,
|
|
69
|
+
this.#onPrimaryPageChanged, this);
|
|
72
70
|
}
|
|
73
71
|
|
|
74
|
-
#
|
|
72
|
+
#onPrimaryPageChanged(
|
|
73
|
+
event: Common.EventTarget.EventTargetEvent<
|
|
74
|
+
{frame: SDK.ResourceTreeModel.ResourceTreeFrame, type: SDK.ResourceTreeModel.PrimaryPageChangeType}>): void {
|
|
75
75
|
const primaryTarget = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
|
|
76
|
-
if (primaryTarget
|
|
77
|
-
|
|
76
|
+
if (!primaryTarget) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (primaryTarget !== this.#target || event.data.type === SDK.ResourceTreeModel.PrimaryPageChangeType.ACTIVATION) {
|
|
80
|
+
// Primary target changed or prerender activated. Switch to it and reset metrics.
|
|
81
|
+
this.#clearMetrics();
|
|
82
|
+
this.#sendStatusUpdate();
|
|
78
83
|
void this.#switchToTarget(primaryTarget);
|
|
79
84
|
}
|
|
80
85
|
}
|
|
@@ -381,11 +386,7 @@ export class LiveMetrics extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
|
|
|
381
386
|
break;
|
|
382
387
|
}
|
|
383
388
|
case 'reset': {
|
|
384
|
-
this.#
|
|
385
|
-
this.#clsValue = undefined;
|
|
386
|
-
this.#inpValue = undefined;
|
|
387
|
-
this.#interactions.clear();
|
|
388
|
-
this.#layoutShifts = [];
|
|
389
|
+
this.#clearMetrics();
|
|
389
390
|
break;
|
|
390
391
|
}
|
|
391
392
|
}
|
|
@@ -393,6 +394,15 @@ export class LiveMetrics extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
|
|
|
393
394
|
this.#sendStatusUpdate();
|
|
394
395
|
}
|
|
395
396
|
|
|
397
|
+
#clearMetrics(): void {
|
|
398
|
+
this.#lcpValue = undefined;
|
|
399
|
+
this.#clsValue = undefined;
|
|
400
|
+
this.#inpValue = undefined;
|
|
401
|
+
this.#interactions.clear();
|
|
402
|
+
this.#interactionsByGroupId.clear();
|
|
403
|
+
this.#layoutShifts = [];
|
|
404
|
+
}
|
|
405
|
+
|
|
396
406
|
#isPrimaryFrameExecutionContext(executionContextId: Protocol.Runtime.ExecutionContextId): boolean {
|
|
397
407
|
if (!this.#target) {
|
|
398
408
|
return false;
|
|
@@ -460,6 +470,7 @@ export class LiveMetrics extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
|
|
|
460
470
|
|
|
461
471
|
clearInteractions(): void {
|
|
462
472
|
this.#interactions.clear();
|
|
473
|
+
this.#interactionsByGroupId.clear();
|
|
463
474
|
this.#sendStatusUpdate();
|
|
464
475
|
}
|
|
465
476
|
|
|
@@ -142,12 +142,12 @@ export function parseRawFramesFromErrorStack(stack: string): RawFrame[]|null {
|
|
|
142
142
|
functionName,
|
|
143
143
|
lineNumber,
|
|
144
144
|
columnNumber,
|
|
145
|
+
isWasm,
|
|
145
146
|
parsedFrameInfo: {
|
|
146
147
|
isAsync,
|
|
147
148
|
isConstructor,
|
|
148
149
|
isEval,
|
|
149
150
|
evalOrigin,
|
|
150
|
-
isWasm,
|
|
151
151
|
wasmModuleName,
|
|
152
152
|
wasmFunctionIndex,
|
|
153
153
|
typeName,
|
|
@@ -181,7 +181,7 @@ export function parseMessage(stack: string): string {
|
|
|
181
181
|
export function augmentRawFramesWithScriptIds(
|
|
182
182
|
rawFrames: RawFrame[], protocolStackTrace: Protocol.Runtime.StackTrace): void {
|
|
183
183
|
function augmentFrame(rawFrame: RawFrame): void {
|
|
184
|
-
const isWasm = rawFrame.
|
|
184
|
+
const isWasm = rawFrame.isWasm;
|
|
185
185
|
const protocolFrame = protocolStackTrace.callFrames.find(frame => {
|
|
186
186
|
if (isWasm) {
|
|
187
187
|
// The parser parses Wasm offsets into the `columnNumber` field. The `lineNumber` is always -1.
|
|
@@ -44,6 +44,10 @@ export interface Frame {
|
|
|
44
44
|
* of the containing function.
|
|
45
45
|
*/
|
|
46
46
|
readonly rawName?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Whether the corresponding raw frame is JS or WASM.
|
|
49
|
+
*/
|
|
50
|
+
readonly isWasm?: boolean;
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
export interface ParsedErrorStackFrame extends Frame {
|
|
@@ -51,7 +55,6 @@ export interface ParsedErrorStackFrame extends Frame {
|
|
|
51
55
|
readonly isConstructor?: boolean;
|
|
52
56
|
readonly isEval?: boolean;
|
|
53
57
|
readonly evalOrigin?: ParsedErrorStackFrame;
|
|
54
|
-
readonly isWasm?: boolean;
|
|
55
58
|
readonly wasmModuleName?: string;
|
|
56
59
|
readonly wasmFunctionIndex?: number;
|
|
57
60
|
readonly typeName?: string;
|
|
@@ -88,10 +88,12 @@ export class FrameImpl implements StackTrace.StackTrace.Frame {
|
|
|
88
88
|
|
|
89
89
|
readonly missingDebugInfo?: StackTrace.StackTrace.MissingDebugInfo;
|
|
90
90
|
readonly rawName?: string;
|
|
91
|
+
readonly isWasm?: boolean;
|
|
91
92
|
|
|
92
93
|
constructor(
|
|
93
94
|
url: string|undefined, uiSourceCode: Workspace.UISourceCode.UISourceCode|undefined, name: string|undefined,
|
|
94
|
-
line: number, column: number, missingDebugInfo?: StackTrace.StackTrace.MissingDebugInfo, rawName?: string
|
|
95
|
+
line: number, column: number, missingDebugInfo?: StackTrace.StackTrace.MissingDebugInfo, rawName?: string,
|
|
96
|
+
isWasm?: boolean) {
|
|
95
97
|
this.url = url;
|
|
96
98
|
this.uiSourceCode = uiSourceCode;
|
|
97
99
|
this.name = name;
|
|
@@ -99,6 +101,7 @@ export class FrameImpl implements StackTrace.StackTrace.Frame {
|
|
|
99
101
|
this.column = column;
|
|
100
102
|
this.missingDebugInfo = missingDebugInfo;
|
|
101
103
|
this.rawName = rawName;
|
|
104
|
+
this.isWasm = isWasm;
|
|
102
105
|
}
|
|
103
106
|
}
|
|
104
107
|
|
|
@@ -192,7 +195,7 @@ export class ParsedErrorStackFrameImpl implements StackTrace.StackTrace.ParsedEr
|
|
|
192
195
|
return this.#evalOrigin;
|
|
193
196
|
}
|
|
194
197
|
get isWasm(): boolean|undefined {
|
|
195
|
-
return this.#
|
|
198
|
+
return this.#frame.isWasm;
|
|
196
199
|
}
|
|
197
200
|
get wasmModuleName(): string|undefined {
|
|
198
201
|
return this.#parsedFrameInfo?.wasmModuleName;
|
|
@@ -284,6 +287,10 @@ export class DebuggableFrameImpl implements StackTrace.StackTrace.DebuggableFram
|
|
|
284
287
|
return this.#frame.rawName;
|
|
285
288
|
}
|
|
286
289
|
|
|
290
|
+
get isWasm(): boolean|undefined {
|
|
291
|
+
return this.#frame.isWasm;
|
|
292
|
+
}
|
|
293
|
+
|
|
287
294
|
get sdkFrame(): SDK.DebuggerModel.CallFrame {
|
|
288
295
|
return this.#sdkFrame;
|
|
289
296
|
}
|
|
@@ -48,8 +48,14 @@ export class StackTraceModel extends SDK.SDKModel.SDKModel<unknown> {
|
|
|
48
48
|
|
|
49
49
|
async createFromProtocolRuntime(stackTrace: Protocol.Runtime.StackTrace, rawFramesToUIFrames: TranslateRawFrames):
|
|
50
50
|
Promise<StackTrace.StackTrace.StackTrace> {
|
|
51
|
+
const debuggerModel = this.target().model(SDK.DebuggerModel.DebuggerModel);
|
|
52
|
+
const syncFrames = stackTrace.callFrames.map((frame): RawFrame => {
|
|
53
|
+
const isWasm = debuggerModel?.isWasm(frame.scriptId) ?? false;
|
|
54
|
+
return {...frame, isWasm};
|
|
55
|
+
});
|
|
56
|
+
|
|
51
57
|
const [syncFragment, asyncFragments] = await Promise.all([
|
|
52
|
-
this.#createFragment(
|
|
58
|
+
this.#createFragment(syncFrames, rawFramesToUIFrames),
|
|
53
59
|
this.#createAsyncFragments(stackTrace, rawFramesToUIFrames),
|
|
54
60
|
]);
|
|
55
61
|
|
|
@@ -126,6 +132,7 @@ export class StackTraceModel extends SDK.SDKModel.SDKModel<unknown> {
|
|
|
126
132
|
functionName: frame.functionName,
|
|
127
133
|
lineNumber: frame.location().lineNumber,
|
|
128
134
|
columnNumber: frame.location().columnNumber,
|
|
135
|
+
isWasm: frame.script.isWasm(),
|
|
129
136
|
})),
|
|
130
137
|
rawFramesToUIFrames);
|
|
131
138
|
return new DebuggableFragmentImpl(fragment, pausedDetails.callFrames);
|
|
@@ -144,8 +151,14 @@ export class StackTraceModel extends SDK.SDKModel.SDKModel<unknown> {
|
|
|
144
151
|
continue;
|
|
145
152
|
}
|
|
146
153
|
const model = StackTraceModel.#modelForTarget(target);
|
|
154
|
+
const targetDebuggerModel = target.model(SDK.DebuggerModel.DebuggerModel);
|
|
155
|
+
const asyncFrames = asyncStackTrace.callFrames.map((frame): RawFrame => {
|
|
156
|
+
const isWasm = targetDebuggerModel?.isWasm(frame.scriptId) ?? false;
|
|
157
|
+
return {...frame, isWasm};
|
|
158
|
+
});
|
|
159
|
+
|
|
147
160
|
const asyncFragmentPromise =
|
|
148
|
-
model.#createFragment(
|
|
161
|
+
model.#createFragment(asyncFrames, rawFramesToUIFrames)
|
|
149
162
|
.then(fragment => new AsyncFragmentImpl(asyncStackTrace.description ?? '', fragment));
|
|
150
163
|
asyncFragments.push(asyncFragmentPromise);
|
|
151
164
|
}
|
|
@@ -201,7 +214,7 @@ export class StackTraceModel extends SDK.SDKModel.SDKModel<unknown> {
|
|
|
201
214
|
node.frames = uiFrames[i++].map(
|
|
202
215
|
frame => new FrameImpl(
|
|
203
216
|
frame.url, frame.uiSourceCode, frame.name, frame.line, frame.column, frame.missingDebugInfo,
|
|
204
|
-
node.rawFrame.functionName));
|
|
217
|
+
node.rawFrame.functionName, node.rawFrame.isWasm));
|
|
205
218
|
|
|
206
219
|
if (node.parsedFrameInfo?.evalOrigin) {
|
|
207
220
|
node.evalOrigin = evalOrigins[evalI++];
|
|
@@ -243,7 +256,7 @@ async function translateEvalOrigin(
|
|
|
243
256
|
const frames = uiFrames[0].map(
|
|
244
257
|
frame => new FrameImpl(
|
|
245
258
|
frame.url, frame.uiSourceCode, frame.name, frame.line, frame.column, frame.missingDebugInfo,
|
|
246
|
-
rawFrame.functionName));
|
|
259
|
+
rawFrame.functionName, rawFrame.isWasm));
|
|
247
260
|
|
|
248
261
|
let parentEvalOrigin: EvalOrigin|undefined;
|
|
249
262
|
if (rawFrame.parsedFrameInfo?.evalOrigin) {
|
|
@@ -11,7 +11,6 @@ export interface ParsedFrameInfo {
|
|
|
11
11
|
readonly isConstructor?: boolean;
|
|
12
12
|
readonly isEval?: boolean;
|
|
13
13
|
readonly evalOrigin?: RawFrame;
|
|
14
|
-
readonly isWasm?: boolean;
|
|
15
14
|
readonly wasmModuleName?: string;
|
|
16
15
|
readonly wasmFunctionIndex?: number;
|
|
17
16
|
readonly typeName?: string;
|
|
@@ -30,6 +29,7 @@ export interface RawFrame {
|
|
|
30
29
|
readonly columnNumber: number;
|
|
31
30
|
|
|
32
31
|
readonly parsedFrameInfo?: ParsedFrameInfo;
|
|
32
|
+
readonly isWasm?: boolean;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
/**
|