chrome-devtools-frontend 1.0.1696961 → 1.0.1697595
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/.geminiignore +0 -1
- package/front_end/core/common/Color.ts +5 -2
- package/front_end/core/host/InspectorFrontendHostAPI.ts +16 -3
- package/front_end/core/host/InspectorFrontendHostStub.ts +3 -2
- package/front_end/core/host/ResourceLoader.ts +1 -2
- package/front_end/core/platform/api/HostRuntime.ts +1 -0
- package/front_end/core/platform/browser/HostRuntime.ts +4 -0
- package/front_end/core/platform/node/HostRuntime.ts +5 -0
- package/front_end/core/root/Runtime.ts +5 -0
- package/front_end/core/sdk/DOMModel.ts +13 -0
- package/front_end/core/sdk/SourceMapScopeChainEntry.ts +9 -6
- package/front_end/core/sdk/SourceMapScopesInfo.ts +3 -1
- package/front_end/foundation/Universe.ts +8 -0
- package/front_end/generated/InspectorBackendCommands.ts +3 -0
- package/front_end/generated/protocol-mapping.d.ts +19 -0
- package/front_end/generated/protocol-proxy-api.d.ts +15 -0
- package/front_end/generated/protocol.ts +35 -0
- package/front_end/models/ai_assistance/AiAgent2.ts +20 -18
- package/front_end/models/ai_assistance/AiConversation.ts +38 -12
- package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +9 -2
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +13 -4
- package/front_end/models/ai_assistance/tools/CookieUtils.ts +10 -8
- package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +1 -1
- package/front_end/models/ai_assistance/tools/GetElementAccessibilityDetails.ts +1 -3
- package/front_end/models/ai_assistance/tools/GetNetworkRequestDetails.ts +9 -8
- package/front_end/models/ai_assistance/tools/GetSourceContent.ts +5 -6
- package/front_end/models/ai_assistance/tools/GetStorageValues.ts +6 -25
- package/front_end/models/ai_assistance/tools/GetStyles.ts +1 -3
- package/front_end/models/ai_assistance/tools/ListNetworkRequests.ts +7 -6
- package/front_end/models/ai_assistance/tools/ListPageOrigins.ts +8 -5
- package/front_end/models/ai_assistance/tools/ListSources.ts +8 -10
- package/front_end/models/ai_assistance/tools/ListStorageKeys.ts +6 -25
- package/front_end/models/ai_assistance/tools/README.md +5 -3
- package/front_end/models/ai_assistance/tools/ResolveDevtoolsNodePath.ts +1 -2
- package/front_end/models/ai_assistance/tools/Tool.ts +52 -14
- package/front_end/models/change_tracker/ChangeTracker.ts +89 -0
- package/front_end/models/change_tracker/change_tracker.ts +9 -0
- package/front_end/models/issues_manager/MarkdownIssueDescription.ts +2 -2
- package/front_end/models/live-metrics/LiveMetrics.ts +1 -2
- package/front_end/models/trace/ModelImpl.ts +0 -6
- package/front_end/models/trace/Processor.ts +4 -7
- package/front_end/models/trace/helpers/Timing.ts +2 -1
- package/front_end/models/trace/types/Overlays.ts +12 -1
- package/front_end/panels/accessibility/AccessibilityAnnouncementRecordingView.ts +67 -19
- package/front_end/panels/application/IndexedDBViews.ts +1 -1
- package/front_end/panels/elements/DOMTreeContextMenu.ts +16 -23
- package/front_end/panels/elements/ElementsTreeElement.ts +286 -59
- package/front_end/panels/elements/ElementsTreeOutline.ts +273 -42
- package/front_end/panels/network/NetworkPanel.ts +137 -52
- package/front_end/panels/network/RequestHeadersView.ts +65 -32
- package/front_end/panels/network/components/RequestHeadersView.css +7 -1
- package/front_end/panels/network/forward/BackendLinking.ts +49 -0
- package/front_end/panels/network/forward/forward.ts +2 -0
- package/front_end/panels/settings/BackendLinkingSettingsTab.ts +303 -0
- package/front_end/panels/settings/backendLinkingSettingsTab.css +78 -0
- package/front_end/panels/settings/settings-meta.ts +25 -0
- package/front_end/panels/settings/settings.ts +2 -0
- package/front_end/panels/timeline/README.md +3 -2
- package/front_end/panels/timeline/TimelineFlameChartView.ts +23 -2
- package/front_end/panels/timeline/overlays/OverlaysImpl.ts +64 -4
- package/front_end/panels/timeline/timelineFlameChartView.css +47 -0
- package/front_end/panels/whats_new/ReleaseNoteText.ts +8 -8
- package/front_end/panels/whats_new/resources/WNDT.md +6 -6
- 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 +6 -0
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +5 -8
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Coverage.d.ts +6 -0
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Coverage.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Coverage.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/ScreenRecording.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/ScreenRecording.js +1 -5
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/ScreenRecording.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/util/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 +6 -0
- package/front_end/third_party/puppeteer/package/package.json +2 -2
- package/front_end/third_party/puppeteer/package/src/cdp/Coverage.ts +6 -0
- package/front_end/third_party/puppeteer/package/src/cdp/ScreenRecording.ts +3 -7
- package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
- package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
- package/front_end/third_party/web-vitals/README.chromium +2 -2
- package/front_end/third_party/web-vitals/package/dist/modules/attribution/onINP.js +8 -5
- package/front_end/third_party/web-vitals/package/package.json +1 -1
- package/front_end/third_party/web-vitals/package/src/attribution/onINP.ts +8 -4
- package/front_end/third_party/web-vitals/rebuild.sh +2 -2
- package/front_end/ui/legacy/ContextMenu.ts +19 -0
- package/front_end/ui/legacy/SoftContextMenu.ts +6 -0
- package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +62 -22
- package/front_end/ui/visual_logging/KnownContextValues.ts +4 -0
- package/package.json +5 -4
package/.geminiignore
CHANGED
|
@@ -613,12 +613,15 @@ export function findFgColorForContrastAPCA(fgColor: Legacy, bgColor: Legacy, req
|
|
|
613
613
|
const fgIsLighter = fgLuminance >= bgLuminance;
|
|
614
614
|
const desiredLuminance = desiredLuminanceAPCA(bgLuminance, requiredContrast, fgIsLighter);
|
|
615
615
|
|
|
616
|
+
const meetsRequiredContrast = (candidate: Legacy): boolean =>
|
|
617
|
+
Math.round(Math.abs(contrastRatioAPCA(candidate.rgba(), bgColor.rgba()))) >= requiredContrast;
|
|
618
|
+
|
|
616
619
|
const saturationComponentIndex = 1;
|
|
617
620
|
const valueComponentIndex = 2;
|
|
618
621
|
|
|
619
622
|
if (approachColorValue(candidateHSVA, valueComponentIndex, desiredLuminance, candidateLuminance)) {
|
|
620
623
|
const candidate = Legacy.fromHSVA(candidateHSVA);
|
|
621
|
-
if (
|
|
624
|
+
if (meetsRequiredContrast(candidate)) {
|
|
622
625
|
return candidate;
|
|
623
626
|
}
|
|
624
627
|
}
|
|
@@ -626,7 +629,7 @@ export function findFgColorForContrastAPCA(fgColor: Legacy, bgColor: Legacy, req
|
|
|
626
629
|
candidateHSVA[valueComponentIndex] = 1;
|
|
627
630
|
if (approachColorValue(candidateHSVA, saturationComponentIndex, desiredLuminance, candidateLuminance)) {
|
|
628
631
|
const candidate = Legacy.fromHSVA(candidateHSVA);
|
|
629
|
-
if (
|
|
632
|
+
if (meetsRequiredContrast(candidate)) {
|
|
630
633
|
return candidate;
|
|
631
634
|
}
|
|
632
635
|
}
|
|
@@ -6,6 +6,11 @@ import type * as Platform from '../../core/platform/platform.js';
|
|
|
6
6
|
import type * as Common from '../common/common.js';
|
|
7
7
|
import type * as Root from '../root/root.js';
|
|
8
8
|
|
|
9
|
+
declare global {
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
11
|
+
var InspectorFrontendHost: InspectorFrontendHostAPI;
|
|
12
|
+
}
|
|
13
|
+
|
|
9
14
|
/**
|
|
10
15
|
* This values should match the one getting called from Chromium
|
|
11
16
|
*/
|
|
@@ -227,6 +232,14 @@ export interface FunctionCallEvent {
|
|
|
227
232
|
* Please note that the "dispatch" side can't be type-checked as the dispatch is
|
|
228
233
|
* done dynamically.
|
|
229
234
|
**/
|
|
235
|
+
export interface DevicesDiscoveryConfig {
|
|
236
|
+
discoverUsbDevices: boolean;
|
|
237
|
+
portForwardingEnabled: boolean;
|
|
238
|
+
portForwardingConfig: Record<string, string>;
|
|
239
|
+
networkDiscoveryEnabled: boolean;
|
|
240
|
+
networkDiscoveryConfig: string[];
|
|
241
|
+
}
|
|
242
|
+
|
|
230
243
|
export interface EventTypes {
|
|
231
244
|
[Events.AppendedToURL]: Platform.DevToolsPath.RawPathString|Platform.DevToolsPath.UrlString;
|
|
232
245
|
[Events.CanceledSaveURL]: Platform.DevToolsPath.UrlString;
|
|
@@ -234,7 +247,7 @@ export interface EventTypes {
|
|
|
234
247
|
[Events.ContextMenuCleared]: void;
|
|
235
248
|
[Events.ContextMenuItemSelected]: number;
|
|
236
249
|
[Events.DeviceCountUpdated]: number;
|
|
237
|
-
[Events.DevicesDiscoveryConfigChanged]:
|
|
250
|
+
[Events.DevicesDiscoveryConfigChanged]: DevicesDiscoveryConfig;
|
|
238
251
|
[Events.DevicesPortForwardingStatusChanged]: void;
|
|
239
252
|
[Events.DevicesUpdated]: void;
|
|
240
253
|
[Events.DispatchMessage]: string;
|
|
@@ -399,7 +412,7 @@ export interface InspectorFrontendHostAPI {
|
|
|
399
412
|
|
|
400
413
|
sendMessageToBackend(message: string): void;
|
|
401
414
|
|
|
402
|
-
setDevicesDiscoveryConfig(config:
|
|
415
|
+
setDevicesDiscoveryConfig(config: DevicesDiscoveryConfig): void;
|
|
403
416
|
|
|
404
417
|
setDevicesUpdatesEnabled(enabled: boolean): void;
|
|
405
418
|
|
|
@@ -423,7 +436,7 @@ export interface InspectorFrontendHostAPI {
|
|
|
423
436
|
|
|
424
437
|
resetZoom(): void;
|
|
425
438
|
|
|
426
|
-
showContextMenuAtPoint(x: number, y: number, items: ContextMenuDescriptor[], document:
|
|
439
|
+
showContextMenuAtPoint(x: number, y: number, items: ContextMenuDescriptor[], document: object): void;
|
|
427
440
|
|
|
428
441
|
reattach(callback: () => void): void;
|
|
429
442
|
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
type ChangeEvent,
|
|
15
15
|
type ClickEvent,
|
|
16
16
|
type ContextMenuDescriptor,
|
|
17
|
+
type DevicesDiscoveryConfig,
|
|
17
18
|
type DispatchHttpRequestRequest,
|
|
18
19
|
type DispatchHttpRequestResult,
|
|
19
20
|
type DoAidaConversationResult,
|
|
@@ -460,7 +461,7 @@ export class InspectorFrontendHostStub implements InspectorFrontendHostAPI {
|
|
|
460
461
|
setOpenNewWindowForPopups(_value: boolean): void {
|
|
461
462
|
}
|
|
462
463
|
|
|
463
|
-
setDevicesDiscoveryConfig(_config:
|
|
464
|
+
setDevicesDiscoveryConfig(_config: DevicesDiscoveryConfig): void {
|
|
464
465
|
}
|
|
465
466
|
|
|
466
467
|
setDevicesUpdatesEnabled(_enabled: boolean): void {
|
|
@@ -472,7 +473,7 @@ export class InspectorFrontendHostStub implements InspectorFrontendHostAPI {
|
|
|
472
473
|
openNodeFrontend(): void {
|
|
473
474
|
}
|
|
474
475
|
|
|
475
|
-
showContextMenuAtPoint(_x: number, _y: number, _items: ContextMenuDescriptor[], _document:
|
|
476
|
+
showContextMenuAtPoint(_x: number, _y: number, _items: ContextMenuDescriptor[], _document: object): void {
|
|
476
477
|
throw new Error('Soft context menu should be used');
|
|
477
478
|
}
|
|
478
479
|
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
import * as Common from '../common/common.js';
|
|
8
8
|
import * as i18n from '../i18n/i18n.js';
|
|
9
9
|
|
|
10
|
-
import {InspectorFrontendHostInstance} from './InspectorFrontendHost.js';
|
|
11
10
|
import type {LoadNetworkResourceResult} from './InspectorFrontendHostAPI.js';
|
|
12
11
|
|
|
13
12
|
const UIStrings = {
|
|
@@ -248,7 +247,7 @@ export const loadAsStream = function(
|
|
|
248
247
|
rawHeaders.push(key + ': ' + headers[key]);
|
|
249
248
|
}
|
|
250
249
|
}
|
|
251
|
-
|
|
250
|
+
globalThis.InspectorFrontendHost.loadNetworkResource(url, rawHeaders.join('\r\n'), streamId, finishedCallback);
|
|
252
251
|
|
|
253
252
|
function finishedCallback(response: LoadNetworkResourceResult): void {
|
|
254
253
|
if (callback) {
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
|
+
import * as Fs from 'node:fs';
|
|
6
|
+
import * as Url from 'node:url';
|
|
5
7
|
import * as WorkerThreads from 'node:worker_threads';
|
|
6
8
|
|
|
7
9
|
import type * as Api from '../api/api.js';
|
|
@@ -101,4 +103,7 @@ export const HOST_RUNTIME: Api.HostRuntime.HostRuntime = {
|
|
|
101
103
|
},
|
|
102
104
|
async saveScreenshot(_options: Api.HostRuntime.ScreenshotOptions): Promise<void>{},
|
|
103
105
|
revokeLastScreenshotUrl(): void{},
|
|
106
|
+
async loadTextFile(url: URL): Promise<string> {
|
|
107
|
+
return await Fs.promises.readFile(Url.fileURLToPath(url), 'utf-8');
|
|
108
|
+
},
|
|
104
109
|
};
|
|
@@ -545,6 +545,10 @@ interface DevToolsMobileSafeAreaEmulation {
|
|
|
545
545
|
enabled: boolean;
|
|
546
546
|
}
|
|
547
547
|
|
|
548
|
+
interface DevToolsNetworkBackendLinking {
|
|
549
|
+
enabled: boolean;
|
|
550
|
+
}
|
|
551
|
+
|
|
548
552
|
/**
|
|
549
553
|
* The host configuration that we expect from the DevTools back-end.
|
|
550
554
|
*
|
|
@@ -602,6 +606,7 @@ export type HostConfig = Platform.TypeScriptUtilities.RecursivePartial<{
|
|
|
602
606
|
devToolsAriaLiveRecording: DevToolsAriaLiveRecording,
|
|
603
607
|
devToolsInstrumentationBreakpoints: DevToolsInstrumentationBreakpoints,
|
|
604
608
|
devToolsMobileSafeAreaEmulation: DevToolsMobileSafeAreaEmulation,
|
|
609
|
+
devToolsNetworkBackendLinking: DevToolsNetworkBackendLinking,
|
|
605
610
|
extensionsOnChromeUrls: ExtensionsOnChromeUrls,
|
|
606
611
|
devToolsComments: HostConfigDevToolsComments,
|
|
607
612
|
}>;
|
|
@@ -1427,6 +1427,19 @@ export class DOMNode extends Common.ObjectWrapper.ObjectWrapper<DOMNodeEventType
|
|
|
1427
1427
|
return this.domModel().nodeForId(response.nodeId);
|
|
1428
1428
|
}
|
|
1429
1429
|
|
|
1430
|
+
async getImplicitAnchorCandidates(): Promise<DeferredDOMNode[]> {
|
|
1431
|
+
const response = await this.#agent.invoke_getImplicitAnchorCandidates({
|
|
1432
|
+
nodeId: this.id,
|
|
1433
|
+
});
|
|
1434
|
+
|
|
1435
|
+
if (response.getError() || !response.backendNodeIds) {
|
|
1436
|
+
return [];
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
const target = this.domModel().target();
|
|
1440
|
+
return response.backendNodeIds.map(backendNodeId => new DeferredDOMNode(target, backendNodeId));
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1430
1443
|
async takeSnapshot(ownerDocumentSnapshot?: DOMDocument): Promise<DOMNode> {
|
|
1431
1444
|
const snapshot = (this instanceof DOMDocument) ? new DOMDocumentSnapshot(this.domModel(), {
|
|
1432
1445
|
nodeId: this.id,
|
|
@@ -73,11 +73,13 @@ export class SourceMapScopeChainEntry implements ScopeChainEntry {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
type(): string {
|
|
76
|
-
|
|
76
|
+
if (this.#scope.isStackFrame) {
|
|
77
|
+
return this.#isInnerMostFunction ? Protocol.Debugger.ScopeType.Local : Protocol.Debugger.ScopeType.Closure;
|
|
78
|
+
}
|
|
79
|
+
// `kind` is a free-form label. The spec encourages 'Global'/'Block' but doesn't mandate the casing.
|
|
80
|
+
switch (this.#scope.kind?.toLowerCase()) {
|
|
77
81
|
case 'global':
|
|
78
82
|
return Protocol.Debugger.ScopeType.Global;
|
|
79
|
-
case 'function':
|
|
80
|
-
return this.#isInnerMostFunction ? Protocol.Debugger.ScopeType.Local : Protocol.Debugger.ScopeType.Closure;
|
|
81
83
|
case 'block':
|
|
82
84
|
return Protocol.Debugger.ScopeType.Block;
|
|
83
85
|
}
|
|
@@ -85,11 +87,12 @@ export class SourceMapScopeChainEntry implements ScopeChainEntry {
|
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
typeName(): string {
|
|
88
|
-
|
|
90
|
+
if (this.#scope.isStackFrame) {
|
|
91
|
+
return this.#isInnerMostFunction ? i18nString(UIStrings.local) : i18nString(UIStrings.closure);
|
|
92
|
+
}
|
|
93
|
+
switch (this.#scope.kind?.toLowerCase()) {
|
|
89
94
|
case 'global':
|
|
90
95
|
return i18nString(UIStrings.global);
|
|
91
|
-
case 'function':
|
|
92
|
-
return this.#isInnerMostFunction ? i18nString(UIStrings.local) : i18nString(UIStrings.closure);
|
|
93
96
|
case 'block':
|
|
94
97
|
return i18nString(UIStrings.block);
|
|
95
98
|
}
|
|
@@ -359,7 +359,9 @@ export class SourceMapScopesInfo {
|
|
|
359
359
|
// Walk the original scope chain outwards and try to find the corresponding generated range along the way.
|
|
360
360
|
for (let originalScope = rangeChain.at(-1)?.originalScope; originalScope; originalScope = originalScope.parent) {
|
|
361
361
|
const range = rangeChain.findLast(r => r.originalScope === originalScope);
|
|
362
|
-
|
|
362
|
+
// `kind` is just a label for scope UI views and has no semantic significance, so `isStackFrame`
|
|
363
|
+
// decides whether this scope is a function scope.
|
|
364
|
+
const isFunctionScope = originalScope.isStackFrame;
|
|
363
365
|
const isInnerMostFunction = isFunctionScope && !seenFunctionScope;
|
|
364
366
|
const returnValue = isInnerMostFunction ? callFrame.returnValue() : null;
|
|
365
367
|
const scopeNumber = range ? findMatchingScopeNumber(callFrame, range) : undefined;
|
|
@@ -11,6 +11,7 @@ import * as AutofillManager from '../models/autofill_manager/autofill_manager.js
|
|
|
11
11
|
import * as Badges from '../models/badges/badges.js';
|
|
12
12
|
import * as Bindings from '../models/bindings/bindings.js';
|
|
13
13
|
import * as Breakpoints from '../models/breakpoints/breakpoints.js';
|
|
14
|
+
import * as ChangeTracker from '../models/change_tracker/change_tracker.js';
|
|
14
15
|
import * as CommentManager from '../models/comment_manager/comment_manager.js';
|
|
15
16
|
import * as CrUXManager from '../models/crux-manager/crux-manager.js';
|
|
16
17
|
import * as Emulation from '../models/emulation/emulation.js';
|
|
@@ -238,6 +239,9 @@ export class Universe {
|
|
|
238
239
|
context.set(CommentManager.CD4ABridge.CD4ABridge, this.cd4aBridge);
|
|
239
240
|
}
|
|
240
241
|
|
|
242
|
+
const changeTracker = new ChangeTracker.ChangeTracker.ChangeTracker(commentManager);
|
|
243
|
+
context.set(ChangeTracker.ChangeTracker.ChangeTracker, changeTracker);
|
|
244
|
+
|
|
241
245
|
this.autofillManager = new AutofillManager.AutofillManager.AutofillManager(targetManager, frameManager);
|
|
242
246
|
context.set(AutofillManager.AutofillManager.AutofillManager, this.autofillManager);
|
|
243
247
|
}
|
|
@@ -275,6 +279,10 @@ export class Universe {
|
|
|
275
279
|
return this.context.get(Breakpoints.BreakpointManager.BreakpointManager);
|
|
276
280
|
}
|
|
277
281
|
|
|
282
|
+
get changeTracker(): ChangeTracker.ChangeTracker.ChangeTracker {
|
|
283
|
+
return this.context.get(ChangeTracker.ChangeTracker.ChangeTracker);
|
|
284
|
+
}
|
|
285
|
+
|
|
278
286
|
get commentManager(): CommentManager.CommentManager.CommentManager {
|
|
279
287
|
return this.context.get(CommentManager.CommentManager.CommentManager);
|
|
280
288
|
}
|
|
@@ -444,6 +444,9 @@ inspectorBackend.registerCommand("DOM.getAnchorElement", [{"name": "nodeId", "ty
|
|
|
444
444
|
inspectorBackend.registerCommand("DOM.forceShowPopover", [{"name": "nodeId", "type": "number", "optional": false, "description": "Id of the popover HTMLElement", "typeRef": "DOM.NodeId"}, {"name": "enable", "type": "boolean", "optional": false, "description": "If true, opens the popover and keeps it open. If false, closes the popover if it was previously force-opened.", "typeRef": null}, {"name": "invokerNodeId", "type": "number", "optional": true, "description": "Optional ID of the element invoking this popover, used to establish the implicit anchor. If not provided, it will fall back to the first invoker in the document, preferring elements with a popovertarget attribute over those with a commandfor attribute. Note that if there are multiple invokers, this is just an estimate.", "typeRef": "DOM.BackendNodeId"}], ["nodeIds"], "When enabling, this API force-opens the popover identified by nodeId and keeps it open until disabled.");
|
|
445
445
|
inspectorBackend.registerCommand("DOM.getImplicitAnchorCandidates", [{"name": "nodeId", "type": "number", "optional": false, "description": "Id of the popover HTMLElement.", "typeRef": "DOM.NodeId"}], ["backendNodeIds"], "Returns candidate nodes that are configured as triggers for the given popover.");
|
|
446
446
|
inspectorBackend.registerCommand("DOM.forceShowInterest", [{"name": "nodeId", "type": "number", "optional": false, "description": "Id of the interest invoker HTMLElement.", "typeRef": "DOM.NodeId"}, {"name": "enable", "type": "boolean", "optional": false, "description": "If true, opens and holds interest. If false, releases forced interest.", "typeRef": null}], [], "When enabling, this API forces an element to gain interest in its target, keeping interest active until disabled.");
|
|
447
|
+
inspectorBackend.registerEnum("DOM.SetTextMarkerRequestType", {Spelling: "spelling", Grammar: "grammar"});
|
|
448
|
+
inspectorBackend.registerCommand("DOM.setTextMarker", [{"name": "nodeId", "type": "number", "optional": true, "description": "Identifier of the node.", "typeRef": "DOM.NodeId"}, {"name": "backendNodeId", "type": "number", "optional": true, "description": "Identifier of the backend node.", "typeRef": "DOM.BackendNodeId"}, {"name": "objectId", "type": "string", "optional": true, "description": "JavaScript object id of the node wrapper.", "typeRef": "Runtime.RemoteObjectId"}, {"name": "type", "type": "string", "optional": false, "description": "The type of marker to set on the given range of text.", "typeRef": "DOM.SetTextMarkerRequestType"}, {"name": "start", "type": "number", "optional": false, "description": "Start offset into the element's rendered text in UTF-16 code units. For a text control, an offset into the control's value. Offsets count text in DOM order and do not enter shadow trees. To mark text inside a shadow tree, pass the element inside the shadow tree.", "typeRef": null}, {"name": "end", "type": "number", "optional": false, "description": "End offset (exclusive) in the same units and space as start.", "typeRef": null}], [], "Sets a spelling or grammar error marker on the given range of text. See https://github.com/Igalia/explainers/blob/main/force-spelling-grammar-markers/README.md Note: exactly one between nodeId, backendNodeId and objectId should be passed to identify the node.");
|
|
449
|
+
inspectorBackend.registerCommand("DOM.clearTextMarkers", [], [], "Clears the spelling and grammar error text markers overlapping the ranges set by setTextMarker in this session. These markers are also removed when the DOM domain is disabled or the session ends.");
|
|
447
450
|
inspectorBackend.registerType("DOM.BackendNode", [{"name": "nodeType", "type": "number", "optional": false, "description": "`Node`'s nodeType.", "typeRef": null}, {"name": "nodeName", "type": "string", "optional": false, "description": "`Node`'s nodeName.", "typeRef": null}, {"name": "backendNodeId", "type": "number", "optional": false, "description": "", "typeRef": "DOM.BackendNodeId"}]);
|
|
448
451
|
inspectorBackend.registerType("DOM.Node", [{"name": "nodeId", "type": "number", "optional": false, "description": "Node identifier that is passed into the rest of the DOM messages as the `nodeId`. Backend will only push node with given `id` once. It is aware of all requested nodes and will only fire DOM events for nodes known to the client.", "typeRef": "DOM.NodeId"}, {"name": "parentId", "type": "number", "optional": true, "description": "The id of the parent node if any.", "typeRef": "DOM.NodeId"}, {"name": "backendNodeId", "type": "number", "optional": false, "description": "The BackendNodeId for this node.", "typeRef": "DOM.BackendNodeId"}, {"name": "nodeType", "type": "number", "optional": false, "description": "`Node`'s nodeType.", "typeRef": null}, {"name": "nodeName", "type": "string", "optional": false, "description": "`Node`'s nodeName.", "typeRef": null}, {"name": "localName", "type": "string", "optional": false, "description": "`Node`'s localName.", "typeRef": null}, {"name": "nodeValue", "type": "string", "optional": false, "description": "`Node`'s nodeValue.", "typeRef": null}, {"name": "childNodeCount", "type": "number", "optional": true, "description": "Child count for `Container` nodes.", "typeRef": null}, {"name": "children", "type": "array", "optional": true, "description": "Child nodes of this node when requested with children.", "typeRef": "DOM.Node"}, {"name": "attributes", "type": "array", "optional": true, "description": "Attributes of the `Element` node in the form of flat array `[name1, value1, name2, value2]`.", "typeRef": "string"}, {"name": "documentURL", "type": "string", "optional": true, "description": "Document URL that `Document` or `FrameOwner` node points to.", "typeRef": null}, {"name": "baseURL", "type": "string", "optional": true, "description": "Base URL that `Document` or `FrameOwner` node uses for URL completion.", "typeRef": null}, {"name": "publicId", "type": "string", "optional": true, "description": "`DocumentType`'s publicId.", "typeRef": null}, {"name": "systemId", "type": "string", "optional": true, "description": "`DocumentType`'s systemId.", "typeRef": null}, {"name": "internalSubset", "type": "string", "optional": true, "description": "`DocumentType`'s internalSubset.", "typeRef": null}, {"name": "xmlVersion", "type": "string", "optional": true, "description": "`Document`'s XML version in case of XML documents.", "typeRef": null}, {"name": "name", "type": "string", "optional": true, "description": "`Attr`'s name.", "typeRef": null}, {"name": "value", "type": "string", "optional": true, "description": "`Attr`'s value.", "typeRef": null}, {"name": "pseudoType", "type": "string", "optional": true, "description": "Pseudo element type for this node.", "typeRef": "DOM.PseudoType"}, {"name": "pseudoIdentifier", "type": "string", "optional": true, "description": "Pseudo element identifier for this node. Only present if there is a valid pseudoType.", "typeRef": null}, {"name": "shadowRootType", "type": "string", "optional": true, "description": "Shadow root type.", "typeRef": "DOM.ShadowRootType"}, {"name": "frameId", "type": "string", "optional": true, "description": "Frame ID for frame owner elements.", "typeRef": "Page.FrameId"}, {"name": "contentDocument", "type": "object", "optional": true, "description": "Content document for frame owner elements.", "typeRef": "DOM.Node"}, {"name": "shadowRoots", "type": "array", "optional": true, "description": "Shadow root list for given element host.", "typeRef": "DOM.Node"}, {"name": "templateContent", "type": "object", "optional": true, "description": "Content document fragment for template elements.", "typeRef": "DOM.Node"}, {"name": "pseudoElements", "type": "array", "optional": true, "description": "Pseudo elements associated with this node.", "typeRef": "DOM.Node"}, {"name": "importedDocument", "type": "object", "optional": true, "description": "Deprecated, as the HTML Imports API has been removed (crbug.com/937746). This property used to return the imported document for the HTMLImport links. The property is always undefined now.", "typeRef": "DOM.Node"}, {"name": "distributedNodes", "type": "array", "optional": true, "description": "Distributed nodes for given insertion point.", "typeRef": "DOM.BackendNode"}, {"name": "isSVG", "type": "boolean", "optional": true, "description": "Whether the node is SVG.", "typeRef": null}, {"name": "compatibilityMode", "type": "string", "optional": true, "description": "", "typeRef": "DOM.CompatibilityMode"}, {"name": "assignedSlot", "type": "object", "optional": true, "description": "", "typeRef": "DOM.BackendNode"}, {"name": "isScrollable", "type": "boolean", "optional": true, "description": "", "typeRef": null}, {"name": "affectedByStartingStyles", "type": "boolean", "optional": true, "description": "", "typeRef": null}, {"name": "adoptedStyleSheets", "type": "array", "optional": true, "description": "", "typeRef": "DOM.StyleSheetId"}, {"name": "adProvenance", "type": "object", "optional": true, "description": "", "typeRef": "Network.AdProvenance"}]);
|
|
449
452
|
inspectorBackend.registerType("DOM.DetachedElementInfo", [{"name": "treeNode", "type": "object", "optional": false, "description": "", "typeRef": "DOM.Node"}, {"name": "retainedNodeIds", "type": "array", "optional": false, "description": "", "typeRef": "DOM.NodeId"}]);
|
|
@@ -2312,6 +2312,25 @@ export namespace ProtocolMapping {
|
|
|
2312
2312
|
paramsType: [Protocol.DOM.ForceShowInterestRequest];
|
|
2313
2313
|
returnType: void;
|
|
2314
2314
|
};
|
|
2315
|
+
/**
|
|
2316
|
+
* Sets a spelling or grammar error marker on the given range of text.
|
|
2317
|
+
* See https://github.com/Igalia/explainers/blob/main/force-spelling-grammar-markers/README.md
|
|
2318
|
+
* Note: exactly one between nodeId, backendNodeId and objectId should be passed
|
|
2319
|
+
* to identify the node.
|
|
2320
|
+
*/
|
|
2321
|
+
'DOM.setTextMarker': {
|
|
2322
|
+
paramsType: [Protocol.DOM.SetTextMarkerRequest];
|
|
2323
|
+
returnType: void;
|
|
2324
|
+
};
|
|
2325
|
+
/**
|
|
2326
|
+
* Clears the spelling and grammar error text markers overlapping the ranges
|
|
2327
|
+
* set by setTextMarker in this session. These markers are also removed when
|
|
2328
|
+
* the DOM domain is disabled or the session ends.
|
|
2329
|
+
*/
|
|
2330
|
+
'DOM.clearTextMarkers': {
|
|
2331
|
+
paramsType: [];
|
|
2332
|
+
returnType: void;
|
|
2333
|
+
};
|
|
2315
2334
|
/**
|
|
2316
2335
|
* Returns event listeners of the given object.
|
|
2317
2336
|
*/
|
|
@@ -1406,6 +1406,21 @@ declare namespace ProtocolProxyApi {
|
|
|
1406
1406
|
*/
|
|
1407
1407
|
invoke_forceShowInterest(params: Protocol.DOM.ForceShowInterestRequest): Promise<Protocol.ProtocolResponseWithError>;
|
|
1408
1408
|
|
|
1409
|
+
/**
|
|
1410
|
+
* Sets a spelling or grammar error marker on the given range of text.
|
|
1411
|
+
* See https://github.com/Igalia/explainers/blob/main/force-spelling-grammar-markers/README.md
|
|
1412
|
+
* Note: exactly one between nodeId, backendNodeId and objectId should be passed
|
|
1413
|
+
* to identify the node.
|
|
1414
|
+
*/
|
|
1415
|
+
invoke_setTextMarker(params: Protocol.DOM.SetTextMarkerRequest): Promise<Protocol.ProtocolResponseWithError>;
|
|
1416
|
+
|
|
1417
|
+
/**
|
|
1418
|
+
* Clears the spelling and grammar error text markers overlapping the ranges
|
|
1419
|
+
* set by setTextMarker in this session. These markers are also removed when
|
|
1420
|
+
* the DOM domain is disabled or the session ends.
|
|
1421
|
+
*/
|
|
1422
|
+
invoke_clearTextMarkers(): Promise<Protocol.ProtocolResponseWithError>;
|
|
1423
|
+
|
|
1409
1424
|
}
|
|
1410
1425
|
export interface DOMDispatcher {
|
|
1411
1426
|
/**
|
|
@@ -5990,6 +5990,41 @@ export namespace DOM {
|
|
|
5990
5990
|
enable: boolean;
|
|
5991
5991
|
}
|
|
5992
5992
|
|
|
5993
|
+
export const enum SetTextMarkerRequestType {
|
|
5994
|
+
Spelling = 'spelling',
|
|
5995
|
+
Grammar = 'grammar',
|
|
5996
|
+
}
|
|
5997
|
+
|
|
5998
|
+
export interface SetTextMarkerRequest {
|
|
5999
|
+
/**
|
|
6000
|
+
* Identifier of the node.
|
|
6001
|
+
*/
|
|
6002
|
+
nodeId?: NodeId;
|
|
6003
|
+
/**
|
|
6004
|
+
* Identifier of the backend node.
|
|
6005
|
+
*/
|
|
6006
|
+
backendNodeId?: BackendNodeId;
|
|
6007
|
+
/**
|
|
6008
|
+
* JavaScript object id of the node wrapper.
|
|
6009
|
+
*/
|
|
6010
|
+
objectId?: Runtime.RemoteObjectId;
|
|
6011
|
+
/**
|
|
6012
|
+
* The type of marker to set on the given range of text.
|
|
6013
|
+
*/
|
|
6014
|
+
type: SetTextMarkerRequestType;
|
|
6015
|
+
/**
|
|
6016
|
+
* Start offset into the element's rendered text in UTF-16 code units.
|
|
6017
|
+
* For a text control, an offset into the control's value.
|
|
6018
|
+
* Offsets count text in DOM order and do not enter shadow trees.
|
|
6019
|
+
* To mark text inside a shadow tree, pass the element inside the shadow tree.
|
|
6020
|
+
*/
|
|
6021
|
+
start: integer;
|
|
6022
|
+
/**
|
|
6023
|
+
* End offset (exclusive) in the same units and space as start.
|
|
6024
|
+
*/
|
|
6025
|
+
end: integer;
|
|
6026
|
+
}
|
|
6027
|
+
|
|
5993
6028
|
/**
|
|
5994
6029
|
* Fired when `Element`'s attribute is modified.
|
|
5995
6030
|
*/
|
|
@@ -10,7 +10,6 @@ import type * as Trace from '../trace/trace.js';
|
|
|
10
10
|
|
|
11
11
|
import {
|
|
12
12
|
AiAgent,
|
|
13
|
-
type AllowedOriginResult,
|
|
14
13
|
type ContextResponse,
|
|
15
14
|
type ConversationContext,
|
|
16
15
|
type MultimodalInputType,
|
|
@@ -26,7 +25,13 @@ import {debugLog} from './debug.js';
|
|
|
26
25
|
import {ExtensionScope} from './ExtensionScope.js';
|
|
27
26
|
import type {Skill, SkillName} from './skills/Skill.js';
|
|
28
27
|
import {SKILLS} from './skills/SkillRegistry.js';
|
|
29
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
type AllToolsCapabilities,
|
|
30
|
+
isOriginAllowedByLock,
|
|
31
|
+
type OriginLockState,
|
|
32
|
+
type Tool,
|
|
33
|
+
type ToolArgs,
|
|
34
|
+
} from './tools/Tool.js';
|
|
30
35
|
import {ToolRegistry} from './tools/ToolRegistry.js';
|
|
31
36
|
|
|
32
37
|
const SKILL_DISPLAY_NAMES: Record<SkillName, string> = {
|
|
@@ -71,6 +76,10 @@ If the user asks a question that requires an investigation or debugging, use thi
|
|
|
71
76
|
* **CRITICAL**: Do not expose raw, internal system identifiers (such as database IDs, internal node paths, or event keys) directly to the user. Use descriptive names instead.`;
|
|
72
77
|
|
|
73
78
|
export interface AiAgent2Options extends ExecuteJsAgentOptions {
|
|
79
|
+
/**
|
|
80
|
+
* Supplies the origin lock state for the conversation.
|
|
81
|
+
*/
|
|
82
|
+
originLock: () => OriginLockState;
|
|
74
83
|
lighthouseRecording?: (overrides?: LHModel.RunTypes.RunOverrides) => Promise<LHModel.ReporterTypes.ReportJSON|null>;
|
|
75
84
|
performanceRecordAndReload?: () => Promise<Trace.TraceModel.ParsedTrace>;
|
|
76
85
|
}
|
|
@@ -85,7 +94,7 @@ export class AiAgent2 extends AiAgent<unknown> {
|
|
|
85
94
|
|
|
86
95
|
#changes: ChangeManager;
|
|
87
96
|
#execJs: typeof executeJsCode;
|
|
88
|
-
readonly #
|
|
97
|
+
readonly #originLock: () => OriginLockState;
|
|
89
98
|
readonly #lighthouseRecording?:
|
|
90
99
|
(overrides?: LHModel.RunTypes.RunOverrides) => Promise<LHModel.ReporterTypes.ReportJSON|null>;
|
|
91
100
|
readonly #performanceRecordAndReload?: () => Promise<Trace.TraceModel.ParsedTrace>;
|
|
@@ -102,11 +111,10 @@ export class AiAgent2 extends AiAgent<unknown> {
|
|
|
102
111
|
}
|
|
103
112
|
|
|
104
113
|
const target = this.targetManager.primaryPageTarget();
|
|
105
|
-
const
|
|
114
|
+
const originLock = this.#originLock();
|
|
106
115
|
// Avoid fetching or caching top-level documents across origins or when
|
|
107
116
|
// the origin lock is blocked/uninitialized.
|
|
108
|
-
|
|
109
|
-
const isTargetAllowed = target && isOriginAllowedByLock(establishedOrigin, target.inspectedSecurityOrigin());
|
|
117
|
+
const isTargetAllowed = target && isOriginAllowedByLock(originLock, target.inspectedSecurityOrigin());
|
|
110
118
|
const domModel = isTargetAllowed ? target.model(SDK.DOMModel.DOMModel) : null;
|
|
111
119
|
// Ensure the DOM document is requested and cached in DOMModel so that
|
|
112
120
|
// subsequent synchronous lookups via domModel.existingDocument() (e.g.,
|
|
@@ -138,7 +146,7 @@ export class AiAgent2 extends AiAgent<unknown> {
|
|
|
138
146
|
this.#lighthouseRecording = opts.lighthouseRecording;
|
|
139
147
|
this.#performanceRecordAndReload = opts.performanceRecordAndReload;
|
|
140
148
|
this.#execJs = opts.execJs ?? executeJsCode;
|
|
141
|
-
this.#
|
|
149
|
+
this.#originLock = opts.originLock;
|
|
142
150
|
this.#declaredTools.add('learnSkills');
|
|
143
151
|
this.declareFunction<{skills: SkillName[]}>('learnSkills', {
|
|
144
152
|
description: () => {
|
|
@@ -297,7 +305,7 @@ User query: ${enhancedQuery}`;
|
|
|
297
305
|
execJs: this.#execJs,
|
|
298
306
|
getExecutionContextNode: () => this.#getExecutionContextNode(),
|
|
299
307
|
getTarget: () => this.#getTarget(),
|
|
300
|
-
|
|
308
|
+
getOriginLock: () => this.#originLock(),
|
|
301
309
|
getLighthouseReport: () => (this.context instanceof AccessibilityContext ? this.context.getItem() : null),
|
|
302
310
|
runLighthouse: async overrides => await (this.#lighthouseRecording?.(overrides) ?? null),
|
|
303
311
|
getPerformanceTraceContext: () => (this.context instanceof PerformanceTraceContext ? this.context : null),
|
|
@@ -318,8 +326,7 @@ User query: ${enhancedQuery}`;
|
|
|
318
326
|
* perform their own origin checks on the resolved entities.
|
|
319
327
|
*/
|
|
320
328
|
#getTarget(): SDK.Target.Target|null {
|
|
321
|
-
|
|
322
|
-
if (allowed && 'blocked' in allowed) {
|
|
329
|
+
if (this.#originLock().status === 'BLOCKED_BY_NAVIGATION') {
|
|
323
330
|
return null;
|
|
324
331
|
}
|
|
325
332
|
return this.targetManager.primaryPageTarget();
|
|
@@ -329,7 +336,7 @@ User query: ${enhancedQuery}`;
|
|
|
329
336
|
* For non-DOM contexts (e.g., Lighthouse accessibility reports or storage items),
|
|
330
337
|
* there is no user-selected DOM node. We fall back to the document body as the
|
|
331
338
|
* default execution context node so scripts have a valid `$0` target.
|
|
332
|
-
*
|
|
339
|
+
* Returns null if the conversation origin is not established or
|
|
333
340
|
* does not match the primary page document's security origin.
|
|
334
341
|
*/
|
|
335
342
|
#getDocumentBodyNode(): SDK.DOMModel.DOMNode|null {
|
|
@@ -338,18 +345,13 @@ User query: ${enhancedQuery}`;
|
|
|
338
345
|
if (!document) {
|
|
339
346
|
return null;
|
|
340
347
|
}
|
|
341
|
-
const
|
|
342
|
-
if (!isOriginAllowedByLock(
|
|
348
|
+
const originLock = this.#originLock();
|
|
349
|
+
if (!isOriginAllowedByLock(originLock, document.securityOrigin())) {
|
|
343
350
|
return null;
|
|
344
351
|
}
|
|
345
352
|
return document.body ?? null;
|
|
346
353
|
}
|
|
347
354
|
|
|
348
|
-
#getConversationOrigin(): SDK.SecurityOrigin.SecurityOrigin|undefined {
|
|
349
|
-
const allowed = this.#allowedOrigin?.();
|
|
350
|
-
return allowed && 'origin' in allowed ? allowed.origin : undefined;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
355
|
get activeSkills(): Set<SkillName> {
|
|
354
356
|
return this.#activeSkills;
|
|
355
357
|
}
|
|
@@ -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
|
|
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(
|
|
399
|
-
|
|
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
|
|
557
|
-
*
|
|
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
|
-
|
|
566
|
+
getOriginLock = (): OriginLockState => {
|
|
560
567
|
if (this.#navigationOccurredDuringRun) {
|
|
561
|
-
return {
|
|
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 {
|
|
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 {
|
|
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
|
-
|
|
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
|
);
|