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,773 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import http from 'node:http';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import { afterAll, beforeAll, describe, expect, test } from 'vitest';
|
|
5
|
-
import { cleanupTestContext, setupTestContext } from './test-utils.js';
|
|
6
|
-
const TEST_PORT = 19984;
|
|
7
|
-
let testCtx = null;
|
|
8
|
-
function getExtensionDistRoot() {
|
|
9
|
-
const candidates = [
|
|
10
|
-
path.join(process.cwd(), 'extension', `dist-${TEST_PORT}`),
|
|
11
|
-
path.resolve(process.cwd(), '..', 'extension', `dist-${TEST_PORT}`),
|
|
12
|
-
];
|
|
13
|
-
const distRoot = candidates.find((candidate) => {
|
|
14
|
-
return fs.existsSync(path.join(candidate, 'src', 'options.html'));
|
|
15
|
-
});
|
|
16
|
-
if (!distRoot) {
|
|
17
|
-
throw new Error(`Could not find extension dist for port ${TEST_PORT}`);
|
|
18
|
-
}
|
|
19
|
-
return distRoot;
|
|
20
|
-
}
|
|
21
|
-
async function createStaticServer(rootDir) {
|
|
22
|
-
const openSockets = new Set();
|
|
23
|
-
const server = http.createServer((req, res) => {
|
|
24
|
-
const url = new URL(req.url || '/', 'http://127.0.0.1');
|
|
25
|
-
const pathname = url.pathname === '/' ? '/src/options.html' : url.pathname;
|
|
26
|
-
const filePath = path.resolve(rootDir, `.${pathname}`);
|
|
27
|
-
if (filePath !== rootDir && !filePath.startsWith(`${rootDir}${path.sep}`)) {
|
|
28
|
-
res.writeHead(403);
|
|
29
|
-
res.end('forbidden');
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
if (!fs.existsSync(filePath)) {
|
|
33
|
-
res.writeHead(404);
|
|
34
|
-
res.end('not found');
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
const contentType = filePath.endsWith('.js')
|
|
38
|
-
? 'text/javascript'
|
|
39
|
-
: filePath.endsWith('.html')
|
|
40
|
-
? 'text/html'
|
|
41
|
-
: filePath.endsWith('.css')
|
|
42
|
-
? 'text/css'
|
|
43
|
-
: 'application/octet-stream';
|
|
44
|
-
res.writeHead(200, { 'Content-Type': contentType });
|
|
45
|
-
res.end(fs.readFileSync(filePath));
|
|
46
|
-
});
|
|
47
|
-
server.on('connection', (socket) => {
|
|
48
|
-
openSockets.add(socket);
|
|
49
|
-
socket.on('close', () => {
|
|
50
|
-
openSockets.delete(socket);
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
await new Promise((resolve) => {
|
|
54
|
-
server.listen(0, '127.0.0.1', () => {
|
|
55
|
-
resolve();
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
const address = server.address();
|
|
59
|
-
if (!address || typeof address === 'string') {
|
|
60
|
-
throw new Error('Failed to start static server');
|
|
61
|
-
}
|
|
62
|
-
return {
|
|
63
|
-
baseUrl: `http://127.0.0.1:${address.port}`,
|
|
64
|
-
close: async () => {
|
|
65
|
-
openSockets.forEach((socket) => {
|
|
66
|
-
socket.destroy();
|
|
67
|
-
});
|
|
68
|
-
await new Promise((resolve, reject) => {
|
|
69
|
-
server.close((error) => {
|
|
70
|
-
if (error) {
|
|
71
|
-
reject(error);
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
resolve();
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
},
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
describe('extension options page', () => {
|
|
81
|
-
beforeAll(async () => {
|
|
82
|
-
testCtx = await setupTestContext({ port: TEST_PORT, tempDirPrefix: 'options-page-test-' });
|
|
83
|
-
}, 600000);
|
|
84
|
-
afterAll(async () => {
|
|
85
|
-
await cleanupTestContext(testCtx);
|
|
86
|
-
testCtx = null;
|
|
87
|
-
});
|
|
88
|
-
test('shows DOM replays and loads selected playback from the options page', async () => {
|
|
89
|
-
if (!testCtx) {
|
|
90
|
-
throw new Error('Test context is not initialized');
|
|
91
|
-
}
|
|
92
|
-
const distRoot = getExtensionDistRoot();
|
|
93
|
-
const staticServer = await createStaticServer(distRoot);
|
|
94
|
-
let replayEventsRequested = false;
|
|
95
|
-
const replay = {
|
|
96
|
-
id: 'replay-options-smoke',
|
|
97
|
-
path: '/Users/test/.tabwright/rrweb-recordings/replay-options-smoke.json',
|
|
98
|
-
startedAt: Date.now() - 2000,
|
|
99
|
-
savedAt: Date.now(),
|
|
100
|
-
duration: 2000,
|
|
101
|
-
size: 2048,
|
|
102
|
-
eventCount: 2,
|
|
103
|
-
tabId: 7,
|
|
104
|
-
sessionId: 'pw-tab-options',
|
|
105
|
-
url: 'https://example.com/materials/new',
|
|
106
|
-
};
|
|
107
|
-
const recordings = Array.from({ length: 30 }, (_, index) => {
|
|
108
|
-
return {
|
|
109
|
-
...replay,
|
|
110
|
-
id: index === 0 ? replay.id : `replay-options-smoke-${index}`,
|
|
111
|
-
path: index === 0 ? replay.path : `/Users/test/.tabwright/rrweb-recordings/replay-options-smoke-${index}.json`,
|
|
112
|
-
startedAt: replay.startedAt - index * 1000,
|
|
113
|
-
savedAt: replay.savedAt - index * 1000,
|
|
114
|
-
tabId: replay.tabId + index,
|
|
115
|
-
};
|
|
116
|
-
});
|
|
117
|
-
const replayEvents = [
|
|
118
|
-
{
|
|
119
|
-
type: 4,
|
|
120
|
-
timestamp: replay.startedAt,
|
|
121
|
-
data: { href: replay.url, width: 1280, height: 720 },
|
|
122
|
-
},
|
|
123
|
-
{
|
|
124
|
-
type: 2,
|
|
125
|
-
timestamp: replay.startedAt + 100,
|
|
126
|
-
data: { node: { id: 1, type: 0, childNodes: [] } },
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
type: 3,
|
|
130
|
-
timestamp: replay.startedAt + 200,
|
|
131
|
-
data: {
|
|
132
|
-
source: 0,
|
|
133
|
-
adds: [],
|
|
134
|
-
removes: [],
|
|
135
|
-
texts: [{ id: 404, value: 'missing node update' }],
|
|
136
|
-
attributes: [],
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
type: 5,
|
|
141
|
-
timestamp: replay.startedAt + 5000,
|
|
142
|
-
data: { tag: 'end', payload: {} },
|
|
143
|
-
},
|
|
144
|
-
];
|
|
145
|
-
const page = await testCtx.browserContext.newPage();
|
|
146
|
-
const missingNodeConsoleWarnings = [];
|
|
147
|
-
page.on('console', (message) => {
|
|
148
|
-
if (message.type() === 'warning' && message.text().includes('Node with id')) {
|
|
149
|
-
missingNodeConsoleWarnings.push(message.text());
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
await page.setViewportSize({ width: 1280, height: 720 });
|
|
153
|
-
try {
|
|
154
|
-
await testCtx.browserContext.grantPermissions(['clipboard-read', 'clipboard-write'], {
|
|
155
|
-
origin: staticServer.baseUrl,
|
|
156
|
-
});
|
|
157
|
-
await page.route(`http://127.0.0.1:${TEST_PORT}/**`, async (route) => {
|
|
158
|
-
const request = route.request();
|
|
159
|
-
const url = new URL(request.url());
|
|
160
|
-
const corsHeaders = {
|
|
161
|
-
'access-control-allow-origin': '*',
|
|
162
|
-
'access-control-allow-methods': 'GET,POST,OPTIONS',
|
|
163
|
-
'access-control-allow-headers': 'content-type',
|
|
164
|
-
};
|
|
165
|
-
if (request.method() === 'OPTIONS') {
|
|
166
|
-
await route.fulfill({ status: 204, headers: corsHeaders, body: '' });
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
if (url.pathname === '/rrweb-recordings') {
|
|
170
|
-
await route.fulfill({
|
|
171
|
-
status: 200,
|
|
172
|
-
headers: { ...corsHeaders, 'content-type': 'application/json' },
|
|
173
|
-
body: JSON.stringify({ recordings }),
|
|
174
|
-
});
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
if (url.pathname === `/rrweb-recordings/${replay.id}/events`) {
|
|
178
|
-
replayEventsRequested = true;
|
|
179
|
-
await route.fulfill({
|
|
180
|
-
status: 200,
|
|
181
|
-
headers: { ...corsHeaders, 'content-type': 'application/json' },
|
|
182
|
-
body: JSON.stringify({ recording: replay, events: replayEvents }),
|
|
183
|
-
});
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
await route.fulfill({ status: 404, headers: corsHeaders, body: 'not found' });
|
|
187
|
-
});
|
|
188
|
-
await page.goto(`${staticServer.baseUrl}/src/options.html`);
|
|
189
|
-
await page.locator('.language-button[data-language="en"]').click();
|
|
190
|
-
const recordingItem = page.locator('.recording-item').first();
|
|
191
|
-
await recordingItem.waitFor({ timeout: 10000 });
|
|
192
|
-
await expect
|
|
193
|
-
.poll(async () => {
|
|
194
|
-
return await recordingItem.textContent();
|
|
195
|
-
})
|
|
196
|
-
.toContain('2 events');
|
|
197
|
-
const replaysList = page.locator('#replays-list');
|
|
198
|
-
await expect
|
|
199
|
-
.poll(async () => {
|
|
200
|
-
return await replaysList.evaluate((element) => {
|
|
201
|
-
const list = element;
|
|
202
|
-
return list.scrollHeight > list.clientHeight;
|
|
203
|
-
});
|
|
204
|
-
})
|
|
205
|
-
.toBe(true);
|
|
206
|
-
await replaysList.evaluate((element) => {
|
|
207
|
-
const list = element;
|
|
208
|
-
list.scrollTop = list.scrollHeight;
|
|
209
|
-
});
|
|
210
|
-
await expect
|
|
211
|
-
.poll(async () => {
|
|
212
|
-
return await replaysList.evaluate((element) => {
|
|
213
|
-
const list = element;
|
|
214
|
-
return list.scrollTop > 0;
|
|
215
|
-
});
|
|
216
|
-
})
|
|
217
|
-
.toBe(true);
|
|
218
|
-
await replaysList.evaluate((element) => {
|
|
219
|
-
const list = element;
|
|
220
|
-
list.scrollTop = 0;
|
|
221
|
-
});
|
|
222
|
-
await recordingItem.locator('.recording-select').click();
|
|
223
|
-
await expect
|
|
224
|
-
.poll(() => {
|
|
225
|
-
return replayEventsRequested;
|
|
226
|
-
})
|
|
227
|
-
.toBe(true);
|
|
228
|
-
await expect
|
|
229
|
-
.poll(async () => {
|
|
230
|
-
return await page.locator('#status-text').textContent();
|
|
231
|
-
})
|
|
232
|
-
.toContain('Replay ready');
|
|
233
|
-
await expect
|
|
234
|
-
.poll(async () => {
|
|
235
|
-
return await page.locator('#replay-controls').isVisible();
|
|
236
|
-
})
|
|
237
|
-
.toBe(true);
|
|
238
|
-
await expect
|
|
239
|
-
.poll(async () => {
|
|
240
|
-
return await page.locator('#replay-play-toggle').textContent();
|
|
241
|
-
})
|
|
242
|
-
.toBe('Play');
|
|
243
|
-
await expect
|
|
244
|
-
.poll(async () => {
|
|
245
|
-
return Number(await page.locator('#replay-timeline').inputValue());
|
|
246
|
-
})
|
|
247
|
-
.toBe(0);
|
|
248
|
-
await page.locator('#replay-play-toggle').click();
|
|
249
|
-
await expect
|
|
250
|
-
.poll(async () => {
|
|
251
|
-
return await page.locator('#replay-play-toggle').textContent();
|
|
252
|
-
})
|
|
253
|
-
.toBe('Pause');
|
|
254
|
-
await expect
|
|
255
|
-
.poll(async () => {
|
|
256
|
-
return await page.locator('#replay-warning').textContent();
|
|
257
|
-
})
|
|
258
|
-
.toContain('1 DOM update');
|
|
259
|
-
expect(missingNodeConsoleWarnings).toEqual([]);
|
|
260
|
-
await page.locator('#replay-play-toggle').click();
|
|
261
|
-
await expect
|
|
262
|
-
.poll(async () => {
|
|
263
|
-
return await page.locator('#replay-play-toggle').textContent();
|
|
264
|
-
})
|
|
265
|
-
.toBe('Play');
|
|
266
|
-
await expect
|
|
267
|
-
.poll(async () => {
|
|
268
|
-
return await page.locator('#replay-details').textContent();
|
|
269
|
-
})
|
|
270
|
-
.toContain('replay-options-smoke');
|
|
271
|
-
await expect
|
|
272
|
-
.poll(async () => {
|
|
273
|
-
return await page.locator('#replay-details').textContent();
|
|
274
|
-
})
|
|
275
|
-
.toContain('https://example.com/materials/new');
|
|
276
|
-
await recordingItem.getByRole('button', { name: 'Copy for AI' }).click();
|
|
277
|
-
const replayContext = await page.evaluate(async () => {
|
|
278
|
-
const clipboardNavigator = navigator;
|
|
279
|
-
return await clipboardNavigator.clipboard.readText();
|
|
280
|
-
});
|
|
281
|
-
expect(replayContext).toContain('Replay ID: replay-options-smoke');
|
|
282
|
-
expect(replayContext).toContain(replay.path);
|
|
283
|
-
await page.locator('#replay-player .replayer-wrapper').waitFor();
|
|
284
|
-
await expect
|
|
285
|
-
.poll(async () => {
|
|
286
|
-
const playerBox = await page.locator('#replay-player').boundingBox();
|
|
287
|
-
const wrapperBox = await page.locator('#replay-player .replayer-wrapper').boundingBox();
|
|
288
|
-
if (!playerBox || !wrapperBox) {
|
|
289
|
-
return false;
|
|
290
|
-
}
|
|
291
|
-
return wrapperBox.width <= playerBox.width + 1 && wrapperBox.height <= playerBox.height + 1;
|
|
292
|
-
})
|
|
293
|
-
.toBe(true);
|
|
294
|
-
}
|
|
295
|
-
finally {
|
|
296
|
-
await testCtx.browserContext.clearPermissions();
|
|
297
|
-
await page.close();
|
|
298
|
-
await staticServer.close();
|
|
299
|
-
}
|
|
300
|
-
}, 30000);
|
|
301
|
-
test('shows capabilities with clear status labels and focused actions', async () => {
|
|
302
|
-
if (!testCtx) {
|
|
303
|
-
throw new Error('Test context is not initialized');
|
|
304
|
-
}
|
|
305
|
-
const distRoot = getExtensionDistRoot();
|
|
306
|
-
const staticServer = await createStaticServer(distRoot);
|
|
307
|
-
const capabilityBase = {
|
|
308
|
-
id: 'query-user',
|
|
309
|
-
title: 'Query User',
|
|
310
|
-
description: 'Look up a user by email.',
|
|
311
|
-
status: 'trusted',
|
|
312
|
-
runtime: 'browser',
|
|
313
|
-
match: ['https://admin.example.com/users*'],
|
|
314
|
-
routingHint: 'exact-match-direct-run',
|
|
315
|
-
permissions: ['browser.read', 'browser.write'],
|
|
316
|
-
sideEffect: 'write',
|
|
317
|
-
requiresConfirmation: true,
|
|
318
|
-
whenToUse: ['Use when the user asks to look up an admin user by email.'],
|
|
319
|
-
whenNotToUse: ['Do not use for public profile lookup.'],
|
|
320
|
-
tags: ['admin'],
|
|
321
|
-
inputSchema: {
|
|
322
|
-
type: 'object',
|
|
323
|
-
properties: {
|
|
324
|
-
email: { type: 'string' },
|
|
325
|
-
},
|
|
326
|
-
required: ['email'],
|
|
327
|
-
},
|
|
328
|
-
outputSchema: {
|
|
329
|
-
type: 'object',
|
|
330
|
-
properties: {
|
|
331
|
-
id: { type: 'string' },
|
|
332
|
-
},
|
|
333
|
-
},
|
|
334
|
-
location: 'project',
|
|
335
|
-
dir: '/Users/test/project/.tabwright/capabilities/query-user',
|
|
336
|
-
autonomousInvocation: {
|
|
337
|
-
allowed: false,
|
|
338
|
-
reasons: ['sideEffect is write', 'requires confirmation'],
|
|
339
|
-
},
|
|
340
|
-
recentRuns: [
|
|
341
|
-
{
|
|
342
|
-
id: 'run-1',
|
|
343
|
-
status: 'success',
|
|
344
|
-
durationMs: 42,
|
|
345
|
-
inputHash: 'abc',
|
|
346
|
-
createdAt: '2026-07-07T00:00:00.000Z',
|
|
347
|
-
},
|
|
348
|
-
],
|
|
349
|
-
agentSkill: {
|
|
350
|
-
target: 'codex',
|
|
351
|
-
draftExists: true,
|
|
352
|
-
draftPath: '/Users/test/project/.tabwright/capabilities/query-user/agent-skills/codex/SKILL.md',
|
|
353
|
-
installedExists: false,
|
|
354
|
-
installedPath: '/Users/test/.codex/skills/query-user/SKILL.md',
|
|
355
|
-
initCommand: 'tabwright capability skill init query-user',
|
|
356
|
-
showCommand: 'tabwright capability skill show query-user',
|
|
357
|
-
installCommand: 'tabwright capability skill install query-user',
|
|
358
|
-
},
|
|
359
|
-
};
|
|
360
|
-
const trustedNextCommand = 'tabwright capability run query-user --browser user --input-json \'{"email":"from-contract@example.com"}\' --confirm query-user --json';
|
|
361
|
-
let authRefreshAttempts = 0;
|
|
362
|
-
let capabilityAuthState = {
|
|
363
|
-
type: 'cookie',
|
|
364
|
-
status: 'missing',
|
|
365
|
-
canRefresh: true,
|
|
366
|
-
browserUrls: ['https://admin.example.com/'],
|
|
367
|
-
requiredCookieNames: ['SESSION'],
|
|
368
|
-
cookieNames: [],
|
|
369
|
-
refreshCommand: 'tabwright capability refresh-auth query-user --browser user --json',
|
|
370
|
-
};
|
|
371
|
-
const capability = {
|
|
372
|
-
...capabilityBase,
|
|
373
|
-
authState: capabilityAuthState,
|
|
374
|
-
lifecycle: {
|
|
375
|
-
stage: 'trusted',
|
|
376
|
-
nextAction: 'run',
|
|
377
|
-
nextCommand: trustedNextCommand,
|
|
378
|
-
contractHealth: {
|
|
379
|
-
state: 'healthy',
|
|
380
|
-
checkedAt: '2026-07-07T00:00:00.000Z',
|
|
381
|
-
reasons: [],
|
|
382
|
-
},
|
|
383
|
-
},
|
|
384
|
-
};
|
|
385
|
-
const driftedNextCommand = 'tabwright capability show drifted-user --json';
|
|
386
|
-
const driftedCapability = {
|
|
387
|
-
...capabilityBase,
|
|
388
|
-
id: 'drifted-user',
|
|
389
|
-
title: 'Drifted User Query',
|
|
390
|
-
status: 'draft',
|
|
391
|
-
autonomousInvocation: {
|
|
392
|
-
allowed: false,
|
|
393
|
-
reasons: ['current contract failed conformance'],
|
|
394
|
-
},
|
|
395
|
-
lifecycle: {
|
|
396
|
-
stage: 'drifted',
|
|
397
|
-
nextAction: 'repair',
|
|
398
|
-
nextCommand: driftedNextCommand,
|
|
399
|
-
contractHealth: {
|
|
400
|
-
state: 'drifted',
|
|
401
|
-
checkedAt: '2026-07-08T00:00:00.000Z',
|
|
402
|
-
reasons: ['output.userId must be string'],
|
|
403
|
-
},
|
|
404
|
-
},
|
|
405
|
-
};
|
|
406
|
-
const disabledCapability = {
|
|
407
|
-
...capabilityBase,
|
|
408
|
-
id: 'legacy-disabled',
|
|
409
|
-
title: 'Legacy Disabled',
|
|
410
|
-
status: 'disabled',
|
|
411
|
-
autonomousInvocation: {
|
|
412
|
-
allowed: false,
|
|
413
|
-
reasons: ['status is disabled'],
|
|
414
|
-
},
|
|
415
|
-
};
|
|
416
|
-
const legacyTrustedCapability = {
|
|
417
|
-
...capabilityBase,
|
|
418
|
-
id: 'legacy-trusted',
|
|
419
|
-
title: 'Legacy Trusted',
|
|
420
|
-
sideEffect: 'read',
|
|
421
|
-
requiresConfirmation: false,
|
|
422
|
-
autonomousInvocation: {
|
|
423
|
-
allowed: true,
|
|
424
|
-
reasons: [],
|
|
425
|
-
},
|
|
426
|
-
};
|
|
427
|
-
const historicalTrustedNextCommand = "tabwright capability run historical-trusted --input-json '{}' --json";
|
|
428
|
-
const historicalTrustedCapability = {
|
|
429
|
-
...legacyTrustedCapability,
|
|
430
|
-
id: 'historical-trusted',
|
|
431
|
-
title: 'Historical Trusted',
|
|
432
|
-
lifecycle: {
|
|
433
|
-
stage: 'trusted',
|
|
434
|
-
nextAction: 'run',
|
|
435
|
-
nextCommand: historicalTrustedNextCommand,
|
|
436
|
-
contractHealth: {
|
|
437
|
-
state: 'unknown',
|
|
438
|
-
reasons: [],
|
|
439
|
-
},
|
|
440
|
-
},
|
|
441
|
-
};
|
|
442
|
-
const futureLifecycleCapability = {
|
|
443
|
-
...legacyTrustedCapability,
|
|
444
|
-
id: 'future-lifecycle',
|
|
445
|
-
title: 'Future Lifecycle',
|
|
446
|
-
recentRuns: [{ status: 'future-run-format' }],
|
|
447
|
-
lifecycle: {
|
|
448
|
-
stage: 'reviewed',
|
|
449
|
-
nextAction: 'approve',
|
|
450
|
-
nextCommand: 'tabwright capability trust future-lifecycle',
|
|
451
|
-
contractHealth: {
|
|
452
|
-
state: 'future-health',
|
|
453
|
-
reasons: [],
|
|
454
|
-
},
|
|
455
|
-
},
|
|
456
|
-
};
|
|
457
|
-
const page = await testCtx.browserContext.newPage();
|
|
458
|
-
await page.setViewportSize({ width: 1280, height: 720 });
|
|
459
|
-
page.setDefaultTimeout(10000);
|
|
460
|
-
async function readClipboard() {
|
|
461
|
-
return await page.evaluate(async () => {
|
|
462
|
-
const clipboardNavigator = navigator;
|
|
463
|
-
return await clipboardNavigator.clipboard.readText();
|
|
464
|
-
});
|
|
465
|
-
}
|
|
466
|
-
try {
|
|
467
|
-
await testCtx.browserContext.grantPermissions(['clipboard-read', 'clipboard-write'], {
|
|
468
|
-
origin: staticServer.baseUrl,
|
|
469
|
-
});
|
|
470
|
-
await page.route(`http://127.0.0.1:${TEST_PORT}/**`, async (route) => {
|
|
471
|
-
const request = route.request();
|
|
472
|
-
const url = new URL(request.url());
|
|
473
|
-
const corsHeaders = {
|
|
474
|
-
'access-control-allow-origin': '*',
|
|
475
|
-
'access-control-allow-methods': 'GET,POST,OPTIONS',
|
|
476
|
-
'access-control-allow-headers': 'content-type',
|
|
477
|
-
};
|
|
478
|
-
if (request.method() === 'OPTIONS') {
|
|
479
|
-
await route.fulfill({ status: 204, headers: corsHeaders, body: '' });
|
|
480
|
-
return;
|
|
481
|
-
}
|
|
482
|
-
if (url.pathname === '/rrweb-recordings') {
|
|
483
|
-
await route.fulfill({
|
|
484
|
-
status: 200,
|
|
485
|
-
headers: { ...corsHeaders, 'content-type': 'application/json' },
|
|
486
|
-
body: JSON.stringify({ recordings: [] }),
|
|
487
|
-
});
|
|
488
|
-
return;
|
|
489
|
-
}
|
|
490
|
-
if (url.pathname === '/capabilities') {
|
|
491
|
-
await route.fulfill({
|
|
492
|
-
status: 200,
|
|
493
|
-
headers: { ...corsHeaders, 'content-type': 'application/json' },
|
|
494
|
-
body: JSON.stringify({
|
|
495
|
-
cwd: '/Users/test/project',
|
|
496
|
-
capabilities: [
|
|
497
|
-
{ ...capability, authState: capabilityAuthState },
|
|
498
|
-
driftedCapability,
|
|
499
|
-
disabledCapability,
|
|
500
|
-
legacyTrustedCapability,
|
|
501
|
-
historicalTrustedCapability,
|
|
502
|
-
futureLifecycleCapability,
|
|
503
|
-
],
|
|
504
|
-
}),
|
|
505
|
-
});
|
|
506
|
-
return;
|
|
507
|
-
}
|
|
508
|
-
if (url.pathname === '/capabilities/query-user/auth/refresh' && request.method() === 'POST') {
|
|
509
|
-
authRefreshAttempts += 1;
|
|
510
|
-
if (authRefreshAttempts === 1) {
|
|
511
|
-
await route.fulfill({
|
|
512
|
-
status: 409,
|
|
513
|
-
headers: { ...corsHeaders, 'content-type': 'application/json' },
|
|
514
|
-
body: JSON.stringify({
|
|
515
|
-
code: 'no_enabled_tab',
|
|
516
|
-
error: 'enable Tabwright on a browser tab before authenticating this capability',
|
|
517
|
-
}),
|
|
518
|
-
});
|
|
519
|
-
return;
|
|
520
|
-
}
|
|
521
|
-
capabilityAuthState = {
|
|
522
|
-
...capabilityAuthState,
|
|
523
|
-
status: 'authenticated',
|
|
524
|
-
cookieNames: ['SESSION'],
|
|
525
|
-
refreshedAt: '2026-07-13T10:00:00.000Z',
|
|
526
|
-
expiresAt: '2026-07-20T10:00:00.000Z',
|
|
527
|
-
};
|
|
528
|
-
await route.fulfill({
|
|
529
|
-
status: 200,
|
|
530
|
-
headers: { ...corsHeaders, 'content-type': 'application/json' },
|
|
531
|
-
body: JSON.stringify({ capability: 'query-user', saved: true, authState: capabilityAuthState }),
|
|
532
|
-
});
|
|
533
|
-
return;
|
|
534
|
-
}
|
|
535
|
-
await route.fulfill({ status: 404, headers: corsHeaders, body: 'not found' });
|
|
536
|
-
});
|
|
537
|
-
await page.goto(`${staticServer.baseUrl}/src/options.html`, { waitUntil: 'domcontentloaded' });
|
|
538
|
-
await page.locator('.language-button[data-language="en"]').click();
|
|
539
|
-
const skillsTab = page.locator('.tab-button[data-tab="skills"]');
|
|
540
|
-
await skillsTab.waitFor();
|
|
541
|
-
await skillsTab.click();
|
|
542
|
-
const capabilityItem = page.locator('.skill-item').filter({ hasText: 'Query User' });
|
|
543
|
-
await capabilityItem.waitFor({ timeout: 10000 });
|
|
544
|
-
await capabilityItem.click();
|
|
545
|
-
await expect
|
|
546
|
-
.poll(async () => {
|
|
547
|
-
return await page.locator('#skill-detail').textContent();
|
|
548
|
-
})
|
|
549
|
-
.toContain('query-user');
|
|
550
|
-
await expect
|
|
551
|
-
.poll(async () => {
|
|
552
|
-
return await page.locator('#skill-detail').textContent();
|
|
553
|
-
})
|
|
554
|
-
.toContain('Needs your confirmation');
|
|
555
|
-
await expect
|
|
556
|
-
.poll(async () => {
|
|
557
|
-
return await page.locator('#skill-detail').textContent();
|
|
558
|
-
})
|
|
559
|
-
.toContain('AI instructions need publishing');
|
|
560
|
-
await expect
|
|
561
|
-
.poll(async () => {
|
|
562
|
-
return await page.locator('.lifecycle-card').textContent();
|
|
563
|
-
})
|
|
564
|
-
.toContain('Contract healthy');
|
|
565
|
-
await page.locator('.lifecycle-card').getByRole('button', { name: 'Copy next step' }).click();
|
|
566
|
-
const runCommand = await readClipboard();
|
|
567
|
-
expect(runCommand).toBe(trustedNextCommand);
|
|
568
|
-
await page.getByRole('button', { name: 'Copy for AI' }).click();
|
|
569
|
-
const aiContext = await readClipboard();
|
|
570
|
-
expect(aiContext).toContain('Capability ID: query-user');
|
|
571
|
-
expect(aiContext).toContain('Look up a user by email.');
|
|
572
|
-
const authCard = page.locator('.auth-card');
|
|
573
|
-
await expect
|
|
574
|
-
.poll(async () => {
|
|
575
|
-
return await authCard.textContent();
|
|
576
|
-
})
|
|
577
|
-
.toContain('Not authenticated');
|
|
578
|
-
await authCard.getByRole('button', { name: 'Authenticate with current Chrome' }).click();
|
|
579
|
-
const authDialog = page.locator('.auth-dialog');
|
|
580
|
-
await expect
|
|
581
|
-
.poll(async () => {
|
|
582
|
-
return await authDialog.textContent();
|
|
583
|
-
})
|
|
584
|
-
.toContain('admin.example.com');
|
|
585
|
-
await authDialog.getByRole('button', { name: 'Allow and authenticate' }).click();
|
|
586
|
-
await expect.poll(() => authRefreshAttempts).toBe(1);
|
|
587
|
-
await expect
|
|
588
|
-
.poll(async () => {
|
|
589
|
-
return await authCard.locator('.auth-error').textContent();
|
|
590
|
-
})
|
|
591
|
-
.toContain('Enable Tabwright on a normal browser tab');
|
|
592
|
-
await authCard.getByRole('button', { name: 'Authenticate with current Chrome' }).click();
|
|
593
|
-
await page.locator('.auth-dialog').getByRole('button', { name: 'Allow and authenticate' }).click();
|
|
594
|
-
await expect.poll(() => authRefreshAttempts).toBe(2);
|
|
595
|
-
await expect
|
|
596
|
-
.poll(async () => {
|
|
597
|
-
return await page.locator('.auth-card').textContent();
|
|
598
|
-
})
|
|
599
|
-
.toContain('Authenticated');
|
|
600
|
-
await page.locator('.skill-item').filter({ hasText: 'Drifted User Query' }).click();
|
|
601
|
-
await expect
|
|
602
|
-
.poll(async () => {
|
|
603
|
-
return await page.locator('.lifecycle-card').textContent();
|
|
604
|
-
})
|
|
605
|
-
.toContain('Repair contract drift');
|
|
606
|
-
await expect
|
|
607
|
-
.poll(async () => {
|
|
608
|
-
return await page.locator('.lifecycle-card').textContent();
|
|
609
|
-
})
|
|
610
|
-
.toContain('output.userId must be string');
|
|
611
|
-
await page.locator('.lifecycle-card').getByRole('button', { name: 'Copy next step' }).click();
|
|
612
|
-
expect(await readClipboard()).toBe(driftedNextCommand);
|
|
613
|
-
await page.locator('.skill-item').filter({ hasText: 'Legacy Disabled' }).click();
|
|
614
|
-
await expect
|
|
615
|
-
.poll(async () => {
|
|
616
|
-
return await page.locator('.lifecycle-card').textContent();
|
|
617
|
-
})
|
|
618
|
-
.toContain('Enable as draft');
|
|
619
|
-
await page.locator('.lifecycle-card').getByRole('button', { name: 'Copy next step' }).click();
|
|
620
|
-
expect(await readClipboard()).toBe("tabwright capability draft 'legacy-disabled'");
|
|
621
|
-
await page.locator('.skill-item').filter({ hasText: 'Legacy Trusted' }).click();
|
|
622
|
-
await expect
|
|
623
|
-
.poll(async () => {
|
|
624
|
-
return await page.locator('.lifecycle-card').textContent();
|
|
625
|
-
})
|
|
626
|
-
.toContain('Not yet checked for usability');
|
|
627
|
-
await page.locator('.lifecycle-card').getByRole('button', { name: 'Copy next step' }).click();
|
|
628
|
-
expect(await readClipboard()).toContain("tabwright capability run 'legacy-trusted'");
|
|
629
|
-
await page.locator('.skill-item').filter({ hasText: 'Historical Trusted' }).click();
|
|
630
|
-
await expect
|
|
631
|
-
.poll(async () => {
|
|
632
|
-
return await page.locator('.lifecycle-card').textContent();
|
|
633
|
-
})
|
|
634
|
-
.toContain('Not yet checked for usability');
|
|
635
|
-
await page.locator('.lifecycle-card').getByRole('button', { name: 'Copy next step' }).click();
|
|
636
|
-
expect(await readClipboard()).toBe(historicalTrustedNextCommand);
|
|
637
|
-
await page.locator('.skill-item').filter({ hasText: 'Future Lifecycle' }).click();
|
|
638
|
-
await expect
|
|
639
|
-
.poll(async () => {
|
|
640
|
-
return await page.locator('.lifecycle-card').textContent();
|
|
641
|
-
})
|
|
642
|
-
.toContain('This extension cannot interpret the capability lifecycle');
|
|
643
|
-
await expect
|
|
644
|
-
.poll(async () => {
|
|
645
|
-
return await page.locator('#skill-detail').textContent();
|
|
646
|
-
})
|
|
647
|
-
.not.toContain('future-run-format');
|
|
648
|
-
await page.locator('.lifecycle-card').getByRole('button', { name: 'Copy next step' }).click();
|
|
649
|
-
expect(await readClipboard()).toBe("tabwright capability describe 'future-lifecycle' --json");
|
|
650
|
-
await page.locator('.skill-item').filter({ hasText: 'Drifted User Query' }).click();
|
|
651
|
-
await page.locator('.language-button[data-language="zh_CN"]').click();
|
|
652
|
-
await expect
|
|
653
|
-
.poll(async () => {
|
|
654
|
-
return await page.locator('.lifecycle-card').textContent();
|
|
655
|
-
})
|
|
656
|
-
.toContain('下一步:重新检查');
|
|
657
|
-
await expect
|
|
658
|
-
.poll(async () => {
|
|
659
|
-
return await page.locator('.lifecycle-card').textContent();
|
|
660
|
-
})
|
|
661
|
-
.toContain('配置发生变化 · 检查于');
|
|
662
|
-
expect(await page.locator('.lifecycle-card').textContent()).not.toContain('$action$');
|
|
663
|
-
}
|
|
664
|
-
finally {
|
|
665
|
-
await testCtx.browserContext.clearPermissions();
|
|
666
|
-
await page.close();
|
|
667
|
-
await staticServer.close();
|
|
668
|
-
}
|
|
669
|
-
}, 30000);
|
|
670
|
-
test('shows a persistent degraded warning for stale relay review endpoints and clears it after recovery', async () => {
|
|
671
|
-
if (!testCtx) {
|
|
672
|
-
throw new Error('Test context is not initialized');
|
|
673
|
-
}
|
|
674
|
-
const distRoot = getExtensionDistRoot();
|
|
675
|
-
const staticServer = await createStaticServer(distRoot);
|
|
676
|
-
let reviewEndpointsAvailable = false;
|
|
677
|
-
const page = await testCtx.browserContext.newPage();
|
|
678
|
-
page.setDefaultTimeout(10000);
|
|
679
|
-
try {
|
|
680
|
-
await page.route(`http://127.0.0.1:${TEST_PORT}/**`, async (route) => {
|
|
681
|
-
const request = route.request();
|
|
682
|
-
const url = new URL(request.url());
|
|
683
|
-
const corsHeaders = {
|
|
684
|
-
'access-control-allow-origin': '*',
|
|
685
|
-
'access-control-allow-methods': 'GET,POST,OPTIONS',
|
|
686
|
-
'access-control-allow-headers': 'content-type',
|
|
687
|
-
};
|
|
688
|
-
if (request.method() === 'OPTIONS') {
|
|
689
|
-
await route.fulfill({ status: 204, headers: corsHeaders, body: '' });
|
|
690
|
-
return;
|
|
691
|
-
}
|
|
692
|
-
if (!reviewEndpointsAvailable) {
|
|
693
|
-
await route.fulfill({ status: 404, headers: corsHeaders, body: 'not found' });
|
|
694
|
-
return;
|
|
695
|
-
}
|
|
696
|
-
if (url.pathname === '/rrweb-recordings') {
|
|
697
|
-
await route.fulfill({
|
|
698
|
-
status: 200,
|
|
699
|
-
headers: { ...corsHeaders, 'content-type': 'application/json' },
|
|
700
|
-
body: JSON.stringify({ recordings: [] }),
|
|
701
|
-
});
|
|
702
|
-
return;
|
|
703
|
-
}
|
|
704
|
-
if (url.pathname === '/capabilities') {
|
|
705
|
-
await route.fulfill({
|
|
706
|
-
status: 200,
|
|
707
|
-
headers: { ...corsHeaders, 'content-type': 'application/json' },
|
|
708
|
-
body: JSON.stringify({ cwd: '/Users/test/project', capabilities: [] }),
|
|
709
|
-
});
|
|
710
|
-
return;
|
|
711
|
-
}
|
|
712
|
-
await route.fulfill({ status: 404, headers: corsHeaders, body: 'not found' });
|
|
713
|
-
});
|
|
714
|
-
await page.goto(`${staticServer.baseUrl}/src/options.html`, { waitUntil: 'domcontentloaded' });
|
|
715
|
-
await page.locator('.language-button[data-language="en"]').click();
|
|
716
|
-
await expect
|
|
717
|
-
.poll(async () => {
|
|
718
|
-
return await page.locator('#relay-review-warning').isVisible();
|
|
719
|
-
})
|
|
720
|
-
.toBe(true);
|
|
721
|
-
await expect
|
|
722
|
-
.poll(async () => {
|
|
723
|
-
return await page.locator('#relay-review-warning').textContent();
|
|
724
|
-
})
|
|
725
|
-
.toContain('Your files were not deleted');
|
|
726
|
-
await expect
|
|
727
|
-
.poll(async () => {
|
|
728
|
-
return await page.locator('#recordings-count').textContent();
|
|
729
|
-
})
|
|
730
|
-
.toBe('–');
|
|
731
|
-
await page.locator('.tab-button[data-tab="skills"]').click();
|
|
732
|
-
await expect
|
|
733
|
-
.poll(async () => {
|
|
734
|
-
return await page.locator('#skills-count').textContent();
|
|
735
|
-
})
|
|
736
|
-
.toBe('–');
|
|
737
|
-
await expect
|
|
738
|
-
.poll(async () => {
|
|
739
|
-
return await page.locator('#relay-review-warning').isVisible();
|
|
740
|
-
})
|
|
741
|
-
.toBe(true);
|
|
742
|
-
reviewEndpointsAvailable = true;
|
|
743
|
-
await page.locator('#refresh-button').click();
|
|
744
|
-
await expect
|
|
745
|
-
.poll(async () => {
|
|
746
|
-
return await page.locator('#skills-count').textContent();
|
|
747
|
-
})
|
|
748
|
-
.toBe('0');
|
|
749
|
-
await expect
|
|
750
|
-
.poll(async () => {
|
|
751
|
-
return await page.locator('#relay-review-warning').isVisible();
|
|
752
|
-
})
|
|
753
|
-
.toBe(true);
|
|
754
|
-
await page.locator('.tab-button[data-tab="recordings"]').click();
|
|
755
|
-
await page.locator('#refresh-button').click();
|
|
756
|
-
await expect
|
|
757
|
-
.poll(async () => {
|
|
758
|
-
return await page.locator('#recordings-count').textContent();
|
|
759
|
-
})
|
|
760
|
-
.toBe('0');
|
|
761
|
-
await expect
|
|
762
|
-
.poll(async () => {
|
|
763
|
-
return await page.locator('#relay-review-warning').isVisible();
|
|
764
|
-
})
|
|
765
|
-
.toBe(false);
|
|
766
|
-
}
|
|
767
|
-
finally {
|
|
768
|
-
await page.close();
|
|
769
|
-
await staticServer.close();
|
|
770
|
-
}
|
|
771
|
-
}, 30000);
|
|
772
|
-
});
|
|
773
|
-
//# sourceMappingURL=options-page.test.js.map
|