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.
Files changed (107) hide show
  1. package/front_end/core/host/UserMetrics.ts +5 -2
  2. package/front_end/core/root/ExperimentNames.ts +1 -0
  3. package/front_end/core/root/Runtime.ts +5 -0
  4. package/front_end/core/sdk/SourceMapCache.ts +13 -11
  5. package/front_end/core/sdk/SourceMapManager.ts +7 -3
  6. package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +84 -22
  7. package/front_end/entrypoints/main/MainImpl.ts +8 -0
  8. package/front_end/generated/InspectorBackendCommands.ts +3 -4
  9. package/front_end/generated/SupportedCSSProperties.js +272 -2
  10. package/front_end/generated/protocol-mapping.d.ts +0 -10
  11. package/front_end/generated/protocol-proxy-api.d.ts +0 -8
  12. package/front_end/generated/protocol.ts +5 -7
  13. package/front_end/models/ai_assistance/AiConversation.ts +16 -11
  14. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +13 -2
  15. package/front_end/models/ai_assistance/agents/AiAgent.ts +65 -11
  16. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +42 -2
  17. package/front_end/models/ai_assistance/agents/GreenDevAgent.ts +68 -5
  18. package/front_end/models/ai_assistance/agents/GreenDevAgentAntigravityCliSocketClient.ts +53 -0
  19. package/front_end/models/ai_assistance/agents/GreenDevAgentGeminiCliSocketClient.ts +117 -0
  20. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +30 -1
  21. package/front_end/models/ai_assistance/ai_assistance.ts +4 -0
  22. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +4 -2
  23. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +5 -2
  24. package/front_end/models/extensions/RecorderExtensionEndpoint.ts +9 -1
  25. package/front_end/models/extensions/RecorderPluginManager.ts +1 -0
  26. package/front_end/models/greendev/Prototypes.ts +17 -5
  27. package/front_end/models/trace/handlers/FramesHandler.ts +19 -13
  28. package/front_end/panels/ai_assistance/components/AccessibilityAgentMarkdownRenderer.ts +3 -0
  29. package/front_end/panels/ai_assistance/components/ChatInput.ts +4 -2
  30. package/front_end/panels/ai_assistance/components/ChatMessage.ts +3 -1
  31. package/front_end/panels/application/preloading/components/PreloadingString.ts +0 -8
  32. package/front_end/panels/common/ExtensionServer.ts +34 -11
  33. package/front_end/panels/elements/CSSRuleValidator.ts +37 -34
  34. package/front_end/panels/elements/CSSRuleValidatorHelper.ts +8 -6
  35. package/front_end/panels/elements/ElementsTreeElement.ts +8 -2
  36. package/front_end/panels/elements/components/CSSHintDetailsView.ts +5 -5
  37. package/front_end/panels/js_timeline/js_timeline-meta.ts +30 -0
  38. package/front_end/panels/protocol_monitor/JSONEditor.ts +4 -4
  39. package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +2 -2
  40. package/front_end/panels/recorder/RecorderController.ts +50 -1
  41. package/front_end/panels/recorder/extensions/ExtensionManager.ts +1 -0
  42. package/front_end/panels/recorder/models/RecordingPlayer.ts +12 -3
  43. package/front_end/panels/recorder/testing/RecorderHelpers.ts +2 -0
  44. package/front_end/panels/settings/SettingsScreen.ts +3 -2
  45. package/front_end/panels/sources/FilteredUISourceCodeListProvider.ts +5 -2
  46. package/front_end/panels/timeline/timeline-meta.ts +10 -6
  47. package/front_end/panels/whats_new/ReleaseNoteText.ts +9 -9
  48. package/front_end/panels/whats_new/resources/WNDT.md +9 -9
  49. package/front_end/third_party/chromium/README.chromium +1 -1
  50. package/front_end/third_party/puppeteer/README.chromium +2 -2
  51. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +8 -5
  52. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +35 -33
  53. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/TargetManager.d.ts.map +1 -1
  54. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/TargetManager.js +0 -1
  55. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/TargetManager.js.map +1 -1
  56. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/WebMCP.d.ts.map +1 -1
  57. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/WebMCP.js +0 -3
  58. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/WebMCP.js.map +1 -1
  59. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.d.ts +8 -8
  60. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.d.ts.map +1 -1
  61. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.js +8 -8
  62. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.js.map +1 -1
  63. package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.d.ts +1 -1
  64. package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.d.ts.map +1 -1
  65. package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.js +1 -1
  66. package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.js.map +1 -1
  67. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/CustomQuerySelector.d.ts +2 -2
  68. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/CustomQuerySelector.d.ts.map +1 -1
  69. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/CustomQuerySelector.js +2 -1
  70. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/CustomQuerySelector.js.map +1 -1
  71. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/injected.d.ts +2 -7
  72. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/injected.d.ts.map +1 -1
  73. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/PuppeteerNode.d.ts +1 -1
  74. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/PuppeteerNode.js +1 -1
  75. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.d.ts +3 -3
  76. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js +3 -3
  77. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js.map +1 -1
  78. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/Mutex.d.ts +10 -7
  79. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/Mutex.d.ts.map +1 -1
  80. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/Mutex.js +16 -12
  81. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/Mutex.js.map +1 -1
  82. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.d.ts +1 -1
  83. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.js +1 -1
  84. package/front_end/third_party/puppeteer/package/lib/types.d.ts +8 -5
  85. package/front_end/third_party/puppeteer/package/package.json +5 -7
  86. package/front_end/third_party/puppeteer/package/src/cdp/TargetManager.ts +0 -1
  87. package/front_end/third_party/puppeteer/package/src/cdp/WebMCP.ts +0 -3
  88. package/front_end/third_party/puppeteer/package/src/common/Debug.ts +11 -11
  89. package/front_end/third_party/puppeteer/package/src/generated/injected.ts +1 -1
  90. package/front_end/third_party/puppeteer/package/src/injected/CustomQuerySelector.ts +3 -2
  91. package/front_end/third_party/puppeteer/package/src/node/PuppeteerNode.ts +1 -1
  92. package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
  93. package/front_end/third_party/puppeteer/package/src/util/Mutex.ts +17 -12
  94. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  95. package/front_end/ui/components/markdown_view/MarkdownLinksMap.ts +7 -0
  96. package/front_end/ui/legacy/InspectorDrawerView.ts +2 -1
  97. package/front_end/ui/legacy/InspectorView.ts +1 -1
  98. package/front_end/ui/legacy/PlusButton.ts +269 -0
  99. package/front_end/ui/legacy/ViewManager.ts +38 -11
  100. package/front_end/ui/legacy/components/source_frame/FontView.ts +11 -3
  101. package/front_end/ui/legacy/components/source_frame/ImageView.ts +16 -0
  102. package/front_end/ui/legacy/components/source_frame/imageView.css +13 -0
  103. package/front_end/ui/legacy/components/utils/Linkifier.ts +1 -1
  104. package/front_end/ui/legacy/legacy.ts +2 -0
  105. package/front_end/ui/visual_logging/KnownContextValues.ts +21 -0
  106. package/mcp/mcp.ts +1 -1
  107. 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 file = ContextSelectionAgent.getUISourceCodes().find(
276
- file => ContextSelectionAgent.uiSourceCodeId.get(file) === params.id);
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, explain the likely root
57
- cause to the user and suggest a concrete fix or next step. If you suspect an issue in a
58
- JavaScript function, point it out.
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
- console.warn('BeyondStyling prototype is enabled:', Greendev.Prototypes.instance().isEnabled('beyondStyling'));
381
- return Greendev.Prototypes.instance().isEnabled('beyondStyling');
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
- const details = JSON.stringify(event);
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(focus: AgentFocus, insight: Trace.Insights.Types.InsightModel) {
52
- this.#traceFormatter = new PerformanceTraceFormatter(focus);
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 = CrUXManager.CrUXManager.instance().getSelectedScope();
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
  }
@@ -14,6 +14,7 @@ export interface ViewDescriptor {
14
14
  pagePath: string;
15
15
  onShown: () => void;
16
16
  onHidden: () => void;
17
+ extensionOrigin: string;
17
18
  }
18
19
 
19
20
  export class RecorderPluginManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
@@ -9,7 +9,8 @@ let instance: Prototypes|null = null;
9
9
 
10
10
  export interface GreenDevSettings {
11
11
  aiAnnotations: Common.Settings.Setting<boolean>;
12
- beyondStyling: Common.Settings.Setting<boolean>;
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 beyondStyling = settings.createSetting(
46
- 'greendev-beyond-styling-enabled',
46
+ const beyondStylingGemini = settings.createSetting(
47
+ 'greendev-beyond-styling-gemini-enabled',
47
48
  false,
48
- Common.Settings.SettingStorageType.LOCAL,
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 {aiAnnotations, beyondStyling, breakpointDebuggerAgent, emulationCapabilities};
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: Record<number, BeginFrameInfo> = {};
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 (!(seqId in this.mapFrames)) {
515
- this.mapFrames[seqId] = new BeginFrameInfo(seqId, startTime, isDropped, isPartial);
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
- if (seqId in this.mapFrames) {
523
- this.mapFrames[seqId].isDropped = isDropped;
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
- if (seqId in this.mapFrames) {
529
- this.mapFrames[seqId].isPartial = isPartial;
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 (seqId in this.mapFrames) {
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
- if (this.mapFrames[currentSeqId].isDropped) {
548
- framesToVisualize.push(this.mapFrames[currentSeqId]);
549
+ const currentFrame = this.mapFrames.get(currentSeqId);
550
+ if (currentFrame && currentFrame.isDropped) {
551
+ framesToVisualize.push(currentFrame);
549
552
  }
550
553
 
551
- delete this.mapFrames[currentSeqId];
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
- framesToVisualize.push(this.mapFrames[seqId]);
557
- delete this.mapFrames[seqId];
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.value = text;
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(text.length, text.length);
537
+ this.#textAreaRef.value.setSelectionRange(truncatedText.length, truncatedText.length);
536
538
  }
537
539
  this.performUpdate();
538
540
  }