@stablyai/internal-playwright 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (297) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +5 -0
  3. package/README.md +168 -0
  4. package/ThirdPartyNotices.txt +6277 -0
  5. package/cli.js +19 -0
  6. package/index.d.ts +17 -0
  7. package/index.js +17 -0
  8. package/index.mjs +18 -0
  9. package/jsx-runtime.js +42 -0
  10. package/jsx-runtime.mjs +21 -0
  11. package/lib/agents/generateAgents.js +265 -0
  12. package/lib/agents/generator.md +102 -0
  13. package/lib/agents/healer.md +78 -0
  14. package/lib/agents/planner.md +135 -0
  15. package/lib/cli.js +274 -0
  16. package/lib/common/config.js +274 -0
  17. package/lib/common/config.js.map +7 -0
  18. package/lib/common/configLoader.js +377 -0
  19. package/lib/common/configLoader.js.map +7 -0
  20. package/lib/common/esmLoaderHost.js +102 -0
  21. package/lib/common/esmLoaderHost.js.map +7 -0
  22. package/lib/common/expectBundle.js +52 -0
  23. package/lib/common/expectBundle.js.map +7 -0
  24. package/lib/common/expectBundleImpl.js +389 -0
  25. package/lib/common/expectBundleImpl.js.map +7 -0
  26. package/lib/common/fixtures.js +302 -0
  27. package/lib/common/fixtures.js.map +7 -0
  28. package/lib/common/globals.js +58 -0
  29. package/lib/common/globals.js.map +7 -0
  30. package/lib/common/ipc.js +60 -0
  31. package/lib/common/ipc.js.map +7 -0
  32. package/lib/common/poolBuilder.js +85 -0
  33. package/lib/common/poolBuilder.js.map +7 -0
  34. package/lib/common/process.js +104 -0
  35. package/lib/common/process.js.map +7 -0
  36. package/lib/common/suiteUtils.js +140 -0
  37. package/lib/common/suiteUtils.js.map +7 -0
  38. package/lib/common/test.js +321 -0
  39. package/lib/common/test.js.map +7 -0
  40. package/lib/common/testLoader.js +100 -0
  41. package/lib/common/testLoader.js.map +7 -0
  42. package/lib/common/testType.js +310 -0
  43. package/lib/common/testType.js.map +7 -0
  44. package/lib/fsWatcher.js +67 -0
  45. package/lib/fsWatcher.js.map +7 -0
  46. package/lib/index.js +696 -0
  47. package/lib/index.js.map +7 -0
  48. package/lib/internalsForTest.js +42 -0
  49. package/lib/internalsForTest.js.map +7 -0
  50. package/lib/isomorphic/events.js +77 -0
  51. package/lib/isomorphic/events.js.map +7 -0
  52. package/lib/isomorphic/folders.js +30 -0
  53. package/lib/isomorphic/folders.js.map +7 -0
  54. package/lib/isomorphic/stringInternPool.js +69 -0
  55. package/lib/isomorphic/stringInternPool.js.map +7 -0
  56. package/lib/isomorphic/teleReceiver.js +507 -0
  57. package/lib/isomorphic/teleReceiver.js.map +7 -0
  58. package/lib/isomorphic/teleSuiteUpdater.js +137 -0
  59. package/lib/isomorphic/teleSuiteUpdater.js.map +7 -0
  60. package/lib/isomorphic/testServerConnection.js +211 -0
  61. package/lib/isomorphic/testServerConnection.js.map +7 -0
  62. package/lib/isomorphic/testServerInterface.js +16 -0
  63. package/lib/isomorphic/testServerInterface.js.map +7 -0
  64. package/lib/isomorphic/testTree.js +334 -0
  65. package/lib/isomorphic/testTree.js.map +7 -0
  66. package/lib/isomorphic/types.d.js +16 -0
  67. package/lib/isomorphic/types.d.js.map +7 -0
  68. package/lib/loader/loaderMain.js +59 -0
  69. package/lib/loader/loaderMain.js.map +7 -0
  70. package/lib/matchers/expect.js +325 -0
  71. package/lib/matchers/expect.js.map +7 -0
  72. package/lib/matchers/matcherHint.js +87 -0
  73. package/lib/matchers/matcherHint.js.map +7 -0
  74. package/lib/matchers/matchers.js +366 -0
  75. package/lib/matchers/matchers.js.map +7 -0
  76. package/lib/matchers/toBeTruthy.js +73 -0
  77. package/lib/matchers/toBeTruthy.js.map +7 -0
  78. package/lib/matchers/toEqual.js +99 -0
  79. package/lib/matchers/toEqual.js.map +7 -0
  80. package/lib/matchers/toHaveURL.js +102 -0
  81. package/lib/matchers/toHaveURL.js.map +7 -0
  82. package/lib/matchers/toMatchAriaSnapshot.js +159 -0
  83. package/lib/matchers/toMatchAriaSnapshot.js.map +7 -0
  84. package/lib/matchers/toMatchSnapshot.js +359 -0
  85. package/lib/matchers/toMatchSnapshot.js.map +7 -0
  86. package/lib/matchers/toMatchText.js +99 -0
  87. package/lib/matchers/toMatchText.js.map +7 -0
  88. package/lib/mcp/browser/actions.d.js +16 -0
  89. package/lib/mcp/browser/backend.js +93 -0
  90. package/lib/mcp/browser/backend.js.map +7 -0
  91. package/lib/mcp/browser/browserContextFactory.js +296 -0
  92. package/lib/mcp/browser/browserServerBackend.js +76 -0
  93. package/lib/mcp/browser/codegen.js +66 -0
  94. package/lib/mcp/browser/config.js +385 -0
  95. package/lib/mcp/browser/context.js +287 -0
  96. package/lib/mcp/browser/response.js +228 -0
  97. package/lib/mcp/browser/sessionLog.js +160 -0
  98. package/lib/mcp/browser/tab.js +277 -0
  99. package/lib/mcp/browser/tool.js +30 -0
  100. package/lib/mcp/browser/tool.js.map +7 -0
  101. package/lib/mcp/browser/tools/common.js +63 -0
  102. package/lib/mcp/browser/tools/console.js +44 -0
  103. package/lib/mcp/browser/tools/dialogs.js +60 -0
  104. package/lib/mcp/browser/tools/evaluate.js +70 -0
  105. package/lib/mcp/browser/tools/files.js +58 -0
  106. package/lib/mcp/browser/tools/form.js +74 -0
  107. package/lib/mcp/browser/tools/install.js +69 -0
  108. package/lib/mcp/browser/tools/keyboard.js +85 -0
  109. package/lib/mcp/browser/tools/mouse.js +107 -0
  110. package/lib/mcp/browser/tools/navigate.js +62 -0
  111. package/lib/mcp/browser/tools/network.js +54 -0
  112. package/lib/mcp/browser/tools/pdf.js +59 -0
  113. package/lib/mcp/browser/tools/screenshot.js +88 -0
  114. package/lib/mcp/browser/tools/snapshot.js +182 -0
  115. package/lib/mcp/browser/tools/tabs.js +67 -0
  116. package/lib/mcp/browser/tools/tool.js +49 -0
  117. package/lib/mcp/browser/tools/tracing.js +74 -0
  118. package/lib/mcp/browser/tools/utils.js +100 -0
  119. package/lib/mcp/browser/tools/verify.js +154 -0
  120. package/lib/mcp/browser/tools/wait.js +63 -0
  121. package/lib/mcp/browser/tools.js +80 -0
  122. package/lib/mcp/browser/tools.js.map +7 -0
  123. package/lib/mcp/browser/watchdog.js +44 -0
  124. package/lib/mcp/config.d.js +16 -0
  125. package/lib/mcp/extension/cdpRelay.js +351 -0
  126. package/lib/mcp/extension/extensionContextFactory.js +75 -0
  127. package/lib/mcp/extension/protocol.js +28 -0
  128. package/lib/mcp/index.js +61 -0
  129. package/lib/mcp/log.js +35 -0
  130. package/lib/mcp/program.js +96 -0
  131. package/lib/mcp/sdk/bundle.js +81 -0
  132. package/lib/mcp/sdk/bundle.js.map +7 -0
  133. package/lib/mcp/sdk/call.js +49 -0
  134. package/lib/mcp/sdk/call.js.map +7 -0
  135. package/lib/mcp/sdk/exports.js +32 -0
  136. package/lib/mcp/sdk/exports.js.map +7 -0
  137. package/lib/mcp/sdk/http.js +187 -0
  138. package/lib/mcp/sdk/http.js.map +7 -0
  139. package/lib/mcp/sdk/inProcessTransport.js +71 -0
  140. package/lib/mcp/sdk/inProcessTransport.js.map +7 -0
  141. package/lib/mcp/sdk/mdb.js +206 -0
  142. package/lib/mcp/sdk/mdb.js.map +7 -0
  143. package/lib/mcp/sdk/proxyBackend.js +128 -0
  144. package/lib/mcp/sdk/proxyBackend.js.map +7 -0
  145. package/lib/mcp/sdk/server.js +189 -0
  146. package/lib/mcp/sdk/server.js.map +7 -0
  147. package/lib/mcp/sdk/tool.js +51 -0
  148. package/lib/mcp/sdk/tool.js.map +7 -0
  149. package/lib/mcp/test/backend.js +67 -0
  150. package/lib/mcp/test/backend.js.map +7 -0
  151. package/lib/mcp/test/browserBackend.js +98 -0
  152. package/lib/mcp/test/context.js +48 -0
  153. package/lib/mcp/test/context.js.map +7 -0
  154. package/lib/mcp/test/generatorTools.js +122 -0
  155. package/lib/mcp/test/plannerTools.js +46 -0
  156. package/lib/mcp/test/seed.js +72 -0
  157. package/lib/mcp/test/streams.js +39 -0
  158. package/lib/mcp/test/streams.js.map +7 -0
  159. package/lib/mcp/test/testBackend.js +97 -0
  160. package/lib/mcp/test/testContext.js +176 -0
  161. package/lib/mcp/test/testTool.js +30 -0
  162. package/lib/mcp/test/testTools.js +115 -0
  163. package/lib/mcp/test/tool.js +30 -0
  164. package/lib/mcp/test/tool.js.map +7 -0
  165. package/lib/mcp/test/tools.js +150 -0
  166. package/lib/mcp/test/tools.js.map +7 -0
  167. package/lib/mcp/vscode/host.js +187 -0
  168. package/lib/mcp/vscode/main.js +77 -0
  169. package/lib/mcpBundleImpl.js +41 -0
  170. package/lib/mcpBundleImpl.js.map +7 -0
  171. package/lib/plugins/gitCommitInfoPlugin.js +198 -0
  172. package/lib/plugins/gitCommitInfoPlugin.js.map +7 -0
  173. package/lib/plugins/index.js +28 -0
  174. package/lib/plugins/index.js.map +7 -0
  175. package/lib/plugins/webServerPlugin.js +209 -0
  176. package/lib/plugins/webServerPlugin.js.map +7 -0
  177. package/lib/program.js +412 -0
  178. package/lib/program.js.map +7 -0
  179. package/lib/reporters/base.js +609 -0
  180. package/lib/reporters/base.js.map +7 -0
  181. package/lib/reporters/blob.js +135 -0
  182. package/lib/reporters/blob.js.map +7 -0
  183. package/lib/reporters/dot.js +82 -0
  184. package/lib/reporters/dot.js.map +7 -0
  185. package/lib/reporters/empty.js +32 -0
  186. package/lib/reporters/empty.js.map +7 -0
  187. package/lib/reporters/github.js +128 -0
  188. package/lib/reporters/github.js.map +7 -0
  189. package/lib/reporters/html.js +644 -0
  190. package/lib/reporters/html.js.map +7 -0
  191. package/lib/reporters/internalReporter.js +130 -0
  192. package/lib/reporters/internalReporter.js.map +7 -0
  193. package/lib/reporters/json.js +254 -0
  194. package/lib/reporters/json.js.map +7 -0
  195. package/lib/reporters/junit.js +230 -0
  196. package/lib/reporters/junit.js.map +7 -0
  197. package/lib/reporters/line.js +113 -0
  198. package/lib/reporters/line.js.map +7 -0
  199. package/lib/reporters/list.js +235 -0
  200. package/lib/reporters/list.js.map +7 -0
  201. package/lib/reporters/listModeReporter.js +69 -0
  202. package/lib/reporters/listModeReporter.js.map +7 -0
  203. package/lib/reporters/markdown.js +144 -0
  204. package/lib/reporters/markdown.js.map +7 -0
  205. package/lib/reporters/merge.js +535 -0
  206. package/lib/reporters/merge.js.map +7 -0
  207. package/lib/reporters/multiplexer.js +104 -0
  208. package/lib/reporters/multiplexer.js.map +7 -0
  209. package/lib/reporters/reporterV2.js +102 -0
  210. package/lib/reporters/reporterV2.js.map +7 -0
  211. package/lib/reporters/teleEmitter.js +297 -0
  212. package/lib/reporters/teleEmitter.js.map +7 -0
  213. package/lib/reporters/versions/blobV1.js +16 -0
  214. package/lib/reporters/versions/blobV1.js.map +7 -0
  215. package/lib/runner/dispatcher.js +491 -0
  216. package/lib/runner/dispatcher.js.map +7 -0
  217. package/lib/runner/failureTracker.js +72 -0
  218. package/lib/runner/failureTracker.js.map +7 -0
  219. package/lib/runner/lastRun.js +77 -0
  220. package/lib/runner/lastRun.js.map +7 -0
  221. package/lib/runner/loadUtils.js +333 -0
  222. package/lib/runner/loadUtils.js.map +7 -0
  223. package/lib/runner/loaderHost.js +89 -0
  224. package/lib/runner/loaderHost.js.map +7 -0
  225. package/lib/runner/processHost.js +161 -0
  226. package/lib/runner/processHost.js.map +7 -0
  227. package/lib/runner/projectUtils.js +241 -0
  228. package/lib/runner/projectUtils.js.map +7 -0
  229. package/lib/runner/rebase.js +189 -0
  230. package/lib/runner/rebase.js.map +7 -0
  231. package/lib/runner/reporters.js +137 -0
  232. package/lib/runner/reporters.js.map +7 -0
  233. package/lib/runner/runner.js +173 -0
  234. package/lib/runner/sigIntWatcher.js +96 -0
  235. package/lib/runner/sigIntWatcher.js.map +7 -0
  236. package/lib/runner/taskRunner.js +127 -0
  237. package/lib/runner/taskRunner.js.map +7 -0
  238. package/lib/runner/tasks.js +410 -0
  239. package/lib/runner/tasks.js.map +7 -0
  240. package/lib/runner/testGroups.js +117 -0
  241. package/lib/runner/testGroups.js.map +7 -0
  242. package/lib/runner/testRunner.js +390 -0
  243. package/lib/runner/testRunner.js.map +7 -0
  244. package/lib/runner/testServer.js +264 -0
  245. package/lib/runner/testServer.js.map +7 -0
  246. package/lib/runner/uiMode.js +271 -0
  247. package/lib/runner/uiModeReporter.js +30 -0
  248. package/lib/runner/uiModeReporter.js.map +7 -0
  249. package/lib/runner/vcs.js +72 -0
  250. package/lib/runner/vcs.js.map +7 -0
  251. package/lib/runner/watchMode.js +395 -0
  252. package/lib/runner/watchMode.js.map +7 -0
  253. package/lib/runner/workerHost.js +95 -0
  254. package/lib/runner/workerHost.js.map +7 -0
  255. package/lib/store.js +98 -0
  256. package/lib/third_party/pirates.js +62 -0
  257. package/lib/third_party/pirates.js.map +7 -0
  258. package/lib/third_party/tsconfig-loader.js +103 -0
  259. package/lib/third_party/tsconfig-loader.js.map +7 -0
  260. package/lib/transform/babelBundle.js +43 -0
  261. package/lib/transform/babelBundle.js.map +7 -0
  262. package/lib/transform/babelBundleImpl.js +461 -0
  263. package/lib/transform/babelBundleImpl.js.map +7 -0
  264. package/lib/transform/compilationCache.js +272 -0
  265. package/lib/transform/compilationCache.js.map +7 -0
  266. package/lib/transform/esmLoader.js +104 -0
  267. package/lib/transform/esmLoader.js.map +7 -0
  268. package/lib/transform/esmUtils.js +32 -0
  269. package/lib/transform/portTransport.js +67 -0
  270. package/lib/transform/portTransport.js.map +7 -0
  271. package/lib/transform/transform.js +293 -0
  272. package/lib/transform/transform.js.map +7 -0
  273. package/lib/util.js +403 -0
  274. package/lib/util.js.map +7 -0
  275. package/lib/utilsBundle.js +43 -0
  276. package/lib/utilsBundle.js.map +7 -0
  277. package/lib/utilsBundleImpl.js +100 -0
  278. package/lib/utilsBundleImpl.js.map +7 -0
  279. package/lib/worker/fixtureRunner.js +258 -0
  280. package/lib/worker/fixtureRunner.js.map +7 -0
  281. package/lib/worker/stepContext.js +34 -0
  282. package/lib/worker/testInfo.js +508 -0
  283. package/lib/worker/testInfo.js.map +7 -0
  284. package/lib/worker/testTracing.js +344 -0
  285. package/lib/worker/testTracing.js.map +7 -0
  286. package/lib/worker/timeoutManager.js +174 -0
  287. package/lib/worker/timeoutManager.js.map +7 -0
  288. package/lib/worker/util.js +31 -0
  289. package/lib/worker/util.js.map +7 -0
  290. package/lib/worker/workerMain.js +520 -0
  291. package/lib/worker/workerMain.js.map +7 -0
  292. package/package.json +74 -0
  293. package/test.d.ts +18 -0
  294. package/test.js +24 -0
  295. package/test.mjs +33 -0
  296. package/types/test.d.ts +10217 -0
  297. package/types/testReporter.d.ts +816 -0
@@ -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 = false;
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() {
66
+ this._includeSnapshot = true;
67
+ }
68
+ setIncludeTabs() {
69
+ this._includeTabs = true;
70
+ }
71
+ async finish() {
72
+ if (this._includeSnapshot && this._context.currentTab())
73
+ this._tabSnapshot = await this._context.currentTabOrDie().captureSnapshot();
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 || 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);
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,160 @@
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 sessionLog_exports = {};
30
+ __export(sessionLog_exports, {
31
+ SessionLog: () => SessionLog
32
+ });
33
+ module.exports = __toCommonJS(sessionLog_exports);
34
+ var import_fs = __toESM(require("fs"));
35
+ var import_path = __toESM(require("path"));
36
+ var import_log = require("../log");
37
+ var import_config = require("./config");
38
+ class SessionLog {
39
+ constructor(sessionFolder) {
40
+ this._ordinal = 0;
41
+ this._pendingEntries = [];
42
+ this._sessionFileQueue = Promise.resolve();
43
+ this._folder = sessionFolder;
44
+ this._file = import_path.default.join(this._folder, "session.md");
45
+ }
46
+ static async create(config, clientInfo) {
47
+ const sessionFolder = await (0, import_config.outputFile)(config, clientInfo, `session-${Date.now()}`, { origin: "code", reason: "Saving session" });
48
+ await import_fs.default.promises.mkdir(sessionFolder, { recursive: true });
49
+ console.error(`Session: ${sessionFolder}`);
50
+ return new SessionLog(sessionFolder);
51
+ }
52
+ logResponse(response) {
53
+ const entry = {
54
+ timestamp: performance.now(),
55
+ toolCall: {
56
+ toolName: response.toolName,
57
+ toolArgs: response.toolArgs,
58
+ result: response.result(),
59
+ isError: response.isError()
60
+ },
61
+ code: response.code(),
62
+ tabSnapshot: response.tabSnapshot()
63
+ };
64
+ this._appendEntry(entry);
65
+ }
66
+ logUserAction(action, tab, code, isUpdate) {
67
+ code = code.trim();
68
+ if (isUpdate) {
69
+ const lastEntry = this._pendingEntries[this._pendingEntries.length - 1];
70
+ if (lastEntry?.userAction?.name === action.name) {
71
+ lastEntry.userAction = action;
72
+ lastEntry.code = code;
73
+ return;
74
+ }
75
+ }
76
+ if (action.name === "navigate") {
77
+ const lastEntry = this._pendingEntries[this._pendingEntries.length - 1];
78
+ if (lastEntry?.tabSnapshot?.url === action.url)
79
+ return;
80
+ }
81
+ const entry = {
82
+ timestamp: performance.now(),
83
+ userAction: action,
84
+ code,
85
+ tabSnapshot: {
86
+ url: tab.page.url(),
87
+ title: "",
88
+ ariaSnapshot: action.ariaSnapshot || "",
89
+ modalStates: [],
90
+ consoleMessages: [],
91
+ downloads: []
92
+ }
93
+ };
94
+ this._appendEntry(entry);
95
+ }
96
+ _appendEntry(entry) {
97
+ this._pendingEntries.push(entry);
98
+ if (this._flushEntriesTimeout)
99
+ clearTimeout(this._flushEntriesTimeout);
100
+ this._flushEntriesTimeout = setTimeout(() => this._flushEntries(), 1e3);
101
+ }
102
+ async _flushEntries() {
103
+ clearTimeout(this._flushEntriesTimeout);
104
+ const entries = this._pendingEntries;
105
+ this._pendingEntries = [];
106
+ const lines = [""];
107
+ for (const entry of entries) {
108
+ const ordinal = (++this._ordinal).toString().padStart(3, "0");
109
+ if (entry.toolCall) {
110
+ lines.push(
111
+ `### Tool call: ${entry.toolCall.toolName}`,
112
+ `- Args`,
113
+ "```json",
114
+ JSON.stringify(entry.toolCall.toolArgs, null, 2),
115
+ "```"
116
+ );
117
+ if (entry.toolCall.result) {
118
+ lines.push(
119
+ entry.toolCall.isError ? `- Error` : `- Result`,
120
+ "```",
121
+ entry.toolCall.result,
122
+ "```"
123
+ );
124
+ }
125
+ }
126
+ if (entry.userAction) {
127
+ const actionData = { ...entry.userAction };
128
+ delete actionData.ariaSnapshot;
129
+ delete actionData.selector;
130
+ delete actionData.signals;
131
+ lines.push(
132
+ `### User action: ${entry.userAction.name}`,
133
+ `- Args`,
134
+ "```json",
135
+ JSON.stringify(actionData, null, 2),
136
+ "```"
137
+ );
138
+ }
139
+ if (entry.code) {
140
+ lines.push(
141
+ `- Code`,
142
+ "```js",
143
+ entry.code,
144
+ "```"
145
+ );
146
+ }
147
+ if (entry.tabSnapshot) {
148
+ const fileName = `${ordinal}.snapshot.yml`;
149
+ import_fs.default.promises.writeFile(import_path.default.join(this._folder, fileName), entry.tabSnapshot.ariaSnapshot).catch(import_log.logUnhandledError);
150
+ lines.push(`- Snapshot: ${fileName}`);
151
+ }
152
+ lines.push("", "");
153
+ }
154
+ this._sessionFileQueue = this._sessionFileQueue.then(() => import_fs.default.promises.appendFile(this._file, lines.join("\n")));
155
+ }
156
+ }
157
+ // Annotate the CommonJS export names for ESM import in node:
158
+ 0 && (module.exports = {
159
+ SessionLog
160
+ });
@@ -0,0 +1,277 @@
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 tab_exports = {};
20
+ __export(tab_exports, {
21
+ Tab: () => Tab,
22
+ TabEvents: () => TabEvents,
23
+ renderModalStates: () => renderModalStates
24
+ });
25
+ module.exports = __toCommonJS(tab_exports);
26
+ var import_events = require("events");
27
+ var import_utils = require("playwright-core/lib/utils");
28
+ var import_utils2 = require("./tools/utils");
29
+ var import_log = require("../log");
30
+ var import_dialogs = require("./tools/dialogs");
31
+ var import_files = require("./tools/files");
32
+ const TabEvents = {
33
+ modalState: "modalState"
34
+ };
35
+ class Tab extends import_events.EventEmitter {
36
+ constructor(context, page, onPageClose) {
37
+ super();
38
+ this._lastTitle = "about:blank";
39
+ this._consoleMessages = [];
40
+ this._recentConsoleMessages = [];
41
+ this._requests = /* @__PURE__ */ new Set();
42
+ this._modalStates = [];
43
+ this._downloads = [];
44
+ this.context = context;
45
+ this.page = page;
46
+ this._onPageClose = onPageClose;
47
+ page.on("console", (event) => this._handleConsoleMessage(messageToConsoleMessage(event)));
48
+ page.on("pageerror", (error) => this._handleConsoleMessage(pageErrorToConsoleMessage(error)));
49
+ page.on("request", (request) => this._requests.add(request));
50
+ page.on("close", () => this._onClose());
51
+ page.on("filechooser", (chooser) => {
52
+ this.setModalState({
53
+ type: "fileChooser",
54
+ description: "File chooser",
55
+ fileChooser: chooser,
56
+ clearedBy: import_files.uploadFile.schema.name
57
+ });
58
+ });
59
+ page.on("dialog", (dialog) => this._dialogShown(dialog));
60
+ page.on("download", (download) => {
61
+ void this._downloadStarted(download);
62
+ });
63
+ page.setDefaultNavigationTimeout(this.context.config.timeouts.navigation);
64
+ page.setDefaultTimeout(this.context.config.timeouts.action);
65
+ page[tabSymbol] = this;
66
+ this._initializedPromise = this._initialize();
67
+ }
68
+ static forPage(page) {
69
+ return page[tabSymbol];
70
+ }
71
+ static async collectConsoleMessages(page) {
72
+ const result = [];
73
+ const messages = await page.consoleMessages().catch(() => []);
74
+ for (const message of messages)
75
+ result.push(messageToConsoleMessage(message));
76
+ const errors = await page.pageErrors().catch(() => []);
77
+ for (const error of errors)
78
+ result.push(pageErrorToConsoleMessage(error));
79
+ return result;
80
+ }
81
+ async _initialize() {
82
+ for (const message of await Tab.collectConsoleMessages(this.page))
83
+ this._handleConsoleMessage(message);
84
+ const requests = await this.page.requests().catch(() => []);
85
+ for (const request of requests)
86
+ this._requests.add(request);
87
+ }
88
+ modalStates() {
89
+ return this._modalStates;
90
+ }
91
+ setModalState(modalState) {
92
+ this._modalStates.push(modalState);
93
+ this.emit(TabEvents.modalState, modalState);
94
+ }
95
+ clearModalState(modalState) {
96
+ this._modalStates = this._modalStates.filter((state) => state !== modalState);
97
+ }
98
+ modalStatesMarkdown() {
99
+ return renderModalStates(this.context, this.modalStates());
100
+ }
101
+ _dialogShown(dialog) {
102
+ this.setModalState({
103
+ type: "dialog",
104
+ description: `"${dialog.type()}" dialog with message "${dialog.message()}"`,
105
+ dialog,
106
+ clearedBy: import_dialogs.handleDialog.schema.name
107
+ });
108
+ }
109
+ async _downloadStarted(download) {
110
+ const entry = {
111
+ download,
112
+ finished: false,
113
+ outputFile: await this.context.outputFile(download.suggestedFilename(), { origin: "web", reason: "Saving download" })
114
+ };
115
+ this._downloads.push(entry);
116
+ await download.saveAs(entry.outputFile);
117
+ entry.finished = true;
118
+ }
119
+ _clearCollectedArtifacts() {
120
+ this._consoleMessages.length = 0;
121
+ this._recentConsoleMessages.length = 0;
122
+ this._requests.clear();
123
+ }
124
+ _handleConsoleMessage(message) {
125
+ this._consoleMessages.push(message);
126
+ this._recentConsoleMessages.push(message);
127
+ }
128
+ _onClose() {
129
+ this._clearCollectedArtifacts();
130
+ this._onPageClose(this);
131
+ }
132
+ async updateTitle() {
133
+ await this._raceAgainstModalStates(async () => {
134
+ this._lastTitle = await (0, import_utils2.callOnPageNoTrace)(this.page, (page) => page.title());
135
+ });
136
+ }
137
+ lastTitle() {
138
+ return this._lastTitle;
139
+ }
140
+ isCurrentTab() {
141
+ return this === this.context.currentTab();
142
+ }
143
+ async waitForLoadState(state, options) {
144
+ await (0, import_utils2.callOnPageNoTrace)(this.page, (page) => page.waitForLoadState(state, options).catch(import_log.logUnhandledError));
145
+ }
146
+ async navigate(url) {
147
+ this._clearCollectedArtifacts();
148
+ const downloadEvent = (0, import_utils2.callOnPageNoTrace)(this.page, (page) => page.waitForEvent("download").catch(import_log.logUnhandledError));
149
+ try {
150
+ await this.page.goto(url, { waitUntil: "domcontentloaded" });
151
+ } catch (_e) {
152
+ const e = _e;
153
+ const mightBeDownload = e.message.includes("net::ERR_ABORTED") || e.message.includes("Download is starting");
154
+ if (!mightBeDownload)
155
+ throw e;
156
+ const download = await Promise.race([
157
+ downloadEvent,
158
+ new Promise((resolve) => setTimeout(resolve, 3e3))
159
+ ]);
160
+ if (!download)
161
+ throw e;
162
+ await new Promise((resolve) => setTimeout(resolve, 500));
163
+ return;
164
+ }
165
+ await this.waitForLoadState("load", { timeout: 5e3 });
166
+ }
167
+ async consoleMessages(type) {
168
+ await this._initializedPromise;
169
+ return this._consoleMessages.filter((message) => type ? message.type === type : true);
170
+ }
171
+ async requests() {
172
+ await this._initializedPromise;
173
+ return this._requests;
174
+ }
175
+ async captureSnapshot() {
176
+ let tabSnapshot;
177
+ const modalStates = await this._raceAgainstModalStates(async () => {
178
+ const snapshot = await this.page._snapshotForAI();
179
+ tabSnapshot = {
180
+ url: this.page.url(),
181
+ title: await this.page.title(),
182
+ ariaSnapshot: snapshot,
183
+ modalStates: [],
184
+ consoleMessages: [],
185
+ downloads: this._downloads
186
+ };
187
+ });
188
+ if (tabSnapshot) {
189
+ tabSnapshot.consoleMessages = this._recentConsoleMessages;
190
+ this._recentConsoleMessages = [];
191
+ }
192
+ return tabSnapshot ?? {
193
+ url: this.page.url(),
194
+ title: "",
195
+ ariaSnapshot: "",
196
+ modalStates,
197
+ consoleMessages: [],
198
+ downloads: []
199
+ };
200
+ }
201
+ _javaScriptBlocked() {
202
+ return this._modalStates.some((state) => state.type === "dialog");
203
+ }
204
+ async _raceAgainstModalStates(action) {
205
+ if (this.modalStates().length)
206
+ return this.modalStates();
207
+ const promise = new import_utils.ManualPromise();
208
+ const listener = (modalState) => promise.resolve([modalState]);
209
+ this.once(TabEvents.modalState, listener);
210
+ return await Promise.race([
211
+ action().then(() => {
212
+ this.off(TabEvents.modalState, listener);
213
+ return [];
214
+ }),
215
+ promise
216
+ ]);
217
+ }
218
+ async waitForCompletion(callback) {
219
+ await this._raceAgainstModalStates(() => (0, import_utils2.waitForCompletion)(this, callback));
220
+ }
221
+ async refLocator(params) {
222
+ return (await this.refLocators([params]))[0];
223
+ }
224
+ async refLocators(params) {
225
+ const snapshot = await this.page._snapshotForAI();
226
+ return params.map((param) => {
227
+ if (!snapshot.includes(`[ref=${param.ref}]`))
228
+ throw new Error(`Ref ${param.ref} not found in the current page snapshot. Try capturing new snapshot.`);
229
+ return this.page.locator(`aria-ref=${param.ref}`).describe(param.element);
230
+ });
231
+ }
232
+ async waitForTimeout(time) {
233
+ if (this._javaScriptBlocked()) {
234
+ await new Promise((f) => setTimeout(f, time));
235
+ return;
236
+ }
237
+ await (0, import_utils2.callOnPageNoTrace)(this.page, (page) => {
238
+ return page.evaluate(() => new Promise((f) => setTimeout(f, 1e3)));
239
+ });
240
+ }
241
+ }
242
+ function messageToConsoleMessage(message) {
243
+ return {
244
+ type: message.type(),
245
+ text: message.text(),
246
+ toString: () => `[${message.type().toUpperCase()}] ${message.text()} @ ${message.location().url}:${message.location().lineNumber}`
247
+ };
248
+ }
249
+ function pageErrorToConsoleMessage(errorOrValue) {
250
+ if (errorOrValue instanceof Error) {
251
+ return {
252
+ type: "error",
253
+ text: errorOrValue.message,
254
+ toString: () => errorOrValue.stack || errorOrValue.message
255
+ };
256
+ }
257
+ return {
258
+ type: "error",
259
+ text: String(errorOrValue),
260
+ toString: () => String(errorOrValue)
261
+ };
262
+ }
263
+ function renderModalStates(context, modalStates) {
264
+ const result = ["### Modal state"];
265
+ if (modalStates.length === 0)
266
+ result.push("- There is no modal state present");
267
+ for (const state of modalStates)
268
+ result.push(`- [${state.description}]: can be handled by the "${state.clearedBy}" tool`);
269
+ return result;
270
+ }
271
+ const tabSymbol = Symbol("tabSymbol");
272
+ // Annotate the CommonJS export names for ESM import in node:
273
+ 0 && (module.exports = {
274
+ Tab,
275
+ TabEvents,
276
+ renderModalStates
277
+ });
@@ -0,0 +1,30 @@
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 tool_exports = {};
20
+ __export(tool_exports, {
21
+ defineTool: () => defineTool
22
+ });
23
+ module.exports = __toCommonJS(tool_exports);
24
+ function defineTool(tool) {
25
+ return tool;
26
+ }
27
+ // Annotate the CommonJS export names for ESM import in node:
28
+ 0 && (module.exports = {
29
+ defineTool
30
+ });
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/mcp/browser/tool.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 type { z } from 'zod';\nimport type * as mcp from '../sdk/exports';\nimport type * as playwright from '../../../index';\n\nexport type Tool<Input extends z.Schema = z.Schema> = {\n schema: mcp.ToolSchema<Input>;\n handle: (page: playwright.Page, params: z.output<Input>) => Promise<mcp.CallToolResult>;\n};\n\nexport function defineTool<Input extends z.Schema>(tool: Tool<Input>): Tool<Input> {\n return tool;\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAyBO,SAAS,WAAmC,MAAgC;AACjF,SAAO;AACT;",
6
+ "names": []
7
+ }