tabwright 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aria-snapshot.d.ts +0 -1
- package/dist/aria-snapshot.js +9 -1
- package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts +0 -1
- package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js +0 -1
- package/dist/bippy.js +1 -1
- package/dist/browser-config.d.ts +0 -1
- package/dist/browser-config.js +0 -1
- package/dist/browser-install.d.ts +0 -1
- package/dist/browser-install.js +0 -1
- package/dist/browser-launch.d.ts +0 -1
- package/dist/browser-launch.js +0 -1
- package/dist/builtin-capabilities.d.ts +0 -1
- package/dist/builtin-capabilities.js +0 -1
- package/dist/capability-agent-skill.d.ts +0 -1
- package/dist/capability-agent-skill.js +0 -1
- package/dist/capability-auth-state.d.ts +0 -1
- package/dist/capability-auth-state.js +0 -1
- package/dist/capability-auth.d.ts +0 -1
- package/dist/capability-auth.js +0 -1
- package/dist/capability-options.d.ts +0 -1
- package/dist/capability-options.js +0 -1
- package/dist/capability-package.d.ts +0 -1
- package/dist/capability-package.js +0 -1
- package/dist/capability-registry.d.ts +0 -1
- package/dist/capability-registry.js +0 -1
- package/dist/capability-runner.d.ts +0 -1
- package/dist/capability-runner.js +0 -1
- package/dist/capability-studio.d.ts +0 -1
- package/dist/capability-studio.js +0 -1
- package/dist/cdp-log.d.ts +0 -1
- package/dist/cdp-log.js +0 -1
- package/dist/cdp-relay.d.ts +0 -1
- package/dist/cdp-relay.js +0 -1
- package/dist/cdp-session.d.ts +0 -1
- package/dist/cdp-session.js +0 -1
- package/dist/cdp-types.d.ts +0 -1
- package/dist/cdp-types.js +0 -1
- package/dist/chrome-discovery.d.ts +0 -1
- package/dist/chrome-discovery.js +0 -1
- package/dist/clean-html.d.ts +0 -1
- package/dist/clean-html.js +0 -1
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +9 -2
- package/dist/cloud-client.d.ts +0 -1
- package/dist/cloud-client.js +0 -1
- package/dist/create-logger.d.ts +0 -1
- package/dist/create-logger.js +0 -1
- package/dist/debugger-examples-types.d.ts +0 -1
- package/dist/debugger-examples-types.js +0 -1
- package/dist/debugger-examples.d.ts +0 -1
- package/dist/debugger-examples.js +0 -1
- package/dist/debugger.d.ts +0 -1
- package/dist/debugger.js +0 -1
- package/dist/diff-utils.d.ts +0 -1
- package/dist/diff-utils.js +0 -1
- package/dist/doctor.d.ts +0 -1
- package/dist/doctor.js +5 -7
- package/dist/editor-examples.d.ts +0 -1
- package/dist/editor-examples.js +0 -1
- package/dist/editor.d.ts +0 -1
- package/dist/editor.js +0 -1
- package/dist/env-compat.d.ts +0 -1
- package/dist/env-compat.js +0 -1
- package/dist/executor.d.ts +0 -1
- package/dist/executor.js +1 -2
- package/dist/extension/background.js +7 -3
- package/dist/extension/manifest.json +1 -1
- package/dist/ghost-browser.d.ts +0 -1
- package/dist/ghost-browser.js +0 -1
- package/dist/ghost-cursor-controller.d.ts +0 -1
- package/dist/ghost-cursor-controller.js +0 -1
- package/dist/ghost-cursor.d.ts +0 -1
- package/dist/ghost-cursor.js +0 -1
- package/dist/htmlrewrite.d.ts +0 -1
- package/dist/htmlrewrite.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/kill-port.d.ts +0 -1
- package/dist/kill-port.js +0 -1
- package/dist/kitty-graphics.d.ts +0 -1
- package/dist/kitty-graphics.js +0 -1
- package/dist/mcp.d.ts +0 -1
- package/dist/mcp.js +0 -1
- package/dist/package-paths.d.ts +0 -1
- package/dist/package-paths.js +0 -1
- package/dist/page-markdown.d.ts +0 -1
- package/dist/page-markdown.js +0 -1
- package/dist/performance-examples.d.ts +0 -1
- package/dist/performance-examples.js +0 -1
- package/dist/playwright-import.d.ts +0 -1
- package/dist/playwright-import.js +0 -1
- package/dist/product-paths.d.ts +0 -1
- package/dist/product-paths.js +0 -1
- package/dist/protocol.d.ts +0 -1
- package/dist/protocol.js +0 -1
- package/dist/react-source.d.ts +0 -1
- package/dist/react-source.js +0 -1
- package/dist/readability.js +1 -1
- package/dist/relay-client.d.ts +0 -1
- package/dist/relay-client.js +0 -1
- package/dist/relay-state.d.ts +0 -1
- package/dist/relay-state.js +0 -1
- package/dist/replay-ai-index.d.ts +0 -1
- package/dist/replay-ai-index.js +0 -1
- package/dist/replay-eval.d.ts +0 -1
- package/dist/replay-eval.js +0 -1
- package/dist/replay-handoff.d.ts +0 -1
- package/dist/replay-handoff.js +0 -1
- package/dist/replay-workflow-compiler.d.ts +0 -1
- package/dist/replay-workflow-compiler.js +0 -1
- package/dist/rrweb-recording-relay.d.ts +0 -1
- package/dist/rrweb-recording-relay.js +0 -1
- package/dist/rrweb-recording.d.ts +0 -1
- package/dist/rrweb-recording.js +0 -1
- package/dist/scoped-fs.d.ts +0 -1
- package/dist/scoped-fs.js +0 -1
- package/dist/selector-generator.js +1 -1
- package/dist/start-relay-server.d.ts +0 -1
- package/dist/start-relay-server.js +0 -1
- package/dist/styles-examples.d.ts +0 -1
- package/dist/styles-examples.js +0 -1
- package/dist/styles.d.ts +0 -1
- package/dist/styles.js +0 -1
- package/dist/tabwright-agent-skill.d.ts +0 -1
- package/dist/tabwright-agent-skill.js +0 -1
- package/dist/test-declarations.d.ts +0 -1
- package/dist/test-declarations.js +0 -1
- package/dist/utils.d.ts +0 -1
- package/dist/utils.js +2 -2
- package/dist/wait-for-page-load.d.ts +0 -1
- package/dist/wait-for-page-load.js +0 -1
- package/dist/workflow-capability.d.ts +0 -1
- package/dist/workflow-capability.js +0 -1
- package/package.json +9 -4
- package/readme.md +35 -0
- package/dist/aria-snapshot.d.ts.map +0 -1
- package/dist/aria-snapshot.js.map +0 -1
- package/dist/aria-snapshot.test.d.ts +0 -2
- package/dist/aria-snapshot.test.d.ts.map +0 -1
- package/dist/aria-snapshot.test.js +0 -270
- package/dist/aria-snapshot.test.js.map +0 -1
- package/dist/aria-snapshot.unit.test.d.ts +0 -2
- package/dist/aria-snapshot.unit.test.d.ts.map +0 -1
- package/dist/aria-snapshot.unit.test.js +0 -542
- package/dist/aria-snapshot.unit.test.js.map +0 -1
- package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts.map +0 -1
- package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js.map +0 -1
- package/dist/browser-config.d.ts.map +0 -1
- package/dist/browser-config.js.map +0 -1
- package/dist/browser-install.d.ts.map +0 -1
- package/dist/browser-install.js.map +0 -1
- package/dist/browser-launch.d.ts.map +0 -1
- package/dist/browser-launch.js.map +0 -1
- package/dist/builtin-capabilities.d.ts.map +0 -1
- package/dist/builtin-capabilities.js.map +0 -1
- package/dist/capability-agent-skill.d.ts.map +0 -1
- package/dist/capability-agent-skill.js.map +0 -1
- package/dist/capability-auth-state.d.ts.map +0 -1
- package/dist/capability-auth-state.js.map +0 -1
- package/dist/capability-auth.d.ts.map +0 -1
- package/dist/capability-auth.js.map +0 -1
- package/dist/capability-cli-confirmation.test.d.ts +0 -2
- package/dist/capability-cli-confirmation.test.d.ts.map +0 -1
- package/dist/capability-cli-confirmation.test.js +0 -79
- package/dist/capability-cli-confirmation.test.js.map +0 -1
- package/dist/capability-options.d.ts.map +0 -1
- package/dist/capability-options.js.map +0 -1
- package/dist/capability-options.test.d.ts +0 -2
- package/dist/capability-options.test.d.ts.map +0 -1
- package/dist/capability-options.test.js +0 -81
- package/dist/capability-options.test.js.map +0 -1
- package/dist/capability-package.d.ts.map +0 -1
- package/dist/capability-package.js.map +0 -1
- package/dist/capability-package.test.d.ts +0 -2
- package/dist/capability-package.test.d.ts.map +0 -1
- package/dist/capability-package.test.js +0 -179
- package/dist/capability-package.test.js.map +0 -1
- package/dist/capability-registry.d.ts.map +0 -1
- package/dist/capability-registry.js.map +0 -1
- package/dist/capability-registry.test.d.ts +0 -2
- package/dist/capability-registry.test.d.ts.map +0 -1
- package/dist/capability-registry.test.js +0 -1683
- package/dist/capability-registry.test.js.map +0 -1
- package/dist/capability-runner.d.ts.map +0 -1
- package/dist/capability-runner.js.map +0 -1
- package/dist/capability-search-relevance.test.d.ts +0 -2
- package/dist/capability-search-relevance.test.d.ts.map +0 -1
- package/dist/capability-search-relevance.test.js +0 -67
- package/dist/capability-search-relevance.test.js.map +0 -1
- package/dist/capability-studio.d.ts.map +0 -1
- package/dist/capability-studio.js.map +0 -1
- package/dist/capability-studio.test.d.ts +0 -2
- package/dist/capability-studio.test.d.ts.map +0 -1
- package/dist/capability-studio.test.js +0 -41
- package/dist/capability-studio.test.js.map +0 -1
- package/dist/cdp-log.d.ts.map +0 -1
- package/dist/cdp-log.js.map +0 -1
- package/dist/cdp-log.test.d.ts +0 -2
- package/dist/cdp-log.test.d.ts.map +0 -1
- package/dist/cdp-log.test.js +0 -109
- package/dist/cdp-log.test.js.map +0 -1
- package/dist/cdp-relay.d.ts.map +0 -1
- package/dist/cdp-relay.js.map +0 -1
- package/dist/cdp-session.d.ts.map +0 -1
- package/dist/cdp-session.js.map +0 -1
- package/dist/cdp-types.d.ts.map +0 -1
- package/dist/cdp-types.js.map +0 -1
- package/dist/channel-owner-inspect.test.d.ts +0 -2
- package/dist/channel-owner-inspect.test.d.ts.map +0 -1
- package/dist/channel-owner-inspect.test.js +0 -75
- package/dist/channel-owner-inspect.test.js.map +0 -1
- package/dist/chrome-discovery.d.ts.map +0 -1
- package/dist/chrome-discovery.js.map +0 -1
- package/dist/chrome-discovery.test.d.ts +0 -2
- package/dist/chrome-discovery.test.d.ts.map +0 -1
- package/dist/chrome-discovery.test.js +0 -41
- package/dist/chrome-discovery.test.js.map +0 -1
- package/dist/clean-html.d.ts.map +0 -1
- package/dist/clean-html.js.map +0 -1
- package/dist/cli-help.test.d.ts +0 -2
- package/dist/cli-help.test.d.ts.map +0 -1
- package/dist/cli-help.test.js +0 -98
- package/dist/cli-help.test.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/cloud-client.d.ts.map +0 -1
- package/dist/cloud-client.js.map +0 -1
- package/dist/create-logger.d.ts.map +0 -1
- package/dist/create-logger.js.map +0 -1
- package/dist/debugger-examples-types.d.ts.map +0 -1
- package/dist/debugger-examples-types.js.map +0 -1
- package/dist/debugger-examples.d.ts.map +0 -1
- package/dist/debugger-examples.js.map +0 -1
- package/dist/debugger.d.ts.map +0 -1
- package/dist/debugger.js.map +0 -1
- package/dist/diff-utils.d.ts.map +0 -1
- package/dist/diff-utils.js.map +0 -1
- package/dist/diff-utils.test.d.ts +0 -2
- package/dist/diff-utils.test.d.ts.map +0 -1
- package/dist/diff-utils.test.js +0 -137
- package/dist/diff-utils.test.js.map +0 -1
- package/dist/doctor.d.ts.map +0 -1
- package/dist/doctor.js.map +0 -1
- package/dist/doctor.test.d.ts +0 -2
- package/dist/doctor.test.d.ts.map +0 -1
- package/dist/doctor.test.js +0 -208
- package/dist/doctor.test.js.map +0 -1
- package/dist/editor-examples.d.ts.map +0 -1
- package/dist/editor-examples.js.map +0 -1
- package/dist/editor.d.ts.map +0 -1
- package/dist/editor.js.map +0 -1
- package/dist/env-compat.d.ts.map +0 -1
- package/dist/env-compat.js.map +0 -1
- package/dist/executor.d.ts.map +0 -1
- package/dist/executor.js.map +0 -1
- package/dist/executor.unit.test.d.ts +0 -2
- package/dist/executor.unit.test.d.ts.map +0 -1
- package/dist/executor.unit.test.js +0 -143
- package/dist/executor.unit.test.js.map +0 -1
- package/dist/extension-connection.test.d.ts +0 -2
- package/dist/extension-connection.test.d.ts.map +0 -1
- package/dist/extension-connection.test.js +0 -708
- package/dist/extension-connection.test.js.map +0 -1
- package/dist/extension-icon-warning.test.d.ts +0 -2
- package/dist/extension-icon-warning.test.d.ts.map +0 -1
- package/dist/extension-icon-warning.test.js +0 -33
- package/dist/extension-icon-warning.test.js.map +0 -1
- package/dist/ghost-browser.d.ts.map +0 -1
- package/dist/ghost-browser.js.map +0 -1
- package/dist/ghost-cursor-controller.d.ts.map +0 -1
- package/dist/ghost-cursor-controller.js.map +0 -1
- package/dist/ghost-cursor.d.ts.map +0 -1
- package/dist/ghost-cursor.js.map +0 -1
- package/dist/htmlrewrite.d.ts.map +0 -1
- package/dist/htmlrewrite.js.map +0 -1
- package/dist/htmlrewrite.test.d.ts +0 -2
- package/dist/htmlrewrite.test.d.ts.map +0 -1
- package/dist/htmlrewrite.test.js +0 -7975
- package/dist/htmlrewrite.test.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/kill-port.d.ts.map +0 -1
- package/dist/kill-port.js.map +0 -1
- package/dist/kitty-graphics.d.ts.map +0 -1
- package/dist/kitty-graphics.js.map +0 -1
- package/dist/kitty-graphics.test.d.ts +0 -2
- package/dist/kitty-graphics.test.d.ts.map +0 -1
- package/dist/kitty-graphics.test.js +0 -125
- package/dist/kitty-graphics.test.js.map +0 -1
- package/dist/locator-selector.test.d.ts +0 -2
- package/dist/locator-selector.test.d.ts.map +0 -1
- package/dist/locator-selector.test.js +0 -98
- package/dist/locator-selector.test.js.map +0 -1
- package/dist/mcp-client.d.ts +0 -20
- package/dist/mcp-client.d.ts.map +0 -1
- package/dist/mcp-client.js +0 -56
- package/dist/mcp-client.js.map +0 -1
- package/dist/mcp.d.ts.map +0 -1
- package/dist/mcp.js.map +0 -1
- package/dist/on-mouse-action.test.d.ts +0 -2
- package/dist/on-mouse-action.test.d.ts.map +0 -1
- package/dist/on-mouse-action.test.js +0 -180
- package/dist/on-mouse-action.test.js.map +0 -1
- package/dist/options-page.test.d.ts +0 -2
- package/dist/options-page.test.d.ts.map +0 -1
- package/dist/options-page.test.js +0 -773
- package/dist/options-page.test.js.map +0 -1
- package/dist/package-paths.d.ts.map +0 -1
- package/dist/package-paths.js.map +0 -1
- package/dist/page-markdown.d.ts.map +0 -1
- package/dist/page-markdown.js.map +0 -1
- package/dist/performance-examples.d.ts.map +0 -1
- package/dist/performance-examples.js.map +0 -1
- package/dist/playwright-import.d.ts.map +0 -1
- package/dist/playwright-import.js.map +0 -1
- package/dist/popup-relocation.test.d.ts +0 -7
- package/dist/popup-relocation.test.d.ts.map +0 -1
- package/dist/popup-relocation.test.js +0 -139
- package/dist/popup-relocation.test.js.map +0 -1
- package/dist/product-paths.d.ts.map +0 -1
- package/dist/product-paths.js.map +0 -1
- package/dist/product-paths.test.d.ts +0 -2
- package/dist/product-paths.test.d.ts.map +0 -1
- package/dist/product-paths.test.js +0 -39
- package/dist/product-paths.test.js.map +0 -1
- package/dist/protocol.d.ts.map +0 -1
- package/dist/protocol.js.map +0 -1
- package/dist/protocol.test.d.ts +0 -2
- package/dist/protocol.test.d.ts.map +0 -1
- package/dist/protocol.test.js +0 -31
- package/dist/protocol.test.js.map +0 -1
- package/dist/react-source.d.ts.map +0 -1
- package/dist/react-source.js.map +0 -1
- package/dist/relay-client.d.ts.map +0 -1
- package/dist/relay-client.js.map +0 -1
- package/dist/relay-client.test.d.ts +0 -2
- package/dist/relay-client.test.d.ts.map +0 -1
- package/dist/relay-client.test.js +0 -305
- package/dist/relay-client.test.js.map +0 -1
- package/dist/relay-core.test.d.ts +0 -2
- package/dist/relay-core.test.d.ts.map +0 -1
- package/dist/relay-core.test.js +0 -1427
- package/dist/relay-core.test.js.map +0 -1
- package/dist/relay-navigation.test.d.ts +0 -2
- package/dist/relay-navigation.test.d.ts.map +0 -1
- package/dist/relay-navigation.test.js +0 -661
- package/dist/relay-navigation.test.js.map +0 -1
- package/dist/relay-session.test.d.ts +0 -2
- package/dist/relay-session.test.d.ts.map +0 -1
- package/dist/relay-session.test.js +0 -1121
- package/dist/relay-session.test.js.map +0 -1
- package/dist/relay-state.d.ts.map +0 -1
- package/dist/relay-state.js.map +0 -1
- package/dist/relay-state.test.d.ts +0 -2
- package/dist/relay-state.test.d.ts.map +0 -1
- package/dist/relay-state.test.js +0 -594
- package/dist/relay-state.test.js.map +0 -1
- package/dist/replay-ai-index.d.ts.map +0 -1
- package/dist/replay-ai-index.js.map +0 -1
- package/dist/replay-ai-index.test.d.ts +0 -2
- package/dist/replay-ai-index.test.d.ts.map +0 -1
- package/dist/replay-ai-index.test.js +0 -255
- package/dist/replay-ai-index.test.js.map +0 -1
- package/dist/replay-cli.test.d.ts +0 -2
- package/dist/replay-cli.test.d.ts.map +0 -1
- package/dist/replay-cli.test.js +0 -275
- package/dist/replay-cli.test.js.map +0 -1
- package/dist/replay-eval.d.ts.map +0 -1
- package/dist/replay-eval.js.map +0 -1
- package/dist/replay-handoff.d.ts.map +0 -1
- package/dist/replay-handoff.js.map +0 -1
- package/dist/replay-handoff.test.d.ts +0 -2
- package/dist/replay-handoff.test.d.ts.map +0 -1
- package/dist/replay-handoff.test.js +0 -123
- package/dist/replay-handoff.test.js.map +0 -1
- package/dist/replay-workflow-compiler.d.ts.map +0 -1
- package/dist/replay-workflow-compiler.js.map +0 -1
- package/dist/replay-workflow-compiler.test.d.ts +0 -2
- package/dist/replay-workflow-compiler.test.d.ts.map +0 -1
- package/dist/replay-workflow-compiler.test.js +0 -223
- package/dist/replay-workflow-compiler.test.js.map +0 -1
- package/dist/rrweb-recording-relay.d.ts.map +0 -1
- package/dist/rrweb-recording-relay.js.map +0 -1
- package/dist/rrweb-recording-relay.test.d.ts +0 -2
- package/dist/rrweb-recording-relay.test.d.ts.map +0 -1
- package/dist/rrweb-recording-relay.test.js +0 -85
- package/dist/rrweb-recording-relay.test.js.map +0 -1
- package/dist/rrweb-recording.d.ts.map +0 -1
- package/dist/rrweb-recording.js.map +0 -1
- package/dist/scoped-fs.d.ts.map +0 -1
- package/dist/scoped-fs.js.map +0 -1
- package/dist/scoped-fs.test.d.ts +0 -5
- package/dist/scoped-fs.test.d.ts.map +0 -1
- package/dist/scoped-fs.test.js +0 -73
- package/dist/scoped-fs.test.js.map +0 -1
- package/dist/skill-stub.test.d.ts +0 -2
- package/dist/skill-stub.test.d.ts.map +0 -1
- package/dist/skill-stub.test.js +0 -22
- package/dist/skill-stub.test.js.map +0 -1
- package/dist/snapshot-tools.test.d.ts +0 -2
- package/dist/snapshot-tools.test.d.ts.map +0 -1
- package/dist/snapshot-tools.test.js +0 -856
- package/dist/snapshot-tools.test.js.map +0 -1
- package/dist/start-relay-server.d.ts.map +0 -1
- package/dist/start-relay-server.js.map +0 -1
- package/dist/styles-examples.d.ts.map +0 -1
- package/dist/styles-examples.js.map +0 -1
- package/dist/styles.d.ts.map +0 -1
- package/dist/styles.js.map +0 -1
- package/dist/tabwright-agent-skill.d.ts.map +0 -1
- package/dist/tabwright-agent-skill.js.map +0 -1
- package/dist/tabwright-agent-skill.test.d.ts +0 -2
- package/dist/tabwright-agent-skill.test.d.ts.map +0 -1
- package/dist/tabwright-agent-skill.test.js +0 -51
- package/dist/tabwright-agent-skill.test.js.map +0 -1
- package/dist/test-declarations.d.ts.map +0 -1
- package/dist/test-declarations.js.map +0 -1
- package/dist/test-utils.d.ts +0 -69
- package/dist/test-utils.d.ts.map +0 -1
- package/dist/test-utils.js +0 -448
- package/dist/test-utils.js.map +0 -1
- package/dist/test-utils.test.d.ts +0 -2
- package/dist/test-utils.test.d.ts.map +0 -1
- package/dist/test-utils.test.js +0 -55
- package/dist/test-utils.test.js.map +0 -1
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js.map +0 -1
- package/dist/wait-for-page-load.d.ts.map +0 -1
- package/dist/wait-for-page-load.js.map +0 -1
- package/dist/workflow-capability.d.ts.map +0 -1
- package/dist/workflow-capability.js.map +0 -1
- package/dist/workflow-script-flow.test.d.ts +0 -2
- package/dist/workflow-script-flow.test.d.ts.map +0 -1
- package/dist/workflow-script-flow.test.js +0 -285
- package/dist/workflow-script-flow.test.js.map +0 -1
- package/src/__snapshots__/x.com.processed.html +0 -1003
- package/src/__snapshots__/x.com.processed.withStyles.html +0 -2720
- package/src/a11y-client.ts +0 -241
- package/src/aria-snapshot.test.ts +0 -311
- package/src/aria-snapshot.ts +0 -1681
- package/src/aria-snapshot.unit.test.ts +0 -615
- package/src/aria-snapshots/github-interactive.txt +0 -193
- package/src/aria-snapshots/github-raw.txt +0 -309
- package/src/aria-snapshots/hackernews-interactive.txt +0 -477
- package/src/aria-snapshots/hackernews-raw.txt +0 -428
- package/src/aria-snapshots/prosemirror-interactive.txt +0 -66
- package/src/aria-snapshots/prosemirror-raw.txt +0 -145
- 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 +0 -5
- package/src/assets/cursors/screen-studio/pointer-macos-tahoe.svg +0 -18
- package/src/assets/x.com.html +0 -32946
- package/src/browser-config.ts +0 -179
- package/src/browser-install.ts +0 -284
- package/src/browser-launch.ts +0 -75
- package/src/builtin-capabilities.ts +0 -2765
- package/src/capability-agent-skill.ts +0 -305
- package/src/capability-auth-state.ts +0 -197
- package/src/capability-auth.ts +0 -249
- package/src/capability-cli-confirmation.test.ts +0 -90
- package/src/capability-options.test.ts +0 -89
- package/src/capability-options.ts +0 -57
- package/src/capability-package.test.ts +0 -204
- package/src/capability-package.ts +0 -555
- package/src/capability-registry.test.ts +0 -1905
- package/src/capability-registry.ts +0 -1234
- package/src/capability-runner.ts +0 -801
- package/src/capability-search-relevance.test.ts +0 -73
- package/src/capability-studio.test.ts +0 -45
- package/src/capability-studio.ts +0 -641
- package/src/cdp-log.test.ts +0 -131
- package/src/cdp-log.ts +0 -112
- package/src/cdp-relay.ts +0 -2944
- package/src/cdp-session.ts +0 -77
- package/src/cdp-types.ts +0 -158
- package/src/channel-owner-inspect.test.ts +0 -94
- package/src/chrome-discovery.test.ts +0 -50
- package/src/chrome-discovery.ts +0 -220
- package/src/clean-html.ts +0 -141
- package/src/cli-help.test.ts +0 -123
- package/src/cli.ts +0 -3181
- package/src/cloud-client.ts +0 -179
- package/src/create-logger.ts +0 -38
- package/src/debugger-examples-types.ts +0 -16
- package/src/debugger-examples.ts +0 -66
- package/src/debugger.ts +0 -708
- package/src/diff-utils.test.ts +0 -152
- package/src/diff-utils.ts +0 -70
- package/src/doctor.test.ts +0 -244
- package/src/doctor.ts +0 -321
- package/src/editor-examples.ts +0 -158
- package/src/editor.ts +0 -426
- package/src/env-compat.ts +0 -28
- package/src/executor.ts +0 -1824
- package/src/executor.unit.test.ts +0 -168
- package/src/extension-connection.test.ts +0 -855
- package/src/extension-icon-warning.test.ts +0 -45
- package/src/ghost-browser.ts +0 -149
- package/src/ghost-cursor-client.ts +0 -494
- package/src/ghost-cursor-controller.ts +0 -129
- package/src/ghost-cursor.ts +0 -123
- package/src/htmlrewrite.test.ts +0 -8008
- package/src/htmlrewrite.ts +0 -390
- package/src/index.ts +0 -53
- package/src/kill-port.ts +0 -219
- package/src/kitty-graphics.test.ts +0 -139
- package/src/kitty-graphics.ts +0 -79
- package/src/locator-selector.test.ts +0 -119
- package/src/mcp-client.ts +0 -78
- package/src/mcp.ts +0 -629
- package/src/on-mouse-action.test.ts +0 -226
- package/src/options-page.test.ts +0 -839
- package/src/package-paths.ts +0 -38
- package/src/page-markdown.ts +0 -240
- package/src/performance-examples.ts +0 -186
- package/src/playwright-import.ts +0 -59
- package/src/popup-relocation.test.ts +0 -163
- package/src/product-paths.test.ts +0 -47
- package/src/product-paths.ts +0 -28
- package/src/protocol.test.ts +0 -52
- package/src/protocol.ts +0 -351
- package/src/react-source.ts +0 -379
- package/src/relay-client.test.ts +0 -375
- package/src/relay-client.ts +0 -572
- package/src/relay-core.test.ts +0 -1603
- package/src/relay-navigation.test.ts +0 -790
- package/src/relay-session.test.ts +0 -1375
- package/src/relay-state.test.ts +0 -729
- package/src/relay-state.ts +0 -561
- package/src/replay-ai-index.test.ts +0 -278
- package/src/replay-ai-index.ts +0 -872
- package/src/replay-cli.test.ts +0 -325
- package/src/replay-eval.ts +0 -1039
- package/src/replay-handoff.test.ts +0 -163
- package/src/replay-handoff.ts +0 -109
- package/src/replay-workflow-compiler.test.ts +0 -250
- package/src/replay-workflow-compiler.ts +0 -700
- package/src/resource.md +0 -409
- package/src/rrweb-recording-relay.test.ts +0 -99
- package/src/rrweb-recording-relay.ts +0 -400
- package/src/rrweb-recording.ts +0 -322
- package/src/scoped-fs.test.ts +0 -80
- package/src/scoped-fs.ts +0 -420
- package/src/skill-stub.test.ts +0 -24
- package/src/snapshot-tools.test.ts +0 -1017
- package/src/snapshots/hacker-news-accessibility-full.md +0 -81
- package/src/snapshots/hacker-news-accessibility-interactive.md +0 -43
- package/src/snapshots/page-markdown-output.txt +0 -16
- package/src/snapshots/shadcn-ui-accessibility-full.md +0 -201
- package/src/snapshots/shadcn-ui-accessibility-interactive.md +0 -109
- package/src/start-relay-server.ts +0 -69
- package/src/styles-examples.ts +0 -84
- package/src/styles.ts +0 -343
- package/src/tabwright-agent-skill.test.ts +0 -61
- package/src/tabwright-agent-skill.ts +0 -105
- package/src/test-declarations.ts +0 -13
- package/src/test-utils.test.ts +0 -70
- package/src/test-utils.ts +0 -566
- package/src/utils.ts +0 -78
- package/src/wait-for-page-load.ts +0 -198
- package/src/workflow-capability.ts +0 -417
- package/src/workflow-script-flow.test.ts +0 -388
|
@@ -1,700 +0,0 @@
|
|
|
1
|
-
import { getSavedRrwebRecordingWithEvents } from './rrweb-recording-relay.js'
|
|
2
|
-
import { buildReplayAiIndex } from './replay-ai-index.js'
|
|
3
|
-
import { saveWorkflowCapability, type SavedWorkflowCapability } from './workflow-capability.js'
|
|
4
|
-
import type { RrwebEvent } from './protocol.js'
|
|
5
|
-
|
|
6
|
-
type ReplayNodeType = 2 | 3
|
|
7
|
-
|
|
8
|
-
interface ReplayDomNode {
|
|
9
|
-
id: number
|
|
10
|
-
type: ReplayNodeType
|
|
11
|
-
tagName?: string
|
|
12
|
-
textContent?: string
|
|
13
|
-
attributes: Record<string, string>
|
|
14
|
-
childIds: number[]
|
|
15
|
-
parentId?: number
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface ReplayClick {
|
|
19
|
-
timestamp: number
|
|
20
|
-
nodeId: number
|
|
21
|
-
text: string
|
|
22
|
-
tagName?: string
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
interface ReplayInput {
|
|
26
|
-
timestamp: number
|
|
27
|
-
nodeId: number
|
|
28
|
-
value: string
|
|
29
|
-
tagName?: string
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface ReplayWorkflowAnalysis {
|
|
33
|
-
replayId: string
|
|
34
|
-
url?: string
|
|
35
|
-
demonstratedValue?: string
|
|
36
|
-
clickedTexts: string[]
|
|
37
|
-
inputValues: string[]
|
|
38
|
-
annotations: Array<{
|
|
39
|
-
text: string
|
|
40
|
-
target?: string
|
|
41
|
-
selectorHints: string[]
|
|
42
|
-
}>
|
|
43
|
-
actionKind: 'list-append' | 'unknown'
|
|
44
|
-
draftDialogAction?: 'continue' | 'restart'
|
|
45
|
-
confidence: 'low' | 'medium' | 'high'
|
|
46
|
-
reasons: string[]
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface CompileReplayWorkflowOptions {
|
|
50
|
-
replayId: string
|
|
51
|
-
id: string
|
|
52
|
-
title?: string
|
|
53
|
-
description?: string
|
|
54
|
-
cwd?: string
|
|
55
|
-
overwrite?: boolean
|
|
56
|
-
valueInputPath?: string
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export interface CompiledReplayWorkflow {
|
|
60
|
-
analysis: ReplayWorkflowAnalysis
|
|
61
|
-
saved: SavedWorkflowCapability
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export class UnsupportedReplayWorkflowError extends Error {
|
|
65
|
-
readonly analysis: ReplayWorkflowAnalysis
|
|
66
|
-
|
|
67
|
-
constructor(options: { analysis: ReplayWorkflowAnalysis }) {
|
|
68
|
-
super(`Replay compiler could not infer a supported workflow: ${options.analysis.reasons.join(' ')}`)
|
|
69
|
-
this.name = 'UnsupportedReplayWorkflowError'
|
|
70
|
-
this.analysis = options.analysis
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
75
|
-
return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function optionalString(value: unknown): string | undefined {
|
|
79
|
-
return typeof value === 'string' && value.trim() ? value : undefined
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function numberValue(value: unknown): number | undefined {
|
|
83
|
-
return typeof value === 'number' && Number.isFinite(value) ? value : undefined
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function normalizeText(value: string | undefined): string {
|
|
87
|
-
return (value || '').replace(/\s+/g, ' ').trim()
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function recordToStringMap(value: unknown): Record<string, string> {
|
|
91
|
-
if (!isRecord(value)) {
|
|
92
|
-
return {}
|
|
93
|
-
}
|
|
94
|
-
return Object.fromEntries(
|
|
95
|
-
Object.entries(value)
|
|
96
|
-
.map(([key, item]) => {
|
|
97
|
-
if (typeof item === 'string') {
|
|
98
|
-
return [key, item] as const
|
|
99
|
-
}
|
|
100
|
-
if (isRecord(item)) {
|
|
101
|
-
return [key, JSON.stringify(item)] as const
|
|
102
|
-
}
|
|
103
|
-
return null
|
|
104
|
-
})
|
|
105
|
-
.filter((entry): entry is readonly [string, string] => {
|
|
106
|
-
return Boolean(entry)
|
|
107
|
-
}),
|
|
108
|
-
)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function getEventType(event: RrwebEvent): number | undefined {
|
|
112
|
-
return numberValue(event.type)
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function getEventTimestamp(event: RrwebEvent): number {
|
|
116
|
-
return numberValue(event.timestamp) || 0
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function getEventData(event: RrwebEvent): Record<string, unknown> {
|
|
120
|
-
return isRecord(event.data) ? event.data : {}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function getNodeId(value: unknown): number | undefined {
|
|
124
|
-
return numberValue(isRecord(value) ? value.id : undefined)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function readReplayNode(rawNode: unknown, parentId?: number): ReplayDomNode | null {
|
|
128
|
-
if (!isRecord(rawNode)) {
|
|
129
|
-
return null
|
|
130
|
-
}
|
|
131
|
-
const id = numberValue(rawNode.id)
|
|
132
|
-
const type = numberValue(rawNode.type)
|
|
133
|
-
if (!id || (type !== 2 && type !== 3)) {
|
|
134
|
-
return null
|
|
135
|
-
}
|
|
136
|
-
const childNodes = Array.isArray(rawNode.childNodes) ? rawNode.childNodes : []
|
|
137
|
-
return {
|
|
138
|
-
id,
|
|
139
|
-
type,
|
|
140
|
-
tagName: optionalString(rawNode.tagName)?.toLowerCase(),
|
|
141
|
-
textContent: optionalString(rawNode.textContent),
|
|
142
|
-
attributes: recordToStringMap(rawNode.attributes),
|
|
143
|
-
childIds: childNodes
|
|
144
|
-
.map((child) => {
|
|
145
|
-
return getNodeId(child)
|
|
146
|
-
})
|
|
147
|
-
.filter((nodeId): nodeId is number => {
|
|
148
|
-
return nodeId !== undefined
|
|
149
|
-
}),
|
|
150
|
-
parentId,
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function addReplayNode(nodes: Map<number, ReplayDomNode>, rawNode: unknown, parentId?: number): void {
|
|
155
|
-
const node = readReplayNode(rawNode, parentId)
|
|
156
|
-
const childNodes = isRecord(rawNode) && Array.isArray(rawNode.childNodes) ? rawNode.childNodes : []
|
|
157
|
-
if (!node && childNodes.length === 0) {
|
|
158
|
-
return
|
|
159
|
-
}
|
|
160
|
-
if (!node) {
|
|
161
|
-
childNodes.forEach((child) => {
|
|
162
|
-
addReplayNode(nodes, child, parentId)
|
|
163
|
-
})
|
|
164
|
-
return
|
|
165
|
-
}
|
|
166
|
-
nodes.set(node.id, node)
|
|
167
|
-
childNodes.forEach((child) => {
|
|
168
|
-
addReplayNode(nodes, child, node.id)
|
|
169
|
-
})
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function removeReplayNode(nodes: Map<number, ReplayDomNode>, nodeId: number): void {
|
|
173
|
-
const node = nodes.get(nodeId)
|
|
174
|
-
if (!node) {
|
|
175
|
-
return
|
|
176
|
-
}
|
|
177
|
-
node.childIds.forEach((childId) => {
|
|
178
|
-
removeReplayNode(nodes, childId)
|
|
179
|
-
})
|
|
180
|
-
nodes.delete(nodeId)
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
function applyMutationEvent(nodes: Map<number, ReplayDomNode>, data: Record<string, unknown>): void {
|
|
184
|
-
const removes = Array.isArray(data.removes) ? data.removes : []
|
|
185
|
-
removes
|
|
186
|
-
.map((remove) => {
|
|
187
|
-
return isRecord(remove) ? numberValue(remove.id) : undefined
|
|
188
|
-
})
|
|
189
|
-
.filter((nodeId): nodeId is number => {
|
|
190
|
-
return nodeId !== undefined
|
|
191
|
-
})
|
|
192
|
-
.forEach((nodeId) => {
|
|
193
|
-
removeReplayNode(nodes, nodeId)
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
const adds = Array.isArray(data.adds) ? data.adds : []
|
|
197
|
-
adds.forEach((add) => {
|
|
198
|
-
if (!isRecord(add)) {
|
|
199
|
-
return
|
|
200
|
-
}
|
|
201
|
-
const parentId = numberValue(add.parentId)
|
|
202
|
-
addReplayNode(nodes, add.node, parentId)
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
const texts = Array.isArray(data.texts) ? data.texts : []
|
|
206
|
-
texts.forEach((text) => {
|
|
207
|
-
if (!isRecord(text)) {
|
|
208
|
-
return
|
|
209
|
-
}
|
|
210
|
-
const nodeId = numberValue(text.id)
|
|
211
|
-
const node = nodeId === undefined ? undefined : nodes.get(nodeId)
|
|
212
|
-
if (!node) {
|
|
213
|
-
return
|
|
214
|
-
}
|
|
215
|
-
node.textContent = optionalString(text.value) || ''
|
|
216
|
-
})
|
|
217
|
-
|
|
218
|
-
const attributes = Array.isArray(data.attributes) ? data.attributes : []
|
|
219
|
-
attributes.forEach((attribute) => {
|
|
220
|
-
if (!isRecord(attribute)) {
|
|
221
|
-
return
|
|
222
|
-
}
|
|
223
|
-
const nodeId = numberValue(attribute.id)
|
|
224
|
-
const node = nodeId === undefined ? undefined : nodes.get(nodeId)
|
|
225
|
-
if (!node) {
|
|
226
|
-
return
|
|
227
|
-
}
|
|
228
|
-
node.attributes = {
|
|
229
|
-
...node.attributes,
|
|
230
|
-
...recordToStringMap(attribute.attributes),
|
|
231
|
-
}
|
|
232
|
-
})
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function nodeText(nodes: Map<number, ReplayDomNode>, nodeId: number): string {
|
|
236
|
-
const node = nodes.get(nodeId)
|
|
237
|
-
if (!node) {
|
|
238
|
-
return ''
|
|
239
|
-
}
|
|
240
|
-
const childText = node.childIds
|
|
241
|
-
.map((childId) => {
|
|
242
|
-
return nodeText(nodes, childId)
|
|
243
|
-
})
|
|
244
|
-
.filter((text) => {
|
|
245
|
-
return text.length > 0
|
|
246
|
-
})
|
|
247
|
-
.join(' ')
|
|
248
|
-
return normalizeText([node.textContent, childText].filter(Boolean).join(' '))
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
function nodeAndAncestors(nodes: Map<number, ReplayDomNode>, nodeId: number, maxDepth: number): ReplayDomNode[] {
|
|
252
|
-
const current = nodes.get(nodeId)
|
|
253
|
-
if (!current) {
|
|
254
|
-
return []
|
|
255
|
-
}
|
|
256
|
-
const ancestors: ReplayDomNode[] = [current]
|
|
257
|
-
let next = current.parentId === undefined ? undefined : nodes.get(current.parentId)
|
|
258
|
-
let depth = 1
|
|
259
|
-
while (next && depth < maxDepth) {
|
|
260
|
-
ancestors.push(next)
|
|
261
|
-
next = next.parentId === undefined ? undefined : nodes.get(next.parentId)
|
|
262
|
-
depth += 1
|
|
263
|
-
}
|
|
264
|
-
return ancestors
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function actionLabelFromText(value: string): string | undefined {
|
|
268
|
-
const text = normalizeText(value)
|
|
269
|
-
if (!text || text.length > 80) {
|
|
270
|
-
return undefined
|
|
271
|
-
}
|
|
272
|
-
if (/to pick up a draggable item/i.test(text)) {
|
|
273
|
-
return undefined
|
|
274
|
-
}
|
|
275
|
-
const matchers: Array<{ label: string; pattern: RegExp }> = [
|
|
276
|
-
{ label: '重新编辑', pattern: /重新编辑/ },
|
|
277
|
-
{ label: '继续编辑', pattern: /继续编辑/ },
|
|
278
|
-
{ label: 'Add entry', pattern: /add entry/i },
|
|
279
|
-
{ label: '新增', pattern: /新增|添加/ },
|
|
280
|
-
{ label: '提交', pattern: /提交|submit/i },
|
|
281
|
-
{ label: 'OK', pattern: /\bOK\b|确定/ },
|
|
282
|
-
{ label: 'Cancel', pattern: /cancel|取消/i },
|
|
283
|
-
{ label: '编辑', pattern: /编辑|\bedit\b/i },
|
|
284
|
-
]
|
|
285
|
-
return matchers.find((matcher) => {
|
|
286
|
-
return matcher.pattern.test(text)
|
|
287
|
-
})?.label
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
function clickLabelFromStructure(nodes: Map<number, ReplayDomNode>, nodeId: number): string | undefined {
|
|
291
|
-
const ancestors = nodeAndAncestors(nodes, nodeId, 8)
|
|
292
|
-
const classText = ancestors
|
|
293
|
-
.map((node) => {
|
|
294
|
-
return node.attributes.class || ''
|
|
295
|
-
})
|
|
296
|
-
.join(' ')
|
|
297
|
-
const inModal = classText.includes('designer-modal')
|
|
298
|
-
if (classText.includes('designer-formily-array-base-addition')) {
|
|
299
|
-
return 'Add entry'
|
|
300
|
-
}
|
|
301
|
-
if (inModal && classText.includes('designer-btn-dangerous')) {
|
|
302
|
-
return '重新编辑'
|
|
303
|
-
}
|
|
304
|
-
if (inModal && classText.includes('designer-btn-primary')) {
|
|
305
|
-
return 'OK'
|
|
306
|
-
}
|
|
307
|
-
return undefined
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
function nearestText(nodes: Map<number, ReplayDomNode>, nodeId: number): string {
|
|
311
|
-
const structuredLabel = clickLabelFromStructure(nodes, nodeId)
|
|
312
|
-
if (structuredLabel) {
|
|
313
|
-
return structuredLabel
|
|
314
|
-
}
|
|
315
|
-
const candidates = nodeAndAncestors(nodes, nodeId, 8)
|
|
316
|
-
.map((node) => {
|
|
317
|
-
return nodeText(nodes, node.id)
|
|
318
|
-
})
|
|
319
|
-
.filter((text) => {
|
|
320
|
-
return text.length > 0
|
|
321
|
-
})
|
|
322
|
-
const actionLabel = candidates
|
|
323
|
-
.map((text) => {
|
|
324
|
-
return actionLabelFromText(text)
|
|
325
|
-
})
|
|
326
|
-
.find((label) => {
|
|
327
|
-
return Boolean(label)
|
|
328
|
-
})
|
|
329
|
-
if (actionLabel) {
|
|
330
|
-
return actionLabel
|
|
331
|
-
}
|
|
332
|
-
return ''
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
function uniqueStrings(values: string[]): string[] {
|
|
336
|
-
return Array.from(new Set(values.filter((value) => {
|
|
337
|
-
return value.length > 0
|
|
338
|
-
})))
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
function lastNonEmpty(values: string[]): string | undefined {
|
|
342
|
-
return values
|
|
343
|
-
.slice()
|
|
344
|
-
.reverse()
|
|
345
|
-
.find((value) => {
|
|
346
|
-
return value.length > 0
|
|
347
|
-
})
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
function detectActionKind(options: { clickedTexts: string[]; inputValues: string[] }): ReplayWorkflowAnalysis['actionKind'] {
|
|
351
|
-
const clicked = options.clickedTexts.join('\n').toLowerCase()
|
|
352
|
-
const hasAdd = clicked.includes('add entry') || clicked.includes('新增') || clicked.includes('添加')
|
|
353
|
-
const hasSubmit = clicked.includes('提交') || clicked.includes('submit')
|
|
354
|
-
if (hasAdd && hasSubmit && lastNonEmpty(options.inputValues)) {
|
|
355
|
-
return 'list-append'
|
|
356
|
-
}
|
|
357
|
-
return 'unknown'
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
function isWorkflowClickLabel(value: string): boolean {
|
|
361
|
-
return /编辑|重新编辑|继续编辑|\bedit\b|add entry|新增|添加|提交|submit|\bOK\b|确定|cancel|取消/i.test(value)
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
export function analyzeReplayWorkflow(options: {
|
|
365
|
-
replayId: string
|
|
366
|
-
url?: string
|
|
367
|
-
events: RrwebEvent[]
|
|
368
|
-
}): ReplayWorkflowAnalysis {
|
|
369
|
-
const aiIndex = buildReplayAiIndex(options)
|
|
370
|
-
const clickedTexts = uniqueStrings(
|
|
371
|
-
aiIndex.actions
|
|
372
|
-
.filter((action) => {
|
|
373
|
-
return action.kind === 'click' && isWorkflowClickLabel(action.label)
|
|
374
|
-
})
|
|
375
|
-
.map((action) => {
|
|
376
|
-
return action.label
|
|
377
|
-
}),
|
|
378
|
-
)
|
|
379
|
-
const inputValues = uniqueStrings(
|
|
380
|
-
aiIndex.actions
|
|
381
|
-
.filter((action) => {
|
|
382
|
-
return action.kind === 'input'
|
|
383
|
-
})
|
|
384
|
-
.map((action) => {
|
|
385
|
-
return normalizeText(action.value)
|
|
386
|
-
}),
|
|
387
|
-
)
|
|
388
|
-
const actionKind = detectActionKind({ clickedTexts, inputValues })
|
|
389
|
-
const demonstratedValue = lastNonEmpty(inputValues)
|
|
390
|
-
const annotations = aiIndex.annotations.map((annotation) => {
|
|
391
|
-
return {
|
|
392
|
-
text: annotation.text,
|
|
393
|
-
target: annotation.target?.label || annotation.target?.text || annotation.target?.tagName,
|
|
394
|
-
selectorHints: annotation.target?.selectorHints || [],
|
|
395
|
-
}
|
|
396
|
-
})
|
|
397
|
-
const draftDialogAction = clickedTexts.some((text) => {
|
|
398
|
-
return text.includes('重新编辑')
|
|
399
|
-
})
|
|
400
|
-
? 'restart'
|
|
401
|
-
: clickedTexts.some((text) => {
|
|
402
|
-
return text.includes('继续编辑')
|
|
403
|
-
})
|
|
404
|
-
? 'continue'
|
|
405
|
-
: undefined
|
|
406
|
-
const reasons = [
|
|
407
|
-
clickedTexts.length > 0 ? `Observed clicks: ${clickedTexts.join(' -> ')}` : 'No click text could be inferred.',
|
|
408
|
-
demonstratedValue ? `Observed final input value: ${demonstratedValue}` : 'No final input value could be inferred.',
|
|
409
|
-
annotations.length > 0 ? `Observed user annotations: ${annotations.map((annotation) => {
|
|
410
|
-
return annotation.text
|
|
411
|
-
}).join(' | ')}` : 'No user annotations were recorded.',
|
|
412
|
-
actionKind === 'list-append' ? 'Detected list append pattern.' : 'Could not classify the replay into a known workflow template.',
|
|
413
|
-
]
|
|
414
|
-
return {
|
|
415
|
-
replayId: options.replayId,
|
|
416
|
-
url: options.url,
|
|
417
|
-
demonstratedValue,
|
|
418
|
-
clickedTexts,
|
|
419
|
-
inputValues,
|
|
420
|
-
annotations,
|
|
421
|
-
actionKind,
|
|
422
|
-
draftDialogAction,
|
|
423
|
-
confidence: actionKind === 'list-append' && demonstratedValue ? 'high' : clickedTexts.length > 0 ? 'medium' : 'low',
|
|
424
|
-
reasons,
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
function literal(value: unknown): string {
|
|
429
|
-
return JSON.stringify(value, null, 2)
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
function buildListAppendScript(analysis: ReplayWorkflowAnalysis, options: CompileReplayWorkflowOptions): string {
|
|
433
|
-
const valueInputPath = options.valueInputPath || 'value'
|
|
434
|
-
const replayUrl = analysis.url || ''
|
|
435
|
-
const pageKey = (() => {
|
|
436
|
-
if (!replayUrl) {
|
|
437
|
-
return ''
|
|
438
|
-
}
|
|
439
|
-
try {
|
|
440
|
-
const url = new URL(replayUrl)
|
|
441
|
-
const directKey = url.searchParams.get('key')
|
|
442
|
-
if (directKey) {
|
|
443
|
-
return directKey
|
|
444
|
-
}
|
|
445
|
-
const hashQuery = url.hash.includes('?') ? url.hash.slice(url.hash.indexOf('?') + 1) : ''
|
|
446
|
-
return new URLSearchParams(hashQuery).get('key') || ''
|
|
447
|
-
} catch {
|
|
448
|
-
return ''
|
|
449
|
-
}
|
|
450
|
-
})()
|
|
451
|
-
const draftDialogAction = analysis.draftDialogAction || 'restart'
|
|
452
|
-
return [
|
|
453
|
-
'// Generated by replayWorkflow.compile: execute the inferred user flow first, return needs_ai on drift.',
|
|
454
|
-
`const replayAnalysis = ${literal(analysis)};`,
|
|
455
|
-
`const replayUrl = ${literal(replayUrl)};`,
|
|
456
|
-
`const expectedPageKey = ${literal(pageKey)};`,
|
|
457
|
-
`const valueInputPath = ${literal(valueInputPath)};`,
|
|
458
|
-
`const draftDialogAction = ${literal(draftDialogAction)};`,
|
|
459
|
-
'',
|
|
460
|
-
'function getPathValue(source, path) {',
|
|
461
|
-
' const parts = String(path || "").split(".").filter((part) => part.length > 0);',
|
|
462
|
-
' return parts.reduce((current, part) => {',
|
|
463
|
-
' if (!current || typeof current !== "object") return undefined;',
|
|
464
|
-
' if (!Object.prototype.hasOwnProperty.call(current, part)) return undefined;',
|
|
465
|
-
' return current[part];',
|
|
466
|
-
' }, source);',
|
|
467
|
-
'}',
|
|
468
|
-
'',
|
|
469
|
-
'function errorMessage(error) {',
|
|
470
|
-
' if (error && typeof error === "object" && typeof error.message === "string") return error.message;',
|
|
471
|
-
' return String(error);',
|
|
472
|
-
'}',
|
|
473
|
-
'',
|
|
474
|
-
'async function readSnapshotText() {',
|
|
475
|
-
' if (typeof snapshot !== "function") return undefined;',
|
|
476
|
-
' try {',
|
|
477
|
-
' const value = await snapshot({ page });',
|
|
478
|
-
' return (typeof value === "string" ? value : JSON.stringify(value, null, 2)).slice(0, 12000);',
|
|
479
|
-
' } catch (error) {',
|
|
480
|
-
' return "snapshot failed: " + errorMessage(error);',
|
|
481
|
-
' }',
|
|
482
|
-
'}',
|
|
483
|
-
'',
|
|
484
|
-
'async function needsAi(reason, extra) {',
|
|
485
|
-
' return {',
|
|
486
|
-
' status: "needs_ai",',
|
|
487
|
-
' reason,',
|
|
488
|
-
' replayAnalysis,',
|
|
489
|
-
' ...extra,',
|
|
490
|
-
' context: {',
|
|
491
|
-
' url: page.url(),',
|
|
492
|
-
' title: await page.title().catch(() => ""),',
|
|
493
|
-
' snapshot: await readSnapshotText(),',
|
|
494
|
-
' },',
|
|
495
|
-
' };',
|
|
496
|
-
'}',
|
|
497
|
-
'',
|
|
498
|
-
'async function countVisible(locator) {',
|
|
499
|
-
' return await locator.evaluateAll((nodes) => nodes.filter((node) => {',
|
|
500
|
-
' return Boolean(node.offsetWidth || node.offsetHeight || node.getClientRects().length);',
|
|
501
|
-
' }).length);',
|
|
502
|
-
'}',
|
|
503
|
-
'',
|
|
504
|
-
'async function clickFirstVisible(candidates, phase) {',
|
|
505
|
-
' for (let index = 0; index < candidates.length; index += 1) {',
|
|
506
|
-
' const selector = candidates[index];',
|
|
507
|
-
' const locator = page.locator(selector);',
|
|
508
|
-
' if (await countVisible(locator).catch(() => 0)) {',
|
|
509
|
-
' await locator.first().click();',
|
|
510
|
-
' return { status: "ok", selector };',
|
|
511
|
-
' }',
|
|
512
|
-
' }',
|
|
513
|
-
' return await needsAi("Expected clickable target was not visible.", { phase, candidates });',
|
|
514
|
-
'}',
|
|
515
|
-
'',
|
|
516
|
-
'async function dialogText() {',
|
|
517
|
-
' const dialog = page.locator(".designer-modal, .ant-modal, [role=dialog]").last();',
|
|
518
|
-
' if (!(await countVisible(dialog).catch(() => 0))) return "";',
|
|
519
|
-
' return await dialog.innerText().catch(() => "");',
|
|
520
|
-
'}',
|
|
521
|
-
'',
|
|
522
|
-
'async function waitForConfigValue(value) {',
|
|
523
|
-
' const detailResponse = await page.waitForResponse((response) => {',
|
|
524
|
-
' return response.url().includes("/enhancedConfigs/detail?id=") && response.status() === 200;',
|
|
525
|
-
' }, { timeout: 15000 }).catch((error) => {',
|
|
526
|
-
' return { error };',
|
|
527
|
-
' });',
|
|
528
|
-
' if (detailResponse && detailResponse.error) {',
|
|
529
|
-
' return { status: "unknown", error: errorMessage(detailResponse.error) };',
|
|
530
|
-
' }',
|
|
531
|
-
' try {',
|
|
532
|
-
' const body = await detailResponse.json();',
|
|
533
|
-
' const configValue = body && body.data && body.data.config ? body.data.config.value : "";',
|
|
534
|
-
' return { status: String(configValue).includes(value) ? "matched" : "mismatch", value: configValue };',
|
|
535
|
-
' } catch (error) {',
|
|
536
|
-
' return { status: "unknown", error: errorMessage(error) };',
|
|
537
|
-
' }',
|
|
538
|
-
'}',
|
|
539
|
-
'',
|
|
540
|
-
'const itemValue = String(getPathValue(input, valueInputPath) ?? input.value ?? input.text ?? "").trim();',
|
|
541
|
-
'if (!itemValue) {',
|
|
542
|
-
' return await needsAi("Missing input value for replay-generated workflow.", { phase: "input", valueInputPath });',
|
|
543
|
-
'}',
|
|
544
|
-
'if (replayUrl && expectedPageKey && !page.url().includes(expectedPageKey)) {',
|
|
545
|
-
' await page.goto(replayUrl);',
|
|
546
|
-
' await page.waitForLoadState("domcontentloaded").catch(() => undefined);',
|
|
547
|
-
'}',
|
|
548
|
-
'if (replayUrl && !expectedPageKey && page.url() === "about:blank") {',
|
|
549
|
-
' await page.goto(replayUrl);',
|
|
550
|
-
' await page.waitForLoadState("domcontentloaded").catch(() => undefined);',
|
|
551
|
-
'}',
|
|
552
|
-
'if (expectedPageKey && !page.url().includes(expectedPageKey)) {',
|
|
553
|
-
' return await needsAi("Current page does not match replay target config.", { phase: "page-check", expectedPageKey });',
|
|
554
|
-
'}',
|
|
555
|
-
'if (await page.locator(`text=${itemValue}`).count()) {',
|
|
556
|
-
' return { status: "completed", reason: "value already exists", value: itemValue, replayAnalysis };',
|
|
557
|
-
'}',
|
|
558
|
-
'',
|
|
559
|
-
'const alreadyEditing =',
|
|
560
|
-
' (await countVisible(page.locator("button:has-text(\\"提交\\")")).catch(() => 0)) > 0 ||',
|
|
561
|
-
' (await countVisible(page.locator("button:has-text(\\"Submit\\")")).catch(() => 0)) > 0 ||',
|
|
562
|
-
' (await countVisible(page.locator(".designer-formily-array-base-addition")).catch(() => 0)) > 0;',
|
|
563
|
-
'if (!alreadyEditing) {',
|
|
564
|
-
' const editResult = await clickFirstVisible([',
|
|
565
|
-
' "button:has-text(\\"编辑\\")",',
|
|
566
|
-
' "button:has-text(\\"Edit\\")",',
|
|
567
|
-
' "button:has-text(\\"重新编辑\\")",',
|
|
568
|
-
' "button:has-text(\\"Restart\\")",',
|
|
569
|
-
' ], "enter-edit");',
|
|
570
|
-
' if (editResult.status !== "ok") return editResult;',
|
|
571
|
-
' await page.waitForTimeout(800);',
|
|
572
|
-
'',
|
|
573
|
-
' const draftText = await dialogText();',
|
|
574
|
-
' if (draftText.includes("继续编辑上次修改") || /continue previous edit|draft/i.test(draftText)) {',
|
|
575
|
-
' const draftResult = draftDialogAction === "continue"',
|
|
576
|
-
' ? await clickFirstVisible(["button:has-text(\\"继续编辑\\")", "button:has-text(\\"Continue\\")"], "draft-dialog")',
|
|
577
|
-
' : await clickFirstVisible(["button:has-text(\\"重新编辑\\")", "button:has-text(\\"Restart\\")"], "draft-dialog");',
|
|
578
|
-
' if (draftResult.status !== "ok") return draftResult;',
|
|
579
|
-
' await page.waitForTimeout(800);',
|
|
580
|
-
' }',
|
|
581
|
-
'}',
|
|
582
|
-
'',
|
|
583
|
-
'const designerInputs = page.locator("textarea.designer-input");',
|
|
584
|
-
'const beforeValues = await designerInputs.evaluateAll((nodes) => nodes.map((node) => node.value));',
|
|
585
|
-
'const addResult = await clickFirstVisible([',
|
|
586
|
-
' "button:has-text(\\"Add entry\\")",',
|
|
587
|
-
' "button:has-text(\\"新增\\")",',
|
|
588
|
-
' "button:has-text(\\"添加\\")",',
|
|
589
|
-
' ".designer-formily-array-base-addition",',
|
|
590
|
-
'], "add-entry");',
|
|
591
|
-
'if (addResult.status !== "ok") return addResult;',
|
|
592
|
-
'await page.waitForTimeout(500);',
|
|
593
|
-
'const afterAddCount = await designerInputs.count();',
|
|
594
|
-
'if (afterAddCount <= beforeValues.length) {',
|
|
595
|
-
' return await needsAi("Add entry did not create a new list input.", { phase: "add-entry", beforeValues, afterAddCount });',
|
|
596
|
-
'}',
|
|
597
|
-
'const targetInput = designerInputs.nth(afterAddCount - 1);',
|
|
598
|
-
'await targetInput.fill(itemValue);',
|
|
599
|
-
'const afterValues = await designerInputs.evaluateAll((nodes) => nodes.map((node) => node.value));',
|
|
600
|
-
'if (!afterValues.includes(itemValue)) {',
|
|
601
|
-
' return await needsAi("Filled value was not present in list inputs.", { phase: "fill", afterValues, itemValue });',
|
|
602
|
-
'}',
|
|
603
|
-
'',
|
|
604
|
-
'const submitResult = await clickFirstVisible(["button:has-text(\\"提交\\")", "button:has-text(\\"Submit\\")"], "submit");',
|
|
605
|
-
'if (submitResult.status !== "ok") return submitResult;',
|
|
606
|
-
'await page.waitForTimeout(500);',
|
|
607
|
-
'const confirmText = await dialogText();',
|
|
608
|
-
'if (!confirmText.includes(itemValue)) {',
|
|
609
|
-
' return await needsAi("Confirm diff does not include the new value.", { phase: "confirm-dialog", confirmText, itemValue });',
|
|
610
|
-
'}',
|
|
611
|
-
'',
|
|
612
|
-
'const updatePromise = page.waitForResponse((response) => {',
|
|
613
|
-
' return response.url().includes("/enhancedConfigs/update") && response.request().method() === "POST";',
|
|
614
|
-
'}, { timeout: 15000 }).catch((error) => {',
|
|
615
|
-
' return { error };',
|
|
616
|
-
'});',
|
|
617
|
-
'const publishPromise = page.waitForResponse((response) => {',
|
|
618
|
-
' return response.url().includes("/enhancedConfigs/publish") && response.request().method() === "POST";',
|
|
619
|
-
'}, { timeout: 15000 }).catch((error) => {',
|
|
620
|
-
' return { error };',
|
|
621
|
-
'});',
|
|
622
|
-
'const detailPromise = waitForConfigValue(itemValue);',
|
|
623
|
-
'const okResult = await clickFirstVisible(["button:has-text(\\"OK\\")", "button:has-text(\\"确定\\")"], "confirm-ok");',
|
|
624
|
-
'if (okResult.status !== "ok") return okResult;',
|
|
625
|
-
'const updateResponse = await updatePromise;',
|
|
626
|
-
'if (updateResponse && updateResponse.error) {',
|
|
627
|
-
' return await needsAi("Update request was not observed.", { phase: "update-request", error: errorMessage(updateResponse.error) });',
|
|
628
|
-
'}',
|
|
629
|
-
'const publishResponse = await publishPromise;',
|
|
630
|
-
'if (publishResponse && publishResponse.error) {',
|
|
631
|
-
' return await needsAi("Publish request was not observed.", { phase: "publish-request", error: errorMessage(publishResponse.error) });',
|
|
632
|
-
'}',
|
|
633
|
-
'const updateBody = await updateResponse.json().catch(() => null);',
|
|
634
|
-
'const publishBody = await publishResponse.json().catch(() => null);',
|
|
635
|
-
'if (!updateBody || updateBody.code !== 0) {',
|
|
636
|
-
' return await needsAi("Update request returned an unexpected body.", { phase: "update-request", updateBody });',
|
|
637
|
-
'}',
|
|
638
|
-
'if (!publishBody || publishBody.code !== 0 || publishBody.data !== true) {',
|
|
639
|
-
' return await needsAi("Publish request returned an unexpected body.", { phase: "publish-request", publishBody });',
|
|
640
|
-
'}',
|
|
641
|
-
'const detail = await detailPromise;',
|
|
642
|
-
'if (detail.status === "mismatch") {',
|
|
643
|
-
' return await needsAi("Detail response does not contain the new value.", { phase: "verify", detail, itemValue });',
|
|
644
|
-
'}',
|
|
645
|
-
'return {',
|
|
646
|
-
' status: "completed",',
|
|
647
|
-
' value: itemValue,',
|
|
648
|
-
' replayAnalysis,',
|
|
649
|
-
' update: { status: updateResponse.status(), body: updateBody },',
|
|
650
|
-
' publish: { status: publishResponse.status(), body: publishBody },',
|
|
651
|
-
' detail,',
|
|
652
|
-
'};',
|
|
653
|
-
'',
|
|
654
|
-
].join('\n')
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
export function compileReplayWorkflow(options: CompileReplayWorkflowOptions): CompiledReplayWorkflow {
|
|
658
|
-
const replay = getSavedRrwebRecordingWithEvents(options.replayId)
|
|
659
|
-
if (!replay) {
|
|
660
|
-
throw new Error(`Replay recording not found: ${options.replayId}`)
|
|
661
|
-
}
|
|
662
|
-
const analysis = analyzeReplayWorkflow({
|
|
663
|
-
replayId: options.replayId,
|
|
664
|
-
url: replay.recording.url,
|
|
665
|
-
events: replay.events,
|
|
666
|
-
})
|
|
667
|
-
if (analysis.actionKind !== 'list-append') {
|
|
668
|
-
throw new UnsupportedReplayWorkflowError({ analysis })
|
|
669
|
-
}
|
|
670
|
-
const script = buildListAppendScript(analysis, options)
|
|
671
|
-
const saved = saveWorkflowCapability({
|
|
672
|
-
id: options.id,
|
|
673
|
-
title: options.title || `Workflow from replay ${options.replayId}`,
|
|
674
|
-
description:
|
|
675
|
-
options.description ||
|
|
676
|
-
'Compiled from an rrweb replay. Appends a list item, submits, publishes, and returns needs_ai on page drift.',
|
|
677
|
-
script,
|
|
678
|
-
cwd: options.cwd,
|
|
679
|
-
location: 'project',
|
|
680
|
-
overwrite: options.overwrite,
|
|
681
|
-
sourceRecordingId: options.replayId,
|
|
682
|
-
inputSchema: {
|
|
683
|
-
type: 'object',
|
|
684
|
-
properties: {
|
|
685
|
-
value: { type: 'string' },
|
|
686
|
-
},
|
|
687
|
-
required: ['value'],
|
|
688
|
-
},
|
|
689
|
-
outputSchema: {
|
|
690
|
-
type: 'object',
|
|
691
|
-
properties: {
|
|
692
|
-
status: { type: 'string' },
|
|
693
|
-
value: { type: 'string' },
|
|
694
|
-
},
|
|
695
|
-
},
|
|
696
|
-
match: replay.recording.url ? [replay.recording.url] : [],
|
|
697
|
-
tags: ['rrweb-replay-compiled'],
|
|
698
|
-
})
|
|
699
|
-
return { analysis, saved }
|
|
700
|
-
}
|