chrome-devtools-frontend 1.0.1696961 → 1.0.1697998

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 (121) hide show
  1. package/.geminiignore +0 -1
  2. package/.stylelintignore +2 -0
  3. package/front_end/core/common/Color.ts +5 -2
  4. package/front_end/core/common/VersionController.ts +5 -1
  5. package/front_end/core/host/InspectorFrontendHostAPI.ts +16 -3
  6. package/front_end/core/host/InspectorFrontendHostStub.ts +3 -2
  7. package/front_end/core/host/ResourceLoader.ts +1 -2
  8. package/front_end/core/platform/api/HostRuntime.ts +1 -0
  9. package/front_end/core/platform/browser/HostRuntime.ts +4 -0
  10. package/front_end/core/platform/node/HostRuntime.ts +5 -0
  11. package/front_end/core/root/Runtime.ts +5 -0
  12. package/front_end/core/sdk/AnimationModel.ts +9 -1
  13. package/front_end/core/sdk/DOMModel.ts +13 -0
  14. package/front_end/core/sdk/SourceMapScopeChainEntry.ts +9 -6
  15. package/front_end/core/sdk/SourceMapScopesInfo.ts +3 -1
  16. package/front_end/foundation/Universe.ts +8 -0
  17. package/front_end/generated/InspectorBackendCommands.ts +4 -1
  18. package/front_end/generated/protocol-mapping.d.ts +19 -0
  19. package/front_end/generated/protocol-proxy-api.d.ts +15 -0
  20. package/front_end/generated/protocol.ts +43 -2
  21. package/front_end/models/ai_assistance/AiAgent2.ts +20 -18
  22. package/front_end/models/ai_assistance/AiConversation.ts +38 -12
  23. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +9 -2
  24. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +26 -0
  25. package/front_end/models/ai_assistance/agents/StylingAgent.ts +13 -4
  26. package/front_end/models/ai_assistance/ai_assistance.ts +4 -4
  27. package/front_end/models/ai_assistance/skills/performance.md +4 -3
  28. package/front_end/models/ai_assistance/tools/CookieUtils.ts +10 -8
  29. package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +1 -1
  30. package/front_end/models/ai_assistance/tools/GetElementAccessibilityDetails.ts +1 -3
  31. package/front_end/models/ai_assistance/tools/GetNetworkRequestDetails.ts +9 -8
  32. package/front_end/models/ai_assistance/tools/GetSourceContent.ts +5 -6
  33. package/front_end/models/ai_assistance/tools/GetStorageValues.ts +6 -25
  34. package/front_end/models/ai_assistance/tools/GetStyles.ts +1 -3
  35. package/front_end/models/ai_assistance/tools/{GetFunctionCode.ts → GetTraceFunctionCode.ts} +26 -13
  36. package/front_end/models/ai_assistance/tools/{GetResourceContent.ts → GetTraceResourceContent.ts} +31 -11
  37. package/front_end/models/ai_assistance/tools/ListNetworkRequests.ts +7 -6
  38. package/front_end/models/ai_assistance/tools/ListPageOrigins.ts +8 -5
  39. package/front_end/models/ai_assistance/tools/ListSources.ts +8 -10
  40. package/front_end/models/ai_assistance/tools/ListStorageKeys.ts +6 -25
  41. package/front_end/models/ai_assistance/tools/README.md +5 -3
  42. package/front_end/models/ai_assistance/tools/ResolveDevtoolsNodePath.ts +1 -2
  43. package/front_end/models/ai_assistance/tools/Tool.ts +54 -16
  44. package/front_end/models/ai_assistance/tools/ToolRegistry.ts +6 -6
  45. package/front_end/models/change_tracker/ChangeTracker.ts +89 -0
  46. package/front_end/models/change_tracker/change_tracker.ts +9 -0
  47. package/front_end/models/elements/DOMChanges.ts +238 -0
  48. package/front_end/models/elements/elements.ts +2 -0
  49. package/front_end/models/issues_manager/MarkdownIssueDescription.ts +2 -2
  50. package/front_end/models/live-metrics/LiveMetrics.ts +1 -2
  51. package/front_end/models/trace/ModelImpl.ts +0 -6
  52. package/front_end/models/trace/Processor.ts +4 -7
  53. package/front_end/models/trace/helpers/Timing.ts +2 -1
  54. package/front_end/models/trace/types/Overlays.ts +12 -1
  55. package/front_end/panels/accessibility/AccessibilityAnnouncementRecordingView.ts +67 -19
  56. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +3 -1
  57. package/front_end/panels/ai_assistance/components/MarkdownRendererWithCodeBlock.ts +25 -5
  58. package/front_end/panels/application/IndexedDBViews.ts +1 -1
  59. package/front_end/panels/browser_debugger/ObjectEventListenersSidebarPane.ts +2 -3
  60. package/front_end/panels/elements/DOMTreeContextMenu.ts +16 -23
  61. package/front_end/panels/elements/ElementsTreeElement.ts +384 -79
  62. package/front_end/panels/elements/ElementsTreeOutline.ts +541 -82
  63. package/front_end/panels/elements/EventListenersWidget.ts +0 -1
  64. package/front_end/panels/event_listeners/EventListenersView.ts +241 -297
  65. package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorController.ts +1 -1
  66. package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +10 -2
  67. package/front_end/panels/network/NetworkConfigView.ts +141 -116
  68. package/front_end/panels/network/NetworkPanel.ts +140 -52
  69. package/front_end/panels/network/RequestHeadersView.ts +65 -32
  70. package/front_end/panels/network/components/RequestHeadersView.css +7 -1
  71. package/front_end/panels/network/forward/BackendLinking.ts +52 -0
  72. package/front_end/panels/network/forward/forward.ts +2 -0
  73. package/front_end/panels/settings/BackendLinkingSettingsTab.ts +308 -0
  74. package/front_end/panels/settings/backendLinkingSettingsTab.css +78 -0
  75. package/front_end/panels/settings/settings-meta.ts +25 -0
  76. package/front_end/panels/settings/settings.ts +2 -0
  77. package/front_end/panels/timeline/README.md +3 -2
  78. package/front_end/panels/timeline/TimelineFlameChartView.ts +23 -2
  79. package/front_end/panels/timeline/TimelineTreeView.ts +11 -1
  80. package/front_end/panels/timeline/overlays/OverlaysImpl.ts +64 -4
  81. package/front_end/panels/timeline/timelineFlameChartView.css +47 -0
  82. package/front_end/panels/whats_new/ReleaseNoteText.ts +8 -8
  83. package/front_end/panels/whats_new/resources/WNDT.md +6 -6
  84. package/front_end/third_party/chromium/README.chromium +1 -1
  85. package/front_end/third_party/puppeteer/README.chromium +2 -2
  86. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +6 -0
  87. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +5 -8
  88. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Coverage.d.ts +6 -0
  89. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Coverage.d.ts.map +1 -1
  90. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Coverage.js.map +1 -1
  91. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/ScreenRecording.d.ts.map +1 -1
  92. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/ScreenRecording.js +1 -5
  93. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/ScreenRecording.js.map +1 -1
  94. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.d.ts +3 -3
  95. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js +3 -3
  96. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js.map +1 -1
  97. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.d.ts +1 -1
  98. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.js +1 -1
  99. package/front_end/third_party/puppeteer/package/lib/types.d.ts +6 -0
  100. package/front_end/third_party/puppeteer/package/package.json +2 -2
  101. package/front_end/third_party/puppeteer/package/src/cdp/Coverage.ts +6 -0
  102. package/front_end/third_party/puppeteer/package/src/cdp/ScreenRecording.ts +3 -7
  103. package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
  104. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  105. package/front_end/third_party/web-vitals/README.chromium +2 -2
  106. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onINP.js +8 -5
  107. package/front_end/third_party/web-vitals/package/package.json +1 -1
  108. package/front_end/third_party/web-vitals/package/src/attribution/onINP.ts +8 -4
  109. package/front_end/third_party/web-vitals/rebuild.sh +2 -2
  110. package/front_end/ui/comments/CommentOverlayManager.ts +169 -40
  111. package/front_end/ui/comments/CommentThreadWidget.ts +221 -0
  112. package/front_end/ui/comments/CommentsOverlayWidget.ts +124 -12
  113. package/front_end/ui/comments/commentThreadWidget.css +173 -0
  114. package/front_end/ui/comments/comments.ts +2 -0
  115. package/front_end/ui/comments/commentsOverlay.css +6 -0
  116. package/front_end/ui/legacy/ContextMenu.ts +19 -0
  117. package/front_end/ui/legacy/SoftContextMenu.ts +6 -0
  118. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +1 -1
  119. package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +66 -22
  120. package/front_end/ui/visual_logging/KnownContextValues.ts +4 -0
  121. package/package.json +9 -8
@@ -38,7 +38,7 @@ import {FileContext} from './contexts/FileContext.js';
38
38
  import {PerformanceTraceContext} from './contexts/PerformanceTraceContext.js';
39
39
  import {RequestContext} from './contexts/RequestContext.js';
40
40
  import {StorageContext} from './contexts/StorageContext.js';
41
- import {ToolAnnotation} from './tools/Tool.js';
41
+ import {type OriginLockState, ToolAnnotation} from './tools/Tool.js';
42
42
  import {ToolRegistry} from './tools/ToolRegistry.js';
43
43
 
44
44
  export const NOT_FOUND_IMAGE_DATA = '';
@@ -381,7 +381,7 @@ export class AiConversation {
381
381
  const isTransitioningFromStorage = previousType === ConversationType.STORAGE && type !== ConversationType.STORAGE;
382
382
  const history = isTransitioningFromStorage ? [] : this.#filterHistoryForNewAgent();
383
383
 
384
- const options = {
384
+ const baseOptions = {
385
385
  aidaClient: this.#aidaClient,
386
386
  serverSideLoggingAllowed: isAiAssistanceServerSideLoggingAllowed(),
387
387
  sessionId: this.id,
@@ -390,13 +390,18 @@ export class AiConversation {
390
390
  onInspectElement: this.#onInspectElement,
391
391
  networkTimeCalculator: this.#networkTimeCalculator,
392
392
  lighthouseRecording: this.#lighthouseRecording,
393
- allowedOrigin: this.allowedOrigin,
394
393
  history,
395
394
  targetManager: this.#targetManager,
396
395
  };
397
396
 
398
- this.#agent = Root.Runtime.hostConfig.devToolsAiV2Architecture?.enabled ? new AiAgent2(options) :
399
- this.#createV1Agent(type, options);
397
+ this.#agent = Root.Runtime.hostConfig.devToolsAiV2Architecture?.enabled ? new AiAgent2({
398
+ ...baseOptions,
399
+ originLock: this.getOriginLock,
400
+ }) :
401
+ this.#createV1Agent(type, {
402
+ ...baseOptions,
403
+ allowedOrigin: this.allowedOrigin,
404
+ });
400
405
  }
401
406
 
402
407
  #createV1Agent(type: ConversationType, options: AgentOptions): AiAgent<unknown> {
@@ -553,19 +558,40 @@ export class AiConversation {
553
558
  }
554
559
 
555
560
  /**
556
- * Returns the permitted origin for agent tool execution, or blocks execution
557
- * if an unapproved cross-origin navigation occurred during the current run.
561
+ * Returns the conversation's origin-locking state:
562
+ * - `BLOCKED_BY_NAVIGATION`: An unapproved cross-origin navigation occurred during the active run.
563
+ * - `ESTABLISHED_ORIGIN`: The conversation is locked to the established origin.
564
+ * - `UNINITIALIZED`: No origin lock has been established yet.
558
565
  */
559
- allowedOrigin = (): AllowedOriginResult => {
566
+ getOriginLock = (): OriginLockState => {
560
567
  if (this.#navigationOccurredDuringRun) {
561
- return {blocked: true};
568
+ return {status: 'BLOCKED_BY_NAVIGATION'};
562
569
  }
563
570
  if (this.#origin) {
564
- return {origin: this.#origin};
571
+ return {status: 'ESTABLISHED_ORIGIN', origin: this.#origin};
572
+ }
573
+ const pageOrigin = getPrimaryPageSecurityOrigin(this.#targetManager);
574
+ if (pageOrigin) {
575
+ this.#origin = pageOrigin;
576
+ return {status: 'ESTABLISHED_ORIGIN', origin: this.#origin};
565
577
  }
566
- this.#origin = getPrimaryPageSecurityOrigin(this.#targetManager);
567
578
 
568
- return {origin: this.#origin};
579
+ return {status: 'UNINITIALIZED'};
580
+ };
581
+
582
+ /**
583
+ * Returns the permitted origin for legacy V1 agent tool execution.
584
+ * Maps the OriginLockState to the AllowedOriginResult format expected by V1 agents.
585
+ */
586
+ allowedOrigin = (): AllowedOriginResult => {
587
+ const lock = this.getOriginLock();
588
+ if (lock.status === 'BLOCKED_BY_NAVIGATION') {
589
+ return {blocked: true};
590
+ }
591
+ if (lock.status === 'ESTABLISHED_ORIGIN') {
592
+ return {origin: lock.origin};
593
+ }
594
+ return {origin: undefined};
569
595
  };
570
596
  }
571
597
 
@@ -11,7 +11,10 @@ import {ChangeManager} from '../ChangeManager.js';
11
11
  import {LighthouseFormatter} from '../data_formatters/LighthouseFormatter.js';
12
12
  import {debugLog} from '../debug.js';
13
13
  import {ExtensionScope} from '../ExtensionScope.js';
14
- import {ToolName} from '../tools/Tool.js';
14
+ import {
15
+ type OriginLockState,
16
+ ToolName,
17
+ } from '../tools/Tool.js';
15
18
  import {ToolRegistry} from '../tools/ToolRegistry.js';
16
19
 
17
20
  import {
@@ -253,7 +256,11 @@ export class AccessibilityAgent extends AiAgent<LHModel.ReporterTypes.ReportJSON
253
256
  createExtensionScope: this.#createExtensionScope.bind(this),
254
257
  execJs: this.#execJs,
255
258
  getExecutionContextNode: () => this.#getDocumentBodyNode(),
256
- getEstablishedOrigin: () => this.context?.getOrigin(),
259
+ getOriginLock: (): OriginLockState => {
260
+ // V1 AccessibilityAgent adapts the selected node's security origin to OriginLockState.
261
+ const origin = this.context?.getOrigin();
262
+ return origin ? {status: 'ESTABLISHED_ORIGIN', origin} : {status: 'UNINITIALIZED'};
263
+ },
257
264
  },
258
265
  options,
259
266
  );
@@ -20,6 +20,7 @@ import {StorageContext} from '../contexts/StorageContext.js';
20
20
  import {formatBytesToKb, seconds} from '../data_formatters/UnitFormatters.js';
21
21
  import {debugLog} from '../debug.js';
22
22
  import {StorageItem} from '../StorageItem.js';
23
+ import {isOriginAllowedByLock} from '../tools/Tool.js';
23
24
 
24
25
  import {
25
26
  type AgentOptions,
@@ -587,4 +588,29 @@ export class ContextSelectionAgent extends AiAgent<never> {
587
588
 
588
589
  return [...uiSourceCodes.values()];
589
590
  }
591
+
592
+ /**
593
+ * Resolves a workspace source file by its ID, ensuring that the file's security
594
+ * origin is authorized by the conversation's established origin lock.
595
+ *
596
+ * Fails closed by returning `undefined` if the established origin is missing or opaque,
597
+ * if the file ID is invalid, or if the file origin does not match the lock.
598
+ */
599
+ static getSourceById(
600
+ id: number,
601
+ establishedOrigin?: SDK.SecurityOrigin.SecurityOrigin,
602
+ // eslint-disable-next-line @devtools/no-instance-of-migrated-singletons
603
+ workspace: Workspace.Workspace.WorkspaceImpl = Workspace.Workspace.WorkspaceImpl.instance(),
604
+ ): Workspace.UISourceCode.UISourceCode|undefined {
605
+ if (!establishedOrigin || !Number.isInteger(id) || id <= 0) {
606
+ return undefined;
607
+ }
608
+ return ContextSelectionAgent.getUISourceCodes(workspace).find(file => {
609
+ if (ContextSelectionAgent.uiSourceCodeId.get(file) !== id) {
610
+ return false;
611
+ }
612
+ return isOriginAllowedByLock({status: 'ESTABLISHED_ORIGIN', origin: establishedOrigin},
613
+ FileContext.originForUISourceCode(file));
614
+ });
615
+ }
590
616
  }
@@ -8,7 +8,10 @@ import type * as SDK from '../../../core/sdk/sdk.js';
8
8
  import {ChangeManager} from '../ChangeManager.js';
9
9
  import {ExtensionScope} from '../ExtensionScope.js';
10
10
  import {AI_ASSISTANCE_CSS_CLASS_NAME} from '../injected.js';
11
- import {ToolName} from '../tools/Tool.js';
11
+ import {
12
+ type OriginLockState,
13
+ ToolName,
14
+ } from '../tools/Tool.js';
12
15
  import {ToolRegistry} from '../tools/ToolRegistry.js';
13
16
 
14
17
  import {
@@ -154,8 +157,10 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
154
157
  }
155
158
  return await getStylesTool.handler(args, {
156
159
  getTarget: () => this.targetManager.primaryPageTarget() ?? context.getItem().domModel().target(),
157
- getEstablishedOrigin: () => {
158
- return context.getOrigin();
160
+ getOriginLock: (): OriginLockState => {
161
+ // V1 StylingAgent adapts the selected DOM node's security origin to OriginLockState.
162
+ const origin = context.getOrigin();
163
+ return origin ? {status: 'ESTABLISHED_ORIGIN', origin} : {status: 'UNINITIALIZED'};
159
164
  },
160
165
  });
161
166
  },
@@ -176,7 +181,11 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
176
181
  createExtensionScope: this.#createExtensionScope.bind(this),
177
182
  execJs: this.#execJs,
178
183
  getExecutionContextNode: () => this.context?.getItem() ?? null,
179
- getEstablishedOrigin: () => this.context?.getOrigin(),
184
+ getOriginLock: (): OriginLockState => {
185
+ // V1 StylingAgent adapts the selected DOM node's security origin to OriginLockState.
186
+ const origin = this.context?.getOrigin();
187
+ return origin ? {status: 'ESTABLISHED_ORIGIN', origin} : {status: 'UNINITIALIZED'};
188
+ },
180
189
  },
181
190
  options,
182
191
  ),
@@ -46,18 +46,18 @@ import * as ExecuteJavaScript from './tools/ExecuteJavaScript.js';
46
46
  import * as GetCookieValues from './tools/GetCookieValues.js';
47
47
  import * as GetDetailedCallTree from './tools/GetDetailedCallTree.js';
48
48
  import * as GetElementAccessibilityDetails from './tools/GetElementAccessibilityDetails.js';
49
- import * as GetFunctionCode from './tools/GetFunctionCode.js';
50
49
  import * as GetInsightDetails from './tools/GetInsightDetails.js';
51
50
  import * as GetLighthouseAudits from './tools/GetLighthouseAudits.js';
52
51
  import * as GetNetworkRequestDetails from './tools/GetNetworkRequestDetails.js';
53
- import * as GetResourceContent from './tools/GetResourceContent.js';
54
52
  import * as GetSourceContent from './tools/GetSourceContent.js';
55
53
  import * as GetStorageBreakdown from './tools/GetStorageBreakdown.js';
56
54
  import * as GetStorageValues from './tools/GetStorageValues.js';
57
55
  import * as GetStyles from './tools/GetStyles.js';
58
56
  import * as GetTraceEventByKey from './tools/GetTraceEventByKey.js';
57
+ import * as GetTraceFunctionCode from './tools/GetTraceFunctionCode.js';
59
58
  import * as GetTraceMainThreadSummary from './tools/GetTraceMainThreadSummary.js';
60
59
  import * as GetTraceNetworkSummary from './tools/GetTraceNetworkSummary.js';
60
+ import * as GetTraceResourceContent from './tools/GetTraceResourceContent.js';
61
61
  import * as ListCookies from './tools/ListCookies.js';
62
62
  import * as ListNetworkRequests from './tools/ListNetworkRequests.js';
63
63
  import * as ListPageOrigins from './tools/ListPageOrigins.js';
@@ -99,18 +99,18 @@ export {
99
99
  GetCookieValues,
100
100
  GetDetailedCallTree,
101
101
  GetElementAccessibilityDetails,
102
- GetFunctionCode,
103
102
  GetInsightDetails,
104
103
  GetLighthouseAudits,
105
104
  GetNetworkRequestDetails,
106
- GetResourceContent,
107
105
  GetSourceContent,
108
106
  GetStorageBreakdown,
109
107
  GetStorageValues,
110
108
  GetStyles,
111
109
  GetTraceEventByKey,
110
+ GetTraceFunctionCode,
112
111
  GetTraceMainThreadSummary,
113
112
  GetTraceNetworkSummary,
113
+ GetTraceResourceContent,
114
114
  Injected,
115
115
  LighthouseFormatter,
116
116
  ListCookies,
@@ -8,8 +8,8 @@ allowed-tools:
8
8
  - getTraceMainThreadSummary
9
9
  - getTraceNetworkSummary
10
10
  - getDetailedCallTree
11
- - getFunctionCode
12
- - getResourceContent
11
+ - getTraceFunctionCode
12
+ - getTraceResourceContent
13
13
  - getInsightDetails
14
14
  ---
15
15
  You are an expert web performance assistant integrated into Chrome DevTools.
@@ -29,7 +29,8 @@ Your goal is to provide actionable advice about web page performance by analyzin
29
29
  3. **Call Tree, Event & Source Inspection**:
30
30
  - Use `getDetailedCallTree` to retrieve bottom-up execution trees for expensive main thread tasks.
31
31
  - Use `getTraceEventByKey` to inspect timing and payload data for individual events.
32
- - Use `getFunctionCode` or `getResourceContent` to inspect the source code and identify root causes.
32
+ - Use `getTraceFunctionCode` to inspect a specific function identified in the call tree, including line-by-line CPU profile execution costs.
33
+ - Use `getTraceResourceContent` to inspect the full text of a script or resource captured within the trace by URL.
33
34
 
34
35
  4. **UI Selection & Trace Recording**:
35
36
  - Use `selectTraceEventByKey` to reveal and select an event in the Performance Flamechart if requested.
@@ -6,7 +6,7 @@ import * as SDK from '../../../core/sdk/sdk.js';
6
6
  import type * as Protocol from '../../../generated/protocol.js';
7
7
 
8
8
  import {MAX_TARGET_ORIGINS} from './DOMStorageUtils.js';
9
- import type {OriginLockCapability} from './Tool.js';
9
+ import {isOriginAllowedByLock, type OriginLockCapability, resolveOriginFromLock} from './Tool.js';
10
10
 
11
11
  export interface CookieDetails {
12
12
  name: string;
@@ -25,14 +25,14 @@ export interface CookieDetails {
25
25
  }
26
26
 
27
27
  /**
28
- * Resolves and validates target origins against the established context origin and primary page target.
28
+ * Resolves and validates target origins against the conversation's origin lock state and primary page target.
29
29
  *
30
30
  * When `requestedOrigins` is empty or omitted, defaults to the established context origin.
31
31
  * Rejects opaque origins, mismatches with the primary page origin, and cross-origin targets.
32
32
  * Limits results to at most `MAX_TARGET_ORIGINS` unique origins.
33
33
  *
34
34
  * @param requestedOrigins Optional list of origin URLs to validate.
35
- * @param context The origin lock capability containing the established origin.
35
+ * @param context The origin lock capability providing access to the conversation's origin lock state.
36
36
  * @param targetManager The target manager used to resolve the primary page target.
37
37
  * @returns An object with validated target origins and the primary page target, or an error object.
38
38
  */
@@ -44,10 +44,12 @@ export function resolveAllowedTargetOrigins(
44
44
  error: string,
45
45
  }
46
46
  {
47
- const establishedOrigin = context.getEstablishedOrigin();
48
- if (!establishedOrigin || establishedOrigin.isOpaque()) {
49
- return {error: 'No origin available or not allowed.'};
47
+ const originLock = context.getOriginLock();
48
+ const originResult = resolveOriginFromLock(originLock);
49
+ if ('error' in originResult) {
50
+ return originResult;
50
51
  }
52
+ const establishedOrigin = originResult.origin;
51
53
 
52
54
  const primaryPageTarget = targetManager.primaryPageTarget();
53
55
  if (!primaryPageTarget) {
@@ -55,7 +57,7 @@ export function resolveAllowedTargetOrigins(
55
57
  }
56
58
 
57
59
  const pageOrigin = primaryPageTarget.inspectedSecurityOrigin();
58
- if (!pageOrigin.isSameOriginWith(establishedOrigin)) {
60
+ if (!isOriginAllowedByLock(originLock, pageOrigin)) {
59
61
  return {error: 'Page origin does not match allowed origin.'};
60
62
  }
61
63
 
@@ -65,7 +67,7 @@ export function resolveAllowedTargetOrigins(
65
67
  [establishedOrigin];
66
68
 
67
69
  const validOrigins =
68
- candidateOrigins.filter(origin => origin.isSameOriginWith(establishedOrigin)).map(origin => origin.siteId());
70
+ candidateOrigins.filter(origin => isOriginAllowedByLock(originLock, origin)).map(origin => origin.siteId());
69
71
 
70
72
  const targetOrigins = Array.from(new Set(validOrigins)).slice(0, MAX_TARGET_ORIGINS);
71
73
  if (targetOrigins.length === 0) {
@@ -131,7 +131,7 @@ const data = {
131
131
  return {error: 'Error: Could not find the context node for execution.'};
132
132
  }
133
133
 
134
- if (!isOriginAllowedByLock(context.getEstablishedOrigin(), executionNode.securityOrigin())) {
134
+ if (!isOriginAllowedByLock(context.getOriginLock(), executionNode.securityOrigin())) {
135
135
  return {error: 'Error: Cannot execute JavaScript on cross-origin target.'};
136
136
  }
137
137
 
@@ -80,8 +80,6 @@ export class GetElementAccessibilityDetailsTool implements
80
80
  params: GetElementAccessibilityDetailsArgs,
81
81
  context: BaseToolCapability&TargetCapability&OriginLockCapability,
82
82
  ): Promise<DataHandlerResult<string>> {
83
- const establishedOrigin = context.getEstablishedOrigin();
84
-
85
83
  const target = context.getTarget();
86
84
  if (!target) {
87
85
  return {error: 'Error: Inspected target not found.'};
@@ -99,7 +97,7 @@ export class GetElementAccessibilityDetailsTool implements
99
97
  // Security check: Ensure the element matches the active conversation's origin lock.
100
98
  // Because getTarget() returns the primary page target to support resolving elements
101
99
  // across frames, origin validation must be enforced directly on the resolved node.
102
- if (!isOriginAllowedByLock(establishedOrigin, resolved.securityOrigin())) {
100
+ if (!isOriginAllowedByLock(context.getOriginLock(), resolved.securityOrigin())) {
103
101
  return {error: 'Error: Node does not belong to the current origin.'};
104
102
  }
105
103
 
@@ -14,6 +14,7 @@ import {
14
14
  type DataTool,
15
15
  isOriginAllowedByLock,
16
16
  type OriginLockCapability,
17
+ resolveOriginFromLock,
17
18
  type ToolArgs,
18
19
  ToolName,
19
20
  } from './Tool.js';
@@ -75,9 +76,12 @@ export class GetNetworkRequestDetailsTool implements
75
76
  args: GetNetworkRequestDetailsArgs,
76
77
  context: BaseToolCapability&OriginLockCapability,
77
78
  ): Promise<DataHandlerResult<unknown>> {
78
- // A conversation is locked to an origin once the first query is made.
79
- // We only allow inspecting requests matching the conversation's established origin.
80
- const establishedOrigin = context.getEstablishedOrigin();
79
+ const originLock = context.getOriginLock();
80
+ const originResult = resolveOriginFromLock(originLock);
81
+ if ('error' in originResult) {
82
+ return originResult;
83
+ }
84
+ const establishedOrigin = originResult.origin;
81
85
 
82
86
  // eslint-disable-next-line @devtools/no-instance-of-migrated-singletons
83
87
  const networkLog = this.#networkLog ?? Logs.NetworkLog.NetworkLog.instance();
@@ -87,13 +91,10 @@ export class GetNetworkRequestDetailsTool implements
87
91
  }
88
92
 
89
93
  // If the conversation is locked to an origin, only allow accessing requests from that origin.
90
- return isOriginAllowedByLock(establishedOrigin, req.initiatorSecurityOrigin());
94
+ return isOriginAllowedByLock(originLock, req.initiatorSecurityOrigin());
91
95
  });
92
96
 
93
- // If establishedOrigin is undefined or opaque, isOriginAllowedByLock() fails closed,
94
- // so find() will never return a request. We check establishedOrigin here as a defensive
95
- // guard and to narrow the type for NetworkRequestFormatter below.
96
- if (!establishedOrigin || !request) {
97
+ if (!request) {
97
98
  return {
98
99
  error: 'No request found',
99
100
  };
@@ -13,6 +13,7 @@ import {
13
13
  type DataHandlerResult,
14
14
  type DataTool,
15
15
  type OriginLockCapability,
16
+ resolveOriginFromLock,
16
17
  type ToolArgs,
17
18
  ToolName,
18
19
  } from './Tool.js';
@@ -64,14 +65,12 @@ export class GetSourceContentTool implements
64
65
  args: GetSourceContentArgs,
65
66
  context: BaseToolCapability&OriginLockCapability,
66
67
  ): Promise<DataHandlerResult<{content: string}>> {
67
- const establishedOrigin = context.getEstablishedOrigin();
68
- if (!establishedOrigin) {
69
- return {
70
- error: 'Unable to find file.',
71
- };
68
+ const originResult = resolveOriginFromLock(context.getOriginLock());
69
+ if ('error' in originResult) {
70
+ return originResult;
72
71
  }
73
72
 
74
- const file = ListSourcesTool.getSourceById(args.id, establishedOrigin);
73
+ const file = ListSourcesTool.getSourceById(args.id, originResult.origin);
75
74
 
76
75
  if (!file) {
77
76
  return {
@@ -8,7 +8,8 @@ import * as Platform from '../../../core/platform/platform.js';
8
8
  import * as SDK from '../../../core/sdk/sdk.js';
9
9
  import type {FunctionHandlerOptions} from '../agents/AiAgent.js';
10
10
 
11
- import {MAX_TARGET_ORIGINS, resolveDOMStorages} from './DOMStorageUtils.js';
11
+ import {resolveAllowedTargetOrigins} from './CookieUtils.js';
12
+ import {resolveDOMStorages} from './DOMStorageUtils.js';
12
13
  import {
13
14
  type BaseToolCapability,
14
15
  type DataHandlerResult,
@@ -112,31 +113,11 @@ export class GetStorageValuesTool implements DataTool<GetStorageValuesArgs, GetS
112
113
 
113
114
  // eslint-disable-next-line @devtools/no-instance-of-migrated-singletons
114
115
  const targetManager = SDK.TargetManager.TargetManager.instance();
115
- const primaryPageTarget = targetManager.primaryPageTarget();
116
-
117
- const establishedOrigin = context.getEstablishedOrigin();
118
- if (!establishedOrigin || establishedOrigin.isOpaque()) {
119
- return {error: 'No origin available or not allowed.'};
120
- }
121
-
122
- if (!primaryPageTarget) {
123
- return {error: 'No origin available or not allowed.'};
124
- }
125
-
126
- const pageOrigin = primaryPageTarget.inspectedSecurityOrigin();
127
- if (!pageOrigin.isSameOriginWith(establishedOrigin)) {
128
- return {error: 'No origin available or not allowed.'};
129
- }
130
-
131
- const candidateOrigins: SDK.SecurityOrigin.SecurityOrigin[] = (args.origins && args.origins.length > 0) ?
132
- args.origins.map(origin => SDK.SecurityOrigin.SecurityOrigin.create(origin)) :
133
- [establishedOrigin];
134
- const validOrigins =
135
- candidateOrigins.filter(origin => origin.isSameOriginWith(establishedOrigin)).map(origin => origin.siteId());
136
- const targetOrigins = Array.from(new Set(validOrigins)).slice(0, MAX_TARGET_ORIGINS);
137
- if (targetOrigins.length === 0) {
138
- return {error: 'No valid origins found.'};
116
+ const targetOriginsResult = resolveAllowedTargetOrigins(args.origins, context, targetManager);
117
+ if ('error' in targetOriginsResult) {
118
+ return {error: targetOriginsResult.error};
139
119
  }
120
+ const {targetOrigins, primaryPageTarget} = targetOriginsResult;
140
121
 
141
122
  const storageKey = (targetOrigins.length === 1 && args.storageKey) ? args.storageKey : undefined;
142
123
 
@@ -97,8 +97,6 @@ export class GetStylesTool implements
97
97
  return {error: 'Error: Could not find the inspected page.'};
98
98
  }
99
99
 
100
- const establishedOrigin = context.getEstablishedOrigin();
101
-
102
100
  for (const uid of params.elements) {
103
101
  result[uid] = {computed: {}, authored: {}};
104
102
  const node = new SDK.DOMModel.DeferredDOMNode(target, uid as Protocol.DOM.BackendNodeId);
@@ -109,7 +107,7 @@ export class GetStylesTool implements
109
107
  // Security check: Ensure the resolved element belongs to the locked origin.
110
108
  // Because getTarget() returns the primary page target to support resolving elements
111
109
  // across frames, origin validation must be enforced directly on the resolved node.
112
- if (!isOriginAllowedByLock(establishedOrigin, resolved.securityOrigin())) {
110
+ if (!isOriginAllowedByLock(context.getOriginLock(), resolved.securityOrigin())) {
113
111
  return {error: 'Error: Node does not belong to the current origin.'};
114
112
  }
115
113
  const styles = await resolved.domModel().cssModel().getComputedStyle(resolved.id);
@@ -21,54 +21,67 @@ const UIStringsNotTranslate = {
21
21
 
22
22
  const lockedString = i18n.i18n.lockedString;
23
23
 
24
- export interface GetFunctionCodeArgs extends ToolArgs {
24
+ /**
25
+ * Arguments for {@link GetTraceFunctionCodeTool}.
26
+ */
27
+ export interface GetTraceFunctionCodeArgs extends ToolArgs {
28
+ /** The URL of the script containing the function recorded in the performance trace. */
25
29
  scriptUrl: string;
30
+ /** The line number where the function is defined (0-based, as reported in the call tree). */
26
31
  line: number;
32
+ /** The column number where the function is defined (0-based, as reported in the call tree). */
27
33
  column: number;
28
34
  }
29
35
 
30
- export class GetFunctionCodeTool implements
31
- DataTool<GetFunctionCodeArgs, string, BaseToolCapability&PerformanceTraceCapability> {
32
- readonly name: ToolName = ToolName.GET_FUNCTION_CODE;
36
+ /**
37
+ * Retrieves function code and line-by-line CPU profile execution costs from the performance trace.
38
+ *
39
+ * Preconditions:
40
+ * - Requires an active, freshly recorded trace session (fails on imported traces).
41
+ * - Requires resource access via the performance trace context.
42
+ */
43
+ export class GetTraceFunctionCodeTool implements
44
+ DataTool<GetTraceFunctionCodeArgs, string, BaseToolCapability&PerformanceTraceCapability> {
45
+ readonly name: ToolName = ToolName.GET_TRACE_FUNCTION_CODE;
33
46
  readonly description: string =
34
- 'Retrieves the code for a function defined at the given location. The result is annotated with the runtime performance of each line of code.';
47
+ 'Retrieves the code for a function recorded in the performance trace at the specified location, annotated with line-by-line CPU runtime profiling execution costs. Do not call this tool unless a performance trace recording is actively loaded.';
35
48
 
36
- readonly parameters: Host.AidaClient.FunctionObjectParam<keyof GetFunctionCodeArgs> = {
49
+ readonly parameters: Host.AidaClient.FunctionObjectParam<keyof GetTraceFunctionCodeArgs> = {
37
50
  type: Host.AidaClient.ParametersTypes.OBJECT,
38
- description: 'Arguments for looking up function code.',
51
+ description: 'Arguments for looking up function code from the performance trace profile.',
39
52
  nullable: false,
40
53
  properties: {
41
54
  scriptUrl: {
42
55
  type: Host.AidaClient.ParametersTypes.STRING,
43
- description: 'The url of the function.',
56
+ description: 'The URL of the script containing the function recorded in the performance trace.',
44
57
  nullable: false,
45
58
  },
46
59
  line: {
47
60
  type: Host.AidaClient.ParametersTypes.INTEGER,
48
- description: 'The line number where the function is defined.',
61
+ description: 'The line number where the function is defined (0-based, as reported in the call tree).',
49
62
  nullable: false,
50
63
  },
51
64
  column: {
52
65
  type: Host.AidaClient.ParametersTypes.INTEGER,
53
- description: 'The column number where the function is defined.',
66
+ description: 'The column number where the function is defined (0-based, as reported in the call tree).',
54
67
  nullable: false,
55
68
  },
56
69
  },
57
70
  required: ['scriptUrl', 'line', 'column'],
58
71
  };
59
72
 
60
- displayInfoFromArgs(params: GetFunctionCodeArgs): {
73
+ displayInfoFromArgs(params: GetTraceFunctionCodeArgs): {
61
74
  title: string,
62
75
  action: string,
63
76
  } {
64
77
  return {
65
78
  title: lockedString(UIStringsNotTranslate.lookingUpFunctionCode),
66
- action: `getFunctionCode('${params.scriptUrl}', ${params.line}, ${params.column})`,
79
+ action: `getTraceFunctionCode('${params.scriptUrl}', ${params.line}, ${params.column})`,
67
80
  };
68
81
  }
69
82
 
70
83
  async handler(
71
- params: GetFunctionCodeArgs,
84
+ params: GetTraceFunctionCodeArgs,
72
85
  capabilities: BaseToolCapability&PerformanceTraceCapability,
73
86
  ): Promise<DataHandlerResult<string>> {
74
87
  const performanceTraceContext = capabilities.getPerformanceTraceContext();
@@ -25,42 +25,57 @@ const UIStringsNotTranslate = {
25
25
 
26
26
  const lockedString = i18n.i18n.lockedString;
27
27
 
28
- export interface GetResourceContentArgs extends ToolArgs {
28
+ /**
29
+ * Arguments for {@link GetTraceResourceContentTool}.
30
+ */
31
+ export interface GetTraceResourceContentArgs extends ToolArgs {
32
+ /** The URL of the resource captured in the performance trace to retrieve. */
29
33
  url: string;
30
34
  }
31
35
 
32
- export class GetResourceContentTool implements DataTool<
33
- GetResourceContentArgs, {content: string}, BaseToolCapability&TargetCapability&PerformanceTraceCapability> {
34
- readonly name: ToolName = ToolName.GET_RESOURCE_CONTENT;
36
+ /**
37
+ * Retrieves text content for a resource or script captured in the performance trace.
38
+ *
39
+ * Precedence:
40
+ * 1. Checks trace metadata (`parsedTrace.data.Scripts`) for scripts captured during recording.
41
+ * 2. Falls back to querying the live page target's `ResourceTreeModel`.
42
+ *
43
+ * Preconditions:
44
+ * - Requires an active, freshly recorded trace session (fails on imported traces).
45
+ * - Fails if resource is binary/non-text, cross-origin, or a `file://` URL.
46
+ */
47
+ export class GetTraceResourceContentTool implements DataTool<
48
+ GetTraceResourceContentArgs, {content: string}, BaseToolCapability&TargetCapability&PerformanceTraceCapability> {
49
+ readonly name: ToolName = ToolName.GET_TRACE_RESOURCE_CONTENT;
35
50
  readonly description: string =
36
- 'Retrieves the content of the resource with the given url. Only use this for text resource types.';
51
+ 'Retrieves the text content of a script or resource captured within the recorded performance trace by URL. Only use this for text resource types. Do not call this tool on imported traces or for general workspace files (use listSources and getSourceContent instead).';
37
52
 
38
- readonly parameters: Host.AidaClient.FunctionObjectParam<keyof GetResourceContentArgs> = {
53
+ readonly parameters: Host.AidaClient.FunctionObjectParam<keyof GetTraceResourceContentArgs> = {
39
54
  type: Host.AidaClient.ParametersTypes.OBJECT,
40
- description: 'Arguments for looking up resource content.',
55
+ description: 'Arguments for looking up resource content from the performance trace.',
41
56
  nullable: false,
42
57
  properties: {
43
58
  url: {
44
59
  type: Host.AidaClient.ParametersTypes.STRING,
45
- description: 'The url for the resource.',
60
+ description: 'The URL of the resource captured in the performance trace to retrieve.',
46
61
  nullable: false,
47
62
  },
48
63
  },
49
64
  required: ['url'],
50
65
  };
51
66
 
52
- displayInfoFromArgs(params: GetResourceContentArgs): {
67
+ displayInfoFromArgs(params: GetTraceResourceContentArgs): {
53
68
  title: string,
54
69
  action: string,
55
70
  } {
56
71
  return {
57
72
  title: lockedString(UIStringsNotTranslate.lookingAtResourceContent),
58
- action: `getResourceContent('${params.url}')`,
73
+ action: `getTraceResourceContent('${params.url}')`,
59
74
  };
60
75
  }
61
76
 
62
77
  async handler(
63
- params: GetResourceContentArgs,
78
+ params: GetTraceResourceContentArgs,
64
79
  capabilities: BaseToolCapability&TargetCapability&PerformanceTraceCapability,
65
80
  ): Promise<DataHandlerResult<{content: string}>> {
66
81
  const performanceTraceContext = capabilities.getPerformanceTraceContext();
@@ -72,6 +87,10 @@ export class GetResourceContentTool implements DataTool<
72
87
  return {error: 'Cannot use this tool on an imported file.'};
73
88
  }
74
89
 
90
+ if (!params.url) {
91
+ return {error: 'Missing arg: url'};
92
+ }
93
+
75
94
  if (!performanceTraceContext.canAccessResource(params.url)) {
76
95
  return {error: 'Resource not found'};
77
96
  }
@@ -82,6 +101,7 @@ export class GetResourceContentTool implements DataTool<
82
101
  let content: string;
83
102
 
84
103
  const url = params.url as Platform.DevToolsPath.UrlString;
104
+ // Check trace metadata for scripts captured during recording before falling back to live page resources.
85
105
  const script = parsedTrace.data.Scripts?.scripts.find(script => script.url === params.url);
86
106
  if (script?.content !== undefined) {
87
107
  content = script.content;