@one2x/playwright 1.57.0-alpha.1
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/LICENSE +202 -0
- package/NOTICE +5 -0
- package/README.md +168 -0
- package/ThirdPartyNotices.txt +6277 -0
- package/cli.js +19 -0
- package/index.d.ts +17 -0
- package/index.js +17 -0
- package/index.mjs +18 -0
- package/jsx-runtime.js +42 -0
- package/jsx-runtime.mjs +21 -0
- package/lib/agents/copilot-setup-steps.yml +34 -0
- package/lib/agents/generateAgents.js +394 -0
- package/lib/agents/generateAgents.js.map +7 -0
- package/lib/agents/playwright-test-coverage.prompt.md +31 -0
- package/lib/agents/playwright-test-generate.prompt.md +8 -0
- package/lib/agents/playwright-test-generator.agent.md +88 -0
- package/lib/agents/playwright-test-heal.prompt.md +6 -0
- package/lib/agents/playwright-test-healer.agent.md +55 -0
- package/lib/agents/playwright-test-plan.prompt.md +9 -0
- package/lib/agents/playwright-test-planner.agent.md +117 -0
- package/lib/common/config.js +280 -0
- package/lib/common/config.js.map +7 -0
- package/lib/common/configLoader.js +344 -0
- package/lib/common/configLoader.js.map +7 -0
- package/lib/common/esmLoaderHost.js +102 -0
- package/lib/common/esmLoaderHost.js.map +7 -0
- package/lib/common/expectBundle.js +52 -0
- package/lib/common/expectBundle.js.map +7 -0
- package/lib/common/expectBundleImpl.js +389 -0
- package/lib/common/expectBundleImpl.js.map +7 -0
- package/lib/common/fixtures.js +302 -0
- package/lib/common/fixtures.js.map +7 -0
- package/lib/common/globals.js +58 -0
- package/lib/common/globals.js.map +7 -0
- package/lib/common/ipc.js +60 -0
- package/lib/common/ipc.js.map +7 -0
- package/lib/common/poolBuilder.js +85 -0
- package/lib/common/poolBuilder.js.map +7 -0
- package/lib/common/process.js +104 -0
- package/lib/common/process.js.map +7 -0
- package/lib/common/suiteUtils.js +140 -0
- package/lib/common/suiteUtils.js.map +7 -0
- package/lib/common/test.js +321 -0
- package/lib/common/test.js.map +7 -0
- package/lib/common/testLoader.js +101 -0
- package/lib/common/testLoader.js.map +7 -0
- package/lib/common/testType.js +298 -0
- package/lib/common/testType.js.map +7 -0
- package/lib/common/validators.js +68 -0
- package/lib/common/validators.js.map +7 -0
- package/lib/fsWatcher.js +67 -0
- package/lib/fsWatcher.js.map +7 -0
- package/lib/index.js +682 -0
- package/lib/index.js.map +7 -0
- package/lib/internalsForTest.js +42 -0
- package/lib/internalsForTest.js.map +7 -0
- package/lib/isomorphic/events.js +77 -0
- package/lib/isomorphic/events.js.map +7 -0
- package/lib/isomorphic/folders.js +30 -0
- package/lib/isomorphic/folders.js.map +7 -0
- package/lib/isomorphic/stringInternPool.js +69 -0
- package/lib/isomorphic/stringInternPool.js.map +7 -0
- package/lib/isomorphic/teleReceiver.js +508 -0
- package/lib/isomorphic/teleReceiver.js.map +7 -0
- package/lib/isomorphic/teleSuiteUpdater.js +137 -0
- package/lib/isomorphic/teleSuiteUpdater.js.map +7 -0
- package/lib/isomorphic/testServerConnection.js +211 -0
- package/lib/isomorphic/testServerConnection.js.map +7 -0
- package/lib/isomorphic/testServerInterface.js +16 -0
- package/lib/isomorphic/testServerInterface.js.map +7 -0
- package/lib/isomorphic/testTree.js +334 -0
- package/lib/isomorphic/testTree.js.map +7 -0
- package/lib/isomorphic/types.d.js +16 -0
- package/lib/isomorphic/types.d.js.map +7 -0
- package/lib/loader/loaderMain.js +59 -0
- package/lib/loader/loaderMain.js.map +7 -0
- package/lib/matchers/expect.js +325 -0
- package/lib/matchers/expect.js.map +7 -0
- package/lib/matchers/matcherHint.js +87 -0
- package/lib/matchers/matcherHint.js.map +7 -0
- package/lib/matchers/matchers.js +366 -0
- package/lib/matchers/matchers.js.map +7 -0
- package/lib/matchers/toBeTruthy.js +73 -0
- package/lib/matchers/toBeTruthy.js.map +7 -0
- package/lib/matchers/toEqual.js +99 -0
- package/lib/matchers/toEqual.js.map +7 -0
- package/lib/matchers/toHaveURL.js +102 -0
- package/lib/matchers/toHaveURL.js.map +7 -0
- package/lib/matchers/toMatchAriaSnapshot.js +159 -0
- package/lib/matchers/toMatchAriaSnapshot.js.map +7 -0
- package/lib/matchers/toMatchSnapshot.js +341 -0
- package/lib/matchers/toMatchSnapshot.js.map +7 -0
- package/lib/matchers/toMatchText.js +99 -0
- package/lib/matchers/toMatchText.js.map +7 -0
- package/lib/mcp/browser/actions.d.js +16 -0
- package/lib/mcp/browser/actions.d.js.map +7 -0
- package/lib/mcp/browser/browserContextFactory.js +357 -0
- package/lib/mcp/browser/browserContextFactory.js.map +7 -0
- package/lib/mcp/browser/browserServerBackend.js +76 -0
- package/lib/mcp/browser/browserServerBackend.js.map +7 -0
- package/lib/mcp/browser/codegen.js +66 -0
- package/lib/mcp/browser/codegen.js.map +7 -0
- package/lib/mcp/browser/config.js +425 -0
- package/lib/mcp/browser/config.js.map +7 -0
- package/lib/mcp/browser/context.js +287 -0
- package/lib/mcp/browser/context.js.map +7 -0
- package/lib/mcp/browser/response.js +228 -0
- package/lib/mcp/browser/response.js.map +7 -0
- package/lib/mcp/browser/sessionLog.js +160 -0
- package/lib/mcp/browser/sessionLog.js.map +7 -0
- package/lib/mcp/browser/tab.js +280 -0
- package/lib/mcp/browser/tab.js.map +7 -0
- package/lib/mcp/browser/tools/actionRetry.js +40 -0
- package/lib/mcp/browser/tools/actionRetry.js.map +7 -0
- package/lib/mcp/browser/tools/common.js +63 -0
- package/lib/mcp/browser/tools/common.js.map +7 -0
- package/lib/mcp/browser/tools/console.js +44 -0
- package/lib/mcp/browser/tools/console.js.map +7 -0
- package/lib/mcp/browser/tools/dialogs.js +60 -0
- package/lib/mcp/browser/tools/dialogs.js.map +7 -0
- package/lib/mcp/browser/tools/evaluate.js +69 -0
- package/lib/mcp/browser/tools/evaluate.js.map +7 -0
- package/lib/mcp/browser/tools/files.js +58 -0
- package/lib/mcp/browser/tools/files.js.map +7 -0
- package/lib/mcp/browser/tools/form.js +79 -0
- package/lib/mcp/browser/tools/form.js.map +7 -0
- package/lib/mcp/browser/tools/install.js +69 -0
- package/lib/mcp/browser/tools/install.js.map +7 -0
- package/lib/mcp/browser/tools/keyboard.js +84 -0
- package/lib/mcp/browser/tools/keyboard.js.map +7 -0
- package/lib/mcp/browser/tools/mouse.js +107 -0
- package/lib/mcp/browser/tools/mouse.js.map +7 -0
- package/lib/mcp/browser/tools/navigate.js +62 -0
- package/lib/mcp/browser/tools/navigate.js.map +7 -0
- package/lib/mcp/browser/tools/network.js +54 -0
- package/lib/mcp/browser/tools/network.js.map +7 -0
- package/lib/mcp/browser/tools/pdf.js +59 -0
- package/lib/mcp/browser/tools/pdf.js.map +7 -0
- package/lib/mcp/browser/tools/screenshot.js +106 -0
- package/lib/mcp/browser/tools/screenshot.js.map +7 -0
- package/lib/mcp/browser/tools/snapshot.js +312 -0
- package/lib/mcp/browser/tools/snapshot.js.map +7 -0
- package/lib/mcp/browser/tools/tabs.js +67 -0
- package/lib/mcp/browser/tools/tabs.js.map +7 -0
- package/lib/mcp/browser/tools/tool.js +49 -0
- package/lib/mcp/browser/tools/tool.js.map +7 -0
- package/lib/mcp/browser/tools/tracing.js +74 -0
- package/lib/mcp/browser/tools/tracing.js.map +7 -0
- package/lib/mcp/browser/tools/utils.js +96 -0
- package/lib/mcp/browser/tools/utils.js.map +7 -0
- package/lib/mcp/browser/tools/verify.js +153 -0
- package/lib/mcp/browser/tools/verify.js.map +7 -0
- package/lib/mcp/browser/tools/wait.js +63 -0
- package/lib/mcp/browser/tools/wait.js.map +7 -0
- package/lib/mcp/browser/tools.js +80 -0
- package/lib/mcp/browser/tools.js.map +7 -0
- package/lib/mcp/browser/watchdog.js +44 -0
- package/lib/mcp/browser/watchdog.js.map +7 -0
- package/lib/mcp/config.d.js +16 -0
- package/lib/mcp/config.d.js.map +7 -0
- package/lib/mcp/extension/cdpRelay.js +351 -0
- package/lib/mcp/extension/cdpRelay.js.map +7 -0
- package/lib/mcp/extension/extensionContextFactory.js +75 -0
- package/lib/mcp/extension/extensionContextFactory.js.map +7 -0
- package/lib/mcp/extension/protocol.js +28 -0
- package/lib/mcp/extension/protocol.js.map +7 -0
- package/lib/mcp/index.js +61 -0
- package/lib/mcp/index.js.map +7 -0
- package/lib/mcp/log.js +35 -0
- package/lib/mcp/log.js.map +7 -0
- package/lib/mcp/program.js +118 -0
- package/lib/mcp/program.js.map +7 -0
- package/lib/mcp/sdk/bundle.js +81 -0
- package/lib/mcp/sdk/bundle.js.map +7 -0
- package/lib/mcp/sdk/exports.js +32 -0
- package/lib/mcp/sdk/exports.js.map +7 -0
- package/lib/mcp/sdk/http.js +276 -0
- package/lib/mcp/sdk/http.js.map +7 -0
- package/lib/mcp/sdk/inProcessTransport.js +71 -0
- package/lib/mcp/sdk/inProcessTransport.js.map +7 -0
- package/lib/mcp/sdk/mdb.js +208 -0
- package/lib/mcp/sdk/mdb.js.map +7 -0
- package/lib/mcp/sdk/proxyBackend.js +128 -0
- package/lib/mcp/sdk/proxyBackend.js.map +7 -0
- package/lib/mcp/sdk/server.js +190 -0
- package/lib/mcp/sdk/server.js.map +7 -0
- package/lib/mcp/sdk/tool.js +51 -0
- package/lib/mcp/sdk/tool.js.map +7 -0
- package/lib/mcp/test/browserBackend.js +98 -0
- package/lib/mcp/test/browserBackend.js.map +7 -0
- package/lib/mcp/test/generatorTools.js +122 -0
- package/lib/mcp/test/generatorTools.js.map +7 -0
- package/lib/mcp/test/plannerTools.js +46 -0
- package/lib/mcp/test/plannerTools.js.map +7 -0
- package/lib/mcp/test/seed.js +82 -0
- package/lib/mcp/test/seed.js.map +7 -0
- package/lib/mcp/test/streams.js +41 -0
- package/lib/mcp/test/streams.js.map +7 -0
- package/lib/mcp/test/testBackend.js +97 -0
- package/lib/mcp/test/testBackend.js.map +7 -0
- package/lib/mcp/test/testContext.js +216 -0
- package/lib/mcp/test/testContext.js.map +7 -0
- package/lib/mcp/test/testTool.js +30 -0
- package/lib/mcp/test/testTool.js.map +7 -0
- package/lib/mcp/test/testTools.js +111 -0
- package/lib/mcp/test/testTools.js.map +7 -0
- package/lib/mcpBundleImpl.js +41 -0
- package/lib/mcpBundleImpl.js.map +7 -0
- package/lib/plugins/gitCommitInfoPlugin.js +198 -0
- package/lib/plugins/gitCommitInfoPlugin.js.map +7 -0
- package/lib/plugins/index.js +28 -0
- package/lib/plugins/index.js.map +7 -0
- package/lib/plugins/webServerPlugin.js +233 -0
- package/lib/plugins/webServerPlugin.js.map +7 -0
- package/lib/program.js +412 -0
- package/lib/program.js.map +7 -0
- package/lib/reporters/base.js +609 -0
- package/lib/reporters/base.js.map +7 -0
- package/lib/reporters/blob.js +135 -0
- package/lib/reporters/blob.js.map +7 -0
- package/lib/reporters/dot.js +82 -0
- package/lib/reporters/dot.js.map +7 -0
- package/lib/reporters/empty.js +32 -0
- package/lib/reporters/empty.js.map +7 -0
- package/lib/reporters/github.js +128 -0
- package/lib/reporters/github.js.map +7 -0
- package/lib/reporters/html.js +623 -0
- package/lib/reporters/html.js.map +7 -0
- package/lib/reporters/internalReporter.js +130 -0
- package/lib/reporters/internalReporter.js.map +7 -0
- package/lib/reporters/json.js +254 -0
- package/lib/reporters/json.js.map +7 -0
- package/lib/reporters/junit.js +232 -0
- package/lib/reporters/junit.js.map +7 -0
- package/lib/reporters/line.js +113 -0
- package/lib/reporters/line.js.map +7 -0
- package/lib/reporters/list.js +231 -0
- package/lib/reporters/list.js.map +7 -0
- package/lib/reporters/listModeReporter.js +69 -0
- package/lib/reporters/listModeReporter.js.map +7 -0
- package/lib/reporters/markdown.js +144 -0
- package/lib/reporters/markdown.js.map +7 -0
- package/lib/reporters/merge.js +541 -0
- package/lib/reporters/merge.js.map +7 -0
- package/lib/reporters/multiplexer.js +104 -0
- package/lib/reporters/multiplexer.js.map +7 -0
- package/lib/reporters/reporterV2.js +102 -0
- package/lib/reporters/reporterV2.js.map +7 -0
- package/lib/reporters/teleEmitter.js +298 -0
- package/lib/reporters/teleEmitter.js.map +7 -0
- package/lib/reporters/versions/blobV1.js +16 -0
- package/lib/reporters/versions/blobV1.js.map +7 -0
- package/lib/runner/dispatcher.js +491 -0
- package/lib/runner/dispatcher.js.map +7 -0
- package/lib/runner/failureTracker.js +72 -0
- package/lib/runner/failureTracker.js.map +7 -0
- package/lib/runner/lastRun.js +77 -0
- package/lib/runner/lastRun.js.map +7 -0
- package/lib/runner/loadUtils.js +334 -0
- package/lib/runner/loadUtils.js.map +7 -0
- package/lib/runner/loaderHost.js +89 -0
- package/lib/runner/loaderHost.js.map +7 -0
- package/lib/runner/processHost.js +161 -0
- package/lib/runner/processHost.js.map +7 -0
- package/lib/runner/projectUtils.js +241 -0
- package/lib/runner/projectUtils.js.map +7 -0
- package/lib/runner/rebase.js +189 -0
- package/lib/runner/rebase.js.map +7 -0
- package/lib/runner/reporters.js +138 -0
- package/lib/runner/reporters.js.map +7 -0
- package/lib/runner/runner.js +110 -0
- package/lib/runner/sigIntWatcher.js +96 -0
- package/lib/runner/sigIntWatcher.js.map +7 -0
- package/lib/runner/taskRunner.js +127 -0
- package/lib/runner/taskRunner.js.map +7 -0
- package/lib/runner/tasks.js +410 -0
- package/lib/runner/tasks.js.map +7 -0
- package/lib/runner/testGroups.js +117 -0
- package/lib/runner/testGroups.js.map +7 -0
- package/lib/runner/testRunner.js +390 -0
- package/lib/runner/testRunner.js.map +7 -0
- package/lib/runner/testServer.js +267 -0
- package/lib/runner/testServer.js.map +7 -0
- package/lib/runner/uiModeReporter.js +30 -0
- package/lib/runner/uiModeReporter.js.map +7 -0
- package/lib/runner/vcs.js +72 -0
- package/lib/runner/vcs.js.map +7 -0
- package/lib/runner/watchMode.js +395 -0
- package/lib/runner/watchMode.js.map +7 -0
- package/lib/runner/workerHost.js +95 -0
- package/lib/runner/workerHost.js.map +7 -0
- package/lib/third_party/pirates.js +62 -0
- package/lib/third_party/pirates.js.map +7 -0
- package/lib/third_party/tsconfig-loader.js +103 -0
- package/lib/third_party/tsconfig-loader.js.map +7 -0
- package/lib/transform/babelBundle.js +43 -0
- package/lib/transform/babelBundle.js.map +7 -0
- package/lib/transform/babelBundleImpl.js +461 -0
- package/lib/transform/babelBundleImpl.js.map +7 -0
- package/lib/transform/compilationCache.js +272 -0
- package/lib/transform/compilationCache.js.map +7 -0
- package/lib/transform/esmLoader.js +104 -0
- package/lib/transform/esmLoader.js.map +7 -0
- package/lib/transform/portTransport.js +67 -0
- package/lib/transform/portTransport.js.map +7 -0
- package/lib/transform/transform.js +293 -0
- package/lib/transform/transform.js.map +7 -0
- package/lib/util.js +403 -0
- package/lib/util.js.map +7 -0
- package/lib/utilsBundle.js +43 -0
- package/lib/utilsBundle.js.map +7 -0
- package/lib/utilsBundleImpl.js +100 -0
- package/lib/utilsBundleImpl.js.map +7 -0
- package/lib/worker/fixtureRunner.js +258 -0
- package/lib/worker/fixtureRunner.js.map +7 -0
- package/lib/worker/testInfo.js +514 -0
- package/lib/worker/testInfo.js.map +7 -0
- package/lib/worker/testTracing.js +344 -0
- package/lib/worker/testTracing.js.map +7 -0
- package/lib/worker/timeoutManager.js +174 -0
- package/lib/worker/timeoutManager.js.map +7 -0
- package/lib/worker/util.js +31 -0
- package/lib/worker/util.js.map +7 -0
- package/lib/worker/workerMain.js +520 -0
- package/lib/worker/workerMain.js.map +7 -0
- package/package.json +74 -0
- package/test.d.ts +18 -0
- package/test.js +24 -0
- package/test.mjs +33 -0
- package/types/test.d.ts +10196 -0
- package/types/testReporter.d.ts +821 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var context_exports = {};
|
|
30
|
+
__export(context_exports, {
|
|
31
|
+
Context: () => Context,
|
|
32
|
+
InputRecorder: () => InputRecorder
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(context_exports);
|
|
35
|
+
var import_fs = __toESM(require("fs"));
|
|
36
|
+
var import_path = __toESM(require("path"));
|
|
37
|
+
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
|
|
38
|
+
var import_playwright_core = require("playwright-core");
|
|
39
|
+
var import_log = require("../log");
|
|
40
|
+
var import_tab = require("./tab");
|
|
41
|
+
var import_config = require("./config");
|
|
42
|
+
var codegen = __toESM(require("./codegen"));
|
|
43
|
+
var import_utils = require("./tools/utils");
|
|
44
|
+
const testDebug = (0, import_utilsBundle.debug)("pw:mcp:test");
|
|
45
|
+
class Context {
|
|
46
|
+
constructor(options) {
|
|
47
|
+
this._tabs = [];
|
|
48
|
+
this._abortController = new AbortController();
|
|
49
|
+
this.config = options.config;
|
|
50
|
+
this.sessionLog = options.sessionLog;
|
|
51
|
+
this.options = options;
|
|
52
|
+
this._browserContextFactory = options.browserContextFactory;
|
|
53
|
+
this._clientInfo = options.clientInfo;
|
|
54
|
+
testDebug("create context");
|
|
55
|
+
Context._allContexts.add(this);
|
|
56
|
+
}
|
|
57
|
+
static {
|
|
58
|
+
this._allContexts = /* @__PURE__ */ new Set();
|
|
59
|
+
}
|
|
60
|
+
static async disposeAll() {
|
|
61
|
+
await Promise.all([...Context._allContexts].map((context) => context.dispose()));
|
|
62
|
+
}
|
|
63
|
+
tabs() {
|
|
64
|
+
return this._tabs;
|
|
65
|
+
}
|
|
66
|
+
currentTab() {
|
|
67
|
+
return this._currentTab;
|
|
68
|
+
}
|
|
69
|
+
currentTabOrDie() {
|
|
70
|
+
if (!this._currentTab)
|
|
71
|
+
throw new Error('No open pages available. Use the "browser_navigate" tool to navigate to a page first.');
|
|
72
|
+
return this._currentTab;
|
|
73
|
+
}
|
|
74
|
+
async newTab() {
|
|
75
|
+
const { browserContext } = await this._ensureBrowserContext();
|
|
76
|
+
const page = await browserContext.newPage();
|
|
77
|
+
this._currentTab = this._tabs.find((t) => t.page === page);
|
|
78
|
+
return this._currentTab;
|
|
79
|
+
}
|
|
80
|
+
async selectTab(index) {
|
|
81
|
+
const tab = this._tabs[index];
|
|
82
|
+
if (!tab)
|
|
83
|
+
throw new Error(`Tab ${index} not found`);
|
|
84
|
+
await tab.page.bringToFront();
|
|
85
|
+
this._currentTab = tab;
|
|
86
|
+
return tab;
|
|
87
|
+
}
|
|
88
|
+
async ensureTab() {
|
|
89
|
+
const { browserContext } = await this._ensureBrowserContext();
|
|
90
|
+
if (!this._currentTab)
|
|
91
|
+
await browserContext.newPage();
|
|
92
|
+
return this._currentTab;
|
|
93
|
+
}
|
|
94
|
+
async closeTab(index) {
|
|
95
|
+
const tab = index === void 0 ? this._currentTab : this._tabs[index];
|
|
96
|
+
if (!tab)
|
|
97
|
+
throw new Error(`Tab ${index} not found`);
|
|
98
|
+
const url = tab.page.url();
|
|
99
|
+
await tab.page.close();
|
|
100
|
+
return url;
|
|
101
|
+
}
|
|
102
|
+
async outputFile(fileName, options) {
|
|
103
|
+
return (0, import_config.outputFile)(this.config, this._clientInfo, fileName, options);
|
|
104
|
+
}
|
|
105
|
+
_onPageCreated(page) {
|
|
106
|
+
const tab = new import_tab.Tab(this, page, (tab2) => this._onPageClosed(tab2));
|
|
107
|
+
this._tabs.push(tab);
|
|
108
|
+
if (!this._currentTab)
|
|
109
|
+
this._currentTab = tab;
|
|
110
|
+
}
|
|
111
|
+
_onPageClosed(tab) {
|
|
112
|
+
const index = this._tabs.indexOf(tab);
|
|
113
|
+
if (index === -1)
|
|
114
|
+
return;
|
|
115
|
+
this._tabs.splice(index, 1);
|
|
116
|
+
if (this._currentTab === tab)
|
|
117
|
+
this._currentTab = this._tabs[Math.min(index, this._tabs.length - 1)];
|
|
118
|
+
if (!this._tabs.length)
|
|
119
|
+
void this.closeBrowserContext();
|
|
120
|
+
}
|
|
121
|
+
async closeBrowserContext() {
|
|
122
|
+
if (!this._closeBrowserContextPromise)
|
|
123
|
+
this._closeBrowserContextPromise = this._closeBrowserContextImpl().catch(import_log.logUnhandledError);
|
|
124
|
+
await this._closeBrowserContextPromise;
|
|
125
|
+
this._closeBrowserContextPromise = void 0;
|
|
126
|
+
}
|
|
127
|
+
isRunningTool() {
|
|
128
|
+
return this._runningToolName !== void 0;
|
|
129
|
+
}
|
|
130
|
+
setRunningTool(name) {
|
|
131
|
+
this._runningToolName = name;
|
|
132
|
+
}
|
|
133
|
+
async _closeBrowserContextImpl() {
|
|
134
|
+
if (!this._browserContextPromise)
|
|
135
|
+
return;
|
|
136
|
+
testDebug("close context");
|
|
137
|
+
const promise = this._browserContextPromise;
|
|
138
|
+
this._browserContextPromise = void 0;
|
|
139
|
+
await promise.then(async ({ browserContext, close }) => {
|
|
140
|
+
if (this.config.saveTrace)
|
|
141
|
+
await browserContext.tracing.stop();
|
|
142
|
+
const videos = this.config.saveVideo ? browserContext.pages().map((page) => page.video()).filter((video) => !!video) : [];
|
|
143
|
+
await close(async () => {
|
|
144
|
+
for (const video of videos) {
|
|
145
|
+
const name = await this.outputFile((0, import_utils.dateAsFileName)("webm"), { origin: "code", reason: "Saving video" });
|
|
146
|
+
await import_fs.default.promises.mkdir(import_path.default.dirname(name), { recursive: true });
|
|
147
|
+
const p = await video.path();
|
|
148
|
+
if (import_fs.default.existsSync(p)) {
|
|
149
|
+
try {
|
|
150
|
+
await import_fs.default.promises.rename(p, name);
|
|
151
|
+
} catch (e) {
|
|
152
|
+
if (e.code !== "EXDEV")
|
|
153
|
+
(0, import_log.logUnhandledError)(e);
|
|
154
|
+
try {
|
|
155
|
+
await import_fs.default.promises.copyFile(p, name);
|
|
156
|
+
await import_fs.default.promises.unlink(p);
|
|
157
|
+
} catch (e2) {
|
|
158
|
+
(0, import_log.logUnhandledError)(e2);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
async dispose() {
|
|
167
|
+
this._abortController.abort("MCP context disposed");
|
|
168
|
+
await this.closeBrowserContext();
|
|
169
|
+
Context._allContexts.delete(this);
|
|
170
|
+
}
|
|
171
|
+
async _setupRequestInterception(context) {
|
|
172
|
+
if (this.config.network?.allowedOrigins?.length) {
|
|
173
|
+
await context.route("**", (route) => route.abort("blockedbyclient"));
|
|
174
|
+
for (const origin of this.config.network.allowedOrigins)
|
|
175
|
+
await context.route(originOrHostGlob(origin), (route) => route.continue());
|
|
176
|
+
}
|
|
177
|
+
if (this.config.network?.blockedOrigins?.length) {
|
|
178
|
+
for (const origin of this.config.network.blockedOrigins)
|
|
179
|
+
await context.route(originOrHostGlob(origin), (route) => route.abort("blockedbyclient"));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async ensureBrowserContext() {
|
|
183
|
+
const { browserContext } = await this._ensureBrowserContext();
|
|
184
|
+
return browserContext;
|
|
185
|
+
}
|
|
186
|
+
_ensureBrowserContext() {
|
|
187
|
+
if (!this._browserContextPromise) {
|
|
188
|
+
this._browserContextPromise = this._setupBrowserContext();
|
|
189
|
+
this._browserContextPromise.catch(() => {
|
|
190
|
+
this._browserContextPromise = void 0;
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
return this._browserContextPromise;
|
|
194
|
+
}
|
|
195
|
+
async _setupBrowserContext() {
|
|
196
|
+
if (this._closeBrowserContextPromise)
|
|
197
|
+
throw new Error("Another browser context is being closed.");
|
|
198
|
+
if (this.config.testIdAttribute)
|
|
199
|
+
import_playwright_core.selectors.setTestIdAttribute(this.config.testIdAttribute);
|
|
200
|
+
const result = await this._browserContextFactory.createContext(this._clientInfo, this._abortController.signal, this._runningToolName);
|
|
201
|
+
const { browserContext } = result;
|
|
202
|
+
await this._setupRequestInterception(browserContext);
|
|
203
|
+
if (this.sessionLog)
|
|
204
|
+
await InputRecorder.create(this, browserContext);
|
|
205
|
+
for (const page of browserContext.pages())
|
|
206
|
+
this._onPageCreated(page);
|
|
207
|
+
browserContext.on("page", (page) => this._onPageCreated(page));
|
|
208
|
+
if (this.config.saveTrace) {
|
|
209
|
+
await browserContext.tracing.start({
|
|
210
|
+
name: "trace-" + Date.now(),
|
|
211
|
+
screenshots: true,
|
|
212
|
+
snapshots: true,
|
|
213
|
+
_live: true
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
return result;
|
|
217
|
+
}
|
|
218
|
+
lookupSecret(secretName) {
|
|
219
|
+
if (!this.config.secrets?.[secretName])
|
|
220
|
+
return { value: secretName, code: codegen.quote(secretName) };
|
|
221
|
+
return {
|
|
222
|
+
value: this.config.secrets[secretName],
|
|
223
|
+
code: `process.env['${secretName}']`
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function originOrHostGlob(originOrHost) {
|
|
228
|
+
try {
|
|
229
|
+
const url = new URL(originOrHost);
|
|
230
|
+
if (url.origin !== "null")
|
|
231
|
+
return `${url.origin}/**`;
|
|
232
|
+
} catch {
|
|
233
|
+
}
|
|
234
|
+
return `*://${originOrHost}/**`;
|
|
235
|
+
}
|
|
236
|
+
class InputRecorder {
|
|
237
|
+
constructor(context, browserContext) {
|
|
238
|
+
this._context = context;
|
|
239
|
+
this._browserContext = browserContext;
|
|
240
|
+
}
|
|
241
|
+
static async create(context, browserContext) {
|
|
242
|
+
const recorder = new InputRecorder(context, browserContext);
|
|
243
|
+
await recorder._initialize();
|
|
244
|
+
return recorder;
|
|
245
|
+
}
|
|
246
|
+
async _initialize() {
|
|
247
|
+
const sessionLog = this._context.sessionLog;
|
|
248
|
+
await this._browserContext._enableRecorder({
|
|
249
|
+
mode: "recording",
|
|
250
|
+
recorderMode: "api"
|
|
251
|
+
}, {
|
|
252
|
+
actionAdded: (page, data, code) => {
|
|
253
|
+
if (this._context.isRunningTool())
|
|
254
|
+
return;
|
|
255
|
+
const tab = import_tab.Tab.forPage(page);
|
|
256
|
+
if (tab)
|
|
257
|
+
sessionLog.logUserAction(data.action, tab, code, false);
|
|
258
|
+
},
|
|
259
|
+
actionUpdated: (page, data, code) => {
|
|
260
|
+
if (this._context.isRunningTool())
|
|
261
|
+
return;
|
|
262
|
+
const tab = import_tab.Tab.forPage(page);
|
|
263
|
+
if (tab)
|
|
264
|
+
sessionLog.logUserAction(data.action, tab, code, true);
|
|
265
|
+
},
|
|
266
|
+
signalAdded: (page, data) => {
|
|
267
|
+
if (this._context.isRunningTool())
|
|
268
|
+
return;
|
|
269
|
+
if (data.signal.name !== "navigation")
|
|
270
|
+
return;
|
|
271
|
+
const tab = import_tab.Tab.forPage(page);
|
|
272
|
+
const navigateAction = {
|
|
273
|
+
name: "navigate",
|
|
274
|
+
url: data.signal.url,
|
|
275
|
+
signals: []
|
|
276
|
+
};
|
|
277
|
+
if (tab)
|
|
278
|
+
sessionLog.logUserAction(navigateAction, tab, `await page.goto('${data.signal.url}');`, false);
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
284
|
+
0 && (module.exports = {
|
|
285
|
+
Context,
|
|
286
|
+
InputRecorder
|
|
287
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/mcp/browser/context.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright (c) Microsoft Corporation.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs';\nimport path from 'path';\n\nimport { debug } from 'playwright-core/lib/utilsBundle';\nimport { selectors } from 'playwright-core';\n\nimport { logUnhandledError } from '../log';\nimport { Tab } from './tab';\nimport { outputFile } from './config';\nimport * as codegen from './codegen';\nimport { dateAsFileName } from './tools/utils';\n\nimport type * as playwright from '../../../types/test';\nimport type { FullConfig } from './config';\nimport type { BrowserContextFactory, BrowserContextFactoryResult } from './browserContextFactory';\nimport type * as actions from './actions';\nimport type { SessionLog } from './sessionLog';\nimport type { Tracing } from '../../../../playwright-core/src/client/tracing';\nimport type { ClientInfo } from '../sdk/server';\n\nconst testDebug = debug('pw:mcp:test');\n\ntype ContextOptions = {\n config: FullConfig;\n browserContextFactory: BrowserContextFactory;\n sessionLog: SessionLog | undefined;\n clientInfo: ClientInfo;\n};\n\nexport class Context {\n readonly config: FullConfig;\n readonly sessionLog: SessionLog | undefined;\n readonly options: ContextOptions;\n private _browserContextPromise: Promise<BrowserContextFactoryResult> | undefined;\n private _browserContextFactory: BrowserContextFactory;\n private _tabs: Tab[] = [];\n private _currentTab: Tab | undefined;\n private _clientInfo: ClientInfo;\n\n private static _allContexts: Set<Context> = new Set();\n private _closeBrowserContextPromise: Promise<void> | undefined;\n private _runningToolName: string | undefined;\n private _abortController = new AbortController();\n\n constructor(options: ContextOptions) {\n this.config = options.config;\n this.sessionLog = options.sessionLog;\n this.options = options;\n this._browserContextFactory = options.browserContextFactory;\n this._clientInfo = options.clientInfo;\n testDebug('create context');\n Context._allContexts.add(this);\n }\n\n static async disposeAll() {\n await Promise.all([...Context._allContexts].map(context => context.dispose()));\n }\n\n tabs(): Tab[] {\n return this._tabs;\n }\n\n currentTab(): Tab | undefined {\n return this._currentTab;\n }\n\n currentTabOrDie(): Tab {\n if (!this._currentTab)\n throw new Error('No open pages available. Use the \"browser_navigate\" tool to navigate to a page first.');\n return this._currentTab;\n }\n\n async newTab(): Promise<Tab> {\n const { browserContext } = await this._ensureBrowserContext();\n const page = await browserContext.newPage();\n this._currentTab = this._tabs.find(t => t.page === page)!;\n return this._currentTab;\n }\n\n async selectTab(index: number) {\n const tab = this._tabs[index];\n if (!tab)\n throw new Error(`Tab ${index} not found`);\n await tab.page.bringToFront();\n this._currentTab = tab;\n return tab;\n }\n\n async ensureTab(): Promise<Tab> {\n const { browserContext } = await this._ensureBrowserContext();\n if (!this._currentTab)\n await browserContext.newPage();\n return this._currentTab!;\n }\n\n async closeTab(index: number | undefined): Promise<string> {\n const tab = index === undefined ? this._currentTab : this._tabs[index];\n if (!tab)\n throw new Error(`Tab ${index} not found`);\n const url = tab.page.url();\n await tab.page.close();\n return url;\n }\n\n async outputFile(fileName: string, options: { origin: 'code' | 'llm' | 'web', reason: string }): Promise<string> {\n return outputFile(this.config, this._clientInfo, fileName, options);\n }\n\n private _onPageCreated(page: playwright.Page) {\n const tab = new Tab(this, page, tab => this._onPageClosed(tab));\n this._tabs.push(tab);\n if (!this._currentTab)\n this._currentTab = tab;\n }\n\n private _onPageClosed(tab: Tab) {\n const index = this._tabs.indexOf(tab);\n if (index === -1)\n return;\n this._tabs.splice(index, 1);\n\n if (this._currentTab === tab)\n this._currentTab = this._tabs[Math.min(index, this._tabs.length - 1)];\n if (!this._tabs.length)\n void this.closeBrowserContext();\n }\n\n async closeBrowserContext() {\n if (!this._closeBrowserContextPromise)\n this._closeBrowserContextPromise = this._closeBrowserContextImpl().catch(logUnhandledError);\n await this._closeBrowserContextPromise;\n this._closeBrowserContextPromise = undefined;\n }\n\n isRunningTool() {\n return this._runningToolName !== undefined;\n }\n\n setRunningTool(name: string | undefined) {\n this._runningToolName = name;\n }\n\n private async _closeBrowserContextImpl() {\n if (!this._browserContextPromise)\n return;\n\n testDebug('close context');\n\n const promise = this._browserContextPromise;\n this._browserContextPromise = undefined;\n\n await promise.then(async ({ browserContext, close }) => {\n if (this.config.saveTrace)\n await browserContext.tracing.stop();\n const videos = this.config.saveVideo ? browserContext.pages().map(page => page.video()).filter(video => !!video) : [];\n await close(async () => {\n for (const video of videos) {\n const name = await this.outputFile(dateAsFileName('webm'), { origin: 'code', reason: 'Saving video' });\n await fs.promises.mkdir(path.dirname(name), { recursive: true });\n const p = await video.path();\n // video.saveAs() does not work for persistent contexts.\n if (fs.existsSync(p)) {\n try {\n await fs.promises.rename(p, name);\n } catch (e) {\n if (e.code !== 'EXDEV')\n logUnhandledError(e);\n // Retry operation (possibly cross-fs) with copy and unlink\n try {\n await fs.promises.copyFile(p, name);\n await fs.promises.unlink(p);\n } catch (e) {\n logUnhandledError(e);\n }\n }\n }\n }\n });\n });\n }\n\n async dispose() {\n this._abortController.abort('MCP context disposed');\n await this.closeBrowserContext();\n Context._allContexts.delete(this);\n }\n\n private async _setupRequestInterception(context: playwright.BrowserContext) {\n if (this.config.network?.allowedOrigins?.length) {\n await context.route('**', route => route.abort('blockedbyclient'));\n\n for (const origin of this.config.network.allowedOrigins)\n await context.route(originOrHostGlob(origin), route => route.continue());\n }\n\n if (this.config.network?.blockedOrigins?.length) {\n for (const origin of this.config.network.blockedOrigins)\n await context.route(originOrHostGlob(origin), route => route.abort('blockedbyclient'));\n }\n }\n\n async ensureBrowserContext(): Promise<playwright.BrowserContext> {\n const { browserContext } = await this._ensureBrowserContext();\n return browserContext;\n }\n\n private _ensureBrowserContext() {\n if (!this._browserContextPromise) {\n this._browserContextPromise = this._setupBrowserContext();\n this._browserContextPromise.catch(() => {\n this._browserContextPromise = undefined;\n });\n }\n return this._browserContextPromise;\n }\n\n private async _setupBrowserContext(): Promise<BrowserContextFactoryResult> {\n if (this._closeBrowserContextPromise)\n throw new Error('Another browser context is being closed.');\n // TODO: move to the browser context factory to make it based on isolation mode.\n\n if (this.config.testIdAttribute)\n selectors.setTestIdAttribute(this.config.testIdAttribute);\n const result = await this._browserContextFactory.createContext(this._clientInfo, this._abortController.signal, this._runningToolName);\n const { browserContext } = result;\n await this._setupRequestInterception(browserContext);\n if (this.sessionLog)\n await InputRecorder.create(this, browserContext);\n for (const page of browserContext.pages())\n this._onPageCreated(page);\n browserContext.on('page', page => this._onPageCreated(page));\n if (this.config.saveTrace) {\n await (browserContext.tracing as Tracing).start({\n name: 'trace-' + Date.now(),\n screenshots: true,\n snapshots: true,\n _live: true,\n });\n }\n return result;\n }\n\n lookupSecret(secretName: string): { value: string, code: string } {\n if (!this.config.secrets?.[secretName])\n return { value: secretName, code: codegen.quote(secretName) };\n return {\n value: this.config.secrets[secretName]!,\n code: `process.env['${secretName}']`,\n };\n }\n}\n\nfunction originOrHostGlob(originOrHost: string) {\n try {\n const url = new URL(originOrHost);\n // localhost:1234 will parse as protocol 'localhost:' and 'null' origin.\n if (url.origin !== 'null')\n return `${url.origin}/**`;\n } catch {\n }\n // Support for legacy host-only mode.\n return `*://${originOrHost}/**`;\n}\n\nexport class InputRecorder {\n private _context: Context;\n private _browserContext: playwright.BrowserContext;\n\n private constructor(context: Context, browserContext: playwright.BrowserContext) {\n this._context = context;\n this._browserContext = browserContext;\n }\n\n static async create(context: Context, browserContext: playwright.BrowserContext) {\n const recorder = new InputRecorder(context, browserContext);\n await recorder._initialize();\n return recorder;\n }\n\n private async _initialize() {\n const sessionLog = this._context.sessionLog!;\n await (this._browserContext as any)._enableRecorder({\n mode: 'recording',\n recorderMode: 'api',\n }, {\n actionAdded: (page: playwright.Page, data: actions.ActionInContext, code: string) => {\n if (this._context.isRunningTool())\n return;\n const tab = Tab.forPage(page);\n if (tab)\n sessionLog.logUserAction(data.action, tab, code, false);\n },\n actionUpdated: (page: playwright.Page, data: actions.ActionInContext, code: string) => {\n if (this._context.isRunningTool())\n return;\n const tab = Tab.forPage(page);\n if (tab)\n sessionLog.logUserAction(data.action, tab, code, true);\n },\n signalAdded: (page: playwright.Page, data: actions.SignalInContext) => {\n if (this._context.isRunningTool())\n return;\n if (data.signal.name !== 'navigation')\n return;\n const tab = Tab.forPage(page);\n const navigateAction: actions.Action = {\n name: 'navigate',\n url: data.signal.url,\n signals: [],\n };\n if (tab)\n sessionLog.logUserAction(navigateAction, tab, `await page.goto('${data.signal.url}');`, false);\n },\n });\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["tab", "fs", "path", "e"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var response_exports = {};
|
|
20
|
+
__export(response_exports, {
|
|
21
|
+
Response: () => Response,
|
|
22
|
+
parseResponse: () => parseResponse,
|
|
23
|
+
requestDebug: () => requestDebug
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(response_exports);
|
|
26
|
+
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
|
|
27
|
+
var import_tab = require("./tab");
|
|
28
|
+
const requestDebug = (0, import_utilsBundle.debug)("pw:mcp:request");
|
|
29
|
+
class Response {
|
|
30
|
+
constructor(context, toolName, toolArgs) {
|
|
31
|
+
this._result = [];
|
|
32
|
+
this._code = [];
|
|
33
|
+
this._images = [];
|
|
34
|
+
this._includeSnapshot = "none";
|
|
35
|
+
this._includeTabs = false;
|
|
36
|
+
this._context = context;
|
|
37
|
+
this.toolName = toolName;
|
|
38
|
+
this.toolArgs = toolArgs;
|
|
39
|
+
}
|
|
40
|
+
addResult(result) {
|
|
41
|
+
this._result.push(result);
|
|
42
|
+
}
|
|
43
|
+
addError(error) {
|
|
44
|
+
this._result.push(error);
|
|
45
|
+
this._isError = true;
|
|
46
|
+
}
|
|
47
|
+
isError() {
|
|
48
|
+
return this._isError;
|
|
49
|
+
}
|
|
50
|
+
result() {
|
|
51
|
+
return this._result.join("\n");
|
|
52
|
+
}
|
|
53
|
+
addCode(code) {
|
|
54
|
+
this._code.push(code);
|
|
55
|
+
}
|
|
56
|
+
code() {
|
|
57
|
+
return this._code.join("\n");
|
|
58
|
+
}
|
|
59
|
+
addImage(image) {
|
|
60
|
+
this._images.push(image);
|
|
61
|
+
}
|
|
62
|
+
images() {
|
|
63
|
+
return this._images;
|
|
64
|
+
}
|
|
65
|
+
setIncludeSnapshot(full) {
|
|
66
|
+
this._includeSnapshot = full ?? "incremental";
|
|
67
|
+
}
|
|
68
|
+
setIncludeTabs() {
|
|
69
|
+
this._includeTabs = true;
|
|
70
|
+
}
|
|
71
|
+
async finish() {
|
|
72
|
+
if (this._includeSnapshot !== "none" && this._context.currentTab())
|
|
73
|
+
this._tabSnapshot = await this._context.currentTabOrDie().captureSnapshot(this._includeSnapshot);
|
|
74
|
+
for (const tab of this._context.tabs())
|
|
75
|
+
await tab.updateTitle();
|
|
76
|
+
}
|
|
77
|
+
tabSnapshot() {
|
|
78
|
+
return this._tabSnapshot;
|
|
79
|
+
}
|
|
80
|
+
logBegin() {
|
|
81
|
+
if (requestDebug.enabled)
|
|
82
|
+
requestDebug(this.toolName, this.toolArgs);
|
|
83
|
+
}
|
|
84
|
+
logEnd() {
|
|
85
|
+
if (requestDebug.enabled)
|
|
86
|
+
requestDebug(this.serialize({ omitSnapshot: true, omitBlobs: true }));
|
|
87
|
+
}
|
|
88
|
+
serialize(options = {}) {
|
|
89
|
+
const response = [];
|
|
90
|
+
if (this._result.length) {
|
|
91
|
+
response.push("### Result");
|
|
92
|
+
response.push(this._result.join("\n"));
|
|
93
|
+
response.push("");
|
|
94
|
+
}
|
|
95
|
+
if (this._code.length) {
|
|
96
|
+
response.push(`### Ran Playwright code
|
|
97
|
+
\`\`\`js
|
|
98
|
+
${this._code.join("\n")}
|
|
99
|
+
\`\`\``);
|
|
100
|
+
response.push("");
|
|
101
|
+
}
|
|
102
|
+
if (this._includeSnapshot !== "none" || this._includeTabs)
|
|
103
|
+
response.push(...renderTabsMarkdown(this._context.tabs(), this._includeTabs));
|
|
104
|
+
if (this._tabSnapshot?.modalStates.length) {
|
|
105
|
+
response.push(...(0, import_tab.renderModalStates)(this._context, this._tabSnapshot.modalStates));
|
|
106
|
+
response.push("");
|
|
107
|
+
} else if (this._tabSnapshot) {
|
|
108
|
+
response.push(renderTabSnapshot(this._tabSnapshot, options));
|
|
109
|
+
response.push("");
|
|
110
|
+
}
|
|
111
|
+
const content = [
|
|
112
|
+
{ type: "text", text: response.join("\n") }
|
|
113
|
+
];
|
|
114
|
+
if (this._context.config.imageResponses !== "omit") {
|
|
115
|
+
for (const image of this._images)
|
|
116
|
+
content.push({ type: "image", data: options.omitBlobs ? "<blob>" : image.data.toString("base64"), mimeType: image.contentType });
|
|
117
|
+
}
|
|
118
|
+
this._redactSecrets(content);
|
|
119
|
+
return { content, isError: this._isError };
|
|
120
|
+
}
|
|
121
|
+
_redactSecrets(content) {
|
|
122
|
+
if (!this._context.config.secrets)
|
|
123
|
+
return;
|
|
124
|
+
for (const item of content) {
|
|
125
|
+
if (item.type !== "text")
|
|
126
|
+
continue;
|
|
127
|
+
for (const [secretName, secretValue] of Object.entries(this._context.config.secrets))
|
|
128
|
+
item.text = item.text.replaceAll(secretValue, `<secret>${secretName}</secret>`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function renderTabSnapshot(tabSnapshot, options = {}) {
|
|
133
|
+
const lines = [];
|
|
134
|
+
if (tabSnapshot.consoleMessages.length) {
|
|
135
|
+
lines.push(`### New console messages`);
|
|
136
|
+
for (const message of tabSnapshot.consoleMessages)
|
|
137
|
+
lines.push(`- ${trim(message.toString(), 100)}`);
|
|
138
|
+
lines.push("");
|
|
139
|
+
}
|
|
140
|
+
if (tabSnapshot.downloads.length) {
|
|
141
|
+
lines.push(`### Downloads`);
|
|
142
|
+
for (const entry of tabSnapshot.downloads) {
|
|
143
|
+
if (entry.finished)
|
|
144
|
+
lines.push(`- Downloaded file ${entry.download.suggestedFilename()} to ${entry.outputFile}`);
|
|
145
|
+
else
|
|
146
|
+
lines.push(`- Downloading file ${entry.download.suggestedFilename()} ...`);
|
|
147
|
+
}
|
|
148
|
+
lines.push("");
|
|
149
|
+
}
|
|
150
|
+
lines.push(`### Page state`);
|
|
151
|
+
lines.push(`- Page URL: ${tabSnapshot.url}`);
|
|
152
|
+
lines.push(`- Page Title: ${tabSnapshot.title}`);
|
|
153
|
+
lines.push(`- Page Snapshot:`);
|
|
154
|
+
lines.push("```yaml");
|
|
155
|
+
lines.push(options.omitSnapshot ? "<snapshot>" : tabSnapshot.ariaSnapshot || "<no changes>");
|
|
156
|
+
lines.push("```");
|
|
157
|
+
return lines.join("\n");
|
|
158
|
+
}
|
|
159
|
+
function renderTabsMarkdown(tabs, force = false) {
|
|
160
|
+
if (tabs.length === 1 && !force)
|
|
161
|
+
return [];
|
|
162
|
+
if (!tabs.length) {
|
|
163
|
+
return [
|
|
164
|
+
"### Open tabs",
|
|
165
|
+
'No open tabs. Use the "browser_navigate" tool to navigate to a page first.',
|
|
166
|
+
""
|
|
167
|
+
];
|
|
168
|
+
}
|
|
169
|
+
const lines = ["### Open tabs"];
|
|
170
|
+
for (let i = 0; i < tabs.length; i++) {
|
|
171
|
+
const tab = tabs[i];
|
|
172
|
+
const current = tab.isCurrentTab() ? " (current)" : "";
|
|
173
|
+
lines.push(`- ${i}:${current} [${tab.lastTitle()}] (${tab.page.url()})`);
|
|
174
|
+
}
|
|
175
|
+
lines.push("");
|
|
176
|
+
return lines;
|
|
177
|
+
}
|
|
178
|
+
function trim(text, maxLength) {
|
|
179
|
+
if (text.length <= maxLength)
|
|
180
|
+
return text;
|
|
181
|
+
return text.slice(0, maxLength) + "...";
|
|
182
|
+
}
|
|
183
|
+
function parseSections(text) {
|
|
184
|
+
const sections = /* @__PURE__ */ new Map();
|
|
185
|
+
const sectionHeaders = text.split(/^### /m).slice(1);
|
|
186
|
+
for (const section of sectionHeaders) {
|
|
187
|
+
const firstNewlineIndex = section.indexOf("\n");
|
|
188
|
+
if (firstNewlineIndex === -1)
|
|
189
|
+
continue;
|
|
190
|
+
const sectionName = section.substring(0, firstNewlineIndex);
|
|
191
|
+
const sectionContent = section.substring(firstNewlineIndex + 1).trim();
|
|
192
|
+
sections.set(sectionName, sectionContent);
|
|
193
|
+
}
|
|
194
|
+
return sections;
|
|
195
|
+
}
|
|
196
|
+
function parseResponse(response) {
|
|
197
|
+
if (response.content?.[0].type !== "text")
|
|
198
|
+
return void 0;
|
|
199
|
+
const text = response.content[0].text;
|
|
200
|
+
const sections = parseSections(text);
|
|
201
|
+
const result = sections.get("Result");
|
|
202
|
+
const code = sections.get("Ran Playwright code");
|
|
203
|
+
const tabs = sections.get("Open tabs");
|
|
204
|
+
const pageState = sections.get("Page state");
|
|
205
|
+
const consoleMessages = sections.get("New console messages");
|
|
206
|
+
const modalState = sections.get("Modal state");
|
|
207
|
+
const downloads = sections.get("Downloads");
|
|
208
|
+
const codeNoFrame = code?.replace(/^```js\n/, "").replace(/\n```$/, "");
|
|
209
|
+
const isError = response.isError;
|
|
210
|
+
const attachments = response.content.slice(1);
|
|
211
|
+
return {
|
|
212
|
+
result,
|
|
213
|
+
code: codeNoFrame,
|
|
214
|
+
tabs,
|
|
215
|
+
pageState,
|
|
216
|
+
consoleMessages,
|
|
217
|
+
modalState,
|
|
218
|
+
downloads,
|
|
219
|
+
isError,
|
|
220
|
+
attachments
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
224
|
+
0 && (module.exports = {
|
|
225
|
+
Response,
|
|
226
|
+
parseResponse,
|
|
227
|
+
requestDebug
|
|
228
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/mcp/browser/response.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright (c) Microsoft Corporation.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { debug } from 'playwright-core/lib/utilsBundle';\nimport { renderModalStates } from './tab';\n\nimport type { Tab, TabSnapshot } from './tab';\nimport type { CallToolResult, ImageContent, TextContent } from '@modelcontextprotocol/sdk/types.js';\nimport type { Context } from './context';\n\nexport const requestDebug = debug('pw:mcp:request');\n\nexport class Response {\n private _result: string[] = [];\n private _code: string[] = [];\n private _images: { contentType: string, data: Buffer }[] = [];\n private _context: Context;\n private _includeSnapshot: 'none' | 'full' | 'incremental' = 'none';\n private _includeTabs = false;\n private _tabSnapshot: TabSnapshot | undefined;\n\n readonly toolName: string;\n readonly toolArgs: Record<string, any>;\n private _isError: boolean | undefined;\n\n constructor(context: Context, toolName: string, toolArgs: Record<string, any>) {\n this._context = context;\n this.toolName = toolName;\n this.toolArgs = toolArgs;\n }\n\n addResult(result: string) {\n this._result.push(result);\n }\n\n addError(error: string) {\n this._result.push(error);\n this._isError = true;\n }\n\n isError() {\n return this._isError;\n }\n\n result() {\n return this._result.join('\\n');\n }\n\n addCode(code: string) {\n this._code.push(code);\n }\n\n code() {\n return this._code.join('\\n');\n }\n\n addImage(image: { contentType: string, data: Buffer }) {\n this._images.push(image);\n }\n\n images() {\n return this._images;\n }\n\n setIncludeSnapshot(full?: 'full') {\n this._includeSnapshot = full ?? 'incremental';\n }\n\n setIncludeTabs() {\n this._includeTabs = true;\n }\n\n async finish() {\n // All the async snapshotting post-action is happening here.\n // Everything below should race against modal states.\n if (this._includeSnapshot !== 'none' && this._context.currentTab())\n this._tabSnapshot = await this._context.currentTabOrDie().captureSnapshot(this._includeSnapshot);\n for (const tab of this._context.tabs())\n await tab.updateTitle();\n }\n\n tabSnapshot(): TabSnapshot | undefined {\n return this._tabSnapshot;\n }\n\n logBegin() {\n if (requestDebug.enabled)\n requestDebug(this.toolName, this.toolArgs);\n }\n\n logEnd() {\n if (requestDebug.enabled)\n requestDebug(this.serialize({ omitSnapshot: true, omitBlobs: true }));\n }\n\n serialize(options: { omitSnapshot?: boolean, omitBlobs?: boolean } = {}): { content: (TextContent | ImageContent)[], isError?: boolean } {\n const response: string[] = [];\n\n // Start with command result.\n if (this._result.length) {\n response.push('### Result');\n response.push(this._result.join('\\n'));\n response.push('');\n }\n\n // Add code if it exists.\n if (this._code.length) {\n response.push(`### Ran Playwright code\n\\`\\`\\`js\n${this._code.join('\\n')}\n\\`\\`\\``);\n response.push('');\n }\n\n // List browser tabs.\n if (this._includeSnapshot !== 'none' || this._includeTabs)\n response.push(...renderTabsMarkdown(this._context.tabs(), this._includeTabs));\n\n // Add snapshot if provided.\n if (this._tabSnapshot?.modalStates.length) {\n response.push(...renderModalStates(this._context, this._tabSnapshot.modalStates));\n response.push('');\n } else if (this._tabSnapshot) {\n response.push(renderTabSnapshot(this._tabSnapshot, options));\n response.push('');\n }\n\n // Main response part\n const content: (TextContent | ImageContent)[] = [\n { type: 'text', text: response.join('\\n') },\n ];\n\n // Image attachments.\n if (this._context.config.imageResponses !== 'omit') {\n for (const image of this._images)\n content.push({ type: 'image', data: options.omitBlobs ? '<blob>' : image.data.toString('base64'), mimeType: image.contentType });\n }\n\n this._redactSecrets(content);\n return { content, isError: this._isError };\n }\n\n private _redactSecrets(content: (TextContent | ImageContent)[]) {\n if (!this._context.config.secrets)\n return;\n\n for (const item of content) {\n if (item.type !== 'text')\n continue;\n for (const [secretName, secretValue] of Object.entries(this._context.config.secrets))\n item.text = item.text.replaceAll(secretValue, `<secret>${secretName}</secret>`);\n }\n }\n}\n\nfunction renderTabSnapshot(tabSnapshot: TabSnapshot, options: { omitSnapshot?: boolean } = {}): string {\n const lines: string[] = [];\n\n if (tabSnapshot.consoleMessages.length) {\n lines.push(`### New console messages`);\n for (const message of tabSnapshot.consoleMessages)\n lines.push(`- ${trim(message.toString(), 100)}`);\n lines.push('');\n }\n\n if (tabSnapshot.downloads.length) {\n lines.push(`### Downloads`);\n for (const entry of tabSnapshot.downloads) {\n if (entry.finished)\n lines.push(`- Downloaded file ${entry.download.suggestedFilename()} to ${entry.outputFile}`);\n else\n lines.push(`- Downloading file ${entry.download.suggestedFilename()} ...`);\n }\n lines.push('');\n }\n\n lines.push(`### Page state`);\n lines.push(`- Page URL: ${tabSnapshot.url}`);\n lines.push(`- Page Title: ${tabSnapshot.title}`);\n lines.push(`- Page Snapshot:`);\n lines.push('```yaml');\n // TODO: perhaps not render page state when there are no changes?\n lines.push(options.omitSnapshot ? '<snapshot>' : (tabSnapshot.ariaSnapshot || '<no changes>'));\n lines.push('```');\n\n return lines.join('\\n');\n}\n\nfunction renderTabsMarkdown(tabs: Tab[], force: boolean = false): string[] {\n if (tabs.length === 1 && !force)\n return [];\n\n if (!tabs.length) {\n return [\n '### Open tabs',\n 'No open tabs. Use the \"browser_navigate\" tool to navigate to a page first.',\n '',\n ];\n }\n\n const lines: string[] = ['### Open tabs'];\n for (let i = 0; i < tabs.length; i++) {\n const tab = tabs[i];\n const current = tab.isCurrentTab() ? ' (current)' : '';\n lines.push(`- ${i}:${current} [${tab.lastTitle()}] (${tab.page.url()})`);\n }\n lines.push('');\n return lines;\n}\n\nfunction trim(text: string, maxLength: number) {\n if (text.length <= maxLength)\n return text;\n return text.slice(0, maxLength) + '...';\n}\n\nfunction parseSections(text: string): Map<string, string> {\n const sections = new Map<string, string>();\n const sectionHeaders = text.split(/^### /m).slice(1); // Remove empty first element\n\n for (const section of sectionHeaders) {\n const firstNewlineIndex = section.indexOf('\\n');\n if (firstNewlineIndex === -1)\n continue;\n\n const sectionName = section.substring(0, firstNewlineIndex);\n const sectionContent = section.substring(firstNewlineIndex + 1).trim();\n sections.set(sectionName, sectionContent);\n }\n\n return sections;\n}\n\nexport function parseResponse(response: CallToolResult) {\n if (response.content?.[0].type !== 'text')\n return undefined;\n const text = response.content[0].text;\n\n const sections = parseSections(text);\n const result = sections.get('Result');\n const code = sections.get('Ran Playwright code');\n const tabs = sections.get('Open tabs');\n const pageState = sections.get('Page state');\n const consoleMessages = sections.get('New console messages');\n const modalState = sections.get('Modal state');\n const downloads = sections.get('Downloads');\n const codeNoFrame = code?.replace(/^```js\\n/, '').replace(/\\n```$/, '');\n const isError = response.isError;\n const attachments = response.content.slice(1);\n\n return {\n result,\n code: codeNoFrame,\n tabs,\n pageState,\n consoleMessages,\n modalState,\n downloads,\n isError,\n attachments,\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|