chrome-devtools-frontend 1.0.1652307 → 1.0.1656291
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/.agents/skills/fixing-skipped-tests/SKILL.md +32 -0
- package/.agents/skills/migrate-chromium-test/SKILL.md +144 -0
- package/.agents/skills/ui-eng-vision-local-lit-renderer/SKILL.md +116 -0
- package/.agents/skills/ui-eng-vision-logic-consolidator/SKILL.md +82 -0
- package/.agents/skills/ui-eng-vision-orchestrator/SKILL.md +123 -0
- package/.agents/skills/ui-eng-vision-test-scaffolder/SKILL.md +125 -0
- package/.agents/skills/ui-eng-vision-widget-promoter/SKILL.md +75 -0
- package/AUTHORS +1 -0
- package/config/owner/COMMON_OWNERS +0 -4
- package/docs/get_the_code.md +1 -2
- package/docs/playbook.md +1 -1
- package/docs/ui_engineering.md +3 -1
- package/eslint.config.mjs +0 -5
- package/front_end/Tests.js +1 -0
- package/front_end/core/common/Settings.ts +47 -30
- package/front_end/core/sdk/CPUThrottlingManager.ts +23 -167
- package/front_end/core/sdk/CSSMetadata.ts +23 -0
- package/front_end/core/sdk/CompilerSourceMappingContentProvider.ts +8 -4
- package/front_end/core/sdk/ConsoleModel.ts +13 -11
- package/front_end/core/sdk/DOMDebuggerModel.ts +11 -5
- package/front_end/core/sdk/DOMModel.ts +4 -0
- package/front_end/core/sdk/EmulationModel.ts +4 -0
- package/front_end/core/sdk/EventBreakpointsModel.ts +9 -5
- package/front_end/core/sdk/IsolateManager.ts +6 -6
- package/front_end/core/sdk/ResourceTreeModel.ts +8 -5
- package/front_end/core/sdk/TargetManager.ts +17 -0
- package/front_end/entrypoints/devtools_app/devtools_app.ts +0 -1
- package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +459 -74
- package/front_end/entrypoints/main/MainImpl.ts +12 -42
- package/front_end/foundation/Universe.ts +116 -3
- package/front_end/generated/InspectorBackendCommands.ts +11 -6
- package/front_end/generated/SupportedCSSProperties.js +124 -34
- package/front_end/generated/protocol-mapping.d.ts +8 -0
- package/front_end/generated/protocol-proxy-api.d.ts +15 -0
- package/front_end/generated/protocol.ts +94 -1
- package/front_end/models/ai_assistance/AiConversation.ts +2 -7
- package/front_end/models/ai_assistance/README.md +4 -3
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +1 -1
- package/front_end/models/ai_assistance/agents/NetworkAgent.snapshot.txt +1 -1
- package/front_end/models/ai_assistance/agents/PerformanceAgent.snapshot.txt +2 -2
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +13 -320
- package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +0 -24
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +2 -358
- package/front_end/models/ai_assistance/ai_assistance.ts +6 -8
- package/front_end/models/ai_assistance/contexts/PerformanceTraceContext.ts +295 -0
- package/front_end/models/ai_assistance/contexts/RequestContext.snapshot.txt +0 -1
- package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +0 -2
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +10 -10
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +12 -11
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +6 -6
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +1 -14
- package/front_end/models/ai_assistance/skills/accessibility.md +4 -2
- package/front_end/models/ai_assistance/tools/GetElementAccessibilityDetails.ts +142 -0
- package/front_end/models/ai_assistance/tools/GetStyles.ts +1 -1
- package/front_end/models/ai_assistance/tools/README.md +21 -1
- package/front_end/models/ai_assistance/tools/{ResolveLighthousePath.ts → ResolveDevtoolsNodePath.ts} +18 -17
- package/front_end/models/ai_assistance/tools/Tool.ts +6 -1
- package/front_end/models/ai_assistance/tools/ToolRegistry.ts +4 -2
- package/front_end/models/autofill_manager/AutofillManager.ts +6 -15
- package/front_end/models/bindings/NetworkProject.ts +4 -8
- package/front_end/models/breakpoints/BreakpointManager.ts +9 -9
- package/front_end/models/emulation/DeviceModeModel.ts +24 -0
- package/front_end/models/emulation/EmulatedDevices.ts +108 -0
- package/front_end/models/heap_snapshot/HeapSnapshotModel.ts +36 -0
- package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +8 -0
- package/front_end/models/issues_manager/IssuesManager.ts +10 -6
- package/front_end/models/javascript_metadata/JavaScriptMetadata.ts +4 -5
- package/front_end/models/javascript_metadata/NativeFunctions.js +1 -1
- package/front_end/models/live-metrics/LiveMetrics.ts +6 -6
- package/front_end/models/live-metrics/web-vitals-injected/spec/spec.ts +5 -5
- package/front_end/models/live-metrics/web-vitals-injected/web-vitals-injected.ts +3 -3
- package/front_end/models/logs/LogManager.ts +25 -10
- package/front_end/models/logs/NetworkLog.ts +24 -19
- package/front_end/models/persistence/AutomaticFileSystemManager.ts +14 -13
- package/front_end/models/persistence/AutomaticFileSystemWorkspaceBinding.ts +26 -14
- package/front_end/models/persistence/IsolatedFileSystem.ts +9 -11
- package/front_end/models/persistence/IsolatedFileSystemManager.ts +22 -11
- package/front_end/models/persistence/NetworkPersistenceManager.ts +73 -44
- package/front_end/models/persistence/PersistenceImpl.ts +4 -5
- package/front_end/models/project_settings/ProjectSettingsModel.ts +12 -11
- package/front_end/models/trace/EntityMapper.ts +1 -1
- package/front_end/models/trace/handlers/ScreenshotsHandler.ts +14 -59
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +12 -38
- package/front_end/panels/ai_assistance/ExportConversation.ts +4 -1
- package/front_end/panels/ai_assistance/components/ChatInput.ts +2 -2
- package/front_end/panels/application/DeviceBoundSessionsView.ts +15 -3
- package/front_end/panels/application/FrameDetailsView.ts +2 -1
- package/front_end/panels/application/IndexedDBViews.ts +38 -36
- package/front_end/panels/application/ServiceWorkersView.ts +23 -16
- package/front_end/panels/application/components/AdsView.ts +4 -0
- package/front_end/panels/autofill/AutofillView.ts +1 -1
- package/front_end/panels/autofill/autofill-meta.ts +3 -2
- package/front_end/panels/common/CPUThrottlingOption.ts +142 -0
- package/front_end/panels/common/ThrottlingUtils.ts +9 -4
- package/front_end/panels/common/common.ts +1 -1
- package/front_end/panels/console/ConsoleViewMessage.ts +45 -0
- package/front_end/panels/elements/AccessibilityTreeUtils.ts +26 -15
- package/front_end/panels/elements/AccessibilityTreeView.ts +12 -9
- package/front_end/panels/elements/ElementsPanel.ts +0 -74
- package/front_end/panels/elements/ElementsTreeOutline.ts +5 -4
- package/front_end/panels/emulation/DeviceModeToolbar.ts +46 -45
- package/front_end/panels/layer_viewer/LayerTreeOutline.ts +118 -68
- package/front_end/panels/layer_viewer/Layers3DView.ts +1 -1
- package/front_end/panels/layer_viewer/layerTreeOutline.css +20 -13
- package/front_end/panels/layers/LayersPanel.ts +1 -1
- package/front_end/panels/mobile_throttling/CalibrationController.ts +6 -5
- package/front_end/panels/mobile_throttling/MobileThrottlingSelector.ts +1 -1
- package/front_end/panels/mobile_throttling/ThrottlingManager.ts +40 -13
- package/front_end/panels/mobile_throttling/ThrottlingPresets.ts +13 -17
- package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +79 -30
- package/front_end/panels/mobile_throttling/throttlingSettingsTab.css +5 -0
- package/front_end/panels/network/LinkPreloadGenerator.ts +101 -0
- package/front_end/panels/network/NetworkLogView.ts +28 -9
- package/front_end/panels/network/NetworkPanel.ts +1 -63
- package/front_end/panels/network/RequestInitiatorView.ts +29 -4
- package/front_end/panels/network/components/HeaderSectionRow.css +9 -7
- package/front_end/panels/network/components/HeaderSectionRow.ts +20 -1
- package/front_end/panels/network/components/RequestHeaderSection.css +5 -3
- package/front_end/panels/network/components/RequestHeaderSection.ts +1 -2
- package/front_end/panels/network/components/RequestHeadersView.css +1 -1
- package/front_end/panels/network/network.ts +2 -0
- package/front_end/panels/profiler/HeapSnapshotView.ts +121 -33
- package/front_end/panels/profiler/ModuleUIStrings.ts +4 -0
- package/front_end/panels/security/SecurityPanel.ts +36 -23
- package/front_end/panels/settings/SettingsScreen.ts +18 -103
- package/front_end/panels/settings/settings-meta.ts +0 -24
- package/front_end/panels/timeline/TimelineController.ts +3 -2
- package/front_end/panels/timeline/TimelineHistoryManager.ts +38 -37
- package/front_end/panels/timeline/TimelinePanel.ts +52 -11
- package/front_end/panels/timeline/components/CPUThrottlingSelector.ts +20 -18
- package/front_end/panels/timeline/components/LiveMetricsView.ts +38 -38
- package/front_end/panels/timeline/components/MetricCard.ts +18 -18
- package/front_end/panels/timeline/components/liveMetricsView.css +6 -6
- package/front_end/panels/timeline/components/metricCard.css +4 -4
- package/front_end/panels/timeline/timelineFlamechartPopover.css +2 -0
- package/front_end/panels/utils/utils.ts +25 -24
- package/front_end/panels/whats_new/ReleaseNoteText.ts +3 -3
- package/front_end/panels/whats_new/resources/WNDT.md +1 -1
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/puppeteer/README.chromium +2 -2
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +34 -55
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +96 -83
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Browser.d.ts +10 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Browser.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Browser.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/BrowserContext.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/BrowserContext.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/BrowserContext.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/CDPSession.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/CDPSession.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/HTTPResponse.d.ts +3 -2
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/HTTPResponse.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/HTTPResponse.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Realm.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Realm.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Target.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Target.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/locators/locators.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/locators/locators.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/HTTPResponse.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/HTTPResponse.js +2 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/HTTPResponse.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/core/Realm.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/core/Realm.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.js +5 -2
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Frame.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Frame.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/FrameManager.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/FrameManager.js +23 -13
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/FrameManager.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/HTTPResponse.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/HTTPResponse.js +4 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/HTTPResponse.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Input.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/LifecycleWatcher.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/LifecycleWatcher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Target.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Target.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/WebMCP.d.ts +3 -41
- 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.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/common/ConnectOptions.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/node/BrowserLauncher.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/node/BrowserLauncher.js +4 -2
- package/front_end/third_party/puppeteer/package/lib/puppeteer/node/BrowserLauncher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/node/LaunchOptions.d.ts +5 -0
- package/front_end/third_party/puppeteer/package/lib/puppeteer/node/LaunchOptions.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/util/httpUtils.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/util/httpUtils.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/util/httpUtils.js +5 -5
- package/front_end/third_party/puppeteer/package/lib/puppeteer/util/httpUtils.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 +34 -55
- package/front_end/third_party/puppeteer/package/package.json +4 -4
- package/front_end/third_party/puppeteer/package/src/api/Browser.ts +13 -1
- package/front_end/third_party/puppeteer/package/src/api/BrowserContext.ts +2 -3
- package/front_end/third_party/puppeteer/package/src/api/CDPSession.ts +3 -1
- package/front_end/third_party/puppeteer/package/src/api/HTTPResponse.ts +3 -2
- package/front_end/third_party/puppeteer/package/src/api/Realm.ts +1 -2
- package/front_end/third_party/puppeteer/package/src/api/Target.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/api/locators/locators.ts +1 -2
- package/front_end/third_party/puppeteer/package/src/bidi/HTTPResponse.ts +3 -1
- package/front_end/third_party/puppeteer/package/src/bidi/core/Realm.ts +1 -3
- package/front_end/third_party/puppeteer/package/src/cdp/Browser.ts +13 -3
- package/front_end/third_party/puppeteer/package/src/cdp/Frame.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/cdp/FrameManager.ts +24 -13
- package/front_end/third_party/puppeteer/package/src/cdp/HTTPResponse.ts +4 -1
- package/front_end/third_party/puppeteer/package/src/cdp/Input.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/cdp/LifecycleWatcher.ts +1 -4
- package/front_end/third_party/puppeteer/package/src/cdp/Target.ts +2 -4
- package/front_end/third_party/puppeteer/package/src/cdp/WebMCP.ts +7 -76
- package/front_end/third_party/puppeteer/package/src/common/ConnectOptions.ts +1 -4
- package/front_end/third_party/puppeteer/package/src/node/BrowserLauncher.ts +4 -1
- package/front_end/third_party/puppeteer/package/src/node/LaunchOptions.ts +5 -0
- package/front_end/third_party/puppeteer/package/src/revisions.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/util/httpUtils.ts +5 -5
- package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
- package/front_end/third_party/puppeteer/third_party/parsel/README.chromium +1 -1
- package/front_end/ui/components/dialogs/Dialog.ts +3 -0
- package/front_end/ui/components/markdown_view/MarkdownLinksMap.ts +0 -7
- package/front_end/ui/helpers/OpenInNewTab.ts +15 -7
- package/front_end/ui/legacy/InspectorDrawerView.ts +7 -5
- package/front_end/ui/legacy/ListWidget.ts +12 -0
- package/front_end/ui/legacy/SplitWidget.ts +12 -11
- package/front_end/ui/legacy/TabbedPane.ts +1 -108
- package/front_end/ui/legacy/components/data_grid/DataGrid.ts +9 -0
- package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +192 -139
- package/front_end/ui/legacy/components/data_grid/DataGridExporter.ts +89 -0
- package/front_end/ui/legacy/components/data_grid/dataGrid.css +10 -0
- package/front_end/ui/legacy/components/data_grid/data_grid.ts +3 -1
- package/front_end/ui/legacy/components/object_ui/CustomPreviewComponent.ts +8 -1
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +110 -17
- package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +89 -40
- package/front_end/ui/legacy/treeoutline.css +1 -1
- package/front_end/ui/visual_logging/KnownContextValues.ts +3 -0
- package/package.json +4 -3
- package/front_end/Images/navigationControls.png +0 -0
- package/front_end/Images/navigationControls_2x.png +0 -0
- package/front_end/Images/popoverArrows.png +0 -0
- package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +0 -746
- package/front_end/entrypoints/greendev_floaty/floaty.css +0 -301
- package/front_end/entrypoints/greendev_floaty/floaty.html +0 -38
- package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +0 -415
- package/front_end/models/ai_assistance/agents/GreenDevAgent.ts +0 -834
- package/front_end/models/ai_assistance/agents/GreenDevAgentAntigravityCliSocketClient.ts +0 -53
- package/front_end/models/ai_assistance/agents/GreenDevAgentGeminiCliSocketClient.ts +0 -117
- package/front_end/models/annotations/AnnotationRepository.ts +0 -238
- package/front_end/models/annotations/AnnotationType.ts +0 -10
- package/front_end/models/annotations/README.md +0 -7
- package/front_end/models/annotations/annotations.ts +0 -6
- package/front_end/models/greendev/Prototypes.ts +0 -68
- package/front_end/models/greendev/README.md +0 -5
- package/front_end/models/greendev/greendev.ts +0 -5
- package/front_end/panels/common/Annotation.ts +0 -184
- package/front_end/panels/common/AnnotationManager.ts +0 -208
- package/front_end/panels/common/annotation.css +0 -40
- package/front_end/panels/greendev/GreenDevPanel.css +0 -282
- package/front_end/panels/greendev/GreenDevPanel.ts +0 -364
- package/front_end/panels/greendev/GreenDevShared.ts +0 -13
- package/front_end/panels/greendev/greendev-meta.ts +0 -52
- package/front_end/panels/greendev/greendev.ts +0 -9
|
@@ -0,0 +1,142 @@
|
|
|
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
|
+
import * as Host from '../../../core/host/host.js';
|
|
6
|
+
import * as i18n from '../../../core/i18n/i18n.js';
|
|
7
|
+
import * as SDK from '../../../core/sdk/sdk.js';
|
|
8
|
+
import type * as Protocol from '../../../generated/protocol.js';
|
|
9
|
+
import type {FunctionCallHandlerResult} from '../agents/AiAgent.js';
|
|
10
|
+
import {DOMNodeContext} from '../contexts/DOMNodeContext.js';
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
type BaseToolCapability,
|
|
14
|
+
type OriginLockCapability,
|
|
15
|
+
type TargetCapability,
|
|
16
|
+
type Tool,
|
|
17
|
+
type ToolArgs,
|
|
18
|
+
ToolName,
|
|
19
|
+
} from './Tool.js';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Arguments for getting accessibility details of an element.
|
|
23
|
+
*/
|
|
24
|
+
export interface GetElementAccessibilityDetailsArgs extends ToolArgs {
|
|
25
|
+
/**
|
|
26
|
+
* The backend node ID of the element to inspect.
|
|
27
|
+
*/
|
|
28
|
+
element: number;
|
|
29
|
+
explanation: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* A tool that retrieves fine-grained accessibility properties (role, name, ARIA properties, focus state)
|
|
34
|
+
* for a resolved element backend node ID. It also returns a DOM snapshot of the element's subtree.
|
|
35
|
+
*/
|
|
36
|
+
export class GetElementAccessibilityDetailsTool implements
|
|
37
|
+
Tool<GetElementAccessibilityDetailsArgs, string, BaseToolCapability&TargetCapability&OriginLockCapability> {
|
|
38
|
+
readonly name = ToolName.GET_ELEMENT_ACCESSIBILITY_DETAILS;
|
|
39
|
+
readonly description =
|
|
40
|
+
'Get detailed accessibility information for an element on the inspected page by its backend node ID.';
|
|
41
|
+
|
|
42
|
+
readonly parameters: Host.AidaClient.FunctionObjectParam<keyof GetElementAccessibilityDetailsArgs> = {
|
|
43
|
+
type: Host.AidaClient.ParametersTypes.OBJECT,
|
|
44
|
+
description: 'Arguments for getting element accessibility details.',
|
|
45
|
+
nullable: false,
|
|
46
|
+
properties: {
|
|
47
|
+
explanation: {
|
|
48
|
+
type: Host.AidaClient.ParametersTypes.STRING,
|
|
49
|
+
description: 'Reason for requesting accessibility details.',
|
|
50
|
+
nullable: false,
|
|
51
|
+
},
|
|
52
|
+
element: {
|
|
53
|
+
type: Host.AidaClient.ParametersTypes.INTEGER,
|
|
54
|
+
description: 'The backend node ID of the element.',
|
|
55
|
+
nullable: false,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
required: ['explanation', 'element'],
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
displayInfoFromArgs(params: GetElementAccessibilityDetailsArgs): {
|
|
62
|
+
title: string,
|
|
63
|
+
thought: string,
|
|
64
|
+
action: string,
|
|
65
|
+
} {
|
|
66
|
+
return {
|
|
67
|
+
title: 'Reading accessibility details',
|
|
68
|
+
thought: params.explanation,
|
|
69
|
+
action: `getElementAccessibilityDetails(${params.element})`,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Handles the request to retrieve accessibility details.
|
|
75
|
+
*
|
|
76
|
+
* Resolves the element backend node ID, validates its origin against the locked origin,
|
|
77
|
+
* requests the AX subtree via AccessibilityModel, and maps the relevant attributes.
|
|
78
|
+
*/
|
|
79
|
+
async handler(
|
|
80
|
+
params: GetElementAccessibilityDetailsArgs,
|
|
81
|
+
context: BaseToolCapability&TargetCapability&OriginLockCapability,
|
|
82
|
+
): Promise<FunctionCallHandlerResult<string>> {
|
|
83
|
+
const establishedOrigin = context.getEstablishedOrigin();
|
|
84
|
+
if (!establishedOrigin) {
|
|
85
|
+
return {error: 'Error: Origin lock is not established.'};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const target = context.getTarget();
|
|
89
|
+
if (!target) {
|
|
90
|
+
return {error: 'Error: Inspected target not found.'};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Resolve the backend node ID to an SDK DOMNode. We use DeferredDOMNode
|
|
94
|
+
// because the backend node ID is the stable identifier received from external
|
|
95
|
+
// sources (like Lighthouse audits), and we need to fetch the local node object to query it.
|
|
96
|
+
const deferredNode = new SDK.DOMModel.DeferredDOMNode(target, params.element as Protocol.DOM.BackendNodeId);
|
|
97
|
+
const resolved = await deferredNode.resolvePromise();
|
|
98
|
+
if (!resolved) {
|
|
99
|
+
return {error: 'Error: Could not resolve element by ID.'};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const nodeContext = new DOMNodeContext(resolved);
|
|
103
|
+
// Security check: Ensure the element matches the active conversation's origin lock.
|
|
104
|
+
if (!nodeContext.isOriginAllowed(establishedOrigin)) {
|
|
105
|
+
return {error: 'Error: Node does not belong to the locked origin.'};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const axModel = target.model(SDK.AccessibilityModel.AccessibilityModel);
|
|
109
|
+
if (!axModel) {
|
|
110
|
+
return {error: 'Error: Accessibility model not found.'};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Accessibility data is not loaded by default for all nodes to optimize performance.
|
|
114
|
+
// We must explicitly request and load the accessibility subtree for the resolved node before querying.
|
|
115
|
+
await axModel.requestAndLoadSubTreeToNode(resolved);
|
|
116
|
+
const axNode = axModel.axNodeForDOMNode(resolved);
|
|
117
|
+
if (!axNode) {
|
|
118
|
+
return {error: 'Error: AX node details not found.'};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const properties = {
|
|
122
|
+
role: axNode.role()?.value,
|
|
123
|
+
name: axNode.name()?.value,
|
|
124
|
+
properties: axNode.properties()?.map(p => ({name: p.name, value: p.value?.value})) ?? [],
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// Take a snapshot of the resolved node's DOM structure. This is required
|
|
128
|
+
// by the DOM_TREE UI widget to render the element's local tree in the AI response panel.
|
|
129
|
+
const snapshot = await resolved.takeSnapshot();
|
|
130
|
+
return {
|
|
131
|
+
result: JSON.stringify(properties, null, 2),
|
|
132
|
+
widgets: [{
|
|
133
|
+
name: 'DOM_TREE',
|
|
134
|
+
data: {
|
|
135
|
+
root: snapshot,
|
|
136
|
+
title: i18n.i18n.lockedString('Element details'),
|
|
137
|
+
accessibleRevealLabel: i18n.i18n.lockedString('Reveal element'),
|
|
138
|
+
},
|
|
139
|
+
}],
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -105,7 +105,7 @@ export class GetStylesTool implements
|
|
|
105
105
|
return {error: 'Error: Could not find the element with uid=' + uid};
|
|
106
106
|
}
|
|
107
107
|
const newContext = new DOMNodeContext(resolved);
|
|
108
|
-
if (
|
|
108
|
+
if (!newContext.isOriginAllowed(establishedOrigin)) {
|
|
109
109
|
return {error: 'Error: Node does not belong to the current origin.'};
|
|
110
110
|
}
|
|
111
111
|
const styles = await resolved.domModel().cssModel().getComputedStyle(resolved.id);
|
|
@@ -17,12 +17,30 @@ Instead of passing a monolithic "grab-bag" context object to all tool handlers,
|
|
|
17
17
|
- `PageExecutionCapability`: For tools executing JavaScript code on the inspected page.
|
|
18
18
|
- `StyleMutationCapability`: For tools managing and applying style mutations via a `ChangeManager`.
|
|
19
19
|
- `TargetCapability`: For tools requiring access to the page's current SDK `Target`.
|
|
20
|
-
- `OriginLockCapability`: For tools enforcing cross-origin security via origin locks. Tools that fetch resources or state from the inspected page (such as styling or source code) must use this capability to verify that the target resource matches the conversation's established origin. This prevents the LLM from executing tools against out-of-origin elements or documents.
|
|
20
|
+
- `OriginLockCapability`: For tools enforcing cross-origin security via origin locks. Tools that fetch resources or state from the inspected page (such as styling or source code) must use this capability to verify that the target resource matches the conversation's established origin. This prevents the LLM from executing tools against out-of-origin elements or documents. Verification should be done by wrapping resolved resources in helper context classes (e.g., `DOMNodeContext`) and calling `isOriginAllowed(establishedOrigin)`.
|
|
21
21
|
|
|
22
22
|
### Unified Context
|
|
23
23
|
|
|
24
24
|
The Agent (e.g., `AiAgent2`) builds the complete dependency union (`AllToolsCapabilities`) and fulfills all capabilities. When the handler is invoked, TypeScript validates that the provided context matches the intersection of capabilities requested by that tool.
|
|
25
25
|
|
|
26
|
+
## Returning UI Widgets
|
|
27
|
+
|
|
28
|
+
Tools can return rich UI components (widgets) to be rendered directly in the AI Assistance panel alongside text results. To do this, include the widget payload in the `widgets` field of the returned `FunctionCallHandlerResult`:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
return {
|
|
32
|
+
result: JSON.stringify(properties, null, 2),
|
|
33
|
+
widgets: [{
|
|
34
|
+
name: 'DOM_TREE',
|
|
35
|
+
data: {
|
|
36
|
+
root: snapshot,
|
|
37
|
+
title: i18n.i18n.lockedString('Element details'),
|
|
38
|
+
accessibleRevealLabel: i18n.i18n.lockedString('Reveal element'),
|
|
39
|
+
},
|
|
40
|
+
}],
|
|
41
|
+
};
|
|
42
|
+
```
|
|
43
|
+
|
|
26
44
|
## Authoring a New Tool
|
|
27
45
|
|
|
28
46
|
To author a new tool:
|
|
@@ -35,6 +53,8 @@ To author a new tool:
|
|
|
35
53
|
See concrete, production examples of capability-based tools in this directory:
|
|
36
54
|
- [ExecuteJavaScript.ts](ExecuteJavaScript.ts): Demonstrates use of `PageExecutionCapability` and `StyleMutationCapability`.
|
|
37
55
|
- [GetStyles.ts](GetStyles.ts): Demonstrates use of `TargetCapability` and `OriginLockCapability`.
|
|
56
|
+
- [GetElementAccessibilityDetails.ts](GetElementAccessibilityDetails.ts): Demonstrates returning UI widgets (`DOM_TREE`) and origin checks with context wrappers.
|
|
57
|
+
- [ResolveDevtoolsNodePath.ts](ResolveDevtoolsNodePath.ts): Demonstrates path resolution input validation and origin lock checks.
|
|
38
58
|
|
|
39
59
|
## ToolRegistry Lookup
|
|
40
60
|
|
package/front_end/models/ai_assistance/tools/{ResolveLighthousePath.ts → ResolveDevtoolsNodePath.ts}
RENAMED
|
@@ -17,11 +17,11 @@ import {
|
|
|
17
17
|
} from './Tool.js';
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
* Arguments for resolving a
|
|
20
|
+
* Arguments for resolving a DevTools node path to a backend node ID.
|
|
21
21
|
*/
|
|
22
|
-
export interface
|
|
22
|
+
export interface ResolveDevtoolsNodePathArgs extends ToolArgs {
|
|
23
23
|
/**
|
|
24
|
-
* A
|
|
24
|
+
* A DevTools node path.
|
|
25
25
|
* This is typically a comma-separated list of child indices and tag names
|
|
26
26
|
* representing the path from the root to the target element (e.g., "1,HTML,1,BODY").
|
|
27
27
|
*/
|
|
@@ -30,19 +30,20 @@ export interface ResolveLighthousePathArgs extends ToolArgs {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
* A tool that resolves a
|
|
33
|
+
* A tool that resolves a DevTools node path to a backend node ID.
|
|
34
34
|
*
|
|
35
35
|
* This is used by the AI assistant to identify specific DOM nodes referred to in
|
|
36
|
-
* Lighthouse reports
|
|
36
|
+
* Lighthouse reports or other sources using node paths. It ensures the resolved node
|
|
37
|
+
* belongs to the locked origin.
|
|
37
38
|
*/
|
|
38
|
-
export class
|
|
39
|
-
|
|
40
|
-
readonly name = ToolName.
|
|
41
|
-
readonly description = 'Resolves a
|
|
39
|
+
export class ResolveDevtoolsNodePathTool implements Tool<ResolveDevtoolsNodePathArgs, {backendNodeId: number},
|
|
40
|
+
BaseToolCapability&TargetCapability&OriginLockCapability> {
|
|
41
|
+
readonly name = ToolName.RESOLVE_DEVTOOLS_NODE_PATH;
|
|
42
|
+
readonly description = 'Resolves a DevTools node path to a backend node ID.';
|
|
42
43
|
|
|
43
|
-
readonly parameters: Host.AidaClient.FunctionObjectParam<keyof
|
|
44
|
+
readonly parameters: Host.AidaClient.FunctionObjectParam<keyof ResolveDevtoolsNodePathArgs> = {
|
|
44
45
|
type: Host.AidaClient.ParametersTypes.OBJECT,
|
|
45
|
-
description: 'Arguments for resolving a
|
|
46
|
+
description: 'Arguments for resolving a DevTools node path to a backend node ID.',
|
|
46
47
|
nullable: false,
|
|
47
48
|
properties: {
|
|
48
49
|
explanation: {
|
|
@@ -52,14 +53,14 @@ export class ResolveLighthousePathTool implements
|
|
|
52
53
|
},
|
|
53
54
|
path: {
|
|
54
55
|
type: Host.AidaClient.ParametersTypes.STRING,
|
|
55
|
-
description: '
|
|
56
|
+
description: 'DevTools node path string.',
|
|
56
57
|
nullable: false,
|
|
57
58
|
},
|
|
58
59
|
},
|
|
59
60
|
required: ['explanation', 'path'],
|
|
60
61
|
};
|
|
61
62
|
|
|
62
|
-
displayInfoFromArgs(params:
|
|
63
|
+
displayInfoFromArgs(params: ResolveDevtoolsNodePathArgs): {
|
|
63
64
|
title: string,
|
|
64
65
|
thought: string,
|
|
65
66
|
action: string,
|
|
@@ -67,7 +68,7 @@ export class ResolveLighthousePathTool implements
|
|
|
67
68
|
return {
|
|
68
69
|
title: 'Resolving element path',
|
|
69
70
|
thought: params.explanation,
|
|
70
|
-
action: `
|
|
71
|
+
action: `resolveDevtoolsNodePath('${params.path}')`,
|
|
71
72
|
};
|
|
72
73
|
}
|
|
73
74
|
|
|
@@ -79,7 +80,7 @@ export class ResolveLighthousePathTool implements
|
|
|
79
80
|
* access to nodes from other origins.
|
|
80
81
|
*/
|
|
81
82
|
async handler(
|
|
82
|
-
params:
|
|
83
|
+
params: ResolveDevtoolsNodePathArgs,
|
|
83
84
|
context: BaseToolCapability&TargetCapability&OriginLockCapability,
|
|
84
85
|
): Promise<FunctionCallHandlerResult<{backendNodeId: number}>> {
|
|
85
86
|
const establishedOrigin = context.getEstablishedOrigin();
|
|
@@ -95,11 +96,11 @@ export class ResolveLighthousePathTool implements
|
|
|
95
96
|
|
|
96
97
|
let nodeId;
|
|
97
98
|
try {
|
|
98
|
-
// Resolves the
|
|
99
|
+
// Resolves the DevTools node path (a representation of the path to a node)
|
|
99
100
|
// and ensures the node is loaded into the frontend DOM model, returning its ID.
|
|
100
101
|
nodeId = await domModel.pushNodeByPathToFrontend(params.path);
|
|
101
102
|
} catch {
|
|
102
|
-
|
|
103
|
+
// pushNodeByPathToFrontend can fail or return undefined
|
|
103
104
|
}
|
|
104
105
|
if (!nodeId) {
|
|
105
106
|
return {error: 'Error: Could not find node by path.'};
|
|
@@ -98,7 +98,8 @@ export const enum ToolName {
|
|
|
98
98
|
LIST_NETWORK_REQUESTS = 'listNetworkRequests',
|
|
99
99
|
GET_NETWORK_REQUEST_DETAILS = 'getNetworkRequestDetails',
|
|
100
100
|
GET_LIGHTHOUSE_AUDITS = 'getLighthouseAudits',
|
|
101
|
-
|
|
101
|
+
RESOLVE_DEVTOOLS_NODE_PATH = 'resolveDevtoolsNodePath',
|
|
102
|
+
GET_ELEMENT_ACCESSIBILITY_DETAILS = 'getElementAccessibilityDetails',
|
|
102
103
|
}
|
|
103
104
|
|
|
104
105
|
/**
|
|
@@ -125,6 +126,10 @@ export interface BaseTool {
|
|
|
125
126
|
export interface Tool<Args extends ToolArgs = ToolArgs, ReturnType = unknown,
|
|
126
127
|
ContextType extends BaseToolCapability = BaseToolCapability> extends BaseTool {
|
|
127
128
|
readonly parameters: Host.AidaClient.FunctionObjectParam<keyof Args>;
|
|
129
|
+
/**
|
|
130
|
+
* Converts the tool arguments into user-friendly display information.
|
|
131
|
+
* This is used by the UI to show what the agent is doing (e.g., in the history/steps log).
|
|
132
|
+
*/
|
|
128
133
|
readonly displayInfoFromArgs?: (
|
|
129
134
|
args: Args,
|
|
130
135
|
) => {
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
5
|
import {ExecuteJavaScriptTool} from './ExecuteJavaScript.js';
|
|
6
|
+
import {GetElementAccessibilityDetailsTool} from './GetElementAccessibilityDetails.js';
|
|
6
7
|
import {GetLighthouseAuditsTool} from './GetLighthouseAudits.js';
|
|
7
8
|
import {GetNetworkRequestDetailsTool} from './GetNetworkRequestDetails.js';
|
|
8
9
|
import {GetStylesTool} from './GetStyles.js';
|
|
9
10
|
import {ListNetworkRequestsTool} from './ListNetworkRequests.js';
|
|
10
|
-
import {
|
|
11
|
+
import {ResolveDevtoolsNodePathTool} from './ResolveDevtoolsNodePath.js';
|
|
11
12
|
import {type AllToolsCapabilities, type Tool, type ToolArgs, ToolName} from './Tool.js';
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -24,7 +25,8 @@ export const TOOLS = {
|
|
|
24
25
|
[ToolName.LIST_NETWORK_REQUESTS]: new ListNetworkRequestsTool(),
|
|
25
26
|
[ToolName.GET_NETWORK_REQUEST_DETAILS]: new GetNetworkRequestDetailsTool(),
|
|
26
27
|
[ToolName.GET_LIGHTHOUSE_AUDITS]: new GetLighthouseAuditsTool(),
|
|
27
|
-
[ToolName.
|
|
28
|
+
[ToolName.RESOLVE_DEVTOOLS_NODE_PATH]: new ResolveDevtoolsNodePathTool(),
|
|
29
|
+
[ToolName.GET_ELEMENT_ACCESSIBILITY_DETAILS]: new GetElementAccessibilityDetailsTool(),
|
|
28
30
|
};
|
|
29
31
|
|
|
30
32
|
/**
|
|
@@ -7,27 +7,18 @@ import * as Platform from '../../core/platform/platform.js';
|
|
|
7
7
|
import * as SDK from '../../core/sdk/sdk.js';
|
|
8
8
|
import type * as Protocol from '../../generated/protocol.js';
|
|
9
9
|
|
|
10
|
-
let autofillManagerInstance: AutofillManager;
|
|
11
|
-
|
|
12
10
|
export class AutofillManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
|
13
11
|
#address = '';
|
|
14
12
|
#filledFields: Protocol.Autofill.FilledField[] = [];
|
|
15
13
|
#matches: Match[] = [];
|
|
16
14
|
#autofillModel: SDK.AutofillModel.AutofillModel|null = null;
|
|
15
|
+
#frameManager: SDK.FrameManager.FrameManager;
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
constructor(targetManager: SDK.TargetManager.TargetManager, frameManager: SDK.FrameManager.FrameManager) {
|
|
19
18
|
super();
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
static instance(opts: {forceNew: boolean|null} = {forceNew: null}): AutofillManager {
|
|
26
|
-
const {forceNew} = opts;
|
|
27
|
-
if (!autofillManagerInstance || forceNew) {
|
|
28
|
-
autofillManagerInstance = new AutofillManager();
|
|
29
|
-
}
|
|
30
|
-
return autofillManagerInstance;
|
|
19
|
+
this.#frameManager = frameManager;
|
|
20
|
+
targetManager.addModelListener(SDK.AutofillModel.AutofillModel, SDK.AutofillModel.Events.ADDRESS_FORM_FILLED,
|
|
21
|
+
this.#addressFormFilled, this, {scoped: true});
|
|
31
22
|
}
|
|
32
23
|
|
|
33
24
|
async #addressFormFilled({data}: Common.EventTarget.EventTargetEvent<
|
|
@@ -56,7 +47,7 @@ export class AutofillManager extends Common.ObjectWrapper.ObjectWrapper<EventTyp
|
|
|
56
47
|
|
|
57
48
|
highlightFilledField(filledField: Protocol.Autofill.FilledField): void {
|
|
58
49
|
const backendNodeId = filledField.fieldId;
|
|
59
|
-
const target =
|
|
50
|
+
const target = this.#frameManager.getFrame(filledField.frameId)?.resourceTreeModel().target();
|
|
60
51
|
if (target) {
|
|
61
52
|
const deferredNode = new SDK.DOMModel.DeferredDOMNode(target, backendNodeId);
|
|
62
53
|
const domModel = target.model(SDK.DOMModel.DOMModel);
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
5
|
import * as Common from '../../core/common/common.js';
|
|
6
|
+
import * as Root from '../../core/root/root.js';
|
|
6
7
|
import * as SDK from '../../core/sdk/sdk.js';
|
|
7
8
|
import type * as Protocol from '../../generated/protocol.js';
|
|
8
9
|
import type * as Workspace from '../workspace/workspace.js';
|
|
@@ -13,21 +14,16 @@ const uiSourceCodeToAttributionMap = new WeakMap<Workspace.UISourceCode.UISource
|
|
|
13
14
|
}>>();
|
|
14
15
|
const projectToTargetMap = new WeakMap<Workspace.Workspace.Project, SDK.Target.Target>();
|
|
15
16
|
|
|
16
|
-
let networkProjectManagerInstance: NetworkProjectManager;
|
|
17
|
-
|
|
18
17
|
export class NetworkProjectManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
|
19
|
-
private constructor() {
|
|
20
|
-
super();
|
|
21
|
-
}
|
|
22
18
|
|
|
23
19
|
static instance({forceNew}: {
|
|
24
20
|
forceNew: boolean,
|
|
25
21
|
} = {forceNew: false}): NetworkProjectManager {
|
|
26
|
-
if (!
|
|
27
|
-
|
|
22
|
+
if (!Root.DevToolsContext.globalInstance().has(NetworkProjectManager) || forceNew) {
|
|
23
|
+
Root.DevToolsContext.globalInstance().set(NetworkProjectManager, new NetworkProjectManager());
|
|
28
24
|
}
|
|
29
25
|
|
|
30
|
-
return
|
|
26
|
+
return Root.DevToolsContext.globalInstance().get(NetworkProjectManager);
|
|
31
27
|
}
|
|
32
28
|
}
|
|
33
29
|
|
|
@@ -14,7 +14,6 @@ import * as SourceMapScopes from '../source_map_scopes/source_map_scopes.js';
|
|
|
14
14
|
import type * as TextUtils from '../text_utils/text_utils.js';
|
|
15
15
|
import * as Workspace from '../workspace/workspace.js';
|
|
16
16
|
|
|
17
|
-
let breakpointManagerInstance: BreakpointManager;
|
|
18
17
|
const INITIAL_RESTORE_BREAKPOINT_COUNT = 100;
|
|
19
18
|
|
|
20
19
|
export class BreakpointManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes> implements
|
|
@@ -35,10 +34,9 @@ export class BreakpointManager extends Common.ObjectWrapper.ObjectWrapper<EventT
|
|
|
35
34
|
readonly #breakpointByStorageId = new Map<string, Breakpoint>();
|
|
36
35
|
#updateBindingsCallbacks: Array<(uiSourceCode: Workspace.UISourceCode.UISourceCode) => Promise<void>> = [];
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
settings: Common.Settings.Settings, restoreInitialBreakpointCount?: number) {
|
|
37
|
+
constructor(targetManager: SDK.TargetManager.TargetManager, workspace: Workspace.Workspace.WorkspaceImpl,
|
|
38
|
+
debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding,
|
|
39
|
+
settings: Common.Settings.Settings, restoreInitialBreakpointCount?: number) {
|
|
42
40
|
super();
|
|
43
41
|
this.#workspace = workspace;
|
|
44
42
|
this.targetManager = targetManager;
|
|
@@ -85,18 +83,20 @@ export class BreakpointManager extends Common.ObjectWrapper.ObjectWrapper<EventT
|
|
|
85
83
|
}): BreakpointManager {
|
|
86
84
|
const {forceNew, targetManager, workspace, debuggerWorkspaceBinding, settings, restoreInitialBreakpointCount} =
|
|
87
85
|
opts;
|
|
88
|
-
if (!
|
|
86
|
+
if (!Root.DevToolsContext.globalInstance().has(BreakpointManager) || forceNew) {
|
|
89
87
|
if (!targetManager || !workspace || !debuggerWorkspaceBinding || !settings) {
|
|
90
88
|
throw new Error(
|
|
91
89
|
`Unable to create settings: targetManager, workspace, debuggerWorkspaceBinding, and settings must be provided: ${
|
|
92
90
|
new Error().stack}`);
|
|
93
91
|
}
|
|
94
92
|
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
Root.DevToolsContext.globalInstance().set(
|
|
94
|
+
BreakpointManager,
|
|
95
|
+
new BreakpointManager(targetManager, workspace, debuggerWorkspaceBinding, settings,
|
|
96
|
+
restoreInitialBreakpointCount));
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
return
|
|
99
|
+
return Root.DevToolsContext.globalInstance().get(BreakpointManager);
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
modelAdded(debuggerModel: SDK.DebuggerModel.DebuggerModel): void {
|
|
@@ -200,6 +200,10 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
|
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
+
static removeInstance(): void {
|
|
204
|
+
deviceModeModelInstance = null;
|
|
205
|
+
}
|
|
206
|
+
|
|
203
207
|
dispose(): void {
|
|
204
208
|
SDK.TargetManager.TargetManager.instance().unobserveModels(SDK.EmulationModel.EmulationModel, this);
|
|
205
209
|
}
|
|
@@ -573,6 +577,25 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
|
|
|
573
577
|
return this.#mode.insets;
|
|
574
578
|
}
|
|
575
579
|
|
|
580
|
+
private currentSafeAreaInsets(): Insets|null {
|
|
581
|
+
if (this.#type !== Type.Device || !this.#mode) {
|
|
582
|
+
return null;
|
|
583
|
+
}
|
|
584
|
+
return this.#mode.safeAreaInsets ?? null;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
private applySafeAreaInsets(insets: Insets|null): void {
|
|
588
|
+
if (!this.#emulationModel) {
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
if (insets) {
|
|
592
|
+
void this.#emulationModel.setSafeAreaInsets(
|
|
593
|
+
{top: insets.top, left: insets.left, bottom: insets.bottom, right: insets.right});
|
|
594
|
+
} else {
|
|
595
|
+
void this.#emulationModel.setSafeAreaInsets({});
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
576
599
|
private getScreenOrientationType(): Protocol.Emulation.ScreenOrientationType {
|
|
577
600
|
if (!this.#mode) {
|
|
578
601
|
throw new Error('Mode required to get orientation type.');
|
|
@@ -649,6 +672,7 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
|
|
|
649
672
|
if (overlayModel) {
|
|
650
673
|
overlayModel.setShowViewportSizeOnResize(this.#type === Type.None);
|
|
651
674
|
}
|
|
675
|
+
this.applySafeAreaInsets(this.currentSafeAreaInsets());
|
|
652
676
|
this.dispatchEventToListeners(Events.UPDATED);
|
|
653
677
|
}
|
|
654
678
|
|
|
@@ -103,6 +103,15 @@ export class EmulatedDevice {
|
|
|
103
103
|
parseIntValue(json, 'bottom'));
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
function parseCutoutShape(json: any): CutoutShape {
|
|
107
|
+
const shape = parseValue(json, 'shape', 'string');
|
|
108
|
+
if (shape !== CutoutShape.PILL && shape !== CutoutShape.NOTCH && shape !== CutoutShape.CIRCLE &&
|
|
109
|
+
shape !== CutoutShape.RECTANGLE) {
|
|
110
|
+
throw new Error('Emulated device mode has unsupported cutout shape: ' + shape);
|
|
111
|
+
}
|
|
112
|
+
return shape;
|
|
113
|
+
}
|
|
114
|
+
|
|
106
115
|
function parseRGBA(json: any): SDK.OverlayModel.HighlightColor {
|
|
107
116
|
const result = {} as SDK.OverlayModel.HighlightColor;
|
|
108
117
|
result.r = parseIntValue(json, 'r');
|
|
@@ -257,6 +266,40 @@ export class EmulatedDevice {
|
|
|
257
266
|
throw new Error('Emulated device mode \'' + mode.title + '\'has wrong mode insets');
|
|
258
267
|
}
|
|
259
268
|
mode.image = (parseValue(modes[i], 'image', 'string', null) as string);
|
|
269
|
+
const safeAreaInsets = parseValue(modes[i], 'safe-area-insets', 'object', null);
|
|
270
|
+
if (safeAreaInsets) {
|
|
271
|
+
mode.safeAreaInsets = parseInsets(safeAreaInsets);
|
|
272
|
+
}
|
|
273
|
+
const cutout = parseValue(modes[i], 'cutout', 'object', null);
|
|
274
|
+
if (cutout) {
|
|
275
|
+
const shape = parseCutoutShape(cutout);
|
|
276
|
+
const baseCutout = {
|
|
277
|
+
x: parseIntValue(cutout, 'x'),
|
|
278
|
+
y: parseIntValue(cutout, 'y'),
|
|
279
|
+
width: parseIntValue(cutout, 'width'),
|
|
280
|
+
height: parseIntValue(cutout, 'height'),
|
|
281
|
+
};
|
|
282
|
+
if (shape === CutoutShape.PILL) {
|
|
283
|
+
mode.cutout = {shape, ...baseCutout, borderRadius: parseIntValue(cutout, 'border-radius')};
|
|
284
|
+
} else if (shape === CutoutShape.NOTCH) {
|
|
285
|
+
mode.cutout = {
|
|
286
|
+
shape,
|
|
287
|
+
...baseCutout,
|
|
288
|
+
upperRadius: parseIntValue(cutout, 'upper-radius'),
|
|
289
|
+
lowerRadius: parseIntValue(cutout, 'lower-radius'),
|
|
290
|
+
};
|
|
291
|
+
} else if (shape === CutoutShape.CIRCLE) {
|
|
292
|
+
mode.cutout = {
|
|
293
|
+
shape,
|
|
294
|
+
...baseCutout,
|
|
295
|
+
cx: parseIntValue(cutout, 'cx'),
|
|
296
|
+
cy: parseIntValue(cutout, 'cy'),
|
|
297
|
+
radius: parseIntValue(cutout, 'radius'),
|
|
298
|
+
};
|
|
299
|
+
} else {
|
|
300
|
+
mode.cutout = {shape, ...baseCutout};
|
|
301
|
+
}
|
|
302
|
+
}
|
|
260
303
|
result.modes.push(mode);
|
|
261
304
|
}
|
|
262
305
|
result.#showByDefault = (parseValue(json, 'show-by-default', 'boolean', undefined) as boolean);
|
|
@@ -359,6 +402,35 @@ export class EmulatedDevice {
|
|
|
359
402
|
},
|
|
360
403
|
image: this.modes[i].image || undefined,
|
|
361
404
|
};
|
|
405
|
+
const safeAreaInsets = this.modes[i].safeAreaInsets;
|
|
406
|
+
if (safeAreaInsets) {
|
|
407
|
+
mode['safe-area-insets'] = {
|
|
408
|
+
left: safeAreaInsets.left,
|
|
409
|
+
top: safeAreaInsets.top,
|
|
410
|
+
right: safeAreaInsets.right,
|
|
411
|
+
bottom: safeAreaInsets.bottom,
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
const cutout = this.modes[i].cutout;
|
|
415
|
+
if (cutout) {
|
|
416
|
+
mode.cutout = {
|
|
417
|
+
shape: cutout.shape,
|
|
418
|
+
x: cutout.x,
|
|
419
|
+
y: cutout.y,
|
|
420
|
+
width: cutout.width,
|
|
421
|
+
height: cutout.height,
|
|
422
|
+
};
|
|
423
|
+
if (cutout.shape === CutoutShape.PILL) {
|
|
424
|
+
mode.cutout['border-radius'] = cutout.borderRadius;
|
|
425
|
+
} else if (cutout.shape === CutoutShape.NOTCH) {
|
|
426
|
+
mode.cutout['upper-radius'] = cutout.upperRadius;
|
|
427
|
+
mode.cutout['lower-radius'] = cutout.lowerRadius;
|
|
428
|
+
} else if (cutout.shape === CutoutShape.CIRCLE) {
|
|
429
|
+
mode.cutout.cx = cutout.cx;
|
|
430
|
+
mode.cutout.cy = cutout.cy;
|
|
431
|
+
mode.cutout.radius = cutout.radius;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
362
434
|
json['modes'].push(mode);
|
|
363
435
|
}
|
|
364
436
|
|
|
@@ -637,7 +709,24 @@ export interface Mode {
|
|
|
637
709
|
orientation: string;
|
|
638
710
|
insets: Insets;
|
|
639
711
|
image: string|null;
|
|
712
|
+
safeAreaInsets?: Insets;
|
|
713
|
+
cutout?: Cutout;
|
|
640
714
|
}
|
|
715
|
+
export const enum CutoutShape {
|
|
716
|
+
PILL = 'pill',
|
|
717
|
+
NOTCH = 'notch',
|
|
718
|
+
CIRCLE = 'circle',
|
|
719
|
+
RECTANGLE = 'rectangle',
|
|
720
|
+
}
|
|
721
|
+
export interface BaseCutout {
|
|
722
|
+
x: number;
|
|
723
|
+
y: number;
|
|
724
|
+
width: number;
|
|
725
|
+
height: number;
|
|
726
|
+
}
|
|
727
|
+
export type Cutout = BaseCutout&({shape: CutoutShape.RECTANGLE}|{shape: CutoutShape.PILL, borderRadius: number}|
|
|
728
|
+
{shape: CutoutShape.NOTCH, upperRadius: number, lowerRadius: number}|
|
|
729
|
+
{shape: CutoutShape.CIRCLE, cx: number, cy: number, radius: number});
|
|
641
730
|
export interface Orientation {
|
|
642
731
|
width: number;
|
|
643
732
|
height: number;
|
|
@@ -655,6 +744,25 @@ export interface JSONMode {
|
|
|
655
744
|
top: number,
|
|
656
745
|
bottom: number,
|
|
657
746
|
};
|
|
747
|
+
'safe-area-insets'?: {
|
|
748
|
+
left: number,
|
|
749
|
+
right: number,
|
|
750
|
+
top: number,
|
|
751
|
+
bottom: number,
|
|
752
|
+
};
|
|
753
|
+
cutout?: {
|
|
754
|
+
shape: string,
|
|
755
|
+
x: number,
|
|
756
|
+
y: number,
|
|
757
|
+
width: number,
|
|
758
|
+
height: number,
|
|
759
|
+
'border-radius'?: number,
|
|
760
|
+
'upper-radius'?: number,
|
|
761
|
+
'lower-radius'?: number,
|
|
762
|
+
cx?: number,
|
|
763
|
+
cy?: number,
|
|
764
|
+
radius?: number,
|
|
765
|
+
};
|
|
658
766
|
}
|
|
659
767
|
|
|
660
768
|
// These props should quoted for the script to work properly
|