chrome-devtools-frontend 1.0.1541552 → 1.0.1542501

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 (39) hide show
  1. package/docs/get_the_code.md +9 -0
  2. package/front_end/Tests.js +1 -0
  3. package/front_end/core/common/Settings.ts +38 -15
  4. package/front_end/core/host/UserMetrics.ts +5 -0
  5. package/front_end/core/sdk/IOModel.ts +1 -4
  6. package/front_end/core/sdk/ServerSentEventsProtocol.ts +4 -0
  7. package/front_end/entrypoints/main/MainImpl.ts +6 -3
  8. package/front_end/foundation/Universe.ts +2 -10
  9. package/front_end/generated/SupportedCSSProperties.js +42 -42
  10. package/front_end/models/ai_code_completion/AiCodeCompletion.ts +72 -31
  11. package/front_end/models/har/Importer.ts +14 -0
  12. package/front_end/models/issues_manager/IssuesManager.ts +0 -5
  13. package/front_end/models/javascript_metadata/NativeFunctions.js +0 -4
  14. package/front_end/models/trace/handlers/ScriptsHandler.ts +26 -0
  15. package/front_end/models/trace/types/TraceEvents.ts +1 -1
  16. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +117 -103
  17. package/front_end/panels/ai_assistance/components/ChatView.ts +7 -31
  18. package/front_end/panels/ai_assistance/components/chatView.css +1 -1
  19. package/front_end/panels/console/ConsoleInsightTeaser.ts +5 -0
  20. package/front_end/panels/console/ConsolePrompt.ts +8 -1
  21. package/front_end/panels/sources/AiCodeCompletionPlugin.ts +17 -1
  22. package/front_end/third_party/chromium/README.chromium +1 -1
  23. package/front_end/ui/components/markdown_view/MarkdownLinksMap.ts +0 -4
  24. package/front_end/ui/components/markdown_view/MarkdownView.docs.ts +95 -0
  25. package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +246 -13
  26. package/front_end/ui/components/text_editor/config.ts +1 -1
  27. package/front_end/ui/legacy/Widget.ts +13 -4
  28. package/front_end/ui/visual_logging/KnownContextValues.ts +11 -0
  29. package/package.json +1 -1
  30. package/front_end/models/issues_manager/UserReidentificationIssue.ts +0 -72
  31. package/front_end/models/issues_manager/descriptions/userReidentificationBlocked.md +0 -5
  32. package/front_end/ui/components/docs/markdown_image/basic.html +0 -19
  33. package/front_end/ui/components/docs/markdown_image/basic.ts +0 -38
  34. package/front_end/ui/components/docs/markdown_link/basic.html +0 -17
  35. package/front_end/ui/components/docs/markdown_link/basic.ts +0 -19
  36. package/front_end/ui/components/docs/markdown_view/basic.html +0 -25
  37. package/front_end/ui/components/docs/markdown_view/basic.ts +0 -67
  38. package/front_end/ui/components/docs/markdown_view/code-block.html +0 -30
  39. package/front_end/ui/components/docs/markdown_view/code-block.ts +0 -71
@@ -368,6 +368,15 @@ out/Default/chrome --custom-devtools-frontend=file://$(realpath out/Default/gen/
368
368
  afterwards, which can be quite a bit faster than building and linking the full
369
369
  Chromium binary.
370
370
 
371
+ Alternatively you can use `npm start` from the DevTools sub folder (`third_party/devtools-frontend/src/`) with the browser set to `chromium`.
372
+ This will tell the command that you are in a Chromium checkout and try to find the correct browser executable path to resolve.
373
+ Or alternately you can use a `.env` file, see [set up here](#using-a-env-file-for-default-script-options).
374
+
375
+ ```bash
376
+ cd third_party/devtools-frontend/src/
377
+ npm start -- --browser=chromium
378
+ ```
379
+
371
380
  ### Testing
372
381
 
373
382
  To run the test suite, use `npm test` from within the DevTools front-end folder:
@@ -955,6 +955,7 @@
955
955
  Common.Settings.Settings.instance({
956
956
  forceNew: true,
957
957
  ...Main.Main.instanceForTest.createSettingsStorage(prefs),
958
+ settingRegistrations: Common.SettingRegistration.getRegisteredSettings(),
958
959
  runSettingsMigration: false,
959
960
  });
960
961
 
@@ -10,7 +10,6 @@ import type {EventDescriptor, EventTargetEvent, GenericEvents} from './EventTarg
10
10
  import {ObjectWrapper} from './Object.js';
11
11
  import {
12
12
  getLocalizedSettingsCategory,
13
- getRegisteredSettings as getRegisteredSettingsInternal,
14
13
  type LearnMore,
15
14
  maybeRemoveSettingExtension,
16
15
  type RegExpSettingItem,
@@ -25,7 +24,21 @@ import {
25
24
 
26
25
  let settingsInstance: Settings|undefined;
27
26
 
27
+ export interface SettingsCreationOptions {
28
+ syncedStorage: SettingsStorage;
29
+ globalStorage: SettingsStorage;
30
+ localStorage: SettingsStorage;
31
+ settingRegistrations: SettingRegistration[];
32
+ logSettingAccess?: (name: string, value: number|string|boolean) => Promise<void>;
33
+ runSettingsMigration?: boolean;
34
+ }
35
+
28
36
  export class Settings {
37
+ readonly syncedStorage: SettingsStorage;
38
+ readonly globalStorage: SettingsStorage;
39
+ readonly localStorage: SettingsStorage;
40
+
41
+ readonly #settingRegistrations: SettingRegistration[];
29
42
  readonly #sessionStorage = new SettingsStorage({});
30
43
  settingNameSet = new Set<string>();
31
44
  orderValuesBySettingCategory = new Map<SettingCategory, Set<number>>();
@@ -34,16 +47,16 @@ export class Settings {
34
47
  readonly moduleSettings = new Map<string, Setting<unknown>>();
35
48
  #logSettingAccess?: (name: string, value: number|string|boolean) => Promise<void>;
36
49
 
37
- private constructor(
38
- readonly syncedStorage: SettingsStorage,
39
- readonly globalStorage: SettingsStorage,
40
- readonly localStorage: SettingsStorage,
41
- logSettingAccess?: (name: string, value: number|string|boolean) => Promise<void>,
42
- runSettingsMigration?: boolean,
43
- ) {
50
+ constructor(
51
+ {syncedStorage, globalStorage, localStorage, settingRegistrations, logSettingAccess, runSettingsMigration}:
52
+ SettingsCreationOptions) {
53
+ this.syncedStorage = syncedStorage;
54
+ this.globalStorage = globalStorage;
55
+ this.localStorage = localStorage;
56
+ this.#settingRegistrations = settingRegistrations;
44
57
  this.#logSettingAccess = logSettingAccess;
45
58
 
46
- for (const registration of this.getRegisteredSettings()) {
59
+ for (const registration of this.#settingRegistrations) {
47
60
  const {settingName, defaultValue, storageType} = registration;
48
61
  const isRegex = registration.settingType === SettingType.REGEX;
49
62
 
@@ -68,7 +81,7 @@ export class Settings {
68
81
  }
69
82
 
70
83
  getRegisteredSettings(): SettingRegistration[] {
71
- return getRegisteredSettingsInternal();
84
+ return this.#settingRegistrations;
72
85
  }
73
86
 
74
87
  static hasInstance(): boolean {
@@ -80,17 +93,27 @@ export class Settings {
80
93
  syncedStorage: SettingsStorage|null,
81
94
  globalStorage: SettingsStorage|null,
82
95
  localStorage: SettingsStorage|null,
96
+ settingRegistrations: SettingRegistration[]|null,
83
97
  logSettingAccess?: (name: string, value: number|string|boolean) => Promise<void>,
84
98
  runSettingsMigration?: boolean,
85
- } = {forceNew: null, syncedStorage: null, globalStorage: null, localStorage: null}): Settings {
86
- const {forceNew, syncedStorage, globalStorage, localStorage, logSettingAccess, runSettingsMigration} = opts;
99
+ } = {forceNew: null, syncedStorage: null, globalStorage: null, localStorage: null, settingRegistrations: null}):
100
+ Settings {
101
+ const {
102
+ forceNew,
103
+ syncedStorage,
104
+ globalStorage,
105
+ localStorage,
106
+ settingRegistrations,
107
+ logSettingAccess,
108
+ runSettingsMigration
109
+ } = opts;
87
110
  if (!settingsInstance || forceNew) {
88
- if (!syncedStorage || !globalStorage || !localStorage) {
111
+ if (!syncedStorage || !globalStorage || !localStorage || !settingRegistrations) {
89
112
  throw new Error(`Unable to create settings: global and local storage must be provided: ${new Error().stack}`);
90
113
  }
91
114
 
92
- settingsInstance =
93
- new Settings(syncedStorage, globalStorage, localStorage, logSettingAccess, runSettingsMigration);
115
+ settingsInstance = new Settings(
116
+ {syncedStorage, globalStorage, localStorage, settingRegistrations, logSettingAccess, runSettingsMigration});
94
117
  }
95
118
 
96
119
  return settingsInstance;
@@ -317,6 +317,11 @@ export class UserMetrics {
317
317
  InspectorFrontendHostInstance.recordPerformanceHistogram(
318
318
  'DevTools.Insights.TeaserGenerationTime', timeInMilliseconds);
319
319
  }
320
+
321
+ consoleInsightTeaserFirstChunkGenerated(timeInMilliseconds: number): void {
322
+ InspectorFrontendHostInstance.recordPerformanceHistogram(
323
+ 'DevTools.Insights.TeaserFirstChunkGenerationTime', timeInMilliseconds);
324
+ }
320
325
  }
321
326
 
322
327
  /**
@@ -25,10 +25,7 @@ export class IOModel extends SDKModel<void> {
25
25
  }
26
26
 
27
27
  async close(handle: Protocol.IO.StreamHandle): Promise<void> {
28
- const result = await this.target().ioAgent().invoke_close({handle});
29
- if (result.getError()) {
30
- console.error('Could not close stream.');
31
- }
28
+ await this.target().ioAgent().invoke_close({handle});
32
29
  }
33
30
 
34
31
  async resolveBlob(objectOrObjectId: Protocol.Runtime.RemoteObjectId|RemoteObject): Promise<string> {
@@ -35,6 +35,10 @@ export class ServerSentEventsParser {
35
35
  await this.#decoder.addBase64Chunk(raw);
36
36
  }
37
37
 
38
+ addTextChunk(chunk: string): void {
39
+ this.#onTextChunk(chunk);
40
+ }
41
+
38
42
  #onTextChunk(chunk: string): void {
39
43
  // A line consists of "this.#line" plus a slice of "chunk[start:<next new cr/lf>]".
40
44
  let start = 0;
@@ -168,9 +168,12 @@ export class MainImpl {
168
168
  Object.assign(Root.Runtime.hostConfig, config);
169
169
 
170
170
  const creationOptions: Foundation.Universe.CreationOptions = {
171
- ...this.createSettingsStorage(prefs),
172
- logSettingAccess: VisualLogging.logSettingAccess,
173
- runSettingsMigration: !Host.InspectorFrontendHost.isUnderTest(),
171
+ settingsCreationOptions: {
172
+ ...this.createSettingsStorage(prefs),
173
+ settingRegistrations: Common.SettingRegistration.getRegisteredSettings(),
174
+ logSettingAccess: VisualLogging.logSettingAccess,
175
+ runSettingsMigration: !Host.InspectorFrontendHost.isUnderTest(),
176
+ },
174
177
  };
175
178
  new Foundation.Universe.Universe(creationOptions);
176
179
 
@@ -6,11 +6,7 @@ import * as Common from '../core/common/common.js';
6
6
 
7
7
  export interface CreationOptions {
8
8
  // Settings things
9
- syncedStorage: Common.Settings.SettingsStorage;
10
- globalStorage: Common.Settings.SettingsStorage;
11
- localStorage: Common.Settings.SettingsStorage;
12
- logSettingAccess?: (name: string, value: number|string|boolean) => Promise<void>;
13
- runSettingsMigration?: boolean;
9
+ settingsCreationOptions: Common.Settings.SettingsCreationOptions;
14
10
  }
15
11
 
16
12
  export class Universe {
@@ -19,11 +15,7 @@ export class Universe {
19
15
  // For now the global is fine as we don't anticipate the MCP server to change settings.
20
16
  Common.Settings.Settings.instance({
21
17
  forceNew: true,
22
- syncedStorage: options.syncedStorage,
23
- globalStorage: options.globalStorage,
24
- localStorage: options.localStorage,
25
- logSettingAccess: options.logSettingAccess,
26
- runSettingsMigration: options.runSettingsMigration,
18
+ ...options.settingsCreationOptions,
27
19
  });
28
20
  }
29
21
  }
@@ -419,10 +419,10 @@ export const generatedProperties = [
419
419
  "column-height",
420
420
  "column-rule-break",
421
421
  "column-rule-color",
422
- "column-rule-edge-end-outset",
423
- "column-rule-edge-start-outset",
424
- "column-rule-interior-end-outset",
425
- "column-rule-interior-start-outset",
422
+ "column-rule-edge-end-inset",
423
+ "column-rule-edge-start-inset",
424
+ "column-rule-interior-end-inset",
425
+ "column-rule-interior-start-inset",
426
426
  "column-rule-style",
427
427
  "column-rule-visibility-items",
428
428
  "column-rule-width",
@@ -642,10 +642,10 @@ export const generatedProperties = [
642
642
  "row-gap",
643
643
  "row-rule-break",
644
644
  "row-rule-color",
645
- "row-rule-edge-end-outset",
646
- "row-rule-edge-start-outset",
647
- "row-rule-interior-end-outset",
648
- "row-rule-interior-start-outset",
645
+ "row-rule-edge-end-inset",
646
+ "row-rule-edge-start-inset",
647
+ "row-rule-interior-end-inset",
648
+ "row-rule-interior-start-inset",
649
649
  "row-rule-style",
650
650
  "row-rule-visibility-items",
651
651
  "row-rule-width",
@@ -1729,28 +1729,28 @@ export const generatedProperties = [
1729
1729
  },
1730
1730
  {
1731
1731
  "inherited": false,
1732
- "name": "column-rule-edge-end-outset"
1732
+ "name": "column-rule-edge-end-inset"
1733
1733
  },
1734
1734
  {
1735
1735
  "inherited": false,
1736
- "name": "column-rule-edge-start-outset"
1736
+ "name": "column-rule-edge-start-inset"
1737
1737
  },
1738
1738
  {
1739
- "inherited": false,
1740
- "name": "column-rule-interior-end-outset"
1739
+ "longhands": [
1740
+ "column-rule-edge-start-inset",
1741
+ "column-rule-edge-end-inset",
1742
+ "column-rule-interior-start-inset",
1743
+ "column-rule-interior-end-inset"
1744
+ ],
1745
+ "name": "column-rule-inset"
1741
1746
  },
1742
1747
  {
1743
1748
  "inherited": false,
1744
- "name": "column-rule-interior-start-outset"
1749
+ "name": "column-rule-interior-end-inset"
1745
1750
  },
1746
1751
  {
1747
- "longhands": [
1748
- "column-rule-edge-start-outset",
1749
- "column-rule-edge-end-outset",
1750
- "column-rule-interior-start-outset",
1751
- "column-rule-interior-end-outset"
1752
- ],
1753
- "name": "column-rule-outset"
1752
+ "inherited": false,
1753
+ "name": "column-rule-interior-start-inset"
1754
1754
  },
1755
1755
  {
1756
1756
  "keywords": [
@@ -3738,28 +3738,28 @@ export const generatedProperties = [
3738
3738
  },
3739
3739
  {
3740
3740
  "inherited": false,
3741
- "name": "row-rule-edge-end-outset"
3741
+ "name": "row-rule-edge-end-inset"
3742
3742
  },
3743
3743
  {
3744
3744
  "inherited": false,
3745
- "name": "row-rule-edge-start-outset"
3745
+ "name": "row-rule-edge-start-inset"
3746
3746
  },
3747
3747
  {
3748
- "inherited": false,
3749
- "name": "row-rule-interior-end-outset"
3748
+ "longhands": [
3749
+ "row-rule-edge-start-inset",
3750
+ "row-rule-edge-end-inset",
3751
+ "row-rule-interior-start-inset",
3752
+ "row-rule-interior-end-inset"
3753
+ ],
3754
+ "name": "row-rule-inset"
3750
3755
  },
3751
3756
  {
3752
3757
  "inherited": false,
3753
- "name": "row-rule-interior-start-outset"
3758
+ "name": "row-rule-interior-end-inset"
3754
3759
  },
3755
3760
  {
3756
- "longhands": [
3757
- "row-rule-edge-start-outset",
3758
- "row-rule-edge-end-outset",
3759
- "row-rule-interior-start-outset",
3760
- "row-rule-interior-end-outset"
3761
- ],
3762
- "name": "row-rule-outset"
3761
+ "inherited": false,
3762
+ "name": "row-rule-interior-start-inset"
3763
3763
  },
3764
3764
  {
3765
3765
  "keywords": [
@@ -3847,16 +3847,16 @@ export const generatedProperties = [
3847
3847
  },
3848
3848
  {
3849
3849
  "longhands": [
3850
- "row-rule-edge-start-outset",
3851
- "row-rule-edge-end-outset",
3852
- "row-rule-interior-start-outset",
3853
- "row-rule-interior-end-outset",
3854
- "column-rule-edge-start-outset",
3855
- "column-rule-edge-end-outset",
3856
- "column-rule-interior-start-outset",
3857
- "column-rule-interior-end-outset"
3858
- ],
3859
- "name": "rule-outset"
3850
+ "row-rule-edge-start-inset",
3851
+ "row-rule-edge-end-inset",
3852
+ "row-rule-interior-start-inset",
3853
+ "row-rule-interior-end-inset",
3854
+ "column-rule-edge-start-inset",
3855
+ "column-rule-edge-end-inset",
3856
+ "column-rule-interior-start-inset",
3857
+ "column-rule-interior-end-inset"
3858
+ ],
3859
+ "name": "rule-inset"
3860
3860
  },
3861
3861
  {
3862
3862
  "longhands": [
@@ -5,7 +5,6 @@
5
5
  import * as Common from '../../core/common/common.js';
6
6
  import * as Host from '../../core/host/host.js';
7
7
  import * as Root from '../../core/root/root.js';
8
- import * as TextEditor from '../../ui/components/text_editor/text_editor.js';
9
8
 
10
9
  import {debugLog} from './debug.js';
11
10
 
@@ -32,6 +31,20 @@ interface CachedRequest {
32
31
  response: Host.AidaClient.CompletionResponse;
33
32
  }
34
33
 
34
+ export interface Callbacks {
35
+ getSelectionHead: () => number;
36
+ getCompletionHint: () => string | undefined | null;
37
+ setAiAutoCompletion: (args: {
38
+ text: string,
39
+ from: number,
40
+ startTime: number,
41
+ onImpression: (rpcGlobalId: Host.AidaClient.RpcGlobalId, latency: number, sampleId?: number) => void,
42
+ clearCachedRequest: () => void,
43
+ rpcGlobalId?: Host.AidaClient.RpcGlobalId,
44
+ sampleId?: number,
45
+ }|null) => void;
46
+ }
47
+
35
48
  /* clang-format off */
36
49
  const consoleAdditionalContextFileContent = `/**
37
50
  * This file describes the execution environment of the Chrome DevTools Console.
@@ -141,24 +154,24 @@ const console = {
141
154
  * the suggestion is displayed.
142
155
  */
143
156
  export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
144
- #editor: TextEditor.TextEditor.TextEditor;
145
157
  #stopSequences: string[];
146
158
  #renderingTimeout?: number;
147
159
  #aidaRequestCache?: CachedRequest;
160
+ // TODO(b/445394511): Remove panel from the class
148
161
  #panel: ContextFlavor;
162
+ #callbacks?: Callbacks;
149
163
 
150
164
  readonly #sessionId: string = crypto.randomUUID();
151
165
  readonly #aidaClient: Host.AidaClient.AidaClient;
152
166
  readonly #serverSideLoggingEnabled: boolean;
153
167
 
154
- constructor(
155
- opts: AgentOptions, editor: TextEditor.TextEditor.TextEditor, panel: ContextFlavor, stopSequences?: string[]) {
168
+ constructor(opts: AgentOptions, panel: ContextFlavor, callbacks?: Callbacks, stopSequences?: string[]) {
156
169
  super();
157
170
  this.#aidaClient = opts.aidaClient;
158
171
  this.#serverSideLoggingEnabled = opts.serverSideLoggingEnabled ?? false;
159
- this.#editor = editor;
160
172
  this.#panel = panel;
161
173
  this.#stopSequences = stopSequences ?? [];
174
+ this.#callbacks = callbacks;
162
175
  }
163
176
 
164
177
  #debouncedRequestAidaSuggestion = Common.Debouncer.debounce(
@@ -171,8 +184,8 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
171
184
 
172
185
  #buildRequest(
173
186
  prefix: string, suffix: string,
174
- inferenceLanguage: Host.AidaClient.AidaInferenceLanguage = Host.AidaClient.AidaInferenceLanguage.JAVASCRIPT):
175
- Host.AidaClient.CompletionRequest {
187
+ inferenceLanguage: Host.AidaClient.AidaInferenceLanguage = Host.AidaClient.AidaInferenceLanguage.JAVASCRIPT,
188
+ additionalFiles?: Host.AidaClient.AdditionalFile[]): Host.AidaClient.CompletionRequest {
176
189
  const userTier = Host.AidaClient.convertToUserTierEnum(this.#userTier);
177
190
  function validTemperature(temperature: number|undefined): number|undefined {
178
191
  return typeof temperature === 'number' && temperature >= 0 ? temperature : undefined;
@@ -180,13 +193,15 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
180
193
  // As a temporary fix for b/441221870 we are prepending a newline for each prefix.
181
194
  prefix = '\n' + prefix;
182
195
 
183
- const additionalFiles = this.#panel === ContextFlavor.CONSOLE ? [{
184
- path: 'devtools-console-context.js',
185
- content: consoleAdditionalContextFileContent,
186
- included_reason: Host.AidaClient.Reason.RELATED_FILE,
187
- }] :
188
- undefined;
189
-
196
+ let additionalContextFiles = additionalFiles ?? undefined;
197
+ if (!additionalContextFiles) {
198
+ additionalContextFiles = this.#panel === ContextFlavor.CONSOLE ? [{
199
+ path: 'devtools-console-context.js',
200
+ content: consoleAdditionalContextFileContent,
201
+ included_reason: Host.AidaClient.Reason.RELATED_FILE,
202
+ }] :
203
+ undefined;
204
+ }
190
205
  return {
191
206
  client: Host.AidaClient.CLIENT_NAME,
192
207
  prefix,
@@ -203,7 +218,7 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
203
218
  user_tier: userTier,
204
219
  client_version: Root.Runtime.getChromeVersion(),
205
220
  },
206
- additional_files: additionalFiles,
221
+ additional_files: additionalContextFiles,
207
222
  };
208
223
  }
209
224
 
@@ -239,7 +254,7 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
239
254
  // `currentHint` is the portion of a standard autocomplete suggestion that the user has not yet typed.
240
255
  // For example, if the user types `document.queryS` and the autocomplete suggests `document.querySelector`,
241
256
  // the `currentHint` is `elector`.
242
- const currentHintInMenu = this.#editor.editor.plugin(TextEditor.Config.showCompletionHint)?.currentHint;
257
+ const currentHintInMenu = this.#callbacks?.getCompletionHint();
243
258
  // TODO(ergunsh): We should not do this check here. Instead, the AI code suggestions should be provided
244
259
  // as it is to the view plugin. The view plugin should choose which one to use based on the completion hint
245
260
  // and selected completion.
@@ -321,21 +336,19 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
321
336
  } = sampleResponse;
322
337
  const remainingDelay = Math.max(DELAY_BEFORE_SHOWING_RESPONSE_MS - (performance.now() - startTime), 0);
323
338
  this.#renderingTimeout = window.setTimeout(() => {
324
- const currentCursorPosition = this.#editor.editor.state.selection.main.head;
339
+ const currentCursorPosition = this.#callbacks?.getSelectionHead();
325
340
  if (currentCursorPosition !== cursorPositionAtRequest) {
326
341
  this.dispatchEventToListeners(Events.RESPONSE_RECEIVED, {});
327
342
  return;
328
343
  }
329
- this.#editor.dispatch({
330
- effects: TextEditor.Config.setAiAutoCompleteSuggestion.of({
331
- text: suggestionText,
332
- from: cursorPositionAtRequest,
333
- rpcGlobalId,
334
- sampleId,
335
- startTime,
336
- onImpression: this.#registerUserImpression.bind(this),
337
- clearCachedRequest: this.clearCachedRequest.bind(this),
338
- })
344
+ this.#callbacks?.setAiAutoCompletion({
345
+ text: suggestionText,
346
+ from: cursorPositionAtRequest,
347
+ rpcGlobalId,
348
+ sampleId,
349
+ startTime,
350
+ onImpression: this.registerUserImpression.bind(this),
351
+ clearCachedRequest: this.clearCachedRequest.bind(this),
339
352
  });
340
353
 
341
354
  if (fromCache) {
@@ -417,7 +430,7 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
417
430
  this.#aidaRequestCache = {request, response};
418
431
  }
419
432
 
420
- #registerUserImpression(rpcGlobalId: Host.AidaClient.RpcGlobalId, latency: number, sampleId?: number): void {
433
+ registerUserImpression(rpcGlobalId: Host.AidaClient.RpcGlobalId, latency: number, sampleId?: number): void {
421
434
  const seconds = Math.floor(latency / 1_000);
422
435
  const remainingMs = latency % 1_000;
423
436
  const nanos = Math.floor(remainingMs * 1_000_000);
@@ -469,14 +482,42 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
469
482
  this.#debouncedRequestAidaSuggestion(prefix, suffix, cursorPositionAtRequest, inferenceLanguage);
470
483
  }
471
484
 
485
+ async completeCode(
486
+ prefix: string, suffix: string, cursorPositionAtRequest: number,
487
+ inferenceLanguage?: Host.AidaClient.AidaInferenceLanguage,
488
+ additionalFiles?: Host.AidaClient.AdditionalFile[]): Promise<{
489
+ response: Host.AidaClient.CompletionResponse | null,
490
+ fromCache: boolean,
491
+ }> {
492
+ const request = this.#buildRequest(prefix, suffix, inferenceLanguage, additionalFiles);
493
+ const {response, fromCache} = await this.#completeCodeCached(request);
494
+
495
+ debugLog('At cursor position', cursorPositionAtRequest, {request, response, fromCache});
496
+ if (!response) {
497
+ return {response: null, fromCache: false};
498
+ }
499
+
500
+ return {response, fromCache};
501
+ }
502
+
472
503
  remove(): void {
473
504
  if (this.#renderingTimeout) {
474
505
  clearTimeout(this.#renderingTimeout);
475
506
  this.#renderingTimeout = undefined;
476
507
  }
477
- this.#editor.dispatch({
478
- effects: TextEditor.Config.setAiAutoCompleteSuggestion.of(null),
479
- });
508
+ this.#callbacks?.setAiAutoCompletion(null);
509
+ }
510
+
511
+ static isAiCodeCompletionEnabled(locale: string): boolean {
512
+ if (!locale.startsWith('en-')) {
513
+ return false;
514
+ }
515
+ const aidaAvailability = Root.Runtime.hostConfig.aidaAvailability;
516
+ if (!aidaAvailability || aidaAvailability.blockedByGeo || aidaAvailability.blockedByAge ||
517
+ aidaAvailability.blockedByEnterprisePolicy) {
518
+ return false;
519
+ }
520
+ return Boolean(aidaAvailability.enabled && Root.Runtime.hostConfig.devToolsAiCodeCompletion?.enabled);
480
521
  }
481
522
  }
482
523
 
@@ -137,6 +137,20 @@ export class Importer {
137
137
  async () =>
138
138
  new TextUtils.ContentData.ContentData(contentText ?? '', isBase64, mimeType ?? '', charset ?? undefined));
139
139
 
140
+ if (request.mimeType === Platform.MimeType.MimeType.EVENTSTREAM && contentText) {
141
+ const issueTime = entry.startedDateTime.getTime() / 1000;
142
+ const onEvent = (eventName: string, data: string, eventId: string): void => {
143
+ request.addEventSourceMessage(issueTime, eventName, eventId, data);
144
+ };
145
+ const parser = new SDK.ServerSentEventProtocol.ServerSentEventsParser(onEvent, charset ?? undefined);
146
+ let text = contentText;
147
+ if (isBase64) {
148
+ const bytes = Common.Base64.decode(contentText);
149
+ text = new TextDecoder(charset ?? undefined).decode(bytes);
150
+ }
151
+ parser.addTextChunk(text);
152
+ }
153
+
140
154
  // Timing data.
141
155
  Importer.setupTiming(request, issueTime, entry.time, entry.timings);
142
156
 
@@ -33,7 +33,6 @@ import {SourceFrameIssuesManager} from './SourceFrameIssuesManager.js';
33
33
  import {SRIMessageSignatureIssue} from './SRIMessageSignatureIssue.js';
34
34
  import {StylesheetLoadingIssue} from './StylesheetLoadingIssue.js';
35
35
  import {UnencodedDigestIssue} from './UnencodedDigestIssue.js';
36
- import {UserReidentificationIssue} from './UserReidentificationIssue.js';
37
36
 
38
37
  export {Events} from './IssuesManagerEvents.js';
39
38
 
@@ -145,10 +144,6 @@ const issueCodeHandlers = new Map<
145
144
  Protocol.Audits.InspectorIssueCode.UnencodedDigestIssue,
146
145
  UnencodedDigestIssue.fromInspectorIssue,
147
146
  ],
148
- [
149
- Protocol.Audits.InspectorIssueCode.UserReidentificationIssue,
150
- UserReidentificationIssue.fromInspectorIssue,
151
- ],
152
147
  ]);
153
148
 
154
149
  /**
@@ -7617,10 +7617,6 @@ export const NativeFunctions = [
7617
7617
  name: "drawElementImage",
7618
7618
  signatures: [["element","x","y","?dwidth","?dheight"]]
7619
7619
  },
7620
- {
7621
- name: "setHitTestRegions",
7622
- signatures: [["hitTestRegions"]]
7623
- },
7624
7620
  {
7625
7621
  name: "Path2D",
7626
7622
  signatures: [["?path"]]
@@ -44,6 +44,7 @@ type GeneratedFileSizes = {
44
44
  }|{files: Record<string, number>, unmappedBytes: number, totalBytes: number};
45
45
 
46
46
  let scriptById = new Map<string, Script>();
47
+ let frameIdByIsolate = new Map<string, string>();
47
48
 
48
49
  export function deps(): HandlerName[] {
49
50
  return ['Meta', 'NetworkRequests'];
@@ -51,6 +52,7 @@ export function deps(): HandlerName[] {
51
52
 
52
53
  export function reset(): void {
53
54
  scriptById = new Map();
55
+ frameIdByIsolate = new Map();
54
56
  }
55
57
 
56
58
  export function handleEvent(event: Types.Events.Event): void {
@@ -73,6 +75,9 @@ export function handleEvent(event: Types.Events.Event): void {
73
75
  if (Types.Events.isRundownScript(event)) {
74
76
  const {isolate, scriptId, url, sourceUrl, sourceMapUrl, sourceMapUrlElided} = event.args.data;
75
77
  const script = getOrMakeScript(isolate, scriptId);
78
+ if (!script.frame) {
79
+ script.frame = frameIdByIsolate.get(String(isolate)) ?? '';
80
+ }
76
81
  script.url = url;
77
82
  script.ts = event.ts;
78
83
  if (sourceUrl) {
@@ -105,6 +110,27 @@ export function handleEvent(event: Types.Events.Event): void {
105
110
  script.content = (script.content ?? '') + sourceText;
106
111
  return;
107
112
  }
113
+
114
+ // Setup frameIdByIsolate, which is used only in the case that we are missing
115
+ // rundown events for a script. We won't get a frame association from the rundown
116
+ // events if the recording started only after the script was first compiled. In
117
+ // that scenario, derive the frame via the isolate / FunctionCall events.
118
+ // TODO: ideally, we put the frame on ScriptCatchup event. So much easier. This approach has some
119
+ // issues.
120
+ if (Types.Events.isFunctionCall(event) && event.args.data?.isolate && event.args.data.frame) {
121
+ const {isolate, frame} = event.args.data;
122
+ const existingValue = frameIdByIsolate.get(isolate);
123
+ if (existingValue !== frame) {
124
+ frameIdByIsolate.set(isolate, frame);
125
+
126
+ // Update the scripts we discovered but without knowing their frame.
127
+ for (const script of scriptById.values()) {
128
+ if (!script.frame && script.isolate === isolate) {
129
+ script.frame = frame;
130
+ }
131
+ }
132
+ }
133
+ }
108
134
  }
109
135
 
110
136
  function findFrame(meta: MetaHandlerData, frameId: string): Types.Events.TraceFrame|null {
@@ -2804,7 +2804,7 @@ export interface FunctionCall extends Complete {
2804
2804
  args: Args&{
2805
2805
  data?: Partial<CallFrame>& {
2806
2806
  frame?: string,
2807
- isolate?: number,
2807
+ isolate?: string,
2808
2808
  },
2809
2809
  };
2810
2810
  }