chrome-devtools-frontend 1.0.1635648 → 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/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/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/ai_assistance.ts +4 -0
- package/front_end/models/greendev/Prototypes.ts +17 -5
- package/front_end/panels/settings/SettingsScreen.ts +3 -2
- 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/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/components/source_frame/FontView.ts +11 -3
- package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
- package/package.json +1 -10
|
@@ -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 '../platform/platform.js';
|
|
6
|
+
|
|
5
7
|
import type {DebugId, SourceMapV3} from './SourceMap.js';
|
|
6
8
|
|
|
7
9
|
/** A thin wrapper around the Cache API to store source map JSONs keyed on Debug IDs */
|
|
@@ -28,14 +30,14 @@ export class SourceMapCache {
|
|
|
28
30
|
this.#name = name;
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
async set(debugId: DebugId, sourceMap: SourceMapV3): Promise<void> {
|
|
33
|
+
async set(debugId: DebugId, securityOrigin: Platform.DevToolsPath.UrlString, sourceMap: SourceMapV3): Promise<void> {
|
|
32
34
|
const cache = await this.#cache();
|
|
33
|
-
await cache.put(SourceMapCache.#urlForDebugId(debugId), new Response(JSON.stringify(sourceMap)));
|
|
35
|
+
await cache.put(SourceMapCache.#urlForDebugId(debugId, securityOrigin), new Response(JSON.stringify(sourceMap)));
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
async get(debugId: DebugId): Promise<SourceMapV3|null> {
|
|
38
|
+
async get(debugId: DebugId, securityOrigin: Platform.DevToolsPath.UrlString): Promise<SourceMapV3|null> {
|
|
37
39
|
const cache = await this.#cache();
|
|
38
|
-
const response = await cache.match(SourceMapCache.#urlForDebugId(debugId));
|
|
40
|
+
const response = await cache.match(SourceMapCache.#urlForDebugId(debugId, securityOrigin));
|
|
39
41
|
return await response?.json() ?? null;
|
|
40
42
|
}
|
|
41
43
|
|
|
@@ -49,8 +51,8 @@ export class SourceMapCache {
|
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
/** The Cache API only allows URL as keys, so we construct a simple one. Given that we have our own cache, we have no risk of conflicting URLs */
|
|
52
|
-
static #urlForDebugId(debugId: DebugId): string {
|
|
53
|
-
return
|
|
54
|
+
static #urlForDebugId(debugId: DebugId, securityOrigin: Platform.DevToolsPath.UrlString): string {
|
|
55
|
+
return `http://debug.id/${encodeURIComponent(debugId)}?origin=${encodeURIComponent(securityOrigin)}`;
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
async disposeForTest(): Promise<void> {
|
|
@@ -59,14 +61,14 @@ export class SourceMapCache {
|
|
|
59
61
|
}
|
|
60
62
|
|
|
61
63
|
const IN_MEMORY_INSTANCE = new (class implements Pick<SourceMapCache, 'get'|'set'|'disposeForTest'> {
|
|
62
|
-
readonly #cache = new Map<
|
|
64
|
+
readonly #cache = new Map<string, SourceMapV3>();
|
|
63
65
|
|
|
64
|
-
async set(debugId: DebugId, sourceMap: SourceMapV3): Promise<void> {
|
|
65
|
-
this.#cache.set(debugId
|
|
66
|
+
async set(debugId: DebugId, securityOrigin: Platform.DevToolsPath.UrlString, sourceMap: SourceMapV3): Promise<void> {
|
|
67
|
+
this.#cache.set(`${debugId}|${securityOrigin}`, sourceMap);
|
|
66
68
|
}
|
|
67
69
|
|
|
68
|
-
async get(debugId: DebugId): Promise<SourceMapV3|null> {
|
|
69
|
-
return this.#cache.get(debugId) ?? null;
|
|
70
|
+
async get(debugId: DebugId, securityOrigin: Platform.DevToolsPath.UrlString): Promise<SourceMapV3|null> {
|
|
71
|
+
return this.#cache.get(`${debugId}|${securityOrigin}`) ?? null;
|
|
70
72
|
}
|
|
71
73
|
|
|
72
74
|
async disposeForTest(): Promise<void> {
|
|
@@ -190,7 +190,9 @@ async function loadSourceMap(
|
|
|
190
190
|
initiator: PageResourceLoadInitiator): Promise<SourceMapV3> {
|
|
191
191
|
try {
|
|
192
192
|
if (debugId) {
|
|
193
|
-
const
|
|
193
|
+
const securityOrigin = initiator.initiatorUrl ? Common.ParsedURL.ParsedURL.extractOrigin(initiator.initiatorUrl) :
|
|
194
|
+
Platform.DevToolsPath.EmptyUrlString;
|
|
195
|
+
const cachedSourceMap = await SourceMapCache.instance().get(debugId, securityOrigin);
|
|
194
196
|
if (cachedSourceMap) {
|
|
195
197
|
return cachedSourceMap;
|
|
196
198
|
}
|
|
@@ -198,9 +200,11 @@ async function loadSourceMap(
|
|
|
198
200
|
|
|
199
201
|
const {content} = await resourceLoader.loadResource(url, initiator);
|
|
200
202
|
const sourceMap = parseSourceMap(content);
|
|
201
|
-
if ('debugId' in sourceMap && sourceMap.debugId) {
|
|
203
|
+
if (debugId && 'debugId' in sourceMap && sourceMap.debugId === debugId) {
|
|
202
204
|
// In case something goes wrong with updating the cache, we still want to use the source map.
|
|
203
|
-
|
|
205
|
+
const securityOrigin = initiator.initiatorUrl ? Common.ParsedURL.ParsedURL.extractOrigin(initiator.initiatorUrl) :
|
|
206
|
+
Platform.DevToolsPath.EmptyUrlString;
|
|
207
|
+
await SourceMapCache.instance().set(sourceMap.debugId as DebugId, securityOrigin, sourceMap).catch();
|
|
204
208
|
}
|
|
205
209
|
return sourceMap;
|
|
206
210
|
} catch (cause) {
|
|
@@ -45,6 +45,9 @@ class GreenDevFloaty {
|
|
|
45
45
|
#backendNodeId?: Protocol.DOM.BackendNodeId;
|
|
46
46
|
#syncChannel: BroadcastChannel;
|
|
47
47
|
#isFloatyWindow: boolean;
|
|
48
|
+
#socketClient:
|
|
49
|
+
AiAssistance.GreenDevAgentAntigravityCliSocketClient.GreenDevAgentAntigravityCliSocketClient|
|
|
50
|
+
AiAssistance.GreenDevAgentGeminiCliSocketClient.GreenDevAgentGeminiCliSocketClient;
|
|
48
51
|
|
|
49
52
|
constructor(document: Document) {
|
|
50
53
|
const params = new URLSearchParams(window.location.hash.substring(1));
|
|
@@ -57,6 +60,12 @@ class GreenDevFloaty {
|
|
|
57
60
|
};
|
|
58
61
|
|
|
59
62
|
this.#initFloatyMode(document);
|
|
63
|
+
if (Greendev.Prototypes.instance().isEnabled('beyondStylingAntigravity')) {
|
|
64
|
+
this.#socketClient =
|
|
65
|
+
new AiAssistance.GreenDevAgentAntigravityCliSocketClient.GreenDevAgentAntigravityCliSocketClient();
|
|
66
|
+
} else {
|
|
67
|
+
this.#socketClient = new AiAssistance.GreenDevAgentGeminiCliSocketClient.GreenDevAgentGeminiCliSocketClient();
|
|
68
|
+
}
|
|
60
69
|
}
|
|
61
70
|
|
|
62
71
|
#initFloatyMode(doc: Document): void {
|
|
@@ -269,12 +278,67 @@ class GreenDevFloaty {
|
|
|
269
278
|
const query = this.#textField.value || this.#textField.placeholder;
|
|
270
279
|
this.#textField.value = '';
|
|
271
280
|
|
|
272
|
-
const
|
|
281
|
+
const useAntigravity = Greendev.Prototypes.instance().isEnabled('beyondStylingAntigravity');
|
|
282
|
+
const useGemini = Greendev.Prototypes.instance().isEnabled('beyondStylingGemini');
|
|
283
|
+
const useGreenDevAgent = useAntigravity || useGemini;
|
|
284
|
+
const isAntigravity = useAntigravity;
|
|
273
285
|
|
|
274
286
|
if (!this.#agent) {
|
|
275
287
|
const aidaClient = new AidaClient();
|
|
276
288
|
if (useGreenDevAgent) {
|
|
289
|
+
if (isAntigravity) {
|
|
290
|
+
this.#socketClient =
|
|
291
|
+
new AiAssistance.GreenDevAgentAntigravityCliSocketClient.GreenDevAgentAntigravityCliSocketClient();
|
|
292
|
+
} else {
|
|
293
|
+
this.#socketClient = new AiAssistance.GreenDevAgentGeminiCliSocketClient.GreenDevAgentGeminiCliSocketClient();
|
|
294
|
+
}
|
|
295
|
+
|
|
277
296
|
this.#agent = new AiAssistance.GreenDevAgent.GreenDevAgent({aidaClient});
|
|
297
|
+
this.#agent.addEventListener(
|
|
298
|
+
AiAssistance.GreenDevAgent.Events.CLI_PROMPT_REQUESTED,
|
|
299
|
+
async (
|
|
300
|
+
event: Common.EventTarget.EventTargetEvent<
|
|
301
|
+
AiAssistance.GreenDevAgent.EventTypes[AiAssistance.GreenDevAgent.Events.CLI_PROMPT_REQUESTED]>) => {
|
|
302
|
+
const {prompt} = event.data;
|
|
303
|
+
const remoteName = isAntigravity ? 'Antigravity' : 'Gemini';
|
|
304
|
+
const aiContent =
|
|
305
|
+
this.#addMessageInternal(`Fix has been submitted to ${remoteName} CLI, please wait...`, false);
|
|
306
|
+
|
|
307
|
+
if (isAntigravity) {
|
|
308
|
+
let fullResponse = '';
|
|
309
|
+
void (
|
|
310
|
+
this.#socketClient as
|
|
311
|
+
AiAssistance.GreenDevAgentAntigravityCliSocketClient.GreenDevAgentAntigravityCliSocketClient)
|
|
312
|
+
.sendPrompt(prompt, (chunk: string) => {
|
|
313
|
+
fullResponse += chunk;
|
|
314
|
+
const responseText = `Antigravity CLI responds: ${fullResponse}`;
|
|
315
|
+
const markdown = new MarkdownView.MarkdownView.MarkdownView();
|
|
316
|
+
markdown.data = {
|
|
317
|
+
tokens: Marked.Marked.lexer(responseText),
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
const style = document.createElement('style');
|
|
321
|
+
style.textContent =
|
|
322
|
+
'.message { font-size: 1.0rem; } .message code { font-size: 1.0rem; font-family: \'Roboto Mono\', ' +
|
|
323
|
+
'monospace; color: green; } .message ul { margin-left: 20px; }';
|
|
324
|
+
markdown.shadowRoot?.appendChild(style);
|
|
325
|
+
|
|
326
|
+
this.#updateAiMessage(aiContent, markdown, responseText);
|
|
327
|
+
});
|
|
328
|
+
} else {
|
|
329
|
+
const response =
|
|
330
|
+
await (this.#socketClient as
|
|
331
|
+
AiAssistance.GreenDevAgentGeminiCliSocketClient.GreenDevAgentGeminiCliSocketClient)
|
|
332
|
+
.sendPrompt(prompt);
|
|
333
|
+
|
|
334
|
+
const responseText = `Gemini CLI responds: ${response}`;
|
|
335
|
+
const markdown = new MarkdownView.MarkdownView.MarkdownView();
|
|
336
|
+
markdown.data = {
|
|
337
|
+
tokens: Marked.Marked.lexer(responseText),
|
|
338
|
+
};
|
|
339
|
+
this.#updateAiMessage(aiContent, markdown, responseText);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
278
342
|
} else {
|
|
279
343
|
this.#agent = new AiAssistance.StylingAgent.StylingAgent({aidaClient});
|
|
280
344
|
this.#nodeContext = new AiAssistance.StylingAgent.NodeContext(this.#node);
|
|
@@ -282,22 +346,7 @@ class GreenDevFloaty {
|
|
|
282
346
|
}
|
|
283
347
|
|
|
284
348
|
this.#addMessageInternal(query, true);
|
|
285
|
-
this.#syncChannel.postMessage({
|
|
286
|
-
type: 'new-message',
|
|
287
|
-
text: query,
|
|
288
|
-
isUser: true,
|
|
289
|
-
sessionId: this.#backendNodeId,
|
|
290
|
-
nodeDescription: document.querySelector('.green-dev-floaty-dialog-node-description')?.textContent,
|
|
291
|
-
});
|
|
292
|
-
|
|
293
349
|
const aiContent = this.#addMessageInternal('Thinking...', false);
|
|
294
|
-
this.#syncChannel.postMessage({
|
|
295
|
-
type: 'new-message',
|
|
296
|
-
text: 'Thinking...',
|
|
297
|
-
isUser: false,
|
|
298
|
-
sessionId: this.#backendNodeId,
|
|
299
|
-
nodeDescription: document.querySelector('.green-dev-floaty-dialog-node-description')?.textContent,
|
|
300
|
-
});
|
|
301
350
|
|
|
302
351
|
let agentFinished = false;
|
|
303
352
|
let steps = 0;
|
|
@@ -433,7 +482,8 @@ ${axTree}`;
|
|
|
433
482
|
markdown.data = {
|
|
434
483
|
tokens: Marked.Marked.lexer(sanitizedText),
|
|
435
484
|
};
|
|
436
|
-
aiContent.
|
|
485
|
+
this.#updateAiMessage(aiContent, markdown, result.text);
|
|
486
|
+
|
|
437
487
|
void new Promise(resolve => setTimeout(resolve, 0)).then(() => {
|
|
438
488
|
const style = document.createElement('style');
|
|
439
489
|
style.textContent =
|
|
@@ -456,15 +506,12 @@ ${axTree}`;
|
|
|
456
506
|
}
|
|
457
507
|
}
|
|
458
508
|
});
|
|
459
|
-
this.#syncChannel.postMessage(
|
|
460
|
-
{type: 'update-last-message', text: result.text, sessionId: this.#backendNodeId});
|
|
461
509
|
agentFinished = true;
|
|
462
510
|
break;
|
|
463
511
|
}
|
|
464
512
|
case ResponseType.ERROR:
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
{type: 'update-last-message', text: this.#formatError(result.error), sessionId: this.#backendNodeId});
|
|
513
|
+
this.#updateAiMessage(
|
|
514
|
+
aiContent, document.createTextNode(this.#formatError(result.error)), this.#formatError(result.error));
|
|
468
515
|
agentFinished = true;
|
|
469
516
|
break;
|
|
470
517
|
case ResponseType.SIDE_EFFECT:
|
|
@@ -503,8 +550,23 @@ ${axTree}`;
|
|
|
503
550
|
this.#chatContainer.appendChild(messageElement);
|
|
504
551
|
this.#chatContainer.scrollTop = this.#chatContainer.scrollHeight;
|
|
505
552
|
}
|
|
553
|
+
|
|
554
|
+
this.#syncChannel.postMessage({
|
|
555
|
+
type: 'new-message',
|
|
556
|
+
text,
|
|
557
|
+
isUser,
|
|
558
|
+
sessionId: this.#backendNodeId,
|
|
559
|
+
nodeDescription: document.querySelector('.green-dev-floaty-dialog-node-description')?.textContent,
|
|
560
|
+
});
|
|
561
|
+
|
|
506
562
|
return content;
|
|
507
563
|
}
|
|
564
|
+
|
|
565
|
+
#updateAiMessage(aiContentElement: HTMLDivElement, newContent: Node, newText: string): void {
|
|
566
|
+
aiContentElement.textContent = '';
|
|
567
|
+
aiContentElement.append(newContent);
|
|
568
|
+
this.#syncChannel.postMessage({type: 'update-last-message', text: newText, sessionId: this.#backendNodeId});
|
|
569
|
+
}
|
|
508
570
|
}
|
|
509
571
|
|
|
510
572
|
let greenDevFloatyInstance: GreenDevFloaty;
|
|
@@ -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
|
+
}
|
|
@@ -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,
|
|
@@ -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
|
}
|
|
@@ -636,7 +636,7 @@ const GREENDEV_VIEW: View = (input, _output, target) => {
|
|
|
636
636
|
<span>${i18nString(UIStrings.greenDevUnstable)}</span>
|
|
637
637
|
</div>
|
|
638
638
|
<div class="settings-experiments-block">
|
|
639
|
-
${renderPrototypeCheckboxes(input.settings, ['aiAnnotations', '
|
|
639
|
+
${renderPrototypeCheckboxes(input.settings, ['aiAnnotations', 'beyondStylingGemini', 'beyondStylingAntigravity', 'breakpointDebuggerAgent', 'emulationCapabilities'])}
|
|
640
640
|
</div>
|
|
641
641
|
</devtools-card>
|
|
642
642
|
</div>
|
|
@@ -646,7 +646,8 @@ const GREENDEV_VIEW: View = (input, _output, target) => {
|
|
|
646
646
|
|
|
647
647
|
const GREENDEV_PROTOTYPE_NAMES: Record<keyof GreenDev.GreenDevSettings, string> = {
|
|
648
648
|
aiAnnotations: 'AI auto-annotations',
|
|
649
|
-
|
|
649
|
+
beyondStylingGemini: 'Beyond Styling (Gemini CLI)',
|
|
650
|
+
beyondStylingAntigravity: 'Beyond Styling (Antigravity CLI)',
|
|
650
651
|
breakpointDebuggerAgent: 'Breakpoint Debugger Agent',
|
|
651
652
|
emulationCapabilities: 'Emulation Capabilities',
|
|
652
653
|
};
|
|
@@ -40,22 +40,22 @@ export function getReleaseNote(): ReleaseNote {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
let releaseNote: ReleaseNote = {
|
|
43
|
-
version:
|
|
44
|
-
header: 'What
|
|
43
|
+
version: 149,
|
|
44
|
+
header: 'What’s new in DevTools 149',
|
|
45
45
|
markdownLinks: [
|
|
46
46
|
{
|
|
47
|
-
key: '
|
|
48
|
-
link: 'https://developer.chrome.com/blog/new-in-devtools-
|
|
47
|
+
key: 'devtools-for-agents',
|
|
48
|
+
link: 'https://developer.chrome.com/blog/new-in-devtools-149/#devtools-for-agents',
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
|
-
key: '
|
|
52
|
-
link: 'https://developer.chrome.com/blog/new-in-devtools-
|
|
51
|
+
key: 'ai-assistance',
|
|
52
|
+
link: 'https://developer.chrome.com/blog/new-in-devtools-149/#ai-assistance',
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
|
-
key: '
|
|
56
|
-
link: 'https://developer.chrome.com/blog/new-in-devtools-
|
|
55
|
+
key: 'css-code-completion',
|
|
56
|
+
link: 'https://developer.chrome.com/blog/new-in-devtools-149/#css-code-completion',
|
|
57
57
|
}
|
|
58
58
|
],
|
|
59
59
|
videoLinks: [],
|
|
60
|
-
link: 'https://developer.chrome.com/blog/new-in-devtools-
|
|
60
|
+
link: 'https://developer.chrome.com/blog/new-in-devtools-149/',
|
|
61
61
|
};
|