tabwright 1.0.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.
- package/LICENSE +21 -0
- package/bin.js +4 -0
- package/dist/a11y-client.js +204 -0
- package/dist/agent-skills/tabwright/SKILL.md +119 -0
- package/dist/aria-snapshot.d.ts +262 -0
- package/dist/aria-snapshot.d.ts.map +1 -0
- package/dist/aria-snapshot.js +1256 -0
- package/dist/aria-snapshot.js.map +1 -0
- package/dist/aria-snapshot.test.d.ts +2 -0
- package/dist/aria-snapshot.test.d.ts.map +1 -0
- package/dist/aria-snapshot.test.js +270 -0
- package/dist/aria-snapshot.test.js.map +1 -0
- package/dist/aria-snapshot.unit.test.d.ts +2 -0
- package/dist/aria-snapshot.unit.test.d.ts.map +1 -0
- package/dist/aria-snapshot.unit.test.js +542 -0
- package/dist/aria-snapshot.unit.test.js.map +1 -0
- package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts +5 -0
- package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts.map +1 -0
- package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js +5 -0
- package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js.map +1 -0
- package/dist/bippy.js +894 -0
- package/dist/browser-config.d.ts +13 -0
- package/dist/browser-config.d.ts.map +1 -0
- package/dist/browser-config.js +126 -0
- package/dist/browser-config.js.map +1 -0
- package/dist/browser-install.d.ts +16 -0
- package/dist/browser-install.d.ts.map +1 -0
- package/dist/browser-install.js +238 -0
- package/dist/browser-install.js.map +1 -0
- package/dist/browser-launch.d.ts +17 -0
- package/dist/browser-launch.d.ts.map +1 -0
- package/dist/browser-launch.js +44 -0
- package/dist/browser-launch.js.map +1 -0
- package/dist/builtin-capabilities.d.ts +28 -0
- package/dist/builtin-capabilities.d.ts.map +1 -0
- package/dist/builtin-capabilities.js +2673 -0
- package/dist/builtin-capabilities.js.map +1 -0
- package/dist/capability-agent-skill.d.ts +60 -0
- package/dist/capability-agent-skill.d.ts.map +1 -0
- package/dist/capability-agent-skill.js +225 -0
- package/dist/capability-agent-skill.js.map +1 -0
- package/dist/capability-auth-state.d.ts +34 -0
- package/dist/capability-auth-state.d.ts.map +1 -0
- package/dist/capability-auth-state.js +157 -0
- package/dist/capability-auth-state.js.map +1 -0
- package/dist/capability-auth.d.ts +36 -0
- package/dist/capability-auth.d.ts.map +1 -0
- package/dist/capability-auth.js +198 -0
- package/dist/capability-auth.js.map +1 -0
- package/dist/capability-cli-confirmation.test.d.ts +2 -0
- package/dist/capability-cli-confirmation.test.d.ts.map +1 -0
- package/dist/capability-cli-confirmation.test.js +79 -0
- package/dist/capability-cli-confirmation.test.js.map +1 -0
- package/dist/capability-options.d.ts +20 -0
- package/dist/capability-options.d.ts.map +1 -0
- package/dist/capability-options.js +31 -0
- package/dist/capability-options.js.map +1 -0
- package/dist/capability-options.test.d.ts +2 -0
- package/dist/capability-options.test.d.ts.map +1 -0
- package/dist/capability-options.test.js +81 -0
- package/dist/capability-options.test.js.map +1 -0
- package/dist/capability-package.d.ts +27 -0
- package/dist/capability-package.d.ts.map +1 -0
- package/dist/capability-package.js +444 -0
- package/dist/capability-package.js.map +1 -0
- package/dist/capability-package.test.d.ts +2 -0
- package/dist/capability-package.test.d.ts.map +1 -0
- package/dist/capability-package.test.js +179 -0
- package/dist/capability-package.test.js.map +1 -0
- package/dist/capability-registry.d.ts +262 -0
- package/dist/capability-registry.d.ts.map +1 -0
- package/dist/capability-registry.js +931 -0
- package/dist/capability-registry.js.map +1 -0
- package/dist/capability-registry.test.d.ts +2 -0
- package/dist/capability-registry.test.d.ts.map +1 -0
- package/dist/capability-registry.test.js +1683 -0
- package/dist/capability-registry.test.js.map +1 -0
- package/dist/capability-runner.d.ts +99 -0
- package/dist/capability-runner.d.ts.map +1 -0
- package/dist/capability-runner.js +608 -0
- package/dist/capability-runner.js.map +1 -0
- package/dist/capability-search-relevance.test.d.ts +2 -0
- package/dist/capability-search-relevance.test.d.ts.map +1 -0
- package/dist/capability-search-relevance.test.js +67 -0
- package/dist/capability-search-relevance.test.js.map +1 -0
- package/dist/capability-studio.d.ts +11 -0
- package/dist/capability-studio.d.ts.map +1 -0
- package/dist/capability-studio.js +593 -0
- package/dist/capability-studio.js.map +1 -0
- package/dist/capability-studio.test.d.ts +2 -0
- package/dist/capability-studio.test.d.ts.map +1 -0
- package/dist/capability-studio.test.js +41 -0
- package/dist/capability-studio.test.js.map +1 -0
- package/dist/cdp-log.d.ts +19 -0
- package/dist/cdp-log.d.ts.map +1 -0
- package/dist/cdp-log.js +83 -0
- package/dist/cdp-log.js.map +1 -0
- package/dist/cdp-log.test.d.ts +2 -0
- package/dist/cdp-log.test.d.ts.map +1 -0
- package/dist/cdp-log.test.js +109 -0
- package/dist/cdp-log.test.js.map +1 -0
- package/dist/cdp-relay.d.ts +19 -0
- package/dist/cdp-relay.d.ts.map +1 -0
- package/dist/cdp-relay.js +2375 -0
- package/dist/cdp-relay.js.map +1 -0
- package/dist/cdp-session.d.ts +37 -0
- package/dist/cdp-session.d.ts.map +1 -0
- package/dist/cdp-session.js +36 -0
- package/dist/cdp-session.js.map +1 -0
- package/dist/cdp-types.d.ts +65 -0
- package/dist/cdp-types.d.ts.map +1 -0
- package/dist/cdp-types.js +91 -0
- package/dist/cdp-types.js.map +1 -0
- package/dist/channel-owner-inspect.test.d.ts +2 -0
- package/dist/channel-owner-inspect.test.d.ts.map +1 -0
- package/dist/channel-owner-inspect.test.js +75 -0
- package/dist/channel-owner-inspect.test.js.map +1 -0
- package/dist/chrome-discovery.d.ts +65 -0
- package/dist/chrome-discovery.d.ts.map +1 -0
- package/dist/chrome-discovery.js +173 -0
- package/dist/chrome-discovery.js.map +1 -0
- package/dist/chrome-discovery.test.d.ts +2 -0
- package/dist/chrome-discovery.test.d.ts.map +1 -0
- package/dist/chrome-discovery.test.js +41 -0
- package/dist/chrome-discovery.test.js.map +1 -0
- package/dist/clean-html.d.ts +11 -0
- package/dist/clean-html.d.ts.map +1 -0
- package/dist/clean-html.js +106 -0
- package/dist/clean-html.js.map +1 -0
- package/dist/cli-help.test.d.ts +2 -0
- package/dist/cli-help.test.d.ts.map +1 -0
- package/dist/cli-help.test.js +98 -0
- package/dist/cli-help.test.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +2709 -0
- package/dist/cli.js.map +1 -0
- package/dist/cloud-client.d.ts +56 -0
- package/dist/cloud-client.d.ts.map +1 -0
- package/dist/cloud-client.js +127 -0
- package/dist/cloud-client.js.map +1 -0
- package/dist/create-logger.d.ts +9 -0
- package/dist/create-logger.d.ts.map +1 -0
- package/dist/create-logger.js +27 -0
- package/dist/create-logger.js.map +1 -0
- package/dist/debugger-api.md +458 -0
- package/dist/debugger-examples-types.d.ts +24 -0
- package/dist/debugger-examples-types.d.ts.map +1 -0
- package/dist/debugger-examples-types.js +2 -0
- package/dist/debugger-examples-types.js.map +1 -0
- package/dist/debugger-examples.d.ts +6 -0
- package/dist/debugger-examples.d.ts.map +1 -0
- package/dist/debugger-examples.js +53 -0
- package/dist/debugger-examples.js.map +1 -0
- package/dist/debugger.d.ts +381 -0
- package/dist/debugger.d.ts.map +1 -0
- package/dist/debugger.js +630 -0
- package/dist/debugger.js.map +1 -0
- package/dist/diff-utils.d.ts +20 -0
- package/dist/diff-utils.d.ts.map +1 -0
- package/dist/diff-utils.js +50 -0
- package/dist/diff-utils.js.map +1 -0
- package/dist/diff-utils.test.d.ts +2 -0
- package/dist/diff-utils.test.d.ts.map +1 -0
- package/dist/diff-utils.test.js +137 -0
- package/dist/diff-utils.test.js.map +1 -0
- package/dist/doctor.d.ts +44 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +246 -0
- package/dist/doctor.js.map +1 -0
- package/dist/doctor.test.d.ts +2 -0
- package/dist/doctor.test.d.ts.map +1 -0
- package/dist/doctor.test.js +208 -0
- package/dist/doctor.test.js.map +1 -0
- package/dist/editor-api.md +374 -0
- package/dist/editor-examples.d.ts +11 -0
- package/dist/editor-examples.d.ts.map +1 -0
- package/dist/editor-examples.js +124 -0
- package/dist/editor-examples.js.map +1 -0
- package/dist/editor.d.ts +203 -0
- package/dist/editor.d.ts.map +1 -0
- package/dist/editor.js +363 -0
- package/dist/editor.js.map +1 -0
- package/dist/env-compat.d.ts +2 -0
- package/dist/env-compat.d.ts.map +1 -0
- package/dist/env-compat.js +27 -0
- package/dist/env-compat.js.map +1 -0
- package/dist/executor.d.ts +229 -0
- package/dist/executor.d.ts.map +1 -0
- package/dist/executor.js +1465 -0
- package/dist/executor.js.map +1 -0
- package/dist/executor.unit.test.d.ts +2 -0
- package/dist/executor.unit.test.d.ts.map +1 -0
- package/dist/executor.unit.test.js +143 -0
- package/dist/executor.unit.test.js.map +1 -0
- package/dist/extension/_locales/en/messages.json +278 -0
- package/dist/extension/_locales/zh_CN/messages.json +256 -0
- package/dist/extension/assets/options-CYH96Lcx.css +1349 -0
- package/dist/extension/background.js +3994 -0
- package/dist/extension/icons/SolarCursorSquareBold.png +0 -0
- package/dist/extension/icons/icon-black-128.png +0 -0
- package/dist/extension/icons/icon-black-16.png +0 -0
- package/dist/extension/icons/icon-black-32.png +0 -0
- package/dist/extension/icons/icon-black-48.png +0 -0
- package/dist/extension/icons/icon-gray-128.png +0 -0
- package/dist/extension/icons/icon-gray-16.png +0 -0
- package/dist/extension/icons/icon-gray-32.png +0 -0
- package/dist/extension/icons/icon-gray-48.png +0 -0
- package/dist/extension/icons/icon-green-128.png +0 -0
- package/dist/extension/icons/icon-green-16.png +0 -0
- package/dist/extension/icons/icon-green-32.png +0 -0
- package/dist/extension/icons/icon-green-48.png +0 -0
- package/dist/extension/icons/tabwright-icon-black.png +0 -0
- package/dist/extension/icons/tabwright-icon-gray-disabled.png +0 -0
- package/dist/extension/icons/tabwright-icon-gray-disabled.svg +1 -0
- package/dist/extension/manifest.json +54 -0
- package/dist/extension/options.js +16145 -0
- package/dist/extension/rrweb-recorder.js +12952 -0
- package/dist/extension/src/options.html +165 -0
- package/dist/extension/src/prism-bash.min.js +1 -0
- package/dist/extension/src/prism.min.js +1 -0
- package/dist/extension/src/welcome.html +396 -0
- package/dist/extension-connection.test.d.ts +2 -0
- package/dist/extension-connection.test.d.ts.map +1 -0
- package/dist/extension-connection.test.js +708 -0
- package/dist/extension-connection.test.js.map +1 -0
- package/dist/extension-icon-warning.test.d.ts +2 -0
- package/dist/extension-icon-warning.test.d.ts.map +1 -0
- package/dist/extension-icon-warning.test.js +33 -0
- package/dist/extension-icon-warning.test.js.map +1 -0
- package/dist/ghost-browser.d.ts +62 -0
- package/dist/ghost-browser.d.ts.map +1 -0
- package/dist/ghost-browser.js +107 -0
- package/dist/ghost-browser.js.map +1 -0
- package/dist/ghost-cursor-client.js +374 -0
- package/dist/ghost-cursor-controller.d.ts +46 -0
- package/dist/ghost-cursor-controller.d.ts.map +1 -0
- package/dist/ghost-cursor-controller.js +98 -0
- package/dist/ghost-cursor-controller.js.map +1 -0
- package/dist/ghost-cursor.d.ts +27 -0
- package/dist/ghost-cursor.d.ts.map +1 -0
- package/dist/ghost-cursor.js +79 -0
- package/dist/ghost-cursor.js.map +1 -0
- package/dist/htmlrewrite.d.ts +8 -0
- package/dist/htmlrewrite.d.ts.map +1 -0
- package/dist/htmlrewrite.js +339 -0
- package/dist/htmlrewrite.js.map +1 -0
- package/dist/htmlrewrite.test.d.ts +2 -0
- package/dist/htmlrewrite.test.d.ts.map +1 -0
- package/dist/htmlrewrite.test.js +7975 -0
- package/dist/htmlrewrite.test.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/kill-port.d.ts +29 -0
- package/dist/kill-port.d.ts.map +1 -0
- package/dist/kill-port.js +190 -0
- package/dist/kill-port.js.map +1 -0
- package/dist/kitty-graphics.d.ts +22 -0
- package/dist/kitty-graphics.d.ts.map +1 -0
- package/dist/kitty-graphics.js +71 -0
- package/dist/kitty-graphics.js.map +1 -0
- package/dist/kitty-graphics.test.d.ts +2 -0
- package/dist/kitty-graphics.test.d.ts.map +1 -0
- package/dist/kitty-graphics.test.js +125 -0
- package/dist/kitty-graphics.test.js.map +1 -0
- package/dist/locator-selector.test.d.ts +2 -0
- package/dist/locator-selector.test.d.ts.map +1 -0
- package/dist/locator-selector.test.js +98 -0
- package/dist/locator-selector.test.js.map +1 -0
- package/dist/mcp-client.d.ts +20 -0
- package/dist/mcp-client.d.ts.map +1 -0
- package/dist/mcp-client.js +56 -0
- package/dist/mcp-client.js.map +1 -0
- package/dist/mcp.d.ts +6 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +511 -0
- package/dist/mcp.js.map +1 -0
- package/dist/on-mouse-action.test.d.ts +2 -0
- package/dist/on-mouse-action.test.d.ts.map +1 -0
- package/dist/on-mouse-action.test.js +180 -0
- package/dist/on-mouse-action.test.js.map +1 -0
- package/dist/options-page.test.d.ts +2 -0
- package/dist/options-page.test.d.ts.map +1 -0
- package/dist/options-page.test.js +773 -0
- package/dist/options-page.test.js.map +1 -0
- package/dist/package-paths.d.ts +4 -0
- package/dist/package-paths.d.ts.map +1 -0
- package/dist/package-paths.js +30 -0
- package/dist/package-paths.js.map +1 -0
- package/dist/page-markdown.d.ts +40 -0
- package/dist/page-markdown.d.ts.map +1 -0
- package/dist/page-markdown.js +181 -0
- package/dist/page-markdown.js.map +1 -0
- package/dist/performance-examples.d.ts +5 -0
- package/dist/performance-examples.d.ts.map +1 -0
- package/dist/performance-examples.js +112 -0
- package/dist/performance-examples.js.map +1 -0
- package/dist/performance-profiling.md +417 -0
- package/dist/playwright-import.d.ts +19 -0
- package/dist/playwright-import.d.ts.map +1 -0
- package/dist/playwright-import.js +40 -0
- package/dist/playwright-import.js.map +1 -0
- package/dist/popup-relocation.test.d.ts +7 -0
- package/dist/popup-relocation.test.d.ts.map +1 -0
- package/dist/popup-relocation.test.js +139 -0
- package/dist/popup-relocation.test.js.map +1 -0
- package/dist/product-paths.d.ts +9 -0
- package/dist/product-paths.d.ts.map +1 -0
- package/dist/product-paths.js +24 -0
- package/dist/product-paths.js.map +1 -0
- package/dist/product-paths.test.d.ts +2 -0
- package/dist/product-paths.test.d.ts.map +1 -0
- package/dist/product-paths.test.js +39 -0
- package/dist/product-paths.test.js.map +1 -0
- package/dist/prompt.md +1004 -0
- package/dist/protocol.d.ts +248 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +59 -0
- package/dist/protocol.js.map +1 -0
- package/dist/protocol.test.d.ts +2 -0
- package/dist/protocol.test.d.ts.map +1 -0
- package/dist/protocol.test.js +31 -0
- package/dist/protocol.test.js.map +1 -0
- package/dist/react-source.d.ts +57 -0
- package/dist/react-source.d.ts.map +1 -0
- package/dist/react-source.js +254 -0
- package/dist/react-source.js.map +1 -0
- package/dist/readability.js +1674 -0
- package/dist/relay-client.d.ts +104 -0
- package/dist/relay-client.d.ts.map +1 -0
- package/dist/relay-client.js +426 -0
- package/dist/relay-client.js.map +1 -0
- package/dist/relay-client.test.d.ts +2 -0
- package/dist/relay-client.test.d.ts.map +1 -0
- package/dist/relay-client.test.js +305 -0
- package/dist/relay-client.test.js.map +1 -0
- package/dist/relay-core.test.d.ts +2 -0
- package/dist/relay-core.test.d.ts.map +1 -0
- package/dist/relay-core.test.js +1427 -0
- package/dist/relay-core.test.js.map +1 -0
- package/dist/relay-navigation.test.d.ts +2 -0
- package/dist/relay-navigation.test.d.ts.map +1 -0
- package/dist/relay-navigation.test.js +661 -0
- package/dist/relay-navigation.test.js.map +1 -0
- package/dist/relay-session.test.d.ts +2 -0
- package/dist/relay-session.test.d.ts.map +1 -0
- package/dist/relay-session.test.js +1121 -0
- package/dist/relay-session.test.js.map +1 -0
- package/dist/relay-state.d.ts +178 -0
- package/dist/relay-state.d.ts.map +1 -0
- package/dist/relay-state.js +346 -0
- package/dist/relay-state.js.map +1 -0
- package/dist/relay-state.test.d.ts +2 -0
- package/dist/relay-state.test.d.ts.map +1 -0
- package/dist/relay-state.test.js +594 -0
- package/dist/relay-state.test.js.map +1 -0
- package/dist/replay-ai-index.d.ts +99 -0
- package/dist/replay-ai-index.d.ts.map +1 -0
- package/dist/replay-ai-index.js +677 -0
- package/dist/replay-ai-index.js.map +1 -0
- package/dist/replay-ai-index.test.d.ts +2 -0
- package/dist/replay-ai-index.test.d.ts.map +1 -0
- package/dist/replay-ai-index.test.js +255 -0
- package/dist/replay-ai-index.test.js.map +1 -0
- package/dist/replay-cli.test.d.ts +2 -0
- package/dist/replay-cli.test.d.ts.map +1 -0
- package/dist/replay-cli.test.js +275 -0
- package/dist/replay-cli.test.js.map +1 -0
- package/dist/replay-eval.d.ts +44 -0
- package/dist/replay-eval.d.ts.map +1 -0
- package/dist/replay-eval.js +902 -0
- package/dist/replay-eval.js.map +1 -0
- package/dist/replay-handoff.d.ts +29 -0
- package/dist/replay-handoff.d.ts.map +1 -0
- package/dist/replay-handoff.js +83 -0
- package/dist/replay-handoff.js.map +1 -0
- package/dist/replay-handoff.test.d.ts +2 -0
- package/dist/replay-handoff.test.d.ts.map +1 -0
- package/dist/replay-handoff.test.js +123 -0
- package/dist/replay-handoff.test.js.map +1 -0
- package/dist/replay-workflow-compiler.d.ts +44 -0
- package/dist/replay-workflow-compiler.d.ts.map +1 -0
- package/dist/replay-workflow-compiler.js +601 -0
- package/dist/replay-workflow-compiler.js.map +1 -0
- package/dist/replay-workflow-compiler.test.d.ts +2 -0
- package/dist/replay-workflow-compiler.test.d.ts.map +1 -0
- package/dist/replay-workflow-compiler.test.js +223 -0
- package/dist/replay-workflow-compiler.test.js.map +1 -0
- package/dist/rrweb-recording-relay.d.ts +56 -0
- package/dist/rrweb-recording-relay.d.ts.map +1 -0
- package/dist/rrweb-recording-relay.js +299 -0
- package/dist/rrweb-recording-relay.js.map +1 -0
- package/dist/rrweb-recording-relay.test.d.ts +2 -0
- package/dist/rrweb-recording-relay.test.d.ts.map +1 -0
- package/dist/rrweb-recording-relay.test.js +85 -0
- package/dist/rrweb-recording-relay.test.js.map +1 -0
- package/dist/rrweb-recording.d.ts +104 -0
- package/dist/rrweb-recording.d.ts.map +1 -0
- package/dist/rrweb-recording.js +180 -0
- package/dist/rrweb-recording.js.map +1 -0
- package/dist/scoped-fs.d.ts +95 -0
- package/dist/scoped-fs.d.ts.map +1 -0
- package/dist/scoped-fs.js +358 -0
- package/dist/scoped-fs.js.map +1 -0
- package/dist/scoped-fs.test.d.ts +5 -0
- package/dist/scoped-fs.test.d.ts.map +1 -0
- package/dist/scoped-fs.test.js +73 -0
- package/dist/scoped-fs.test.js.map +1 -0
- package/dist/selector-generator.js +7378 -0
- package/dist/skill-stub.test.d.ts +2 -0
- package/dist/skill-stub.test.d.ts.map +1 -0
- package/dist/skill-stub.test.js +22 -0
- package/dist/skill-stub.test.js.map +1 -0
- package/dist/snapshot-tools.test.d.ts +2 -0
- package/dist/snapshot-tools.test.d.ts.map +1 -0
- package/dist/snapshot-tools.test.js +856 -0
- package/dist/snapshot-tools.test.js.map +1 -0
- package/dist/start-relay-server.d.ts +6 -0
- package/dist/start-relay-server.d.ts.map +1 -0
- package/dist/start-relay-server.js +57 -0
- package/dist/start-relay-server.js.map +1 -0
- package/dist/styles-api.md +124 -0
- package/dist/styles-examples.d.ts +8 -0
- package/dist/styles-examples.d.ts.map +1 -0
- package/dist/styles-examples.js +64 -0
- package/dist/styles-examples.js.map +1 -0
- package/dist/styles.d.ts +27 -0
- package/dist/styles.d.ts.map +1 -0
- package/dist/styles.js +231 -0
- package/dist/styles.js.map +1 -0
- package/dist/tabwright-agent-skill.d.ts +30 -0
- package/dist/tabwright-agent-skill.d.ts.map +1 -0
- package/dist/tabwright-agent-skill.js +74 -0
- package/dist/tabwright-agent-skill.js.map +1 -0
- package/dist/tabwright-agent-skill.test.d.ts +2 -0
- package/dist/tabwright-agent-skill.test.d.ts.map +1 -0
- package/dist/tabwright-agent-skill.test.js +51 -0
- package/dist/tabwright-agent-skill.test.js.map +1 -0
- package/dist/test-declarations.d.ts +13 -0
- package/dist/test-declarations.d.ts.map +1 -0
- package/dist/test-declarations.js +2 -0
- package/dist/test-declarations.js.map +1 -0
- package/dist/test-utils.d.ts +69 -0
- package/dist/test-utils.d.ts.map +1 -0
- package/dist/test-utils.js +448 -0
- package/dist/test-utils.js.map +1 -0
- package/dist/test-utils.test.d.ts +2 -0
- package/dist/test-utils.test.d.ts.map +1 -0
- package/dist/test-utils.test.js +55 -0
- package/dist/test-utils.test.js.map +1 -0
- package/dist/utils.d.ts +26 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +60 -0
- package/dist/utils.js.map +1 -0
- package/dist/wait-for-page-load.d.ts +16 -0
- package/dist/wait-for-page-load.d.ts.map +1 -0
- package/dist/wait-for-page-load.js +146 -0
- package/dist/wait-for-page-load.js.map +1 -0
- package/dist/workflow-capability.d.ts +72 -0
- package/dist/workflow-capability.d.ts.map +1 -0
- package/dist/workflow-capability.js +316 -0
- package/dist/workflow-capability.js.map +1 -0
- package/dist/workflow-script-flow.test.d.ts +2 -0
- package/dist/workflow-script-flow.test.d.ts.map +1 -0
- package/dist/workflow-script-flow.test.js +285 -0
- package/dist/workflow-script-flow.test.js.map +1 -0
- package/package.json +80 -0
- package/src/__snapshots__/x.com.processed.html +1003 -0
- package/src/__snapshots__/x.com.processed.withStyles.html +2720 -0
- package/src/a11y-client.ts +241 -0
- package/src/agent-skills/conan-config/SKILL.md +141 -0
- package/src/agent-skills/conan-config/agents/openai.yaml +4 -0
- package/src/aria-snapshot.test.ts +311 -0
- package/src/aria-snapshot.ts +1681 -0
- package/src/aria-snapshot.unit.test.ts +615 -0
- package/src/aria-snapshots/github-interactive.txt +193 -0
- package/src/aria-snapshots/github-raw.txt +309 -0
- package/src/aria-snapshots/hackernews-interactive.txt +477 -0
- package/src/aria-snapshots/hackernews-raw.txt +428 -0
- package/src/aria-snapshots/prosemirror-interactive.txt +66 -0
- package/src/aria-snapshots/prosemirror-raw.txt +145 -0
- package/src/assets/aria-labels-hacker-news.png +0 -0
- package/src/assets/aria-labels-old-reddit.png +0 -0
- package/src/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.ts +5 -0
- package/src/assets/cursors/screen-studio/pointer-macos-tahoe.svg +18 -0
- package/src/assets/x.com.html +32946 -0
- package/src/browser-config.ts +179 -0
- package/src/browser-install.ts +284 -0
- package/src/browser-launch.ts +75 -0
- package/src/builtin-capabilities.ts +2765 -0
- package/src/capability-agent-skill.ts +305 -0
- package/src/capability-auth-state.ts +197 -0
- package/src/capability-auth.ts +249 -0
- package/src/capability-cli-confirmation.test.ts +90 -0
- package/src/capability-options.test.ts +89 -0
- package/src/capability-options.ts +57 -0
- package/src/capability-package.test.ts +204 -0
- package/src/capability-package.ts +555 -0
- package/src/capability-registry.test.ts +1905 -0
- package/src/capability-registry.ts +1234 -0
- package/src/capability-runner.ts +801 -0
- package/src/capability-search-relevance.test.ts +73 -0
- package/src/capability-studio.test.ts +45 -0
- package/src/capability-studio.ts +641 -0
- package/src/cdp-log.test.ts +131 -0
- package/src/cdp-log.ts +112 -0
- package/src/cdp-relay.ts +2944 -0
- package/src/cdp-session.ts +77 -0
- package/src/cdp-types.ts +158 -0
- package/src/channel-owner-inspect.test.ts +94 -0
- package/src/chrome-discovery.test.ts +50 -0
- package/src/chrome-discovery.ts +220 -0
- package/src/clean-html.ts +141 -0
- package/src/cli-help.test.ts +123 -0
- package/src/cli.ts +3181 -0
- package/src/cloud-client.ts +179 -0
- package/src/create-logger.ts +38 -0
- package/src/debugger-examples-types.ts +16 -0
- package/src/debugger-examples.ts +66 -0
- package/src/debugger.ts +708 -0
- package/src/diff-utils.test.ts +152 -0
- package/src/diff-utils.ts +70 -0
- package/src/doctor.test.ts +244 -0
- package/src/doctor.ts +321 -0
- package/src/editor-examples.ts +158 -0
- package/src/editor.ts +426 -0
- package/src/env-compat.ts +28 -0
- package/src/executor.ts +1824 -0
- package/src/executor.unit.test.ts +168 -0
- package/src/extension-connection.test.ts +855 -0
- package/src/extension-icon-warning.test.ts +45 -0
- package/src/ghost-browser.ts +149 -0
- package/src/ghost-cursor-client.ts +494 -0
- package/src/ghost-cursor-controller.ts +129 -0
- package/src/ghost-cursor.ts +123 -0
- package/src/htmlrewrite.test.ts +8008 -0
- package/src/htmlrewrite.ts +390 -0
- package/src/index.ts +53 -0
- package/src/kill-port.ts +219 -0
- package/src/kitty-graphics.test.ts +139 -0
- package/src/kitty-graphics.ts +79 -0
- package/src/locator-selector.test.ts +119 -0
- package/src/mcp-client.ts +78 -0
- package/src/mcp.ts +629 -0
- package/src/on-mouse-action.test.ts +226 -0
- package/src/options-page.test.ts +839 -0
- package/src/package-paths.ts +38 -0
- package/src/page-markdown.ts +240 -0
- package/src/performance-examples.ts +186 -0
- package/src/playwright-import.ts +59 -0
- package/src/popup-relocation.test.ts +163 -0
- package/src/product-paths.test.ts +47 -0
- package/src/product-paths.ts +28 -0
- package/src/protocol.test.ts +52 -0
- package/src/protocol.ts +351 -0
- package/src/react-source.ts +379 -0
- package/src/relay-client.test.ts +375 -0
- package/src/relay-client.ts +572 -0
- package/src/relay-core.test.ts +1603 -0
- package/src/relay-navigation.test.ts +790 -0
- package/src/relay-session.test.ts +1375 -0
- package/src/relay-state.test.ts +729 -0
- package/src/relay-state.ts +561 -0
- package/src/replay-ai-index.test.ts +278 -0
- package/src/replay-ai-index.ts +872 -0
- package/src/replay-cli.test.ts +325 -0
- package/src/replay-eval.ts +1039 -0
- package/src/replay-handoff.test.ts +163 -0
- package/src/replay-handoff.ts +109 -0
- package/src/replay-workflow-compiler.test.ts +250 -0
- package/src/replay-workflow-compiler.ts +700 -0
- package/src/resource.md +409 -0
- package/src/rrweb-recording-relay.test.ts +99 -0
- package/src/rrweb-recording-relay.ts +400 -0
- package/src/rrweb-recording.ts +322 -0
- package/src/scoped-fs.test.ts +80 -0
- package/src/scoped-fs.ts +420 -0
- package/src/skill-stub.test.ts +24 -0
- package/src/skill.md +1413 -0
- package/src/snapshot-tools.test.ts +1017 -0
- package/src/snapshots/hacker-news-accessibility-full.md +81 -0
- package/src/snapshots/hacker-news-accessibility-interactive.md +43 -0
- package/src/snapshots/page-markdown-output.txt +16 -0
- package/src/snapshots/shadcn-ui-accessibility-full.md +201 -0
- package/src/snapshots/shadcn-ui-accessibility-interactive.md +109 -0
- package/src/start-relay-server.ts +69 -0
- package/src/styles-examples.ts +84 -0
- package/src/styles.ts +343 -0
- package/src/tabwright-agent-skill.test.ts +61 -0
- package/src/tabwright-agent-skill.ts +105 -0
- package/src/test-declarations.ts +13 -0
- package/src/test-utils.test.ts +70 -0
- package/src/test-utils.ts +566 -0
- package/src/utils.ts +78 -0
- package/src/wait-for-page-load.ts +198 -0
- package/src/workflow-capability.ts +417 -0
- package/src/workflow-script-flow.test.ts +388 -0
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
# Profile Website Performance with Tabwright
|
|
2
|
+
|
|
3
|
+
Tabwright can profile a real website in your own Chrome using **CDP**, **Navigation Timing**,
|
|
4
|
+
and **PerformanceObserver**.
|
|
5
|
+
|
|
6
|
+
Use it to answer four practical questions quickly:
|
|
7
|
+
|
|
8
|
+
1. **Did the page render fast enough?**
|
|
9
|
+
2. **What requests cost the most bytes?**
|
|
10
|
+
3. **What blocked first paint or LCP?**
|
|
11
|
+
4. **What blocked interactivity?**
|
|
12
|
+
|
|
13
|
+
## What to measure
|
|
14
|
+
|
|
15
|
+
| Metric | Good | Needs work | Usually means |
|
|
16
|
+
| --- | --- | --- | --- |
|
|
17
|
+
| **TTFB** | under **800ms** | over **1.2s** | slow server or cache miss |
|
|
18
|
+
| **FCP** | under **1.8s** | over **3s** | content appears late |
|
|
19
|
+
| **LCP** | under **2.5s** | over **4s** | hero image, font, CSS, server, or JS delay |
|
|
20
|
+
| **CLS** | under **0.1** | over **0.25** | unstable layout |
|
|
21
|
+
| **Long task** | under **50ms** | over **100ms** | main thread blocked by JS |
|
|
22
|
+
| **JS transfer** | under **250KB** | over **500KB** | too much hydration or client code |
|
|
23
|
+
| **Font / media transfer** | context dependent | large above-the-fold assets | fonts, posters, videos, hero images |
|
|
24
|
+
|
|
25
|
+
## What usually blocks what
|
|
26
|
+
|
|
27
|
+
- **First paint / FCP** is usually gated by **TTFB**, critical HTML, critical CSS, and above-the-fold fonts/images.
|
|
28
|
+
- **LCP** is usually gated by the **largest hero asset**. Common causes: hero image, poster image, custom font, render-blocking CSS, or slow server response.
|
|
29
|
+
- **Interactivity** is usually gated by **long tasks**. Common causes: too much JS on startup, hydration, or a large framework chunk.
|
|
30
|
+
- **Load event** often stays late because of **non-critical assets** like videos, analytics, background images, and delayed client bundles.
|
|
31
|
+
|
|
32
|
+
## Quick commands
|
|
33
|
+
|
|
34
|
+
Create a session and open a page:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
tabwright session new
|
|
38
|
+
tabwright -s 1 -e 'state.page = context.pages().find((p) => p.url() === "about:blank") ?? (await context.newPage()); await state.page.goto("https://example.com", { waitUntil: "domcontentloaded" })'
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Collect a concise vitals report:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
tabwright -s 1 -e "$(cat <<'EOF'
|
|
45
|
+
await state.page.evaluate(() => {
|
|
46
|
+
const metrics = { paints: {}, lcp: 0, cls: 0 }
|
|
47
|
+
globalThis.__pwMetrics = metrics
|
|
48
|
+
|
|
49
|
+
new PerformanceObserver((list) => {
|
|
50
|
+
for (const entry of list.getEntries()) {
|
|
51
|
+
metrics.paints[entry.name] = entry.startTime
|
|
52
|
+
}
|
|
53
|
+
}).observe({ type: 'paint', buffered: true })
|
|
54
|
+
|
|
55
|
+
new PerformanceObserver((list) => {
|
|
56
|
+
const lastEntry = list.getEntries().at(-1)
|
|
57
|
+
if (lastEntry) {
|
|
58
|
+
metrics.lcp = lastEntry.startTime
|
|
59
|
+
}
|
|
60
|
+
}).observe({ type: 'largest-contentful-paint', buffered: true })
|
|
61
|
+
|
|
62
|
+
new PerformanceObserver((list) => {
|
|
63
|
+
for (const entry of list.getEntries()) {
|
|
64
|
+
if (!entry.hadRecentInput) {
|
|
65
|
+
metrics.cls += entry.value
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}).observe({ type: 'layout-shift', buffered: true })
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
await state.page.reload({ waitUntil: 'domcontentloaded' })
|
|
72
|
+
await waitForPageLoad({ page: state.page, timeout: 10000 })
|
|
73
|
+
await state.page.waitForTimeout(3000)
|
|
74
|
+
|
|
75
|
+
const report = await state.page.evaluate(() => {
|
|
76
|
+
const nav = performance.getEntriesByType('navigation')[0]
|
|
77
|
+
const metrics = globalThis.__pwMetrics
|
|
78
|
+
return {
|
|
79
|
+
ttfb: nav?.responseStart || 0,
|
|
80
|
+
domContentLoaded: nav?.domContentLoadedEventEnd || 0,
|
|
81
|
+
load: nav?.loadEventEnd || 0,
|
|
82
|
+
fcp: metrics?.paints['first-contentful-paint'] || 0,
|
|
83
|
+
lcp: metrics?.lcp || 0,
|
|
84
|
+
cls: metrics?.cls || 0,
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
console.log(JSON.stringify(report, null, 2))
|
|
89
|
+
EOF
|
|
90
|
+
)"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
List the heaviest requests with CDP:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
tabwright -s 1 -e "$(cat <<'EOF'
|
|
97
|
+
const cdp = await getCDPSession({ page: state.page })
|
|
98
|
+
await cdp.send('Network.enable')
|
|
99
|
+
await cdp.send('Network.setCacheDisabled', { cacheDisabled: true })
|
|
100
|
+
|
|
101
|
+
const responses = new Map()
|
|
102
|
+
const finished = new Map()
|
|
103
|
+
|
|
104
|
+
cdp.on('Network.responseReceived', (event) => {
|
|
105
|
+
responses.set(event.requestId, {
|
|
106
|
+
url: event.response.url,
|
|
107
|
+
mimeType: event.response.mimeType,
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
cdp.on('Network.loadingFinished', (event) => {
|
|
112
|
+
finished.set(event.requestId, event.encodedDataLength)
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
await state.page.reload({ waitUntil: 'domcontentloaded' })
|
|
116
|
+
await waitForPageLoad({ page: state.page, timeout: 10000 })
|
|
117
|
+
await state.page.waitForTimeout(3000)
|
|
118
|
+
|
|
119
|
+
const largest = [...responses.entries()]
|
|
120
|
+
.map(([requestId, response]) => ({
|
|
121
|
+
url: response.url,
|
|
122
|
+
mimeType: response.mimeType,
|
|
123
|
+
bytes: finished.get(requestId) || 0,
|
|
124
|
+
}))
|
|
125
|
+
.sort((a, b) => b.bytes - a.bytes)
|
|
126
|
+
.slice(0, 10)
|
|
127
|
+
|
|
128
|
+
console.log(JSON.stringify(largest, null, 2))
|
|
129
|
+
EOF
|
|
130
|
+
)"
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Check interactivity blockers:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
tabwright -s 1 -e "$(cat <<'EOF'
|
|
137
|
+
await state.page.evaluate(() => {
|
|
138
|
+
globalThis.__pwLongTasks = []
|
|
139
|
+
globalThis.__pwEvents = []
|
|
140
|
+
|
|
141
|
+
new PerformanceObserver((list) => {
|
|
142
|
+
globalThis.__pwLongTasks.push(
|
|
143
|
+
...list.getEntries().map((entry) => ({ startTime: entry.startTime, duration: entry.duration })),
|
|
144
|
+
)
|
|
145
|
+
}).observe({ type: 'longtask', buffered: true })
|
|
146
|
+
|
|
147
|
+
new PerformanceObserver((list) => {
|
|
148
|
+
globalThis.__pwEvents.push(
|
|
149
|
+
...list.getEntries().map((entry) => ({
|
|
150
|
+
name: entry.name,
|
|
151
|
+
duration: entry.duration,
|
|
152
|
+
interactionId: entry.interactionId,
|
|
153
|
+
})),
|
|
154
|
+
)
|
|
155
|
+
}).observe({ type: 'event', buffered: true, durationThreshold: 16 })
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
await state.page.getByRole('button').first().click()
|
|
159
|
+
await state.page.waitForTimeout(1000)
|
|
160
|
+
|
|
161
|
+
const report = await state.page.evaluate(() => ({
|
|
162
|
+
longTasks: globalThis.__pwLongTasks.filter((entry) => entry.duration >= 50),
|
|
163
|
+
interactions: globalThis.__pwEvents.filter((entry) => entry.interactionId !== 0),
|
|
164
|
+
}))
|
|
165
|
+
|
|
166
|
+
console.log(JSON.stringify(report, null, 2))
|
|
167
|
+
EOF
|
|
168
|
+
)"
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## How to read the results
|
|
172
|
+
|
|
173
|
+
**Fast render, heavy payload**
|
|
174
|
+
|
|
175
|
+
- If **FCP** and **LCP** are good but total bytes are huge, the page probably **looks fast on desktop** but wastes bandwidth on mobile.
|
|
176
|
+
- This often happens with **hero videos**, large poster images, or custom fonts.
|
|
177
|
+
|
|
178
|
+
**Slow first paint**
|
|
179
|
+
|
|
180
|
+
- If **TTFB** is high, fix **server latency** or caching first.
|
|
181
|
+
- If **TTFB** is fine but **FCP** is slow, inspect critical CSS, fonts, and above-the-fold images.
|
|
182
|
+
|
|
183
|
+
**Slow interactivity**
|
|
184
|
+
|
|
185
|
+
- If you see **long tasks over 50ms**, startup JS is the first suspect.
|
|
186
|
+
- Look for large client bundles, hydration-heavy UI, and event handlers doing too much work.
|
|
187
|
+
|
|
188
|
+
**Need deeper CPU answers**
|
|
189
|
+
|
|
190
|
+
- If vitals and request sizes are not enough, record a **`.cpuprofile`** with Tabwright's raw **`Profiler.*`** CDP commands and inspect it with **[profano](https://github.com/remorses/profano)**.
|
|
191
|
+
- A good place to keep your reusable profiling snippets is your dots repo, for example **`~/.config/opencode/`**.
|
|
192
|
+
|
|
193
|
+
**Good load event is not enough**
|
|
194
|
+
|
|
195
|
+
- A page can have a decent `load` time and still feel slow if **LCP** or **long tasks** are bad.
|
|
196
|
+
- Prefer **TTFB + FCP + LCP + CLS + long tasks** over the load event alone.
|
|
197
|
+
|
|
198
|
+
## Performance checklist
|
|
199
|
+
|
|
200
|
+
**If TTFB is bad**
|
|
201
|
+
|
|
202
|
+
- cache HTML closer to users
|
|
203
|
+
- reduce origin work before response
|
|
204
|
+
- avoid expensive server-side data fetching on the critical route
|
|
205
|
+
|
|
206
|
+
**If FCP or LCP is bad**
|
|
207
|
+
|
|
208
|
+
- trim or defer render-blocking CSS
|
|
209
|
+
- avoid large above-the-fold fonts and images
|
|
210
|
+
- preload only truly critical assets
|
|
211
|
+
- compress hero media harder
|
|
212
|
+
|
|
213
|
+
**If interactivity is bad**
|
|
214
|
+
|
|
215
|
+
- reduce startup JS
|
|
216
|
+
- split large client bundles
|
|
217
|
+
- avoid hydrating UI that is not immediately interactive
|
|
218
|
+
- move optional widgets behind user action or idle time
|
|
219
|
+
- if the culprit is still unclear, switch from vitals to a CPU profile and inspect hot functions with **profano**
|
|
220
|
+
|
|
221
|
+
**If bytes are bad but vitals look good**
|
|
222
|
+
|
|
223
|
+
- optimize for slower devices anyway
|
|
224
|
+
- background videos are the first thing to cut
|
|
225
|
+
- subset fonts and trim non-critical client features
|
|
226
|
+
|
|
227
|
+
## Examples
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
// Example snippets for profiling website performance with Tabwright and CDP.
|
|
231
|
+
|
|
232
|
+
import { console, getCDPSession, page } from './debugger-examples-types.js'
|
|
233
|
+
|
|
234
|
+
type PerfMetrics = {
|
|
235
|
+
paints: Record<string, number>
|
|
236
|
+
lcp: number
|
|
237
|
+
cls: number
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
type ObservedPerfEntry = {
|
|
241
|
+
name: string
|
|
242
|
+
startTime: number
|
|
243
|
+
duration: number
|
|
244
|
+
hadRecentInput?: boolean
|
|
245
|
+
value?: number
|
|
246
|
+
interactionId?: number
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
type NavigationTimingEntry = {
|
|
250
|
+
responseStart: number
|
|
251
|
+
domContentLoadedEventEnd: number
|
|
252
|
+
loadEventEnd: number
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
type LongTaskEntry = {
|
|
256
|
+
startTime: number
|
|
257
|
+
duration: number
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
type EventTimingEntry = {
|
|
261
|
+
name: string
|
|
262
|
+
duration: number
|
|
263
|
+
interactionId: number
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Example: Collect navigation timing and basic web vitals from the current page
|
|
267
|
+
async function collectWebVitals() {
|
|
268
|
+
await page.evaluate(() => {
|
|
269
|
+
const metrics: PerfMetrics = {
|
|
270
|
+
paints: {},
|
|
271
|
+
lcp: 0,
|
|
272
|
+
cls: 0,
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const perfGlobal = globalThis as typeof globalThis & {
|
|
276
|
+
__pwPerfMetrics?: PerfMetrics
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
perfGlobal.__pwPerfMetrics = metrics
|
|
280
|
+
|
|
281
|
+
new PerformanceObserver((list) => {
|
|
282
|
+
for (const entry of list.getEntries() as ObservedPerfEntry[]) {
|
|
283
|
+
metrics.paints[entry.name] = entry.startTime
|
|
284
|
+
}
|
|
285
|
+
}).observe({ type: 'paint', buffered: true } as never)
|
|
286
|
+
|
|
287
|
+
new PerformanceObserver((list) => {
|
|
288
|
+
const entries = list.getEntries() as ObservedPerfEntry[]
|
|
289
|
+
const lastEntry = entries[entries.length - 1]
|
|
290
|
+
if (!lastEntry) {
|
|
291
|
+
return
|
|
292
|
+
}
|
|
293
|
+
metrics.lcp = lastEntry.startTime
|
|
294
|
+
}).observe({ type: 'largest-contentful-paint', buffered: true } as never)
|
|
295
|
+
|
|
296
|
+
new PerformanceObserver((list) => {
|
|
297
|
+
for (const entry of list.getEntries() as ObservedPerfEntry[]) {
|
|
298
|
+
if (entry.hadRecentInput) {
|
|
299
|
+
continue
|
|
300
|
+
}
|
|
301
|
+
metrics.cls += entry.value || 0
|
|
302
|
+
}
|
|
303
|
+
}).observe({ type: 'layout-shift', buffered: true } as never)
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
await page.reload({ waitUntil: 'domcontentloaded' })
|
|
307
|
+
|
|
308
|
+
const report = await page.evaluate(() => {
|
|
309
|
+
const perfGlobal = globalThis as typeof globalThis & {
|
|
310
|
+
__pwPerfMetrics?: PerfMetrics
|
|
311
|
+
}
|
|
312
|
+
const nav = performance.getEntriesByType('navigation' as never)[0] as unknown as
|
|
313
|
+
| NavigationTimingEntry
|
|
314
|
+
| undefined
|
|
315
|
+
const metrics = perfGlobal.__pwPerfMetrics
|
|
316
|
+
|
|
317
|
+
return {
|
|
318
|
+
ttfb: nav?.responseStart || 0,
|
|
319
|
+
domContentLoaded: nav?.domContentLoadedEventEnd || 0,
|
|
320
|
+
load: nav?.loadEventEnd || 0,
|
|
321
|
+
fcp: metrics?.paints['first-contentful-paint'] || 0,
|
|
322
|
+
lcp: metrics?.lcp || 0,
|
|
323
|
+
cls: metrics?.cls || 0,
|
|
324
|
+
}
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
console.log(report)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Example: Measure the biggest transferred requests with raw CDP network events
|
|
331
|
+
async function collectHeaviestRequests() {
|
|
332
|
+
const cdp = await getCDPSession({ page })
|
|
333
|
+
await cdp.send('Network.enable')
|
|
334
|
+
await cdp.send('Network.setCacheDisabled', { cacheDisabled: true })
|
|
335
|
+
|
|
336
|
+
const responses = new Map<string, { url: string; mimeType: string }>()
|
|
337
|
+
const finished = new Map<string, number>()
|
|
338
|
+
|
|
339
|
+
cdp.on('Network.responseReceived', (event) => {
|
|
340
|
+
responses.set(event.requestId, {
|
|
341
|
+
url: event.response.url,
|
|
342
|
+
mimeType: event.response.mimeType,
|
|
343
|
+
})
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
cdp.on('Network.loadingFinished', (event) => {
|
|
347
|
+
finished.set(event.requestId, event.encodedDataLength)
|
|
348
|
+
})
|
|
349
|
+
|
|
350
|
+
await page.reload({ waitUntil: 'domcontentloaded' })
|
|
351
|
+
|
|
352
|
+
const largest = [...responses.entries()]
|
|
353
|
+
.map(([requestId, response]) => {
|
|
354
|
+
return {
|
|
355
|
+
url: response.url,
|
|
356
|
+
mimeType: response.mimeType,
|
|
357
|
+
bytes: finished.get(requestId) || 0,
|
|
358
|
+
}
|
|
359
|
+
})
|
|
360
|
+
.sort((a, b) => b.bytes - a.bytes)
|
|
361
|
+
.slice(0, 10)
|
|
362
|
+
|
|
363
|
+
console.log(largest)
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Example: Check whether interactivity is blocked by long tasks or slow events
|
|
367
|
+
async function measureInteractivity() {
|
|
368
|
+
await page.evaluate(() => {
|
|
369
|
+
const perfGlobal = globalThis as typeof globalThis & {
|
|
370
|
+
__pwLongTasks?: LongTaskEntry[]
|
|
371
|
+
__pwEventTimings?: EventTimingEntry[]
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
perfGlobal.__pwLongTasks = []
|
|
375
|
+
perfGlobal.__pwEventTimings = []
|
|
376
|
+
|
|
377
|
+
new PerformanceObserver((list) => {
|
|
378
|
+
perfGlobal.__pwLongTasks?.push(
|
|
379
|
+
...(list.getEntries() as ObservedPerfEntry[]).map((entry) => ({
|
|
380
|
+
startTime: entry.startTime,
|
|
381
|
+
duration: entry.duration,
|
|
382
|
+
})),
|
|
383
|
+
)
|
|
384
|
+
}).observe({ type: 'longtask', buffered: true } as never)
|
|
385
|
+
|
|
386
|
+
new PerformanceObserver((list) => {
|
|
387
|
+
perfGlobal.__pwEventTimings?.push(
|
|
388
|
+
...(list.getEntries() as ObservedPerfEntry[]).map((entry) => ({
|
|
389
|
+
name: entry.name,
|
|
390
|
+
duration: entry.duration,
|
|
391
|
+
interactionId: entry.interactionId || 0,
|
|
392
|
+
})),
|
|
393
|
+
)
|
|
394
|
+
}).observe({ type: 'event', buffered: true, durationThreshold: 16 } as never)
|
|
395
|
+
})
|
|
396
|
+
|
|
397
|
+
const button = page.getByRole('button').first()
|
|
398
|
+
await button.click()
|
|
399
|
+
|
|
400
|
+
const report = await page.evaluate(() => {
|
|
401
|
+
const perfGlobal = globalThis as typeof globalThis & {
|
|
402
|
+
__pwLongTasks?: LongTaskEntry[]
|
|
403
|
+
__pwEventTimings?: EventTimingEntry[]
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return {
|
|
407
|
+
longTasks: (perfGlobal.__pwLongTasks || []).filter((entry) => entry.duration >= 50),
|
|
408
|
+
events: (perfGlobal.__pwEventTimings || []).filter((entry) => entry.interactionId !== 0),
|
|
409
|
+
}
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
console.log(report)
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
export { collectWebVitals, collectHeaviestRequests, measureInteractivity }
|
|
416
|
+
|
|
417
|
+
```
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conditional playwright-core import. When patchright mode is enabled via
|
|
3
|
+
* TABWRIGHT_PATCHRIGHT=1 env var, imports from @playwriter/patchright-core
|
|
4
|
+
* instead of @xmorse/playwright-core. Both packages expose identical APIs.
|
|
5
|
+
*
|
|
6
|
+
* Type imports continue to use @xmorse/playwright-core directly (types are
|
|
7
|
+
* the same in both packages) so TypeScript resolution works without the
|
|
8
|
+
* optional patchright dep being installed.
|
|
9
|
+
*/
|
|
10
|
+
export type { Page, Frame, Browser, BrowserContext, Locator, FrameLocator, ElementHandle, CDPSession, MouseActionEvent, } from '@xmorse/playwright-core';
|
|
11
|
+
export type { BrowserType } from '@xmorse/playwright-core';
|
|
12
|
+
type Chromium = typeof import('@xmorse/playwright-core').chromium;
|
|
13
|
+
/**
|
|
14
|
+
* Returns the chromium BrowserType, loading from patchright-core if enabled.
|
|
15
|
+
* Caches after first call.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getChromium(): Promise<Chromium>;
|
|
18
|
+
export declare function isPatchrightEnabled(): boolean;
|
|
19
|
+
//# sourceMappingURL=playwright-import.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playwright-import.d.ts","sourceRoot":"","sources":["../src/playwright-import.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,YAAY,EACV,IAAI,EACJ,KAAK,EACL,OAAO,EACP,cAAc,EACd,OAAO,EACP,YAAY,EACZ,aAAa,EACb,UAAU,EACV,gBAAgB,GACjB,MAAM,yBAAyB,CAAA;AAEhC,YAAY,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAE1D,KAAK,QAAQ,GAAG,cAAc,yBAAyB,EAAE,QAAQ,CAAA;AAIjE;;;GAGG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,QAAQ,CAAC,CAqBrD;AAED,wBAAgB,mBAAmB,IAAI,OAAO,CAG7C"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conditional playwright-core import. When patchright mode is enabled via
|
|
3
|
+
* TABWRIGHT_PATCHRIGHT=1 env var, imports from @playwriter/patchright-core
|
|
4
|
+
* instead of @xmorse/playwright-core. Both packages expose identical APIs.
|
|
5
|
+
*
|
|
6
|
+
* Type imports continue to use @xmorse/playwright-core directly (types are
|
|
7
|
+
* the same in both packages) so TypeScript resolution works without the
|
|
8
|
+
* optional patchright dep being installed.
|
|
9
|
+
*/
|
|
10
|
+
let _chromium;
|
|
11
|
+
/**
|
|
12
|
+
* Returns the chromium BrowserType, loading from patchright-core if enabled.
|
|
13
|
+
* Caches after first call.
|
|
14
|
+
*/
|
|
15
|
+
export async function getChromium() {
|
|
16
|
+
if (_chromium) {
|
|
17
|
+
return _chromium;
|
|
18
|
+
}
|
|
19
|
+
if (isPatchrightEnabled()) {
|
|
20
|
+
try {
|
|
21
|
+
// Dynamic import — @playwriter/patchright-core is an optional dependency.
|
|
22
|
+
// Types come from @xmorse/playwright-core (identical API surface).
|
|
23
|
+
const mod = await import('@playwriter/patchright-core');
|
|
24
|
+
_chromium = mod.chromium;
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
throw new Error('@playwriter/patchright-core is not installed. Install it with: pnpm add @playwriter/patchright-core', { cause: e });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
const mod = await import('@xmorse/playwright-core');
|
|
32
|
+
_chromium = mod.chromium;
|
|
33
|
+
}
|
|
34
|
+
return _chromium;
|
|
35
|
+
}
|
|
36
|
+
export function isPatchrightEnabled() {
|
|
37
|
+
const value = process.env.TABWRIGHT_PATCHRIGHT || process.env.PLAYWRITER_PATCHRIGHT;
|
|
38
|
+
return value === '1' || value === 'true';
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=playwright-import.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playwright-import.js","sourceRoot":"","sources":["../src/playwright-import.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAkBH,IAAI,SAA+B,CAAA;AAEnC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,IAAI,mBAAmB,EAAE,EAAE,CAAC;QAC1B,IAAI,CAAC;YACH,0EAA0E;YAC1E,mEAAmE;YACnE,MAAM,GAAG,GAA2B,MAAM,MAAM,CAAC,6BAAuC,CAAC,CAAA;YACzF,SAAS,GAAG,GAAG,CAAC,QAAQ,CAAA;QAC1B,CAAC;QAAC,OAAO,CAAU,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CACb,qGAAqG,EACrG,EAAE,KAAK,EAAE,CAAC,EAAE,CACb,CAAA;QACH,CAAC;IACH,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAA;QACnD,SAAS,GAAG,GAAG,CAAC,QAAQ,CAAA;IAC1B,CAAC;IACD,OAAO,SAAU,CAAA;AACnB,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAA;IACnF,OAAO,KAAK,KAAK,GAAG,IAAI,KAAK,KAAK,MAAM,CAAA;AAC1C,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for auto-relocation of popup windows to tabs.
|
|
3
|
+
* - Connected source tab → popup gets relocated + auto-attached.
|
|
4
|
+
* - No source tab connected → popup is left alone.
|
|
5
|
+
*/
|
|
6
|
+
import './test-declarations.js';
|
|
7
|
+
//# sourceMappingURL=popup-relocation.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"popup-relocation.test.d.ts","sourceRoot":"","sources":["../src/popup-relocation.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAaH,OAAO,wBAAwB,CAAA"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for auto-relocation of popup windows to tabs.
|
|
3
|
+
* - Connected source tab → popup gets relocated + auto-attached.
|
|
4
|
+
* - No source tab connected → popup is left alone.
|
|
5
|
+
*/
|
|
6
|
+
import { createMCPClient } from './mcp-client.js';
|
|
7
|
+
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
8
|
+
import { setupTestContext, cleanupTestContext, getExtensionServiceWorker, createSimpleServer, js, } from './test-utils.js';
|
|
9
|
+
import './test-declarations.js';
|
|
10
|
+
const TEST_PORT = 19995;
|
|
11
|
+
describe('Popup window relocation', () => {
|
|
12
|
+
let client;
|
|
13
|
+
let cleanup = null;
|
|
14
|
+
let testCtx = null;
|
|
15
|
+
let htmlServer = null;
|
|
16
|
+
beforeAll(async () => {
|
|
17
|
+
testCtx = await setupTestContext({
|
|
18
|
+
port: TEST_PORT,
|
|
19
|
+
tempDirPrefix: 'pw-popup-test-',
|
|
20
|
+
toggleExtension: true,
|
|
21
|
+
});
|
|
22
|
+
const result = await createMCPClient({ port: TEST_PORT });
|
|
23
|
+
client = result.client;
|
|
24
|
+
cleanup = result.cleanup;
|
|
25
|
+
htmlServer = await createSimpleServer({
|
|
26
|
+
routes: {
|
|
27
|
+
'/opener': `<!doctype html>
|
|
28
|
+
<html>
|
|
29
|
+
<body>
|
|
30
|
+
<button id="open-popup" onclick="window.open('/target', '', 'width=400,height=300,popup=1')">Open popup</button>
|
|
31
|
+
</body>
|
|
32
|
+
</html>`,
|
|
33
|
+
'/target': `<!doctype html>
|
|
34
|
+
<html>
|
|
35
|
+
<body>
|
|
36
|
+
<h1 id="target-heading">Popup target page</h1>
|
|
37
|
+
</body>
|
|
38
|
+
</html>`,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
}, 600000);
|
|
42
|
+
afterAll(async () => {
|
|
43
|
+
if (htmlServer) {
|
|
44
|
+
await htmlServer.close();
|
|
45
|
+
}
|
|
46
|
+
await cleanupTestContext(testCtx, cleanup);
|
|
47
|
+
cleanup = null;
|
|
48
|
+
testCtx = null;
|
|
49
|
+
});
|
|
50
|
+
it('relocates popup window into main browser context as a tab', async () => {
|
|
51
|
+
if (!htmlServer)
|
|
52
|
+
throw new Error('html server not initialized');
|
|
53
|
+
const browserContext = testCtx.browserContext;
|
|
54
|
+
const serviceWorker = await getExtensionServiceWorker(browserContext);
|
|
55
|
+
await client.callTool({
|
|
56
|
+
name: 'execute',
|
|
57
|
+
arguments: {
|
|
58
|
+
code: js `
|
|
59
|
+
state.popupTestPage = context.pages().find((p) => p.url() === 'about:blank') ?? (await context.newPage());
|
|
60
|
+
await state.popupTestPage.goto('${htmlServer.baseUrl}/opener', { waitUntil: 'domcontentloaded' });
|
|
61
|
+
return { url: state.popupTestPage.url(), pagesBefore: context.pages().length };
|
|
62
|
+
`,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
const clickResult = await client.callTool({
|
|
66
|
+
name: 'execute',
|
|
67
|
+
arguments: {
|
|
68
|
+
code: js `
|
|
69
|
+
await state.popupTestPage.click('#open-popup');
|
|
70
|
+
await state.popupTestPage.waitForTimeout(1500);
|
|
71
|
+
return { pagesAfter: context.pages().length, allUrls: context.pages().map((p) => p.url()) };
|
|
72
|
+
`,
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
const clickOutput = clickResult.content[0].text;
|
|
76
|
+
expect(clickOutput).toContain('/target');
|
|
77
|
+
expect(clickResult.isError).not.toBe(true);
|
|
78
|
+
expect(clickOutput).toContain('[WARNING] New page opened from current page');
|
|
79
|
+
expect(clickOutput).not.toContain('Popup window detected');
|
|
80
|
+
expect(clickOutput).not.toContain('cannot be controlled by playwriter');
|
|
81
|
+
const windowTypes = await serviceWorker.evaluate(async () => {
|
|
82
|
+
const windows = await chrome.windows.getAll({ populate: false });
|
|
83
|
+
return windows.map((w) => w.type);
|
|
84
|
+
});
|
|
85
|
+
expect(windowTypes).not.toContain('popup');
|
|
86
|
+
expect(windowTypes).toContain('normal');
|
|
87
|
+
await client.callTool({
|
|
88
|
+
name: 'execute',
|
|
89
|
+
arguments: {
|
|
90
|
+
code: js `
|
|
91
|
+
const targetPage = context.pages().find((p) => p.url().endsWith('/target'));
|
|
92
|
+
if (targetPage) { await targetPage.close(); }
|
|
93
|
+
await state.popupTestPage.close();
|
|
94
|
+
delete state.popupTestPage;
|
|
95
|
+
`,
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
}, 60000);
|
|
99
|
+
it('leaves popup windows alone when no Tabwright tab is connected', async () => {
|
|
100
|
+
if (!htmlServer)
|
|
101
|
+
throw new Error('html server not initialized');
|
|
102
|
+
const browserContext = testCtx.browserContext;
|
|
103
|
+
const serviceWorker = await getExtensionServiceWorker(browserContext);
|
|
104
|
+
await serviceWorker.evaluate(async () => {
|
|
105
|
+
await globalThis.disconnectEverything();
|
|
106
|
+
});
|
|
107
|
+
await new Promise((r) => {
|
|
108
|
+
setTimeout(r, 200);
|
|
109
|
+
});
|
|
110
|
+
// Drive the browser directly via browserContext (not MCP/extension) so
|
|
111
|
+
// the opener tab stays unconnected.
|
|
112
|
+
const unconnectedPage = await browserContext.newPage();
|
|
113
|
+
await unconnectedPage.goto(`${htmlServer.baseUrl}/opener`, { waitUntil: 'domcontentloaded' });
|
|
114
|
+
await unconnectedPage.bringToFront();
|
|
115
|
+
await unconnectedPage.click('#open-popup');
|
|
116
|
+
// If relocation DID happen, the popup window would be gone by now.
|
|
117
|
+
await new Promise((r) => {
|
|
118
|
+
setTimeout(r, 1500);
|
|
119
|
+
});
|
|
120
|
+
const windowTypes = await serviceWorker.evaluate(async () => {
|
|
121
|
+
const windows = await chrome.windows.getAll({ populate: false });
|
|
122
|
+
return windows.map((w) => w.type);
|
|
123
|
+
});
|
|
124
|
+
expect(windowTypes).toContain('popup');
|
|
125
|
+
const windowIdsToClose = await serviceWorker.evaluate(async () => {
|
|
126
|
+
const windows = await chrome.windows.getAll({ populate: false });
|
|
127
|
+
return windows.filter((w) => w.type === 'popup').map((w) => w.id);
|
|
128
|
+
});
|
|
129
|
+
for (const windowId of windowIdsToClose) {
|
|
130
|
+
if (windowId !== undefined) {
|
|
131
|
+
await serviceWorker.evaluate(async (id) => {
|
|
132
|
+
await chrome.windows.remove(id);
|
|
133
|
+
}, windowId);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
await unconnectedPage.close();
|
|
137
|
+
}, 60000);
|
|
138
|
+
});
|
|
139
|
+
//# sourceMappingURL=popup-relocation.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"popup-relocation.test.js","sourceRoot":"","sources":["../src/popup-relocation.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const TABWRIGHT_DATA_DIR_NAME = ".tabwright";
|
|
2
|
+
export declare const LEGACY_PLAYWRITER_DATA_DIR_NAME = ".playwriter";
|
|
3
|
+
export declare function getTabwrightUserDataDir(options?: {
|
|
4
|
+
homeDir?: string;
|
|
5
|
+
}): string;
|
|
6
|
+
export declare function getTabwrightProjectDataDir(options?: {
|
|
7
|
+
cwd?: string;
|
|
8
|
+
}): string;
|
|
9
|
+
//# sourceMappingURL=product-paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product-paths.d.ts","sourceRoot":"","sources":["../src/product-paths.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,uBAAuB,eAAe,CAAA;AACnD,eAAO,MAAM,+BAA+B,gBAAgB,CAAA;AAE5D,wBAAgB,uBAAuB,CAAC,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,MAAM,CASlF;AAED,wBAAgB,0BAA0B,CAAC,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,MAAM,CASjF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
export const TABWRIGHT_DATA_DIR_NAME = '.tabwright';
|
|
5
|
+
export const LEGACY_PLAYWRITER_DATA_DIR_NAME = '.playwriter';
|
|
6
|
+
export function getTabwrightUserDataDir(options = {}) {
|
|
7
|
+
const homeDir = options.homeDir || os.homedir();
|
|
8
|
+
const currentDir = path.join(homeDir, TABWRIGHT_DATA_DIR_NAME);
|
|
9
|
+
const legacyDir = path.join(homeDir, LEGACY_PLAYWRITER_DATA_DIR_NAME);
|
|
10
|
+
if (!fs.existsSync(currentDir) && fs.existsSync(legacyDir)) {
|
|
11
|
+
return legacyDir;
|
|
12
|
+
}
|
|
13
|
+
return currentDir;
|
|
14
|
+
}
|
|
15
|
+
export function getTabwrightProjectDataDir(options = {}) {
|
|
16
|
+
const cwd = options.cwd || process.cwd();
|
|
17
|
+
const currentDir = path.join(cwd, TABWRIGHT_DATA_DIR_NAME);
|
|
18
|
+
const legacyDir = path.join(cwd, LEGACY_PLAYWRITER_DATA_DIR_NAME);
|
|
19
|
+
if (!fs.existsSync(currentDir) && fs.existsSync(legacyDir)) {
|
|
20
|
+
return legacyDir;
|
|
21
|
+
}
|
|
22
|
+
return currentDir;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=product-paths.js.map
|