chrome-devtools-frontend 1.0.1632065 → 1.0.1635876
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/front_end/core/host/UserMetrics.ts +5 -2
- package/front_end/core/root/ExperimentNames.ts +1 -0
- package/front_end/core/root/Runtime.ts +5 -0
- package/front_end/core/sdk/SourceMapCache.ts +13 -11
- package/front_end/core/sdk/SourceMapManager.ts +7 -3
- package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +84 -22
- package/front_end/entrypoints/main/MainImpl.ts +8 -0
- package/front_end/generated/InspectorBackendCommands.ts +3 -4
- package/front_end/generated/SupportedCSSProperties.js +272 -2
- package/front_end/generated/protocol-mapping.d.ts +0 -10
- package/front_end/generated/protocol-proxy-api.d.ts +0 -8
- package/front_end/generated/protocol.ts +5 -7
- package/front_end/models/ai_assistance/AiConversation.ts +16 -11
- package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +13 -2
- package/front_end/models/ai_assistance/agents/AiAgent.ts +65 -11
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +42 -2
- package/front_end/models/ai_assistance/agents/GreenDevAgent.ts +68 -5
- package/front_end/models/ai_assistance/agents/GreenDevAgentAntigravityCliSocketClient.ts +53 -0
- package/front_end/models/ai_assistance/agents/GreenDevAgentGeminiCliSocketClient.ts +117 -0
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +30 -1
- package/front_end/models/ai_assistance/ai_assistance.ts +4 -0
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +4 -2
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +5 -2
- package/front_end/models/extensions/RecorderExtensionEndpoint.ts +9 -1
- package/front_end/models/extensions/RecorderPluginManager.ts +1 -0
- package/front_end/models/greendev/Prototypes.ts +17 -5
- package/front_end/models/trace/handlers/FramesHandler.ts +19 -13
- package/front_end/panels/ai_assistance/components/AccessibilityAgentMarkdownRenderer.ts +3 -0
- package/front_end/panels/ai_assistance/components/ChatInput.ts +4 -2
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +3 -1
- package/front_end/panels/application/preloading/components/PreloadingString.ts +0 -8
- package/front_end/panels/common/ExtensionServer.ts +34 -11
- package/front_end/panels/elements/CSSRuleValidator.ts +37 -34
- package/front_end/panels/elements/CSSRuleValidatorHelper.ts +8 -6
- package/front_end/panels/elements/ElementsTreeElement.ts +8 -2
- package/front_end/panels/elements/components/CSSHintDetailsView.ts +5 -5
- package/front_end/panels/js_timeline/js_timeline-meta.ts +30 -0
- package/front_end/panels/protocol_monitor/JSONEditor.ts +4 -4
- package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +2 -2
- package/front_end/panels/recorder/RecorderController.ts +50 -1
- package/front_end/panels/recorder/extensions/ExtensionManager.ts +1 -0
- package/front_end/panels/recorder/models/RecordingPlayer.ts +12 -3
- package/front_end/panels/recorder/testing/RecorderHelpers.ts +2 -0
- package/front_end/panels/settings/SettingsScreen.ts +3 -2
- package/front_end/panels/sources/FilteredUISourceCodeListProvider.ts +5 -2
- package/front_end/panels/timeline/timeline-meta.ts +10 -6
- package/front_end/panels/whats_new/ReleaseNoteText.ts +9 -9
- package/front_end/panels/whats_new/resources/WNDT.md +9 -9
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/puppeteer/README.chromium +2 -2
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +8 -5
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +35 -33
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/TargetManager.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/TargetManager.js +0 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/TargetManager.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/WebMCP.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/WebMCP.js +0 -3
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/WebMCP.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.d.ts +8 -8
- package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.js +8 -8
- package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/CustomQuerySelector.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/CustomQuerySelector.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/CustomQuerySelector.js +2 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/CustomQuerySelector.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/injected.d.ts +2 -7
- package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/injected.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/node/PuppeteerNode.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/node/PuppeteerNode.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/util/Mutex.d.ts +10 -7
- package/front_end/third_party/puppeteer/package/lib/puppeteer/util/Mutex.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/util/Mutex.js +16 -12
- package/front_end/third_party/puppeteer/package/lib/puppeteer/util/Mutex.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/types.d.ts +8 -5
- package/front_end/third_party/puppeteer/package/package.json +5 -7
- package/front_end/third_party/puppeteer/package/src/cdp/TargetManager.ts +0 -1
- package/front_end/third_party/puppeteer/package/src/cdp/WebMCP.ts +0 -3
- package/front_end/third_party/puppeteer/package/src/common/Debug.ts +11 -11
- package/front_end/third_party/puppeteer/package/src/generated/injected.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/injected/CustomQuerySelector.ts +3 -2
- package/front_end/third_party/puppeteer/package/src/node/PuppeteerNode.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
- package/front_end/third_party/puppeteer/package/src/util/Mutex.ts +17 -12
- package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
- package/front_end/ui/components/markdown_view/MarkdownLinksMap.ts +7 -0
- package/front_end/ui/legacy/InspectorDrawerView.ts +2 -1
- package/front_end/ui/legacy/InspectorView.ts +1 -1
- package/front_end/ui/legacy/PlusButton.ts +269 -0
- package/front_end/ui/legacy/ViewManager.ts +38 -11
- package/front_end/ui/legacy/components/source_frame/FontView.ts +11 -3
- package/front_end/ui/legacy/components/source_frame/ImageView.ts +16 -0
- package/front_end/ui/legacy/components/source_frame/imageView.css +13 -0
- package/front_end/ui/legacy/components/utils/Linkifier.ts +1 -1
- package/front_end/ui/legacy/legacy.ts +2 -0
- package/front_end/ui/visual_logging/KnownContextValues.ts +21 -0
- package/mcp/mcp.ts +1 -1
- package/package.json +1 -10
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
AiAgent,
|
|
21
21
|
type AllowedOriginResult,
|
|
22
22
|
type ContextResponse,
|
|
23
|
+
isOpaqueOrigin,
|
|
23
24
|
type RequestOptions,
|
|
24
25
|
} from './AiAgent.js';
|
|
25
26
|
import {FileContext} from './FileAgent.js';
|
|
@@ -126,6 +127,11 @@ export class ContextSelectionAgent extends AiAgent<never> {
|
|
|
126
127
|
};
|
|
127
128
|
}
|
|
128
129
|
const origin = allowedOriginResult.origin;
|
|
130
|
+
if (origin && isOpaqueOrigin(origin)) {
|
|
131
|
+
return {
|
|
132
|
+
error: 'No requests recorded by DevTools',
|
|
133
|
+
};
|
|
134
|
+
}
|
|
129
135
|
|
|
130
136
|
let hasCrossOriginRequest = false;
|
|
131
137
|
for (const request of Logs.NetworkLog.NetworkLog.instance().requests()) {
|
|
@@ -196,6 +202,11 @@ export class ContextSelectionAgent extends AiAgent<never> {
|
|
|
196
202
|
};
|
|
197
203
|
}
|
|
198
204
|
const origin = allowedOriginResult.origin;
|
|
205
|
+
if (origin && isOpaqueOrigin(origin)) {
|
|
206
|
+
return {
|
|
207
|
+
error: 'No request found',
|
|
208
|
+
};
|
|
209
|
+
}
|
|
199
210
|
const request = Logs.NetworkLog.NetworkLog.instance().requests().find(req => {
|
|
200
211
|
if (req.requestId() !== id) {
|
|
201
212
|
return false;
|
|
@@ -235,8 +246,23 @@ export class ContextSelectionAgent extends AiAgent<never> {
|
|
|
235
246
|
};
|
|
236
247
|
},
|
|
237
248
|
handler: async () => {
|
|
249
|
+
const allowedOriginResult = this.#allowedOrigin();
|
|
250
|
+
if ('blocked' in allowedOriginResult) {
|
|
251
|
+
return {
|
|
252
|
+
error: 'Cross-origin access blocked due to navigation. Please start a new chat.',
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
const origin = allowedOriginResult.origin;
|
|
256
|
+
|
|
238
257
|
const files: Array<{file: string, id: number | undefined}> = [];
|
|
239
258
|
for (const file of ContextSelectionAgent.getUISourceCodes()) {
|
|
259
|
+
const fileUrl = file.url();
|
|
260
|
+
const fileOrigin = Common.ParsedURL.ParsedURL.extractOrigin(fileUrl);
|
|
261
|
+
|
|
262
|
+
if (origin && fileOrigin !== origin) {
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
|
|
240
266
|
files.push({
|
|
241
267
|
file: file.fullDisplayName(),
|
|
242
268
|
id: ContextSelectionAgent.uiSourceCodeId.get(file),
|
|
@@ -272,8 +298,22 @@ export class ContextSelectionAgent extends AiAgent<never> {
|
|
|
272
298
|
};
|
|
273
299
|
},
|
|
274
300
|
handler: async params => {
|
|
275
|
-
const
|
|
276
|
-
|
|
301
|
+
const allowedOriginResult = this.#allowedOrigin();
|
|
302
|
+
if ('blocked' in allowedOriginResult) {
|
|
303
|
+
return {
|
|
304
|
+
error: 'Cross-origin access blocked due to navigation. Please start a new chat.',
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
const origin = allowedOriginResult.origin;
|
|
308
|
+
|
|
309
|
+
const file = ContextSelectionAgent.getUISourceCodes().find(file => {
|
|
310
|
+
if (ContextSelectionAgent.uiSourceCodeId.get(file) !== params.id) {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
const fileUrl = file.url();
|
|
314
|
+
const fileOrigin = Common.ParsedURL.ParsedURL.extractOrigin(fileUrl);
|
|
315
|
+
return !origin || fileOrigin === origin;
|
|
316
|
+
});
|
|
277
317
|
|
|
278
318
|
if (!file) {
|
|
279
319
|
return {
|
|
@@ -2,6 +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 * as Common from '../../../core/common/common.js';
|
|
5
6
|
import * as Host from '../../../core/host/host.js';
|
|
6
7
|
import * as Root from '../../../core/root/root.js';
|
|
7
8
|
import * as SDK from '../../../core/sdk/sdk.js';
|
|
@@ -53,9 +54,9 @@ additional context and resolve the user request.
|
|
|
53
54
|
directly relevant to the user's problem. Do not get distracted by generic framework
|
|
54
55
|
messages.
|
|
55
56
|
|
|
56
|
-
6. **Formulate a Hypothesis**: Based on your code investigation,
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
6. **Formulate a Hypothesis**: Based on your code investigation, and if you have a promising
|
|
58
|
+
fix, ALWAYS apply it using the provided 'applyFix' function. If you can identify more than
|
|
59
|
+
one fix, ask the user which one to apply.
|
|
59
60
|
|
|
60
61
|
### Available Information
|
|
61
62
|
|
|
@@ -82,6 +83,7 @@ To help you further, you can call the following functions:
|
|
|
82
83
|
request list.
|
|
83
84
|
- 'getReactComponentProps': This function takes a uid (the backend DOM node id) and returns
|
|
84
85
|
the React component props for that element.
|
|
86
|
+
- 'applyFix': This function accepts a code diff to apply to the code base.
|
|
85
87
|
|
|
86
88
|
Stick to what you have evidence for and refrain from speculating on things you
|
|
87
89
|
don't have concrete evidence for, such as CORS or Ad-blockers.
|
|
@@ -112,11 +114,38 @@ export class GreenDevContext extends ConversationContext<string> {
|
|
|
112
114
|
}
|
|
113
115
|
}
|
|
114
116
|
|
|
117
|
+
export const enum Events {
|
|
118
|
+
CLI_PROMPT_REQUESTED = 'CliPromptRequested',
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export interface EventTypes {
|
|
122
|
+
[Events.CLI_PROMPT_REQUESTED]: {prompt: string};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export const enum RemoteEndpoint {
|
|
126
|
+
GEMINI_CLI_SOCKET = 'GeminiCliSocket',
|
|
127
|
+
ANTIGRAVITY_CLI_SOCKET = 'AntigravityCliSocket',
|
|
128
|
+
}
|
|
129
|
+
|
|
115
130
|
/**
|
|
116
131
|
* This agent is a general-purpose web page troubleshooting agent for GreenDev
|
|
117
132
|
* prototypes.
|
|
118
133
|
*/
|
|
119
134
|
export class GreenDevAgent extends AiAgent<string> {
|
|
135
|
+
#eventTarget = new Common.ObjectWrapper.ObjectWrapper<EventTypes>();
|
|
136
|
+
|
|
137
|
+
addEventListener<T extends keyof EventTypes>(
|
|
138
|
+
eventType: T, listener: (arg0: Common.EventTarget.EventTargetEvent<EventTypes[T]>) => void,
|
|
139
|
+
thisObject?: Object): Common.EventTarget.EventDescriptor<EventTypes, T> {
|
|
140
|
+
return this.#eventTarget.addEventListener(eventType, listener, thisObject);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
removeEventListener<T extends keyof EventTypes>(
|
|
144
|
+
eventType: T, listener: (arg0: Common.EventTarget.EventTargetEvent<EventTypes[T]>) => void,
|
|
145
|
+
thisObject?: Object): void {
|
|
146
|
+
this.#eventTarget.removeEventListener(eventType, listener, thisObject);
|
|
147
|
+
}
|
|
148
|
+
|
|
120
149
|
constructor(options: AgentOptions) {
|
|
121
150
|
super(options);
|
|
122
151
|
|
|
@@ -327,6 +356,38 @@ export class GreenDevAgent extends AiAgent<string> {
|
|
|
327
356
|
};
|
|
328
357
|
},
|
|
329
358
|
});
|
|
359
|
+
|
|
360
|
+
this.declareFunction<{
|
|
361
|
+
codeSuggestionDiff: string,
|
|
362
|
+
}>('applyFix', {
|
|
363
|
+
description: 'Apply a code fix for the user to review.',
|
|
364
|
+
parameters: {
|
|
365
|
+
type: Host.AidaClient.ParametersTypes.OBJECT,
|
|
366
|
+
description: '',
|
|
367
|
+
nullable: false,
|
|
368
|
+
properties: {
|
|
369
|
+
codeSuggestionDiff: {
|
|
370
|
+
type: Host.AidaClient.ParametersTypes.STRING,
|
|
371
|
+
description: 'The diff of the suggested code change.',
|
|
372
|
+
nullable: false,
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
required: ['codeSuggestionDiff'],
|
|
376
|
+
},
|
|
377
|
+
handler: async (params: {codeSuggestionDiff: string}) => {
|
|
378
|
+
const result = await this.applyFix(params.codeSuggestionDiff);
|
|
379
|
+
return {
|
|
380
|
+
result,
|
|
381
|
+
};
|
|
382
|
+
},
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
async applyFix(codeSuggestionDiff: string): Promise<string> {
|
|
387
|
+
console.warn('[GreenDevAgent] applyFix called with:', codeSuggestionDiff);
|
|
388
|
+
this.#eventTarget.dispatchEventToListeners(
|
|
389
|
+
Events.CLI_PROMPT_REQUESTED, {prompt: `Apply this diff:\n${codeSuggestionDiff}`});
|
|
390
|
+
return 'The fix suggestion has been submitted.';
|
|
330
391
|
}
|
|
331
392
|
|
|
332
393
|
override preamble = preamble;
|
|
@@ -377,8 +438,10 @@ export class GreenDevAgent extends AiAgent<string> {
|
|
|
377
438
|
}
|
|
378
439
|
|
|
379
440
|
static isEnabled(): boolean {
|
|
380
|
-
|
|
381
|
-
|
|
441
|
+
const isGeminiEnabled = Greendev.Prototypes.instance().isEnabled('beyondStylingGemini');
|
|
442
|
+
const isAntigravityEnabled = Greendev.Prototypes.instance().isEnabled('beyondStylingAntigravity');
|
|
443
|
+
console.warn('BeyondStyling prototype is enabled:', isGeminiEnabled || isAntigravityEnabled);
|
|
444
|
+
return isGeminiEnabled || isAntigravityEnabled;
|
|
382
445
|
}
|
|
383
446
|
|
|
384
447
|
static formatConsoleMessage(message: SDK.ConsoleModel.ConsoleMessage, index: number): string {
|
|
@@ -0,0 +1,53 @@
|
|
|
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
|
+
export class GreenDevAgentAntigravityCliSocketClient {
|
|
6
|
+
#websocket: WebSocket;
|
|
7
|
+
sessionReady: Promise<void>;
|
|
8
|
+
#sessionReadyResolve: ((value: void|PromiseLike<void>) => void)|null = null;
|
|
9
|
+
|
|
10
|
+
constructor() {
|
|
11
|
+
this.sessionReady = new Promise(resolve => {
|
|
12
|
+
this.#sessionReadyResolve = resolve;
|
|
13
|
+
});
|
|
14
|
+
this.#websocket = new WebSocket('ws://localhost:5566');
|
|
15
|
+
this.#websocket.onopen = this.#onOpen.bind(this);
|
|
16
|
+
this.#websocket.onmessage = this.#onMessage.bind(this);
|
|
17
|
+
this.#websocket.onclose = this.#onClose.bind(this);
|
|
18
|
+
this.#websocket.onerror = this.#onError.bind(this);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
#onOpen(): void {
|
|
22
|
+
console.warn('WebSocket connected (Antigravity).');
|
|
23
|
+
if (this.#sessionReadyResolve) {
|
|
24
|
+
this.#sessionReadyResolve();
|
|
25
|
+
this.#sessionReadyResolve = null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
#onMessage(event: MessageEvent): void {
|
|
30
|
+
console.warn('Antigravity WebSocket message received:', event.data);
|
|
31
|
+
if (this.#onChunkCallback) {
|
|
32
|
+
this.#onChunkCallback(event.data);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#onClose(): void {
|
|
37
|
+
console.warn('WebSocket disconnected (Antigravity).');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
#onError(error: Event): void {
|
|
41
|
+
console.error('WebSocket error (Antigravity):', error);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
#onChunkCallback: ((chunk: string) => void)|null = null;
|
|
45
|
+
|
|
46
|
+
sendPrompt(promptText: string, onChunk: (chunk: string) => void): Promise<void> {
|
|
47
|
+
this.#onChunkCallback = onChunk;
|
|
48
|
+
|
|
49
|
+
console.warn(`Sending Antigravity prompt: "${promptText}"`);
|
|
50
|
+
this.#websocket.send(promptText);
|
|
51
|
+
return Promise.resolve();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
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
|
+
export class GreenDevAgentGeminiCliSocketClient {
|
|
6
|
+
#websocket: WebSocket;
|
|
7
|
+
#sessionId?: string;
|
|
8
|
+
#activeMessage = '';
|
|
9
|
+
#messageLog: string[] = [];
|
|
10
|
+
#promptResolve: ((response: string) => void)|null = null;
|
|
11
|
+
sessionReady: Promise<void>;
|
|
12
|
+
#sessionReadyResolve: ((value: void|PromiseLike<void>) => void)|null = null;
|
|
13
|
+
|
|
14
|
+
constructor() {
|
|
15
|
+
this.sessionReady = new Promise(resolve => {
|
|
16
|
+
this.#sessionReadyResolve = resolve;
|
|
17
|
+
});
|
|
18
|
+
this.#websocket = new WebSocket('ws://localhost:6655');
|
|
19
|
+
this.#websocket.onopen = this.#onOpen.bind(this);
|
|
20
|
+
this.#websocket.onmessage = this.#onMessage.bind(this);
|
|
21
|
+
this.#websocket.onclose = this.#onClose.bind(this);
|
|
22
|
+
this.#websocket.onerror = this.#onError.bind(this);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#onOpen(): void {
|
|
26
|
+
console.warn('WebSocket connected.');
|
|
27
|
+
this.#websocket.send(
|
|
28
|
+
JSON.stringify({jsonrpc: '2.0', method: 'session/new', params: {cwd: '.', mcpServers: []}, id: 14}));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
#onMessage(event: MessageEvent): void {
|
|
32
|
+
this.#messageLog.push(event.data);
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const data = JSON.parse(event.data);
|
|
36
|
+
|
|
37
|
+
if (data?.result?.sessionId && !this.#sessionId) {
|
|
38
|
+
this.#sessionId = data.result.sessionId;
|
|
39
|
+
console.warn(`Successfully created new session with ID: ${this.#sessionId}`);
|
|
40
|
+
if (this.#sessionReadyResolve) {
|
|
41
|
+
this.#sessionReadyResolve();
|
|
42
|
+
this.#sessionReadyResolve = null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const update = data?.params?.update;
|
|
47
|
+
if (update?.sessionUpdate === 'agent_message_chunk') {
|
|
48
|
+
this.#activeMessage += update.content?.text || '';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (data?.result?.stopReason) {
|
|
52
|
+
if (this.#activeMessage) {
|
|
53
|
+
console.warn(this.#activeMessage);
|
|
54
|
+
}
|
|
55
|
+
console.warn(`Stop Reason: ${data.result.stopReason}`, this.#messageLog);
|
|
56
|
+
|
|
57
|
+
if (this.#promptResolve) {
|
|
58
|
+
this.#promptResolve(this.#activeMessage);
|
|
59
|
+
this.#promptResolve = null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
this.#activeMessage = '';
|
|
63
|
+
this.#messageLog = [];
|
|
64
|
+
} else if (data?.method === 'session/request_permission') {
|
|
65
|
+
// TODO(finnur): Needs augmenting once I turn off YOLO in the bridge.
|
|
66
|
+
this.#websocket.send(JSON.stringify({
|
|
67
|
+
jsonrpc: '2.0',
|
|
68
|
+
id: data.id,
|
|
69
|
+
result: {
|
|
70
|
+
outcome: {
|
|
71
|
+
selected: {
|
|
72
|
+
optionId: 'proceed_always',
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
} catch (e) {
|
|
79
|
+
// Log the raw data if it's not valid JSON.
|
|
80
|
+
console.error('Failed to parse WebSocket message or process data:', event.data, e);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
#onClose(): void {
|
|
85
|
+
console.warn('WebSocket disconnected.');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
#onError(error: Event): void {
|
|
89
|
+
console.error('WebSocket error:', error);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
sendPrompt(promptText: string): Promise<string> {
|
|
93
|
+
return new Promise((resolve, reject) => {
|
|
94
|
+
if (this.#promptResolve) {
|
|
95
|
+
reject(new Error('Another prompt is already in progress.'));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (!this.#sessionId) {
|
|
99
|
+
reject(new Error('Cannot send prompt without a session ID.'));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
this.#promptResolve = resolve;
|
|
103
|
+
|
|
104
|
+
console.warn(`Sending prompt: "${promptText}"`);
|
|
105
|
+
console.warn('Thinking...');
|
|
106
|
+
this.#websocket.send(JSON.stringify({
|
|
107
|
+
jsonrpc: '2.0',
|
|
108
|
+
method: 'session/prompt',
|
|
109
|
+
params: {
|
|
110
|
+
prompt: [{type: 'text', text: promptText}],
|
|
111
|
+
sessionId: this.#sessionId,
|
|
112
|
+
},
|
|
113
|
+
id: 15,
|
|
114
|
+
}));
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -14,6 +14,7 @@ import * as Logs from '../../logs/logs.js';
|
|
|
14
14
|
import * as SourceMapScopes from '../../source_map_scopes/source_map_scopes.js';
|
|
15
15
|
import * as TextUtils from '../../text_utils/text_utils.js';
|
|
16
16
|
import * as Trace from '../../trace/trace.js';
|
|
17
|
+
import {sanitizeHeaders} from '../data_formatters/NetworkRequestFormatter.js';
|
|
17
18
|
import {
|
|
18
19
|
PerformanceInsightFormatter,
|
|
19
20
|
} from '../data_formatters/PerformanceInsightFormatter.js';
|
|
@@ -1060,7 +1061,35 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
|
1060
1061
|
}
|
|
1061
1062
|
|
|
1062
1063
|
// TODO(b/425270067): Format in the same way that "Summary" detail tab does.
|
|
1063
|
-
|
|
1064
|
+
let details;
|
|
1065
|
+
if (Trace.Types.Events.isSyntheticNetworkRequest(event)) {
|
|
1066
|
+
const eventToSerialize = {
|
|
1067
|
+
...event,
|
|
1068
|
+
args: {
|
|
1069
|
+
...event.args,
|
|
1070
|
+
data: {
|
|
1071
|
+
...event.args.data,
|
|
1072
|
+
responseHeaders: event.args.data.responseHeaders ? sanitizeHeaders(event.args.data.responseHeaders) :
|
|
1073
|
+
null,
|
|
1074
|
+
},
|
|
1075
|
+
},
|
|
1076
|
+
};
|
|
1077
|
+
details = JSON.stringify(eventToSerialize);
|
|
1078
|
+
} else if (Trace.Types.Events.isResourceReceiveResponse(event)) {
|
|
1079
|
+
const eventToSerialize = {
|
|
1080
|
+
...event,
|
|
1081
|
+
args: {
|
|
1082
|
+
...event.args,
|
|
1083
|
+
data: {
|
|
1084
|
+
...event.args.data,
|
|
1085
|
+
headers: event.args.data.headers ? sanitizeHeaders(event.args.data.headers) : undefined,
|
|
1086
|
+
},
|
|
1087
|
+
},
|
|
1088
|
+
};
|
|
1089
|
+
details = JSON.stringify(eventToSerialize);
|
|
1090
|
+
} else {
|
|
1091
|
+
details = JSON.stringify(event);
|
|
1092
|
+
}
|
|
1064
1093
|
|
|
1065
1094
|
const key = `getEventByKey('${params.eventKey}')`;
|
|
1066
1095
|
this.#cacheFunctionResult(focus, key, details);
|
|
@@ -10,6 +10,8 @@ import * as ContextSelectionAgent from './agents/ContextSelectionAgent.js';
|
|
|
10
10
|
import * as ConversationSummaryAgent from './agents/ConversationSummaryAgent.js';
|
|
11
11
|
import * as FileAgent from './agents/FileAgent.js';
|
|
12
12
|
import * as GreenDevAgent from './agents/GreenDevAgent.js';
|
|
13
|
+
import * as GreenDevAgentAntigravityCliSocketClient from './agents/GreenDevAgentAntigravityCliSocketClient.js';
|
|
14
|
+
import * as GreenDevAgentGeminiCliSocketClient from './agents/GreenDevAgentGeminiCliSocketClient.js';
|
|
13
15
|
import * as NetworkAgent from './agents/NetworkAgent.js';
|
|
14
16
|
import * as PatchAgent from './agents/PatchAgent.js';
|
|
15
17
|
import * as PerformanceAgent from './agents/PerformanceAgent.js';
|
|
@@ -57,6 +59,8 @@ export {
|
|
|
57
59
|
FileAgent,
|
|
58
60
|
FileFormatter,
|
|
59
61
|
GreenDevAgent,
|
|
62
|
+
GreenDevAgentAntigravityCliSocketClient,
|
|
63
|
+
GreenDevAgentGeminiCliSocketClient,
|
|
60
64
|
Injected,
|
|
61
65
|
LighthouseFormatter,
|
|
62
66
|
NetworkAgent,
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
5
|
import * as Common from '../../../core/common/common.js';
|
|
6
|
+
import type * as CrUXManager from '../../crux-manager/crux-manager.js';
|
|
6
7
|
import * as Trace from '../../trace/trace.js';
|
|
7
8
|
import type {ConversationSuggestions} from '../agents/AiAgent.js';
|
|
8
9
|
import type {AgentFocus} from '../performance/AIContext.js';
|
|
@@ -48,8 +49,9 @@ export class PerformanceInsightFormatter {
|
|
|
48
49
|
#insight: Trace.Insights.Types.InsightModel;
|
|
49
50
|
#parsedTrace: Trace.TraceModel.ParsedTrace;
|
|
50
51
|
|
|
51
|
-
constructor(
|
|
52
|
-
|
|
52
|
+
constructor(
|
|
53
|
+
focus: AgentFocus, insight: Trace.Insights.Types.InsightModel, deviceScope: CrUXManager.DeviceScope|null = null) {
|
|
54
|
+
this.#traceFormatter = new PerformanceTraceFormatter(focus, deviceScope);
|
|
53
55
|
this.#insight = insight;
|
|
54
56
|
this.#parsedTrace = focus.parsedTrace;
|
|
55
57
|
}
|
|
@@ -35,15 +35,17 @@ export class PerformanceTraceFormatter {
|
|
|
35
35
|
#insightSet: Trace.Insights.Types.InsightSet|null;
|
|
36
36
|
#eventsSerializer: Trace.EventsSerializer.EventsSerializer;
|
|
37
37
|
#formattedFunctionCodes = new Set<string>();
|
|
38
|
+
#deviceScope: CrUXManager.DeviceScope|null;
|
|
38
39
|
resolveFunctionCode?:
|
|
39
40
|
(url: Platform.DevToolsPath.UrlString, line: number,
|
|
40
41
|
column: number) => Promise<SourceMapScopes.FunctionCodeResolver.FunctionCode|null>;
|
|
41
42
|
|
|
42
|
-
constructor(focus: AgentFocus) {
|
|
43
|
+
constructor(focus: AgentFocus, deviceScope: CrUXManager.DeviceScope|null = null) {
|
|
43
44
|
this.#focus = focus;
|
|
44
45
|
this.#parsedTrace = focus.parsedTrace;
|
|
45
46
|
this.#insightSet = focus.primaryInsightSet;
|
|
46
47
|
this.#eventsSerializer = focus.eventsSerializer;
|
|
48
|
+
this.#deviceScope = deviceScope;
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
serializeEvent(event: Trace.Types.Events.Event): string {
|
|
@@ -64,7 +66,8 @@ export class PerformanceTraceFormatter {
|
|
|
64
66
|
return [];
|
|
65
67
|
}
|
|
66
68
|
try {
|
|
67
|
-
const cruxScope =
|
|
69
|
+
const cruxScope: CrUXManager.Scope = this.#deviceScope ? {pageScope: 'url', deviceScope: this.#deviceScope} :
|
|
70
|
+
CrUXManager.CrUXManager.instance().getSelectedScope();
|
|
68
71
|
const parts: string[] = [];
|
|
69
72
|
const fieldMetrics =
|
|
70
73
|
Trace.Insights.Common.getFieldMetricsForInsightSet(insightSet, this.#parsedTrace.metadata, cruxScope);
|
|
@@ -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 type * as Platform from '../../core/platform/platform.js';
|
|
6
|
+
|
|
5
7
|
import {PrivateAPI} from './ExtensionAPI.js';
|
|
6
8
|
import {ExtensionEndpoint} from './ExtensionEndpoint.js';
|
|
7
9
|
import {RecorderPluginManager} from './RecorderPluginManager.js';
|
|
@@ -10,20 +12,26 @@ export class RecorderExtensionEndpoint extends ExtensionEndpoint {
|
|
|
10
12
|
private readonly name: string;
|
|
11
13
|
private readonly mediaType?: string;
|
|
12
14
|
private readonly capabilities: PrivateAPI.RecordingExtensionPluginCapability[];
|
|
15
|
+
readonly #extensionOrigin: Platform.DevToolsPath.UrlString;
|
|
13
16
|
|
|
14
17
|
constructor(
|
|
15
18
|
name: string, port: MessagePort, capabilities: PrivateAPI.RecordingExtensionPluginCapability[],
|
|
16
|
-
mediaType?: string) {
|
|
19
|
+
extensionOrigin: Platform.DevToolsPath.UrlString, mediaType?: string) {
|
|
17
20
|
super(port);
|
|
18
21
|
this.name = name;
|
|
19
22
|
this.mediaType = mediaType;
|
|
20
23
|
this.capabilities = capabilities;
|
|
24
|
+
this.#extensionOrigin = extensionOrigin;
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
getName(): string {
|
|
24
28
|
return this.name;
|
|
25
29
|
}
|
|
26
30
|
|
|
31
|
+
getOrigin(): Platform.DevToolsPath.UrlString {
|
|
32
|
+
return this.#extensionOrigin;
|
|
33
|
+
}
|
|
34
|
+
|
|
27
35
|
getCapabilities(): PrivateAPI.RecordingExtensionPluginCapability[] {
|
|
28
36
|
return this.capabilities;
|
|
29
37
|
}
|
|
@@ -9,7 +9,8 @@ let instance: Prototypes|null = null;
|
|
|
9
9
|
|
|
10
10
|
export interface GreenDevSettings {
|
|
11
11
|
aiAnnotations: Common.Settings.Setting<boolean>;
|
|
12
|
-
|
|
12
|
+
beyondStylingGemini: Common.Settings.Setting<boolean>;
|
|
13
|
+
beyondStylingAntigravity: Common.Settings.Setting<boolean>;
|
|
13
14
|
breakpointDebuggerAgent: Common.Settings.Setting<boolean>;
|
|
14
15
|
emulationCapabilities: Common.Settings.Setting<boolean>;
|
|
15
16
|
}
|
|
@@ -42,10 +43,15 @@ export class Prototypes {
|
|
|
42
43
|
false,
|
|
43
44
|
Common.Settings.SettingStorageType.LOCAL,
|
|
44
45
|
);
|
|
45
|
-
const
|
|
46
|
-
'greendev-beyond-styling-enabled',
|
|
46
|
+
const beyondStylingGemini = settings.createSetting(
|
|
47
|
+
'greendev-beyond-styling-gemini-enabled',
|
|
47
48
|
false,
|
|
48
|
-
Common.Settings.SettingStorageType.
|
|
49
|
+
Common.Settings.SettingStorageType.GLOBAL,
|
|
50
|
+
);
|
|
51
|
+
const beyondStylingAntigravity = settings.createSetting(
|
|
52
|
+
'greendev-beyond-styling-antigravity-enabled',
|
|
53
|
+
false,
|
|
54
|
+
Common.Settings.SettingStorageType.GLOBAL,
|
|
49
55
|
);
|
|
50
56
|
const breakpointDebuggerAgent = settings.createSetting(
|
|
51
57
|
'greendev-breakpoint-debugger-agent-enabled',
|
|
@@ -58,6 +64,12 @@ export class Prototypes {
|
|
|
58
64
|
Common.Settings.SettingStorageType.LOCAL,
|
|
59
65
|
);
|
|
60
66
|
|
|
61
|
-
return {
|
|
67
|
+
return {
|
|
68
|
+
aiAnnotations,
|
|
69
|
+
beyondStylingGemini,
|
|
70
|
+
beyondStylingAntigravity,
|
|
71
|
+
breakpointDebuggerAgent,
|
|
72
|
+
emulationCapabilities
|
|
73
|
+
};
|
|
62
74
|
}
|
|
63
75
|
}
|
|
@@ -507,26 +507,28 @@ export class TimelineFrameBeginFrameQueue {
|
|
|
507
507
|
private queueFrames: number[] = [];
|
|
508
508
|
|
|
509
509
|
// Maps frameSeqId to BeginFrameInfo.
|
|
510
|
-
private mapFrames
|
|
510
|
+
private mapFrames = new Map<number, BeginFrameInfo>();
|
|
511
511
|
|
|
512
512
|
// Add a BeginFrame to the queue, if it does not already exit.
|
|
513
513
|
addFrameIfNotExists(seqId: number, startTime: Types.Timing.Micro, isDropped: boolean, isPartial: boolean): void {
|
|
514
|
-
if (!
|
|
515
|
-
this.mapFrames
|
|
514
|
+
if (!this.mapFrames.has(seqId)) {
|
|
515
|
+
this.mapFrames.set(seqId, new BeginFrameInfo(seqId, startTime, isDropped, isPartial));
|
|
516
516
|
this.queueFrames.push(seqId);
|
|
517
517
|
}
|
|
518
518
|
}
|
|
519
519
|
|
|
520
520
|
// Set a BeginFrame in queue as dropped.
|
|
521
521
|
setDropped(seqId: number, isDropped: boolean): void {
|
|
522
|
-
|
|
523
|
-
|
|
522
|
+
const frame = this.mapFrames.get(seqId);
|
|
523
|
+
if (frame) {
|
|
524
|
+
frame.isDropped = isDropped;
|
|
524
525
|
}
|
|
525
526
|
}
|
|
526
527
|
|
|
527
528
|
setPartial(seqId: number, isPartial: boolean): void {
|
|
528
|
-
|
|
529
|
-
|
|
529
|
+
const frame = this.mapFrames.get(seqId);
|
|
530
|
+
if (frame) {
|
|
531
|
+
frame.isPartial = isPartial;
|
|
530
532
|
}
|
|
531
533
|
}
|
|
532
534
|
|
|
@@ -535,7 +537,7 @@ export class TimelineFrameBeginFrameQueue {
|
|
|
535
537
|
|
|
536
538
|
// Do not visualize this frame in the rare case where the current DrawFrame
|
|
537
539
|
// does not have a corresponding BeginFrame.
|
|
538
|
-
if (
|
|
540
|
+
if (this.mapFrames.has(seqId)) {
|
|
539
541
|
// Pop all BeginFrames before the current frame, and add only the dropped
|
|
540
542
|
// ones in |frames_to_visualize|.
|
|
541
543
|
// Non-dropped frames popped here are BeginFrames that are never
|
|
@@ -544,17 +546,21 @@ export class TimelineFrameBeginFrameQueue {
|
|
|
544
546
|
// be naturally presented as continuationss of other frames.
|
|
545
547
|
while (this.queueFrames[0] !== seqId) {
|
|
546
548
|
const currentSeqId = this.queueFrames[0];
|
|
547
|
-
|
|
548
|
-
|
|
549
|
+
const currentFrame = this.mapFrames.get(currentSeqId);
|
|
550
|
+
if (currentFrame && currentFrame.isDropped) {
|
|
551
|
+
framesToVisualize.push(currentFrame);
|
|
549
552
|
}
|
|
550
553
|
|
|
551
|
-
|
|
554
|
+
this.mapFrames.delete(currentSeqId);
|
|
552
555
|
this.queueFrames.shift();
|
|
553
556
|
}
|
|
554
557
|
|
|
555
558
|
// Pop the BeginFrame associated with the current DrawFrame.
|
|
556
|
-
|
|
557
|
-
|
|
559
|
+
const frame = this.mapFrames.get(seqId);
|
|
560
|
+
if (frame) {
|
|
561
|
+
framesToVisualize.push(frame);
|
|
562
|
+
}
|
|
563
|
+
this.mapFrames.delete(seqId);
|
|
558
564
|
this.queueFrames.shift();
|
|
559
565
|
}
|
|
560
566
|
return framesToVisualize;
|
|
@@ -123,6 +123,9 @@ export class AccessibilityAgentMarkdownRenderer extends MarkdownRendererWithCode
|
|
|
123
123
|
if (!node) {
|
|
124
124
|
return;
|
|
125
125
|
}
|
|
126
|
+
if (node.frameId() !== this.mainFrameId) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
126
129
|
const linkedNode = PanelsCommon.DOMLinkifier.Linkifier.instance().linkify(node, {textContent: label});
|
|
127
130
|
return linkedNode;
|
|
128
131
|
}
|
|
@@ -530,9 +530,11 @@ export class ChatInput extends UI.Widget.Widget implements SDK.TargetManager.Obs
|
|
|
530
530
|
|
|
531
531
|
setInputValue(text: string): void {
|
|
532
532
|
if (this.#textAreaRef.value) {
|
|
533
|
-
this.#textAreaRef.value.
|
|
533
|
+
const maxLength = this.#textAreaRef.value.maxLength;
|
|
534
|
+
const truncatedText = (maxLength >= 0) ? text.substring(0, maxLength) : text;
|
|
535
|
+
this.#textAreaRef.value.value = truncatedText;
|
|
534
536
|
// Place the cursor at the end of the new value.
|
|
535
|
-
this.#textAreaRef.value.setSelectionRange(
|
|
537
|
+
this.#textAreaRef.value.setSelectionRange(truncatedText.length, truncatedText.length);
|
|
536
538
|
}
|
|
537
539
|
this.performUpdate();
|
|
538
540
|
}
|