diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fd6e5572..dc19599f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,18 +2,19 @@ name: TeleDOM CI Pipeline on: push: - branches: [ main ] + branches: [ master, main, 'fix/**', 'feature/**' ] pull_request: - branches: [ main ] + branches: [ master, main ] + workflow_dispatch: jobs: build-and-test: - name: Build & Test (Node ${{ matrix.node-version }} on ${{ matrix.os }}) + name: Node ${{ matrix.node-version }} (${{ matrix.os }}) runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, windows-latest] - node-version: [18.x, 20.x, 22.x] + node-version: [20.x, 22.x] steps: - name: Checkout Repository @@ -32,6 +33,50 @@ jobs: - name: Run Unit Tests run: npm run test:unit + env: + NODE_OPTIONS: "--experimental-require-module" - name: Run Operational Test Suite run: npm run test:operational + env: + NODE_OPTIONS: "--experimental-require-module" + + python-sdk: + name: Python ${{ matrix.python-version }} (${{ matrix.os }}) + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + python-version: ["3.10", "3.11", "3.12"] + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Setup Node.js (for bridge server in operational tests) + uses: actions/setup-node@v4 + with: + node-version: 20.x + + - name: Install Node Dependencies & Build Server + run: | + npm install + npm run build + + - name: Setup Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install Python QA Tools + run: python -m pip install ruff mypy + + - name: Lint Python SDK (Ruff) + run: python -m ruff check sdk/python + + - name: Typecheck Python SDK (Mypy) + run: python -m mypy sdk/python + + - name: Run Python SDK Tests + run: python sdk/python/test_sdk.py + diff --git a/README.md b/README.md index 8401b771..f2afc491 100644 --- a/README.md +++ b/README.md @@ -1,138 +1,363 @@ -# ⚡ TeleDOM v4.1 +
-### 🧠 Temporal Browser Intelligence Engine + Agent-Owned Workflow Runtime · 350 Certified MCP Tools for Autonomous AI Agents +**English** · [فارسی (Persian)](README_FA.md) -[![TypeScript 5.8+](https://img.shields.io/badge/TypeScript-5.8%2B-blue.svg?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/) -[![Chrome Extension Manifest V3](https://img.shields.io/badge/Chrome_Extension-Manifest_V3-red.svg?style=flat-square&logo=googlechrome&logoColor=white)](https://developer.chrome.com/docs/extensions/mv3/) -[![Model Context Protocol 350 Tools](https://img.shields.io/badge/Model_Context_Protocol-350_Tools-purple.svg?style=flat-square&logo=probot&logoColor=white)](https://modelcontextprotocol.io/) -[![Certification 350/350 Stdio](https://img.shields.io/badge/Certification-350%2F350_Stdio-brightgreen.svg?style=flat-square&logo=checkmarx&logoColor=white)](#-testing--quality-verification) -[![Tests 319/319 Passed](https://img.shields.io/badge/Tests-319%2F319_Passed-success.svg?style=flat-square&logo=vitest&logoColor=white)](#-testing--quality-verification) -[![Python SDK](https://img.shields.io/badge/Python_SDK-Semantic_Browser_Programming-3776AB.svg?style=flat-square&logo=python&logoColor=white)](./sdk/python/) -[![License Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg?style=flat-square&logo=apache)](LICENSE) +TeleDOM Logo + +# TeleDOM v4.1 + +**Temporal Browser Intelligence Engine + Agent-Owned Workflow Runtime** + +*350 Certified MCP Tools • Sub-Millisecond Time-Travel DOM • Manifest V3 Chrome Extension • Zero-Dependency Python SDK* + +[![Version](https://img.shields.io/badge/version-4.1.0-blue.svg)](package.json) +[![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE) +[![TypeScript](https://img.shields.io/badge/TypeScript-5.8%2B-3178C6.svg?logo=typescript&logoColor=white)](https://www.typescriptlang.org/) +[![Python](https://img.shields.io/badge/Python-3.9%2B-3776AB.svg?logo=python&logoColor=white)](./sdk/python/) +[![Chrome Extension](https://img.shields.io/badge/Chrome_Extension-Manifest_V3-4285F4.svg?logo=googlechrome&logoColor=white)](https://developer.chrome.com/docs/extensions/mv3/) +[![MCP](https://img.shields.io/badge/MCP-350_Certified_Tools-7B1FA2.svg?logo=probot&logoColor=white)](./docs/TOOLS_CATALOG_350_EN.md) +[![Tests](https://img.shields.io/badge/tests-320%20passed-brightgreen.svg)](#running-tests--quality-verification) +[![Profiles](https://img.shields.io/badge/profiles-4_runtime_levels-orange.svg)](#token-efficient-operating-profiles) + +
--- -### 🌐 Language & Documentation Catalogs +## Table of Contents + +
+Jump to section + +- [What is TeleDOM?](#what-is-teledom) +- [Why use it?](#why-use-it) +- [Visual Demo & Architecture Preview](#visual-demo--architecture-preview) +- [Feature Highlights](#feature-highlights) +- [Tech Stack](#tech-stack) +- [Quick Start](#quick-start) +- [Token-Efficient Operating Profiles](#token-efficient-operating-profiles) +- [How it Works](#how-it-works) +- [Agent-Owned Workflows & Target Memory](#agent-owned-workflows--target-memory) +- [The 350 Certified MCP Tools Surface](#the-350-certified-mcp-tools-surface) +- [Dedicated Universal CLI (`dom-antigravity`)](#dedicated-universal-cli-dom-antigravity) +- [Python SDK Reference](#python-sdk-reference) +- [Settings & Environment Variables](#settings--environment-variables) +- [Session vs Persistent Data](#session-vs-persistent-data) +- [Supported Environments & Compatibility](#supported-environments--compatibility) +- [System Requirements](#system-requirements) +- [Development & Building from Source](#development--building-from-source) +- [Running Tests & Quality Verification](#running-tests--quality-verification) +- [Project Structure](#project-structure) +- [Troubleshooting](#troubleshooting) +- [Honest Limitations](#honest-limitations) +- [Security & Privacy Model](#security--privacy-model) +- [FAQ](#faq) +- [Documentation Index](#documentation-index) +- [Contributing & Security](#contributing--security) +- [License & Author](#license--author) + +
+ +--- + +## What is TeleDOM? + +**TeleDOM** is an enterprise-grade **Temporal Browser Intelligence Engine** and **Model Context Protocol (MCP)** platform providing **350 certified tools** for autonomous AI coding agents (Claude, Cursor, Antigravity, Cline, OpenAI Swarm) and frontend engineering teams. + +Instead of running inside an artificial, headless sandbox, TeleDOM connects directly to a live Chromium browser via a hardened Manifest V3 extension. It continuously records DOM mutations, user actions, network events, and layout shifts with nanosecond precision: + +- **Temporal EventMesh:** Hash-chained, tamper-evident event log with nanosecond timestamps, vector clocks, and causality links. +- **Sub-Millisecond DOM Time-Travel:** Reconstructs the exact virtual DOM state at any point in time ($State(T)$) for diffing and regression analysis. +- **Agent-Owned Workflows (TeleDOM Flow):** AI agents teach tasks once, persist them as parameterized programs, and rerun them with up to **80% fewer round trips** and **50% fewer DOM scans**. +- **Real User Context:** Runs against real user sessions, active logins, cookies, and extensions without brittle login re-authentication. -- 📖 **[Complete 350 Tools English Catalog (Documentation)](./docs/TOOLS_CATALOG_350_EN.md)** -- 🇮🇷 **[کاتالوگ جامع و تفصیلی ۳۵۰ ابزار به زبان فارسی](./docs/TOOLS_CATALOG_350_FA.md)** -- 🇮🇷 **[راهنمای فارسی پروژه (README_FA.md)](./README_FA.md)** -- ⚡ **[Agent-Owned Workflows (TeleDOM Flow)](./docs/workflow/AGENT_WORKFLOWS.md)** — teach once · reuse forever · prove what happened -- 🐍 **[Python SDK — Semantic Browser Programming](./docs/workflow/PYTHON_SDK.md)** -- 📋 **[Release Notes & Verification Report](./docs/workflow/RELEASE_NOTES.md)** -- 💡 **[250 Production Recipes (EXAMPLES.md)](./EXAMPLES.md)** | **[۲۵۰ مثال کاربردی فارسی](./EXAMPLES_FA.md)** -- 📊 **[Improvement Matrix (106 Improvements)](./docs/intelligence/IMPROVEMENTS.md)** -- 📈 **[Measured Benchmarks & Metrics](./docs/intelligence/BENCHMARKS.md)** +> **Name meaning:** *Tele* (remote observation and telemetry across system boundaries) + *DOM* (Document Object Model). TeleDOM bridges AI agents to the live temporal state of any webpage. + +> [!NOTE] +> TeleDOM runs **100% locally on your machine**. No cloud telemetry, no remote analytics, and zero external network calls during normal operation. + +--- + +## Why use it? + +| Problem in Existing Solutions | TeleDOM Solution | +|-------------------------------|-------------------| +| **Headless blank sandbox:** Conventional Puppeteer/Playwright instances lack user logins, cookies, and saved sessions | **Real Chrome session:** Connects directly to the user's active browser profile with full extension and auth state | +| **Brittle scrapers & agents:** AI agents re-explore pages from scratch on every run, wasting time and tokens | **Agent-Owned Workflows & Target Memory:** Persists discovered elements and multi-step flows for instant verbatim replay | +| **Token context bloat:** Dumping 50k+ lines of raw HTML quickly exhausts the LLM's context window | **4 Token-Efficient Profiles:** Scales schema exposure from ~2,400 tokens (`minimal`) up to full enterprise (`full`) | +| **Ephemeral errors:** Transient DOM bugs, layout shifts, and race conditions disappear after page reloads | **Sub-millisecond Time-Travel ($State(T)$):** Deterministic snapshot interpolation at any historical timestamp | +| **Hallucinated assertions:** AI tools often assume actions succeeded without proof | **Formal Invariants & Proof Engine:** Mathematical verification of DOM structural equivalence and zero false positives | +| **Manual DevTools debugging:** Engineers spend hours sifting through network waterfalls and console logs | **Autonomous Root-Cause Investigator (`td_investigate`):** Generates hypothesis graphs and portable `.tdom` bundles | +| **Chrome MV3 30s timeouts:** Manifest V3 service workers get terminated by Chrome during long agent tasks | **24s Alarm Heartbeat:** Self-healing keep-alive pulse + DevTools (F12) CDP collision protection | +| **Dangerous automated mutations:** Blind AI clicks can trigger unintended state modifications or deletions | **Safe Mutation Engine:** Atomic transactional dry-runs with guaranteed zero-cost rollbacks | --- -## ⚡ v4.1 — The Agent-Owned Workflow Runtime +## Visual Demo & Architecture Preview -> **TeleDOM is not the decision-maker; TeleDOM is the enabler.** -> **The Agent is the brain. TeleDOM is the hands, eyes, memory and browser toolbox.** -> *Teach the browser task once. Turn it into a reusable program. Run it anywhere the browser can go.* +
+ +![TeleDOM Autonomous AI Agent Live Demo](https://raw.githubusercontent.com/IrMaho/TeleDOM/master/assets/teledom_live_agent_demo.gif) + +> 🎬 **Live Automation Demo:** Autonomous AI agent driving real-time browser forensic recording, live DOM inspection, synthetic actions, and multi-turn workflows. ([Watch Full 1080p Video](./assets/teledom_live_agent_demo.mp4)) + +
```text -AGENT — discover · reason · write workflows · version · debug · repair · generate bots - │ MCP (Level 1: 350 tools) ──────────────┐ - │ Python SDK (Level 2: semantic browser) ─┐ │ - ▼ ▼ -TELEDOM — browser observation · primitives · target memory · - workflow persistence · DUMB execution · evidence · replay · proof ++-------------------------------------------------------------------------+ +| AI AGENT / CLIENT | +| (Antigravity IDE · Cursor · Claude Desktop · Cline) | ++------------------------------------+------------------------------------+ + | (JSON-RPC 2.0 over stdio) + v ++-------------------------------------------------------------------------+ +| TELEDOM V4.1 MCP SERVER (350 TOOLS) | +| ├── 144 td_* Temporal Intelligence & Workflow Runtime Tools | +| ├── 54 dt_* Chrome DevTools Fusion Tools | +| ├── 31 fx_* Advanced Visual & Forensic Tools | +| ├── 121 Core & Live Interaction Tools | +| └── Zero-Config On-Demand Auto-Bridge Dispatcher (:3847) | ++------------------+------------------------------------+-----------------+ + | | (WebSocket :3847) + v v ++------------------------------------+ +---------------------------------+ +| WORKFLOW RUNTIME ENGINE | | CHROME EXTENSION (MV3) | +| ├── Workflow Persistence & Diff | | ├── MutationObserver Engine | +| ├── Target Memory Fingerprints | | ├── Ctrl+Shift+Click Picker | +| ├── EventMesh & Causal Graph | | ├── Canvas Screenshot Pipeline | +| └── Verification & Formal Proofs | | └── Synthetic Action Driver | ++------------------------------------+ +---------------------------------+ ``` -### The Golden Automation Demo +| Operating Surface | Primary Purpose | +|-------------------|-----------------| +| **MCP Server (`stdio`)** | Exposes 350 certified tools to any Model Context Protocol-compatible AI agent | +| **CLI (`dom-antigravity`)** | One-click workspace installation, status diagnostics, clean screenshots, bridge daemon | +| **Chrome Extension (MV3)** | Captures mutations, coordinates element picking, executes synthetic clicks/types | +| **Python SDK (`teledom`)** | Zero-dependency Python 3.9+ library for programmatic, semantic browser automation | -```text -RUN #1 (explore) 5 tool calls · 2 DOM scans · 5 MCP round trips - → agent learns: saves learned targets + writes the workflow +--- -RUN #2 (reuse) 1 td_workflow_run call · 1 DOM scan - ✔ verify_cta ✔ click_cta ✔ extract ✔ assert → SUCCESS - deterministic execution record + verbatim replay +## Feature Highlights -KPIs: 80% fewer MCP round trips · 50% fewer DOM scans · replay PASS - 0 unsafe-action bypass · 0 workflow corruption · 350/350 certified +- **Agent-Owned Workflow Runtime:** Build, parameterize, version, diff, and execute complex multi-step web programs (`td_workflow_run`). +- **Target Memory & Fingerprinting:** Persists discovered DOM selectors and signatures to eliminate repetitive element searches. +- **Nanosecond Temporal EventMesh:** Tamper-evident hash-chained event log with vector clocks, causality chains, and Merkle root verification. +- **Sub-Millisecond DOM Time-Travel:** Instant reconstruction of exact virtual DOM state at any past timestamp $T$ ($State(T)$). +- **Counterfactual Browser Simulation:** Branch virtual DOM executions, suppress mutations or network requests, and compare alternative outcomes. +- **Autonomous Incident Investigator:** Single-command triage (`td_investigate`), multi-stage hypothesis generation, and portable `.tdom` bundles. +- **Safe Mutation Engine:** Transactional DOM modifications with immutable diffs, side-effect-free dry runs, and guaranteed rollbacks. +- **Passive Security Intelligence:** Zero-trust page scanning, prompt-injection defense, runtime XSS detection, and automatic credential sanitization. +- **4 Configurable Runtime Profiles:** Scale from ultra-lean 22 tools (~2,400 tokens) to the complete 350-tool enterprise suite. +- **Zero-Dependency Python SDK:** Native Python 3.9+ interface with context managers for high-level browser control. +- **Universal Stdio JSON-RPC 2.0 Certification:** 350/350 tools fully certified against real operational test schemas. + +--- + +## Tech Stack + +| Layer | Technology | Purpose | +|-------|------------|---------| +| **Core Runtime** | Node.js 22+ & TypeScript 5.8+ | Non-blocking async MCP server, EventMesh, and storage engine | +| **Agent Protocol** | Model Context Protocol (MCP) | Universal JSON-RPC 2.0 interface for AI coding agents | +| **Browser Extension** | Chrome Extension Manifest V3 | MutationObserver, WeakMap element binding, Canvas cropping | +| **Browser Integration** | Chrome DevTools Protocol (CDP) | Direct DevTools inspection, Lighthouse audits, network HAR | +| **Python SDK** | Pure Python 3.9+ (Zero Dependencies) | High-level `Browser` and `Workflow` semantic client | +| **Testing & QA** | Vitest 3.x, Ruff, Mypy | Unit tests, Python typing, and operational stdio certification | +| **Platforms** | Windows 10/11, macOS, Linux | Cross-platform desktop and CI execution support | + +--- + +## Quick Start + +### Option A — One-Click Setup for AI Coding Agents (Recommended) + +Install the global CLI and configure your agent workspace: + +```bash +# 1. Install CLI globally +npm install -g teledom + +# 2. Configure TeleDOM for your current workspace (.agents) +dom-antigravity install --workspace + +# Or register globally for all projects in Antigravity IDE: +dom-antigravity install --global ``` -### 44 New Production Tools in v4.1: +### Option B — Run from Source (Developers) -| Family | Tool Count | Tools Included | -|---|:---:|---| -| **Browser Primitives** | **22** | `td_browser_*` · `td_dom_inspect/query/extract/snapshot` · `td_target_find/check/describe` · `td_action_click/type/select/hover/press/scroll` · `td_wait` · `td_screenshot` · `td_execute_script` · `td_network_inspect` · `td_console_read` | -| **Workflow Runtime** | **14** | `td_workflow_save/get/list/update/delete/clone/diff/export/import/validate/run/runs/run_get/replay` — dumb execution with policy gates, deterministic records, verbatim replay | -| **Agent-Owned Tooling** | **8** | `td_target_memory_*` (learned targets — no DOM re-analysis) · `td_agent_artifact_*` (custom tools, scripts, policies — stored verbatim, never interpreted) | +```bash +git clone https://github.com/IrMaho/TeleDOM.git +cd TeleDOM +npm install +npm run build +npm run test:unit +``` -Browser-first, **API-optional**: web applications and complex SPAs without public APIs are the primary target, not the exception. The AI agent chooses its own discovery strategy (DOM → semantics → accessibility → script → coordinates) whenever abstractions fail — TeleDOM provides rock-solid, deterministic execution primitives. +### Option C — Python SDK + +```bash +pip install ./sdk/python +``` + +```python +from teledom import Browser + +with Browser() as browser: + browser.inspect() + browser.type("#search-box", "Autonomous Coding Agents") + browser.click("#submit-btn") +``` + +### First Workflow in 60 Seconds + +1. Load the unpacked Chrome extension from `teledom/dist/extension` in `chrome://extensions/`. +2. Connect your AI agent (Antigravity IDE, Cursor, Claude Desktop) via MCP. +3. The server **automatically spawns the WebSocket bridge** on port `3847` on demand. +4. Let the agent inspect the page and record a workflow: + ```json + {"name": "td_workflow_save", "arguments": {"name": "login_flow", "steps": [...]}} + ``` +5. Replay the workflow anytime with single-call deterministic precision: + ```json + {"name": "td_workflow_run", "arguments": {"workflow_id": "login_flow"}} + ``` --- -## ⚡ Overview & TeleDOM in One Line +## Token-Efficient Operating Profiles -> **TeleDOM in one line:** *See what happened. Understand why. Simulate what-if. Fix safely. Prove the result.* +To eliminate context window bloat and reduce token expenses by up to **94%**, TeleDOM introduces 4 runtime profiles via the `TELEDOM_PROFILE` environment variable: -TeleDOM is a production-grade **Temporal Browser Intelligence Engine** and universal **Model Context Protocol (MCP)** platform providing **350 certified tools** for autonomous AI coding agents (Claude, Cursor, Antigravity, Cline, OpenAI Swarm) and frontend engineering teams. +| Profile | Exposed Tools | Approx. Schema Tokens | Best For | Description | +|:---|:---:|:---:|:---|:---| +| **`minimal`** | **22** | **~2,400 tokens** | Budget LLMs & fast agent tasks | Core browsing: navigate, click, type, inspect, screenshot | +| **`core`** | **42** | **~4,800 tokens** | Autonomous navigation & workflows | Core actions + target memory + workflow runtime | +| **`forensics`** | **74** | **~8,500 tokens** | QA debugging, audits & triage | Visual regressions, DOM diffs, network & console logs | +| **`full`** *(default)* | **350** | **~40,000 tokens** | Deep reasoning & enterprise suites | Complete 350-tool surface with full backward compatibility | -Every important claim is backed by mathematical evidence, confidence scoring, provenance tracking, and machine-verifiable proof. +```bash +# Launch MCP server with the ultra-lean core profile +TELEDOM_PROFILE=core npx teledom +``` -### v4.1 Measured Verification Metrics (generated by `npm run bench` — [full matrix](./docs/intelligence/BENCHMARKS.md)) +--- -| Metric | Result | Description | -|---|---|---| -| **Golden Incident Suite (1,032 scenarios × 24 categories)** | **100.0%** | 860/860 resolvable scenarios resolved with 0 ambiguity | -| **Investigation Completion Rate (ICR)** | **100.0%** | Full root-cause causal chain discovered autonomously | -| **Replay Fidelity (RF)** | **100.0%** | Byte-for-byte deterministic virtual DOM state reproduction | -| **Root-Cause Accuracy** | **100.0%** | Exact fault classification (unmount, CSS, race condition, error) | -| **False Success Rate** | **0.00%** | Zero false-positive diagnostic reports | -| **Chaos Engineering Suite (16 injections)** | **16/16 contained** | Full containment, observation, explanation, and auto-recovery | -| **Operational JSON-RPC Certification** | **350/350 tools CERTIFIED** | Real stdio JSON-RPC 2.0 captures with schema validation | -| **Unit & Integration Test Suite** | **319/319 tests green** | 100% pass rate across 36 test suites | -| **Improvement Matrix** | **106 validated items** | 104 implemented, 2 explicitly deferred with architectural reasons | +## How it Works + +```mermaid +flowchart LR + A["AI Agent / LLM"] -->|"JSON-RPC 2.0 / stdio"| B["ForensicMCPServer"] + B -->|"Auto-Bridge (Port 3847)"| C["Chrome MV3 Extension"] + C -->|"MutationObserver"| D["Target Webpage"] + D -->|"Nanosecond Events"| E["Temporal EventMesh"] + E -->|"Time-Travel Snapshot"| F["Virtual DOM State(T)"] + F -->|"Deterministic Replay"| G["Mathematical Proof & Verification"] +``` + +```mermaid +flowchart TB + subgraph AgentLayer["Agent Layer"] + IDE["Antigravity IDE / Cursor / Claude"] + PY["Python SDK teledom"] + CLI["Universal CLI dom-antigravity"] + end + + subgraph ServerLayer["TeleDOM MCP Runtime (Node.js)"] + MCP["ForensicMCPServer (350 Tools)"] + WF["Workflow Runtime Engine"] + TM["Target Memory Store"] + EM["Temporal EventMesh Kernel"] + CE["Causal & Incident Investigator"] + AB["Zero-Config Auto-Bridge"] + end + + subgraph BrowserLayer["Browser Runtime (Chrome MV3)"] + CS["Content Script & WeakMap NodeId"] + MO["MutationObserver Engine"] + EV["Synthetic Action Dispatcher"] + SC["Canvas Screenshot Pipeline"] + end + + IDE --> MCP + PY --> MCP + CLI --> AB + MCP --> WF + MCP --> TM + MCP --> EM + MCP --> CE + MCP --> AB + AB <-->|"WebSocket Frames (Port 3847)"| CS + CS --> MO + CS --> EV + CS --> SC +``` --- -## 🚀 Live Demo +## Agent-Owned Workflows & Target Memory -![TeleDOM Autonomous AI Agent Live Demo](https://raw.githubusercontent.com/IrMaho/TeleDOM/master/assets/teledom_live_agent_demo.gif) +TeleDOM v4.1 shifts browser automation from fragile, manual scripting to **agent-authored reusable programs**: + +```text +RUN #1 (Explore) 5 tool calls · 2 DOM scans · 5 MCP round trips + → Agent learns: saves learned targets + writes the workflow -> 🎬 **Live Automation Demo:** Autonomous AI Coding Agent driving real-time browser forensic recording, live DOM inspection, synthetic actions, and multi-turn autonomous web flows. ([Watch Full 1080p Video](./assets/teledom_live_agent_demo.mp4)) +RUN #2 (Reuse) 1 td_workflow_run call · 1 DOM scan + ✔ verify_cta ✔ click_cta ✔ extract ✔ assert → SUCCESS + Deterministic execution record + verbatim replay + +KPIs: 80% fewer MCP round trips · 50% fewer DOM scans · replay PASS + 0 unsafe-action bypass · 0 workflow corruption · 350/350 certified +``` + +### 44 Specialized v4.1 Tools: + +| Family | Count | Tools Included | +|---|:---:|---| +| **Browser Primitives** | **22** | `td_browser_*`, `td_dom_*`, `td_target_*`, `td_action_*`, `td_wait`, `td_screenshot`, `td_execute_script`, `td_network_inspect`, `td_console_read` | +| **Workflow Runtime** | **14** | `td_workflow_save/get/list/update/delete/clone/diff/export/import/validate/run/runs/run_get/replay` | +| **Agent-Owned Tooling** | **8** | `td_target_memory_*` (persistent targets), `td_agent_artifact_*` (custom tools & policies) | --- -## 📖 Table of Contents - -- [⚡ v4.1 — The Agent-Owned Workflow Runtime](#-v41--the-agent-owned-workflow-runtime) -- [⚡ Overview & TeleDOM in One Line](#-overview--teledom-in-one-line) -- [🐍 Python SDK Quickstart](#-python-sdk-quickstart) -- [✨ Key Capabilities](#-key-capabilities) -- [💻 Dedicated Universal CLI (`dom-antigravity`)](#-dedicated-universal-cli-dom-antigravity) -- [🏗️ System Architecture](#-system-architecture) - - [Dual-Environment Execution Model](#dual-environment-execution-model) - - [High-Level Architecture Diagram](#high-level-architecture-diagram) - - [Zero-Config On-Demand Auto-Bridge](#-zero-config-on-demand-auto-bridge) - - [Clean Screenshot & Visual Forensics Pipeline](#-clean-screenshot--visual-forensics-pipeline) - - [Time-Travel Reconstruction Engine](#time-travel-reconstruction-engine) -- [📁 Repository Structure](#-repository-structure) -- [🤖 Model Context Protocol (MCP) 350 Tools Reference](#-model-context-protocol-mcp-350-tools-reference) - - [1. 144 `td_*` Temporal Intelligence & Workflow Runtime Tools](#1-144-td_-temporal-intelligence--workflow-runtime-tools) - - [2. 54 `dt_*` Chrome DevTools Fusion Tools](#2-54-dt_-chrome-devtools-fusion-tools) - - [3. 31 `fx_*` Advanced Visual & Forensic Tools](#3-31-fx_-advanced-visual--forensic-tools) - - [4. 121 Core & Live Interaction Tools](#4-121-core--live-interaction-tools) -- [🚀 Installation & Quick Start](#-installation--quick-start) - - [1. Global System Installation (One-Click)](#1-global-system-installation-one-click) - - [2. Workspace Installation for Any Project](#2-workspace-installation-for-any-project) - - [3. Load Chrome Extension in Browser](#3-load-chrome-extension-in-browser) - - [4. Configure External AI Clients (Claude / Cursor / Cline)](#4-configure-external-ai-clients-claude--cursor--cline) -- [🧪 Testing & Quality Verification](#-testing--quality-verification) -- [🔐 Security, Privacy & Performance](#-security-privacy--performance) -- [❓ Troubleshooting & FAQ](#-troubleshooting--faq) -- [📜 License](#-license) +## The 350 Certified MCP Tools Surface + +TeleDOM provides the most comprehensive browser toolset available for AI agents, certified 100% against operational schemas: + +| Family | Prefix | Tool Count | Primary Responsibilities | +|---|---|:---:|---| +| **Temporal Intelligence & Workflows** | `td_*` | **144** | EventMesh, Causal analysis, Evidence Graph, Counterfactuals, Workflow runtime, Target memory, Proofs, Security | +| **Chrome DevTools Fusion** | `dt_*` | **54** | Direct DevTools inspection, Lighthouse audits, HeapSnapshots, Network HAR, Console logs, Emulation | +| **Advanced Forensic Capabilities** | `fx_*` | **31** | Network-DOM correlation, Visual regression, Layout shifts, Z-index occlusion, Safe mutation guards | +| **Core & Live Interaction** | Core / v3 | **121** | Live element picking, screenshot cropping, synthetic actions, DOM diffing, time-travel, lifecycle traces | +| **Total Certified Tools** | | **350** | **100% Operational Stdio Certification (350/350 PASS)** | + +> Complete parameter schemas and operational examples: +> - 📖 **[English Tools Catalog (3,800+ lines)](./docs/TOOLS_CATALOG_350_EN.md)** +> - 🇮🇷 **[کاتالوگ جامع ۳۵۰ ابزار به زبان فارسی](./docs/TOOLS_CATALOG_350_FA.md)** --- -## 🐍 Python SDK Quickstart +## Dedicated Universal CLI (`dom-antigravity`) + +Registered binary with aliases `mcp-dom` and `browser-antigravity`: -TeleDOM provides an official, zero-dependency Python SDK (`sdk/python/teledom`): +| Command | Option / Alias | Description | +|---------|----------------|-------------| +| `dom-antigravity install` | `--workspace` (`-w`) | Configure TeleDOM in current workspace (`.agents/mcp_config.json`) | +| `dom-antigravity install` | `--global` (`-g`) | Configure TeleDOM globally for all projects in Antigravity IDE | +| `dom-antigravity install` | `--target ` | Install MCP config into a specific directory | +| `dom-antigravity status` | | Check bridge server health (`:3847`) and connected Chrome tabs | +| `dom-antigravity screenshot` | | Capture pristine live full-page & element screenshots to disk | +| `dom-antigravity bridge` | | Start WebSocket bridge manually (optional — Auto-Bridge handles this) | +| `dom-antigravity config` | `cursor` / `claude` | Print ready-to-use JSON configuration blocks | + +--- + +## Python SDK Reference + +Zero-dependency Python package (`sdk/python/teledom`): ```python from teledom import Browser, Workflow @@ -143,148 +368,147 @@ with Browser() as browser: browser.type("#search-box", "Autonomous Agents") browser.click("#submit-btn") - # 2. Workflow creation & execution + # 2. Build and persist a workflow wf = Workflow("triage_issues", client=browser.client) wf.input("filter", "Issue label filter", default="bug") - wf.step("filter_step", "td_target_check", args={"selector": ".issue-row"}) + wf.step("check_table", "td_target_check", args={"selector": ".issue-row"}) wf.save(version="1.0.0") - # 3. Execute with deterministic audit record + # 3. Deterministic execution run = wf.run({"filter": "security"}) - print("Workflow run status:", run["run"]["status"]) + print("Run status:", run["run"]["status"]) ``` --- -## ✨ Key Capabilities - -| Capability | Description | -| :--- | :--- | -| **Agent-Owned Workflow Engine** | Build, parameterize, version, diff, and execute complex multi-step browser programs without writing custom scrapers. | -| **Target Memory & Fast Resolution** | Persist discovered element identities (`td_target_memory_save`) to eliminate repetitive DOM explorations on subsequent runs. | -| **Temporal EventMesh Kernel** | Hash-chained tamper-evident event log with nanosecond timestamps, vector clocks, causality links, and Merkle root verification. | -| **Sub-Millisecond DOM Time-Travel** | Instant state reconstruction at any arbitrary timestamp $T$ or event $E$ (`State(T)`), diff calculation, and timeline queries. | -| **Counterfactual Browser Simulation** | Branch virtual execution, suppress network calls or mutations, simulate alternative DOM branches, and compare counterfactual outcomes. | -| **Safe Mutation Engine** | Atomic transactional DOM modifications with immutable before/after diffs, side-effect-free dry runs, and guaranteed zero-cost rollbacks. | -| **Autonomous Incident Investigator** | Single-command root-cause triage (`td_investigate`), multi-stage hypothesis generation, evidence scoring, and `.tdom` portable incident bundles. | -| **Mathematical Proof & Verification** | Formal invariants verification (`StateInvariant`), structural equivalence proofs, regression assertions, and zero false-positive certification. | -| **Passive Security Intelligence** | Zero-trust page scanning, runtime XSS vulnerability detection, open CORS/CSP misconfiguration analysis, secret redaction, and prompt-injection defense. | -| **Self-Healing Runtime & Guardian** | Circuit-breaker protection, memory leak detection, garbage collector retention trees, and self-repairing WebSocket bridge connections. | -| **350 Universal JSON-RPC 2.0 MCP Tools** | The largest and most comprehensive browser toolset for AI agents across temporal intelligence, DevTools, forensics, and live automation. | +## Settings & Environment Variables + +| Variable | Default | Description | +|----------|---------|-------------| +| `TELEDOM_PROFILE` | `full` | Operating profile: `minimal` (22), `core` (42), `forensics` (74), `full` (350) | +| `TELEDOM_PORT` | `3847` | WebSocket & HTTP bridge server port | +| `TELEDOM_BRIDGE_TOKEN` | *None* | Optional Bearer auth token for bridge mutating endpoints | +| `TELEDOM_STORAGE_DIR` | `.teledom` | Directory path for local incident bundles and session data | +| `TELEDOM_HEADLESS` | `false` | Set `true` to run against headless Chrome with CDP | +| `DEBUG` | `false` | Enable verbose JSON-RPC and EventMesh debug logging | --- -## 💻 Dedicated Universal CLI (`dom-antigravity`) +## Session vs Persistent Data -The package exposes a global CLI binary registered as `dom-antigravity` (with aliases `mcp-dom` and `browser-antigravity`): +| Data Category | Storage Location | Persists across restarts? | +|---------------|------------------|:-------------------------:| +| **Workflows & Steps** | `.mcpdom_projects/workflows/` | **Yes** | +| **Target Memory Signatures** | `.mcpdom_projects/targets/` | **Yes** | +| **Incident Bundles (`.tdom`)** | `.forensic_sessions/` | **Yes** | +| **Live WebSocket Bridge** | Port `:3847` in-memory | **No** (reconnects automatically) | +| **Virtual DOM Memory Caches** | Node.js process heap | **No** (reconstructed on demand) | -```bash -# 1. Install MCP configuration & skills into current workspace (.agents) -dom-antigravity install --workspace -# Short alias: -dom-antigravity install -w +> [!IMPORTANT] +> Target Memory and Workflows store only structural selectors and execution schemas. User credentials, credit cards, and auth tokens are **never written to disk** thanks to built-in `PrivacyEngine` sanitization. -# 2. Install globally for ALL projects in Antigravity IDE -dom-antigravity install --global -# Short alias: -dom-antigravity install -g +--- + +## Supported Environments & Compatibility -# 3. Install into a specific target directory -dom-antigravity install --target "C:/path/to/project" +| Category | Supported Versions | Notes | +|----------|-------------------|-------| +| **Browsers** | Chrome 120+, Chromium, Edge, Brave | Manifest V3 extension support required | +| **Node.js** | 18.x, 20.x, 22.x LTS | Built and certified on Node 22 | +| **Python** | 3.9, 3.10, 3.11, 3.12, 3.13 | Zero third-party dependencies required | +| **Operating Systems** | Windows 10/11, macOS, Linux | Full cross-platform support | +| **AI Agent Clients** | Antigravity IDE, Cursor, Claude Desktop, Cline, Windsurf | Standard Model Context Protocol (MCP) | -# 4. Check bridge server health & connected Chrome tabs -dom-antigravity status +--- + +## System Requirements -# 5. Capture clean live Chrome screenshot (Full Page + Cropped Element) -dom-antigravity screenshot +| Component | Minimum Requirement | Recommended | +|-----------|---------------------|-------------| +| **Operating System** | Windows 10, macOS 12, Ubuntu 20.04 | Windows 11 / macOS 14 | +| **Node.js** | 18.18.0+ | 22.x LTS | +| **Python** | 3.9+ (optional for SDK) | 3.11+ | +| **RAM** | 4 GB | 8 GB+ for heavy DOM time-travel | +| **Disk Space** | 200 MB | 500 MB (including test bundles) | +| **Browser** | Google Chrome 120+ | Latest Stable Chrome | -# 6. Start WebSocket Bridge manually (Optional — Auto-Bridge handles this on demand) -dom-antigravity bridge +--- -# 7. Print ready-to-use JSON configuration for Claude Desktop or Cursor -dom-antigravity config cursor -dom-antigravity config claude +## Development & Building from Source + +```bash +# Install dependencies +npm install + +# Build all components (Client UI, Chrome Extension, MCP Server) +npm run build + +# Specialized build targets +npm run build:client # Vite client build +npm run build:extension # Chrome MV3 extension bundle +npm run build:server # Vite MCP server bundle ``` --- -## 🏗️ System Architecture +## Running Tests & Quality Verification -### Dual-Environment Execution Model +```bash +# 1. Master QA Suite (Build + 320 Unit Tests + 17 Python SDK Tests + Linting) +npm run qa:all -TeleDOM operates cleanly across two distinct runtime environments: +# 2. Unit and Intelligence Test Suite (320 tests, 100% green) +npm run test:unit -1. **Browser Runtime (Chrome Extension Manifest V3 / Content Script / Injected Page Context)**: - - Captures low-level DOM mutations using `MutationObserver`. - - Binds persistent `LogicalNodeId` identifiers to live nodes via `WeakMap`. - - Listens to `Ctrl + Shift + Mouse Click` for visual element picking. - - Executes synthetic live actions (`click`, `type`, `hover`, `focus`, `scroll`, `drag`). - - Renders cropped element bounding boxes on HTML5 Canvas. - - Hides floating overlays during screenshot captures. +# 3. Python SDK Self-Test Suite (17 tests) +npm run test:sdk -2. **Node.js / MCP Server Runtime (`ForensicMCPServer`)**: - - Exposes **350 JSON-RPC 2.0 MCP tools** over `stdio` and HTTP. - - Auto-spawns and manages the WebSocket bridge on port `3847`. - - Powers the Temporal EventMesh kernel, Causal Engine, and Evidence Graph. - - Reconstructs virtual DOM snapshots at sub-millisecond timestamps. - - Executes counterfactual simulations, incident investigations, and formal proofs. +# 4. Python SDK Lint & Type Checks (Ruff + Mypy) +npm run lint:python ---- +# 5. Full Operational Stdio Certification (350/350 tools CERTIFIED) +npm run test:operational -### High-Level Architecture Diagram +# 6. Deterministic Benchmarks (10K / 100K / 1M events) +npm run bench -```text -┌────────────────────────────────────────────────────────────────────────┐ -│ AI AGENT / MCP CLIENT │ -│ (Antigravity IDE / Cursor / Claude Desktop / CLI) │ -└───────────────────────────────────┬────────────────────────────────────┘ - │ (JSON-RPC 2.0 over stdio) - ▼ -┌────────────────────────────────────────────────────────────────────────┐ -│ TELEDOM V4.1 MCP SERVER (350 TOOLS) │ -│ ├── 144 td_* Temporal Intelligence & Workflow Runtime Tools │ -│ ├── 54 dt_* Chrome DevTools Fusion Tools │ -│ ├── 31 fx_* Advanced Forensic Capabilities │ -│ ├── 121 Core & Live Interaction Tools │ -│ └── Zero-Config On-Demand Auto-Bridge Dispatcher │ -└───────────────────┬────────────────────────────────┬───────────────────┘ - │ │ (WebSocket / HTTP :3847) - ▼ ▼ -┌───────────────────────────────┐ ┌────────────────────────────────────┐ -│ WORKFLOW RUNTIME │ │ LIVE WEBSOCKET BRIDGE SERVER │ -│ ├── Workflow Persistence │ │ (Port 3847 - Auto-Managed) │ -│ ├── Target Memory Store │ └─────────────────┬──────────────────┘ -│ ├── EventMesh & Causal Graph │ │ -│ ├── Counterfactual Engine │ │ (Bi-directional JSON frames) -│ └── Verification & Proofs │ ▼ -└───────────────────────────────┘ ┌────────────────────────────────────┐ - │ CHROME EXTENSION (MV3) │ - │ ├── Mutation Observer Engine │ - │ ├── Ctrl+Shift+Click Live Picker │ - │ ├── Canvas Screenshot Pipeline │ - │ └── Synthetic Interaction Driver │ - └────────────────────────────────────┘ +# 7. Golden Incident Suite (1,032 scenarios) +npm run golden + +# 8. Chaos Engineering Injections (16/16 contained) +npm run chaos ``` +### Verification Metrics: + +| Metric | Result | Description | +|---|---|---| +| **Golden Incident Suite** | **100.0%** | 860/860 resolvable scenarios resolved with 0 ambiguity | +| **Investigation Completion Rate (ICR)** | **100.0%** | Full root-cause causal chain discovered autonomously | +| **Replay Fidelity (RF)** | **100.0%** | Byte-for-byte deterministic virtual DOM state reproduction | +| **Root-Cause Accuracy** | **100.0%** | Exact fault classification (unmount, CSS, race condition) | +| **Operational JSON-RPC Certification** | **350/350 tools CERTIFIED** | Real stdio JSON-RPC 2.0 captures with schema validation | +| **Unit & Integration Test Suite** | **320/320 tests green** | 100% pass rate across 36 test suites | + --- -## 📁 Repository Structure +## Project Structure ```text teledom/ ├── src/ │ ├── intelligence/ # Temporal Intelligence Engine (EventMesh, Causal, Proof, Incident) │ │ └── workflow/ # v4.1 Agent-Owned Workflow Runtime (domain, executor, store, facade) -│ ├── core/ # Core recorders, sequence counters, privacy, PNG builder +│ ├── core/ # Core recorders, sequence counters, privacy engine, PNG builder │ ├── diff/ # Structural DOM diff engine (attributes, classes, styles, subtrees) │ ├── extension/ # Chrome Extension Manifest V3 (content scripts, service worker) │ ├── lifecycle/ # Lifecycle tracer, disappearing UI analyzer │ ├── mcp/ # Universal MCP Server, 350 tools definition, dispatchers │ ├── reconstruction/ # Sub-millisecond snapshot interpolation & time-travel │ ├── storage/ # Local disk storage & indexing engine -│ └── ui/ # Observatory UI, visual state viewers +│ └── ui/ # Observatory UI & visual state viewers ├── sdk/ -│ └── python/ # Official Python SDK (BrowserController, WorkflowEngine, TargetMemory) +│ └── python/ # Official Python SDK (Browser, Workflow, TargetMemory) ├── docs/ │ ├── TOOLS_CATALOG_350_EN.md # Complete English reference for all 350 tools │ ├── TOOLS_CATALOG_350_FA.md # کاتالوگ جامع ۳۵۰ ابزار به زبان فارسی @@ -298,145 +522,95 @@ teledom/ │ └── operational/ # Full 350/350 JSON-RPC stdio acceptance test suite ├── operational-tests/ # 350 dedicated folders with test definitions & assertions ├── package.json # Version 4.1.0, scripts, dependencies -└── README.md # English documentation (this file) +├── README.md # English documentation (this file) +└── README_FA.md # Persian documentation (راهنمای فارسی) ``` --- -## 🤖 Model Context Protocol (MCP) 350 Tools Reference +## Troubleshooting -TeleDOM v4.1 exposes **350 production-ready JSON-RPC 2.0 tools** grouped into four distinct families. - -For detailed schemas, parameter documentation, and operational examples for all 350 tools: -- 📖 **[English Tools Catalog (3,800+ lines)](./docs/TOOLS_CATALOG_350_EN.md)** -- 🇮🇷 **[کاتالوگ جامع ۳۵۰ ابزار به زبان فارسی (۳,۹۰۰+ سطر)](./docs/TOOLS_CATALOG_350_FA.md)** - -### Summary of Tool Families - -| Family | Prefix / Category | Tool Count | Description | -|---|---|:---:|---| -| **Temporal Intelligence & Workflows** | `td_*` | **144** | EventMesh, Causal analysis, Evidence Graph, Counterfactuals, Workflow save/run/diff/replay, Target memory, Proofs, Security | -| **Chrome DevTools Fusion** | `dt_*` | **54** | Direct DevTools inspection, Lighthouse audits, HeapSnapshots, Network HAR, Console logs, Emulation | -| **Advanced Forensic Capabilities** | `fx_*` | **31** | Network-DOM correlation, Visual regression, Layout shifts, Z-index occlusion, Safe mutation guards | -| **Core & Live Interaction** | Core / v3 | **121** | Live element picking, screenshot cropping, synthetic actions, DOM diffing, time-travel, lifecycle traces | -| **Total Certified Tools** | | **350** | **100% Operational Certification (350/350 Stdio PASS)** | +| Symptom | Likely Cause | Fix | +|---------|--------------|-----| +| **Extension badge gray / disconnected** | Bridge server not running or wrong port | Run `dom-antigravity status` or start MCP server; Auto-Bridge connects automatically on port `3847` | +| **`EADDRINUSE: 3847`** | Another instance or background process occupies port 3847 | Terminate the orphan process or configure `TELEDOM_PORT=3848` | +| **Token limit exceeded in AI agent** | Running with default `full` profile (350 tools = ~40k tokens) | Switch to `TELEDOM_PROFILE=core` (~4,800 tokens) or `minimal` (~2,400 tokens) | +| **DevTools (F12) CDP collision** | Chrome DevTools window opened while agent attached CDP | TeleDOM includes auto-collision detection; close F12 DevTools to allow CDP attachment | +| **Python SDK connection error** | Bridge server not active | Ensure MCP server or `dom-antigravity bridge` is active before initializing Python client | +| **DOM mutations not recording** | Extension disabled or page loaded before extension started | Refresh the target tab (`Ctrl+R`) to re-inject content scripts | --- -## 🚀 Installation & Quick Start - -### 1. Global System Installation (One-Click) - -Install the global CLI and register TeleDOM into your user configuration: - -```bash -npm install -g teledom -dom-antigravity install --global -``` - -### 2. Workspace Installation for Any Project - -To enable TeleDOM for an individual project repository: - -```bash -cd /path/to/your-project -npx teledom install --workspace -``` - -This creates `.agents/mcp_config.json` and registers the full 350-tool skill definitions into `.agents/skills/`. +## Honest Limitations -### 3. Load Chrome Extension in Browser +| Limitation | Detail & Workaround | +|------------|---------------------| +| **Chromium-first** | Built for Chrome, Edge, and Brave via Manifest V3. Firefox and Safari live extensions are not currently supported. | +| **Headless CI requires setup** | Live DOM capture requires a display context. In automated CI pipelines, run under `xvfb-run` or use CDP direct mode. | +| **Context cost of `full` profile** | Exposing all 350 tools consumes ~40,000 tokens. Use `TELEDOM_PROFILE=core` for everyday development and agent tasks. | +| **Sandboxed virtual replay** | Inline scripts (`onclick`, `onload`) are intentionally stripped during virtual time-travel replay for security. | +| **Single active bridge port** | Default port `3847` is shared across tabs. For concurrent multi-agent isolation, specify distinct `TELEDOM_PORT` values. | -1. Open Google Chrome and navigate to `chrome://extensions/`. -2. Enable **Developer mode** in the top-right corner. -3. Click **Load unpacked** and select the `teledom/dist/extension` folder. -4. The TeleDOM extension badge will appear in your toolbar. - -### 4. Configure External AI Clients (Claude / Cursor / Cline) - -#### Claude Desktop Configuration (`claude_desktop_config.json`) - -```json -{ - "mcpServers": { - "teledom": { - "command": "node", - "args": ["C:/path/to/teledom/dist/server/mcp-server.js"] - } - } -} -``` - -#### Cursor Configuration (`.cursor/mcp.json`) - -```json -{ - "mcpServers": { - "teledom": { - "command": "node", - "args": ["C:/path/to/teledom/dist/server/mcp-server.js"] - } - } -} -``` +We document our engineering trade-offs openly so expectations remain aligned with reality. --- -## 🧪 Testing & Quality Verification +## FAQ -TeleDOM is backed by a rigorous multi-tier testing pipeline: +**Do I need to start the WebSocket bridge manually?** +No. `ForensicMCPServer` includes a zero-config Auto-Bridge. Whenever an AI agent connects over MCP, the server initializes the bridge on port `3847` in the background. -```bash -# 1. Run full unit and intelligence test suite (319 tests) -npm run test:unit - -# 2. Run Python SDK self-test (17 tests) -npm run test:sdk +**How do I reduce token consumption in Cursor or Claude?** +Set `TELEDOM_PROFILE=core` (42 tools, ~4,800 tokens) or `TELEDOM_PROFILE=minimal` (22 tools, ~2,400 tokens) in your MCP client environment configuration. -# 3. Run full operational stdio JSON-RPC certification (350 tools) -npm run test:operational +**Can I run TeleDOM offline without internet access?** +Yes. TeleDOM operates 100% locally. The MCP server, WebSocket bridge, and Chrome extension do not make any external network requests. -# 4. Run deterministic benchmark matrix (10K / 100K / 1M events) -npm run bench +**How does TeleDOM prevent AI agents from clicking dangerous buttons?** +The Safe Mutation Engine executes actions within a transactional boundary with dry-run validation, preventing destructive DOM changes without explicit confirmation. -# 5. Run golden incident suite (1,032 scenarios) -npm run golden +**Where can I find documentation for individual tools?** +All 350 tools are documented with full parameter schemas and JSON-RPC operational examples in [docs/TOOLS_CATALOG_350_EN.md](./docs/TOOLS_CATALOG_350_EN.md) and [docs/TOOLS_CATALOG_350_FA.md](./docs/TOOLS_CATALOG_350_FA.md). -# 6. Run chaos engineering injection suite -npm run chaos +--- -# 7. Build production bundle (client, server, extension) -npm run build -``` +## Documentation Index + +| Document | English | Persian | +|----------|---------|---------| +| **Main README** | [README.md](README.md) | [README_FA.md](README_FA.md) | +| **350 Tools Catalog** | [docs/TOOLS_CATALOG_350_EN.md](./docs/TOOLS_CATALOG_350_EN.md) | [docs/TOOLS_CATALOG_350_FA.md](./docs/TOOLS_CATALOG_350_FA.md) | +| **Agent-Owned Workflows** | [docs/workflow/AGENT_WORKFLOWS.md](./docs/workflow/AGENT_WORKFLOWS.md) | [docs/workflow/AGENT_WORKFLOWS.md](./docs/workflow/AGENT_WORKFLOWS.md) | +| **Python SDK Guide** | [docs/workflow/PYTHON_SDK.md](./docs/workflow/PYTHON_SDK.md) | [docs/workflow/PYTHON_SDK.md](./docs/workflow/PYTHON_SDK.md) | +| **Production Recipes** | [EXAMPLES.md](EXAMPLES.md) | [EXAMPLES_FA.md](EXAMPLES_FA.md) | +| **System Architecture** | [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md) | [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md) | +| **Benchmarks & Metrics** | [docs/intelligence/BENCHMARKS.md](./docs/intelligence/BENCHMARKS.md) | [docs/intelligence/BENCHMARKS.md](./docs/intelligence/BENCHMARKS.md) | +| **Release Notes** | [docs/workflow/RELEASE_NOTES.md](./docs/workflow/RELEASE_NOTES.md) | [docs/workflow/RELEASE_NOTES.md](./docs/workflow/RELEASE_NOTES.md) | +| **Troubleshooting Guide** | [docs/TROUBLESHOOTING.md](./docs/TROUBLESHOOTING.md) | [docs/TROUBLESHOOTING.md](./docs/TROUBLESHOOTING.md) | +| **Contributing** | [CONTRIBUTING.md](CONTRIBUTING.md) | [CONTRIBUTING.md](CONTRIBUTING.md) | +| **Security Policy** | [SECURITY.md](SECURITY.md) | [SECURITY.md](SECURITY.md) | +| **Changelog** | [CHANGELOG.md](CHANGELOG.md) | [CHANGELOG.md](CHANGELOG.md) | --- -## 🔐 Security, Privacy & Performance +## Contributing & Security -1. **Zero-Trust Privacy Masking**: `PrivacyEngine` automatically sanitizes password fields, credit card numbers (Luhn-compliant), Social Security numbers, bearer tokens, API keys, and custom CSS selectors in both recording and live inspection. -2. **Sandboxed Virtual Replay**: Reconstructed DOM environments strip inline `on*` event handlers and prevent script execution, eliminating arbitrary code execution risks. -3. **Sub-Millisecond Overhead**: Low-overhead streaming observers use `requestAnimationFrame` and `requestIdleCallback` throttling to ensure zero dropped frames on 120 Hz displays. -4. **Clean Compositor Framing**: Overlay hiding ensures pristine, unpolluted visual screenshots during automation. +Contributions are warmly welcomed — bug reports, workflow patterns, and tool improvements. +Please review [CONTRIBUTING.md](CONTRIBUTING.md) and [SECURITY.md](SECURITY.md) before submitting a pull request. --- -## ❓ Troubleshooting & FAQ - -#### Q: Do I need to run `npm run bridge` in a separate terminal? -> **A**: No! `ForensicMCPServer` includes a zero-config auto-bridge. Whenever an AI agent connects via MCP, the server automatically initializes the WebSocket bridge on port `3847` in the background. +## License & Author -#### Q: How do I test capturing a real Chrome screenshot from the terminal? -> **A**: Run `dom-antigravity screenshot`. It connects to your active Chrome tab, captures a pristine full-page screenshot and cropped element screenshot, and saves them to disk. +TeleDOM is open-source software licensed under the **Apache License, Version 2.0**. +See the [LICENSE](LICENSE) file for complete terms. -#### Q: How are the 350 tools documented? -> **A**: Every single tool is documented with full parameter schemas, TypeScript interfaces, and concrete operational JSON-RPC examples in [TOOLS_CATALOG_350_EN.md](./docs/TOOLS_CATALOG_350_EN.md) and [TOOLS_CATALOG_350_FA.md](./docs/TOOLS_CATALOG_350_FA.md). +Author: **Mohammad Javad (IrMaho)** --- -## 📜 License +
-Licensed under the **Apache License, Version 2.0**. See the [LICENSE](LICENSE) file for complete terms: +**TeleDOM v4.1** — *See what happened. Understand why. Simulate what-if. Fix safely. Prove the result.* -```text -http://www.apache.org/licenses/LICENSE-2.0 -``` +
diff --git a/README_FA.md b/README_FA.md index c1ecbe37..524f17bb 100644 --- a/README_FA.md +++ b/README_FA.md @@ -1,49 +1,305 @@ +
+ +[English](README.md) · **فارسی** + +لوگوی تله‌دام + +# تله‌دام نسخه ۴.۱ (TeleDOM v4.1) + +**موتور هوش زمانی مرورگر + محیط اجرای اتوماسیون با مالکیت عامل** + +*۳۵۰ ابزار اعتبارسنجی‌شده MCP • بازسازی زمان‌محور DOM زیر میلی‌ثانیه • افزونه کروم MV3 • پکیج پایتون بدون وابستگی* + +[![نسخه](https://img.shields.io/badge/version-4.1.0-blue.svg)](package.json) +[![مجوز: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE) +[![تایپ‌اسکریپت](https://img.shields.io/badge/TypeScript-5.8%2B-3178C6.svg?logo=typescript&logoColor=white)](https://www.typescriptlang.org/) +[![پایتون](https://img.shields.io/badge/Python-3.9%2B-3776AB.svg?logo=python&logoColor=white)](./sdk/python/) +[![افزونه کروم](https://img.shields.io/badge/Chrome_Extension-Manifest_V3-4285F4.svg?logo=googlechrome&logoColor=white)](https://developer.chrome.com/docs/extensions/mv3/) +[![ابزارهای MCP](https://img.shields.io/badge/MCP-350_Certified_Tools-7B1FA2.svg?logo=probot&logoColor=white)](./docs/TOOLS_CATALOG_350_FA.md) +[![تست‌ها](https://img.shields.io/badge/tests-320%20passed-brightgreen.svg)](#اجرای-تستها-و-تضمین-کیفیت) +[![پروفایل‌ها](https://img.shields.io/badge/profiles-4_runtime_levels-orange.svg)](#پروفایلهای-بهینه-مصرف-توکن) + +
+ +--- +
-# ⚡ تله‌دام نسخه ۴.۱ (TeleDOM v4.1) +## فهرست مطالب + +
+پرش به بخش + +- [تله‌دام چیست؟](#تلهدام-چیست) +- [چرا استفاده کنیم؟](#چرا-استفاده-کنیم) +- [پیش‌نمایش بصری و دموی معماری](#پیشنمایش-بصری-و-دموی-معماری) +- [ویژگی‌های برجسته و کلیدی](#ویژگیهای-برجسته-و-کلیدی) +- [پشته فناوری](#پشته-فناوری) +- [شروع سریع](#شروع-سریع) +- [پروفایل‌های بهینه مصرف توکن](#پروفایلهای-بهینه-مصرف-توکن) +- [نحوه کار](#نحوه-کار) +- [گردش‌کارهای عامل‌محور و حافظه تارگت](#گردشکارهای-عامل‌محور-و-حافظه-تارگت) +- [زرادخانه ۳۵۰ ابزار استاندارد MCP](#زرادخانه-۳۵۰-ابزار-استاندارد-mcp) +- [رابط خط فرمان همگانی (`dom-antigravity`)](#رابط-خط-فرمان-همگانی-dom-antigravity) +- [مرجع کتابخانه پایتون (Python SDK)](#مرجع-کتابخانه-پایتون-python-sdk) +- [مرجع تنظیمات و متغیرهای محیطی](#مرجع-تنظیمات-و-متغیرهای-محیطی) +- [دادهٔ جلسه در مقابل دادهٔ پایدار](#دادهٔ-جلسه-در-مقابل-دادهٔ-پایدار) +- [محیط‌های پشتیبانی‌شده و جدول سازگاری](#محیطهای-پشتیبانیشده-و-جدول-سازگاری) +- [نیازمندی‌های سیستم](#نیازمندیهای-سیستم) +- [توسعه و ساخت از سورس](#توسعه-و-ساخت-از-سورس) +- [اجرای تست‌ها و تضمین کیفیت](#اجرای-تستها-و-تضمین-کیفیت) +- [ساختار مخزن پروژه](#ساختار-مخزن-پروژه) +- [عیب‌یابی و رفع اشکال](#عیبیابی-و-رفع-اشکال) +- [محدودیت‌های صادقانه](#محدودیتهای-صادقانه) +- [مدل امنیت و حریم خصوصی](#مدل-امنیت-و-حریم-خصوصی) +- [سوالات متداول (FAQ)](#سوالات-متداول-faq) +- [نمایه مستندات پروژه](#نمایه-مستندات-پروژه) +- [مشارکت و امنیت](#مشارکت-و-امنیت) +- [لایسنس و نویسنده](#لایسنس-و-نویسنده) + +
-### 🧠 موتور هوش زمانی و محیط اجرای اتوماسیون مرورگر ویژه عامل‌های هوش مصنوعی • سرور جامع ۳۵۰ ابزار اعتبارسنجی‌شده MCP +--- + +## تله‌دام چیست؟ + +**تله‌دام (TeleDOM)** یک موتور صنعتی **هوش زمانی مرورگر (Temporal Browser Intelligence Engine)** و پلتفرم فراگیر پروتکل کانتکست مدل (**MCP**) شامل **۳۵۰ ابزار اعتبارسنجی‌شده** است که برای عامل‌های هوش مصنوعی خودمختار (مانند Claude، Cursor، Antigravity، Cline و OpenAI Swarm) و تیم‌های مهندسی فرانت‌اند طراحی شده است. + +بر خلاف مرورگرهای مصنوعی یا محیط‌های بدون‌سر (Headless)، تله‌دام از طریق یک افزونه استاندارد و مقاوم Manifest V3 مستقیماً به مرورگر واقعی و زنده کاربر متصل می‌شود و تمامی رویدادها، جهش‌های DOM، درخواست‌های شبکه و تغییرات ساختار صفحه را با دقت نانوثانیه ثبت می‌کند: + +- **هسته هوش زمانی EventMesh:** زنجیره ثبت وقایع غیرقابل‌دستکاری همراه با مهرهای زمانی نانوثانیه، ساعت‌های برداری و ردیابی علّی پیوندها. +- **سفر در زمان DOM زیر میلی‌ثانیه:** بازسازی کامل و بایت‌به‌بایت درخت مجازی DOM در هر لحظه دلخواه از گذشته ($State(T)$) جهت استخراج تفاضل‌ها و تحلیل رگرسیون. +- **گردش‌کارهای با مالکیت عامل (TeleDOM Flow):** عامل هوش مصنوعی فرآیند را یک‌بار یاد می‌گیرد، به شکل یک برنامه پارامتریک پایدار ذخیره می‌کند و در دفعات بعد با **۸۰٪ کاهش رفت‌وبرگشت MCP** و **۵۰٪ کاهش اسکن DOM** آن را به صورت قطعی اجرا می‌نماید. +- **زمینه واقعی کاربر:** دسترسی مستقیم به سشن‌های لاگین فعال، کوکی‌ها، افزونه‌ها و نشست‌های کاری کاربر بدون نیاز به ورود مجدد اطلاعات حساس. -[![TypeScript 5.8+](https://img.shields.io/badge/TypeScript-5.8%2B-blue.svg?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/) -[![Chrome Extension Manifest V3](https://img.shields.io/badge/Chrome_Extension-Manifest_V3-red.svg?style=flat-square&logo=googlechrome&logoColor=white)](https://developer.chrome.com/docs/extensions/mv3/) -[![Model Context Protocol 350 Tools](https://img.shields.io/badge/Model_Context_Protocol-350_Tools-purple.svg?style=flat-square&logo=probot&logoColor=white)](https://modelcontextprotocol.io/) -[![Certification 350/350 Stdio](https://img.shields.io/badge/Certification-350%2F350_Stdio-brightgreen.svg?style=flat-square&logo=checkmarx&logoColor=white)](./docs/TOOLS_CATALOG_350_FA.md) -[![Tests 319/319 Passed](https://img.shields.io/badge/Tests-319%2F319_Passed-success.svg?style=flat-square&logo=vitest&logoColor=white)](#-تستها-و-تضمین-کیفیت) -[![Python SDK](https://img.shields.io/badge/Python_SDK-Semantic_Browser_Programming-3776AB.svg?style=flat-square&logo=python&logoColor=white)](./sdk/python/) -[![License Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg?style=flat-square&logo=apache)](LICENSE) +> **وجه تسمیه:** نام *TeleDOM* از ترکیب *Tele* (تله‌متری و رصد از راه دور فراسوی مرزهای سیستم) و *DOM* (درخت ساختاری صفحات وب) پدید آمده است. + +> [!NOTE] +> تله‌دام **۱۰۰٪ به صورت محلی و آفلاین** روی رایانه شما اجرا می‌شود. این سیستم هیچ‌گونه دیتای تله‌متری، ارسال ابری یا اتصال به سرورهای خارجی در عملکرد عادی خود ندارد. --- -### 🌐 دسترسی به مستندات و کاتالوگ ابزارها +## چرا استفاده کنیم؟ -- 📖 **[کاتالوگ جامع و تفصیلی ۳۵۰ ابزار به زبان فارسی (TOOLS_CATALOG_350_FA.md)](./docs/TOOLS_CATALOG_350_FA.md)** -- 🇬🇧 **[English 350 Tools Catalog (Documentation)](./docs/TOOLS_CATALOG_350_EN.md)** -- 🇬🇧 **[English Project Readme (README.md)](./README.md)** -- ⚡ **[مستندات معماری گردش‌کار عامل‌محور (TeleDOM Flow)](./docs/workflow/AGENT_WORKFLOWS.md)** -- 🐍 **[راهنمای جامع پکیج رسمی پایتون (Python SDK)](./docs/workflow/PYTHON_SDK.md)** -- 📋 **[گزارش تغییرات و اعتبارسنجی نسخه ۴.۱](./docs/workflow/RELEASE_NOTES.md)** -- 💡 **[۲۵۰ مثال کاربردی عملیاتی به زبان فارسی (EXAMPLES_FA.md)](./EXAMPLES_FA.md)** | **[250 Production Recipes EN](./EXAMPLES.md)** -- 📊 **[ماتریس بهبودها و پیشرفت‌های معماری](./docs/intelligence/IMPROVEMENTS.md)** -- 📈 **[بنچمارک‌ها و سنجه‌های عملکردی سنجیده‌شده](./docs/intelligence/BENCHMARKS.md)** +| چالش در راهکارهای موجود | پاسخ مهندسی تله‌دام (TeleDOM) | +|-------------------------|-----------------------------| +| **محیط خام و بدون سشن:** مرورگرهای سنتی Puppeteer/Playwright فاقد سشن‌های لاگین، کوکی‌ها و زمینه واقعی کاربر هستند | **سشن واقعی کروم:** اتصال زنده به پروفایل فعال مرورگر کاربر همراه با دسترسی کامل به سشن‌ها و کوکی‌ها | +| **اسکرپرهای شکننده و پرهزینه:** عامل‌های AI در هر بار اجرا صفحه را از صفر اسکن می‌کنند که موجب هدررفت توکن می‌شود | **گردش‌کار عامل‌محور و حافظه المان‌ها:** ذخیره ردپای تارگت‌ها و بازپخش آنی، قطعی و بایت‌به‌بایت بدون نیاز به اسکن مجدد | +| **انفجار مصرف توکن مدل‌های زبانی:** ارسال کدهای خام ۵۰ هزار خطی HTML پنجره کانتکست مدل را فوراً پر می‌کند | **۴ پروفایل مصرف بهینه:** مقیاس‌بندی هوشمند اسکیما از ۲,۴۰۰ توکن (`minimal`) تا سطح کامل سازمانی (`full`) | +| **خطاهای زودگذر و ناپدیدشونده:** خطاهای استایل، جابه‌جایی‌های چیدمان و Race Conditionها با رفرش صفحه گم می‌شوند | **سفر در زمان زیر میلی‌ثانیه‌ای ($State(T)$):** بازسازی دقیق وضعیت DOM در هر لحظه دلخواه از خط زمانی | +| **ادعاهای توهم‌آمیز بدون اثبات:** ربات‌های تست ادعا می‌کنند که اکشن‌ها موفق بوده‌اند اما سندی وجود ندارد | **موتور اثبات و نامتغیرها:** راستی‌آزمایی ریاضی هم‌ارزی ساختاری DOM و تضمین صفر درصد مثبت کاذب | +| **دیباگ دستی و زمان‌بر در کنسول:** مهندسان ساعت‌ها وقت خود را صرف بررسی لاگ‌های شبکه و کنسول می‌کنند | **بازرس خودکار علت ریشه‌ای (`td_investigate`):** تولید خودکار گراف فرضیات علّی و فایل‌های بسته حادثه `.tdom` | +| **تایم‌اوت ۳۰ ثانیه‌ای کروم MV3:** سرویس‌ورکر افزونه در تسک‌های طولانی‌مدت توسط کروم خاموش می‌شود | **ضربان قلب آلارم ۲۴ ثانیه‌ای:** احیای مداوم ارتباط + محافظت از تداخل DevTools (F12) با پروتکل CDP | +| **اکشن‌های مخرب و غیرقابل‌برگشت:** کلیک‌های نادانسته عامل ممکن است داده‌های مهم را حذف یا دستکاری کند | **موتور جهش امن:** اجرای ترانزاکشنال اتمیک همراه با پیش‌نمایش کاملاً بدون اثر (Dry-run) و بازگشت قطعی | --- -## ⚡ تله‌دام نسخه ۴.۱ — محیط اجرای اتوماسیون با مالکیت عامل (Agent-Owned Runtime) +## پیش‌نمایش بصری و دموی معماری + +
-> **تله‌دام تصمیم‌گیرنده نیست؛ تله‌دام توانمندساز است.** -> **عامل هوش مصنوعی مغز متفکر است؛ تله‌دام دست‌ها، چشم‌ها، حافظه و جعبه‌ابزار مرورگر اوست.** -> *وظیفه را یک‌بار به مرورگر بیاموزید. آن را به برنامه‌ای با قابلیت بازپخش تبدیل کنید. روی هر وب‌سایتی که مرورگر قادر به باز کردن آن است اجرا نمایید.* +![دموی زنده کار با عامل هوش مصنوعی و TeleDOM](https://raw.githubusercontent.com/IrMaho/TeleDOM/master/assets/teledom_live_agent_demo.gif) + +> 🎬 **دموی ویدیویی زنده:** اجرای خودکار عامل هوش مصنوعی برای ضبط رخدادهای مرورگر، بازرسی درخت DOM، انجام تعاملات و اجرای چندمرحله‌ای اتوماسیون وب بدون دخالت دست! ([مشاهده و دانلود ویدیو 1080p](./assets/teledom_live_agent_demo.mp4)) + +
```text -عامل هوش مصنوعی (Agent) — کشف سایت · استدلال منطقی · نوشتن ورک‌فلو · نسخه‌بندی · دیباگ · تولید ربات - │ ارتباط MCP (سطح ۱: ۳۵۰ ابزار استاندارد) ──────────────┐ - │ پکیج Python SDK (سطح ۲: برنامه‌نویسی معنایی مرورگر) ─┐ │ - ▼ ▼ -تله‌دام (TeleDOM) — مشاهده مرورگر · ابزارهای پایه · حافظه المان‌ها · - ذخیره‌سازی ورک‌فلو · اجرای قطعی · شواهد · بازپخش · اثبات ریاضی ++-------------------------------------------------------------------------+ +| عامل هوش مصنوعی / کلاینت | +| (Antigravity IDE · Cursor · Claude Desktop · Cline) | ++------------------------------------+------------------------------------+ + | (ارتباط JSON-RPC 2.0 روی stdio) + v ++-------------------------------------------------------------------------+ +| سرور جامع تله‌دام نسخه ۴.۱ (۳۵۰ ابزار) | +| ├── ۱۴۴ ابزار هوش زمانی، گردش‌کار و حافظه عامل td_* | +| ├── ۵۴ ابزار تلفیق DevTools کروم dt_* | +| ├── ۳۱ ابزار کالبدشکافی پیشرفته بصری fx_* | +| ├── ۱۲۱ ابزار پایه، بازرسی زنده و تعامل | +| └── توزیع‌کننده پل ارتباطی خودکار روی پورت ۳۸۴۷ | ++------------------+------------------------------------+-----------------+ + | | (وب‌سوکت :3847) + v v ++------------------------------------+ +---------------------------------+ +| موتور اجرای گردش‌کار | | افزونه کروم (Manifest V3) | +| ├── ذخیره‌سازی و تفاضل ورک‌فلوها | | ├── موتور ناظر تغییرات DOM | +| ├── حافظه مشخصات پایدار المان‌ها | | ├── انتخابگر بصری المان‌ها | +| ├── هسته EventMesh و گراف علّی | | ├── خط لوله اسکرین‌شات تمیز | +| └── موتور اثبات و نامتغیرها | | └── درایور تعاملات شبیه‌سازی‌شده| ++------------------------------------+ +---------------------------------+ ``` -### دموی طلایی اجرای ورک‌فلو +| سطح عملیاتی | هدف و کاربرد اصلی | +|-------------|-------------------| +| **سرور MCP (`stdio`)** | ارائه ۳۵۰ ابزار اعتبارسنجی‌شده به کلیه کلاینت‌های سازگار با استاندارد Model Context Protocol | +| **خط فرمان (`dom-antigravity`)** | پیکربندی یک‌کلیکه ورک‌اسپیس‌ها، بررسی سلامت سیستم، ثبت اسکرین‌شات تمیز و مدیریت دیمن بریج | +| **افزونه کروم (MV3)** | رهگیری جهش‌های صفحه، تسهیل انتخاب المان با کلید ترکیبی، اجرای کلیک و تایپ شبیه‌سازی‌شده | +| **کتابخانه پایتون (`teledom`)** | پکیج خالص پایتون ۳.۹+ بدون هیچ وابستگی خارجی جهت برنامه‌نویسی سطح بالای معنایی مرورگر | + +--- + +## ویژگی‌های برجسته و کلیدی + +- **محیط اجرای گردش‌کار با مالکیت عامل:** ساخت، پارامتریک‌سازی، نسخه‌بندی، مقایسه تفاوت‌ها و بازپخش قطعی برنامه‌های چندمرحله‌ای مرورگر (`td_workflow_run`). +- **حافظه المان‌ها و اثرانگشت ساختاری:** ذخیره پایدار سلکتورها و هویت المان‌ها جهت رفع نیاز به اسکن‌های مکرر و خسته‌کننده صفحه. +- **هسته EventMesh زمانی با دقت نانوثانیه:** لاگ وقایع غیرقابل‌دستکاری با زنجیره هش SHA-256، ساعت‌های برداری و ریشه‌های درخت مرکل. +- **سفر در زمان DOM زیر میلی‌ثانیه‌ای:** بازسازی لحظه‌ای وضعیت DOM در هر مهر زمانی گذشته ($State(T)$). +- **شبیه‌سازی مرورگر خلاف‌واقع (Counterfactual):** انشعاب‌گیری فرضی از وضعیت DOM، فیلتر کردن رخدادها یا درخواست‌ها و مقایسه پیامدهای احتمالی. +- **کارآگاه خودکار حوادث (`td_investigate`):** تریاژ خودکار تنها با یک دستور، فرمول‌بندی فرضیات علّی و تولید پکیج‌های حادثه `.tdom`. +- **موتور جهش امن (Safe Mutation):** اعمال اتمیک و ترانزاکشنال تغییرات با امکان پیش‌نمایش بی‌خطر (Dry-run) و بازگشت تضمینی. +- **هوش امنیتی منفعل (Passive Security):** مانیتورینگ بدون‌توقف صفحه، مقابله با تزریق پرامپت، کشف XSS و سانسور داده‌های حساس. +- **۴ پروفایل مصرف بهینه توکن:** مدیریت هوشمند پنجره کانتکست از ۲۲ ابزار فوق‌سریع (~۲,۴۰۰ توکن) تا زرادخانه کامل ۳۵۰ ابزار. +- **کتابخانه رسمی پایتون با صفر وابستگی:** کنترل سطح‌بالای مرورگر در پایتون ۳.۹+ با استفاده از ساختار کانتکست منیجر. +- **اعتبارسنجی ۱۰۰٪ عملیاتی پروتکل JSON-RPC:** تایید کامل ۳۵۰ ابزار از ۳۵۰ ابزار روی کانال ارتباطی واقعی stdio. + +--- + +## پشته فناوری + +| لایه | فناوری | کاربرد در سیستم | +|------|--------|-----------------| +| **هسته و ران‌تایم** | Node.js 22+ & TypeScript 5.8+ | سرور غیرمسدودکننده MCP، هسته EventMesh و سیستم فایلینگ | +| **پروتکل عامل هوش مصنوعی** | Model Context Protocol (MCP) | استاندارد ارتباطی JSON-RPC 2.0 برای تمامی عامل‌های هوش مصنوعی | +| **اکستنشن مرورگر** | Chrome Extension Manifest V3 | ثبت جهش‌ها با MutationObserver، اتصال گره‌ها با WeakMap | +| **یکپارچگی مرورگر** | Chrome DevTools Protocol (CDP) | ممیزی Lighthouse، تحلیل HAR شبکه و ارزیابی عمیق کارایی | +| **پکیج پایتون** | Pure Python 3.9+ (Zero-Dependency) | کلاینت سطح‌بالای معنایی شامل `Browser` و `Workflow` | +| **تست و ارزیابی کیفیت** | Vitest 3.x, Ruff, Mypy | تست‌های واحد، سازگاری تایپ‌ها و سوئیت اعتبارسنجی stdio | +| **پلتفرم‌های مقصد** | Windows 10/11, macOS, Linux | پشتیبانی همه‌جانبه از تمام سیستم‌عامل‌های رومیزی و CI | + +--- + +## شروع سریع + +### مسیر الف — راه‌اندازی با یک کلیک برای عامل‌های هوش مصنوعی (پیشنهادی) + +نصب ابزار خط فرمان و فعال‌سازی تله‌دام برای ورک‌اسپیس یا سیستم: + +```bash +# ۱. نصب باینری سراسری +npm install -g teledom + +# ۲. پیکربندی تله‌دام برای پروژه فعلی (.agents) +dom-antigravity install --workspace + +# یا پیکربندی سراسری برای تمام پروژه‌های Antigravity IDE: +dom-antigravity install --global +``` + +### مسیر ب — اجرای پروژه از سورس (توسعه‌دهندگان) + +```bash +git clone https://github.com/IrMaho/TeleDOM.git +cd TeleDOM +npm install +npm run build +npm run test:unit +``` + +### مسیر ج — استفاده در پایتون (Python SDK) + +```bash +pip install ./sdk/python +``` + +```python +from teledom import Browser + +with Browser() as browser: + browser.inspect() + browser.type("#search-box", "عامل‌های خودمختار هوش مصنوعی") + browser.click("#submit-btn") +``` + +### اولین اتوماسیون در ۶۰ ثانیه + +۱. پوشه `teledom/dist/extension` را به عنوان افزونه بازشده (Unpacked) در `chrome://extensions/` لود کنید. +۲. عامل هوش مصنوعی خود (Antigravity IDE، Cursor یا Claude Desktop) را متصل نمایید. +۳. سرور **پل وب‌سوکت را به‌صورت خودکار** روی پورت `۳۸۴۷` فعال می‌کند. +۴. از عامل بخواهید صفحه را بازرسی کرده و گردش‌کار را ذخیره کند: + ```json + {"name": "td_workflow_save", "arguments": {"name": "login_flow", "steps": [...]}} + ``` +۵. این گردش‌کار را در هر زمان با یک فراخوانی قطعی بازپخش کنید: + ```json + {"name": "td_workflow_run", "arguments": {"workflow_id": "login_flow"}} + ``` + +--- + +## پروفایل‌های بهینه مصرف توکن + +برای جلوگیری از هدررفت کانتکست مدل‌های زبانی و کاهش هزینه‌های پردازش تا **۹۴٪**، تله‌دام ۴ پروفایل اجرایی از طریق متغیر محیطی `TELEDOM_PROFILE` ارائه می‌دهد: + +| پروفایل | ابزارهای فعال | توکن تخمینی اسکیما | کاربرد ایده‌آل | توضیحات | +|:---|:---:|:---:|:---|:---| +| **`minimal`** | **۲۲** | **حدود ۲,۴۰۰ توکن** | پاسخ‌های سریع و مدل‌های کم‌هزینه | عملیات پایه ناوبری: بازرسی، کلیک، تایپ، اسکرین‌شات | +| **`core`** | **۴۲** | **حدود ۴,۸۰۰ توکن** | اتوماسیون کامل و پایدار | ابزارهای اصلی + حافظه تارگت‌ها + موتور اجرای گردش‌کار | +| **`forensics`** | **۷۴** | **حدود ۸,۵۰۰ توکن** | ممیزی، خطایابی و تست‌های QA | تحلیل رگرسیون دیداری، تفاضل DOM، لاگ‌های شبکه و کنسول | +| **`full`** *(پیش‌فرض)* | **۳۵۰** | **حدود ۴۰,۰۰۰ توکن** | استدلال عمیق و نیازهای سازمانی | زرادخانه کامل ۳۵۰ ابزار با سازگاری کامل با نسخه‌های قبل | + +```bash +# اجرای سرور با پروفایل سبک Core +TELEDOM_PROFILE=core npx teledom +``` + +--- + +## نحوه کار + +```mermaid +flowchart LR + A["عامل هوش مصنوعی / LLM"] -->|"ارتباط JSON-RPC 2.0 / stdio"| B["سرور ForensicMCPServer"] + B -->|"پل خودکار (پورت ۳۸۴۷)"| C["افزونه کروم MV3"] + C -->|"MutationObserver"| D["صفحه وب هدف"] + D -->|"رویدادهای نانوثانیه"| E["هسته EventMesh زمانی"] + E -->|"اسنپ‌شات سفر در زمان"| F["وضعیت مجازی DOM در لحظه T"] + F -->|"بازپخش قطعی"| G["اثبات ریاضی و اعتبارسنجی"] +``` + +```mermaid +flowchart TB + subgraph AgentLayer["لایه عامل هوش مصنوعی"] + IDE["محیط Antigravity IDE / Cursor / Claude"] + PY["پکیج رسمی پایتون teledom"] + CLI["رابط خط فرمان dom-antigravity"] + end + + subgraph ServerLayer["لایه سرور MCP تله‌دام (Node.js)"] + MCP["سرور ForensicMCPServer (۳۵۰ ابزار)"] + WF["موتور اجرای گردش‌کار"] + TM["حافظه پایدار تارگت‌ها"] + EM["هسته هوش زمانی EventMesh"] + CE["موتور استدلال علّی و ریشه‌یابی"] + AB["پل خودکار وب‌سوکت (پورت ۳۸۴۷)"] + end + + subgraph BrowserLayer["لایه اجرای مرورگر (Chrome MV3)"] + CS["اسکریپت محتوا و اتصال گره‌ها"] + MO["موتور ناظر تغییرات DOM"] + EV["توزیع‌کننده تعاملات مصنوعی"] + SC["خط لوله اسکرین‌شات Canvas"] + end + + IDE --> MCP + PY --> MCP + CLI --> AB + MCP --> WF + MCP --> TM + MCP --> EM + MCP --> CE + MCP --> AB + AB <-->|"فریم‌های وب‌سوکت (پورت ۳۸۴۷)"| CS + CS --> MO + CS --> EV + CS --> SC +``` + +--- + +## گردش‌کارهای عامل‌محور و حافظه تارگت + +تله‌دام نسخه ۴.۱ مفهوم اتوماسیون مرورگر را از اسکریپت‌نویسی سنتی به **برنامه‌های با قابلیت بازپخش با مالکیت عامل** تغییر می‌دهد: ```text اجرای اول (کشف صفحه): ۵ فراخوانی ابزار · ۲ اسکن کامل DOM · ۵ رفت‌وبرگشت به MCP @@ -54,223 +310,191 @@ ثبت گزارش قطعی اجرای عملیات با قابلیت بازپخش مو‌به‌مو شاخص‌های عملکردی: ۸۰٪ کاهش رفت‌وبرگشت MCP · ۵۰٪ کاهش اسکن DOM · بازپخش موفق - صفر درصد بای‌پس ناخواسته · صفر درصد تداخل · ۳۵۰/۳۵۰ ابزار تاییدشده + صفر درصد بای‌پس ناخواسته · صفر درصد تداخل · ۳۵۰/۳۵۰ ابزار تاییدشده ``` -### ۴۴ ابزار جدید اضافه شده در نسخه ۴.۱: +### ۴۴ ابزار تخصصی اضافه شده در نسخه ۴.۱: | دسته‌بندی ابزارها | تعداد | ابزارهای موجود | |---|:---:|---| -| **ابزارهای پایه مرورگر (Browser Primitives)** | **۲۲** | `td_browser_*` · `td_dom_inspect/query/extract/snapshot` · `td_target_find/check/describe` · `td_action_click/type/select/hover/press/scroll` · `td_wait` · `td_screenshot` · `td_execute_script` · `td_network_inspect` · `td_console_read` | -| **محیط اجرای گردش‌کار (Workflow Runtime)** | **۱۴** | `td_workflow_save/get/list/update/delete/clone/diff/export/import/validate/run/runs/run_get/replay` — اجرای قطعی همراه با گیت‌های امنیتی، گزارش وضعیت و بازپخش بایت‌به‌بایت | -| **ابزارها و حافظه اختصاصی عامل (Agent Tooling)** | **۸** | `td_target_memory_*` (شناسایی ذخیره‌شده المان‌ها بدون نیاز به اسکن مجدد DOM) · `td_agent_artifact_*` (ابزارهای سفارشی، اسکریپت‌ها و سیاست‌ها بدون تغییر در هسته) | - -رویکرد **مرورگر به عنوان پایه (Browser-First)** و **عدم وابستگی به API**: وب‌سایت‌های پیچیده و برنامه‌های SPA فاقد API عمومی هدف اصلی هستند. عامل هوش مصنوعی شیوه کشف را خودش انتخاب می‌کند و تله‌دام اجرای مطمئن را بدون مداخله انجام می‌دهد. +| **ابزارهای پایه مرورگر** | **۲۲** | `td_browser_*` · `td_dom_*` · `td_target_*` · `td_action_*` · `td_wait` · `td_screenshot` · `td_execute_script` · `td_network_inspect` · `td_console_read` | +| **محیط اجرای گردش‌کار** | **۱۴** | `td_workflow_save/get/list/update/delete/clone/diff/export/import/validate/run/runs/run_get/replay` | +| **ابزارها و حافظه اختصاصی عامل** | **۸** | `td_target_memory_*` (تارگت‌های پایدار) · `td_agent_artifact_*` (ابزارها و سیاست‌های سفارشی) | --- -## ⚡ معرفی و خلاصه تله‌دام در یک خط - -> **تله‌دام در یک خط:** *ببین چه اتفاقی افتاد. دلیلش را بفهم. شبیه‌سازی خلاف‌واقع کن. با اطمینان اصلاح کن. نتیجه را با اثبات ریاضی نشان بده.* - -**تله‌دام (TeleDOM)** یک موتور صنعتی **هوش زمانی مرورگر (Temporal Browser Intelligence)** و پلتفرم فراگیر **پروتکل کانتکست مدل (Model Context Protocol - MCP)** است که **۳۵۰ ابزار اعتبارسنجی‌شده** را برای عامل‌های خودمختار هوش مصنوعی (مانند Claude، Cursor، Antigravity، Cline، OpenAI Swarm) و مهندسان فرانت‌اند فراهم می‌آورد. +## زرادخانه ۳۵۰ ابزار استاندارد MCP -در این پلتفرم، تمام ادعاها و گزارش‌های تشخیصی متکی به شواهد رمزنگاری‌شده، گراف علّی، زنجیره هدر و اثبات‌های ریاضی ماشین‌خوان هستند. +تله‌دام دارای جامع‌ترین جعبه‌ابزار مرورگر برای عامل‌های هوش مصنوعی با تاییدیه ۱۰۰٪ عملیاتی است: -### سنجه‌های اعتبارسنجی نسخه ۴.۱ (تولیدشده با `npm run bench` — [ماتریس کامل](./docs/intelligence/BENCHMARKS.md)) +| خانواده ابزار | پیشوند | تعداد ابزار | وظایف و قابلیت‌های اصلی | +|---|---|:---:|---| +| **هوش زمانی و گردش‌کار** | `td_*` | **۱۴۴** | هسته EventMesh، تحلیل علّی، گراف شواهد، سناریوهای شرطی، گردش‌کارها، حافظه المان‌ها، اثبات‌ها و امنیت | +| **تلفیق DevTools کروم** | `dt_*` | **۵۴** | بازرسی مستقیم کلاینت کروم، ممیزی Lighthouse، ثبت HeapSnapshot، ردیابی HAR شبکه، لاگ‌های کنسول | +| **کالبدشکافی پیشرفته بصری** | `fx_*` | **۳۱** | پیوند رخدادهای شبکه با DOM، رگرسیون دیداری، جابه‌جایی چیدمان، تداخل Z-index، گارد جهش امن | +| **ابزارهای پایه و تعامل زنده** | Core / v3 | **۱۲۱** | انتخابگر بصری المان‌ها، برش اسکرین‌شات، تعاملات شبیه‌سازی‌شده، مقایسه ساختاری DOM، سفر در زمان | +| **مجموع کل ابزارهای تاییدشده** | | **۳۵۰** | **تاییدیه عملیاتی ۱۰۰٪ روی کانال stdio (پاس شدن ۳۵۰/۳۵۰)** | -| سنجه | نتیجه | توضیح | -|---|---|---| -| **مجموعه حوادث طلایی (۱,۰۳۲ سناریو در ۲۴ دسته‌بندی)** | **۱۰۰.۰٪** | حل کامل ۸۶۰ سناریوی قابل‌حل بدون هیچ‌گونه ابهام | -| **نرخ تکمیل بررسی ریشه خطا (ICR)** | **۱۰۰.۰٪** | کشف خودکار و گام‌به‌گام زنجیره علّی خطا | -| **دقت بازپخش اسنپ‌شات‌ها (RF)** | **۱۰۰.۰٪** | بازسازی بایت‌به‌بایت و قطعی وضعیت درخت مجازی DOM | -| **دقت تشخیص علت ریشه‌ای** | **۱۰۰.۰٪** | دسته‌بندی دقیق نوع خطا (حذف کامپوننت، تغییرات CSS، تداخل شبکه و غیره) | -| **نرخ موفقیت کاذب (False Success)** | **۰.۰۰٪** | صفر درصد گزارش مثبت کاذب در تمام آزمایش‌ها | -| **مجموعه تست آشوب (Chaos Engineering - ۱۶ تزریق)** | **۱۶/۱۶ مهارشده** | مهار کامل، مشاهده، توضیح علّی و بازیابی خودکار | -| **اعتبارسنجی عملیاتی پروتکل JSON-RPC** | **۳۵۰/۳۵۰ ابزار تاییدشده** | ثبت و تست واقعی تمام ۳۵۰ ابزار روی کانال stdio | -| **مجموعه تست‌های واحد و یکپارچگی** | **۳۱۹/۳۱۹ تست موفق** | پاس شدن ۱۰۰٪ تست‌ها در ۳۶ فایل تستی | -| **ماتریس بهبودهای معماری** | **۱۰۶ مورد معتبر** | ۱۰۴ مورد پیاده‌سازی کامل و ۲ مورد موکول‌شده با دلایل مستند | +> جهت مشاهده کاتالوگ تفصیلی، اسکیماهای کامل و نمونه‌های فراخوانی: +> - 🇮🇷 **[کاتالوگ جامع ۳۵۰ ابزار به زبان فارسی](./docs/TOOLS_CATALOG_350_FA.md)** +> - 📖 **[English Tools Catalog (3,800+ lines)](./docs/TOOLS_CATALOG_350_EN.md)** --- -## 🚀 دموی زنده و ویدیویی - -![دموی زنده کار با عامل هوش مصنوعی و TeleDOM](https://raw.githubusercontent.com/IrMaho/TeleDOM/master/assets/teledom_live_agent_demo.gif) - -> 🎬 **دموی ویدیویی زنده:** اجرای خودکار عامل هوش مصنوعی برای ضبط رخدادهای مرورگر، بازرسی درخت DOM، انجام تعاملات و انتشار چندمرحله‌ای توییت‌ها بدون دخالت دست انسان! ([مشاهده و دانلود ویدیوی باکیفیت 1080p](./assets/teledom_live_agent_demo.mp4)) +## رابط خط فرمان همگانی (`dom-antigravity`) ---- +باینری ثبت‌شده سیستم با نام‌های مستعار `mcp-dom` و `browser-antigravity`: -## 📖 فهرست مطالب - -- [⚡ تله‌دام نسخه ۴.۱ — محیط اجرای اتوماسیون با مالکیت عامل](#-تلهدام-نسخه-۴۱--محیط-اجرای-اتوماسیون-با-مالکیت-عامل-agent-owned-runtime) -- [⚡ معرفی و خلاصه تله‌دام در یک خط](#-معرفی-و-خلاصه-تلهدام-در-یک-خط) -- [🐍 شروع سریع با پکیج پایتون (Python SDK)](#-شروع-سریع-با-پکیج-پایتون-python-sdk) -- [✨ قابلیت‌های کلیدی](#-قابلیتهای-کلیدی) -- [💻 ترمینال و رابط خط فرمان اختصاصی (`dom-antigravity`)](#-ترمینال-و-رابط-خط-فرمان-اختصاصی-dom-antigravity) -- [🏗️ معماری سیستم](#-معماری-سیستم) - - [مدل اجرای دو محیطی (Dual-Environment Model)](#مدل-اجرای-دو-محیطی-dual-environment-model) - - [دیاگرام کلان معماری](#دیاگرام-کلان-معماری) - - [پل ارتباطی خودکار و بدون تنظیمات (Zero-Config Auto-Bridge)](#-پل-ارتباطی-خودکار-و-بدون-تنظیمات-zero-config-auto-bridge) - - [پایپ‌لاین اسکرین‌شات تمیز و کالبدشکافی بصری](#-پایپلاین-اسکرینشات-تمیز-و-کالبدشکافی-بصری) - - [موتور بازسازی وضعیت و سفر در زمان (Time-Travel)](#موتور-بازسازی-وضعیت-و-سفر-در-زمان-time-travel) -- [📁 ساختار کامل مخزن](#-ساختار-کامل-مخزن) -- [🤖 مرجع ابزارهای پروتکل کانتکست مدل (MCP) - ۳۵۰ ابزار](#-مرجع-ابزارهای-پروتکل-کانتکست-مدل-mcp---۳۵۰-ابزار) - - [۱. ۱۴۴ ابزار هوش زمانی و محیط گردش‌کار (`td_*`)](#۱-۱۴۴-ابزار-هوش-زمانی-و-محیط-گردشکار-td_) - - [۲. ۵۴ ابزار تلفیق DevTools کروم (`dt_*`)](#۲-۵۴-ابزار-تلفیق-devtools-کروم-dt_) - - [۳. ۳۱ ابزار کالبدشکافی پیشرفته (`fx_*`)](#۳-۳۱-ابزار-کالبدشکافی-پیشرفته-fx_) - - [۴. ۱۲۱ ابزار پایه، تعامل زنده و انتخابگر بصری](#۴-۱۲۱-ابزار-پایه-تعامل-زنده-و-انتخابگر-بصری) -- [🚀 راهنمای نصب و شروع سریع](#-راهنمای-نصب-و-شروع-سریع) - - [۱. نصب سراسری در سیستم (یک‌کلیک)](#۱-نصب-سراسری-در-سیستم-یککلیک) - - [۲. نصب اختصاصی در هر پروژه یا ورک‌اسپیس](#۲-نصب-اختصاصی-در-هر-پروژه-یا-ورکاسپیس) - - [۳. لود کردن افزونه در مرورگر کروم](#۳-لود-کردن-افزونه-در-مرورگر-کروم) - - [۴. اتصال به کلاینت‌های هوش مصنوعی (Claude / Cursor / Cline)](#۴-اتصال-به-کلاینتهای-هوش-مصنوعی-claude--cursor--cline) -- [🧪 تست‌ها و تضمین کیفیت](#-تستها-و-تضمین-کیفیت) -- [🔐 امنیت، حریم خصوصی و عملکرد](#-امنیت-حریم-خصوصی-و-عملکرد) -- [❓ عیب‌یابی و سوالات متداول](#-عیبیابی-و-سوالات-متداول) -- [📜 لایسنس و شرایط استفاده](#-لایسنس-و-شرایط-استفاده) +| دستور | گزینه / نام مستعار | توضیحات و عملکرد | +|-------|--------------------|-------------------| +| `dom-antigravity install` | `--workspace` (`-w`) | پیکربندی خودکار تله‌دام در پروژه جاری (`.agents/mcp_config.json`) | +| `dom-antigravity install` | `--global` (`-g`) | ثبت سراسری تله‌دام برای تمامی پروژه‌ها در Antigravity IDE | +| `dom-antigravity install` | `--target ` | نصب تنظیمات در یک پوشه یا ورک‌اسپیس دلخواه | +| `dom-antigravity status` | | بررسی سلامت سرور پل ارتباطی (`:3847`) و تب‌های فعال کروم | +| `dom-antigravity screenshot` | | ثبت اسکرین‌شات تمیز از صفحه کامل و المان‌های بریده‌شده روی دیسک | +| `dom-antigravity bridge` | | اجرای دستی پل وب‌سوکت (اختیاری — پل خودکار این کار را مدیریت می‌کند) | +| `dom-antigravity config` | `cursor` / `claude` | چاپ بلاک تنظیمات JSON آماده برای استفاده در کلاینت‌های مختلف | --- -## 🐍 شروع سریع با پکیج پایتون (Python SDK) +## مرجع کتابخانه پایتون (Python SDK) -تله‌دام دارای یک SDK رسمی پایتون با وابستگی صفر (`sdk/python/teledom`) است: +کتابخانه رسمی پایتون با وابستگی صفر (`sdk/python/teledom`): ```python from teledom import Browser, Workflow with Browser() as browser: - # ۱. کنترل پیشرفته مرورگر + # ۱. کنترل سطح بالای مرورگر page = browser.inspect() browser.type("#search-box", "عامل‌های خودمختار هوش مصنوعی") browser.click("#submit-btn") - # ۲. ساخت و ذخیره ورک‌فلو توسط عامل + # ۲. ساخت و ذخیره یک گردش‌کار اختصاصی wf = Workflow("triage_issues", client=browser.client) wf.input("filter", "فیلتر برچسب ایشوها", default="bug") - wf.step("filter_step", "td_target_check", args={"selector": ".issue-row"}) + wf.step("check_table", "td_target_check", args={"selector": ".issue-row"}) wf.save(version="1.0.0") - # ۳. اجرای ورک‌فلو با گزارش‌گیری قطعی و بدون افت توکن + # ۳. اجرای قطعی با گزارش وضعیت run = wf.run({"filter": "security"}) - print("وضعیت اجرای ورک‌فلو:", run["run"]["status"]) + print("وضعیت اجرا:", run["run"]["status"]) ``` --- -## ✨ قابلیت‌های کلیدی - -| قابلیت | توضیح | -| :--- | :--- | -| **موتور گردش‌کار عامل‌محور** | ساخت، پارامتریک‌سازی، نسخه‌بندی، مقایسه تفاوت‌ها و اجرای قطعی برنامه‌های چندمرحله‌ای مرورگر. | -| **حافظه المان‌ها (Target Memory)** | ذخیره شناسه‌های پایدار المان‌ها (`td_target_memory_save`) جهت حذف اسکن‌های تکراری DOM در دفعات بعدی. | -| **هسته EventMesh زمانی** | ثبت لاگ وقایع غیرقابل‌دستکاری با زنجیره هش SHA-256، مهرهای زمانی با دقت نانوثانیه، ساعت‌های برداری و درخت مرکل. | -| **سفر در زمان DOM زیر میلی‌ثانیه** | بازسازی لحظه‌ای وضعیت DOM در هر مهر زمانی دلخواه $T$ یا شناسه رویداد $E$، محاسبه تفاوت‌های ساختاری و پرس‌وجوی خط زمانی. | -| **شبیه‌سازی مرورگر خلاف‌واقع (Counterfactual)** | ایجاد شاخه‌های فرضی، متوقف‌سازی درخواست‌های شبکه یا جهش‌های خاص DOM و مقایسه نتایج شاخه‌های مجازی بدون اثرگذاری روی صفحه اصلی. | -| **موتور جهش امن (Safe Mutation Transactions)** | اعمال تغییرات ترانزاکشنال و اتمیک با پیش‌نمایش کاملاً بدون اثر جانبی (Dry-run) و بازگشت تضمینی (Rollback). | -| **بازرس خودکار حوادث (`td_investigate`)** | تریاژ و خطایابی خودکار با یک دستور، فرمول‌بندی فرضیات، امتیازدهی به شواهد و تولید فایل‌های پرتابل `.tdom`. | -| **اثبات ریاضی و اعتبارسنجی نامتغیرها** | راستی‌آزمایی نامتغیرهای سیستم، اثبات هم‌ارزی ساختاری، مهار رگرسیون و گواهی عدم موفقیت کاذب. | -| **هوش امنیتی منفعل (Passive Security)** | اسکن صفحه بر پایه معماری Zero-Trust، شناسایی حملات تزریق پرامپت، شناسایی آسیب‌پذیری‌های XSS و سانسور خودکار اطلاعات حساس. | -| **تاب‌آوری خودترمیم و دیده‌بان منابع** | قطع‌کننده مدار (Circuit Breaker)، کشف نشت حافظه، ردیابی اشیاء سرگردان زباله‌روب و برقراری مجدد خودکار پل وب‌سوکت. | -| **۳۵۰ ابزار استاندارد JSON-RPC 2.0 MCP** | جامع‌ترین جعبه‌ابزار مرورگر برای عامل‌های هوش مصنوعی در زمینه‌های هوش زمانی، ابزارهای DevTools، کالبدشکافی و تعامل زنده. | +## مرجع تنظیمات و متغیرهای محیطی + +| متغیر محیطی | مقدار پیش‌فرض | توضیحات | +|-------------|---------------|---------| +| `TELEDOM_PROFILE` | `full` | پروفایل عملیاتی: `minimal` (۲۲), `core` (۴۲), `forensics` (۷۴), `full` (۳۵۰) | +| `TELEDOM_PORT` | `3847` | پورت ارتباطی سرور پل وب‌سوکت و HTTP | +| `TELEDOM_BRIDGE_TOKEN` | *تعریف‌نشده* | توکن امنیتی اختیاری Bearer برای محافظت از اندپوینت‌های حساس | +| `TELEDOM_STORAGE_DIR` | `.teledom` | مسیر پوشه ذخیره‌سازی محلی سشن‌ها و بسته‌های حادثه | +| `TELEDOM_HEADLESS` | `false` | تنظیم روی `true` جهت اتصال به کروم Headless با پروتکل CDP | +| `DEBUG` | `false` | فعال‌سازی لاگ‌های جزئی JSON-RPC و رخدادهای EventMesh | --- -## 💻 ترمینال و رابط خط فرمان اختصاصی (`dom-antigravity`) +## دادهٔ جلسه در مقابل دادهٔ پایدار -این پکیج یک باینری خط فرمان سراسری با نام `dom-antigravity` (همراه با نام‌های مستعار `mcp-dom` و `browser-antigravity`) ارائه می‌دهد: +| نوع داده | محل نگهداری | ماندگاری پس از ریستارت؟ | +|----------|-------------|:----------------------:| +| **ورک‌فلوها و گام‌های اجرایی** | `.mcpdom_projects/workflows/` | **بله** | +| **اثرانگشت و حافظه المان‌ها** | `.mcpdom_projects/targets/` | **بله** | +| **پرونده‌های حادثه (`.tdom`)** | `.forensic_sessions/` | **بله** | +| **اتصال زنده پل وب‌سوکت** | حافظه رم در پورت `:3847` | **خیر** (اتصال خودکار مجدد) | +| **کش موقت اسنپ‌شات‌های مجازی** | حافظه هیپ فرآیند Node.js | **خیر** (بازسازی در صورت تقاضا) | -```bash -# ۱. نصب تنظیمات MCP و مهارت‌ها در ورک‌اسپیس جاری (.agents) -dom-antigravity install --workspace -# نام کوتاه: -dom-antigravity install -w +> [!IMPORTANT] +> در حافظه تارگت‌ها و فایل‌های گردش‌کار، صرفاً سلکتورها و اسکیماهای ساختاری ذخیره می‌شوند. رمزهای عبور کاربران، اطلاعات کارت‌های بانکی و کلیدهای دسترسی به لطف ماژول `PrivacyEngine` **هرگز روی دیسک نوشته نمی‌شوند**. -# ۲. نصب سراسری برای تمامی پروژه‌ها در Antigravity IDE -dom-antigravity install --global -# نام کوتاه: -dom-antigravity install -g +--- + +## محیط‌های پشتیبانی‌شده و جدول سازگاری + +| دسته‌بندی | نسخه‌های پشتیبانی‌شده | نکات | +|-----------|-----------------------|------| +| **مرورگرها** | کروم ۱۲۰ به بعد، Chromium، مایکروسافت Edge، بریو (Brave) | نیازمند پشتیبانی از اکستنشن Manifest V3 | +| **ران‌تایم نود** | Node.js نسخه‌های 18.x, 20.x, 22.x LTS | کامپایل و اعتبارسنجی‌شده روی Node 22 | +| **محیط پایتون** | Python نسخه‌های 3.9, 3.10, 3.11, 3.12, 3.13 | بدون نیاز به نصب هرگونه کتابخانه متفرقه | +| **سیستم‌عامل‌ها** | ویندوز 10/11، سیستم‌عامل macOS، توزیع‌های مختلف لینوکس | پشتیبانی کامل دسکتاپ و سرور | +| **کلاینت‌های هوش مصنوعی** | Antigravity IDE، Cursor، Claude Desktop، Cline، Windsurf | سازگاری کامل با استاندارد Model Context Protocol | -# ۳. نصب در یک پوشه خاص -dom-antigravity install --target "C:/path/to/project" +--- + +## نیازمندی‌های سیستم + +| مولفه | حداقل نیازمندی | مقدار پیشنهادی | +|-------|----------------|----------------| +| **سیستم‌عامل** | ویندوز 10، مک‌او‌اس 12، اوبونتو 20.04 | ویندوز 11 / مک‌او‌اس 14 | +| **Node.js** | 18.18.0 به بالا | 22.x LTS | +| **Python** | 3.9 به بالا (جهت پکیج پایتون) | 3.11 به بالا | +| **حافظه رم (RAM)** | ۴ گیگابایت | ۸ گیگابایت به بالا برای تحلیل سنگین DOM | +| **فضای دیسک** | ۲۰۰ مگابایت | ۵۰۰ مگابایت (شامل فایل‌های آزمون) | +| **مرورگر** | Google Chrome 120+ | آخرین نسخه پایدار Google Chrome | + +--- -# ۴. بررسی سلامت پل ارتباطی و تب‌های متصل کروم -dom-antigravity status +## توسعه و ساخت از سورس -# ۵. ثبت اسکرین‌شات تمیز از کروم (صفحه کامل + المان برش‌خورده) -dom-antigravity screenshot +```bash +# نصب وابستگی‌ها +npm install -# ۶. روشن کردن دستی پل ارتباطی وب‌سوکت (اختیاری — پل خودکار آن را مدیریت می‌کند) -dom-antigravity bridge +# کامپایل تمام بخش‌ها (کلاینت، افزونه کروم، سرور MCP) +npm run build -# ۷. نمایش فایل پیکربندی آماده برای Claude Desktop یا Cursor -dom-antigravity config cursor -dom-antigravity config claude +# ساخت اختصاصی هر بخش +npm run build:client # کامپایل کلاینت با Vite +npm run build:extension # باندل افزونه کروم MV3 +npm run build:server # کامپایل سرور MCP ``` --- -## 🏗️ معماری سیستم +## اجرای تست‌ها و تضمین کیفیت -### مدل اجرای دو محیطی (Dual-Environment Model) +```bash +# ۱. سوئیت آزمون جامع مهندسی (بیلد + ۳۲۰ تست واحد + ۱۷ تست پایتون + لینت) +npm run qa:all + +# ۲. اجرای آزمون‌های واحد و هوش زمانی (۳۲۰ تست، ۱۰۰٪ سبز) +npm run test:unit -تله‌دام در دو محیط اجرایی کاملاً مجزا و هماهنگ فعالیت می‌کند: +# ۳. اجرای تست‌های پکیج پایتون (۱۷ تست) +npm run test:sdk -۱. **محیط مرورگر (افزونه کروم Manifest V3 / اسکریپت محتوا / کانتکست تزریق‌شده):** - - رهگیری تغییرات DOM با استفاده از `MutationObserver`. - - تخصیص شناسه‌های پایدار `LogicalNodeId` به المان‌ها از طریق `WeakMap`. - - شنود کلیدهای `Ctrl + Shift + Click` برای انتخاب بصری المان‌ها. - - اجرای تعاملات شبیه‌سازی‌شده (`click`، `type`، `hover`، `focus`، `scroll`، `drag`). - - برش دقیق المان‌ها روی بوم گرافیکی HTML5 Canvas. - - مخفی‌سازی ویجت‌های افزونه هنگام ثبت اسکرین‌شات. +# ۴. اعتبارسنجی کدهای پایتون و سازگاری تایپ‌ها (Ruff + Mypy) +npm run lint:python -۲. **محیط سرور Node.js و سرور MCP (`ForensicMCPServer`):** - - ارائه **۳۵۰ ابزار پروتکل MCP** روی کانال‌های `stdio` و HTTP. - - راه‌اندازی و مدیریت خودکار پل ارتباطی وب‌سوکت روی پورت `۳۸۴۷`. - - راه‌اندازی هسته هوش زمانی EventMesh، گراف شواهد و موتور استدلال علّی. - - بازسازی اسنپ‌شات‌های مجازی DOM در کسری از میلی‌ثانیه. - - ذخیره‌سازی، اعتبارسنجی و اجرای قطعی ورک‌فلوهای تعریف‌شده توسط عامل. +# ۵. آزمون عملیاتی تاییدیه تمامی ۳۵۰ ابزار روی کانال stdio (تاییدیه ۱۰۰٪) +npm run test:operational ---- +# ۶. اجرای بنچمارک‌های قطعی (۱۰ هزار، ۱۰۰ هزار و ۱ میلیون رویداد) +npm run bench -### دیاگرام کلان معماری +# ۷. اجرای مجموعه آزمون‌های حوادث طلایی (۱,۰۳۲ سناریو) +npm run golden -```text -┌────────────────────────────────────────────────────────────────────────┐ -│ عامل هوش مصنوعی / کلاینت MCP │ -│ (Antigravity IDE / Cursor / Claude Desktop / CLI) │ -└───────────────────────────────────┬────────────────────────────────────┘ - │ (ارتباط JSON-RPC 2.0 روی stdio) - ▼ -┌────────────────────────────────────────────────────────────────────────┐ -│ سرور جامع تله‌دام نسخه ۴.۱ (۳۵۰ ابزار) │ -│ ├── ۱۴۴ ابزار هوش زمانی، گردش‌کار و حافظه عامل td_* │ -│ ├── ۵۴ ابزار تلفیق DevTools کروم dt_* │ -│ ├── ۳۱ ابزار کالبدشکافی پیشرفته fx_* │ -│ ├── ۱۲۱ ابزار پایه، بازرسی زنده و تعامل │ -│ └── توزیع‌کننده پل ارتباطی خودکار روی پورت ۳۸۴۷ │ -└───────────────────┬────────────────────────────────┬───────────────────┘ - │ │ (ارتباط وب‌سوکت روی پورت ۳۸۴۷) - ▼ ▼ -┌───────────────────────────────┐ ┌────────────────────────────────────┐ -│ موتور اجرای گردش‌کار │ │ سرور پل ارتباطی وب‌سوکت │ -│ ├── ذخیره و اجرای ورک‌فلوها │ │ (پورت ۳۸۴۷ - مدیریت خودکار) │ -│ ├── حافظه المان‌ها (Targets) │ └─────────────────┬──────────────────┘ -│ ├── هسته EventMesh و علّی │ │ -│ ├── شبیه‌ساز خلاف‌واقع │ │ (فریم‌های دوطرفه JSON) -│ └── موتور اثبات و نامتغیرها │ ▼ -└───────────────────────────────┘ ┌────────────────────────────────────┐ - │ افزونه کروم (Manifest V3) │ - │ ├── موتور ناظر تغییرات DOM │ - │ ├── انتخابگر بصری المان‌ها │ - │ ├── خط لوله اسکرین‌شات تمیز │ - │ └── درایور تعاملات شبیه‌سازی‌شده │ - └────────────────────────────────────┘ +# ۸. اجرای آزمون‌های مهندسی آشوب و تزریق خطا (۱۶ از ۱۶ مهارشده) +npm run chaos ``` +### سنجه‌های اعتبارسنجی سنجیده‌شده: + +| سنجه | نتیجه | توضیح | +|---|---|---| +| **مجموعه حوادث طلایی** | **۱۰۰.۰٪** | حل کامل ۸۶۰ سناریوی قابل‌حل بدون هیچ‌گونه ابهام | +| **نرخ تکمیل بررسی ریشه خطا (ICR)** | **۱۰۰.۰٪** | کشف خودکار و گام‌به‌گام زنجیره علّی خطا | +| **دقت بازپخش اسنپ‌شات‌ها (RF)** | **۱۰۰.۰٪** | بازسازی بایت‌به‌بایت و قطعی وضعیت درخت مجازی DOM | +| **دقت تشخیص علت ریشه‌ای** | **۱۰۰.۰٪** | دسته‌بندی دقیق نوع خطا (حذف کامپوننت، تغییرات CSS، رقابت شبکه) | +| **اعتبارسنجی عملیاتی پروتکل JSON-RPC** | **۳۵۰/۳۵۰ ابزار تاییدشده** | ثبت و تست واقعی تمام ۳۵۰ ابزار روی کانال stdio | +| **مجموعه تست‌های واحد و یکپارچگی** | **۳۲۰/۳۲۰ تست موفق** | پاس شدن ۱۰۰٪ تست‌ها در ۳۶ فایل تستی | + --- -## 📁 ساختار کامل مخزن +## ساختار مخزن پروژه ```text teledom/ @@ -286,7 +510,7 @@ teledom/ │ ├── storage/ # لایه ذخیره‌سازی محلی روی دیسک و ایندکسینگ │ └── ui/ # رابط کاربری رصدخانه (Observatory UI) ├── sdk/ -│ └── python/ # پکیج رسمی پایتون (BrowserController, WorkflowEngine, TargetMemory) +│ └── python/ # پکیج رسمی پایتون (Browser, Workflow, TargetMemory) ├── docs/ │ ├── TOOLS_CATALOG_350_FA.md # کاتالوگ جامع و تفصیلی ۳۵۰ ابزار به زبان فارسی │ ├── TOOLS_CATALOG_350_EN.md # Complete English reference for all 350 tools @@ -300,147 +524,105 @@ teledom/ │ └── operational/ # مجموعه آزمون‌های عملیاتی تاییدیه ۳۵۰ ابزار روی کانال stdio ├── operational-tests/ # ۳۵۰ پوشه اختصاصی شامل تعاریف تست و اعتبارسنجی‌ها ├── package.json # نسخه ۴.۱.۰، اسکریپت‌ها و وابستگی‌ها +├── README.md # مستندات انگلیسی پروژه └── README_FA.md # راهنمای جامع فارسی (این فایل) ``` --- -## 🤖 مرجع ابزارهای پروتکل کانتکست مدل (MCP) - ۳۵۰ ابزار - -تله‌دام نسخه ۴.۱ دارای **۳۵۰ ابزار استاندارد و اعتبارسنجی‌شده JSON-RPC 2.0** در چهار خانواده تخصصی است. +## عیب‌یابی و رفع اشکال -برای مشاهده مشخصات کامل پارامترها، اسکیماهای ورودی و مثال‌های عملیاتی تمامی ۳۵۰ ابزار: -- 📖 **[کاتالوگ جامع ۳۵۰ ابزار به زبان فارسی (بیش از ۳,۹۰۰ سطر)](./docs/TOOLS_CATALOG_350_FA.md)** -- 🇬🇧 **[English Tools Catalog (3,800+ lines)](./docs/TOOLS_CATALOG_350_EN.md)** - -### جدول تفکیکی خانواده‌های ابزارها - -| خانواده ابزار | پیشوند / دسته | تعداد ابزار | توضیحات و کاربرد | -|---|---|:---:|---| -| **هوش زمانی و گردش‌کار** | `td_*` | **۱۴۴** | هسته EventMesh، تحلیل علّی، گراف شواهد، ذخیره/اجرا/دیف/بازپخش ورک‌فلوها، حافظه المان‌ها، اثبات‌های ریاضی و امنیت | -| **تلفیق DevTools کروم** | `dt_*` | **۵۴** | بازرسی مستقیم کلاینت کروم، ممیزی Lighthouse، ثبت HeapSnapshot، ردیابی شبکه HAR، لاگ‌های کنسول و شبیه‌سازی دستگاه‌ها | -| **کالبدشکافی پیشرفته** | `fx_*` | **۳۱** | ارتباط وقایع شبکه با جهش‌های DOM، رگرسیون بصری، تغییرات چیدمان (Layout Shifts)، تداخل Z-index و گارد جهش امن | -| **ابزارهای پایه و تعامل زنده** | Core / v3 | **۱۲۱** | انتخابگر بصری المان‌ها، برش اسکرین‌شات، تعاملات مصنوعی، مقایسه ساختاری DOM، سفر در زمان و ردیابی چرخه حیات | -| **مجموع کل ابزارهای تاییدشده** | | **۳۵۰** | **تاییدیه عملیاتی ۱۰۰٪ (پاس شدن ۳۵۰/۳۵۰ ابزار روی Stdio)** | +| نشانه خطا | علت احتمالی | راه‌حل | +|-----------|-------------|--------| +| **آیکون افزونه خاکستری / غیرفعال است** | سرور بریج روشن نیست یا پورت تداخل دارد | دستور `dom-antigravity status` را اجرا کنید یا سرور MCP را بالا بیاورید؛ پل خودکار روی پورت `۳۸۴۷` فعال می‌شود | +| **خطای `EADDRINUSE: 3847`** | فرآیند دیگری پورت ۳۸۴۷ را اشغال کرده است | پروسس سرگردان قبلی را متوقف کنید یا متغیر `TELEDOM_PORT=3848` را تنظیم نمایید | +| **خطای پر شدن کانتکست در مدل هوش مصنوعی** | اجرای پیش‌فرض در پروفایل کامل (۳۵۰ ابزار حدود ۴۰ هزار توکن است) | پروفایل را به `TELEDOM_PROFILE=core` (~۴,۸۰۰ توکن) یا `minimal` (~۲,۴۰۰ توکن) تغییر دهید | +| **تداخل DevTools کروم (F12) با CDP** | پنجره دیباگر کروم همزمان باز است | تله‌دام مجهز به کشف تداخل است؛ پنجره F12 کروم را ببندید تا پروتکل CDP به افزونه متصل شود | +| **خطای اتصال پکیج پایتون** | سرور ارتباطی بالا نیست | مطمئن شوید قبل از اجرای اسکریپت پایتون، سرور MCP یا دستور `dom-antigravity bridge` فعال باشد | +| **جهش‌های DOM ثبت نمی‌شوند** | افزونه غیرفعال است یا قبل از روشن شدن افزونه صفحه باز شده | تب مربوطه در مرورگر را مجدداً رفرش کنید (`Ctrl+R`) تا اسکریپت‌های افزونه تزریق شوند | --- -## 🚀 راهنمای نصب و شروع سریع - -### ۱. نصب سراسری در سیستم (یک‌کلیک) - -نصب ابزار خط فرمان و ثبت تنظیمات تله‌دام در پیکربندی سراسری کاربر: - -```bash -npm install -g teledom -dom-antigravity install --global -``` - -### ۲. نصب اختصاصی در هر پروژه یا ورک‌اسپیس - -جهت فعال‌سازی تله‌دام برای یک مخزن یا پروژه به‌خصوص: - -```bash -cd /path/to/your-project -npx teledom install --workspace -``` - -این دستور فایل `.agents/mcp_config.json` را ایجاد کرده و تعاریف کامل مهارت‌های ۳۵۰ ابزار را در پوشه `.agents/skills/` ثبت می‌نماید. +## محدودیت‌های صادقانه -### ۳. لود کردن افزونه در مرورگر کروم +| محدودیت | جزئیات فنی و راهکار جایگزین | +|---------|------------------------------| +| **تمرکز اولیه بر خانواده Chromium** | برای مرورگرهای Chrome، Edge و Brave توسعه یافته است. افزونه فایرفاکس و سافاری در حال حاضر در دسترس نیستند. | +| **نیاز محیط‌های Headless در CI به تنظیم اولیه** | ضبط زنده تغییرات DOM نیازمند رندر گرافیکی است. در سرورهای CI از ابزارهایی مانند `xvfb-run` یا حالت اتصال مستقیم CDP استفاده کنید. | +| **هزینه توکن در پروفایل `full`** | نمایش اسکیماهای هر ۳۵۰ ابزار حدود ۴۰,۰۰۰ توکن فضا می‌برد. برای کارهای روزمره از پروفایل `core` استفاده فرمایید. | +| **ایزوله‌سازی اسکریپت‌ها در بازپخش مجازی** | کلیه اسکریپت‌های درون‌خطی (`onclick` و غیره) در حالت بازپخش به دلایل امنیتی غیرفعال می‌شوند. | +| **پورت اشتراکی پیش‌فرض** | پورت پیش‌فرض `۳۸۴۷` بین تب‌ها به اشتراک گذاشته می‌شود. برای محیط‌های ایزوله چند عاملی، پورت‌های مجزا در `TELEDOM_PORT` تعریف کنید. | -۱. مرورگر Google Chrome را باز کرده و به آدرس `chrome://extensions/` بروید. -۲. گزینه **Developer mode** را در گوشه بالا سمت راست روشن کنید. -۳. روی دکمه **Load unpacked** کلیک کرده و پوشه `teledom/dist/extension` را انتخاب کنید. -۴. آیکون تله‌دام در نوار ابزار کروم ظاهر می‌شود. +ما محدودیت‌ها و ملاحظات مهندسی را صادقانه بیان می‌کنیم تا انتظارات با واقعیت منطبق باشد. -### ۴. اتصال به کلاینت‌های هوش مصنوعی (Claude / Cursor / Cline) +--- -#### پیکربندی Claude Desktop (`claude_desktop_config.json`) +## مدل امنیت و حریم خصوصی -```json -{ - "mcpServers": { - "teledom": { - "command": "node", - "args": ["C:/path/to/teledom/dist/server/mcp-server.js"] - } - } -} -``` - -#### پیکربندی Cursor (`.cursor/mcp.json`) - -```json -{ - "mcpServers": { - "teledom": { - "command": "node", - "args": ["C:/path/to/teledom/dist/server/mcp-server.js"] - } - } -} -``` +۱. **امنیت درگاه پل ارتباطی (پورت ۳۸۴۷):** تنظیمات CORS کاملاً محدود به لوکال‌هاست و افزونه رسمی کروم بوده و درخواست‌های ارتقا به وب‌سوکت اعتبارسنجی می‌شوند تا هیچ وب‌سایت متفرقه‌ای نتواند به ابزارها دسترسی یابد. +۲. **ماسک‌سازی خودکار داده‌های حساس:** هسته `PrivacyEngine` به صورت خودکار مقادیر فیلدهای رمز عبور، شماره کارت‌های بانکی، کدهای ملی، توکن‌های Bearer و کلیدهای API را قبل از ذخیره‌سازی سانسور می‌کند. +۳. **گارد جهش امن (Safe Mutation Guard):** اعمال تغییرات روی DOM داخل یک کانتکست ترانزاکشنال و با امکان پیش‌نمایش بی‌خطر (Dry-run) انجام می‌شود تا از حذف یا ویرایش ناخواسته المان‌ها جلوگیری شود. --- -## 🧪 تست‌ها و تضمین کیفیت +## سوالات متداول (FAQ) -تله‌دام دارای یک پایپ‌لاین آزمون چندلایه‌ای بسیار سخت‌گیرانه است: +**آیا لازم است سرور وب‌سوکت را به صورت دستی در یک ترمینال جداگانه باز کنم؟** +خیر. سرور `ForensicMCPServer` مجهز به قابلیت پل ارتباطی خودکار (Auto-Bridge) است. به محض اتصال عامل هوش مصنوعی، سرور پورت ۳۸۴۷ را در پس‌زمینه روشن می‌کند. -```bash -# ۱. اجرای کل تست‌های واحد و تست‌های هوش زمانی (۳۱۹ تست) -npm run test:unit +**چگونه مصرف توکن را در Cursor یا Claude به حداقل برسانم؟** +کافیست متغیر `TELEDOM_PROFILE=core` (۴۲ ابزار، حدود ۴,۸۰۰ توکن) یا `TELEDOM_PROFILE=minimal` (۲۲ ابزار، حدود ۲,۴۰۰ توکن) را در فایل پیکربندی کلاینت خود قرار دهید. -# ۲. اجرای آزمون‌های اختصاصی پکیج پایتون (۱۷ تست) -npm run test:sdk - -# ۳. اجرای آزمون عملیاتی تاییدیه تمامی ۳۵۰ ابزار روی کانال stdio -npm run test:operational +**آیا تله‌دام بدون دسترسی به اینترنت و به صورت آفلاین کار می‌کند؟** +بله. تله‌دام کاملاً محلی است. سرور، افزونه و پل ارتباطی بدون نیاز به هیچ شبکه خارجی روی رایانه شما اجرا می‌شوند. -# ۴. اجرای ماتریس بنچمارک قطعی (۱۰ هزار، ۱۰۰ هزار و ۱ میلیون رویداد) -npm run bench +**تله‌دام چگونه از کلیک اشتباه روی دکمه‌های خطرناک جلوگیری می‌کند؟** +موتور جهش امن تمامی اکشن‌ها را ابتدا در یک محیط شبیه‌سازی ارزیابی کرده و بدون تایید مستقیم عامل اجازه اعمال اثرات مخرب را نمی‌دهد. -# ۵. اجرای مجموعه تست‌های حوادث طلایی (۱,۰۳۲ سناریو) -npm run golden +**اسناد تفصیلی مربوط به تک‌تک ابزارها در کجا قرار دارد؟** +هر ۳۵۰ ابزار به همراه پارامترهای ورودی و نمونه‌های عملیاتی در اسناد [docs/TOOLS_CATALOG_350_FA.md](./docs/TOOLS_CATALOG_350_FA.md) و [docs/TOOLS_CATALOG_350_EN.md](./docs/TOOLS_CATALOG_350_EN.md) ثبت شده‌اند. -# ۶. اجرای تست‌های مهندسی آشوب و تزریق خطا -npm run chaos +--- -# ۷. بیلد نهایی پروژه (کلاینت، سرور، افزونه مرورگر) -npm run build -``` +## نمایه مستندات پروژه + +| عنوان سند | نسخه انگلیسی | نسخه فارسی | +|-----------|--------------|------------| +| **راهنمای اصلی پروژه** | [README.md](README.md) | [README_FA.md](README_FA.md) | +| **کاتالوگ جامع ۳۵۰ ابزار** | [docs/TOOLS_CATALOG_350_EN.md](./docs/TOOLS_CATALOG_350_EN.md) | [docs/TOOLS_CATALOG_350_FA.md](./docs/TOOLS_CATALOG_350_FA.md) | +| **راهنمای گردش‌کار عامل‌محور** | [docs/workflow/AGENT_WORKFLOWS.md](./docs/workflow/AGENT_WORKFLOWS.md) | [docs/workflow/AGENT_WORKFLOWS.md](./docs/workflow/AGENT_WORKFLOWS.md) | +| **مستندات پکیج پایتون** | [docs/workflow/PYTHON_SDK.md](./docs/workflow/PYTHON_SDK.md) | [docs/workflow/PYTHON_SDK.md](./docs/workflow/PYTHON_SDK.md) | +| **دستورالعمل‌ها و مثال‌های عملیاتی** | [EXAMPLES.md](EXAMPLES.md) | [EXAMPLES_FA.md](EXAMPLES_FA.md) | +| **سند تفصیلی معماری سیستم** | [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md) | [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md) | +| **گزارش بنچمارک‌ها و ارزیابی** | [docs/intelligence/BENCHMARKS.md](./docs/intelligence/BENCHMARKS.md) | [docs/intelligence/BENCHMARKS.md](./docs/intelligence/BENCHMARKS.md) | +| **یادداشت‌های انتشار نسخه ۴.۱** | [docs/workflow/RELEASE_NOTES.md](./docs/workflow/RELEASE_NOTES.md) | [docs/workflow/RELEASE_NOTES.md](./docs/workflow/RELEASE_NOTES.md) | +| **راهنمای جامع عیب‌یابی** | [docs/TROUBLESHOOTING.md](./docs/TROUBLESHOOTING.md) | [docs/TROUBLESHOOTING.md](./docs/TROUBLESHOOTING.md) | +| **راهنمای مشارکت در پروژه** | [CONTRIBUTING.md](CONTRIBUTING.md) | [CONTRIBUTING.md](CONTRIBUTING.md) | +| **خط‌مشی امنیت** | [SECURITY.md](SECURITY.md) | [SECURITY.md](SECURITY.md) | +| **گزارش تغییرات (Changelog)** | [CHANGELOG.md](CHANGELOG.md) | [CHANGELOG.md](CHANGELOG.md) | --- -## 🔐 امنیت، حریم خصوصی و عملکرد +## مشارکت و امنیت -۱. **ماسک‌سازی اطلاعات حساس به‌صورت پیش‌فرض:** کلاس `PrivacyEngine` تمام فیلدهای رمز عبور، شماره کارت‌های بانکی (سازگار با الگوریتم Luhn)، کدهای ملی، توکن‌های دسترسی، کلیدهای API و سلکتورهای سفارشی اعلام‌شده توسط کاربر را سانسور می‌کند. -۲. **امنیت بازپخش در محیط ایزوله (Sandbox):** در محیط بازسازی اسنپ‌شات‌ها، تمام هندلرهای رویداد درون‌خطی (`on*`) حذف شده و اجرای اسکریپت‌ها مسدود می‌گردد تا از هرگونه اجرای کد ناخواسته جلوگیری شود. -۳. **مصرف بسیار ناچیز منابع و سرعت بالا:** ناظرهای DOM از مکانیزم‌های زمان‌بندی `requestAnimationFrame` و `requestIdleCallback` استفاده می‌کنند تا عملکرد صفحه وب حتی در فرکانس‌های ۱۲۰ هرتز دچار افت فریم نشود. -۴. **فریم‌بندی تمیز کارت گرافیک:** مخفی‌سازی دقیق ویجت‌ها در زمان ثبت اسکرین‌شات از هرگونه آلودگی دیداری در تصاویر جلوگیری می‌کند. +از مشارکت توسعه‌دهندگان، گزارش خطاها و ارسال پول‌ریکوئست‌ها صمیمانه استقبال می‌شود. +لطفاً پیش از ارسال درخواست، فایل‌های [CONTRIBUTING.md](CONTRIBUTING.md) و [SECURITY.md](SECURITY.md) را مطالعه فرمایید. --- -## ❓ عیب‌یابی و سوالات متداول - -#### س: آیا لازم است دستور `npm run bridge` را در یک ترمینال جداگانه باز نگه دارم؟ -> **پاسخ:** خیر! سرور `ForensicMCPServer` مجهز به قابلیت پل خودکار است. هر زمان که عامل هوش مصنوعی یا کلاینتی به سرور MCP وصل شود، سرور به‌صورت خودکار پل ارتباطی WebSocket روی پورت ۳۸۴۷ را در پس‌زمینه روشن می‌کند. +## لایسنس و نویسنده -#### س: چگونه ثبت اسکرین‌شات واقعی از مرورگر کروم را از ترمینال تست کنم؟ -> **پاسخ:** کافیست دستور `dom-antigravity screenshot` را در ترمینال اجرا کنید. این دستور به تب فعال کروم شما وصل شده، یک اسکرین‌شات کامل و یک اسکرین‌شات بریده‌شده از المان تهیه کرده و روی دیسک ذخیره می‌کند. +پروژه تله‌دام یک نرم‌افزار متن‌باز تحت مجوز **Apache License, Version 2.0** است. +متن کامل مجوز در فایل [LICENSE](LICENSE) قابل دسترسی است. -#### س: ۳۵۰ ابزار سیستم در کجا مستند شده‌اند؟ -> **پاسخ:** تک‌تک ابزارها با اسکیماهای کامل ورودی، رابط‌های تایپ‌اسکریپت و نمونه‌های فراخوانی واقعی در فایل‌های [TOOLS_CATALOG_350_FA.md](./docs/TOOLS_CATALOG_350_FA.md) و [TOOLS_CATALOG_350_EN.md](./docs/TOOLS_CATALOG_350_EN.md) مستند شده‌اند. +نویسنده و توسعه‌دهنده اصلی: **محمد جواد (IrMaho)** --- -## 📜 لایسنس و شرایط استفاده +
-این پروژه تحت مجوز **Apache License, Version 2.0** منتشر شده است. متن کامل لایسنس در فایل [LICENSE](LICENSE) یا آدرس زیر در دسترس است: +**تله‌دام نسخه ۴.۱ (TeleDOM v4.1)** — *ببین چه اتفاقی افتاد. دلیلش را بفهم. شبیه‌سازی کن. با اطمینان اصلاح کن. نتیجه را با اثبات نشان بده.* -```text -http://www.apache.org/licenses/LICENSE-2.0 -``` +
diff --git a/assets/teledom_3d_logo.png b/assets/teledom_3d_logo.png new file mode 100644 index 00000000..7f45d1be Binary files /dev/null and b/assets/teledom_3d_logo.png differ diff --git a/bin/mcp-server.js b/bin/mcp-server.js index a0a4f77c..cb16181e 100644 --- a/bin/mcp-server.js +++ b/bin/mcp-server.js @@ -55,5 +55,15 @@ if (typeof document === 'undefined') { global.__FORENSIC_SIMULATION__ = true; } +const profileArg = process.argv.find((a) => a.startsWith('--profile=')); +if (profileArg) { + process.env.TELEDOM_PROFILE = profileArg.split('=')[1]; +} else { + const profileIdx = process.argv.indexOf('--profile'); + if (profileIdx !== -1 && process.argv[profileIdx + 1]) { + process.env.TELEDOM_PROFILE = process.argv[profileIdx + 1]; + } +} + const server = new ForensicMCPServer(); server.startStdio(); diff --git a/chrome-extension/dist/extension/content-script.js b/chrome-extension/dist/extension/content-script.js index 85ef3552..faa564d3 100644 --- a/chrome-extension/dist/extension/content-script.js +++ b/chrome-extension/dist/extension/content-script.js @@ -1,10 +1,10 @@ -var Bt=Object.defineProperty;var Ft=(U,z,Y)=>z in U?Bt(U,z,{enumerable:!0,configurable:!0,writable:!0,value:Y}):U[z]=Y;var f=(U,z,Y)=>Ft(U,typeof z!="symbol"?z+"":z,Y);(function(){"use strict";var U=(l=>(l[l.ELEMENT_NODE=1]="ELEMENT_NODE",l[l.ATTRIBUTE_NODE=2]="ATTRIBUTE_NODE",l[l.TEXT_NODE=3]="TEXT_NODE",l[l.CDATA_SECTION_NODE=4]="CDATA_SECTION_NODE",l[l.PROCESSING_INSTRUCTION_NODE=7]="PROCESSING_INSTRUCTION_NODE",l[l.COMMENT_NODE=8]="COMMENT_NODE",l[l.DOCUMENT_NODE=9]="DOCUMENT_NODE",l[l.DOCUMENT_TYPE_NODE=10]="DOCUMENT_TYPE_NODE",l[l.DOCUMENT_FRAGMENT_NODE=11]="DOCUMENT_FRAGMENT_NODE",l))(U||{});class z{constructor(){f(this,"nextId",1);f(this,"nodeToIdMap",new WeakMap);f(this,"idToNodeMap",new Map);f(this,"identities",new Map);f(this,"parentHistory",new Map)}getOrCreateId(e,t=0){if(this.nodeToIdMap.has(e))return this.nodeToIdMap.get(e);const s=this.nextId++;this.nodeToIdMap.set(e,s),this.idToNodeMap.set(s,e);const i=e.nodeType===U.ELEMENT_NODE||e.nodeType===1?e:null,r=i&&i.tagName?i.tagName.toLowerCase():void 0,o=r?r.includes("-"):!1,a={id:s,nodeType:e.nodeType,tagName:r,createdAt:t,initialSelectorHint:i?this.computeSelector(i):void 0,isCustomElement:o};return this.identities.set(s,a),s}getId(e){return this.nodeToIdMap.get(e)}getNode(e){return this.idToNodeMap.get(e)}getIdentity(e){return this.identities.get(e)}recordParent(e,t){if(!t)return;const s=this.parentHistory.get(e)||[];s[s.length-1]!==t&&(s.push(t),this.parentHistory.set(e,s))}getParentHistory(e){return this.parentHistory.get(e)||[]}computeSelector(e){try{const t=typeof e.id=="string"?e.id:e.getAttribute?e.getAttribute("id"):"";if(t&&/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(t))return`#${t}`;const s=e.tagName?e.tagName.toLowerCase():"element";if(s==="body"||s==="html"||s==="head")return s;let n=[];e.classList&&typeof e.classList.forEach=="function"?n=Array.from(e.classList):typeof e.className=="string"?n=e.className.split(/\s+/):e.className&&typeof e.className.baseVal=="string"&&(n=e.className.baseVal.split(/\s+/));let i="";if(n.length>0){const r=n.filter(o=>typeof o=="string"&&/^[a-zA-Z0-9_-]+$/.test(o)&&!o.startsWith("ng-")&&!o.startsWith("_ng")).slice(0,3);r.length>0&&(i="."+r.join("."))}if(e.parentElement&&e.parentElement.children){const r=Array.from(e.parentElement.children).filter(o=>o.tagName&&o.tagName.toLowerCase()===s);if(r.length>1){const o=r.indexOf(e)+1;if(o>0)return`${s}${i}:nth-of-type(${o})`}}return`${s}${i}`}catch{return e.tagName?e.tagName.toLowerCase():"element"}}computeFullSelectorPath(e){const t=[];let s=e;for(;s&&s.tagName&&s.tagName.toLowerCase()!=="html";){const n=this.computeSelector(s);if(t.unshift(n),s.id&&/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(s.id))break;s=s.parentElement}return t.join(" > ")}removeNode(e){this.idToNodeMap.get(e)&&this.idToNodeMap.delete(e)}reset(){this.nextId=1,this.nodeToIdMap=new WeakMap,this.idToNodeMap.clear(),this.identities.clear(),this.parentHistory.clear()}}const Y={maskAllInputs:!1,maskInputTypes:["password","hidden","tel","email"],maskSelectors:["[data-private]",".private-data",".sensitive",'[data-testid="sensitive"]'],blockSelectors:[".recording-blocked","[data-recording-ignore]"],redactHeaders:["authorization","cookie","set-cookie","x-api-key","proxy-authorization","token"],redactQueryParams:["token","key","auth","secret","password","access_token","apiKey","bearer"],maxTextLength:1e5};class se{constructor(e={}){f(this,"config");this.config={...Y,...e}}shouldBlockNode(e){if(!e||!e.matches)return!1;for(const t of this.config.blockSelectors)try{if(e.matches(t)||e.closest(t))return!0}catch{}return!1}shouldMaskText(e){if(!e||!e.matches)return!1;for(const t of this.config.maskSelectors)try{if(e.matches(t)||e.closest(t))return!0}catch{}return!1}maskValue(e,t,s){return e&&(this.config.maskAllInputs?"*".repeat(Math.min(e.length,12)):t&&this.config.maskInputTypes.includes(t.toLowerCase())||s&&/(password|token|secret|cvv|credit|auth|ssn)/i.test(s)?"••••••••":e)}sanitizeText(e,t=!1){return e&&(t?e.replace(/[^\s\n\r\t]/g,"*"):e.length>this.config.maxTextLength?e.substring(0,this.config.maxTextLength)+"... [TRUNCATED]":e)}sanitizeHeaders(e){if(!e)return;const t={};for(const[s,n]of Object.entries(e)){const i=s.toLowerCase();this.config.redactHeaders.some(r=>i.includes(r))?t[s]="[REDACTED]":t[s]=n}return t}sanitizeUrl(e){try{const t=new URL(e);for(const s of this.config.redactQueryParams)t.searchParams.has(s)&&t.searchParams.set(s,"[REDACTED]");return t.toString()}catch{return e}}}class oe{constructor(){f(this,"currentSequence",0);f(this,"sessionStartTime");f(this,"sessionStartWallClock");this.sessionStartTime=typeof performance<"u"?performance.now():0,this.sessionStartWallClock=Date.now()}nextSequence(){return this.currentSequence+=1,this.currentSequence}getSequence(){return this.currentSequence}getRelativeTimestamp(){return typeof performance<"u"?Math.round((performance.now()-this.sessionStartTime)*100)/100:Date.now()-this.sessionStartWallClock}getWallClock(){return Date.now()}generateEventId(e="evt",t){const s=t!==void 0?t:this.nextSequence(),n=Math.random().toString(36).substring(2,8);return`${e}_${s}_${n}`}reset(){this.currentSequence=0,this.sessionStartTime=typeof performance<"u"?performance.now():0,this.sessionStartWallClock=Date.now()}}class me{constructor(e,t,s){f(this,"registry");f(this,"privacy");f(this,"sequenceCounter");this.registry=e,this.privacy=t,this.sequenceCounter=s}captureSnapshot(e=document,t=""){const s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.nextSequence(),i={},r=e.documentElement||e.body,o=this.registry.getOrCreateId(e,s);if(i[o]={id:o,nodeType:U.DOCUMENT_NODE,tagName:"#document",children:[],parentId:null},e.doctype){const c=this.registry.getOrCreateId(e.doctype,s);i[c]={id:c,nodeType:U.DOCUMENT_TYPE_NODE,tagName:e.doctype.name||"html",parentId:o},i[o].children.push(c)}if(r){const c=this.serializeNode(r,o,i,s);c&&i[o].children.push(c)}const a=this.getViewportInfo();return{snapshotId:`snap_${n}_${Date.now()}`,sessionId:t,timestamp:s,sequence:n,rootId:o,nodes:i,title:e.title||"",url:typeof window<"u"?window.location.href:"",origin:typeof window<"u"?window.location.origin:"",viewport:a,doctype:e.doctype?e.doctype.name:void 0,totalNodeCount:Object.keys(i).length}}serializeNode(e,t,s,n){if(!e||e.nodeType===Node.ELEMENT_NODE&&this.privacy.shouldBlockNode(e))return null;const i=this.registry.getOrCreateId(e,n);this.registry.recordParent(i,t);const r={id:i,nodeType:e.nodeType,parentId:t};if(e.nodeType===Node.ELEMENT_NODE){const o=e;r.tagName=o.tagName.toLowerCase(),r.isCustomElement=r.tagName.includes("-"),r.namespaceURI=o.namespaceURI;const a={};if(o.attributes)for(let c=0;c"u"?{width:1920,height:1080,scrollX:0,scrollY:0,devicePixelRatio:1}:{width:window.innerWidth||((e=document.documentElement)==null?void 0:e.clientWidth)||1920,height:window.innerHeight||((t=document.documentElement)==null?void 0:t.clientHeight)||1080,scrollX:window.scrollX||window.pageXOffset||0,scrollY:window.scrollY||window.pageYOffset||0,devicePixelRatio:window.devicePixelRatio||1}}}class Re{constructor(e,t,s,n,i,r=""){f(this,"observer",null);f(this,"registry");f(this,"privacy");f(this,"sequenceCounter");f(this,"snapshotEngine");f(this,"callback");f(this,"sessionId");f(this,"isObserving",!1);this.registry=e,this.privacy=t,this.sequenceCounter=s,this.snapshotEngine=n,this.callback=i,this.sessionId=r}setSessionId(e){this.sessionId=e}start(e=document){this.isObserving||typeof MutationObserver>"u"||(this.observer=new MutationObserver(this.handleMutations.bind(this)),this.observer.observe(e,{childList:!0,attributes:!0,characterData:!0,subtree:!0,attributeOldValue:!0,characterDataOldValue:!0}),this.isObserving=!0)}stop(){this.observer&&(this.observer.disconnect(),this.observer=null),this.isObserving=!1}takeRecords(){if(this.observer){const e=this.observer.takeRecords();e.length>0&&this.handleMutations(e)}}handleMutations(e){const t=this.sequenceCounter.getRelativeTimestamp(),s=this.sequenceCounter.getWallClock();for(let n=0;n0)for(let o=0;o0)for(let o=0;o"u"||typeof document>"u"||(this.isListening=!0,this.cleanups=[],this.attachUserEventListeners(),this.attachNavigationListeners(),this.attachViewportListeners())}stop(){this.cleanups.forEach(e=>{try{e()}catch{}}),this.cleanups=[],this.isListening=!1}attachUserEventListeners(){[{type:"click",handler:t=>this.handlePointerEvent(t,"USER_CLICK"),options:{capture:!0,passive:!0}},{type:"dblclick",handler:t=>this.handlePointerEvent(t,"USER_DBLCLICK"),options:{capture:!0,passive:!0}},{type:"input",handler:t=>this.handleInputEvent(t),options:{capture:!0,passive:!0}},{type:"change",handler:t=>this.handleInputEvent(t,"USER_CHANGE"),options:{capture:!0,passive:!0}},{type:"submit",handler:t=>this.handleSubmitEvent(t),options:{capture:!0,passive:!0}},{type:"keydown",handler:t=>this.handleKeyboardEvent(t,"USER_KEYDOWN"),options:{capture:!0,passive:!0}},{type:"keyup",handler:t=>this.handleKeyboardEvent(t,"USER_KEYUP"),options:{capture:!0,passive:!0}},{type:"focus",handler:t=>this.handleFocusBlurEvent(t,"USER_FOCUS"),options:{capture:!0,passive:!0}},{type:"blur",handler:t=>this.handleFocusBlurEvent(t,"USER_BLUR"),options:{capture:!0,passive:!0}}].forEach(({type:t,handler:s,options:n})=>{document.addEventListener(t,s,n),this.cleanups.push(()=>document.removeEventListener(t,s,n))})}handlePointerEvent(e,t){const s=e,n=e.target,i=this.sequenceCounter.getRelativeTimestamp(),r=this.sequenceCounter.getWallClock(),o=n?this.registry.getOrCreateId(n,i):void 0,a=n&&n.nodeType===Node.ELEMENT_NODE?this.registry.computeSelector(n):void 0,c=this.sequenceCounter.nextSequence(),u={id:this.sequenceCounter.generateEventId("usr_clk",c),sessionId:this.sessionId,timestamp:i,sequence:c,wallClockTime:r,type:t,category:"USER",source:"USER_INTERACTION",targetNodeId:o,targetSelector:a,payload:{eventType:e.type,targetNodeId:o,targetSelector:a,clientX:s.clientX,clientY:s.clientY,button:s.button,isTrusted:e.isTrusted}};this.callback(u)}handleInputEvent(e,t="USER_INPUT"){const s=e.target;if(!s)return;const n=this.sequenceCounter.getRelativeTimestamp(),i=this.sequenceCounter.getWallClock(),r=this.registry.getOrCreateId(s,n),o=this.registry.computeSelector(s);let a="";if(s.tagName.toLowerCase()==="input"){const d=s;a=this.privacy.maskValue(d.value,d.type,d.name)}else if(s.tagName.toLowerCase()==="textarea"){const d=s;a=this.privacy.maskValue(d.value,"textarea",d.name)}else s.tagName.toLowerCase()==="select"&&(a=s.value);const c=this.sequenceCounter.nextSequence(),u={id:this.sequenceCounter.generateEventId("usr_inp",c),sessionId:this.sessionId,timestamp:n,sequence:c,wallClockTime:i,type:t,category:"USER",source:"USER_INTERACTION",targetNodeId:r,targetSelector:o,payload:{eventType:e.type,targetNodeId:r,targetSelector:o,inputValue:a,isTrusted:e.isTrusted}};this.callback(u)}handleSubmitEvent(e){const t=e.target,s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.getWallClock(),i=t?this.registry.getOrCreateId(t,s):void 0,r=t?this.registry.computeSelector(t):void 0,o=this.sequenceCounter.nextSequence(),a={id:this.sequenceCounter.generateEventId("usr_sub",o),sessionId:this.sessionId,timestamp:s,sequence:o,wallClockTime:n,type:"USER_SUBMIT",category:"USER",source:"USER_INTERACTION",targetNodeId:i,targetSelector:r,payload:{eventType:"submit",targetNodeId:i,targetSelector:r}};this.callback(a)}handleKeyboardEvent(e,t){const s=e.target,n=this.sequenceCounter.getRelativeTimestamp(),i=this.sequenceCounter.getWallClock(),r=s?this.registry.getOrCreateId(s,n):void 0,o=s?this.registry.computeSelector(s):void 0;let a=e.key;s&&s.tagName.toLowerCase()==="input"&&s.type==="password"&&(a="*");const c=this.sequenceCounter.nextSequence(),u={id:this.sequenceCounter.generateEventId("usr_key",c),sessionId:this.sessionId,timestamp:n,sequence:c,wallClockTime:i,type:t,category:"USER",source:"USER_INTERACTION",targetNodeId:r,targetSelector:o,payload:{eventType:e.type,targetNodeId:r,targetSelector:o,key:a,code:e.code,isTrusted:e.isTrusted}};this.callback(u)}handleFocusBlurEvent(e,t){const s=e.target,n=this.sequenceCounter.getRelativeTimestamp(),i=this.sequenceCounter.getWallClock(),r=s?this.registry.getOrCreateId(s,n):void 0,o=s?this.registry.computeSelector(s):void 0,a=this.sequenceCounter.nextSequence(),c={id:this.sequenceCounter.generateEventId("usr_foc",a),sessionId:this.sessionId,timestamp:n,sequence:a,wallClockTime:i,type:t,category:"USER",source:"USER_INTERACTION",targetNodeId:r,targetSelector:o,payload:{eventType:e.type,targetNodeId:r,targetSelector:o}};this.callback(c)}attachNavigationListeners(){if(typeof window>"u"||!window.history)return;const e=window.history.pushState,t=window.history.replaceState;window.history.pushState=(...r)=>{const o=e.apply(window.history,r);return this.recordNavigation("pushState",window.location.href,r[0],r[2]?String(r[2]):void 0),o},window.history.replaceState=(...r)=>{const o=t.apply(window.history,r);return this.recordNavigation("replaceState",window.location.href,r[0],r[2]?String(r[2]):void 0),o};const s=r=>{this.recordNavigation("popstate",window.location.href,r.state)};window.addEventListener("popstate",s);const n=r=>{this.recordNavigation("hashchange",r.newURL,void 0,void 0,r.oldURL)};window.addEventListener("hashchange",n);const i=()=>{this.recordNavigation("visibilitychange",window.location.href,{visibilityState:document.visibilityState,hidden:document.hidden})};document.addEventListener("visibilitychange",i),this.cleanups.push(()=>{window.history.pushState=e,window.history.replaceState=t,window.removeEventListener("popstate",s),window.removeEventListener("hashchange",n),document.removeEventListener("visibilitychange",i)})}recordNavigation(e,t,s,n,i){const r=this.sequenceCounter.getRelativeTimestamp(),o=this.sequenceCounter.getWallClock(),a=this.sequenceCounter.nextSequence(),c={id:this.sequenceCounter.generateEventId("nav",a),sessionId:this.sessionId,timestamp:r,sequence:a,wallClockTime:o,type:`NAV_${e.toUpperCase()}`,category:"NAVIGATION",source:"PAGE",payload:{navigationType:e,url:this.privacy.sanitizeUrl(t),previousUrl:i?this.privacy.sanitizeUrl(i):void 0,state:s,title:n||document.title}};this.callback(c)}attachViewportListeners(){if(typeof window>"u")return;let e=null;const t=()=>{e&&clearTimeout(e),e=setTimeout(()=>{const i=this.sequenceCounter.getRelativeTimestamp(),r=this.sequenceCounter.getWallClock(),o=this.sequenceCounter.nextSequence(),a={id:this.sequenceCounter.generateEventId("vp_res",o),sessionId:this.sessionId,timestamp:i,sequence:o,wallClockTime:r,type:"VIEWPORT_RESIZE",category:"VIEWPORT",source:"BROWSER_RUNTIME",payload:{width:window.innerWidth,height:window.innerHeight,devicePixelRatio:window.devicePixelRatio}};this.callback(a)},100)};window.addEventListener("resize",t,{passive:!0});let s=null;const n=()=>{s&&clearTimeout(s),s=setTimeout(()=>{const i=this.sequenceCounter.getRelativeTimestamp(),r=this.sequenceCounter.getWallClock(),o=this.sequenceCounter.nextSequence(),a={id:this.sequenceCounter.generateEventId("vp_scr",o),sessionId:this.sessionId,timestamp:i,sequence:o,wallClockTime:r,type:"VIEWPORT_SCROLL",category:"VIEWPORT",source:"BROWSER_RUNTIME",payload:{scrollX:window.scrollX,scrollY:window.scrollY}};this.callback(a)},100)};window.addEventListener("scroll",n,{passive:!0}),this.cleanups.push(()=>{e&&clearTimeout(e),s&&clearTimeout(s),window.removeEventListener("resize",t),window.removeEventListener("scroll",n)})}}class ke{constructor(e,t,s,n=""){f(this,"privacy");f(this,"sequenceCounter");f(this,"callback");f(this,"sessionId");f(this,"isInstrumented",!1);f(this,"originalConsole",{});f(this,"originalOnError",null);f(this,"cleanups",[]);this.privacy=e,this.sequenceCounter=t,this.callback=s,this.sessionId=n}setSessionId(e){this.sessionId=e}start(){this.isInstrumented||typeof window>"u"||(this.isInstrumented=!0,this.cleanups=[],this.instrumentConsole(),this.instrumentGlobalErrors(),this.instrumentUnhandledRejections())}stop(){this.cleanups.forEach(e=>{try{e()}catch{}}),this.cleanups=[],this.isInstrumented=!1}instrumentConsole(){if(typeof console>"u")return;["log","warn","error","info","debug"].forEach(t=>{const s=console[t];s&&(this.originalConsole[t]=s,console[t]=(...n)=>{try{this.recordConsole(t,n)}catch{}return s.apply(console,n)},this.cleanups.push(()=>{console[t]=s}))})}recordConsole(e,t){const s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.getWallClock(),i=this.sequenceCounter.nextSequence(),r=t.map(u=>{const d=typeof u;let h="";try{u instanceof Error?h=`${u.name}: ${u.message} -${u.stack||""}`:d==="object"&&u!==null?h=JSON.stringify(u,(p,y)=>typeof y=="function"?"[Function]":y):h=String(u)}catch{h="[Unserializable Object]"}return{type:d,value:this.privacy.sanitizeText(h)}}),o=r.map(u=>u.value).join(" ");let a;try{const u=new Error().stack;u&&(a=u.split(` +var Ft=Object.defineProperty;var Vt=($,H,W)=>H in $?Ft($,H,{enumerable:!0,configurable:!0,writable:!0,value:W}):$[H]=W;var b=($,H,W)=>Vt($,typeof H!="symbol"?H+"":H,W);(function(){"use strict";var $=(l=>(l[l.ELEMENT_NODE=1]="ELEMENT_NODE",l[l.ATTRIBUTE_NODE=2]="ATTRIBUTE_NODE",l[l.TEXT_NODE=3]="TEXT_NODE",l[l.CDATA_SECTION_NODE=4]="CDATA_SECTION_NODE",l[l.PROCESSING_INSTRUCTION_NODE=7]="PROCESSING_INSTRUCTION_NODE",l[l.COMMENT_NODE=8]="COMMENT_NODE",l[l.DOCUMENT_NODE=9]="DOCUMENT_NODE",l[l.DOCUMENT_TYPE_NODE=10]="DOCUMENT_TYPE_NODE",l[l.DOCUMENT_FRAGMENT_NODE=11]="DOCUMENT_FRAGMENT_NODE",l))($||{});class H{constructor(){b(this,"nextId",1);b(this,"nodeToIdMap",new WeakMap);b(this,"idToNodeMap",new Map);b(this,"identities",new Map);b(this,"parentHistory",new Map)}getOrCreateId(e,t=0){if(this.nodeToIdMap.has(e))return this.nodeToIdMap.get(e);const s=this.nextId++;this.nodeToIdMap.set(e,s),this.idToNodeMap.set(s,e);const i=e.nodeType===$.ELEMENT_NODE||e.nodeType===1?e:null,r=i&&i.tagName?i.tagName.toLowerCase():void 0,o=r?r.includes("-"):!1,a={id:s,nodeType:e.nodeType,tagName:r,createdAt:t,initialSelectorHint:i?this.computeSelector(i):void 0,isCustomElement:o};return this.identities.set(s,a),s}getId(e){return this.nodeToIdMap.get(e)}getNode(e){return this.idToNodeMap.get(e)}getIdentity(e){return this.identities.get(e)}recordParent(e,t){if(!t)return;const s=this.parentHistory.get(e)||[];s[s.length-1]!==t&&(s.push(t),this.parentHistory.set(e,s))}getParentHistory(e){return this.parentHistory.get(e)||[]}computeSelector(e){try{const t=typeof e.id=="string"?e.id:e.getAttribute?e.getAttribute("id"):"";if(t&&/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(t))return`#${t}`;const s=e.tagName?e.tagName.toLowerCase():"element";if(s==="body"||s==="html"||s==="head")return s;let n=[];e.classList&&typeof e.classList.forEach=="function"?n=Array.from(e.classList):typeof e.className=="string"?n=e.className.split(/\s+/):e.className&&typeof e.className.baseVal=="string"&&(n=e.className.baseVal.split(/\s+/));let i="";if(n.length>0){const r=n.filter(o=>typeof o=="string"&&/^[a-zA-Z0-9_-]+$/.test(o)&&!o.startsWith("ng-")&&!o.startsWith("_ng")).slice(0,3);r.length>0&&(i="."+r.join("."))}if(e.parentElement&&e.parentElement.children){const r=Array.from(e.parentElement.children).filter(o=>o.tagName&&o.tagName.toLowerCase()===s);if(r.length>1){const o=r.indexOf(e)+1;if(o>0)return`${s}${i}:nth-of-type(${o})`}}return`${s}${i}`}catch{return e.tagName?e.tagName.toLowerCase():"element"}}computeFullSelectorPath(e){const t=[];let s=e;for(;s&&s.tagName&&s.tagName.toLowerCase()!=="html";){const n=this.computeSelector(s);if(t.unshift(n),s.id&&/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(s.id))break;s=s.parentElement}return t.join(" > ")}removeNode(e){this.idToNodeMap.get(e)&&this.idToNodeMap.delete(e)}reset(){this.nextId=1,this.nodeToIdMap=new WeakMap,this.idToNodeMap.clear(),this.identities.clear(),this.parentHistory.clear()}}const W={maskAllInputs:!1,maskInputTypes:["password","hidden","tel","email"],maskSelectors:["[data-private]",".private-data",".sensitive",'[data-testid="sensitive"]'],blockSelectors:[".recording-blocked","[data-recording-ignore]"],redactHeaders:["authorization","cookie","set-cookie","x-api-key","proxy-authorization","token"],redactQueryParams:["token","key","auth","secret","password","access_token","apiKey","bearer"],maxTextLength:1e5};class J{constructor(e={}){b(this,"config");this.config={...W,...e}}shouldBlockNode(e){if(!e||!e.matches)return!1;for(const t of this.config.blockSelectors)try{if(e.matches(t)||e.closest(t))return!0}catch{}return!1}shouldMaskText(e){if(!e||!e.matches)return!1;for(const t of this.config.maskSelectors)try{if(e.matches(t)||e.closest(t))return!0}catch{}return!1}maskValue(e,t,s){return e&&(this.config.maskAllInputs?"*".repeat(Math.min(e.length,12)):t&&this.config.maskInputTypes.includes(t.toLowerCase())||s&&/(password|token|secret|cvv|credit|auth|ssn)/i.test(s)?"••••••••":e)}sanitizeText(e,t=!1){return e&&(t?e.replace(/[^\s\n\r\t]/g,"*"):e.length>this.config.maxTextLength?e.substring(0,this.config.maxTextLength)+"... [TRUNCATED]":e)}sanitizeHeaders(e){if(!e)return;const t={};for(const[s,n]of Object.entries(e)){const i=s.toLowerCase();this.config.redactHeaders.some(r=>i.includes(r))?t[s]="[REDACTED]":t[s]=n}return t}sanitizeUrl(e){try{const t=new URL(e);for(const s of this.config.redactQueryParams)t.searchParams.has(s)&&t.searchParams.set(s,"[REDACTED]");return t.toString()}catch{return e}}}class ne{constructor(){b(this,"currentSequence",0);b(this,"sessionStartTime");b(this,"sessionStartWallClock");this.sessionStartTime=typeof performance<"u"?performance.now():0,this.sessionStartWallClock=Date.now()}nextSequence(){return this.currentSequence+=1,this.currentSequence}getSequence(){return this.currentSequence}getRelativeTimestamp(){return typeof performance<"u"?Math.round((performance.now()-this.sessionStartTime)*100)/100:Date.now()-this.sessionStartWallClock}getWallClock(){return Date.now()}generateEventId(e="evt",t){const s=t!==void 0?t:this.nextSequence(),n=Math.random().toString(36).substring(2,8);return`${e}_${s}_${n}`}reset(){this.currentSequence=0,this.sessionStartTime=typeof performance<"u"?performance.now():0,this.sessionStartWallClock=Date.now()}}class he{constructor(e,t,s){b(this,"registry");b(this,"privacy");b(this,"sequenceCounter");this.registry=e,this.privacy=t,this.sequenceCounter=s}captureSnapshot(e=document,t=""){const s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.nextSequence(),i={},r=e.documentElement||e.body,o=this.registry.getOrCreateId(e,s);if(i[o]={id:o,nodeType:$.DOCUMENT_NODE,tagName:"#document",children:[],parentId:null},e.doctype){const c=this.registry.getOrCreateId(e.doctype,s);i[c]={id:c,nodeType:$.DOCUMENT_TYPE_NODE,tagName:e.doctype.name||"html",parentId:o},i[o].children.push(c)}if(r){const c=this.serializeNode(r,o,i,s);c&&i[o].children.push(c)}const a=this.getViewportInfo();return{snapshotId:`snap_${n}_${Date.now()}`,sessionId:t,timestamp:s,sequence:n,rootId:o,nodes:i,title:e.title||"",url:typeof window<"u"?window.location.href:"",origin:typeof window<"u"?window.location.origin:"",viewport:a,doctype:e.doctype?e.doctype.name:void 0,totalNodeCount:Object.keys(i).length}}serializeNode(e,t,s,n){if(!e||e.nodeType===Node.ELEMENT_NODE&&this.privacy.shouldBlockNode(e))return null;const i=this.registry.getOrCreateId(e,n);this.registry.recordParent(i,t);const r={id:i,nodeType:e.nodeType,parentId:t};if(e.nodeType===Node.ELEMENT_NODE){const o=e;r.tagName=o.tagName.toLowerCase(),r.isCustomElement=r.tagName.includes("-"),r.namespaceURI=o.namespaceURI;const a={};if(o.attributes)for(let c=0;c"u"?{width:1920,height:1080,scrollX:0,scrollY:0,devicePixelRatio:1}:{width:window.innerWidth||((e=document.documentElement)==null?void 0:e.clientWidth)||1920,height:window.innerHeight||((t=document.documentElement)==null?void 0:t.clientHeight)||1080,scrollX:window.scrollX||window.pageXOffset||0,scrollY:window.scrollY||window.pageYOffset||0,devicePixelRatio:window.devicePixelRatio||1}}}class Ne{constructor(e,t,s,n,i,r=""){b(this,"observer",null);b(this,"registry");b(this,"privacy");b(this,"sequenceCounter");b(this,"snapshotEngine");b(this,"callback");b(this,"sessionId");b(this,"isObserving",!1);this.registry=e,this.privacy=t,this.sequenceCounter=s,this.snapshotEngine=n,this.callback=i,this.sessionId=r}setSessionId(e){this.sessionId=e}start(e=document){this.isObserving||typeof MutationObserver>"u"||(this.observer=new MutationObserver(this.handleMutations.bind(this)),this.observer.observe(e,{childList:!0,attributes:!0,characterData:!0,subtree:!0,attributeOldValue:!0,characterDataOldValue:!0}),this.isObserving=!0)}stop(){this.observer&&(this.observer.disconnect(),this.observer=null),this.isObserving=!1}takeRecords(){if(this.observer){const e=this.observer.takeRecords();e.length>0&&this.handleMutations(e)}}handleMutations(e){const t=this.sequenceCounter.getRelativeTimestamp(),s=this.sequenceCounter.getWallClock();for(let n=0;n0)for(let o=0;o0)for(let o=0;o"u"||typeof document>"u"||(this.isListening=!0,this.cleanups=[],this.attachUserEventListeners(),this.attachNavigationListeners(),this.attachViewportListeners())}stop(){this.cleanups.forEach(e=>{try{e()}catch{}}),this.cleanups=[],this.isListening=!1}attachUserEventListeners(){[{type:"click",handler:t=>this.handlePointerEvent(t,"USER_CLICK"),options:{capture:!0,passive:!0}},{type:"dblclick",handler:t=>this.handlePointerEvent(t,"USER_DBLCLICK"),options:{capture:!0,passive:!0}},{type:"input",handler:t=>this.handleInputEvent(t),options:{capture:!0,passive:!0}},{type:"change",handler:t=>this.handleInputEvent(t,"USER_CHANGE"),options:{capture:!0,passive:!0}},{type:"submit",handler:t=>this.handleSubmitEvent(t),options:{capture:!0,passive:!0}},{type:"keydown",handler:t=>this.handleKeyboardEvent(t,"USER_KEYDOWN"),options:{capture:!0,passive:!0}},{type:"keyup",handler:t=>this.handleKeyboardEvent(t,"USER_KEYUP"),options:{capture:!0,passive:!0}},{type:"focus",handler:t=>this.handleFocusBlurEvent(t,"USER_FOCUS"),options:{capture:!0,passive:!0}},{type:"blur",handler:t=>this.handleFocusBlurEvent(t,"USER_BLUR"),options:{capture:!0,passive:!0}}].forEach(({type:t,handler:s,options:n})=>{document.addEventListener(t,s,n),this.cleanups.push(()=>document.removeEventListener(t,s,n))})}handlePointerEvent(e,t){const s=e,n=e.target,i=this.sequenceCounter.getRelativeTimestamp(),r=this.sequenceCounter.getWallClock(),o=n?this.registry.getOrCreateId(n,i):void 0,a=n&&n.nodeType===Node.ELEMENT_NODE?this.registry.computeSelector(n):void 0,c=this.sequenceCounter.nextSequence(),u={id:this.sequenceCounter.generateEventId("usr_clk",c),sessionId:this.sessionId,timestamp:i,sequence:c,wallClockTime:r,type:t,category:"USER",source:"USER_INTERACTION",targetNodeId:o,targetSelector:a,payload:{eventType:e.type,targetNodeId:o,targetSelector:a,clientX:s.clientX,clientY:s.clientY,button:s.button,isTrusted:e.isTrusted}};this.callback(u)}handleInputEvent(e,t="USER_INPUT"){const s=e.target;if(!s)return;const n=this.sequenceCounter.getRelativeTimestamp(),i=this.sequenceCounter.getWallClock(),r=this.registry.getOrCreateId(s,n),o=this.registry.computeSelector(s);let a="";if(s.tagName.toLowerCase()==="input"){const h=s;a=this.privacy.maskValue(h.value,h.type,h.name)}else if(s.tagName.toLowerCase()==="textarea"){const h=s;a=this.privacy.maskValue(h.value,"textarea",h.name)}else s.tagName.toLowerCase()==="select"&&(a=s.value);const c=this.sequenceCounter.nextSequence(),u={id:this.sequenceCounter.generateEventId("usr_inp",c),sessionId:this.sessionId,timestamp:n,sequence:c,wallClockTime:i,type:t,category:"USER",source:"USER_INTERACTION",targetNodeId:r,targetSelector:o,payload:{eventType:e.type,targetNodeId:r,targetSelector:o,inputValue:a,isTrusted:e.isTrusted}};this.callback(u)}handleSubmitEvent(e){const t=e.target,s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.getWallClock(),i=t?this.registry.getOrCreateId(t,s):void 0,r=t?this.registry.computeSelector(t):void 0,o=this.sequenceCounter.nextSequence(),a={id:this.sequenceCounter.generateEventId("usr_sub",o),sessionId:this.sessionId,timestamp:s,sequence:o,wallClockTime:n,type:"USER_SUBMIT",category:"USER",source:"USER_INTERACTION",targetNodeId:i,targetSelector:r,payload:{eventType:"submit",targetNodeId:i,targetSelector:r}};this.callback(a)}handleKeyboardEvent(e,t){const s=e.target,n=this.sequenceCounter.getRelativeTimestamp(),i=this.sequenceCounter.getWallClock(),r=s?this.registry.getOrCreateId(s,n):void 0,o=s?this.registry.computeSelector(s):void 0;let a=e.key;s&&s.tagName.toLowerCase()==="input"&&s.type==="password"&&(a="*");const c=this.sequenceCounter.nextSequence(),u={id:this.sequenceCounter.generateEventId("usr_key",c),sessionId:this.sessionId,timestamp:n,sequence:c,wallClockTime:i,type:t,category:"USER",source:"USER_INTERACTION",targetNodeId:r,targetSelector:o,payload:{eventType:e.type,targetNodeId:r,targetSelector:o,key:a,code:e.code,isTrusted:e.isTrusted}};this.callback(u)}handleFocusBlurEvent(e,t){const s=e.target,n=this.sequenceCounter.getRelativeTimestamp(),i=this.sequenceCounter.getWallClock(),r=s?this.registry.getOrCreateId(s,n):void 0,o=s?this.registry.computeSelector(s):void 0,a=this.sequenceCounter.nextSequence(),c={id:this.sequenceCounter.generateEventId("usr_foc",a),sessionId:this.sessionId,timestamp:n,sequence:a,wallClockTime:i,type:t,category:"USER",source:"USER_INTERACTION",targetNodeId:r,targetSelector:o,payload:{eventType:e.type,targetNodeId:r,targetSelector:o}};this.callback(c)}attachNavigationListeners(){if(typeof window>"u"||!window.history)return;const e=window.history.pushState,t=window.history.replaceState;window.history.pushState=(...r)=>{const o=e.apply(window.history,r);return this.recordNavigation("pushState",window.location.href,r[0],r[2]?String(r[2]):void 0),o},window.history.replaceState=(...r)=>{const o=t.apply(window.history,r);return this.recordNavigation("replaceState",window.location.href,r[0],r[2]?String(r[2]):void 0),o};const s=r=>{this.recordNavigation("popstate",window.location.href,r.state)};window.addEventListener("popstate",s);const n=r=>{this.recordNavigation("hashchange",r.newURL,void 0,void 0,r.oldURL)};window.addEventListener("hashchange",n);const i=()=>{this.recordNavigation("visibilitychange",window.location.href,{visibilityState:document.visibilityState,hidden:document.hidden})};document.addEventListener("visibilitychange",i),this.cleanups.push(()=>{window.history.pushState=e,window.history.replaceState=t,window.removeEventListener("popstate",s),window.removeEventListener("hashchange",n),document.removeEventListener("visibilitychange",i)})}recordNavigation(e,t,s,n,i){const r=this.sequenceCounter.getRelativeTimestamp(),o=this.sequenceCounter.getWallClock(),a=this.sequenceCounter.nextSequence(),c={id:this.sequenceCounter.generateEventId("nav",a),sessionId:this.sessionId,timestamp:r,sequence:a,wallClockTime:o,type:`NAV_${e.toUpperCase()}`,category:"NAVIGATION",source:"PAGE",payload:{navigationType:e,url:this.privacy.sanitizeUrl(t),previousUrl:i?this.privacy.sanitizeUrl(i):void 0,state:s,title:n||document.title}};this.callback(c)}attachViewportListeners(){if(typeof window>"u")return;let e=null;const t=()=>{e&&clearTimeout(e),e=setTimeout(()=>{const i=this.sequenceCounter.getRelativeTimestamp(),r=this.sequenceCounter.getWallClock(),o=this.sequenceCounter.nextSequence(),a={id:this.sequenceCounter.generateEventId("vp_res",o),sessionId:this.sessionId,timestamp:i,sequence:o,wallClockTime:r,type:"VIEWPORT_RESIZE",category:"VIEWPORT",source:"BROWSER_RUNTIME",payload:{width:window.innerWidth,height:window.innerHeight,devicePixelRatio:window.devicePixelRatio}};this.callback(a)},100)};window.addEventListener("resize",t,{passive:!0});let s=null;const n=()=>{s&&clearTimeout(s),s=setTimeout(()=>{const i=this.sequenceCounter.getRelativeTimestamp(),r=this.sequenceCounter.getWallClock(),o=this.sequenceCounter.nextSequence(),a={id:this.sequenceCounter.generateEventId("vp_scr",o),sessionId:this.sessionId,timestamp:i,sequence:o,wallClockTime:r,type:"VIEWPORT_SCROLL",category:"VIEWPORT",source:"BROWSER_RUNTIME",payload:{scrollX:window.scrollX,scrollY:window.scrollY}};this.callback(a)},100)};window.addEventListener("scroll",n,{passive:!0}),this.cleanups.push(()=>{e&&clearTimeout(e),s&&clearTimeout(s),window.removeEventListener("resize",t),window.removeEventListener("scroll",n)})}}class Me{constructor(e,t,s,n=""){b(this,"privacy");b(this,"sequenceCounter");b(this,"callback");b(this,"sessionId");b(this,"isInstrumented",!1);b(this,"originalConsole",{});b(this,"originalOnError",null);b(this,"cleanups",[]);this.privacy=e,this.sequenceCounter=t,this.callback=s,this.sessionId=n}setSessionId(e){this.sessionId=e}start(){this.isInstrumented||typeof window>"u"||(this.isInstrumented=!0,this.cleanups=[],this.instrumentConsole(),this.instrumentGlobalErrors(),this.instrumentUnhandledRejections())}stop(){this.cleanups.forEach(e=>{try{e()}catch{}}),this.cleanups=[],this.isInstrumented=!1}instrumentConsole(){if(typeof console>"u")return;["log","warn","error","info","debug"].forEach(t=>{const s=console[t];s&&(this.originalConsole[t]=s,console[t]=(...n)=>{try{this.recordConsole(t,n)}catch{}return s.apply(console,n)},this.cleanups.push(()=>{console[t]=s}))})}recordConsole(e,t){const s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.getWallClock(),i=this.sequenceCounter.nextSequence(),r=t.map(u=>{const h=typeof u;let g="";try{u instanceof Error?g=`${u.name}: ${u.message} +${u.stack||""}`:h==="object"&&u!==null?g=JSON.stringify(u,(p,y)=>typeof y=="function"?"[Function]":y):g=String(u)}catch{g="[Unserializable Object]"}return{type:h,value:this.privacy.sanitizeText(g)}}),o=r.map(u=>u.value).join(" ");let a;try{const u=new Error().stack;u&&(a=u.split(` `).slice(2,8).join(` -`))}catch{}const c={id:this.sequenceCounter.generateEventId("con",i),sessionId:this.sessionId,timestamp:s,sequence:i,wallClockTime:n,type:`RUNTIME_CONSOLE_${e.toUpperCase()}`,category:e==="error"?"ERROR":"CONSOLE",source:"PAGE",payload:{level:e,args:r,formattedMessage:o,stackTrace:a}};this.callback(c)}instrumentGlobalErrors(){if(typeof window>"u")return;const e=t=>{var o,a;const s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.getWallClock(),i=this.sequenceCounter.nextSequence(),r={id:this.sequenceCounter.generateEventId("err",i),sessionId:this.sessionId,timestamp:s,sequence:i,wallClockTime:n,type:"RUNTIME_ERROR",category:"ERROR",source:"PAGE",payload:{message:t.message||"Unknown runtime error",filename:t.filename,lineno:t.lineno,colno:t.colno,stack:((o=t.error)==null?void 0:o.stack)||void 0,name:((a=t.error)==null?void 0:a.name)||"Error"}};this.callback(r)};window.addEventListener("error",e),this.cleanups.push(()=>window.removeEventListener("error",e))}instrumentUnhandledRejections(){if(typeof window>"u")return;const e=t=>{const s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.getWallClock(),i=this.sequenceCounter.nextSequence();let r="Unhandled Promise Rejection",o;if(t.reason instanceof Error)r=t.reason.message,o=t.reason.stack;else if(typeof t.reason=="string")r=t.reason;else if(t.reason)try{r=JSON.stringify(t.reason)}catch{r=String(t.reason)}const a={id:this.sequenceCounter.generateEventId("rej",i),sessionId:this.sessionId,timestamp:s,sequence:i,wallClockTime:n,type:"RUNTIME_UNHANDLED_REJECTION",category:"ERROR",source:"PAGE",payload:{message:r,stack:o,isUnhandledRejection:!0}};this.callback(a)};window.addEventListener("unhandledrejection",e),this.cleanups.push(()=>window.removeEventListener("unhandledrejection",e))}}class Oe{constructor(e,t,s,n=""){f(this,"privacy");f(this,"sequenceCounter");f(this,"callback");f(this,"sessionId");f(this,"isInstrumented",!1);f(this,"originalFetch",null);f(this,"originalXHROpen",null);f(this,"originalXHRSend",null);f(this,"cleanups",[]);this.privacy=e,this.sequenceCounter=t,this.callback=s,this.sessionId=n}setSessionId(e){this.sessionId=e}start(){this.isInstrumented||typeof window>"u"||(this.isInstrumented=!0,this.cleanups=[],this.instrumentFetch(),this.instrumentXHR())}stop(){this.cleanups.forEach(e=>{try{e()}catch{}}),this.cleanups=[],this.isInstrumented=!1}instrumentFetch(){if(typeof window.fetch!="function")return;this.originalFetch=window.fetch;const e=this;window.fetch=async function(...t){const s=e.sequenceCounter.generateEventId("req_f"),n=t[0],i=t[1];let r="";typeof n=="string"?r=n:n instanceof URL?r=n.toString():n&&typeof n=="object"&&"url"in n&&(r=n.url);const o=((i==null?void 0:i.method)||(typeof n=="object"&&"method"in n?n.method:"GET")).toUpperCase(),a=e.privacy.sanitizeUrl(r),c=e.sequenceCounter.getRelativeTimestamp(),u=e.sequenceCounter.getWallClock(),d=e.sequenceCounter.nextSequence(),h={id:s,sessionId:e.sessionId,timestamp:c,sequence:d,wallClockTime:u,type:"NETWORK_REQUEST_START",category:"NETWORK",source:"PAGE",payload:{requestId:s,url:a,method:o,resourceType:"fetch",hasBody:!!(i!=null&&i.body)}};e.callback(h);try{const p=await e.originalFetch.apply(this,t),y=e.sequenceCounter.getRelativeTimestamp(),v=e.sequenceCounter.getWallClock(),m=e.sequenceCounter.nextSequence(),g=Math.max(0,Math.round((y-c)*100)/100),b={id:e.sequenceCounter.generateEventId("res_f",m),sessionId:e.sessionId,timestamp:y,sequence:m,wallClockTime:v,type:"NETWORK_RESPONSE_COMPLETE",category:"NETWORK",source:"PAGE",causality:{triggeredBy:s,precededBy:s},payload:{requestId:s,url:a,method:o,status:p.status,statusText:p.statusText,durationMs:g}};return e.callback(b),p}catch(p){const y=e.sequenceCounter.getRelativeTimestamp(),v=e.sequenceCounter.getWallClock(),m=e.sequenceCounter.nextSequence(),g=Math.max(0,Math.round((y-c)*100)/100),b={id:e.sequenceCounter.generateEventId("res_err",m),sessionId:e.sessionId,timestamp:y,sequence:m,wallClockTime:v,type:"NETWORK_REQUEST_FAILED",category:"NETWORK",source:"PAGE",causality:{triggeredBy:s,precededBy:s},payload:{requestId:s,url:a,method:o,status:0,statusText:"Failed",durationMs:g,error:(p==null?void 0:p.message)||"Network request failed"}};throw e.callback(b),p}},this.cleanups.push(()=>{this.originalFetch&&(window.fetch=this.originalFetch)})}instrumentXHR(){if(typeof XMLHttpRequest>"u")return;this.originalXHROpen=XMLHttpRequest.prototype.open,this.originalXHRSend=XMLHttpRequest.prototype.send;const e=this;XMLHttpRequest.prototype.open=function(t,s,...n){return this._forensicRequestId=e.sequenceCounter.generateEventId("req_x"),this._forensicMethod=(t||"GET").toUpperCase(),this._forensicUrl=typeof s=="string"?s:s.toString(),e.originalXHROpen.apply(this,[t,s,...n])},XMLHttpRequest.prototype.send=function(t){const s=this._forensicRequestId||e.sequenceCounter.generateEventId("req_x"),n=this._forensicMethod||"GET",i=e.privacy.sanitizeUrl(this._forensicUrl||""),r=e.sequenceCounter.getRelativeTimestamp(),o=e.sequenceCounter.getWallClock(),a=e.sequenceCounter.nextSequence();this._forensicStartTime=r;const c={id:s,sessionId:e.sessionId,timestamp:r,sequence:a,wallClockTime:o,type:"NETWORK_REQUEST_START",category:"NETWORK",source:"PAGE",payload:{requestId:s,url:i,method:n,resourceType:"xhr",hasBody:!!t}};e.callback(c);const u=()=>{const d=e.sequenceCounter.getRelativeTimestamp(),h=e.sequenceCounter.getWallClock(),p=e.sequenceCounter.nextSequence(),y=Math.max(0,Math.round((d-(this._forensicStartTime||r))*100)/100),v={id:e.sequenceCounter.generateEventId("res_x",p),sessionId:e.sessionId,timestamp:d,sequence:p,wallClockTime:h,type:this.status>=200&&this.status<400?"NETWORK_RESPONSE_COMPLETE":"NETWORK_REQUEST_FAILED",category:"NETWORK",source:"PAGE",causality:{triggeredBy:s,precededBy:s},payload:{requestId:s,url:i,method:n,status:this.status,statusText:this.statusText,durationMs:y,error:this.status===0?"XHR Network Error or Aborted":void 0}};e.callback(v)};return this.addEventListener("load",u),this.addEventListener("error",u),this.addEventListener("abort",u),e.originalXHRSend.apply(this,[t])},this.cleanups.push(()=>{this.originalXHROpen&&(XMLHttpRequest.prototype.open=this.originalXHROpen),this.originalXHRSend&&(XMLHttpRequest.prototype.send=this.originalXHRSend)})}}class Le{constructor(e={}){f(this,"sequenceCounter");f(this,"registry");f(this,"privacy");f(this,"snapshotEngine");f(this,"mutationObserver");f(this,"eventCollector");f(this,"diagnostics");f(this,"networkMonitor");f(this,"metadata");f(this,"isRecording",!1);f(this,"isPaused",!1);f(this,"eventListeners",new Set);f(this,"checkpointListeners",new Set);f(this,"lastCheckpointSequence",0);f(this,"lastCheckpointTimestamp",0);f(this,"checkpointTimer",null);f(this,"checkpointIntervalEvents",200);f(this,"checkpointIntervalMs",3e4);this.sequenceCounter=new oe,this.registry=new z,this.privacy=new se(e.privacy),this.snapshotEngine=new me(this.registry,this.privacy,this.sequenceCounter);const t=n=>this.handleEvent(n);this.mutationObserver=new Re(this.registry,this.privacy,this.sequenceCounter,this.snapshotEngine,t),this.eventCollector=new Me(this.registry,this.privacy,this.sequenceCounter,t),this.diagnostics=new ke(this.privacy,this.sequenceCounter,t),this.networkMonitor=new Oe(this.privacy,this.sequenceCounter,t),e.checkpointIntervalEvents&&(this.checkpointIntervalEvents=e.checkpointIntervalEvents),e.checkpointIntervalMs&&(this.checkpointIntervalMs=e.checkpointIntervalMs);const s=e.sessionId||`session_${Date.now()}_${Math.random().toString(36).substring(2,7)}`;this.metadata=this.createInitialMetadata(s,e.sessionName)}getSessionId(){return this.metadata.id}getMetadata(){return{...this.metadata,durationMs:this.sequenceCounter.getRelativeTimestamp(),endTime:this.metadata.endTime||Date.now()}}getRegistry(){return this.registry}onEvent(e){return this.eventListeners.add(e),()=>this.eventListeners.delete(e)}onCheckpoint(e){return this.checkpointListeners.add(e),()=>this.checkpointListeners.delete(e)}start(e=typeof document<"u"?document:{}){if(this.isRecording)throw new Error(`Recorder session ${this.metadata.id} is already active`);this.sequenceCounter.reset(),this.registry.reset(),this.isRecording=!0,this.isPaused=!1,this.metadata.status="recording",this.metadata.startTime=Date.now(),this.mutationObserver.setSessionId(this.metadata.id),this.eventCollector.setSessionId(this.metadata.id),this.diagnostics.setSessionId(this.metadata.id),this.networkMonitor.setSessionId(this.metadata.id);const t=this.snapshotEngine.captureSnapshot(e,this.metadata.id);this.metadata.stats.nodeCount=t.totalNodeCount;const s={id:this.sequenceCounter.generateEventId("snap_init",t.sequence),sessionId:this.metadata.id,timestamp:t.timestamp,sequence:t.sequence,wallClockTime:Date.now(),type:"DOM_SNAPSHOT",category:"DOM",source:"PAGE",payload:{snapshot:t}};return this.createCheckpoint(t,"INITIAL"),this.mutationObserver.start(e),this.eventCollector.start(),this.diagnostics.start(),this.networkMonitor.start(),this.handleEvent(s),this.checkpointIntervalMs>0&&typeof setInterval<"u"&&(this.checkpointTimer=setInterval(()=>{this.isRecording&&!this.isPaused&&this.captureCheckpoint("PERIODIC",e)},this.checkpointIntervalMs)),t}stop(){return this.isRecording?(this.mutationObserver.takeRecords(),this.mutationObserver.stop(),this.eventCollector.stop(),this.diagnostics.stop(),this.networkMonitor.stop(),this.checkpointTimer&&(clearInterval(this.checkpointTimer),this.checkpointTimer=null),this.isRecording=!1,this.metadata.status="stopped",this.metadata.endTime=Date.now(),this.metadata.durationMs=this.sequenceCounter.getRelativeTimestamp(),this.getMetadata()):this.getMetadata()}pause(){!this.isRecording||this.isPaused||(this.isPaused=!0,this.metadata.status="paused")}resume(){!this.isRecording||!this.isPaused||(this.isPaused=!1,this.metadata.status="recording")}captureCheckpoint(e="MANUAL",t=document){if(!this.isRecording)return null;const s=this.snapshotEngine.captureSnapshot(t,this.metadata.id);return this.createCheckpoint(s,e)}recordCustomEvent(e,t,s,n){const i=this.sequenceCounter.getRelativeTimestamp(),r=this.sequenceCounter.getWallClock(),o=this.sequenceCounter.nextSequence(),a={id:this.sequenceCounter.generateEventId("ext",o),sessionId:this.metadata.id,timestamp:i,sequence:o,wallClockTime:r,type:e,category:"EXTENSION",source:"CONTENT_SCRIPT",targetNodeId:s,targetSelector:n,payload:t};return this.handleEvent(a),a}recordScreenshot(e,t="MANUAL"){const s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.getWallClock(),i=this.sequenceCounter.nextSequence(),r={id:this.sequenceCounter.generateEventId("scr",i),sessionId:this.metadata.id,timestamp:s,sequence:i,wallClockTime:n,type:"SCREENSHOT_CHECKPOINT",category:"SCREENSHOT",source:"BROWSER_RUNTIME",payload:{screenshotId:`shot_${i}`,dataUrl:e,viewport:{width:typeof window<"u"?window.innerWidth:1920,height:typeof window<"u"?window.innerHeight:1080,scrollX:typeof window<"u"?window.scrollX:0,scrollY:typeof window<"u"?window.scrollY:0,devicePixelRatio:typeof window<"u"?window.devicePixelRatio:1},triggerReason:t}};return this.handleEvent(r),r}addAnnotation(e,t,s="AGENT",n){const i=this.sequenceCounter.getRelativeTimestamp(),r=this.sequenceCounter.nextSequence(),o={id:`ann_${r}_${Math.random().toString(36).substring(2,6)}`,sessionId:this.metadata.id,timestamp:i,sequence:r,nodeId:n,author:s,label:e,comment:t,createdAt:Date.now()},a={id:o.id,sessionId:this.metadata.id,timestamp:i,sequence:r,wallClockTime:Date.now(),type:"ANNOTATION",category:"ANNOTATION",source:s==="USER"?"USER_INTERACTION":"BROWSER_RUNTIME",targetNodeId:n,payload:{annotation:o}};return this.handleEvent(a),o}createCheckpoint(e,t){const s=this.sequenceCounter.getSequence()-this.lastCheckpointSequence;this.lastCheckpointSequence=this.sequenceCounter.getSequence(),this.lastCheckpointTimestamp=e.timestamp,this.metadata.stats.checkpointCount+=1;const n={checkpointId:`chk_${e.sequence}_${Date.now()}`,sessionId:this.metadata.id,timestamp:e.timestamp,sequence:e.sequence,wallClockTime:Date.now(),snapshot:e,eventIndex:this.metadata.stats.eventCount,eventsSinceLastCheckpoint:s,trigger:t},i={id:n.checkpointId,sessionId:this.metadata.id,timestamp:e.timestamp,sequence:e.sequence,wallClockTime:n.wallClockTime,type:"CHECKPOINT",category:"CHECKPOINT",source:"BROWSER_RUNTIME",payload:{checkpointId:n.checkpointId,snapshot:e,eventsSinceLastCheckpoint:s,totalEventsSoFar:this.metadata.stats.eventCount}};return this.checkpointListeners.forEach(r=>{try{r(n)}catch(o){console.error("[ForensicRecorder] Checkpoint listener error:",o)}}),this.handleEvent(i),n}handleEvent(e){this.isPaused&&e.type!=="CHECKPOINT"&&e.type!=="ANNOTATION"||(this.metadata.stats.eventCount+=1,e.category==="DOM"&&(this.metadata.stats.mutationCount+=1),e.category==="ERROR"&&(this.metadata.stats.errorCount+=1),e.category==="CONSOLE"&&(this.metadata.stats.consoleCount+=1),e.category==="NETWORK"&&(this.metadata.stats.networkCount+=1),e.category==="SCREENSHOT"&&(this.metadata.stats.screenshotCount+=1),this.isRecording&&e.type!=="CHECKPOINT"&&e.type!=="DOM_SNAPSHOT"&&this.sequenceCounter.getSequence()-this.lastCheckpointSequence>=this.checkpointIntervalEvents&&typeof document<"u"&&this.captureCheckpoint("PERIODIC"),this.eventListeners.forEach(t=>{try{t(e)}catch(s){console.error("[ForensicRecorder] Event listener error:",s)}}))}createInitialMetadata(e,t){const s={domRecording:typeof MutationObserver<"u"?"HEALTHY":"UNAVAILABLE",userEvents:typeof window<"u"?"HEALTHY":"UNAVAILABLE",console:typeof console<"u"?"HEALTHY":"UNAVAILABLE",network:typeof window<"u"&&typeof window.fetch<"u"?"HEALTHY":"PARTIAL",screenshots:"HEALTHY",shadowDom:typeof Element<"u"&&"attachShadow"in Element.prototype?"HEALTHY":"RESTRICTED",iframes:"PARTIAL"},n={eventCount:0,mutationCount:0,errorCount:0,consoleCount:0,networkCount:0,checkpointCount:0,screenshotCount:0,nodeCount:0};return{id:e,name:t||`Recording ${new Date().toLocaleTimeString()}`,url:typeof window<"u"?window.location.href:"about:blank",origin:typeof window<"u"?window.location.origin:"",title:typeof document<"u"?document.title:"Forensic Session",userAgent:typeof navigator<"u"?navigator.userAgent:"Node.js/ForensicAgent",schemaVersion:"2.0.0",recorderVersion:"2.0.0",extensionVersion:"2.0.0",startTime:Date.now(),status:"recording",health:s,stats:n}}}class L{static inspectPage(e=document){var n,i,r,o,a,c,u,d,h,p,y,v,m,g;const t=e.defaultView||(typeof window<"u"?window:{}),s=e.activeElement;return{url:((n=t.location)==null?void 0:n.href)||((i=e.location)==null?void 0:i.href)||"",title:e.title||"",origin:((r=t.location)==null?void 0:r.origin)||"",viewport:{width:t.innerWidth||((o=e.documentElement)==null?void 0:o.clientWidth)||1920,height:t.innerHeight||((a=e.documentElement)==null?void 0:a.clientHeight)||1080,scrollX:t.scrollX||t.pageXOffset||((c=e.documentElement)==null?void 0:c.scrollLeft)||0,scrollY:t.scrollY||t.pageYOffset||((u=e.documentElement)==null?void 0:u.scrollTop)||0,devicePixelRatio:t.devicePixelRatio||1},documentDimensions:{width:Math.max(((d=e.body)==null?void 0:d.scrollWidth)||0,((h=e.documentElement)==null?void 0:h.scrollWidth)||0),height:Math.max(((p=e.body)==null?void 0:p.scrollHeight)||0,((y=e.documentElement)==null?void 0:y.scrollHeight)||0)},activeElement:s?{tag:((v=s.tagName)==null?void 0:v.toLowerCase())||"",selector:this.computeBestSelector(s),text:(m=s.textContent)==null?void 0:m.slice(0,100).trim()}:void 0,focusedElement:typeof e.hasFocus=="function"&&e.hasFocus()&&s?{tag:((g=s.tagName)==null?void 0:g.toLowerCase())||"",selector:this.computeBestSelector(s)}:void 0,visibilityState:e.visibilityState||"visible",readyState:e.readyState||"complete",framesCount:e.querySelectorAll?e.querySelectorAll("iframe, frame").length:0}}static inspectElement(e,t){var te,Ne;const s=e.ownerDocument||document,n=s.defaultView||(typeof window<"u"?window:{}),i=e,r=e.tagName?e.tagName.toLowerCase():"element",o=this.extractClasses(e),{bestSelector:a,candidates:c}=this.generateSelectorCandidates(e),u={},d={};if(e.attributes)for(let G=0;G0||w.height>0||w.right>0||w.bottom>0,M=!S||w.right>0&&w.bottom>0&&w.left=q||w.top>=A),_=!O&&C!=="none"&&N!=="hidden"&&I>0&&M,P={disabled:i.disabled??e.hasAttribute("disabled"),readOnly:i.readOnly??e.hasAttribute("readonly"),checked:i.checked,selected:i.selected,focused:s.activeElement===e,isShadowHost:!!e.shadowRoot,hasShadowRoot:!!e.shadowRoot},H=[];let $=e.parentElement;for(;$&&$.tagName&&$.tagName.toLowerCase()!=="html";)H.push(this.computeBestSelector($)),$=$.parentElement;const F={count:e.children?e.children.length:0,tags:e.children?Array.from(e.children).slice(0,10).map(G=>G.tagName.toLowerCase()):[]};let W;if(t){const G=t.getId(e);W={logicalNodeId:G??null,creationSequence:null,lastMutationSequence:null,eventCount:0,isRecorded:G!=null}}return{tag:r,id:e.id||void 0,classes:o,role:h||void 0,ariaAttributes:Object.keys(d).length>0?d:void 0,text:v.slice(0,200),normalizedText:m.slice(0,200),value:g,type:b.type||void 0,selector:a,bestSelector:a,selectorCandidates:c,bounds:w,visibility:{isVisible:_,display:C,visibility:N,opacity:I,pointerEvents:R,isClipped:O,isInViewport:M,zIndex:x},computedStyle:E?{display:C,visibility:N,opacity:String(I),position:E.position,zIndex:String(x),pointerEvents:R,overflow:E.overflow,boxSizing:E.boxSizing,color:E.color,backgroundColor:E.backgroundColor,fontSize:E.fontSize}:{},attributes:u,state:P,context:{parentChain:H,parentSelector:H[0]||void 0,childrenSummary:F,containingBlock:(E==null?void 0:E.position)==="fixed"?"viewport":H[0]||void 0,iframe:null,shadowRoot:e.shadowRoot?"open":null},forensics:W}}static inspectVisualState(e){var b,T;const t=e.ownerDocument||document,s=t.defaultView||(typeof window<"u"?window:{}),n=e.getBoundingClientRect?e.getBoundingClientRect():{x:0,y:0,width:0,height:0,top:0,right:0,bottom:0,left:0},i=s.getComputedStyle?s.getComputedStyle(e):null,r=s.innerWidth||((b=t.documentElement)==null?void 0:b.clientWidth)||1920,o=s.innerHeight||((T=t.documentElement)==null?void 0:T.clientHeight)||1080,a=s.scrollX||s.pageXOffset||0,c=s.scrollY||s.pageYOffset||0,u=s.devicePixelRatio||1,d=(i==null?void 0:i.display)||"block",h=(i==null?void 0:i.visibility)||"visible",p=i&&parseFloat(i.opacity)||1,y=n.right>0&&n.bottom>0&&n.left=r||n.top>=o;let g=null;if(t.elementFromPoint&&y&&!v&&d!=="none"){const w=Math.max(0,Math.min(r-1,n.left+n.width/2)),E=Math.max(0,Math.min(o-1,n.top+n.height/2));try{const C=t.elementFromPoint(w,E);C&&C!==e&&!e.contains(C)&&!C.contains(e)&&(g=this.computeBestSelector(C))}catch{}}return{selector:this.computeBestSelector(e),bounds:{x:n.x??n.left??0,y:n.y??n.top??0,width:n.width??0,height:n.height??0,top:n.top??0,right:n.right??0,bottom:n.bottom??0,left:n.left??0},viewport:{scrollX:a,scrollY:c,width:r,height:o,devicePixelRatio:u},layout:{display:d,position:(i==null?void 0:i.position)||"static",zIndex:(i==null?void 0:i.zIndex)||"auto",opacity:p,visibility:h,overflow:(i==null?void 0:i.overflow)||"visible",boxSizing:(i==null?void 0:i.boxSizing)||"content-box",pointerEvents:(i==null?void 0:i.pointerEvents)||"auto"},occlusion:{isInViewport:y,isClipped:v||m,isZeroDimension:v,isTransparent:p===0,isDisplayNone:d==="none",isVisibilityHidden:h==="hidden",isOffscreen:m,occludedBy:g},computedStyleSummary:i?{display:d,position:i.position,zIndex:i.zIndex,opacity:String(p),visibility:h,pointerEvents:i.pointerEvents}:{}}}static generateSelectorCandidates(e){const t=e.ownerDocument||document,s=e.tagName?e.tagName.toLowerCase():"element",n=[];if(e.id&&/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(e.id)){const c=`#${e.id}`;try{t.querySelectorAll&&t.querySelectorAll(c).length===1&&n.push(c)}catch{n.push(c)}}const i=["data-testid","data-test","data-id","data-qa","data-cy","aria-label","name"];for(const c of i){const u=e.getAttribute(c);if(u&&/^[a-zA-Z0-9_-]+$/.test(u)){const d=`${s}[${c}="${u}"]`;try{t.querySelectorAll&&t.querySelectorAll(d).length===1&&n.push(d)}catch{n.push(d)}}}const r=this.extractClasses(e).filter(c=>/^[a-zA-Z0-9_-]+$/.test(c)&&!c.startsWith("ng-")&&!c.startsWith("_ng"));if(r.length>0){const c=`${s}.${r.slice(0,3).join(".")}`;try{t.querySelectorAll&&t.querySelectorAll(c).length===1&&n.push(c)}catch{n.push(c)}}if(e.parentElement&&e.parentElement.children){const c=Array.from(e.parentElement.children).filter(u=>u.tagName&&u.tagName.toLowerCase()===s);if(c.length>1){const u=c.indexOf(e)+1;if(u>0){const d=this.computeBestSelector(e.parentElement);n.push(`${d} > ${s}:nth-of-type(${u})`)}}}const o=r.length>0?`${s}.${r[0]}`:s;return n.push(o),{bestSelector:n[0]||s,candidates:n}}static computeBestSelector(e){return this.generateSelectorCandidates(e).bestSelector}static extractClasses(e){return e.classList&&typeof e.classList.forEach=="function"?Array.from(e.classList):typeof e.className=="string"?e.className.split(/\s+/).filter(Boolean):e.className&&typeof e.className.baseVal=="string"?e.className.baseVal.split(/\s+/).filter(Boolean):[]}static inferImplicitRole(e){switch(e.tagName?e.tagName.toLowerCase():""){case"a":return e.hasAttribute("href")?"link":void 0;case"button":return"button";case"input":{const s=e.type||"text";return s==="button"||s==="submit"||s==="reset"?"button":s==="checkbox"?"checkbox":s==="radio"?"radio":"textbox"}case"select":return"combobox";case"textarea":return"textbox";case"nav":return"navigation";case"header":return"banner";case"footer":return"contentinfo";case"main":return"main";case"article":return"article";case"section":return"region";default:return}}}f(L,"privacyEngine",new se);class De{constructor(e){f(this,"registry");f(this,"lastSelectedElementRef");f(this,"timingHook",null);f(this,"lastTrajectory",[]);this.registry=e}setLastSelectedElement(e){this.lastSelectedElementRef=e}setTimingHook(e){this.timingHook=e}getLastTrajectory(){return this.lastTrajectory}async timing(e){this.timingHook&&await this.timingHook(e)}resolveTarget(e,t=document){if(e.selectedElementRef&&this.lastSelectedElementRef&&t.contains(this.lastSelectedElementRef))return this.lastSelectedElementRef;if(typeof e.nodeId=="number"&&this.registry){const s=this.registry.getNode(e.nodeId);if(s&&s instanceof Element&&t.contains(s))return s}if(e.selector)try{const s=t.querySelectorAll(e.selector);if(s.length>1){for(let n=0;n{r+=T.length});try{d.observe(t.body||t.documentElement,{childList:!0,attributes:!0,characterData:!0,subtree:!0})}catch{}const h=T=>{o.push(T.message||"Runtime Error")};typeof window<"u"&&window.addEventListener("error",h);try{await this.dispatchAction(n,e)}finally{typeof window<"u"&&window.removeEventListener("error",h)}let p=!0;if((b=e.options)!=null&&b.waitForStabilization){const T=e.options.stabilizationTimeoutMs||300;await new Promise(w=>setTimeout(w,Math.min(2e3,T)))}d.disconnect();let y;t.contains(n)&&(y=L.inspectElement(n,this.registry));const v=Date.now()-s,m=a!=null&&a.__FORENSIC_CONSOLE_BUFFER__?a.__FORENSIC_CONSOLE_BUFFER__.slice(c).filter(T=>(T==null?void 0:T.level)==="error").length:0,g=a!=null&&a.__FORENSIC_NETWORK_BUFFER__?a.__FORENSIC_NETWORK_BUFFER__.slice(u).length:0;return{success:!0,action:e.action,target:y||i,beforeState:i,afterState:y,effects:{domMutations:r,consoleErrors:m,networkRequests:g,runtimeErrors:o},durationMs:v,stabilized:p}}async dispatchAction(e,t){var n,i,r,o,a,c;const s=e;switch(t.action){case"click":{this.scrollIntoViewIfNeeded(e),await this.timing("move"),await this.timing("click"),this.dispatchMouseEvent(e,"pointerdown"),this.dispatchMouseEvent(e,"mousedown"),typeof s.focus=="function"&&s.focus(),this.dispatchMouseEvent(e,"pointerup"),this.dispatchMouseEvent(e,"mouseup"),typeof s.click=="function"?s.click():this.dispatchMouseEvent(e,"click");break}case"double_click":{this.scrollIntoViewIfNeeded(e),await this.timing("click"),this.dispatchMouseEvent(e,"click"),await this.timing("click"),this.dispatchMouseEvent(e,"click"),this.dispatchMouseEvent(e,"dblclick");break}case"right_click":{this.scrollIntoViewIfNeeded(e),await this.timing("click"),this.dispatchMouseEvent(e,"pointerdown",{button:2}),this.dispatchMouseEvent(e,"mousedown",{button:2}),this.dispatchMouseEvent(e,"contextmenu",{button:2});break}case"hover":{await this.timing("move"),this.dispatchMouseEvent(e,"pointerenter"),this.dispatchMouseEvent(e,"mouseenter"),this.dispatchMouseEvent(e,"mouseover"),await this.timing("move"),this.dispatchMouseEvent(e,"mousemove");break}case"focus":{typeof s.focus=="function"&&s.focus(),e.dispatchEvent(new FocusEvent("focus",{bubbles:!0}));break}case"blur":{typeof s.blur=="function"&&s.blur(),e.dispatchEvent(new FocusEvent("blur",{bubbles:!0}));break}case"type":{const u=t.text||"",d=e,h=((n=e.ownerDocument)==null?void 0:n.defaultView)||(typeof window<"u"?window:null);typeof s.focus=="function"&&s.focus();for(const y of u){await this.timing("type");const v=g=>{try{const T=(h==null?void 0:h.KeyboardEvent)||(typeof KeyboardEvent<"u"?KeyboardEvent:null);if(T)return new T(g,{key:y,bubbles:!0})}catch{}const b=(h==null?void 0:h.CustomEvent)||(h==null?void 0:h.Event)||CustomEvent;return new b(g,{bubbles:!0,cancelable:!0})},m=(g,b)=>{try{const w=(h==null?void 0:h.InputEvent)||(typeof InputEvent<"u"?InputEvent:null);if(w)return new w(g,b)}catch{}const T=(h==null?void 0:h.CustomEvent)||(h==null?void 0:h.Event)||CustomEvent;return new T(g,{bubbles:!0,cancelable:!0})};e.dispatchEvent(v("keydown")),e.dispatchEvent(v("keypress")),"value"in d&&(d.value=(d.value||"")+y),e.dispatchEvent(m("input",{data:y,inputType:"insertText",bubbles:!0})),e.dispatchEvent(v("keyup"))}const p=(h==null?void 0:h.Event)||Event;e.dispatchEvent(new p("change",{bubbles:!0}));break}case"clear":{const u=e,d=((i=e.ownerDocument)==null?void 0:i.defaultView)||(typeof window<"u"?window:null);if("value"in u){u.value="";const h=(y,v)=>{try{const g=(d==null?void 0:d.InputEvent)||(typeof InputEvent<"u"?InputEvent:null);if(g)return new g(y,v)}catch{}const m=(d==null?void 0:d.CustomEvent)||(d==null?void 0:d.Event)||CustomEvent;return new m(y,{bubbles:!0,cancelable:!0})};e.dispatchEvent(h("input",{inputType:"deleteContentBackward",bubbles:!0}));const p=(d==null?void 0:d.Event)||Event;e.dispatchEvent(new p("change",{bubbles:!0}))}break}case"press_key":{const u=t.key||"Enter",d=((r=e.ownerDocument)==null?void 0:r.defaultView)||(typeof window<"u"?window:null),h=p=>{try{const v=(d==null?void 0:d.KeyboardEvent)||(typeof KeyboardEvent<"u"?KeyboardEvent:null);if(v)return new v(p,{key:u,bubbles:!0})}catch{}const y=(d==null?void 0:d.CustomEvent)||(d==null?void 0:d.Event)||CustomEvent;return new y(p,{bubbles:!0,cancelable:!0})};e.dispatchEvent(h("keydown")),e.dispatchEvent(h("keypress")),e.dispatchEvent(h("keyup"));break}case"select_option":{const u=e;((o=u.tagName)==null?void 0:o.toLowerCase())==="select"&&t.optionValue&&(u.value=t.optionValue,e.dispatchEvent(new Event("change",{bubbles:!0})));break}case"scroll_into_view":{this.scrollIntoViewIfNeeded(e,!0);break}case"scroll":{const u=((a=t.scrollDelta)==null?void 0:a.x)||0,d=((c=t.scrollDelta)==null?void 0:c.y)||0;typeof e.scrollBy=="function"&&e.scrollBy(u,d);break}default:throw new Error(`Unsupported interaction action: ${t.action}`)}}scrollIntoViewIfNeeded(e,t=!1){if(typeof e.scrollIntoView=="function")try{e.scrollIntoView({behavior:"auto",block:"center",inline:"center"})}catch{e.scrollIntoView(t)}}dispatchMouseEvent(e,t,s={}){const n=e.getBoundingClientRect?e.getBoundingClientRect():{left:0,top:0,width:0,height:0},i=n.left+n.width/2,r=n.top+n.height/2,o=new MouseEvent(t,{bubbles:s.bubbles!==void 0?s.bubbles:!0,cancelable:s.cancelable!==void 0?s.cancelable:!0,clientX:i,clientY:r,button:s.button||0,buttons:s.button===2?2:1});e.dispatchEvent(o)}}class ae{static matches(e,t){if(!e||e.nodeType!==U.ELEMENT_NODE)return!1;const s=t.trim();return s?s.includes(",")?s.split(",").some(n=>this.matchesSimple(e,n.trim())):this.matchesCompound(e,s):!1}static querySelector(e,t,s){const n=this.querySelectorAll(e,t,s,1);return n.length>0?n[0]:null}static querySelectorAll(e,t,s,n=1/0){const i=[],r=s[t];if(!r)return i;const o=[...r.children||[]],a=new Set;for(;o.length>0&&i.length=n))break;u.children&&u.children.length>0&&o.push(...u.children)}}return i}static getElementById(e,t){for(const s of Object.values(t))if(s.nodeType===U.ELEMENT_NODE&&!s.isDetached&&s.attributes&&s.attributes.id===e&&this.isNodeConnected(s,t))return s;return null}static isNodeConnected(e,t){if(e.isDetached)return!1;let s=e;const n=new Set;for(;s&&s.parentId;){if(n.has(s.id))return!1;n.add(s.id);const i=t[s.parentId];if(!i||i.isDetached)return!1;s=i}return!0}static computeSelector(e,t){var r,o;if(!e)return"";if(e.nodeType!==U.ELEMENT_NODE)return e.tagName||`#node-${e.id}`;if((r=e.attributes)!=null&&r.id)return`#${e.attributes.id}`;const s=e.tagName||"div",n=(((o=e.attributes)==null?void 0:o.class)||"").split(/\s+/).filter(a=>a&&!a.startsWith("ng-")).slice(0,2),i=n.length>0?"."+n.join("."):"";if(e.parentId&&t[e.parentId]){const c=(t[e.parentId].children||[]).map(u=>t[u]).filter(u=>u&&u.nodeType===U.ELEMENT_NODE&&u.tagName===s);if(c.length>1){const u=c.findIndex(d=>d.id===e.id)+1;return`${s}${i}:nth-of-type(${u})`}}return`${s}${i}`}static matchesCompound(e,t){return this.matchesSimple(e,t)}static matchesSimple(e,t){var i,r,o,a,c,u,d;const s=((i=e.tagName)==null?void 0:i.toLowerCase())||"";if(t==="*")return!0;if(t.startsWith("#")){const h=t.substring(1);return((r=e.attributes)==null?void 0:r.id)===h}if(t.startsWith(".")){const h=t.substring(1);return(((o=e.attributes)==null?void 0:o.class)||"").split(/\s+/).includes(h)}if(t.startsWith("[")&&t.endsWith("]")){const h=t.substring(1,t.length-1);if(h.includes("=")){const[p,y]=h.split("="),v=y.replace(/^["']|["']$/g,"");return((a=e.attributes)==null?void 0:a[p.trim()])===v}return!!((c=e.attributes)!=null&&c[h.trim()])}const n=t.match(/^([a-zA-Z0-9_-]+)(.*)$/);if(n){const h=n[1].toLowerCase(),p=n[2];if(h!==s&&h!=="*")return!1;if(!p)return!0;if(p.startsWith("#"))return((u=e.attributes)==null?void 0:u.id)===p.substring(1);if(p.startsWith("."))return(((d=e.attributes)==null?void 0:d.class)||"").split(/\s+/).includes(p.substring(1));if(p.startsWith("["))return this.matchesSimple(e,p)}return!1}}class $e{static traceElement(e,t,s){var x,q;const n=[...t].sort((A,S)=>A.sequence-S.sequence);let i=e.nodeId,r="unknown",o=e.selector||"",a={},c=0,u=0,d="init";if(!i&&e.selector&&s){const A=ae.querySelector(e.selector,s.rootId,s.nodes);A&&(i=A.id,r=A.tagName||"element",a={...A.attributes||{}},o=e.selector)}if(!i&&e.selector){for(const A of n)if(A.type==="DOM_MUTATION_ADD"){const S=A.payload;if(S.node&&ae.matches(S.node,e.selector)){i=S.node.id,r=S.node.tagName||"element",a={...S.node.attributes||{}},c=A.timestamp,u=A.sequence,d=A.id;break}}}if(!i)return null;const h=[];let p=!0,y=null,v=null,m,g=0;if(s&&s.nodes[i]){const A=s.nodes[i];r=A.tagName||r,a={...A.attributes||{}},o||(o=ae.computeSelector(A,s.nodes)),h.push({timestamp:s.timestamp,sequence:s.sequence,wallClockTime:Date.now(),stage:"CREATED",eventId:s.snapshotId,eventType:"DOM_SNAPSHOT",description:`Element <${r}> existed in initial baseline snapshot [ID: ${i}]`,details:{initialParentId:A.parentId,attributes:a},nodeSnapshot:A})}const b=new Map;if(s)for(const[A,S]of Object.entries(s.nodes))b.set(Number(A),S.parentId??null);const T=(A,S)=>{let M=b.get(S);const O=new Set;for(;M&&!O.has(M);){if(M===A)return!0;O.add(M),M=b.get(M)}return!1};for(const A of n){const S=A.timestamp,M=A.sequence,O=A.wallClockTime;if(A.type==="DOM_MUTATION_ADD"){const _=A.payload;(x=_.node)!=null&&x.id&&b.set(_.node.id,_.parentId??null),((q=_.node)==null?void 0:q.id)===i&&(p=!0,r=_.node.tagName||r,c=S,u=M,d=A.id,a={..._.node.attributes||{}},h.push({timestamp:S,sequence:M,wallClockTime:O,stage:"ATTACHED_TO_DOM",eventId:A.id,eventType:A.type,description:`Element <${r}> added to DOM under parent ID ${_.parentId}`,details:{parentId:_.parentId,index:_.index},nodeSnapshot:_.node}))}if(A.type==="DOM_MUTATION_REMOVE"){const _=A.payload;_.nodeId===i?(p=!1,y=S,v=M,m=A.id,h.push({timestamp:S,sequence:M,wallClockTime:O,stage:"REMOVED_FROM_DOM",eventId:A.id,eventType:A.type,description:`Element <${r}> explicitly removed from parent ID ${_.parentId}`,details:{parentId:_.parentId,removedIndex:_.index}})):T(_.nodeId,i)&&(p=!1,y=S,v=M,m=A.id,h.push({timestamp:S,sequence:M,wallClockTime:O,stage:"PARENT_SUBTREE_REPLACED",eventId:A.id,eventType:A.type,description:`Ancestor element [ID: ${_.nodeId}] was removed, causing target element [ID: ${i}] to detach from DOM`,details:{removedAncestorId:_.nodeId,parentId:_.parentId}}))}if(A.type==="DOM_MUTATION_MOVE"){const _=A.payload;_.nodeId&&b.set(_.nodeId,_.newParentId??null),_.nodeId===i&&(g++,h.push({timestamp:S,sequence:M,wallClockTime:O,stage:"REPARENTED",eventId:A.id,eventType:A.type,description:`Element reparented from parent ${_.oldParentId} to ${_.newParentId}`,details:{oldParentId:_.oldParentId,newParentId:_.newParentId}}))}if(A.type==="DOM_MUTATION_ATTR"){const _=A.payload;if(_.nodeId===i){g++;const P=_.attributeName.toLowerCase();let H="ATTRIBUTE_MODIFIED";P==="class"&&(H="CLASS_MODIFIED"),P==="style"&&(H="STYLE_MODIFIED"),h.push({timestamp:S,sequence:M,wallClockTime:O,stage:H,eventId:A.id,eventType:A.type,description:`Attribute '${_.attributeName}' changed from '${_.oldValue??""}' to '${_.newValue??""}'`,details:{attributeName:_.attributeName,oldValue:_.oldValue,newValue:_.newValue}})}}if(A.type==="DOM_MUTATION_TEXT"){const _=A.payload;_.nodeId===i&&(g++,h.push({timestamp:S,sequence:M,wallClockTime:O,stage:"TEXT_MODIFIED",eventId:A.id,eventType:A.type,description:`Text content changed: "${_.oldText}" → "${_.newText}"`,details:{oldText:_.oldText,newText:_.newText}}))}}const w=y??c,E=500,C=n.filter(A=>(A.category==="ERROR"||A.category==="CONSOLE")&&Math.abs(A.timestamp-w)<=E),N=n.filter(A=>A.category==="NETWORK"&&Math.abs(A.timestamp-w)<=E),I=n.length>0?n[n.length-1].timestamp:c,R=Math.max(0,(y??I)-c);return{targetNodeId:i,tagName:r,selectorHint:o,initialAttributes:a,createdAt:c,createdSequence:u,createdEventId:d,removedAt:y,removedSequence:v,removedEventId:m,isCurrentlyAlive:p,lifespanMs:Math.round(R*100)/100,mutationCount:g,entries:h,correlatedDiagnostics:C,correlatedNetwork:N}}}class qe{static analyze(e,t,s){var R,x,q,A;const n=typeof e=="number"?{nodeId:e}:{selector:e},i=$e.traceElement(n,t,s);if(!i)return{targetQuery:e,found:!1,disappearanceMechanism:"UNKNOWN",likelyRootCause:"Target element could not be found in recording baseline or event stream",confidenceScore:0,detailedExplanation:`No element matching "${e}" was ever created, recorded in the initial DOM snapshot, or observed in mutation events.`,evidentiaryTrail:[],precedingEvents:[],followingEvents:[],correlatedErrors:[],correlatedNetworkCalls:[],alternativeHypotheses:[{hypothesis:"Element was injected into an unmonitored isolated iframe or ShadowRoot closed mode",likelihood:40,evidenceFor:["Element query yielded zero matches in monitored document"],evidenceAgainst:["Iframes/ShadowRoots were accessible in this session"]},{hypothesis:"Selector typo or timing mismatch",likelihood:60,evidenceFor:["Target selector did not match any recorded tag or class"],evidenceAgainst:[]}]};const r=[...t].sort((S,M)=>S.sequence-M.sequence),o=[],a=[];let c="UNKNOWN",u="Unknown disappearance mechanism",d=50,h="",p=i.removedAt??void 0;const y=i.entries.find(S=>S.stage==="REMOVED_FROM_DOM"),v=i.entries.find(S=>S.stage==="PARENT_SUBTREE_REPLACED"),m=i.entries.find(S=>S.stage==="CLASS_MODIFIED"&&/\b(hidden|hide|d-none|invisible|collapsed)\b/i.test(String(S.details.newValue||""))),g=i.entries.find(S=>S.stage==="STYLE_MODIFIED"&&/display\s*:\s*none|visibility\s*:\s*hidden|opacity\s*:\s*0/i.test(String(S.details.newValue||"")));y?(c="DIRECT_NODE_REMOVAL",p=y.timestamp,u=`Element [ID: ${i.targetNodeId}] <${i.tagName}> was directly removed from its parent [ID: ${y.details.parentId}] via DOM removeChild/replaceChild`,d=95,o.push({timestamp:y.timestamp,sequence:y.sequence,eventId:y.eventId,eventType:y.eventType,evidenceType:"DIRECT",description:`Direct DOM removal mutation: element detached from parent ID ${y.details.parentId}`,confidenceContribution:50})):v?(c="PARENT_SUBTREE_REPLACED",p=v.timestamp,u=`Host framework (e.g. React/Vue re-render) destroyed and replaced Ancestor container [ID: ${v.details.removedAncestorId}], causing injected element to be unmounted`,d=92,o.push({timestamp:v.timestamp,sequence:v.sequence,eventId:v.eventId,eventType:v.eventType,evidenceType:"DIRECT",description:`Ancestor container [ID: ${v.details.removedAncestorId}] was removed, wiping out all child subtrees`,confidenceContribution:50})):g?(c="STYLE_DISPLAY_NONE",p=g.timestamp,u=`Element was visually hidden by an inline style modification: "${g.details.newValue}"`,d=88,o.push({timestamp:g.timestamp,sequence:g.sequence,eventId:g.eventId,eventType:g.eventType,evidenceType:"DIRECT",description:`Inline style changed to "${g.details.newValue}"`,confidenceContribution:45})):m?(c="CLASS_TRIGGERED_HIDDEN",p=m.timestamp,u=`Element was visually hidden because its CSS class list was modified to include "${m.details.newValue}"`,d=85,o.push({timestamp:m.timestamp,sequence:m.sequence,eventId:m.eventId,eventType:m.eventType,evidenceType:"DIRECT",description:`Class list changed from "${m.details.oldValue??""}" to "${m.details.newValue??""}"`,confidenceContribution:45})):i.isCurrentlyAlive&&(c="UNKNOWN",u=`Element [ID: ${i.targetNodeId}] is currently alive and attached to the DOM tree (no unmount mutation detected)`,d=70,h="The element exists in the current DOM state. If it is not visible on screen, it may be clipped by viewport boundaries, z-index stacking context, or 0x0 pixel dimensions.");const b=p??i.createdAt,T=500,w=r.filter(S=>S.timestamp>=b-T&&S.timestampS.timestamp>b&&S.timestamp<=b+T),C=w.filter(S=>S.category==="ERROR");if(C.length>0){const S=C[0],M=((R=S.payload)==null?void 0:R.message)||"Unknown runtime error";o.push({timestamp:S.timestamp,sequence:S.sequence,eventId:S.id,eventType:S.type,evidenceType:"PRECEDING",description:`Runtime error occurred ${(b-S.timestamp).toFixed(1)}ms before disappearance: "${M}"`,confidenceContribution:20,rawEvent:S}),u+=` (preceded by runtime error: "${M}")`}const N=w.filter(S=>S.type==="NETWORK_RESPONSE_COMPLETE"||S.type==="NETWORK_REQUEST_FAILED");if(N.length>0){const S=N[0],M=((x=S.payload)==null?void 0:x.url)||"network request";o.push({timestamp:S.timestamp,sequence:S.sequence,eventId:S.id,eventType:S.type,evidenceType:"PRECEDING",description:`Network response completed ${(b-S.timestamp).toFixed(1)}ms before disappearance: ${M}`,confidenceContribution:15,rawEvent:S})}const I=w.filter(S=>S.category==="NAVIGATION");if(I.length>0){const S=I[0];o.push({timestamp:S.timestamp,sequence:S.sequence,eventId:S.id,eventType:S.type,evidenceType:"PRECEDING",description:`Navigation event (${(q=S.payload)==null?void 0:q.navigationType}) occurred ${(b-S.timestamp).toFixed(1)}ms before disappearance`,confidenceContribution:25,rawEvent:S}),u+=` following SPA navigation to "${(A=S.payload)==null?void 0:A.url}"`}return h||(h=[`Element <${i.tagName}> (Logical ID: ${i.targetNodeId}, selector: "${i.selectorHint}") was created at ${i.createdAt.toFixed(1)}ms.`,`It remained alive in the DOM for ${i.lifespanMs.toFixed(1)}ms and experienced ${i.mutationCount} mutations.`,`At timestamp ${b.toFixed(1)}ms, it disappeared via [${c}].`,`Diagnosis: ${u}.`].join(" ")),c==="PARENT_SUBTREE_REPLACED"?(a.push({hypothesis:"Direct cleanup called by extension code",likelihood:25,evidenceFor:["Element was unmounted shortly after creation"],evidenceAgainst:["Ancestor container mutation was recorded from host page context"]}),a.push({hypothesis:"Host single-page app route change destroyed component tree",likelihood:35,evidenceFor:I.length>0?["Preceding navigation event recorded"]:[],evidenceAgainst:I.length===0?["No navigation events occurred in temporal window"]:[]})):c==="DIRECT_NODE_REMOVAL"&&a.push({hypothesis:"Third-party script or ad-blocker removed the injected node",likelihood:30,evidenceFor:["Direct node removal occurred without ancestor replacement"],evidenceAgainst:["No ad-blocker signatures or extension error logs observed"]}),{targetQuery:e,targetNodeId:i.targetNodeId,found:!0,tagName:i.tagName,selectorHint:i.selectorHint,createdAt:i.createdAt,firstVisibleAt:i.createdAt,lastKnownGoodStateAt:Math.max(0,b-1),disappearedAt:p,lifespanMs:i.lifespanMs,disappearanceMechanism:c,likelyRootCause:u,confidenceScore:Math.min(99,d),detailedExplanation:h,evidentiaryTrail:o,precedingEvents:w,followingEvents:E,correlatedErrors:C,correlatedNetworkCalls:N,alternativeHypotheses:a}}}class Pe{constructor(e){f(this,"activeObservation",null);f(this,"registry");f(this,"sequenceCounter");this.registry=e,this.sequenceCounter=new oe}isObserving(){return this.activeObservation!==null}startObservation(e,t=document){this.activeObservation&&this.stopObservation(t);const s=`obs_${Date.now()}_${Math.random().toString(36).slice(2,6)}`,n=Date.now(),i=L.inspectElement(e,this.registry),r=i.bestSelector,o=[],a=this.registry?this.registry.getOrCreateId(e,0):100;o.push({id:`evt_init_${s}`,sessionId:s,timestamp:0,sequence:1,wallClockTime:n,type:"DOM_MUTATION_ADD",category:"DOM",source:"BROWSER_RUNTIME",targetNodeId:a,targetSelector:r,payload:{node:{id:a,nodeType:1,tagName:i.tag,attributes:i.attributes,textContent:i.text,children:[],parentId:null},parentId:null,index:0}});const c=new MutationObserver(u=>{const d=Date.now()-n;for(const h of u)if(h.type==="childList"){for(let p=0;p0&&(m=qe.analyze(n,a)),{observationId:t,targetSelector:n,targetNodeId:((g=r.forensics)==null?void 0:g.logicalNodeId)||void 0,startTime:i,endTime:u,durationMs:d,initialState:r,finalState:p,disappeared:y,disappearanceReason:v,mutations:a.filter(b=>b.category==="DOM"),diagnostics:a.filter(b=>b.category==="ERROR"||b.category==="CONSOLE"),networkEvents:a.filter(b=>b.category==="NETWORK"),screenshots:c,correlationReport:m}}}class Ue{constructor(e={}){f(this,"isExplicitModeActive",!1);f(this,"isGlobalShortcutActive",!1);f(this,"highlighterEl",null);f(this,"badgeEl",null);f(this,"lastSelectedElement",null);f(this,"options",{});f(this,"onMouseMoveBound");f(this,"onClickBound");f(this,"onKeyDownBound");f(this,"onGlobalClickBound");this.options=e,this.onMouseMoveBound=this.handleMouseMove.bind(this),this.onClickBound=this.handleClick.bind(this),this.onKeyDownBound=this.handleKeyDown.bind(this),this.onGlobalClickBound=this.handleGlobalCtrlShiftClick.bind(this),this.initGlobalShortcutListener()}initGlobalShortcutListener(){typeof window>"u"||this.isGlobalShortcutActive||(window.addEventListener("click",this.onGlobalClickBound,!0),this.isGlobalShortcutActive=!0)}startPicker(e){typeof document>"u"||(e&&(this.options={...this.options,...e}),!this.isExplicitModeActive&&(this.isExplicitModeActive=!0,this.ensureHighlighter(),document.body&&(document.body.style.cursor="crosshair"),window.addEventListener("mousemove",this.onMouseMoveBound,!0),window.addEventListener("click",this.onClickBound,!0),window.addEventListener("keydown",this.onKeyDownBound,!0)))}stopPicker(){this.isExplicitModeActive&&(this.isExplicitModeActive=!1,typeof document<"u"&&document.body&&(document.body.style.cursor="default"),this.removeHighlighter(),typeof window<"u"&&(window.removeEventListener("mousemove",this.onMouseMoveBound,!0),window.removeEventListener("click",this.onClickBound,!0),window.removeEventListener("keydown",this.onKeyDownBound,!0)))}getLastSelectedElement(){return this.lastSelectedElement}setSelectedElement(e){let t;return"tag"in e&&"bestSelector"in e&&typeof e.getAttribute!="function"?t=e:(t=L.inspectElement(e,this.options.nodeRegistry),this.flashSelection(e)),this.lastSelectedElement=t,this.options.onSelected&&this.options.onSelected(t),t}handleGlobalCtrlShiftClick(e){if(!e.ctrlKey||!e.shiftKey)return;const t=e.target;if(!t||this.isExtensionOwned(t))return;e.preventDefault(),e.stopPropagation(),e.stopImmediatePropagation();const s=this.setSelectedElement(t);this.notifyExtension(s)}handleMouseMove(e){if(!this.isExplicitModeActive)return;const t=e.target;if(!t||this.isExtensionOwned(t)){this.hideHighlighter();return}this.updateHighlighter(t)}handleClick(e){if(!this.isExplicitModeActive)return;const t=e.target;if(!t||this.isExtensionOwned(t))return;e.preventDefault(),e.stopPropagation(),e.stopImmediatePropagation();const s=this.setSelectedElement(t);this.notifyExtension(s),this.stopPicker()}handleKeyDown(e){e.key==="Escape"&&this.isExplicitModeActive&&(e.preventDefault(),this.stopPicker(),this.options.onCanceled&&this.options.onCanceled())}isExtensionOwned(e){return!!(e.id==="forensic-recorder-floating-host"||e.id==="forensic-inspect-highlighter"||e.closest("#forensic-recorder-floating-host")||e.closest("#forensic-inspect-highlighter")||e.hasAttribute("data-forensic-internal")||e.closest("[data-forensic-internal]"))}ensureHighlighter(){if(typeof document>"u"||this.highlighterEl)return;const e=this.options.highlightColor||"#0ea5e9",t=document.createElement("div");t.id="forensic-inspect-highlighter",t.setAttribute("data-forensic-internal","true"),t.style.position="fixed",t.style.pointerEvents="none",t.style.zIndex="2147483640",t.style.border=`2px solid ${e}`,t.style.background="rgba(14, 165, 233, 0.18)",t.style.borderRadius="3px",t.style.boxShadow=`0 0 12px ${e}88`,t.style.transition="all 0.05s ease-out",t.style.display="none";const s=document.createElement("div");s.setAttribute("data-forensic-internal","true"),s.style.position="absolute",s.style.bottom="100%",s.style.left="0",s.style.transform="translateY(-4px)",s.style.background="#0f172a",s.style.color="#38bdf8",s.style.fontSize="11px",s.style.fontFamily="monospace",s.style.fontWeight="bold",s.style.padding="2px 6px",s.style.borderRadius="3px",s.style.boxShadow="0 2px 6px rgba(0,0,0,0.5)",s.style.whiteSpace="nowrap",s.style.pointerEvents="none",t.appendChild(s),document.body.appendChild(t),this.highlighterEl=t,this.badgeEl=s}updateHighlighter(e){if(this.ensureHighlighter(),!this.highlighterEl||!this.badgeEl)return;const t=e.getBoundingClientRect();this.highlighterEl.style.display="block",this.highlighterEl.style.left=`${t.left}px`,this.highlighterEl.style.top=`${t.top}px`,this.highlighterEl.style.width=`${Math.max(1,t.width)}px`,this.highlighterEl.style.height=`${Math.max(1,t.height)}px`;const s=e.tagName.toLowerCase(),n=e.id?`#${e.id}`:"",i=e.className&&typeof e.className=="string"?"."+e.className.split(/\s+/)[0]:"",r=`${Math.round(t.width)}×${Math.round(t.height)}`;this.badgeEl.textContent=`<${s}${n}${i}> [${r}]`}hideHighlighter(){this.highlighterEl&&(this.highlighterEl.style.display="none")}removeHighlighter(){this.highlighterEl&&this.highlighterEl.parentElement&&this.highlighterEl.remove(),this.highlighterEl=null,this.badgeEl=null}flashSelection(e){if(typeof document>"u"||!e.getBoundingClientRect)return;const t=e.getBoundingClientRect(),s=document.createElement("div");s.setAttribute("data-forensic-internal","true"),s.style.position="fixed",s.style.left=`${t.left}px`,s.style.top=`${t.top}px`,s.style.width=`${Math.max(1,t.width)}px`,s.style.height=`${Math.max(1,t.height)}px`,s.style.border="2px solid #22c55e",s.style.background="rgba(34, 197, 94, 0.25)",s.style.zIndex="2147483645",s.style.pointerEvents="none",s.style.transition="opacity 0.6s ease-out",document.body.appendChild(s),setTimeout(()=>{s.style.opacity="0",setTimeout(()=>s.remove(),600)},400)}notifyExtension(e){var t;try{typeof chrome<"u"&&((t=chrome.runtime)!=null&&t.sendMessage)&&chrome.runtime.sendMessage({type:"ELEMENT_SELECTED",elementInfo:e,timestamp:Date.now()})}catch{}}destroy(){this.stopPicker(),typeof window<"u"&&window.removeEventListener("click",this.onGlobalClickBound,!0),this.isGlobalShortcutActive=!1}}class fe{static getCrcTable(){if(this.crcTable)return this.crcTable;const e=new Uint32Array(256);for(let t=0;t<256;t++){let s=t;for(let n=0;n<8;n++)s=s&1?3988292384^s>>>1:s>>>1;e[t]=s>>>0}return this.crcTable=e,e}static crc32(e,t=0,s=e.length){const n=this.getCrcTable();let i=4294967295;for(let r=t;r>>8^n[(i^e[r])&255];return(i^4294967295)>>>0}static adler32(e){let t=1,s=0;for(let n=0;n>>0}static createPNG(e){const t=Math.max(1,Math.min(1920,Math.floor(e.width))),s=Math.max(1,Math.min(1080,Math.floor(e.height))),n=e.backgroundColor||[15,23,42,255],i=e.headerColor||[56,189,248,255],r=e.borderColor||[99,102,241,255],o=1+t*4,a=new Uint8Array(o*s),c=Math.min(30,Math.floor(s*.2));for(let g=0;g=e.length,h=new Uint8Array(5+u);h[0]=d?1:0,h[1]=u&255,h[2]=u>>>8&255;const p=~u&65535;h[3]=p&255,h[4]=p>>>8&255,h.set(e.subarray(n,n+u),5),t.push(h),n+=u}const i=t.reduce((c,u)=>c+u.length,0)+2+4,r=new Uint8Array(i);let o=0;r[o++]=120,r[o++]=1;for(const c of t)r.set(c,o),o+=c.length;const a=this.adler32(e);return r[o++]=a>>>24&255,r[o++]=a>>>16&255,r[o++]=a>>>8&255,r[o++]=a&255,r}static writeChunk(e,t,s,n){const i=n.length,r=new DataView(e.buffer,e.byteOffset,e.byteLength);r.setUint32(t,i,!1),t+=4;const o=new Uint8Array(4+i);for(let c=0;c<4;c++){const u=s.charCodeAt(c);e[t+c]=u,o[c]=u}t+=4,i>0&&(e.set(n,t),o.set(n,4),t+=i);const a=this.crc32(o);return r.setUint32(t,a,!1),t+=4,t}}f(fe,"crcTable",null);const ne=500;class He{constructor(e,t){f(this,"history",[]);f(this,"undoStack",[]);f(this,"redoStack",[]);f(this,"counter",0);f(this,"transaction",null);this.doc=e,this.registry=t}mutate(e){var d;const t=`mut_${Date.now().toString(36)}_${++this.counter}`,s=Date.now();let n;try{n=this.resolveTarget(e.target)}catch(h){return this.failure(t,e,null,h.message,Date.now()-s)}const i=this.snapshotState(n);let r=null,o=null,a,c=!0;try{const h=this.applyOperation(t,e,n);h&&(this.transaction?this.transaction.undoRecords.push(h):(this.undoStack.push(h),this.redoStack=[]));const y=(n.isConnected!==void 0?n.isConnected:this.doc.contains(n))?n:this.doc.querySelector(i.selector)||n;r=this.snapshotState(y),o=this.quickDiff(i,r,n)}catch(h){c=!1,a=h.message,r=null}const u={mutationId:t,operation:e.operation,success:c,before:i,after:r,diff:o,affectedSelector:c?i.selector:null,durationMs:Date.now()-s,error:a,undoable:c&&(this.transaction?this.transaction.undoRecords.length>0:this.undoStack.length>0)};return this.transaction&&this.transaction.steps.push({stepId:`step_${this.transaction.steps.length+1}`,mutation:u}),this.pushHistory({mutationId:t,transactionId:(d=this.transaction)==null?void 0:d.id,timestamp:Date.now(),operation:e.operation,targetSelector:i.selector,success:c,summary:`${e.operation} on ${i.selector}${o?` (+${o.added}/-${o.removed}/~${o.changed})`:""}`,undoApplied:!1,redoApplied:!1}),u}beginTransaction(){if(this.transaction)throw new Error(`TRANSACTION_ALREADY_OPEN: ${this.transaction.id} — commit or rollback first.`);return this.transaction={id:`tx_${Date.now().toString(36)}_${++this.counter}`,steps:[],undoRecords:[]},this.transaction.id}commitTransaction(e){if(!this.transaction)throw new Error("NO_OPEN_TRANSACTION: begin a transaction before committing.");const t=this.transaction,s=Date.now();let n=!0,i;if(e)try{n=e({id:t.id,steps:t.steps})!==!1,n||(i="VERIFY_FAILED: caller verification rejected the transaction state.")}catch(o){n=!1,i=`VERIFY_ERROR: ${o.message}`}if(!n)return this.rollbackInternal(t,i||"VERIFY_FAILED",s);this.undoStack.push(...t.undoRecords),this.undoStack.length>ne&&this.undoStack.splice(0,this.undoStack.length-ne),this.redoStack=[];const r=this.summaryOf(t);return this.transaction=null,{transactionId:t.id,committed:!0,rolledBack:!1,steps:t.steps,durationMs:Date.now()-s,finalStateSummary:r}}rollbackTransaction(e){if(!this.transaction)throw new Error("NO_OPEN_TRANSACTION: begin a transaction before rolling back.");const t=this.transaction;return this.rollbackInternal(t,e||"ROLLBACK_REQUESTED",Date.now())}rollbackInternal(e,t,s){for(const i of[...e.undoRecords].reverse())try{this.applyUndo(i)}catch{}const n=this.summaryOf(e);return this.transaction=null,{transactionId:e.id,committed:!1,rolledBack:!0,steps:e.steps,error:t,durationMs:Date.now()-s,finalStateSummary:n}}undo(){const e=this.transaction?this.transaction.undoRecords:this.undoStack,t=e.pop();if(!t)return{success:!1,message:"Nothing to undo — the mutation history is empty."};try{this.applyUndo(t)}catch(s){return e.push(t),{success:!1,mutationId:t.mutationId,message:`UNDO_FAILED: ${s.message}`}}return this.redoStack.push(t),this.markHistory(t.mutationId,"undo"),{success:!0,mutationId:t.mutationId,message:`Undid ${t.operation} on ${t.targetSelector}.`}}redo(){const e=this.redoStack.pop();if(!e)return{success:!1,message:"Nothing to redo — no undone mutation is pending."};try{const t=this.resolveTarget({selector:e.targetSelector}),s={operation:e.operation,target:{selector:e.targetSelector}};return this.reapplyRecord(e,t,s)?((this.transaction?this.transaction.undoRecords:this.undoStack).push(e),this.markHistory(e.mutationId,"redo"),{success:!0,mutationId:e.mutationId,message:`Redid ${e.operation} on ${e.targetSelector}.`}):(this.redoStack.push(e),{success:!1,mutationId:e.mutationId,message:"REDO_FAILED: target state diverged — cannot safely reapply."})}catch(t){return this.redoStack.push(e),{success:!1,mutationId:e.mutationId,message:`REDO_FAILED: ${t.message}`}}}getHistory(e=100){return this.history.slice(-e)}getUndoDepth(){return this.transaction?this.transaction.undoRecords.length:this.undoStack.length}getRedoDepth(){return this.redoStack.length}getOpenTransactionId(){var e;return((e=this.transaction)==null?void 0:e.id)||null}preview(e){var t;try{const s=this.resolveTarget(e.target),n=[];let i=1;(e.operation==="set_inner_html"||e.operation==="set_outer_html")&&(n.push("HTML replacement can destroy descendant node identity — captured regions targeting children may become stale."),i=s.querySelectorAll("*").length+1),(e.operation==="remove_element"||e.operation==="unwrap_element")&&(n.push("Removal is destructive; the undo record preserves the full serialized subtree."),i=s.querySelectorAll("*").length+1),e.operation==="move_element"&&!e.parent&&n.push("No parent target supplied — move requires payload.parent."),e.operation==="wrap_element"&&!e.newElementHtml&&n.push("No wrapper HTML supplied — a neutral
wrapper will be generated.");const r=Be(e,s);return{valid:n.filter(o=>o.includes("requires")||o.includes("No parent")).length===0,operation:e.operation,target:{selector:this.snapshotState(s).selector,tag:s.tagName.toLowerCase()},expectedChange:r,affectedNodes:i,warnings:n}}catch(s){return{valid:!1,operation:e.operation,target:{selector:String(((t=e.target)==null?void 0:t.selector)||""),tag:""},expectedChange:"—",affectedNodes:0,warnings:[],error:s.message}}}applyOperation(e,t,s){var r;const n=this.snapshotState(s).selector,i=t.operation;switch(i){case"set_attribute":{if(!t.attribute)throw new Error("ATTRIBUTE_REQUIRED: payload.attribute is missing.");const o=s.getAttribute(t.attribute);return s.setAttribute(t.attribute,t.value??""),this.undoFor(e,i,n,{kind:o===null?"remove-attribute":"restore-attribute",attribute:t.attribute,value:o})}case"remove_attribute":{if(!t.attribute)throw new Error("ATTRIBUTE_REQUIRED: payload.attribute is missing.");const o=s.getAttribute(t.attribute);if(o===null)throw new Error(`ATTRIBUTE_NOT_PRESENT: "${t.attribute}" is not set on ${n}.`);return s.removeAttribute(t.attribute),this.undoFor(e,i,n,{kind:"restore-attribute",attribute:t.attribute,value:o})}case"set_text":{const o=s.textContent||"";return s.textContent=t.text??"",this.undoFor(e,i,n,{kind:"restore-text",text:o})}case"replace_text":{if(!t.text||!t.replacement)throw new Error("TEXT_PATTERNS_REQUIRED: payload.text (search) and payload.replacement are required.");const o=s.textContent||"";return s.textContent=o.split(t.text).join(t.replacement),this.undoFor(e,i,n,{kind:"restore-text",text:o})}case"set_inner_html":{const o=s.innerHTML;return s.innerHTML=t.html??"",this.undoFor(e,i,n,{kind:"restore-outer-html",outerHtml:s.outerHTML.replace(t.html??"",o)||void 0,text:o,attribute:"__inner"})}case"set_outer_html":{const o=s.outerHTML,a=s.parentElement;if(!a)throw new Error("ORPHAN_ELEMENT: element has no parent — cannot replace outer HTML.");const c=this.doc.createComment(`mcpdom_undo_${e}`);s.replaceWith(c);const u=this.doc.createElement("template");u.innerHTML=t.html??"";const d=u.content.firstElementChild;return d?c.replaceWith(d):c.replaceWith(this.doc.createTextNode(t.html??"")),this.undoFor(e,i,n,{kind:"reinsert-node",outerHtml:o,parentSelector:this.snapshotState(a).selector,nextSiblingSelector:this.siblingSelector(d||s)})}case"add_class":{const o=Array.from(s.classList);for(const a of t.classes||[])s.classList.add(a);return this.undoFor(e,i,n,{kind:"restore-classes",classes:o})}case"remove_class":{const o=Array.from(s.classList);for(const a of t.classes||[])s.classList.remove(a);return this.undoFor(e,i,n,{kind:"restore-classes",classes:o})}case"replace_class":{const o=Array.from(s.classList);for(const a of t.classes||[])s.classList.remove(a);return t.value&&s.classList.add(t.value),this.undoFor(e,i,n,{kind:"restore-classes",classes:o})}case"set_style":{const o=this.doc.defaultView;if(!(o!=null&&o.getComputedStyle))throw new Error("STYLE_UNAVAILABLE: computed style API is unavailable in this context.");const a={};for(const c of Object.keys(t.style||{}))a[c]=o.getComputedStyle(s).getPropertyValue(c),s.style.setProperty(c,t.style[c]);return this.undoFor(e,i,n,{kind:"restore-style",style:a})}case"remove_style":{const o={};for(const a of t.classes||[])o[a]=s.style.getPropertyValue(a),s.style.removeProperty(a);return this.undoFor(e,i,n,{kind:"restore-style",style:o})}case"add_element":{const o=t.parent?this.resolveTarget(t.parent):s,a=this.doc.createElement("template");a.innerHTML=t.newElementHtml??"
";const c=a.content.firstElementChild;if(!c)throw new Error("INVALID_HTML: payload.newElementHtml does not produce an element.");switch(t.position||"append"){case"before":s.before(c);break;case"after":s.after(c);break;case"prepend":o.prepend(c);break;default:o.appendChild(c)}return this.undoFor(e,i,n,{kind:"remove-node",attribute:this.snapshotState(c).selector})}case"remove_element":{const o=s.outerHTML,a=s.parentElement,c=s.nextElementSibling;return s.remove(),this.undoFor(e,i,n,{kind:"reinsert-node",outerHtml:o,parentSelector:a?this.snapshotState(a).selector:void 0,nextSiblingSelector:c?this.snapshotState(c).selector:null})}case"replace_element":{const o=s.outerHTML,a=s.parentElement,c=this.doc.createElement("template");c.innerHTML=t.newElementHtml??"
";const u=c.content.firstElementChild;if(!u)throw new Error("INVALID_HTML: payload.newElementHtml does not produce an element.");const d=s.nextElementSibling;return s.replaceWith(u),this.undoFor(e,i,n,{kind:"reinsert-node",outerHtml:o,parentSelector:a?this.snapshotState(a).selector:void 0,nextSiblingSelector:d?this.snapshotState(d).selector:null})}case"move_element":{if(!t.parent)throw new Error("PARENT_REQUIRED: payload.parent is required for move_element.");const o=this.resolveTarget(t.parent),a=s.outerHTML,c=s.parentElement,u=s.nextElementSibling,d=t.position==="before"||t.position==="prepend"?o.firstElementChild:null;return o[t.position==="prepend"?"prepend":"appendChild"](s),this.undoFor(e,i,n,{kind:"restore-position",parentSelector:c?this.snapshotState(c).selector:void 0,nextSiblingSelector:u?this.snapshotState(u).selector:d?this.snapshotState(d).selector:null,outerHtml:a})}case"wrap_element":{const o=this.doc.createElement("template");o.innerHTML=t.newElementHtml||'
';const a=o.content.firstElementChild;if(!a)throw new Error("INVALID_HTML: wrapper template produced no element.");const c=s.parentElement,u=s.nextElementSibling;return s.replaceWith(a),a.appendChild(s),this.undoFor(e,i,n,{kind:"restore-position",parentSelector:c?this.snapshotState(c).selector:void 0,nextSiblingSelector:u?this.snapshotState(u).selector:null})}case"unwrap_element":{const o=s.outerHTML,a=s.parentElement;if(!a)throw new Error("ORPHAN_ELEMENT: cannot unwrap a root-level element.");const c=s.nextElementSibling,u=Array.from(s.children);for(const d of u)a.insertBefore(d,s);return s.remove(),this.undoFor(e,i,n,{kind:"reinsert-node",outerHtml:o,parentSelector:this.snapshotState(a).selector,nextSiblingSelector:c?this.snapshotState(c).selector:null})}case"clone_subtree":{const o=t.parent?this.resolveTarget(t.parent):s.parentElement||s,a=s.cloneNode(!0);if(t.copyAttributes!==!1)for(const c of Array.from(a.attributes))c.name==="id"&&a.removeAttribute("id");return(r=o.appendChild)==null||r.call(o,a),this.undoFor(e,i,n,{kind:"remove-node",attribute:this.snapshotState(a).selector})}default:throw new Error(`UNKNOWN_OPERATION: ${i} is not a supported DOM mutation.`)}}applyUndo(e){const t=e.inverse;switch(t.kind){case"restore-outer-html":{const s=this.resolveTarget({selector:e.targetSelector});if(t.outerHtml!==void 0){const n=this.doc.createElement("template");n.innerHTML=t.outerHtml;const i=n.content.firstElementChild;i&&s.replaceWith(i)}else t.attribute==="__inner"&&(s.innerHTML=t.text||"");break}case"reinsert-node":{const s=t.parentSelector?this.resolveTarget({selector:t.parentSelector}):this.doc.body,n=this.doc.createElement("template");n.innerHTML=t.outerHtml||"";const i=n.content.firstElementChild;if(!i)throw new Error("UNDO_CORRUPT: serialized subtree could not be restored.");const r=t.nextSiblingSelector?this.safeResolve(t.nextSiblingSelector):null;s.insertBefore(i,r);break}case"remove-node":{const s=this.safeResolve(t.attribute||e.targetSelector);s&&s.remove();break}case"restore-attribute":{this.resolveTarget({selector:e.targetSelector}).setAttribute(t.attribute,t.value??"");break}case"remove-attribute":{this.resolveTarget({selector:e.targetSelector}).removeAttribute(t.attribute);break}case"restore-text":{const s=this.resolveTarget({selector:e.targetSelector});s.textContent=t.text||"";break}case"restore-classes":{const s=this.resolveTarget({selector:e.targetSelector});s.removeAttribute("class");for(const n of t.classes||[])s.classList.add(n);break}case"restore-style":{const s=this.resolveTarget({selector:e.targetSelector});s.style.removeProperty("all");for(const[n,i]of Object.entries(t.style||{}))s.style.setProperty(n,i);break}case"restore-position":{const s=this.doc.createElement("template");s.innerHTML=t.outerHtml||"";const n=s.content.firstElementChild;if(!n)throw new Error("UNDO_CORRUPT: serialized subtree could not be restored.");const i=this.safeResolve(e.targetSelector);i&&i.remove();const r=t.parentSelector?this.safeResolve(t.parentSelector):this.doc.body,o=t.nextSiblingSelector?this.safeResolve(t.nextSiblingSelector):null;(r||this.doc.body).insertBefore(n,o);break}}}reapplyRecord(e,t,s){var i;const n=e.inverse;switch(e.operation){case"set_attribute":return(n.kind==="restore-attribute"||n.kind==="remove-attribute")&&s.value!==void 0?(t.setAttribute(s.attribute||n.attribute||"",s.value),!0):!1;case"add_class":{for(const r of s.classes||[])t.classList.add(r);return(((i=s.classes)==null?void 0:i.length)||0)>0}case"remove_class":{for(const r of s.classes||n.classes||[])t.classList.remove(r);return!0}case"set_text":return s.text!==void 0?(t.textContent=s.text,!0):!1;case"set_inner_html":return s.html!==void 0?(t.innerHTML=s.html,!0):!1;default:return!1}}resolveTarget(e){if(!e)throw new Error("TARGET_REQUIRED: mutation requires a target.");if(typeof e=="string"&&(e={selector:e}),e.selector){try{const t=this.doc.querySelectorAll(e.selector);if(t.length===1)return t[0];if(t.length>1)return Array.from(t).find(n=>{try{return L.inspectElement(n).visibility.isVisible}catch{return!1}})||t[0]}catch(t){throw new Error(`TARGET_INVALID: ${t.message}`)}throw new Error(`TARGET_NOT_FOUND: selector "${e.selector}" matches no element.`)}if(e.xpath){try{const s=this.doc.evaluate(e.xpath,this.doc,null,9,null).singleNodeValue;if(s)return s}catch(t){throw new Error(`TARGET_INVALID_XPATH: ${t.message}`)}throw new Error("TARGET_NOT_FOUND: xpath matches no element.")}if(typeof e.nodeId=="number"&&this.registry){const t=this.registry.getNode(e.nodeId);if(t&&t.nodeType===1&&this.doc.contains(t))return t;throw new Error("TARGET_STALE: logical node id no longer resolves to an attached element.")}throw new Error("TARGET_INVALID: target has neither selector, xpath nor nodeId.")}safeResolve(e){try{return this.doc.querySelector(e)}catch{return null}}snapshotState(e){const t=L.inspectElement(e,this.registry),s=e.outerHTML.length>2e4?e.outerHTML.slice(0,2e4)+"…[truncated]":e.outerHTML;return{selector:t.bestSelector,outerHtml:s,attributes:this.attrsOf(e)}}attrsOf(e){const t={};for(const s of Array.from(e.attributes))t[s.name]=s.value.length>300?s.value.slice(0,300)+"…":s.value;return t}quickDiff(e,t,s){if(!t)return null;let n=0,i=0,r=0;const o=new Set(Object.keys(e.attributes)),a=new Set(Object.keys(t.attributes||{}));for(const u of o)a.has(u)||i++;for(const u of a)o.has(u)?e.attributes[u]!==t.attributes[u]&&r++:n++;e.outerHtml!==t.outerHtml&&n+i+r===0&&r++;const c=s.querySelectorAll?s.querySelectorAll("*").length:0;return{added:n,removed:i,changed:r,summary:`attributes +${n}/-${i}/~${r}; subtree nodes: ${c}`}}undoFor(e,t,s,n){return{mutationId:e,operation:t,targetSelector:s,inverse:n}}siblingSelector(e){try{return this.snapshotState(e).selector}catch{return null}}pushHistory(e){this.history.push(e),this.history.length>ne&&this.history.splice(0,this.history.length-ne)}markHistory(e,t){for(let s=this.history.length-1;s>=0;s--)if(this.history[s].mutationId===e){t==="undo"?this.history[s].undoApplied=!0:this.history[s].redoApplied=!0;return}}summaryOf(e){var n;const t=((n=this.doc.documentElement)==null?void 0:n.outerHTML.length)||0,s=e.steps.filter(i=>i.mutation.success).length;return{domLength:t,diffSummary:`${s}/${e.steps.length} mutations applied`}}failure(e,t,s,n,i){var r;return{mutationId:e,operation:t.operation,success:!1,before:s||{selector:String(((r=t.target)==null?void 0:r.selector)||"?"),outerHtml:"",attributes:{}},after:null,diff:null,affectedSelector:null,durationMs:i,error:n,undoable:!1}}}function Be(l,e){switch(l.operation){case"set_attribute":return`attribute "${l.attribute}" will be set to "${(l.value??"").slice(0,40)}"`;case"remove_attribute":return`attribute "${l.attribute}" will be removed`;case"set_text":return`text content will be replaced (${(l.text||"").length} chars)`;case"replace_text":return`every occurrence of "${l.text}" will become "${l.replacement}"`;case"set_inner_html":return`inner HTML will be replaced (${(l.html||"").length} chars)`;case"set_outer_html":return"element (and subtree) will be replaced with provided HTML";case"add_class":return`classes ${(l.classes||[]).join(", ")} will be added`;case"remove_class":return`classes ${(l.classes||[]).join(", ")} will be removed`;case"replace_class":return`classes ${(l.classes||[]).join(", ")} will be replaced with "${l.value}"`;case"set_style":return`inline styles ${Object.keys(l.style||{}).join(", ")} will be set`;case"remove_style":return`inline styles ${(l.classes||[]).join(", ")} will be removed`;case"add_element":return`a new element will be inserted ${l.position||"append"} the target`;case"remove_element":return"the element and its subtree will be removed";case"replace_element":return"the element will be replaced with new HTML";case"move_element":return"the element will be moved into the specified parent";case"wrap_element":return"the element will be wrapped in a new container";case"unwrap_element":return"children will be lifted out and the wrapper removed";case"clone_subtree":return"a deep clone of the subtree will be appended";default:return"unknown operation"}}class Fe{constructor(){f(this,"executionCounter",0)}async execute(e,t,s={}){const n=Math.min(Math.max(s.timeoutMs??5e3,100),3e4),i=`js_${Date.now().toString(36)}_${++this.executionCounter}`,r=e.defaultView;if(!r)return this.result(i,"BLOCKED_BY_CONTEXT",0,t,[],{name:"NoWindow",message:"The document has no associated window — execution context unavailable."});const o=e.documentElement?e.documentElement.outerHTML.length:0,a=[],c=this.hookConsole(r,a);let u="EXECUTED_SUCCESSFULLY",d,h,p=o,y=!1;const v=Date.now();try{const b=this.buildRunner(r,t),T=new Promise((w,E)=>{var N;const C=setTimeout(()=>{y=!0,E(new Error(`Script timed out after ${n}ms`))},n);(N=C==null?void 0:C.unref)==null||N.call(C)});d=await Promise.race([b,T])}catch(b){y?u="TIMED_OUT":u="EXECUTED_WITH_ERROR",h={name:(b==null?void 0:b.name)||"Error",message:(b==null?void 0:b.message)||String(b),stack:b!=null&&b.stack?String(b.stack).slice(0,2e3):void 0}}const m=Date.now()-v;p=e.documentElement?e.documentElement.outerHTML.length:0,c();const g=this.serialize(d);return u==="EXECUTED_SUCCESSFULLY"&&g.serializationFailed&&(u="SERIALIZATION_FAILED",h={name:"SerializationError",message:g.message||"Result could not be serialized."}),{status:u,executionId:i,durationMs:m,result:u==="EXECUTED_SUCCESSFULLY"?g.text:void 0,error:h,consoleOutput:a.slice(0,100),domChanged:o!==p,domLengthBefore:o,domLengthAfter:p,world:s.world||"ISOLATED",timeoutMs:n,codePreview:t.length>300?t.slice(0,300)+"…":t}}buildRunner(e,t){const s=`(async function() { +`))}catch{}const c={id:this.sequenceCounter.generateEventId("con",i),sessionId:this.sessionId,timestamp:s,sequence:i,wallClockTime:n,type:`RUNTIME_CONSOLE_${e.toUpperCase()}`,category:e==="error"?"ERROR":"CONSOLE",source:"PAGE",payload:{level:e,args:r,formattedMessage:o,stackTrace:a}};this.callback(c)}instrumentGlobalErrors(){if(typeof window>"u")return;const e=t=>{var o,a;const s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.getWallClock(),i=this.sequenceCounter.nextSequence(),r={id:this.sequenceCounter.generateEventId("err",i),sessionId:this.sessionId,timestamp:s,sequence:i,wallClockTime:n,type:"RUNTIME_ERROR",category:"ERROR",source:"PAGE",payload:{message:t.message||"Unknown runtime error",filename:t.filename,lineno:t.lineno,colno:t.colno,stack:((o=t.error)==null?void 0:o.stack)||void 0,name:((a=t.error)==null?void 0:a.name)||"Error"}};this.callback(r)};window.addEventListener("error",e),this.cleanups.push(()=>window.removeEventListener("error",e))}instrumentUnhandledRejections(){if(typeof window>"u")return;const e=t=>{const s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.getWallClock(),i=this.sequenceCounter.nextSequence();let r="Unhandled Promise Rejection",o;if(t.reason instanceof Error)r=t.reason.message,o=t.reason.stack;else if(typeof t.reason=="string")r=t.reason;else if(t.reason)try{r=JSON.stringify(t.reason)}catch{r=String(t.reason)}const a={id:this.sequenceCounter.generateEventId("rej",i),sessionId:this.sessionId,timestamp:s,sequence:i,wallClockTime:n,type:"RUNTIME_UNHANDLED_REJECTION",category:"ERROR",source:"PAGE",payload:{message:r,stack:o,isUnhandledRejection:!0}};this.callback(a)};window.addEventListener("unhandledrejection",e),this.cleanups.push(()=>window.removeEventListener("unhandledrejection",e))}}class Re{constructor(e,t,s,n=""){b(this,"privacy");b(this,"sequenceCounter");b(this,"callback");b(this,"sessionId");b(this,"isInstrumented",!1);b(this,"originalFetch",null);b(this,"originalXHROpen",null);b(this,"originalXHRSend",null);b(this,"cleanups",[]);this.privacy=e,this.sequenceCounter=t,this.callback=s,this.sessionId=n}setSessionId(e){this.sessionId=e}start(){this.isInstrumented||typeof window>"u"||(this.isInstrumented=!0,this.cleanups=[],this.instrumentFetch(),this.instrumentXHR())}stop(){this.cleanups.forEach(e=>{try{e()}catch{}}),this.cleanups=[],this.isInstrumented=!1}instrumentFetch(){if(typeof window.fetch!="function")return;this.originalFetch=window.fetch;const e=this;window.fetch=async function(...t){const s=e.sequenceCounter.generateEventId("req_f"),n=t[0],i=t[1];let r="";typeof n=="string"?r=n:n instanceof URL?r=n.toString():n&&typeof n=="object"&&"url"in n&&(r=n.url);const o=((i==null?void 0:i.method)||(typeof n=="object"&&"method"in n?n.method:"GET")).toUpperCase(),a=e.privacy.sanitizeUrl(r),c=e.sequenceCounter.getRelativeTimestamp(),u=e.sequenceCounter.getWallClock(),h=e.sequenceCounter.nextSequence(),g={id:s,sessionId:e.sessionId,timestamp:c,sequence:h,wallClockTime:u,type:"NETWORK_REQUEST_START",category:"NETWORK",source:"PAGE",payload:{requestId:s,url:a,method:o,resourceType:"fetch",hasBody:!!(i!=null&&i.body)}};e.callback(g);try{const p=await e.originalFetch.apply(this,t),y=e.sequenceCounter.getRelativeTimestamp(),v=e.sequenceCounter.getWallClock(),m=e.sequenceCounter.nextSequence(),d=Math.max(0,Math.round((y-c)*100)/100),f={id:e.sequenceCounter.generateEventId("res_f",m),sessionId:e.sessionId,timestamp:y,sequence:m,wallClockTime:v,type:"NETWORK_RESPONSE_COMPLETE",category:"NETWORK",source:"PAGE",causality:{triggeredBy:s,precededBy:s},payload:{requestId:s,url:a,method:o,status:p.status,statusText:p.statusText,durationMs:d}};return e.callback(f),p}catch(p){const y=e.sequenceCounter.getRelativeTimestamp(),v=e.sequenceCounter.getWallClock(),m=e.sequenceCounter.nextSequence(),d=Math.max(0,Math.round((y-c)*100)/100),f={id:e.sequenceCounter.generateEventId("res_err",m),sessionId:e.sessionId,timestamp:y,sequence:m,wallClockTime:v,type:"NETWORK_REQUEST_FAILED",category:"NETWORK",source:"PAGE",causality:{triggeredBy:s,precededBy:s},payload:{requestId:s,url:a,method:o,status:0,statusText:"Failed",durationMs:d,error:(p==null?void 0:p.message)||"Network request failed"}};throw e.callback(f),p}},this.cleanups.push(()=>{this.originalFetch&&(window.fetch=this.originalFetch)})}instrumentXHR(){if(typeof XMLHttpRequest>"u")return;this.originalXHROpen=XMLHttpRequest.prototype.open,this.originalXHRSend=XMLHttpRequest.prototype.send;const e=this;XMLHttpRequest.prototype.open=function(t,s,...n){return this._forensicRequestId=e.sequenceCounter.generateEventId("req_x"),this._forensicMethod=(t||"GET").toUpperCase(),this._forensicUrl=typeof s=="string"?s:s.toString(),e.originalXHROpen.apply(this,[t,s,...n])},XMLHttpRequest.prototype.send=function(t){const s=this._forensicRequestId||e.sequenceCounter.generateEventId("req_x"),n=this._forensicMethod||"GET",i=e.privacy.sanitizeUrl(this._forensicUrl||""),r=e.sequenceCounter.getRelativeTimestamp(),o=e.sequenceCounter.getWallClock(),a=e.sequenceCounter.nextSequence();this._forensicStartTime=r;const c={id:s,sessionId:e.sessionId,timestamp:r,sequence:a,wallClockTime:o,type:"NETWORK_REQUEST_START",category:"NETWORK",source:"PAGE",payload:{requestId:s,url:i,method:n,resourceType:"xhr",hasBody:!!t}};e.callback(c);const u=()=>{const h=e.sequenceCounter.getRelativeTimestamp(),g=e.sequenceCounter.getWallClock(),p=e.sequenceCounter.nextSequence(),y=Math.max(0,Math.round((h-(this._forensicStartTime||r))*100)/100),v={id:e.sequenceCounter.generateEventId("res_x",p),sessionId:e.sessionId,timestamp:h,sequence:p,wallClockTime:g,type:this.status>=200&&this.status<400?"NETWORK_RESPONSE_COMPLETE":"NETWORK_REQUEST_FAILED",category:"NETWORK",source:"PAGE",causality:{triggeredBy:s,precededBy:s},payload:{requestId:s,url:i,method:n,status:this.status,statusText:this.statusText,durationMs:y,error:this.status===0?"XHR Network Error or Aborted":void 0}};e.callback(v)};return this.addEventListener("load",u),this.addEventListener("error",u),this.addEventListener("abort",u),e.originalXHRSend.apply(this,[t])},this.cleanups.push(()=>{this.originalXHROpen&&(XMLHttpRequest.prototype.open=this.originalXHROpen),this.originalXHRSend&&(XMLHttpRequest.prototype.send=this.originalXHRSend)})}}class Oe{constructor(e={}){b(this,"sequenceCounter");b(this,"registry");b(this,"privacy");b(this,"snapshotEngine");b(this,"mutationObserver");b(this,"eventCollector");b(this,"diagnostics");b(this,"networkMonitor");b(this,"metadata");b(this,"isRecording",!1);b(this,"isPaused",!1);b(this,"eventListeners",new Set);b(this,"checkpointListeners",new Set);b(this,"lastCheckpointSequence",0);b(this,"lastCheckpointTimestamp",0);b(this,"checkpointTimer",null);b(this,"checkpointIntervalEvents",200);b(this,"checkpointIntervalMs",3e4);this.sequenceCounter=new ne,this.registry=new H,this.privacy=new J(e.privacy),this.snapshotEngine=new he(this.registry,this.privacy,this.sequenceCounter);const t=n=>this.handleEvent(n);this.mutationObserver=new Ne(this.registry,this.privacy,this.sequenceCounter,this.snapshotEngine,t),this.eventCollector=new ke(this.registry,this.privacy,this.sequenceCounter,t),this.diagnostics=new Me(this.privacy,this.sequenceCounter,t),this.networkMonitor=new Re(this.privacy,this.sequenceCounter,t),e.checkpointIntervalEvents&&(this.checkpointIntervalEvents=e.checkpointIntervalEvents),e.checkpointIntervalMs&&(this.checkpointIntervalMs=e.checkpointIntervalMs);const s=e.sessionId||`session_${Date.now()}_${Math.random().toString(36).substring(2,7)}`;this.metadata=this.createInitialMetadata(s,e.sessionName)}getSessionId(){return this.metadata.id}getMetadata(){return{...this.metadata,durationMs:this.sequenceCounter.getRelativeTimestamp(),endTime:this.metadata.endTime||Date.now()}}getRegistry(){return this.registry}onEvent(e){return this.eventListeners.add(e),()=>this.eventListeners.delete(e)}onCheckpoint(e){return this.checkpointListeners.add(e),()=>this.checkpointListeners.delete(e)}start(e=typeof document<"u"?document:{}){if(this.isRecording)throw new Error(`Recorder session ${this.metadata.id} is already active`);this.sequenceCounter.reset(),this.registry.reset(),this.isRecording=!0,this.isPaused=!1,this.metadata.status="recording",this.metadata.startTime=Date.now(),this.mutationObserver.setSessionId(this.metadata.id),this.eventCollector.setSessionId(this.metadata.id),this.diagnostics.setSessionId(this.metadata.id),this.networkMonitor.setSessionId(this.metadata.id);const t=this.snapshotEngine.captureSnapshot(e,this.metadata.id);this.metadata.stats.nodeCount=t.totalNodeCount;const s={id:this.sequenceCounter.generateEventId("snap_init",t.sequence),sessionId:this.metadata.id,timestamp:t.timestamp,sequence:t.sequence,wallClockTime:Date.now(),type:"DOM_SNAPSHOT",category:"DOM",source:"PAGE",payload:{snapshot:t}};return this.createCheckpoint(t,"INITIAL"),this.mutationObserver.start(e),this.eventCollector.start(),this.diagnostics.start(),this.networkMonitor.start(),this.handleEvent(s),this.checkpointIntervalMs>0&&typeof setInterval<"u"&&(this.checkpointTimer=setInterval(()=>{this.isRecording&&!this.isPaused&&this.captureCheckpoint("PERIODIC",e)},this.checkpointIntervalMs)),t}stop(){return this.isRecording?(this.mutationObserver.takeRecords(),this.mutationObserver.stop(),this.eventCollector.stop(),this.diagnostics.stop(),this.networkMonitor.stop(),this.checkpointTimer&&(clearInterval(this.checkpointTimer),this.checkpointTimer=null),this.isRecording=!1,this.metadata.status="stopped",this.metadata.endTime=Date.now(),this.metadata.durationMs=this.sequenceCounter.getRelativeTimestamp(),this.getMetadata()):this.getMetadata()}pause(){!this.isRecording||this.isPaused||(this.isPaused=!0,this.metadata.status="paused")}resume(){!this.isRecording||!this.isPaused||(this.isPaused=!1,this.metadata.status="recording")}captureCheckpoint(e="MANUAL",t=document){if(!this.isRecording)return null;const s=this.snapshotEngine.captureSnapshot(t,this.metadata.id);return this.createCheckpoint(s,e)}recordCustomEvent(e,t,s,n){const i=this.sequenceCounter.getRelativeTimestamp(),r=this.sequenceCounter.getWallClock(),o=this.sequenceCounter.nextSequence(),a={id:this.sequenceCounter.generateEventId("ext",o),sessionId:this.metadata.id,timestamp:i,sequence:o,wallClockTime:r,type:e,category:"EXTENSION",source:"CONTENT_SCRIPT",targetNodeId:s,targetSelector:n,payload:t};return this.handleEvent(a),a}recordScreenshot(e,t="MANUAL"){const s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.getWallClock(),i=this.sequenceCounter.nextSequence(),r={id:this.sequenceCounter.generateEventId("scr",i),sessionId:this.metadata.id,timestamp:s,sequence:i,wallClockTime:n,type:"SCREENSHOT_CHECKPOINT",category:"SCREENSHOT",source:"BROWSER_RUNTIME",payload:{screenshotId:`shot_${i}`,dataUrl:e,viewport:{width:typeof window<"u"?window.innerWidth:1920,height:typeof window<"u"?window.innerHeight:1080,scrollX:typeof window<"u"?window.scrollX:0,scrollY:typeof window<"u"?window.scrollY:0,devicePixelRatio:typeof window<"u"?window.devicePixelRatio:1},triggerReason:t}};return this.handleEvent(r),r}addAnnotation(e,t,s="AGENT",n){const i=this.sequenceCounter.getRelativeTimestamp(),r=this.sequenceCounter.nextSequence(),o={id:`ann_${r}_${Math.random().toString(36).substring(2,6)}`,sessionId:this.metadata.id,timestamp:i,sequence:r,nodeId:n,author:s,label:e,comment:t,createdAt:Date.now()},a={id:o.id,sessionId:this.metadata.id,timestamp:i,sequence:r,wallClockTime:Date.now(),type:"ANNOTATION",category:"ANNOTATION",source:s==="USER"?"USER_INTERACTION":"BROWSER_RUNTIME",targetNodeId:n,payload:{annotation:o}};return this.handleEvent(a),o}createCheckpoint(e,t){const s=this.sequenceCounter.getSequence()-this.lastCheckpointSequence;this.lastCheckpointSequence=this.sequenceCounter.getSequence(),this.lastCheckpointTimestamp=e.timestamp,this.metadata.stats.checkpointCount+=1;const n={checkpointId:`chk_${e.sequence}_${Date.now()}`,sessionId:this.metadata.id,timestamp:e.timestamp,sequence:e.sequence,wallClockTime:Date.now(),snapshot:e,eventIndex:this.metadata.stats.eventCount,eventsSinceLastCheckpoint:s,trigger:t},i={id:n.checkpointId,sessionId:this.metadata.id,timestamp:e.timestamp,sequence:e.sequence,wallClockTime:n.wallClockTime,type:"CHECKPOINT",category:"CHECKPOINT",source:"BROWSER_RUNTIME",payload:{checkpointId:n.checkpointId,snapshot:e,eventsSinceLastCheckpoint:s,totalEventsSoFar:this.metadata.stats.eventCount}};return this.checkpointListeners.forEach(r=>{try{r(n)}catch(o){console.error("[ForensicRecorder] Checkpoint listener error:",o)}}),this.handleEvent(i),n}handleEvent(e){this.isPaused&&e.type!=="CHECKPOINT"&&e.type!=="ANNOTATION"||(this.metadata.stats.eventCount+=1,e.category==="DOM"&&(this.metadata.stats.mutationCount+=1),e.category==="ERROR"&&(this.metadata.stats.errorCount+=1),e.category==="CONSOLE"&&(this.metadata.stats.consoleCount+=1),e.category==="NETWORK"&&(this.metadata.stats.networkCount+=1),e.category==="SCREENSHOT"&&(this.metadata.stats.screenshotCount+=1),this.isRecording&&e.type!=="CHECKPOINT"&&e.type!=="DOM_SNAPSHOT"&&this.sequenceCounter.getSequence()-this.lastCheckpointSequence>=this.checkpointIntervalEvents&&typeof document<"u"&&this.captureCheckpoint("PERIODIC"),this.eventListeners.forEach(t=>{try{t(e)}catch(s){console.error("[ForensicRecorder] Event listener error:",s)}}))}createInitialMetadata(e,t){const s={domRecording:typeof MutationObserver<"u"?"HEALTHY":"UNAVAILABLE",userEvents:typeof window<"u"?"HEALTHY":"UNAVAILABLE",console:typeof console<"u"?"HEALTHY":"UNAVAILABLE",network:typeof window<"u"&&typeof window.fetch<"u"?"HEALTHY":"PARTIAL",screenshots:"HEALTHY",shadowDom:typeof Element<"u"&&"attachShadow"in Element.prototype?"HEALTHY":"RESTRICTED",iframes:"PARTIAL"},n={eventCount:0,mutationCount:0,errorCount:0,consoleCount:0,networkCount:0,checkpointCount:0,screenshotCount:0,nodeCount:0};return{id:e,name:t||`Recording ${new Date().toLocaleTimeString()}`,url:typeof window<"u"?window.location.href:"about:blank",origin:typeof window<"u"?window.location.origin:"",title:typeof document<"u"?document.title:"Forensic Session",userAgent:typeof navigator<"u"?navigator.userAgent:"Node.js/ForensicAgent",schemaVersion:"2.0.0",recorderVersion:"2.0.0",extensionVersion:"2.0.0",startTime:Date.now(),status:"recording",health:s,stats:n}}}class k{static inspectPage(e=document){var n,i,r,o,a,c,u,h,g,p,y,v,m,d;const t=e.defaultView||(typeof window<"u"?window:{}),s=e.activeElement;return{url:((n=t.location)==null?void 0:n.href)||((i=e.location)==null?void 0:i.href)||"",title:e.title||"",origin:((r=t.location)==null?void 0:r.origin)||"",viewport:{width:t.innerWidth||((o=e.documentElement)==null?void 0:o.clientWidth)||1920,height:t.innerHeight||((a=e.documentElement)==null?void 0:a.clientHeight)||1080,scrollX:t.scrollX||t.pageXOffset||((c=e.documentElement)==null?void 0:c.scrollLeft)||0,scrollY:t.scrollY||t.pageYOffset||((u=e.documentElement)==null?void 0:u.scrollTop)||0,devicePixelRatio:t.devicePixelRatio||1},documentDimensions:{width:Math.max(((h=e.body)==null?void 0:h.scrollWidth)||0,((g=e.documentElement)==null?void 0:g.scrollWidth)||0),height:Math.max(((p=e.body)==null?void 0:p.scrollHeight)||0,((y=e.documentElement)==null?void 0:y.scrollHeight)||0)},activeElement:s?{tag:((v=s.tagName)==null?void 0:v.toLowerCase())||"",selector:this.computeBestSelector(s),text:(m=s.textContent)==null?void 0:m.slice(0,100).trim()}:void 0,focusedElement:typeof e.hasFocus=="function"&&e.hasFocus()&&s?{tag:((d=s.tagName)==null?void 0:d.toLowerCase())||"",selector:this.computeBestSelector(s)}:void 0,visibilityState:e.visibilityState||"visible",readyState:e.readyState||"complete",framesCount:e.querySelectorAll?e.querySelectorAll("iframe, frame").length:0}}static inspectElement(e,t){var xe,_e;const s=e.ownerDocument||document,n=s.defaultView||(typeof window<"u"?window:{}),i=e,r=e.tagName?e.tagName.toLowerCase():"element",o=this.extractClasses(e),{bestSelector:a,candidates:c}=this.generateSelectorCandidates(e),u={},h={};if(e.attributes)for(let V=0;V0||E.height>0||E.right>0||E.bottom>0,R=!C||E.right>0&&E.bottom>0&&E.left=L||E.top>=I),A=!P&&T!=="none"&&x!=="hidden"&&N>0&&R,se={disabled:i.disabled??e.hasAttribute("disabled"),readOnly:i.readOnly??e.hasAttribute("readonly"),checked:i.checked,selected:i.selected,focused:s.activeElement===e,isShadowHost:!!e.shadowRoot,hasShadowRoot:!!e.shadowRoot},z=[];let G=e.parentElement;for(;G&&G.tagName&&G.tagName.toLowerCase()!=="html";)z.push(this.computeBestSelector(G)),G=G.parentElement;const Ht={count:e.children?e.children.length:0,tags:e.children?Array.from(e.children).slice(0,10).map(V=>V.tagName.toLowerCase()):[]};let Ae;if(t){const V=t.getId(e);Ae={logicalNodeId:V??null,creationSequence:null,lastMutationSequence:null,eventCount:0,isRecorded:V!=null}}return{tag:r,id:e.id||void 0,classes:o,role:g||void 0,ariaAttributes:Object.keys(h).length>0?h:void 0,text:v.slice(0,200),normalizedText:m.slice(0,200),value:d,type:f.type||void 0,selector:a,bestSelector:a,selectorCandidates:c,bounds:E,visibility:{isVisible:A,display:T,visibility:x,opacity:N,pointerEvents:D,isClipped:P,isInViewport:R,zIndex:M},computedStyle:S?{display:T,visibility:x,opacity:String(N),position:S.position,zIndex:String(M),pointerEvents:D,overflow:S.overflow,boxSizing:S.boxSizing,color:S.color,backgroundColor:S.backgroundColor,fontSize:S.fontSize}:{},attributes:u,state:se,context:{parentChain:z,parentSelector:z[0]||void 0,childrenSummary:Ht,containingBlock:(S==null?void 0:S.position)==="fixed"?"viewport":z[0]||void 0,iframe:null,shadowRoot:e.shadowRoot?"open":null},forensics:Ae}}static inspectVisualState(e){var f,w;const t=e.ownerDocument||document,s=t.defaultView||(typeof window<"u"?window:{}),n=e.getBoundingClientRect?e.getBoundingClientRect():{x:0,y:0,width:0,height:0,top:0,right:0,bottom:0,left:0},i=s.getComputedStyle?s.getComputedStyle(e):null,r=s.innerWidth||((f=t.documentElement)==null?void 0:f.clientWidth)||1920,o=s.innerHeight||((w=t.documentElement)==null?void 0:w.clientHeight)||1080,a=s.scrollX||s.pageXOffset||0,c=s.scrollY||s.pageYOffset||0,u=s.devicePixelRatio||1,h=(i==null?void 0:i.display)||"block",g=(i==null?void 0:i.visibility)||"visible",p=i&&parseFloat(i.opacity)||1,y=n.right>0&&n.bottom>0&&n.left=r||n.top>=o;let d=null;if(t.elementFromPoint&&y&&!v&&h!=="none"){const E=Math.max(0,Math.min(r-1,n.left+n.width/2)),S=Math.max(0,Math.min(o-1,n.top+n.height/2));try{const T=t.elementFromPoint(E,S);T&&T!==e&&!e.contains(T)&&!T.contains(e)&&(d=this.computeBestSelector(T))}catch{}}return{selector:this.computeBestSelector(e),bounds:{x:n.x??n.left??0,y:n.y??n.top??0,width:n.width??0,height:n.height??0,top:n.top??0,right:n.right??0,bottom:n.bottom??0,left:n.left??0},viewport:{scrollX:a,scrollY:c,width:r,height:o,devicePixelRatio:u},layout:{display:h,position:(i==null?void 0:i.position)||"static",zIndex:(i==null?void 0:i.zIndex)||"auto",opacity:p,visibility:g,overflow:(i==null?void 0:i.overflow)||"visible",boxSizing:(i==null?void 0:i.boxSizing)||"content-box",pointerEvents:(i==null?void 0:i.pointerEvents)||"auto"},occlusion:{isInViewport:y,isClipped:v||m,isZeroDimension:v,isTransparent:p===0,isDisplayNone:h==="none",isVisibilityHidden:g==="hidden",isOffscreen:m,occludedBy:d},computedStyleSummary:i?{display:h,position:i.position,zIndex:i.zIndex,opacity:String(p),visibility:g,pointerEvents:i.pointerEvents}:{}}}static generateSelectorCandidates(e){const t=e.ownerDocument||document,s=e.tagName?e.tagName.toLowerCase():"element",n=[];if(e.id&&/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(e.id)){const c=`#${e.id}`;try{t.querySelectorAll&&t.querySelectorAll(c).length===1&&n.push(c)}catch{n.push(c)}}const i=["data-testid","data-test","data-id","data-qa","data-cy","aria-label","name"];for(const c of i){const u=e.getAttribute(c);if(u&&/^[a-zA-Z0-9_-]+$/.test(u)){const h=`${s}[${c}="${u}"]`;try{t.querySelectorAll&&t.querySelectorAll(h).length===1&&n.push(h)}catch{n.push(h)}}}const r=this.extractClasses(e).filter(c=>/^[a-zA-Z0-9_-]+$/.test(c)&&!c.startsWith("ng-")&&!c.startsWith("_ng"));if(r.length>0){const c=`${s}.${r.slice(0,3).join(".")}`;try{t.querySelectorAll&&t.querySelectorAll(c).length===1&&n.push(c)}catch{n.push(c)}}if(e.parentElement&&e.parentElement.children){const c=Array.from(e.parentElement.children).filter(u=>u.tagName&&u.tagName.toLowerCase()===s);if(c.length>1){const u=c.indexOf(e)+1;if(u>0){const h=this.computeBestSelector(e.parentElement);n.push(`${h} > ${s}:nth-of-type(${u})`)}}}const o=r.length>0?`${s}.${r[0]}`:s;return n.push(o),{bestSelector:n[0]||s,candidates:n}}static computeBestSelector(e){return this.generateSelectorCandidates(e).bestSelector}static extractClasses(e){return e.classList&&typeof e.classList.forEach=="function"?Array.from(e.classList):typeof e.className=="string"?e.className.split(/\s+/).filter(Boolean):e.className&&typeof e.className.baseVal=="string"?e.className.baseVal.split(/\s+/).filter(Boolean):[]}static inferImplicitRole(e){switch(e.tagName?e.tagName.toLowerCase():""){case"a":return e.hasAttribute("href")?"link":void 0;case"button":return"button";case"input":{const s=e.type||"text";return s==="button"||s==="submit"||s==="reset"?"button":s==="checkbox"?"checkbox":s==="radio"?"radio":"textbox"}case"select":return"combobox";case"textarea":return"textbox";case"nav":return"navigation";case"header":return"banner";case"footer":return"contentinfo";case"main":return"main";case"article":return"article";case"section":return"region";default:return}}}b(k,"privacyEngine",new J);class Le{constructor(e){b(this,"registry");b(this,"lastSelectedElementRef");b(this,"timingHook",null);b(this,"lastTrajectory",[]);this.registry=e}setLastSelectedElement(e){this.lastSelectedElementRef=e}setTimingHook(e){this.timingHook=e}getLastTrajectory(){return this.lastTrajectory}async timing(e){this.timingHook&&await this.timingHook(e)}resolveTarget(e,t=document){if(e.selectedElementRef&&this.lastSelectedElementRef&&t.contains(this.lastSelectedElementRef))return this.lastSelectedElementRef;if(typeof e.nodeId=="number"&&this.registry){const s=this.registry.getNode(e.nodeId);if(s&&s instanceof Element&&t.contains(s))return s}if(e.selector)try{const s=t.querySelectorAll(e.selector);if(s.length>1){for(let n=0;n{r+=w.length});try{h.observe(t.body||t.documentElement,{childList:!0,attributes:!0,characterData:!0,subtree:!0})}catch{}const g=w=>{o.push(w.message||"Runtime Error")};typeof window<"u"&&window.addEventListener("error",g);try{await this.dispatchAction(n,e)}finally{typeof window<"u"&&window.removeEventListener("error",g)}let p=!0;if((f=e.options)!=null&&f.waitForStabilization){const w=e.options.stabilizationTimeoutMs||300;await new Promise(E=>setTimeout(E,Math.min(2e3,w)))}h.disconnect();let y;t.contains(n)&&(y=k.inspectElement(n,this.registry));const v=Date.now()-s,m=a!=null&&a.__FORENSIC_CONSOLE_BUFFER__?a.__FORENSIC_CONSOLE_BUFFER__.slice(c).filter(w=>(w==null?void 0:w.level)==="error").length:0,d=a!=null&&a.__FORENSIC_NETWORK_BUFFER__?a.__FORENSIC_NETWORK_BUFFER__.slice(u).length:0;return{success:!0,action:e.action,target:y||i,beforeState:i,afterState:y,effects:{domMutations:r,consoleErrors:m,networkRequests:d,runtimeErrors:o},durationMs:v,stabilized:p}}async dispatchAction(e,t){var n,i,r,o,a,c;const s=e;switch(t.action){case"click":{this.scrollIntoViewIfNeeded(e),await this.timing("move"),await this.timing("click"),this.dispatchMouseEvent(e,"pointerdown"),this.dispatchMouseEvent(e,"mousedown"),typeof s.focus=="function"&&s.focus(),this.dispatchMouseEvent(e,"pointerup"),this.dispatchMouseEvent(e,"mouseup"),typeof s.click=="function"?s.click():this.dispatchMouseEvent(e,"click");break}case"double_click":{this.scrollIntoViewIfNeeded(e),await this.timing("click"),this.dispatchMouseEvent(e,"click"),await this.timing("click"),this.dispatchMouseEvent(e,"click"),this.dispatchMouseEvent(e,"dblclick");break}case"right_click":{this.scrollIntoViewIfNeeded(e),await this.timing("click"),this.dispatchMouseEvent(e,"pointerdown",{button:2}),this.dispatchMouseEvent(e,"mousedown",{button:2}),this.dispatchMouseEvent(e,"contextmenu",{button:2});break}case"hover":{await this.timing("move"),this.dispatchMouseEvent(e,"pointerenter"),this.dispatchMouseEvent(e,"mouseenter"),this.dispatchMouseEvent(e,"mouseover"),await this.timing("move"),this.dispatchMouseEvent(e,"mousemove");break}case"focus":{typeof s.focus=="function"&&s.focus(),e.dispatchEvent(new FocusEvent("focus",{bubbles:!0}));break}case"blur":{typeof s.blur=="function"&&s.blur(),e.dispatchEvent(new FocusEvent("blur",{bubbles:!0}));break}case"type":{const u=t.text||"",h=e,g=((n=e.ownerDocument)==null?void 0:n.defaultView)||(typeof window<"u"?window:null);typeof s.focus=="function"&&s.focus();for(const y of u){await this.timing("type");const v=d=>{try{const w=(g==null?void 0:g.KeyboardEvent)||(typeof KeyboardEvent<"u"?KeyboardEvent:null);if(w)return new w(d,{key:y,bubbles:!0})}catch{}const f=(g==null?void 0:g.CustomEvent)||(g==null?void 0:g.Event)||CustomEvent;return new f(d,{bubbles:!0,cancelable:!0})},m=(d,f)=>{try{const E=(g==null?void 0:g.InputEvent)||(typeof InputEvent<"u"?InputEvent:null);if(E)return new E(d,f)}catch{}const w=(g==null?void 0:g.CustomEvent)||(g==null?void 0:g.Event)||CustomEvent;return new w(d,{bubbles:!0,cancelable:!0})};e.dispatchEvent(v("keydown")),e.dispatchEvent(v("keypress")),"value"in h&&(h.value=(h.value||"")+y),e.dispatchEvent(m("input",{data:y,inputType:"insertText",bubbles:!0})),e.dispatchEvent(v("keyup"))}const p=(g==null?void 0:g.Event)||Event;e.dispatchEvent(new p("change",{bubbles:!0}));break}case"clear":{const u=e,h=((i=e.ownerDocument)==null?void 0:i.defaultView)||(typeof window<"u"?window:null);if("value"in u){u.value="";const g=(y,v)=>{try{const d=(h==null?void 0:h.InputEvent)||(typeof InputEvent<"u"?InputEvent:null);if(d)return new d(y,v)}catch{}const m=(h==null?void 0:h.CustomEvent)||(h==null?void 0:h.Event)||CustomEvent;return new m(y,{bubbles:!0,cancelable:!0})};e.dispatchEvent(g("input",{inputType:"deleteContentBackward",bubbles:!0}));const p=(h==null?void 0:h.Event)||Event;e.dispatchEvent(new p("change",{bubbles:!0}))}break}case"press_key":{const u=t.key||"Enter",h=((r=e.ownerDocument)==null?void 0:r.defaultView)||(typeof window<"u"?window:null),g=p=>{try{const v=(h==null?void 0:h.KeyboardEvent)||(typeof KeyboardEvent<"u"?KeyboardEvent:null);if(v)return new v(p,{key:u,bubbles:!0})}catch{}const y=(h==null?void 0:h.CustomEvent)||(h==null?void 0:h.Event)||CustomEvent;return new y(p,{bubbles:!0,cancelable:!0})};e.dispatchEvent(g("keydown")),e.dispatchEvent(g("keypress")),e.dispatchEvent(g("keyup"));break}case"select_option":{const u=e;((o=u.tagName)==null?void 0:o.toLowerCase())==="select"&&t.optionValue&&(u.value=t.optionValue,e.dispatchEvent(new Event("change",{bubbles:!0})));break}case"scroll_into_view":{this.scrollIntoViewIfNeeded(e,!0);break}case"scroll":{const u=((a=t.scrollDelta)==null?void 0:a.x)||0,h=((c=t.scrollDelta)==null?void 0:c.y)||0;typeof e.scrollBy=="function"&&e.scrollBy(u,h);break}default:throw new Error(`Unsupported interaction action: ${t.action}`)}}scrollIntoViewIfNeeded(e,t=!1){if(typeof e.scrollIntoView=="function")try{e.scrollIntoView({behavior:"auto",block:"center",inline:"center"})}catch{e.scrollIntoView(t)}}dispatchMouseEvent(e,t,s={}){const n=e.getBoundingClientRect?e.getBoundingClientRect():{left:0,top:0,width:0,height:0},i=n.left+n.width/2,r=n.top+n.height/2,o=new MouseEvent(t,{bubbles:s.bubbles!==void 0?s.bubbles:!0,cancelable:s.cancelable!==void 0?s.cancelable:!0,clientX:i,clientY:r,button:s.button||0,buttons:s.button===2?2:1});e.dispatchEvent(o)}}class ie{static matches(e,t){if(!e||e.nodeType!==$.ELEMENT_NODE)return!1;const s=t.trim();return s?s.includes(",")?s.split(",").some(n=>this.matchesSimple(e,n.trim())):this.matchesCompound(e,s):!1}static querySelector(e,t,s){const n=this.querySelectorAll(e,t,s,1);return n.length>0?n[0]:null}static querySelectorAll(e,t,s,n=1/0){const i=[],r=s[t];if(!r)return i;const o=[...r.children||[]],a=new Set;for(;o.length>0&&i.length=n))break;u.children&&u.children.length>0&&o.push(...u.children)}}return i}static getElementById(e,t){for(const s of Object.values(t))if(s.nodeType===$.ELEMENT_NODE&&!s.isDetached&&s.attributes&&s.attributes.id===e&&this.isNodeConnected(s,t))return s;return null}static isNodeConnected(e,t){if(e.isDetached)return!1;let s=e;const n=new Set;for(;s&&s.parentId;){if(n.has(s.id))return!1;n.add(s.id);const i=t[s.parentId];if(!i||i.isDetached)return!1;s=i}return!0}static computeSelector(e,t){var r,o;if(!e)return"";if(e.nodeType!==$.ELEMENT_NODE)return e.tagName||`#node-${e.id}`;if((r=e.attributes)!=null&&r.id)return`#${e.attributes.id}`;const s=e.tagName||"div",n=(((o=e.attributes)==null?void 0:o.class)||"").split(/\s+/).filter(a=>a&&!a.startsWith("ng-")).slice(0,2),i=n.length>0?"."+n.join("."):"";if(e.parentId&&t[e.parentId]){const c=(t[e.parentId].children||[]).map(u=>t[u]).filter(u=>u&&u.nodeType===$.ELEMENT_NODE&&u.tagName===s);if(c.length>1){const u=c.findIndex(h=>h.id===e.id)+1;return`${s}${i}:nth-of-type(${u})`}}return`${s}${i}`}static matchesCompound(e,t){return this.matchesSimple(e,t)}static matchesSimple(e,t){var i,r,o,a,c,u,h;const s=((i=e.tagName)==null?void 0:i.toLowerCase())||"";if(t==="*")return!0;if(t.startsWith("#")){const g=t.substring(1);return((r=e.attributes)==null?void 0:r.id)===g}if(t.startsWith(".")){const g=t.substring(1);return(((o=e.attributes)==null?void 0:o.class)||"").split(/\s+/).includes(g)}if(t.startsWith("[")&&t.endsWith("]")){const g=t.substring(1,t.length-1);if(g.includes("=")){const[p,y]=g.split("="),v=y.replace(/^["']|["']$/g,"");return((a=e.attributes)==null?void 0:a[p.trim()])===v}return!!((c=e.attributes)!=null&&c[g.trim()])}const n=t.match(/^([a-zA-Z0-9_-]+)(.*)$/);if(n){const g=n[1].toLowerCase(),p=n[2];if(g!==s&&g!=="*")return!1;if(!p)return!0;if(p.startsWith("#"))return((u=e.attributes)==null?void 0:u.id)===p.substring(1);if(p.startsWith("."))return(((h=e.attributes)==null?void 0:h.class)||"").split(/\s+/).includes(p.substring(1));if(p.startsWith("["))return this.matchesSimple(e,p)}return!1}}class De{static traceElement(e,t,s){var M,L;const n=[...t].sort((I,C)=>I.sequence-C.sequence);let i=e.nodeId,r="unknown",o=e.selector||"",a={},c=0,u=0,h="init";if(!i&&e.selector&&s){const I=ie.querySelector(e.selector,s.rootId,s.nodes);I&&(i=I.id,r=I.tagName||"element",a={...I.attributes||{}},o=e.selector)}if(!i&&e.selector){for(const I of n)if(I.type==="DOM_MUTATION_ADD"){const C=I.payload;if(C.node&&ie.matches(C.node,e.selector)){i=C.node.id,r=C.node.tagName||"element",a={...C.node.attributes||{}},c=I.timestamp,u=I.sequence,h=I.id;break}}}if(!i)return null;const g=[];let p=!0,y=null,v=null,m,d=0;if(s&&s.nodes[i]){const I=s.nodes[i];r=I.tagName||r,a={...I.attributes||{}},o||(o=ie.computeSelector(I,s.nodes)),g.push({timestamp:s.timestamp,sequence:s.sequence,wallClockTime:Date.now(),stage:"CREATED",eventId:s.snapshotId,eventType:"DOM_SNAPSHOT",description:`Element <${r}> existed in initial baseline snapshot [ID: ${i}]`,details:{initialParentId:I.parentId,attributes:a},nodeSnapshot:I})}const f=new Map;if(s)for(const[I,C]of Object.entries(s.nodes))f.set(Number(I),C.parentId??null);const w=(I,C)=>{let R=f.get(C);const P=new Set;for(;R&&!P.has(R);){if(R===I)return!0;P.add(R),R=f.get(R)}return!1};for(const I of n){const C=I.timestamp,R=I.sequence,P=I.wallClockTime;if(I.type==="DOM_MUTATION_ADD"){const A=I.payload;(M=A.node)!=null&&M.id&&f.set(A.node.id,A.parentId??null),((L=A.node)==null?void 0:L.id)===i&&(p=!0,r=A.node.tagName||r,c=C,u=R,h=I.id,a={...A.node.attributes||{}},g.push({timestamp:C,sequence:R,wallClockTime:P,stage:"ATTACHED_TO_DOM",eventId:I.id,eventType:I.type,description:`Element <${r}> added to DOM under parent ID ${A.parentId}`,details:{parentId:A.parentId,index:A.index},nodeSnapshot:A.node}))}if(I.type==="DOM_MUTATION_REMOVE"){const A=I.payload;A.nodeId===i?(p=!1,y=C,v=R,m=I.id,g.push({timestamp:C,sequence:R,wallClockTime:P,stage:"REMOVED_FROM_DOM",eventId:I.id,eventType:I.type,description:`Element <${r}> explicitly removed from parent ID ${A.parentId}`,details:{parentId:A.parentId,removedIndex:A.index}})):w(A.nodeId,i)&&(p=!1,y=C,v=R,m=I.id,g.push({timestamp:C,sequence:R,wallClockTime:P,stage:"PARENT_SUBTREE_REPLACED",eventId:I.id,eventType:I.type,description:`Ancestor element [ID: ${A.nodeId}] was removed, causing target element [ID: ${i}] to detach from DOM`,details:{removedAncestorId:A.nodeId,parentId:A.parentId}}))}if(I.type==="DOM_MUTATION_MOVE"){const A=I.payload;A.nodeId&&f.set(A.nodeId,A.newParentId??null),A.nodeId===i&&(d++,g.push({timestamp:C,sequence:R,wallClockTime:P,stage:"REPARENTED",eventId:I.id,eventType:I.type,description:`Element reparented from parent ${A.oldParentId} to ${A.newParentId}`,details:{oldParentId:A.oldParentId,newParentId:A.newParentId}}))}if(I.type==="DOM_MUTATION_ATTR"){const A=I.payload;if(A.nodeId===i){d++;const se=A.attributeName.toLowerCase();let z="ATTRIBUTE_MODIFIED";se==="class"&&(z="CLASS_MODIFIED"),se==="style"&&(z="STYLE_MODIFIED"),g.push({timestamp:C,sequence:R,wallClockTime:P,stage:z,eventId:I.id,eventType:I.type,description:`Attribute '${A.attributeName}' changed from '${A.oldValue??""}' to '${A.newValue??""}'`,details:{attributeName:A.attributeName,oldValue:A.oldValue,newValue:A.newValue}})}}if(I.type==="DOM_MUTATION_TEXT"){const A=I.payload;A.nodeId===i&&(d++,g.push({timestamp:C,sequence:R,wallClockTime:P,stage:"TEXT_MODIFIED",eventId:I.id,eventType:I.type,description:`Text content changed: "${A.oldText}" → "${A.newText}"`,details:{oldText:A.oldText,newText:A.newText}}))}}const E=y??c,S=500,T=n.filter(I=>(I.category==="ERROR"||I.category==="CONSOLE")&&Math.abs(I.timestamp-E)<=S),x=n.filter(I=>I.category==="NETWORK"&&Math.abs(I.timestamp-E)<=S),N=n.length>0?n[n.length-1].timestamp:c,D=Math.max(0,(y??N)-c);return{targetNodeId:i,tagName:r,selectorHint:o,initialAttributes:a,createdAt:c,createdSequence:u,createdEventId:h,removedAt:y,removedSequence:v,removedEventId:m,isCurrentlyAlive:p,lifespanMs:Math.round(D*100)/100,mutationCount:d,entries:g,correlatedDiagnostics:T,correlatedNetwork:x}}}class $e{static analyze(e,t,s){var D,M,L,I;const n=typeof e=="number"?{nodeId:e}:{selector:e},i=De.traceElement(n,t,s);if(!i)return{targetQuery:e,found:!1,disappearanceMechanism:"UNKNOWN",likelyRootCause:"Target element could not be found in recording baseline or event stream",confidenceScore:0,detailedExplanation:`No element matching "${e}" was ever created, recorded in the initial DOM snapshot, or observed in mutation events.`,evidentiaryTrail:[],precedingEvents:[],followingEvents:[],correlatedErrors:[],correlatedNetworkCalls:[],alternativeHypotheses:[{hypothesis:"Element was injected into an unmonitored isolated iframe or ShadowRoot closed mode",likelihood:40,evidenceFor:["Element query yielded zero matches in monitored document"],evidenceAgainst:["Iframes/ShadowRoots were accessible in this session"]},{hypothesis:"Selector typo or timing mismatch",likelihood:60,evidenceFor:["Target selector did not match any recorded tag or class"],evidenceAgainst:[]}]};const r=[...t].sort((C,R)=>C.sequence-R.sequence),o=[],a=[];let c="UNKNOWN",u="Unknown disappearance mechanism",h=50,g="",p=i.removedAt??void 0;const y=i.entries.find(C=>C.stage==="REMOVED_FROM_DOM"),v=i.entries.find(C=>C.stage==="PARENT_SUBTREE_REPLACED"),m=i.entries.find(C=>C.stage==="CLASS_MODIFIED"&&/\b(hidden|hide|d-none|invisible|collapsed)\b/i.test(String(C.details.newValue||""))),d=i.entries.find(C=>C.stage==="STYLE_MODIFIED"&&/display\s*:\s*none|visibility\s*:\s*hidden|opacity\s*:\s*0/i.test(String(C.details.newValue||"")));y?(c="DIRECT_NODE_REMOVAL",p=y.timestamp,u=`Element [ID: ${i.targetNodeId}] <${i.tagName}> was directly removed from its parent [ID: ${y.details.parentId}] via DOM removeChild/replaceChild`,h=95,o.push({timestamp:y.timestamp,sequence:y.sequence,eventId:y.eventId,eventType:y.eventType,evidenceType:"DIRECT",description:`Direct DOM removal mutation: element detached from parent ID ${y.details.parentId}`,confidenceContribution:50})):v?(c="PARENT_SUBTREE_REPLACED",p=v.timestamp,u=`Host framework (e.g. React/Vue re-render) destroyed and replaced Ancestor container [ID: ${v.details.removedAncestorId}], causing injected element to be unmounted`,h=92,o.push({timestamp:v.timestamp,sequence:v.sequence,eventId:v.eventId,eventType:v.eventType,evidenceType:"DIRECT",description:`Ancestor container [ID: ${v.details.removedAncestorId}] was removed, wiping out all child subtrees`,confidenceContribution:50})):d?(c="STYLE_DISPLAY_NONE",p=d.timestamp,u=`Element was visually hidden by an inline style modification: "${d.details.newValue}"`,h=88,o.push({timestamp:d.timestamp,sequence:d.sequence,eventId:d.eventId,eventType:d.eventType,evidenceType:"DIRECT",description:`Inline style changed to "${d.details.newValue}"`,confidenceContribution:45})):m?(c="CLASS_TRIGGERED_HIDDEN",p=m.timestamp,u=`Element was visually hidden because its CSS class list was modified to include "${m.details.newValue}"`,h=85,o.push({timestamp:m.timestamp,sequence:m.sequence,eventId:m.eventId,eventType:m.eventType,evidenceType:"DIRECT",description:`Class list changed from "${m.details.oldValue??""}" to "${m.details.newValue??""}"`,confidenceContribution:45})):i.isCurrentlyAlive&&(c="UNKNOWN",u=`Element [ID: ${i.targetNodeId}] is currently alive and attached to the DOM tree (no unmount mutation detected)`,h=70,g="The element exists in the current DOM state. If it is not visible on screen, it may be clipped by viewport boundaries, z-index stacking context, or 0x0 pixel dimensions.");const f=p??i.createdAt,w=500,E=r.filter(C=>C.timestamp>=f-w&&C.timestampC.timestamp>f&&C.timestamp<=f+w),T=E.filter(C=>C.category==="ERROR");if(T.length>0){const C=T[0],R=((D=C.payload)==null?void 0:D.message)||"Unknown runtime error";o.push({timestamp:C.timestamp,sequence:C.sequence,eventId:C.id,eventType:C.type,evidenceType:"PRECEDING",description:`Runtime error occurred ${(f-C.timestamp).toFixed(1)}ms before disappearance: "${R}"`,confidenceContribution:20,rawEvent:C}),u+=` (preceded by runtime error: "${R}")`}const x=E.filter(C=>C.type==="NETWORK_RESPONSE_COMPLETE"||C.type==="NETWORK_REQUEST_FAILED");if(x.length>0){const C=x[0],R=((M=C.payload)==null?void 0:M.url)||"network request";o.push({timestamp:C.timestamp,sequence:C.sequence,eventId:C.id,eventType:C.type,evidenceType:"PRECEDING",description:`Network response completed ${(f-C.timestamp).toFixed(1)}ms before disappearance: ${R}`,confidenceContribution:15,rawEvent:C})}const N=E.filter(C=>C.category==="NAVIGATION");if(N.length>0){const C=N[0];o.push({timestamp:C.timestamp,sequence:C.sequence,eventId:C.id,eventType:C.type,evidenceType:"PRECEDING",description:`Navigation event (${(L=C.payload)==null?void 0:L.navigationType}) occurred ${(f-C.timestamp).toFixed(1)}ms before disappearance`,confidenceContribution:25,rawEvent:C}),u+=` following SPA navigation to "${(I=C.payload)==null?void 0:I.url}"`}return g||(g=[`Element <${i.tagName}> (Logical ID: ${i.targetNodeId}, selector: "${i.selectorHint}") was created at ${i.createdAt.toFixed(1)}ms.`,`It remained alive in the DOM for ${i.lifespanMs.toFixed(1)}ms and experienced ${i.mutationCount} mutations.`,`At timestamp ${f.toFixed(1)}ms, it disappeared via [${c}].`,`Diagnosis: ${u}.`].join(" ")),c==="PARENT_SUBTREE_REPLACED"?(a.push({hypothesis:"Direct cleanup called by extension code",likelihood:25,evidenceFor:["Element was unmounted shortly after creation"],evidenceAgainst:["Ancestor container mutation was recorded from host page context"]}),a.push({hypothesis:"Host single-page app route change destroyed component tree",likelihood:35,evidenceFor:N.length>0?["Preceding navigation event recorded"]:[],evidenceAgainst:N.length===0?["No navigation events occurred in temporal window"]:[]})):c==="DIRECT_NODE_REMOVAL"&&a.push({hypothesis:"Third-party script or ad-blocker removed the injected node",likelihood:30,evidenceFor:["Direct node removal occurred without ancestor replacement"],evidenceAgainst:["No ad-blocker signatures or extension error logs observed"]}),{targetQuery:e,targetNodeId:i.targetNodeId,found:!0,tagName:i.tagName,selectorHint:i.selectorHint,createdAt:i.createdAt,firstVisibleAt:i.createdAt,lastKnownGoodStateAt:Math.max(0,f-1),disappearedAt:p,lifespanMs:i.lifespanMs,disappearanceMechanism:c,likelyRootCause:u,confidenceScore:Math.min(99,h),detailedExplanation:g,evidentiaryTrail:o,precedingEvents:E,followingEvents:S,correlatedErrors:T,correlatedNetworkCalls:x,alternativeHypotheses:a}}}class qe{constructor(e){b(this,"activeObservation",null);b(this,"registry");b(this,"sequenceCounter");this.registry=e,this.sequenceCounter=new ne}isObserving(){return this.activeObservation!==null}startObservation(e,t=document){this.activeObservation&&this.stopObservation(t);const s=`obs_${Date.now()}_${Math.random().toString(36).slice(2,6)}`,n=Date.now(),i=k.inspectElement(e,this.registry),r=i.bestSelector,o=[],a=this.registry?this.registry.getOrCreateId(e,0):100;o.push({id:`evt_init_${s}`,sessionId:s,timestamp:0,sequence:1,wallClockTime:n,type:"DOM_MUTATION_ADD",category:"DOM",source:"BROWSER_RUNTIME",targetNodeId:a,targetSelector:r,payload:{node:{id:a,nodeType:1,tagName:i.tag,attributes:i.attributes,textContent:i.text,children:[],parentId:null},parentId:null,index:0}});const c=new MutationObserver(u=>{const h=Date.now()-n;for(const g of u)if(g.type==="childList"){for(let p=0;p0&&(m=$e.analyze(n,a)),{observationId:t,targetSelector:n,targetNodeId:((d=r.forensics)==null?void 0:d.logicalNodeId)||void 0,startTime:i,endTime:u,durationMs:h,initialState:r,finalState:p,disappeared:y,disappearanceReason:v,mutations:a.filter(f=>f.category==="DOM"),diagnostics:a.filter(f=>f.category==="ERROR"||f.category==="CONSOLE"),networkEvents:a.filter(f=>f.category==="NETWORK"),screenshots:c,correlationReport:m}}}class Pe{constructor(e={}){b(this,"isExplicitModeActive",!1);b(this,"isGlobalShortcutActive",!1);b(this,"highlighterEl",null);b(this,"badgeEl",null);b(this,"lastSelectedElement",null);b(this,"options",{});b(this,"onMouseMoveBound");b(this,"onClickBound");b(this,"onKeyDownBound");b(this,"onGlobalClickBound");this.options=e,this.onMouseMoveBound=this.handleMouseMove.bind(this),this.onClickBound=this.handleClick.bind(this),this.onKeyDownBound=this.handleKeyDown.bind(this),this.onGlobalClickBound=this.handleGlobalCtrlShiftClick.bind(this),this.initGlobalShortcutListener()}initGlobalShortcutListener(){typeof window>"u"||this.isGlobalShortcutActive||(window.addEventListener("click",this.onGlobalClickBound,!0),this.isGlobalShortcutActive=!0)}startPicker(e){typeof document>"u"||(e&&(this.options={...this.options,...e}),!this.isExplicitModeActive&&(this.isExplicitModeActive=!0,this.ensureHighlighter(),document.body&&(document.body.style.cursor="crosshair"),window.addEventListener("mousemove",this.onMouseMoveBound,!0),window.addEventListener("click",this.onClickBound,!0),window.addEventListener("keydown",this.onKeyDownBound,!0)))}stopPicker(){this.isExplicitModeActive&&(this.isExplicitModeActive=!1,typeof document<"u"&&document.body&&(document.body.style.cursor="default"),this.removeHighlighter(),typeof window<"u"&&(window.removeEventListener("mousemove",this.onMouseMoveBound,!0),window.removeEventListener("click",this.onClickBound,!0),window.removeEventListener("keydown",this.onKeyDownBound,!0)))}getLastSelectedElement(){return this.lastSelectedElement}setSelectedElement(e){let t;return"tag"in e&&"bestSelector"in e&&typeof e.getAttribute!="function"?t=e:(t=k.inspectElement(e,this.options.nodeRegistry),this.flashSelection(e)),this.lastSelectedElement=t,this.options.onSelected&&this.options.onSelected(t),t}handleGlobalCtrlShiftClick(e){if(!e.ctrlKey||!e.shiftKey)return;const t=e.target;if(!t||this.isExtensionOwned(t))return;e.preventDefault(),e.stopPropagation(),e.stopImmediatePropagation();const s=this.setSelectedElement(t);this.notifyExtension(s)}handleMouseMove(e){if(!this.isExplicitModeActive)return;const t=e.target;if(!t||this.isExtensionOwned(t)){this.hideHighlighter();return}this.updateHighlighter(t)}handleClick(e){if(!this.isExplicitModeActive)return;const t=e.target;if(!t||this.isExtensionOwned(t))return;e.preventDefault(),e.stopPropagation(),e.stopImmediatePropagation();const s=this.setSelectedElement(t);this.notifyExtension(s),this.stopPicker()}handleKeyDown(e){e.key==="Escape"&&this.isExplicitModeActive&&(e.preventDefault(),this.stopPicker(),this.options.onCanceled&&this.options.onCanceled())}isExtensionOwned(e){return!!(e.id==="forensic-recorder-floating-host"||e.id==="forensic-inspect-highlighter"||e.closest("#forensic-recorder-floating-host")||e.closest("#forensic-inspect-highlighter")||e.hasAttribute("data-forensic-internal")||e.closest("[data-forensic-internal]"))}ensureHighlighter(){if(typeof document>"u"||this.highlighterEl)return;const e=this.options.highlightColor||"#0ea5e9",t=document.createElement("div");t.id="forensic-inspect-highlighter",t.setAttribute("data-forensic-internal","true"),t.style.position="fixed",t.style.pointerEvents="none",t.style.zIndex="2147483640",t.style.border=`2px solid ${e}`,t.style.background="rgba(14, 165, 233, 0.18)",t.style.borderRadius="3px",t.style.boxShadow=`0 0 12px ${e}88`,t.style.transition="all 0.05s ease-out",t.style.display="none";const s=document.createElement("div");s.setAttribute("data-forensic-internal","true"),s.style.position="absolute",s.style.bottom="100%",s.style.left="0",s.style.transform="translateY(-4px)",s.style.background="#0f172a",s.style.color="#38bdf8",s.style.fontSize="11px",s.style.fontFamily="monospace",s.style.fontWeight="bold",s.style.padding="2px 6px",s.style.borderRadius="3px",s.style.boxShadow="0 2px 6px rgba(0,0,0,0.5)",s.style.whiteSpace="nowrap",s.style.pointerEvents="none",t.appendChild(s),document.body.appendChild(t),this.highlighterEl=t,this.badgeEl=s}updateHighlighter(e){if(this.ensureHighlighter(),!this.highlighterEl||!this.badgeEl)return;const t=e.getBoundingClientRect();this.highlighterEl.style.display="block",this.highlighterEl.style.left=`${t.left}px`,this.highlighterEl.style.top=`${t.top}px`,this.highlighterEl.style.width=`${Math.max(1,t.width)}px`,this.highlighterEl.style.height=`${Math.max(1,t.height)}px`;const s=e.tagName.toLowerCase(),n=e.id?`#${e.id}`:"",i=e.className&&typeof e.className=="string"?"."+e.className.split(/\s+/)[0]:"",r=`${Math.round(t.width)}×${Math.round(t.height)}`;this.badgeEl.textContent=`<${s}${n}${i}> [${r}]`}hideHighlighter(){this.highlighterEl&&(this.highlighterEl.style.display="none")}removeHighlighter(){this.highlighterEl&&this.highlighterEl.parentElement&&this.highlighterEl.remove(),this.highlighterEl=null,this.badgeEl=null}flashSelection(e){if(typeof document>"u"||!e.getBoundingClientRect)return;const t=e.getBoundingClientRect(),s=document.createElement("div");s.setAttribute("data-forensic-internal","true"),s.style.position="fixed",s.style.left=`${t.left}px`,s.style.top=`${t.top}px`,s.style.width=`${Math.max(1,t.width)}px`,s.style.height=`${Math.max(1,t.height)}px`,s.style.border="2px solid #22c55e",s.style.background="rgba(34, 197, 94, 0.25)",s.style.zIndex="2147483645",s.style.pointerEvents="none",s.style.transition="opacity 0.6s ease-out",document.body.appendChild(s),setTimeout(()=>{s.style.opacity="0",setTimeout(()=>s.remove(),600)},400)}notifyExtension(e){var t;try{typeof chrome<"u"&&((t=chrome.runtime)!=null&&t.sendMessage)&&chrome.runtime.sendMessage({type:"ELEMENT_SELECTED",elementInfo:e,timestamp:Date.now()})}catch{}}destroy(){this.stopPicker(),typeof window<"u"&&window.removeEventListener("click",this.onGlobalClickBound,!0),this.isGlobalShortcutActive=!1}}class ge{static getCrcTable(){if(this.crcTable)return this.crcTable;const e=new Uint32Array(256);for(let t=0;t<256;t++){let s=t;for(let n=0;n<8;n++)s=s&1?3988292384^s>>>1:s>>>1;e[t]=s>>>0}return this.crcTable=e,e}static crc32(e,t=0,s=e.length){const n=this.getCrcTable();let i=4294967295;for(let r=t;r>>8^n[(i^e[r])&255];return(i^4294967295)>>>0}static adler32(e){let t=1,s=0;for(let n=0;n>>0}static createPNG(e){const t=Math.max(1,Math.min(1920,Math.floor(e.width))),s=Math.max(1,Math.min(1080,Math.floor(e.height))),n=e.backgroundColor||[15,23,42,255],i=e.headerColor||[56,189,248,255],r=e.borderColor||[99,102,241,255],o=1+t*4,a=new Uint8Array(o*s),c=Math.min(30,Math.floor(s*.2));for(let d=0;d=e.length,g=new Uint8Array(5+u);g[0]=h?1:0,g[1]=u&255,g[2]=u>>>8&255;const p=~u&65535;g[3]=p&255,g[4]=p>>>8&255,g.set(e.subarray(n,n+u),5),t.push(g),n+=u}const i=t.reduce((c,u)=>c+u.length,0)+2+4,r=new Uint8Array(i);let o=0;r[o++]=120,r[o++]=1;for(const c of t)r.set(c,o),o+=c.length;const a=this.adler32(e);return r[o++]=a>>>24&255,r[o++]=a>>>16&255,r[o++]=a>>>8&255,r[o++]=a&255,r}static writeChunk(e,t,s,n){const i=n.length,r=new DataView(e.buffer,e.byteOffset,e.byteLength);r.setUint32(t,i,!1),t+=4;const o=new Uint8Array(4+i);for(let c=0;c<4;c++){const u=s.charCodeAt(c);e[t+c]=u,o[c]=u}t+=4,i>0&&(e.set(n,t),o.set(n,4),t+=i);const a=this.crc32(o);return r.setUint32(t,a,!1),t+=4,t}}b(ge,"crcTable",null);const Q=500;class Ue{constructor(e,t){b(this,"history",[]);b(this,"undoStack",[]);b(this,"redoStack",[]);b(this,"counter",0);b(this,"transaction",null);this.doc=e,this.registry=t}mutate(e){var h;const t=`mut_${Date.now().toString(36)}_${++this.counter}`,s=Date.now();let n;try{n=this.resolveTarget(e.target)}catch(g){return this.failure(t,e,null,g.message,Date.now()-s)}const i=this.snapshotState(n);let r=null,o=null,a,c=!0;try{const g=this.applyOperation(t,e,n);g&&(this.transaction?this.transaction.undoRecords.push(g):(this.undoStack.push(g),this.redoStack=[]));const y=(n.isConnected!==void 0?n.isConnected:this.doc.contains(n))?n:this.doc.querySelector(i.selector)||n;r=this.snapshotState(y),o=this.quickDiff(i,r,n)}catch(g){c=!1,a=g.message,r=null}const u={mutationId:t,operation:e.operation,success:c,before:i,after:r,diff:o,affectedSelector:c?i.selector:null,durationMs:Date.now()-s,error:a,undoable:c&&(this.transaction?this.transaction.undoRecords.length>0:this.undoStack.length>0)};return this.transaction&&this.transaction.steps.push({stepId:`step_${this.transaction.steps.length+1}`,mutation:u}),this.pushHistory({mutationId:t,transactionId:(h=this.transaction)==null?void 0:h.id,timestamp:Date.now(),operation:e.operation,targetSelector:i.selector,success:c,summary:`${e.operation} on ${i.selector}${o?` (+${o.added}/-${o.removed}/~${o.changed})`:""}`,undoApplied:!1,redoApplied:!1}),u}beginTransaction(){if(this.transaction)throw new Error(`TRANSACTION_ALREADY_OPEN: ${this.transaction.id} — commit or rollback first.`);return this.transaction={id:`tx_${Date.now().toString(36)}_${++this.counter}`,steps:[],undoRecords:[]},this.transaction.id}commitTransaction(e){if(!this.transaction)throw new Error("NO_OPEN_TRANSACTION: begin a transaction before committing.");const t=this.transaction,s=Date.now();let n=!0,i;if(e)try{n=e({id:t.id,steps:t.steps})!==!1,n||(i="VERIFY_FAILED: caller verification rejected the transaction state.")}catch(o){n=!1,i=`VERIFY_ERROR: ${o.message}`}if(!n)return this.rollbackInternal(t,i||"VERIFY_FAILED",s);this.undoStack.push(...t.undoRecords),this.undoStack.length>Q&&this.undoStack.splice(0,this.undoStack.length-Q),this.redoStack=[];const r=this.summaryOf(t);return this.transaction=null,{transactionId:t.id,committed:!0,rolledBack:!1,steps:t.steps,durationMs:Date.now()-s,finalStateSummary:r}}rollbackTransaction(e){if(!this.transaction)throw new Error("NO_OPEN_TRANSACTION: begin a transaction before rolling back.");const t=this.transaction;return this.rollbackInternal(t,e||"ROLLBACK_REQUESTED",Date.now())}rollbackInternal(e,t,s){for(const i of[...e.undoRecords].reverse())try{this.applyUndo(i)}catch{}const n=this.summaryOf(e);return this.transaction=null,{transactionId:e.id,committed:!1,rolledBack:!0,steps:e.steps,error:t,durationMs:Date.now()-s,finalStateSummary:n}}undo(){const e=this.transaction?this.transaction.undoRecords:this.undoStack,t=e.pop();if(!t)return{success:!1,message:"Nothing to undo — the mutation history is empty."};try{this.applyUndo(t)}catch(s){return e.push(t),{success:!1,mutationId:t.mutationId,message:`UNDO_FAILED: ${s.message}`}}return this.redoStack.push(t),this.markHistory(t.mutationId,"undo"),{success:!0,mutationId:t.mutationId,message:`Undid ${t.operation} on ${t.targetSelector}.`}}redo(){const e=this.redoStack.pop();if(!e)return{success:!1,message:"Nothing to redo — no undone mutation is pending."};try{const t=this.resolveTarget({selector:e.targetSelector}),s={operation:e.operation,target:{selector:e.targetSelector}};return this.reapplyRecord(e,t,s)?((this.transaction?this.transaction.undoRecords:this.undoStack).push(e),this.markHistory(e.mutationId,"redo"),{success:!0,mutationId:e.mutationId,message:`Redid ${e.operation} on ${e.targetSelector}.`}):(this.redoStack.push(e),{success:!1,mutationId:e.mutationId,message:"REDO_FAILED: target state diverged — cannot safely reapply."})}catch(t){return this.redoStack.push(e),{success:!1,mutationId:e.mutationId,message:`REDO_FAILED: ${t.message}`}}}getHistory(e=100){return this.history.slice(-e)}getUndoDepth(){return this.transaction?this.transaction.undoRecords.length:this.undoStack.length}getRedoDepth(){return this.redoStack.length}getOpenTransactionId(){var e;return((e=this.transaction)==null?void 0:e.id)||null}preview(e){var t;try{const s=this.resolveTarget(e.target),n=[];let i=1;(e.operation==="set_inner_html"||e.operation==="set_outer_html")&&(n.push("HTML replacement can destroy descendant node identity — captured regions targeting children may become stale."),i=s.querySelectorAll("*").length+1),(e.operation==="remove_element"||e.operation==="unwrap_element")&&(n.push("Removal is destructive; the undo record preserves the full serialized subtree."),i=s.querySelectorAll("*").length+1),e.operation==="move_element"&&!e.parent&&n.push("No parent target supplied — move requires payload.parent."),e.operation==="wrap_element"&&!e.newElementHtml&&n.push("No wrapper HTML supplied — a neutral
wrapper will be generated.");const r=He(e,s);return{valid:n.filter(o=>o.includes("requires")||o.includes("No parent")).length===0,operation:e.operation,target:{selector:this.snapshotState(s).selector,tag:s.tagName.toLowerCase()},expectedChange:r,affectedNodes:i,warnings:n}}catch(s){return{valid:!1,operation:e.operation,target:{selector:String(((t=e.target)==null?void 0:t.selector)||""),tag:""},expectedChange:"—",affectedNodes:0,warnings:[],error:s.message}}}applyOperation(e,t,s){var r;const n=this.snapshotState(s).selector,i=t.operation;switch(i){case"set_attribute":{if(!t.attribute)throw new Error("ATTRIBUTE_REQUIRED: payload.attribute is missing.");const o=s.getAttribute(t.attribute);return s.setAttribute(t.attribute,t.value??""),this.undoFor(e,i,n,{kind:o===null?"remove-attribute":"restore-attribute",attribute:t.attribute,value:o})}case"remove_attribute":{if(!t.attribute)throw new Error("ATTRIBUTE_REQUIRED: payload.attribute is missing.");const o=s.getAttribute(t.attribute);if(o===null)throw new Error(`ATTRIBUTE_NOT_PRESENT: "${t.attribute}" is not set on ${n}.`);return s.removeAttribute(t.attribute),this.undoFor(e,i,n,{kind:"restore-attribute",attribute:t.attribute,value:o})}case"set_text":{const o=s.textContent||"";return s.textContent=t.text??"",this.undoFor(e,i,n,{kind:"restore-text",text:o})}case"replace_text":{if(!t.text||!t.replacement)throw new Error("TEXT_PATTERNS_REQUIRED: payload.text (search) and payload.replacement are required.");const o=s.textContent||"";return s.textContent=o.split(t.text).join(t.replacement),this.undoFor(e,i,n,{kind:"restore-text",text:o})}case"set_inner_html":{const o=s.innerHTML;return s.innerHTML=t.html??"",this.undoFor(e,i,n,{kind:"restore-outer-html",outerHtml:s.outerHTML.replace(t.html??"",o)||void 0,text:o,attribute:"__inner"})}case"set_outer_html":{const o=s.outerHTML,a=s.parentElement;if(!a)throw new Error("ORPHAN_ELEMENT: element has no parent — cannot replace outer HTML.");const c=this.doc.createComment(`mcpdom_undo_${e}`);s.replaceWith(c);const u=this.doc.createElement("template");u.innerHTML=t.html??"";const h=u.content.firstElementChild;return h?c.replaceWith(h):c.replaceWith(this.doc.createTextNode(t.html??"")),this.undoFor(e,i,n,{kind:"reinsert-node",outerHtml:o,parentSelector:this.snapshotState(a).selector,nextSiblingSelector:this.siblingSelector(h||s)})}case"add_class":{const o=Array.from(s.classList);for(const a of t.classes||[])s.classList.add(a);return this.undoFor(e,i,n,{kind:"restore-classes",classes:o})}case"remove_class":{const o=Array.from(s.classList);for(const a of t.classes||[])s.classList.remove(a);return this.undoFor(e,i,n,{kind:"restore-classes",classes:o})}case"replace_class":{const o=Array.from(s.classList);for(const a of t.classes||[])s.classList.remove(a);return t.value&&s.classList.add(t.value),this.undoFor(e,i,n,{kind:"restore-classes",classes:o})}case"set_style":{const o=this.doc.defaultView;if(!(o!=null&&o.getComputedStyle))throw new Error("STYLE_UNAVAILABLE: computed style API is unavailable in this context.");const a={};for(const c of Object.keys(t.style||{}))a[c]=o.getComputedStyle(s).getPropertyValue(c),s.style.setProperty(c,t.style[c]);return this.undoFor(e,i,n,{kind:"restore-style",style:a})}case"remove_style":{const o={};for(const a of t.classes||[])o[a]=s.style.getPropertyValue(a),s.style.removeProperty(a);return this.undoFor(e,i,n,{kind:"restore-style",style:o})}case"add_element":{const o=t.parent?this.resolveTarget(t.parent):s,a=this.doc.createElement("template");a.innerHTML=t.newElementHtml??"
";const c=a.content.firstElementChild;if(!c)throw new Error("INVALID_HTML: payload.newElementHtml does not produce an element.");switch(t.position||"append"){case"before":s.before(c);break;case"after":s.after(c);break;case"prepend":o.prepend(c);break;default:o.appendChild(c)}return this.undoFor(e,i,n,{kind:"remove-node",attribute:this.snapshotState(c).selector})}case"remove_element":{const o=s.outerHTML,a=s.parentElement,c=s.nextElementSibling;return s.remove(),this.undoFor(e,i,n,{kind:"reinsert-node",outerHtml:o,parentSelector:a?this.snapshotState(a).selector:void 0,nextSiblingSelector:c?this.snapshotState(c).selector:null})}case"replace_element":{const o=s.outerHTML,a=s.parentElement,c=this.doc.createElement("template");c.innerHTML=t.newElementHtml??"
";const u=c.content.firstElementChild;if(!u)throw new Error("INVALID_HTML: payload.newElementHtml does not produce an element.");const h=s.nextElementSibling;return s.replaceWith(u),this.undoFor(e,i,n,{kind:"reinsert-node",outerHtml:o,parentSelector:a?this.snapshotState(a).selector:void 0,nextSiblingSelector:h?this.snapshotState(h).selector:null})}case"move_element":{if(!t.parent)throw new Error("PARENT_REQUIRED: payload.parent is required for move_element.");const o=this.resolveTarget(t.parent),a=s.outerHTML,c=s.parentElement,u=s.nextElementSibling,h=t.position==="before"||t.position==="prepend"?o.firstElementChild:null;return o[t.position==="prepend"?"prepend":"appendChild"](s),this.undoFor(e,i,n,{kind:"restore-position",parentSelector:c?this.snapshotState(c).selector:void 0,nextSiblingSelector:u?this.snapshotState(u).selector:h?this.snapshotState(h).selector:null,outerHtml:a})}case"wrap_element":{const o=this.doc.createElement("template");o.innerHTML=t.newElementHtml||'
';const a=o.content.firstElementChild;if(!a)throw new Error("INVALID_HTML: wrapper template produced no element.");const c=s.parentElement,u=s.nextElementSibling;return s.replaceWith(a),a.appendChild(s),this.undoFor(e,i,n,{kind:"restore-position",parentSelector:c?this.snapshotState(c).selector:void 0,nextSiblingSelector:u?this.snapshotState(u).selector:null})}case"unwrap_element":{const o=s.outerHTML,a=s.parentElement;if(!a)throw new Error("ORPHAN_ELEMENT: cannot unwrap a root-level element.");const c=s.nextElementSibling,u=Array.from(s.children);for(const h of u)a.insertBefore(h,s);return s.remove(),this.undoFor(e,i,n,{kind:"reinsert-node",outerHtml:o,parentSelector:this.snapshotState(a).selector,nextSiblingSelector:c?this.snapshotState(c).selector:null})}case"clone_subtree":{const o=t.parent?this.resolveTarget(t.parent):s.parentElement||s,a=s.cloneNode(!0);if(t.copyAttributes!==!1)for(const c of Array.from(a.attributes))c.name==="id"&&a.removeAttribute("id");return(r=o.appendChild)==null||r.call(o,a),this.undoFor(e,i,n,{kind:"remove-node",attribute:this.snapshotState(a).selector})}default:throw new Error(`UNKNOWN_OPERATION: ${i} is not a supported DOM mutation.`)}}applyUndo(e){const t=e.inverse;switch(t.kind){case"restore-outer-html":{const s=this.resolveTarget({selector:e.targetSelector});if(t.outerHtml!==void 0){const n=this.doc.createElement("template");n.innerHTML=t.outerHtml;const i=n.content.firstElementChild;i&&s.replaceWith(i)}else t.attribute==="__inner"&&(s.innerHTML=t.text||"");break}case"reinsert-node":{const s=t.parentSelector?this.resolveTarget({selector:t.parentSelector}):this.doc.body,n=this.doc.createElement("template");n.innerHTML=t.outerHtml||"";const i=n.content.firstElementChild;if(!i)throw new Error("UNDO_CORRUPT: serialized subtree could not be restored.");const r=t.nextSiblingSelector?this.safeResolve(t.nextSiblingSelector):null;s.insertBefore(i,r);break}case"remove-node":{const s=this.safeResolve(t.attribute||e.targetSelector);s&&s.remove();break}case"restore-attribute":{this.resolveTarget({selector:e.targetSelector}).setAttribute(t.attribute,t.value??"");break}case"remove-attribute":{this.resolveTarget({selector:e.targetSelector}).removeAttribute(t.attribute);break}case"restore-text":{const s=this.resolveTarget({selector:e.targetSelector});s.textContent=t.text||"";break}case"restore-classes":{const s=this.resolveTarget({selector:e.targetSelector});s.removeAttribute("class");for(const n of t.classes||[])s.classList.add(n);break}case"restore-style":{const s=this.resolveTarget({selector:e.targetSelector});s.style.removeProperty("all");for(const[n,i]of Object.entries(t.style||{}))s.style.setProperty(n,i);break}case"restore-position":{const s=this.doc.createElement("template");s.innerHTML=t.outerHtml||"";const n=s.content.firstElementChild;if(!n)throw new Error("UNDO_CORRUPT: serialized subtree could not be restored.");const i=this.safeResolve(e.targetSelector);i&&i.remove();const r=t.parentSelector?this.safeResolve(t.parentSelector):this.doc.body,o=t.nextSiblingSelector?this.safeResolve(t.nextSiblingSelector):null;(r||this.doc.body).insertBefore(n,o);break}}}reapplyRecord(e,t,s){var i;const n=e.inverse;switch(e.operation){case"set_attribute":return(n.kind==="restore-attribute"||n.kind==="remove-attribute")&&s.value!==void 0?(t.setAttribute(s.attribute||n.attribute||"",s.value),!0):!1;case"add_class":{for(const r of s.classes||[])t.classList.add(r);return(((i=s.classes)==null?void 0:i.length)||0)>0}case"remove_class":{for(const r of s.classes||n.classes||[])t.classList.remove(r);return!0}case"set_text":return s.text!==void 0?(t.textContent=s.text,!0):!1;case"set_inner_html":return s.html!==void 0?(t.innerHTML=s.html,!0):!1;default:return!1}}resolveTarget(e){if(!e)throw new Error("TARGET_REQUIRED: mutation requires a target.");if(typeof e=="string"&&(e={selector:e}),e.selector){try{const t=this.doc.querySelectorAll(e.selector);if(t.length===1)return t[0];if(t.length>1)return Array.from(t).find(n=>{try{return k.inspectElement(n).visibility.isVisible}catch{return!1}})||t[0]}catch(t){throw new Error(`TARGET_INVALID: ${t.message}`)}throw new Error(`TARGET_NOT_FOUND: selector "${e.selector}" matches no element.`)}if(e.xpath){try{const s=this.doc.evaluate(e.xpath,this.doc,null,9,null).singleNodeValue;if(s)return s}catch(t){throw new Error(`TARGET_INVALID_XPATH: ${t.message}`)}throw new Error("TARGET_NOT_FOUND: xpath matches no element.")}if(typeof e.nodeId=="number"&&this.registry){const t=this.registry.getNode(e.nodeId);if(t&&t.nodeType===1&&this.doc.contains(t))return t;throw new Error("TARGET_STALE: logical node id no longer resolves to an attached element.")}throw new Error("TARGET_INVALID: target has neither selector, xpath nor nodeId.")}safeResolve(e){try{return this.doc.querySelector(e)}catch{return null}}snapshotState(e){const t=k.inspectElement(e,this.registry),s=e.outerHTML.length>2e4?e.outerHTML.slice(0,2e4)+"…[truncated]":e.outerHTML;return{selector:t.bestSelector,outerHtml:s,attributes:this.attrsOf(e)}}attrsOf(e){const t={};for(const s of Array.from(e.attributes))t[s.name]=s.value.length>300?s.value.slice(0,300)+"…":s.value;return t}quickDiff(e,t,s){if(!t)return null;let n=0,i=0,r=0;const o=new Set(Object.keys(e.attributes)),a=new Set(Object.keys(t.attributes||{}));for(const u of o)a.has(u)||i++;for(const u of a)o.has(u)?e.attributes[u]!==t.attributes[u]&&r++:n++;e.outerHtml!==t.outerHtml&&n+i+r===0&&r++;const c=s.querySelectorAll?s.querySelectorAll("*").length:0;return{added:n,removed:i,changed:r,summary:`attributes +${n}/-${i}/~${r}; subtree nodes: ${c}`}}undoFor(e,t,s,n){return{mutationId:e,operation:t,targetSelector:s,inverse:n}}siblingSelector(e){try{return this.snapshotState(e).selector}catch{return null}}pushHistory(e){this.history.push(e),this.history.length>Q&&this.history.splice(0,this.history.length-Q)}markHistory(e,t){for(let s=this.history.length-1;s>=0;s--)if(this.history[s].mutationId===e){t==="undo"?this.history[s].undoApplied=!0:this.history[s].redoApplied=!0;return}}summaryOf(e){var n;const t=((n=this.doc.documentElement)==null?void 0:n.outerHTML.length)||0,s=e.steps.filter(i=>i.mutation.success).length;return{domLength:t,diffSummary:`${s}/${e.steps.length} mutations applied`}}failure(e,t,s,n,i){var r;return{mutationId:e,operation:t.operation,success:!1,before:s||{selector:String(((r=t.target)==null?void 0:r.selector)||"?"),outerHtml:"",attributes:{}},after:null,diff:null,affectedSelector:null,durationMs:i,error:n,undoable:!1}}}function He(l,e){switch(l.operation){case"set_attribute":return`attribute "${l.attribute}" will be set to "${(l.value??"").slice(0,40)}"`;case"remove_attribute":return`attribute "${l.attribute}" will be removed`;case"set_text":return`text content will be replaced (${(l.text||"").length} chars)`;case"replace_text":return`every occurrence of "${l.text}" will become "${l.replacement}"`;case"set_inner_html":return`inner HTML will be replaced (${(l.html||"").length} chars)`;case"set_outer_html":return"element (and subtree) will be replaced with provided HTML";case"add_class":return`classes ${(l.classes||[]).join(", ")} will be added`;case"remove_class":return`classes ${(l.classes||[]).join(", ")} will be removed`;case"replace_class":return`classes ${(l.classes||[]).join(", ")} will be replaced with "${l.value}"`;case"set_style":return`inline styles ${Object.keys(l.style||{}).join(", ")} will be set`;case"remove_style":return`inline styles ${(l.classes||[]).join(", ")} will be removed`;case"add_element":return`a new element will be inserted ${l.position||"append"} the target`;case"remove_element":return"the element and its subtree will be removed";case"replace_element":return"the element will be replaced with new HTML";case"move_element":return"the element will be moved into the specified parent";case"wrap_element":return"the element will be wrapped in a new container";case"unwrap_element":return"children will be lifted out and the wrapper removed";case"clone_subtree":return"a deep clone of the subtree will be appended";default:return"unknown operation"}}class Fe{constructor(){b(this,"executionCounter",0)}async execute(e,t,s={}){const n=Math.min(Math.max(s.timeoutMs??5e3,100),3e4),i=`js_${Date.now().toString(36)}_${++this.executionCounter}`,r=e.defaultView;if(!r)return this.result(i,"BLOCKED_BY_CONTEXT",0,t,[],{name:"NoWindow",message:"The document has no associated window — execution context unavailable."});const o=e.documentElement?e.documentElement.outerHTML.length:0,a=[],c=this.hookConsole(r,a);let u="EXECUTED_SUCCESSFULLY",h,g,p=o,y=!1;const v=Date.now();try{const f=this.buildRunner(r,t),w=new Promise((E,S)=>{var x;const T=setTimeout(()=>{y=!0,S(new Error(`Script timed out after ${n}ms`))},n);(x=T==null?void 0:T.unref)==null||x.call(T)});h=await Promise.race([f,w])}catch(f){y?u="TIMED_OUT":u="EXECUTED_WITH_ERROR",g={name:(f==null?void 0:f.name)||"Error",message:(f==null?void 0:f.message)||String(f),stack:f!=null&&f.stack?String(f.stack).slice(0,2e3):void 0}}const m=Date.now()-v;p=e.documentElement?e.documentElement.outerHTML.length:0,c();const d=this.serialize(h);return u==="EXECUTED_SUCCESSFULLY"&&d.serializationFailed&&(u="SERIALIZATION_FAILED",g={name:"SerializationError",message:d.message||"Result could not be serialized."}),{status:u,executionId:i,durationMs:m,result:u==="EXECUTED_SUCCESSFULLY"?d.text:void 0,error:g,consoleOutput:a.slice(0,100),domChanged:o!==p,domLengthBefore:o,domLengthAfter:p,world:s.world||"ISOLATED",timeoutMs:n,codePreview:t.length>300?t.slice(0,300)+"…":t}}buildRunner(e,t){const s=`(async function() { ${t} -})()`,n=e;if(typeof n.eval!="function")return Promise.reject(new Error("BLOCKED_BY_CONTEXT: window.eval is unavailable in this context."));try{const i=n.eval(s);return i&&typeof i.then=="function"?i:Promise.resolve(i)}catch(i){return Promise.reject(i)}}hookConsole(e,t){var o;const s=["log","warn","error","info","debug"],n={},i=e,r=100;for(const a of s){const c=(o=i.console)==null?void 0:o[a];if(typeof c=="function"){n[a]=c;try{i.console[a]=(...u)=>{t.length{for(const a of s)if(n[a])try{i.console[a]=n[a]}catch{}}}serialize(e){if(e===void 0)return{text:"undefined"};if(e===null)return{text:"null"};try{if(typeof e=="string")return{text:e.slice(0,5e3)};const t=JSON.stringify(e,be,1);return t===void 0?{serializationFailed:!0,message:"JSON.stringify returned undefined (circular or non-serializable structure)."}:{text:t.length>5e4?t.slice(0,5e4)+"…[truncated]":t}}catch(t){return{serializationFailed:!0,message:(t==null?void 0:t.message)||"Serialization failed."}}}result(e,t,s,n,i,r){return{status:t,executionId:e,durationMs:s,error:r,consoleOutput:i,domChanged:!1,domLengthBefore:0,domLengthAfter:0,world:"ISOLATED",timeoutMs:5e3,codePreview:n.length>300?n.slice(0,300)+"…":n}}}function be(l,e){var t;if(e&&typeof e=="object"&&e.nodeType===1){const s=e;return{__element:!0,tag:s.tagName.toLowerCase(),id:s.getAttribute("id")||void 0,selector:s.tagName.toLowerCase()+(s.getAttribute("id")?`#${s.getAttribute("id")}`:""),text:(s.textContent||"").trim().slice(0,60)}}return typeof e=="function"?{__function:!0,name:e.name||"anonymous"}:e&&e.nodeType===9?{__document:!0,url:(t=e.location)==null?void 0:t.href}:e}function Ve(l){try{if(typeof l=="string")return l;if(l instanceof Error)return`${l.name}: ${l.message}`;const e=JSON.stringify(l,be);return e===void 0?String(l):e}catch{return String(l)}}const ye={"desktop-full-hd":{width:1920,height:1080,category:"desktop"},"desktop-hd":{width:1366,height:768,category:"desktop"},"desktop-laptop":{width:1440,height:900,category:"desktop"},"desktop-xga":{width:1280,height:1024,category:"desktop"},"desktop-1024":{width:1024,height:768,category:"desktop"},"tablet-ipad":{width:768,height:1024,category:"tablet"},"tablet-ipad-pro":{width:1024,height:1366,category:"tablet"},"tablet-portrait":{width:768,height:1024,category:"tablet"},"tablet-landscape":{width:1024,height:768,category:"tablet"},"mobile-iphone-se":{width:375,height:667,category:"mobile"},"mobile-iphone-12":{width:390,height:844,category:"mobile"},"mobile-iphone-14-pro-max":{width:430,height:932,category:"mobile"},"mobile-pixel-7":{width:412,height:915,category:"mobile"},"mobile-galaxy-s8":{width:360,height:740,category:"mobile"},"mobile-small":{width:320,height:568,category:"mobile"},"test-a4":{width:800,height:600,category:"test"},"test-square":{width:512,height:512,category:"test"}},Ee={"iphone-13":{width:390,height:844,devicePixelRatio:3,userAgent:"Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1",touch:!0,category:"mobile"},"ipad-air":{width:820,height:1180,devicePixelRatio:2,userAgent:"Mozilla/5.0 (iPad; CPU OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1",touch:!0,category:"tablet"},"pixel-7":{width:412,height:915,devicePixelRatio:2.625,userAgent:"Mozilla/5.0 (Linux; Android 14; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36",touch:!0,category:"mobile"},"galaxy-s23":{width:384,height:800,devicePixelRatio:3,userAgent:"Mozilla/5.0 (Linux; Android 14; SM-S911B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36",touch:!0,category:"mobile"},"macbook-pro-16":{width:1728,height:1080,devicePixelRatio:2,userAgent:"Mozilla/5.0 (Macintosh; Intel Mac OS X 14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",touch:!1,category:"desktop"},"windows-desktop":{width:1920,height:1080,devicePixelRatio:1,userAgent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",touch:!1,category:"desktop"}};class ze{constructor(e){f(this,"original",null);f(this,"modified",!1);f(this,"activePreset",null);f(this,"activeDevice",null);this.doc=e}state(){const e=this.doc.defaultView;return{width:(e==null?void 0:e.innerWidth)||0,height:(e==null?void 0:e.innerHeight)||0,devicePixelRatio:(e==null?void 0:e.devicePixelRatio)||1,scrollX:(e==null?void 0:e.scrollX)||0,scrollY:(e==null?void 0:e.scrollY)||0,original:this.original,isModified:this.modified}}resize(e,t,s){const n=this.doc.defaultView,i={width:(n==null?void 0:n.innerWidth)||0,height:(n==null?void 0:n.innerHeight)||0},r=this.pageDigest();this.original||(this.original={...i});const o=this.applySize(e,t);this.modified=!0,this.activePreset=s||this.activePreset;const a=this.pageDigest();return{success:!0,applied:{width:o.width,height:o.height},previous:i,original:{...this.original},preset:s||void 0,beforeState:r,afterState:a,reversible:!0,mode:this.isSimulation()?"simulation":"browser-window"}}applyPreset(e){const t=ye[e];if(!t)throw new Error(`UNKNOWN_PRESET: "${e}". Available: ${Object.keys(ye).join(", ")}`);return this.resize(t.width,t.height,e)}emulateDevice(e){const t=Ee[e];if(!t)throw new Error(`UNKNOWN_DEVICE: "${e}". Available: ${Object.keys(Ee).join(", ")}`);const s=this.resize(t.width,t.height,`device:${e}`);this.activeDevice=e;const n=this.doc.defaultView;return n&&this.isSimulation()&&n.devicePixelRatio!==void 0&&(n.devicePixelRatio=t.devicePixelRatio),{device:e,resize:s,profile:{width:t.width,height:t.height,devicePixelRatio:t.devicePixelRatio,touch:t.touch,category:t.category},userAgentNote:this.isSimulation()?"User-Agent override requires the Chrome DevTools Protocol (real browser session); in this context the viewport, dpr and touch metadata are applied and the UA is reported but not enforced.":"User-Agent and touch behaviors are applied by the browser emulation layer.",userAgentApplied:!this.isSimulation()}}reset(){var s,n;const e={width:((s=this.doc.defaultView)==null?void 0:s.innerWidth)||0,height:((n=this.doc.defaultView)==null?void 0:n.innerHeight)||0},t=this.original?{...this.original}:{...e};return this.original&&this.applySize(this.original.width,this.original.height),this.modified=!1,this.activePreset=null,this.activeDevice=null,{success:!0,applied:{width:t.width,height:t.height},previous:e,original:{...t},reversible:!0,mode:this.isSimulation()?"simulation":"browser-window"}}runResponsiveTest(e,t={restore:!0}){var c,u,d,h;const s=t.restore!==!1,n=this.original?{...this.original}:{width:((c=this.doc.defaultView)==null?void 0:c.innerWidth)||0,height:((u=this.doc.defaultView)==null?void 0:u.innerHeight)||0};this.original||(this.original={...n});const i=e.map(p=>{this.applySize(p.width,p.height),this.modified=!0;const y=this.pageDigest();return{label:p.label,width:p.width,height:p.height,domLength:y.domLength,interactiveCount:y.interactiveCount,horizontalOverflow:this.hasHorizontalOverflow(),screenshotId:void 0}}),r=i.slice(1).map((p,y)=>({from:i[y].label,to:p.label,domLengthDelta:p.domLength-i[y].domLength,interactiveDelta:p.interactiveCount-i[y].interactiveCount}));let o={width:((d=i[i.length-1])==null?void 0:d.width)||0,height:((h=i[i.length-1])==null?void 0:h.height)||0},a=!1;return s&&(this.applySize(n.width,n.height),this.modified=!1,o={...n},a=!0),{success:!0,originalViewport:n,steps:i,restored:a,finalViewport:o,comparisons:r}}getActivePreset(){return this.activePreset}getActiveDevice(){return this.activeDevice}applySize(e,t){const s=Math.max(200,Math.min(7680,Math.round(e))),n=Math.max(200,Math.min(4320,Math.round(t))),i=this.doc.defaultView;return i&&(typeof i.innerWidth=="number"&&(i.innerWidth=s),typeof i.innerHeight=="number"&&(i.innerHeight=n),typeof i.outerWidth=="number"&&(i.outerWidth=s),typeof i.outerHeight=="number"&&(i.outerHeight=n)),{width:s,height:n}}pageDigest(){var t,s,n,i;const e=this.doc.querySelectorAll('a[href], button, input, select, textarea, [role="button"], [onclick]').length;return{url:((s=(t=this.doc.defaultView)==null?void 0:t.location)==null?void 0:s.href)||((n=this.doc.location)==null?void 0:n.href)||"",domLength:((i=this.doc.documentElement)==null?void 0:i.outerHTML.length)||0,interactiveCount:e}}hasHorizontalOverflow(){const e=this.doc.documentElement,t=this.doc.body,s=this.doc.defaultView;return!s||!e?!1:Math.max(e.scrollWidth||0,(t==null?void 0:t.scrollWidth)||0)>(s.innerWidth||e.clientWidth||0)+1}isSimulation(){return typeof globalThis.__FORENSIC_SIMULATION__<"u"}}const We=[/^css-/,/^jsx-/,/^sc-[A-Za-z]/,/^emotion/,/^chakra-/,/^mantine-/i,/^_ng[a-z]/,/^ng-/i,/^v-/,/^(?=.*\d)[a-z0-9]{6,12}$/i,/^data-v-/],Xe=["id","name","data-testid","data-test","data-id","data-qa","data-cy","data-component","data-role","aria-label","aria-labelledby","aria-describedby","role","type","href","for","title","alt","rel","placeholder"];function ve(l){let e=2166136261;for(let t=0;t>>0).toString(16).padStart(8,"0")}function ie(l){return We.some(e=>e.test(l))}function Ge(l){return Xe.includes(l)}function ce(l){const e=l.trim();return e?!!((e.match(/\d/g)||[]).length/e.length>.5||/^\d+[.,:\-/ ]+\d+/.test(e)||/\b\d{10,}\b/.test(e)):!1}function Ke(l,e=80){return Array.from(l.childNodes).filter(s=>s.nodeType===3).map(s=>(s.textContent||"").trim()).join(" ").replace(/\s+/g," ").slice(0,e)}function Ye(l,e){const t=[];let s=l;for(;s&&t.length!ie(b)),r=Ke(e),o=e.getBoundingClientRect(),a={width:Math.round(o.width),height:Math.round(o.height)},c=Ye(e,4),u=c.join(">"),h=Array.from(e.children||[]).slice(0,8).map(b=>b.tagName.toLowerCase()).join("|"),p=e.getAttribute("role")||(t!=null&&t.getComputedStyle,void 0)||je(e),y=ve(JSON.stringify({t:e.tagName.toLowerCase(),a:s,c:i.slice(0,4),r:p||null,anc:u,desc:h,txt:ce(r)?null:r.slice(0,40),d:a})),v=[];let m="low";return!s.id&&!s["data-testid"]&&!s.name&&(m="medium",v.push("no stable identity attribute")),n.length>0&&i.length===0&&(m=v.length?"high":"medium",v.push("all classes are framework-generated")),ce(r)&&(v.push("text appears dynamic"),m==="low"&&(m="medium")),e.tagName.toLowerCase().includes("-")&&(v.push("custom element (web component)"),m==="low"&&(m="medium")),{fingerprintId:`fp_${y}`,hash:y,tagHierarchy:c,stableAttributes:s,meaningfulText:r,classes:i,role:p||void 0,dimensions:a,ancestorPattern:u,descendantPattern:h,volatilityRisk:m,volatilityReasons:v}}compare(e,t){const s=[],n=e.tagHierarchy[0]===t.tagHierarchy[0]?1:0;s.push({name:"tag",score:n,weight:.15});const i=we(e.ancestorPattern.split(">"),t.ancestorPattern.split(">"));s.push({name:"ancestorPattern",score:i,weight:.2});const r=Je(e.stableAttributes,t.stableAttributes);s.push({name:"stableAttributes",score:r,weight:.25});const o=we(e.classes,t.classes);s.push({name:"classes",score:o,weight:.1});const a=(e.role||"")===(t.role||"")&&e.role?1:0;s.push({name:"role",score:a,weight:.1});const c=e.meaningfulText===t.meaningfulText&&e.meaningfulText?1:0;s.push({name:"text",score:c,weight:.1});const u=Ze(e.dimensions,t.dimensions);s.push({name:"dimensions",score:u,weight:.1});const d=s.reduce((h,p)=>h+p.score*p.weight,0);return{score:Math.round(d*1e3)/1e3,components:s}}}function je(l){switch(l.tagName.toLowerCase()){case"a":return l.getAttribute("href")?"link":void 0;case"button":return"button";case"nav":return"navigation";case"header":return"banner";case"footer":return"contentinfo";case"main":return"main";case"aside":return"complementary";case"article":return"article";case"form":return"form";case"input":{const t=l.getAttribute("type")||"text";return t==="checkbox"?"checkbox":t==="radio"?"radio":t==="button"||t==="submit"?"button":"textbox"}case"select":return"combobox";case"textarea":return"textbox";case"img":return"img";case"table":return"table";case"ul":case"ol":return"list";case"li":return"listitem";case"h1":case"h2":case"h3":case"h4":case"h5":case"h6":return"heading";default:return}}function we(l,e){if(!l.length&&!e.length)return 1;if(!l.length||!e.length)return 0;const t=new Set(e);return l.filter(n=>t.has(n)).length/Math.max(l.length,e.length)}function Je(l,e){const t=Object.keys(l),s=Object.keys(e);if(!t.length&&!s.length)return .5;if(!t.length||!s.length)return 0;let n=0,i=0;for(const r of t)r in e&&(i++,l[r]===e[r]&&n++);return i===0?0:n/Math.max(t.length,s.length)}function Ze(l,e){if(l.width===0&&l.height===0&&e.width===0&&e.height===0)return .5;const t=Se(l.width,e.width),s=Se(l.height,e.height);return(t+s)/2}function Se(l,e){if(l===e)return 1;if(l===0||e===0)return 0;const t=Math.min(l,e)/Math.max(l,e);return t>.9?1:t>.7?.5:0}const Qe=["data-testid","data-test","data-id","data-qa","data-cy","data-component","data-role","aria-label","name","id"],Te=/^[a-zA-Z][a-zA-Z0-9_-]*$/,et=/^[a-zA-Z0-9_ .:-]+$/;class Z{constructor(e){f(this,"doc");this.doc=e}generateCandidates(e){const t=[],s=e.tagName.toLowerCase(),n=e.getAttribute("id");if(n&&Te.test(n)){const u=`#${Ce(n)}`;t.push(this.evaluate(e,u,"id",1,["unique stable id"]))}for(const u of Qe){if(u==="id")continue;const d=e.getAttribute(u);if(d&&et.test(d)&&d.length<100){const h=`${s}[${u}="${Q(d)}"]`;t.push(this.evaluate(e,h,"semantic-attribute",.92,[`semantic attribute ${u}`]))}}const i=Array.from(e.classList||[]).filter(u=>!ie(u));if(i.length){const u=`${s}.${i.slice(0,3).map(Ce).join(".")}`;t.push(this.evaluate(e,u,"class",.72,i.length?["stable class names"]:[]))}const r=this.buildStructuralPath(e);r&&t.push(this.evaluate(e,r,"structural-path",.55,["position-based structural path"]));const o=B(e);if(o&&o.length>=2&&o.length<=60&&!ce(o)){const u=`${s}:nth-of-type(1)`,d=this.buildTextXPath(e,o);d&&(t.push({selector:u,strategy:"text-derived-xpath",confidence:.6,unique:this.isXPathUnique(d),reasons:[`matches text "${o.slice(0,30)}"`]}),t[t.length-1].xpath=d)}const a=this.buildAttributeFingerprintSelector(e);a&&t.push(this.evaluate(e,a,"attribute-fingerprint",.68,["combination of stable attributes"]));const c=new Map;for(const u of t){const d=u.strategy==="text-derived-xpath"?`xpath:${u.xpath}`:u.selector,h=c.get(d);(!h||u.confidence>h.confidence)&&c.set(d,u)}return Array.from(c.values()).sort((u,d)=>d.confidence-u.confidence)}bestSelector(e){const t=this.generateCandidates(e),s=t.find(n=>n.unique&&n.confidence>=.7)||t[0];return{selector:(s==null?void 0:s.selector)||e.tagName.toLowerCase(),strategy:(s==null?void 0:s.strategy)||"tag",confidence:(s==null?void 0:s.confidence)||.3}}buildXPath(e){const t=[];let s=e;for(;s&&s!==this.doc.documentElement;){const n=s.getAttribute("id");if(n&&Te.test(n)){t.unshift(`*[@id="${Q(n)}"]`);break}const i=s.parentElement;if(!i){t.unshift(s.tagName.toLowerCase());break}const o=Array.from(i.children).filter(a=>a.tagName===s.tagName).indexOf(s)+1;t.unshift(`${s.tagName.toLowerCase()}[${o}]`),s=i}return s===this.doc.documentElement&&(!t.length||!t[0].includes("@id"))&&t.unshift("html"),"//"+t.join("/")}buildTextXPath(e,t){try{const s=e.tagName.toLowerCase(),n=tt(t);return`//${s}[normalize-space(text())=${n}]`}catch{return null}}buildStructuralPath(e,t=4){const s=[];let n=e;for(;n&&s.lengthc.tagName===n.tagName);if(a.length>1){const c=a.indexOf(n)+1;s.unshift(`${o}:nth-of-type(${c})`)}else s.unshift(o);if(n=r,n===this.doc.body){s.unshift("body");break}if(n===this.doc.documentElement)break}const i=s.join(" > ");return i.includes("body")?i:"body > "+i}buildAttributeFingerprintSelector(e){const t=e.tagName.toLowerCase(),s=[],n=e.getAttribute("type");n&&s.push(`type="${Q(n)}"`);const i=e.getAttribute("href");i&&i.length<80&&!i.startsWith("javascript:")&&s.push(`href^="${Q(i.slice(0,40))}"`);const r=e.getAttribute("placeholder");return r&&r.length<60&&s.push(`placeholder="${Q(r)}"`),s.length>=2?`${t}[${s.join("][")}]`:null}evaluate(e,t,s,n,i){let r=!1,o=0;try{const c=this.doc.querySelectorAll(t);o=c.length,r=c.length===1&&c[0]===e}catch{return{selector:t,strategy:s,confidence:0,unique:!1,reasons:["invalid selector syntax"]}}let a=n;return o===0?(a=0,i.push("selector matched nothing (invalid candidate)")):o===1&&r?i.push("matches exactly this element"):(a=a*.4,i.push(`matches ${o} elements — ambiguous`)),{selector:t,strategy:s,confidence:Math.round(a*100)/100,unique:r,reasons:i}}isXPathUnique(e){try{return this.doc.evaluate(`count(${e})`,this.doc,null,4,null).numberValue===1}catch{return!1}}}function B(l){return Array.from(l.childNodes).filter(e=>e.nodeType===3).map(e=>(e.textContent||"").trim()).join(" ").replace(/\s+/g," ")}function Ce(l){return l.replace(/([^a-zA-Z0-9_\u00A0-\uFFFF-])/g,"\\$1")}function Q(l){return l.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function tt(l){return l.includes("'")?l.includes('"')?`concat(${l.split("'").map(e=>`'${e}'`).join(`, "'", `)})`:`"${l}"`:`'${l}'`}class st{constructor(e,t){f(this,"fingerprintEngine",new re);f(this,"counter",0);this.doc=e,this.registry=t}buildTarget(e,t="selector"){var d;const s=new Z(this.doc),n=s.generateCandidates(e),i=s.bestSelector(e),r=this.fingerprintEngine.fingerprint(e),o=L.inspectElement(e,this.registry),a=e.getBoundingClientRect();let c=i.confidence*.6;return r.volatilityRisk==="low"?c+=.3:r.volatilityRisk==="medium"&&(c+=.15),n.find(h=>h.unique&&h.confidence>=.9)&&(c+=.1),c=Math.max(.05,Math.min(1,c)),this.counter++,{targetId:`tgt_${Date.now().toString(36)}_${this.counter}`,tag:e.tagName.toLowerCase(),role:o.role||r.role,selector:i.selector,selectorCandidates:n,xpath:s.buildXPath(e),domPath:(((d=o.context)==null?void 0:d.parentChain)||[]).concat(i.selector).join(" > "),textFingerprint:r.meaningfulText,attributeFingerprint:JSON.stringify(r.stableAttributes),structuralFingerprint:r.hash,attributes:o.attributes||{},confidence:Math.round(c*100)/100,bounds:{x:Math.round(a.x),y:Math.round(a.y),width:Math.round(a.width),height:Math.round(a.height)},resolvedFrom:t}}resolveAndBuild(e){let t=null,s="unknown";typeof e=="string"&&(e={selector:e});const n=e;if(n.selectedElementRef&&(s="selectedElementRef"),!t&&n.selector)try{const i=this.doc.querySelectorAll(n.selector);if(i.length===0)return{error:`TARGET_NOT_FOUND: selector "${n.selector}" matches no element`};i.length>1?(t=nt(i,this.doc)||i[0],s+="+disambiguated"):(t=i[0],s="selector")}catch(i){return{error:`TARGET_INVALID: ${i.message}`}}if(!t&&n.xpath)try{t=this.doc.evaluate(n.xpath,this.doc,null,9,null).singleNodeValue,s="xpath"}catch(i){return{error:`TARGET_INVALID_XPATH: ${i.message}`}}if(!t&&typeof n.nodeId=="number"&&this.registry){const i=this.registry.getNode(n.nodeId);i&&i.nodeType===1&&this.doc.contains(i)&&(t=i,s="nodeId")}return!t&&n.coordinates&&(t=this.doc.elementFromPoint(n.coordinates.x,n.coordinates.y),s="coordinates"),t?{element:t,target:this.buildTarget(t,s)}:{error:"TARGET_NOT_FOUND: no usable resolution strategy succeeded"}}}function nt(l,e){for(const t of Array.from(l)){const s=t;try{if(L.inspectElement(s).visibility.isVisible)return s}catch{}}return null}class it{constructor(e){f(this,"fingerprintEngine",new re);this.doc=e}recover(e,t){var p;const s=[],n=[];let i=null;try{i=this.doc.querySelectorAll(e)}catch(y){s.push(`selector syntax error: ${y.message}`)}if(i&&i.length>0){s.push("selector still matches — no recovery needed");const y=i[0];return{recovered:!0,confidence:1,strategy:"original-selector",resolvedSelector:e,matchedElementInfo:Ie(y),alternatives:[],diagnostics:s,recommendation:"Original selector works; the earlier failure was transient (likely a navigation or render race)."}}s.push("selector no longer matches any element");const o=this.collectCandidates(t,s).map(y=>({element:y,score:this.scoreMatch(y,t)})).filter(y=>y.score.score>.35).sort((y,v)=>v.score.score-y.score.score);for(const y of o.slice(0,5)){const v=new Z(this.doc).bestSelector(y.element);n.push({selector:v.selector,confidence:Math.round(y.score.score*100)/100,strategy:"recovery-match"})}if(!o.length)return{recovered:!1,confidence:0,strategy:"none",alternatives:n,diagnostics:s,recommendation:"No sufficiently similar element exists. The region may have been removed, or the page structure changed fundamentally. Re-inspect the page and capture a new target."};const a=o[0],c=o.length>1?a.score.score-o[1].score.score:1;s.push(`best candidate score: ${a.score.score.toFixed(3)} (margin ${c.toFixed(3)})`);for(const y of a.score.components)y.score>0&&s.push(` - ${y.name}: ${(y.score*100).toFixed(0)}%`);if(a.score.score<.62||o.length>1&&c<.15)return{recovered:!1,confidence:Math.round(a.score.score*100)/100,strategy:"recovery-refused",resolvedSelector:(p=n[0])==null?void 0:p.selector,alternatives:n,diagnostics:s,recommendation:"Recovery refused: best match is not confident enough or too close to a competing element. Inspect alternatives manually before acting — refusing to avoid acting on a wrong element."};const h=new Z(this.doc).bestSelector(a.element).selector;return{recovered:!0,confidence:Math.round(a.score.score*100)/100,strategy:"fingerprint-recovery",resolvedSelector:h,matchedElementInfo:Ie(a.element),alternatives:n,diagnostics:s,recommendation:`Recovered target with ${(a.score.score*100).toFixed(0)}% confidence. Verify the resolved selector before destructive actions.`}}collectCandidates(e,t){var r,o;const s=new Set,n=this.doc.querySelectorAll(e.tag);let i=0;for(const a of Array.from(n))if(s.add(a),++i>=400)break;if((r=e.classes)!=null&&r.length){const a=e.classes.filter(c=>!ie(c));for(const c of a.slice(0,2))try{for(const u of Array.from(this.doc.querySelectorAll(`.${c}`)).slice(0,100))s.add(u)}catch{}}if((o=e.stableAttributes)!=null&&o.name)try{for(const a of Array.from(this.doc.querySelectorAll(`[name="${e.stableAttributes.name}"]`)))s.add(a)}catch{}if(e.parentSelector)try{for(const a of Array.from(this.doc.querySelectorAll(`${e.parentSelector} > ${e.tag}`)).slice(0,100))s.add(a)}catch{}return t.push(`collected ${s.size} candidate elements for scoring`),Array.from(s)}scoreMatch(e,t){const s=[],n=e.tagName.toLowerCase()===t.tag.toLowerCase()?1:0;s.push({name:"tag",score:n,weight:.15});const i=(t.text||"").trim().slice(0,40),r=B(e).slice(0,40),o=(e.textContent||"").trim().slice(0,40);let a=0;if(i){const g=r?r===i?1:le(i,r):0,b=o?o===i?1:le(i,o):0;a=Math.max(g,b)}s.push({name:"text",score:a,weight:.3});const c=new Set((t.classes||[]).filter(g=>!ie(g))),u=Array.from(e.classList||[]),d=c.size?u.filter(g=>c.has(g)).length/c.size:.5;s.push({name:"classes",score:d,weight:.2});const h=t.stableAttributes||{},p=Object.keys(h);let y=.5;if(p.length){let g=0;for(const b of p)e.getAttribute(b)===h[b]&&g++;y=g/p.length}s.push({name:"attributes",score:y,weight:.2});const v=t.childCount!==void 0?e.children.length===t.childCount?1:le(String(t.childCount),String(e.children.length)):.5;if(s.push({name:"childCount",score:v,weight:.05}),t.fingerprintHash){const g={fingerprintId:"snapshot",hash:t.fingerprintHash,tagHierarchy:[t.tag],stableAttributes:h,meaningfulText:i,classes:t.classes||[],dimensions:{width:0,height:0},ancestorPattern:"",descendantPattern:"",volatilityRisk:"medium",volatilityReasons:[]},b=this.fingerprintEngine.fingerprint(e),T=this.fingerprintEngine.compare(g,b);s.push({name:"fingerprint",score:T.score,weight:.1})}const m=s.reduce((g,b)=>g+b.score*b.weight,0);return{score:Math.max(0,Math.min(1,m)),components:s}}diagnose(e){const t=[];let s=!0,n=0,i,r=[];try{n=this.doc.querySelectorAll(e).length}catch(o){s=!1,i=o.message,t.push("Selector is syntactically invalid CSS.")}if(s&&n===0){t.push("Selector parses but matches nothing — element may be removed, re-rendered, or inside a shadow root."),r=this.relaxSelector(e);for(const o of r)try{if(this.doc.querySelectorAll(o).length>0){t.push(`Relaxed form "${o}" matches — the over-specific part of the selector is stale.`);break}}catch{}}return s&&n>1&&t.push(`Selector matches ${n} elements — it is ambiguous; use a more specific form or index.`),{selector:e,valid:s,matches:n,parseError:i,closestWorkingSelectors:r.filter(o=>{try{return this.doc.querySelectorAll(o).length>0}catch{return!1}}),diagnosis:t}}relaxSelector(e){const t=[],s=e.split(/[ >]+/).filter(Boolean);s.length>1&&(t.push(s.slice(0,-1).join(" ")),t.push(s[s.length-1]));const n=e.replace(/:nth-of-type\(\d+\)/g,"").replace(/\.[^. >#:[]+/g,(i,r,o)=>o[r-1]==="\\"?i:"");return n!==e&&n.trim()&&t.push(n.trim()),t}}function le(l,e){if(!l||!e)return 0;const t=Ae(l),s=Ae(e);if(t===s)return 1;if(t.includes(s)||s.includes(t))return .7;const n=new Set(t.split(/\s+/)),i=new Set(s.split(/\s+/));return Array.from(n).filter(o=>i.has(o)).length/Math.max(n.size,i.size)}function Ae(l){return l.toLowerCase().replace(/[^a-z0-9 ]/g," ").replace(/\s+/g," ").trim()}function Ie(l){return{tag:l.tagName.toLowerCase(),id:l.getAttribute("id")||void 0,text:B(l).slice(0,60),classes:Array.from(l.classList||[])}}class ue{constructor(e){f(this,"state");this.state=e>>>0,this.state===0&&(this.state=2654435769)}next(){this.state=this.state+1831565813>>>0;let e=this.state;return e=Math.imul(e^e>>>15,e|1),e^=e+Math.imul(e^e>>>7,e|61),((e^e>>>14)>>>0)/4294967296}range(e,t){return e+this.next()*(t-e)}int(e,t){return Math.floor(this.range(e,t+1))}chance(e){return this.next()setTimeout(t,e))}chance(){return this.rng.next()<.5}}const ot=[{ruleId:"red_key_password",kind:"key-pattern",pattern:"password|passwd|pwd",description:"Keys containing password/passwd/pwd",enabled:!0,userAdded:!1},{ruleId:"red_key_token",kind:"key-pattern",pattern:"token|jwt|bearer|auth|session.?id|secret|api.?key|client.?secret",description:"Keys containing token/jwt/auth/session-id/secret/api-key",enabled:!0,userAdded:!1},{ruleId:"red_key_credential",kind:"key-pattern",pattern:"credential|login|user.?pass|otp|2fa|mfa|verification",description:"Keys containing credential/login/otp/2fa/verification",enabled:!0,userAdded:!1},{ruleId:"red_key_payment",kind:"key-pattern",pattern:"card|payment|billing|iban|cvv|cvc|pan",description:"Keys containing card/payment/billing/iban/cvv",enabled:!0,userAdded:!1},{ruleId:"red_key_personal",kind:"key-pattern",pattern:"ssn|social.?security|national.?id|passport|tax.?id",description:"Keys containing personal identifier patterns",enabled:!0,userAdded:!1},{ruleId:"red_val_jwt",kind:"value-pattern",pattern:"eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+",description:"JWT-shaped tokens",enabled:!0,userAdded:!1},{ruleId:"red_val_bearer",kind:"value-pattern",pattern:"bearer\\s+[A-Za-z0-9._-]+",description:"Bearer tokens",enabled:!0,userAdded:!1},{ruleId:"red_val_long_hex",kind:"value-pattern",pattern:"\\b[a-f0-9]{32,}\\b",description:"32+ char hex strings (session/API ids)",enabled:!0,userAdded:!1},{ruleId:"red_val_sk",kind:"value-pattern",pattern:"\\b(sk|pk|rk)_[A-Za-z0-9_]{20,}\\b",description:"Stripe-style secret keys (sk_live_…)",enabled:!0,userAdded:!1},{ruleId:"red_attr_input_password",kind:"attribute-name",pattern:"value",description:"value attributes on password inputs handled by PrivacyEngine maskValue",enabled:!0,userAdded:!1},{ruleId:"red_attr_secret",kind:"attribute-name",pattern:"data-secret|data-token|data-api-key|secret|access.?token",description:"Secret-carrying attributes",enabled:!0,userAdded:!1}],at=[{exclusionId:"excl_mcpdom_overlay",selector:"[data-mcpdom-internal], [data-forensic-internal], #forensic-recorder-floating-host, #forensic-inspect-highlighter",reason:"MCPDOM-injected UI must never contaminate captured DOM (§68 clean capture)",userAdded:!1},{exclusionId:"excl_mcpdom_ids",selector:'[id^="forensic-"], [id^="mcpdom-"]',reason:"MCPDOM-namespaced nodes",userAdded:!1}],de="[REDACTED]";class he{constructor(e){f(this,"config");f(this,"base",new se);f(this,"compiledKeyPatterns",[]);f(this,"compiledValuePatterns",[]);f(this,"compiledAttrPatterns",[]);this.config={rules:[...ot],exclusions:[...at],stubMode:!0,...e},this.recompile()}recompile(){this.compiledKeyPatterns=[],this.compiledValuePatterns=[],this.compiledAttrPatterns=[];for(const e of this.config.rules){if(!e.enabled)continue;const t="i";try{switch(e.kind){case"key-pattern":this.compiledKeyPatterns.push(new RegExp(e.pattern,t));break;case"value-pattern":this.compiledValuePatterns.push(new RegExp(e.pattern,"i"));break;case"attribute-name":this.compiledAttrPatterns.push(new RegExp(`^(${e.pattern})$`,"i"));break}}catch{}}}getRules(){return[...this.config.rules]}setRuleEnabled(e,t){const s=this.config.rules.find(n=>n.ruleId===e);return s?(s.enabled=t,this.recompile(),!0):!1}addRule(e){const t=`red_custom_${this.config.rules.length+1}_${Date.now().toString(36)}`,s={...e,ruleId:t,userAdded:!0};return this.config.rules.push(s),this.recompile(),s}removeRule(e){const t=this.config.rules.findIndex(s=>s.ruleId===e);return t<0||!this.config.rules[t].userAdded?!1:(this.config.rules.splice(t,1),this.recompile(),!0)}getExclusions(){return[...this.config.exclusions]}addExclusion(e,t){const n={exclusionId:`excl_custom_${this.config.exclusions.length+1}_${Date.now().toString(36)}`,selector:e,reason:t,userAdded:!0};return this.config.exclusions.push(n),n}removeExclusion(e){const t=this.config.exclusions.findIndex(s=>s.exclusionId===e);return t<0||!this.config.exclusions[t].userAdded?!1:(this.config.exclusions.splice(t,1),!0)}isSensitiveKey(e){return this.compiledKeyPatterns.some(t=>t.test(e))}redactValue(e){let t=e;for(const s of this.compiledValuePatterns)s.test(t)&&(t=t.replace(new RegExp(s.source,"gi"),de));return t}redactByKeyValue(e,t){return this.isSensitiveKey(e)?this.config.stubMode?de:t:this.redactValue(t)}isSensitiveAttribute(e){return this.compiledAttrPatterns.some(t=>t.test(e))}redactAttributes(e){const t={};for(const[s,n]of Object.entries(e))this.isSensitiveAttribute(s)?t[s]=de:t[s]=this.redactValue(n);return t}cleanSubtree(e){const t=e.cloneNode(!0);for(const s of this.config.exclusions){let n=null;try{n=t.querySelectorAll(s.selector)}catch{continue}for(const i of Array.from(n))i.remove();try{if(t.matches(s.selector))return this.doclessEmptyStub(t)}catch{}}return t}isExcluded(e){for(const t of this.config.exclusions)try{if(e.matches(t.selector)||e.closest(t.selector))return!0}catch{}return!1}doclessEmptyStub(e){return e.innerHTML="",e.setAttribute("data-mcpdom-excluded","true"),e}toJSON(){return{rules:this.getRules(),exclusions:this.getExclusions(),stubMode:this.config.stubMode}}static fromJSON(e){return new he({rules:Array.isArray(e==null?void 0:e.rules)?e.rules:void 0,exclusions:Array.isArray(e==null?void 0:e.exclusions)?e.exclusions:void 0,stubMode:typeof(e==null?void 0:e.stubMode)=="boolean"?e.stubMode:void 0})}}const ge='a[href], button, input, select, textarea, [role="button"], [role="link"], [role="tab"], [onclick], [tabindex]';function X(l,e){return{items:l.slice(0,e),truncated:l.length>e}}function k(l,e,t,s,n,i){return{analyzer:l,summary:e,count:t,items:s,warnings:n,truncated:i}}function D(l){try{return L.inspectElement(l).bestSelector}catch{return l.tagName.toLowerCase()}}const ct=l=>{const e=Array.from(l.querySelectorAll("form")),t=e.map(n=>{const i=Array.from(n.querySelectorAll("input, select, textarea")).map(r=>({tag:r.tagName.toLowerCase(),type:r.getAttribute("type")||(r.tagName.toLowerCase()==="textarea"?"textarea":r.tagName.toLowerCase()==="select"?"select":"text"),name:r.getAttribute("name")||void 0,id:r.getAttribute("id")||void 0,required:r.hasAttribute("required"),pattern:r.getAttribute("pattern")||void 0,maxLength:r.getAttribute("maxlength")||void 0,placeholder:r.getAttribute("placeholder")||void 0,ariaLabel:r.getAttribute("aria-label")||void 0,autocomplete:r.getAttribute("autocomplete")||void 0,hasLabel:!!(r.getAttribute("id")&&l.querySelector(`label[for="${r.getAttribute("id")}"]`))||!!r.closest("label"),defaultValue:r.value!==void 0&&(r.getAttribute("type")||"text")!=="password"?String(r.value).slice(0,40):void 0}));return{selector:D(n),action:n.getAttribute("action")||void 0,method:(n.getAttribute("method")||"GET").toUpperCase(),id:n.getAttribute("id")||void 0,fieldCount:i.length,submitButton:n.querySelector('button[type="submit"], input[type="submit"]')?D(n.querySelector('button[type="submit"], input[type="submit"]')):void 0,validationAttributes:i.filter(r=>r.required||r.pattern).length,fields:i}}),s=X(t,50);return k("analyze_forms",`${e.length} form(s) with ${t.reduce((n,i)=>n+i.fieldCount,0)} total fields`,e.length,s.items,[],s.truncated)},lt=l=>{const e=Array.from(l.querySelectorAll("a[href]")),t=e.map(n=>({href:n.getAttribute("href")||"",text:B(n).slice(0,60),selector:D(n),rel:n.getAttribute("rel")||void 0,target:n.getAttribute("target")||void 0,download:n.hasAttribute("download"),external:/^https?:\/\//i.test(n.getAttribute("href")||"")&&!ut(n.getAttribute("href")||"",l),anchorOnly:(n.getAttribute("href")||"").startsWith("#")})),s=X(t,200);return k("extract_links",`${e.length} link(s): ${t.filter(n=>n.external).length} external, ${t.filter(n=>n.anchorOnly).length} anchors`,e.length,s.items,[],s.truncated)};function ut(l,e){var t,s,n,i;try{return new URL(l,((s=(t=e.defaultView)==null?void 0:t.location)==null?void 0:s.href)||"http://localhost").origin===(((i=(n=e.defaultView)==null?void 0:n.location)==null?void 0:i.origin)||"")}catch{return!1}}const dt=l=>{const e=Array.from(l.querySelectorAll("img")),t=Array.from(l.querySelectorAll("video")),s=Array.from(l.querySelectorAll("audio")),n=Array.from(l.querySelectorAll("canvas")),i=[],r=[...e.map(c=>({kind:"img",selector:D(c),src:(c.getAttribute("src")||"").slice(0,150),alt:c.getAttribute("alt"),width:c.getAttribute("width")||void 0,height:c.getAttribute("height")||void 0,naturalWidth:c.naturalWidth||void 0,naturalHeight:c.naturalHeight||void 0,lazy:c.getAttribute("loading")==="lazy",missingAlt:!c.hasAttribute("alt")})),...t.map(c=>{var u;return{kind:"video",selector:D(c),src:(c.getAttribute("src")||((u=c.querySelector("source"))==null?void 0:u.getAttribute("src"))||"").slice(0,150),controls:c.hasAttribute("controls"),autoplay:c.hasAttribute("autoplay"),muted:c.hasAttribute("muted"),poster:c.getAttribute("poster")||void 0}}),...s.map(c=>{var u;return{kind:"audio",selector:D(c),src:(c.getAttribute("src")||((u=c.querySelector("source"))==null?void 0:u.getAttribute("src"))||"").slice(0,150),controls:c.hasAttribute("controls")}}),...n.map(c=>({kind:"canvas",selector:D(c),width:c.width,height:c.height}))],o=r.filter(c=>c.missingAlt).length;o&&i.push(`${o} image(s) missing alt text (accessibility risk).`);const a=X(r,200);return k("analyze_media",`${e.length} images, ${t.length} videos, ${s.length} audios, ${n.length} canvases`,r.length,a.items,i,a.truncated)},ht=l=>{const e=l.defaultView,t=[],s={};if(e!=null&&e.getComputedStyle){const i=e.getComputedStyle(l.documentElement);for(let r=0;r({name:i,value:r}));return k("get_css_variables",`${n.length} CSS custom properties found`,n.length,n,t,!1)},gt=l=>{const e=l.defaultView,t=[],s=new Map;if(e!=null&&e.getComputedStyle)for(const i of Array.from(l.querySelectorAll("body, body *")).slice(0,800)){const r=e.getComputedStyle(i),o=r.fontFamily||"",a=r.fontSize||"",c=`${o.split(",")[0].replace(/["']/g,"").trim()} @ ${a}`;s.set(c,(s.get(c)||0)+1)}else t.push("getComputedStyle unavailable — font usage analysis requires rendered styles.");const n=Array.from(s.entries()).map(([i,r])=>({font:i,usage:r})).sort((i,r)=>r.usage-i.usage);return k("analyze_fonts",`${n.length} distinct font/size combinations`,n.length,n,t,!1)},pt=l=>{const e=l.defaultView,t=[],s=new Map;if(e!=null&&e.getComputedStyle)for(const i of Array.from(l.querySelectorAll("body, body *")).slice(0,800)){const r=e.getComputedStyle(i);for(const o of["color","background-color","border-top-color"]){const a=r.getPropertyValue(o);a&&a!=="rgba(0, 0, 0, 0)"&&s.set(a,(s.get(a)||0)+1)}}else{for(const i of Array.from(l.querySelectorAll("[style]")).slice(0,300)){const r=i.getAttribute("style")||"",o=/(color)\s*:\s*([^;]+)/gi;let a;for(;a=o.exec(r);)s.set(a[2].trim(),(s.get(a[2].trim())||0)+1)}t.push("getComputedStyle unavailable — palette from inline styles only.")}const n=Array.from(s.entries()).map(([i,r])=>({color:i,usage:r})).sort((i,r)=>r.usage-i.usage).slice(0,40);return k("extract_color_palette",`${s.size} distinct colors in use`,s.size,n,t,!1)},mt=l=>{const e=l.defaultView,t=[],s=[];if(!(e!=null&&e.getComputedStyle))return t.push("getComputedStyle unavailable — z-index analysis requires rendered styles."),k("detect_zindex_conflicts","unavailable",0,[],t,!1);const n=[];for(const i of Array.from(l.querySelectorAll("body *")).slice(0,1e3)){const r=e.getComputedStyle(i),o=r.zIndex;o&&o!=="auto"&&parseInt(o,10)>0&&n.push({selector:D(i),z:parseInt(o,10),position:r.position,stacking:r.position==="fixed"||r.position==="sticky"||r.opacity!=="1"||r.transform!=="none"?"creates-stacking-context":"plain"})}for(let i=0;i1e5&&s.push({zIndex:n[i].z,elements:[n[i].selector],note:"extremely high z-index — competes with platform overlays (MCPDOM uses 2147483640+)."})}return k("detect_zindex_conflicts",`${n.length} z-indexed elements, ${s.length} potential conflict(s)`,s.length,X(s,40).items,t,s.length>40)},ft=l=>{const e=l.defaultView,t=[],s=l.documentElement,n=l.body,i=Math.max((s==null?void 0:s.scrollWidth)||0,(n==null?void 0:n.scrollWidth)||0),r=(e==null?void 0:e.innerWidth)||(s==null?void 0:s.clientWidth)||0,o=i>r+1;if(o&&(t.push({issue:"horizontal-overflow",detail:`document scrollWidth ${i} exceeds viewport ${r}`}),e!=null&&e.getComputedStyle))for(const c of Array.from(l.querySelectorAll("body *")).slice(0,600)){const u=c.getBoundingClientRect();if(u.right>r+2&&u.width>100&&(t.push({issue:"element-exceeds-viewport",selector:D(c),right:Math.round(u.right),width:Math.round(u.width)}),t.length>15))break}let a=0;for(const c of Array.from(l.querySelectorAll(ge)).slice(0,500)){const u=c.getBoundingClientRect();(u.width===0||u.height===0)&&a++}return a&&t.push({issue:"zero-size-interactive-elements",count:a}),k("detect_layout_issues",o?`HORIZONTAL OVERFLOW: page is ${i-r}px wider than viewport`:"No horizontal overflow detected",t.length,t,[],!1)},bt=l=>{const e=Array.from(l.querySelectorAll(ge)),t=new Map,s=e.slice(0,300).map(n=>{const i=pe(n),r=i.role||n.tagName.toLowerCase();return t.set(r,(t.get(r)||0)+1),{selector:i.bestSelector,tag:i.tag,role:i.role,text:i.text.slice(0,40),visible:i.visibility.isVisible,disabled:n.disabled||n.hasAttribute("disabled"),inViewport:i.visibility.isInViewport}});return k("census_interactive_elements",`${e.length} interactive elements: ${Array.from(t.entries()).map(([n,i])=>`${n}×${i}`).join(", ")||"none"}`,e.length,s,[],e.length>300)};function pe(l){try{return L.inspectElement(l)}catch{return{tag:l.tagName.toLowerCase(),role:void 0,text:"",bestSelector:l.tagName.toLowerCase(),bounds:{x:0,y:0,width:0,height:0,top:0,right:0,bottom:0,left:0},visibility:{isVisible:!1,isInViewport:!1}}}}const yt=l=>{const e=["header","nav","main","aside","footer","article","section","figure","figcaption","mark","time","address","details","summary","dialog"],t=[];for(const i of e){const r=Array.from(l.querySelectorAll(i));if(r.length)for(const o of r.slice(0,20))t.push({tag:i,selector:D(o),role:o.getAttribute("role")||Et(i),text:B(o).slice(0,50),childCount:o.children.length})}const s=t.filter(i=>["banner","navigation","main","complementary","contentinfo"].includes(i.role)),n=[];return t.find(i=>i.tag==="main")||n.push("No
element — page lacks a primary landmark."),l.querySelectorAll("header").length>1&&n.push("Multiple
elements outside sections — ambiguous banner landmark."),k("detect_semantic_elements",`${t.length} semantic elements, ${s.length} landmarks`,t.length,X(t,100).items,n,t.length>100)};function Et(l){return{header:"banner",nav:"navigation",main:"main",aside:"complementary",footer:"contentinfo",article:"article",section:"region",form:"form"}[l]}const _e={analyze_forms:ct,extract_links:lt,analyze_media:dt,get_css_variables:ht,analyze_fonts:gt,extract_color_palette:pt,detect_zindex_conflicts:mt,detect_layout_issues:ft,census_interactive_elements:bt,detect_semantic_elements:yt,scan_accessibility_issues:l=>{var i;const e=[];for(const r of Array.from(l.querySelectorAll("img")).slice(0,200))r.hasAttribute("alt")||e.push({rule:"img-alt",severity:"error",selector:D(r),message:"Image is missing the alt attribute."});for(const r of Array.from(l.querySelectorAll("input:not([type=hidden]):not([type=submit]):not([type=button])")).slice(0,200)){const o=r.getAttribute("id");o&&l.querySelector(`label[for="${o}"]`)||r.closest("label")||r.getAttribute("aria-label")||r.getAttribute("aria-labelledby")||e.push({rule:"input-label",severity:"error",selector:D(r),message:"Form input has no associated label, aria-label or aria-labelledby."})}for(const r of Array.from(l.querySelectorAll('button, a[href], [role="button"]')).slice(0,300)){const o=B(r).trim(),a=r.getAttribute("aria-label");!o&&!a&&e.push({rule:"accessible-name",severity:"error",selector:D(r),message:"Interactive element has no accessible name (no text, no aria-label).",hint:r.querySelector("img[alt]")?"Contains an image — consider alt text or aria-label.":void 0})}const t=Array.from(l.querySelectorAll("h1, h2, h3, h4, h5, h6")).slice(0,100);let s=0;for(const r of t){const o=parseInt(r.tagName[1],10);s&&o>s+1&&e.push({rule:"heading-order",severity:"warning",selector:D(r),message:`Heading level jumps from h${s} to h${o}.`}),s=o}(i=l.documentElement)!=null&&i.getAttribute("lang")||e.push({rule:"html-lang",severity:"warning",selector:"html",message:"The element has no lang attribute."});const n=e.filter(r=>r.severity==="error").length;return k("scan_accessibility_issues",`${e.length} issue(s): ${n} errors, ${e.length-n} warnings`,e.length,X(e,100).items,[],e.length>100)},detect_dead_click_targets:l=>{const e=l.defaultView,t=[];for(const s of Array.from(l.querySelectorAll(ge)).slice(0,500)){const n=s.getBoundingClientRect(),i=e!=null&&e.getComputedStyle?e.getComputedStyle(s):null,r=n.width===0||n.height===0,o=i?i.pointerEvents==="none":!1,a=i?i.display==="none"||i.visibility==="hidden":!1,c=s.getAttribute("aria-hidden")==="true";(r||o||a||c)&&t.push({selector:D(s),tag:s.tagName.toLowerCase(),text:B(s).slice(0,30),reasons:[r&&"zero-size",o&&"pointer-events:none",a&&`hidden (${i?i.display:"?"}/${i?i.visibility:"?"})`,c&&"aria-hidden"].filter(Boolean)})}return k("detect_dead_click_targets",`${t.length} unreachable interactive element(s)`,t.length,X(t,80).items,[],t.length>80)},inventory_animations:l=>{const e=l.defaultView,t=[],s=[];if(!(e!=null&&e.getComputedStyle))return t.push("getComputedStyle unavailable — animation inventory requires rendered styles."),k("inventory_animations","unavailable",0,[],t,!1);for(const i of Array.from(l.querySelectorAll("body *")).slice(0,800)){const r=e.getComputedStyle(i),o=r.animationName!=="none"?`${r.animationName} ${r.animationDuration}`:null,a=r.transitionProperty!=="none"&&r.transitionProperty!=="all"?`${r.transitionProperty} ${r.transitionDuration}`:r.transitionProperty==="all"?`all ${r.transitionDuration}`:null;(o||a)&&s.push({selector:D(i),animation:o,transition:a,transitionTiming:r.transitionTimingFunction||void 0})}const n=s.filter(i=>i.animation&&i.animation.includes("infinite"));return n.length>5&&t.push(`${n.length} infinitely looping animations — may indicate decorative spinners or a stuck loading state.`),k("inventory_animations",`${s.length} animated/transitioning elements`,s.length,X(s,80).items,t,s.length>80)},map_frame_tree:l=>{const e=[],t=(n,i,r)=>{const o=Array.from(n.querySelectorAll("iframe, frame"));for(const a of o){const c=a.getAttribute("src")||"(no src)";let u=!1,d=null;try{const h=a.contentDocument;h&&(u=!0,d=h.querySelectorAll("*").length,r<3&&t(h,`${i} > ${a.tagName.toLowerCase()}[${c.slice(0,50)}]`,r+1))}catch{u=!1}e.push({path:`${i} > ${a.tagName.toLowerCase()}`,selector:D(a),src:c.slice(0,120),title:a.getAttribute("title")||void 0,name:a.getAttribute("name")||void 0,sandbox:a.getAttribute("sandbox")||void 0,accessible:u,childCount:d,limitation:u?void 0:"Same-origin policy blocks contentDocument access (cross-origin frame)."})}};t(l,"document",0);const s=e.filter(n=>!n.accessible).length;return k("map_frame_tree",`${e.length} frame(s), ${s} inaccessible (cross-origin)`,e.length,e,[],!1)},inventory_shadow_roots:l=>{const e=[],t=(s,n,i)=>{const r=(s instanceof ShadowRoot,Array.from(s.querySelectorAll("*")));for(const o of r)if(o.shadowRoot){const a=o.shadowRoot,c=`${n} > ${o.tagName.toLowerCase()}::shadowRoot(${a.mode})`;e.push({path:c.slice(0,200),hostSelector:D(o),hostTag:o.tagName.toLowerCase(),mode:a.mode,childCount:a.querySelectorAll("*").length,styles:a.querySelectorAll("style").length}),i<4&&t(a,c,i+1)}};return t(l.documentElement,"document",0),k("inventory_shadow_roots",`${e.length} open shadow root(s) found`,e.length,e,[],!1)},inspect_page_storage:l=>{const e=l.defaultView,t=new he,s=[],n=[];if(!(e!=null&&e.localStorage)||!(e!=null&&e.sessionStorage))return k("inspect_page_storage","Web Storage API unavailable in this context",0,[],["localStorage/sessionStorage are not accessible here (JSDOM limitation or sandboxed iframe)."],!1);try{for(let r=0;rr+(o.size||0),0);return k("inspect_page_storage",`${n.length} storage entries (~${i} bytes), sensitive keys redacted`,n.length,X(n,100).items,s,n.length>100)},get_performance_metrics:l=>{var i,r,o,a;const e=l.defaultView,t=[],s=e==null?void 0:e.performance;if(!(s!=null&&s.timing)&&!(s!=null&&s.getEntriesByType))return k("get_performance_metrics","Performance API unavailable",0,[],["window.performance is not exposed in this context."],!1);const n=[];try{const c=(r=(i=s.getEntriesByType)==null?void 0:i.call(s,"navigation"))==null?void 0:r[0];if(c)n.push({metric:"navigation-timing",domContentLoaded:Math.round(c.domContentLoadedEventEnd),loadComplete:Math.round(c.loadEventEnd),domInteractive:Math.round(c.domInteractive),type:c.type,redirectCount:c.redirectCount,sizeTransfer:c.transferSize});else if(s.timing){const h=s.timing;n.push({metric:"navigation-timing-legacy",domContentLoaded:h.domContentLoadedEventEnd-h.navigationStart,loadComplete:h.loadEventEnd-h.navigationStart,domInteractive:h.domInteractive-h.navigationStart})}const u=((o=s.getEntriesByType)==null?void 0:o.call(s,"paint"))||[];for(const h of u)n.push({metric:h.name,startTime:Math.round(h.startTime)});const d=((a=s.getEntriesByType)==null?void 0:a.call(s,"resource"))||[];if(d.length){const h=d.reduce((y,v)=>y+v.duration,0),p=[...d].sort((y,v)=>v.duration-y.duration).slice(0,5).map(y=>({url:String(y.name).slice(0,100),duration:Math.round(y.duration)}));n.push({metric:"resource-summary",count:d.length,totalDuration:Math.round(h),slowest:p})}s.memory&&n.push({metric:"memory",usedJSHeapMB:Math.round(s.memory.usedJSHeapSize/1048576*10)/10,totalJSHeapMB:Math.round(s.memory.totalJSHeapSize/1048576*10)/10})}catch(c){t.push(`performance read failed: ${c.message}`)}return k("get_performance_metrics",`${n.length} metric group(s)`,n.length,n,t,!1)},extract_seo_metadata:l=>{var r,o,a;const e=c=>{var u;return((u=l.querySelector(`meta[name="${c}"]`))==null?void 0:u.getAttribute("content"))||void 0},t=c=>{var u;return((u=l.querySelector(`meta[property="${c}"]`))==null?void 0:u.getAttribute("content"))||void 0},s=[{field:"title",value:l.title||void 0},{field:"description",value:e("description")},{field:"canonical",value:(r=l.querySelector('link[rel="canonical"]'))==null?void 0:r.getAttribute("href")},{field:"robots",value:e("robots")},{field:"viewport",value:e("viewport")},{field:"charset",value:(o=l.querySelector("meta[charset]"))==null?void 0:o.getAttribute("charset")},{field:"og:title",value:t("og:title")},{field:"og:description",value:t("og:description")},{field:"og:image",value:t("og:image")},{field:"og:url",value:t("og:url")},{field:"twitter:card",value:e("twitter:card")},{field:"language",value:(a=l.documentElement)==null?void 0:a.getAttribute("lang")}],n=l.querySelectorAll("h1").length,i=[];return n===0&&i.push("No h1 — page lacks a primary heading."),n>1&&i.push(`Multiple h1 elements (${n}).`),e("description")||i.push("No meta description."),s.push({field:"h1Count",value:n}),k("extract_seo_metadata",`SEO metadata extracted; ${i.length} warning(s)`,s.length,s,i,!1)},extract_structured_data:l=>{var t;const e=[];for(const s of Array.from(l.querySelectorAll('script[type="application/ld+json"]')))try{const n=JSON.parse(s.textContent||"{}");e.push({format:"JSON-LD",type:n["@type"]||(Array.isArray(n)?"array":"unknown"),data:n})}catch(n){e.push({format:"JSON-LD",type:"invalid-json",error:n.message})}for(const s of Array.from(l.querySelectorAll("[itemscope]")).slice(0,30)){const n=s.getAttribute("itemtype")||"unknown",i={};for(const r of Array.from(s.querySelectorAll("[itemprop]"))){const o=r.getAttribute("itemprop")||"",a=r.getAttribute("content")||r.getAttribute("href")||((t=r.textContent)==null?void 0:t.trim())||"";i[o]=a.slice(0,100)}e.push({format:"microdata",type:n.split("/").pop()||n,data:i})}return k("extract_structured_data",`${e.length} structured data block(s)`,e.length,e,[],!1)},extract_tables:l=>{const e=Array.from(l.querySelectorAll("table")),t=e.slice(0,30).map(s=>{var a,c,u;const n=Array.from(s.querySelectorAll("thead th, tr:first-child th")).map(d=>{var h;return((h=d.textContent)==null?void 0:h.trim())||""}),i=Array.from(s.querySelectorAll("tbody tr, tr")).filter(d=>!d.querySelector("th")).slice(0,50),r=i.map(d=>Array.from(d.querySelectorAll("td")).map(h=>(h.textContent||"").trim().slice(0,60))),o=(c=(a=s.querySelector("caption"))==null?void 0:a.textContent)==null?void 0:c.trim();return{selector:D(s),caption:o,columnCount:n.length||((u=r[0])==null?void 0:u.length)||0,rowCount:i.length,headers:n,rows:r}});return k("extract_tables",`${e.length} table(s)`,e.length,t,[],e.length>30)},extract_lists:l=>{const e=Array.from(l.querySelectorAll("ul, ol")),t=e.slice(0,60).map(s=>{const n=Array.from(s.querySelectorAll(":scope > li")).slice(0,40);return{selector:D(s),kind:s.tagName.toLowerCase(),ordered:s.tagName.toLowerCase()==="ol",itemCount:n.length,items:n.map(i=>B(i).slice(0,60)),nested:s.querySelectorAll("ul, ol").length}});return k("extract_lists",`${e.length} list(s)`,e.length,t,[],e.length>60)},analyze_page_content:l=>{const e=l.body,t=(e==null?void 0:e.innerText)||(e==null?void 0:e.textContent)||"",s=t.trim()?t.trim().split(/\s+/).length:0,n=Array.from(l.querySelectorAll("h1, h2, h3, h4, h5, h6")).map(c=>({level:parseInt(c.tagName[1],10),text:B(c).slice(0,80)})),i=l.querySelectorAll("p").length,r=i?Math.round(s/i):0,o=Math.round(s/220*10)/10,a=[{metric:"wordCount",value:s},{metric:"paragraphCount",value:i},{metric:"avgParagraphWords",value:r},{metric:"estimatedReadingMinutes",value:o},{metric:"headingCount",value:n.length},{metric:"imageCount",value:l.querySelectorAll("img").length},{metric:"linkDensity",value:Math.round(l.querySelectorAll("a[href]").length/Math.max(1,s)*1e3)/1e3},{metric:"headings",value:n.slice(0,50)}];return k("analyze_page_content",`${s} words, ${i} paragraphs, ~${o} min read`,a.length,a,[],!1)},search_dom:(l,e)=>{const t=String((e==null?void 0:e.query)||"").trim();if(!t)return k("search_dom","No query supplied",0,[],["Provide a text query; optionally tag/attr filters."],!1);const s=t.toLowerCase(),n=[],i=Math.min((e==null?void 0:e.limit)||50,200),r=Array.from(l.querySelectorAll("*"));for(const o of r){if(n.length>=i)break;if(e!=null&&e.tag&&o.tagName.toLowerCase()!==String(e.tag).toLowerCase())continue;const a=B(o),c=Array.from(o.attributes);let u=0,d="";o.tagName.toLowerCase().includes(s)&&(u+=.2,d="tag match"),a.toLowerCase().includes(s)&&a.length<200&&(u+=.6,d="text match");for(const h of c)if(h.name.toLowerCase().includes(s)||h.value.length<100&&h.value.toLowerCase().includes(s)){u+=.4,d=`attribute ${h.name} match`;break}if(e!=null&&e.attr){const h=String(e.attr).toLowerCase(),p=e.attrValue?String(e.attrValue).toLowerCase():null;if(c.find(v=>v.name.toLowerCase()===h&&(!p||v.value.toLowerCase().includes(p))))u+=.5;else continue}if(u>0){const h=pe(o);n.push({selector:h.bestSelector,tag:h.tag,role:h.role,text:h.text.slice(0,60),score:Math.round(u*100)/100,reason:d,visible:h.visibility.isVisible,bounds:{x:Math.round(h.bounds.x),y:Math.round(h.bounds.y),w:Math.round(h.bounds.width),h:Math.round(h.bounds.height)}})}}return n.sort((o,a)=>a.score-o.score),k("search_dom",`${n.length} element(s) match "${t}"`,n.length,n,[],n.length>=i)},inventory_ctas:l=>{var t;const e=[];for(const s of Array.from(l.querySelectorAll('button, a[class*="btn"], a[class*="button"], input[type="submit"], [role="button"]')).slice(0,100)){const n=pe(s);e.push({selector:n.bestSelector,tag:n.tag,text:n.text.slice(0,50),styleHint:(t=s.getAttribute("class"))==null?void 0:t.slice(0,60),primary:/primary|cta|submit|main/i.test(s.getAttribute("class")||"")||s.type==="submit",visible:n.visibility.isVisible})}return k("inventory_ctas",`${e.length} call-to-action element(s)`,e.length,e,[],!1)},detect_focus_traps:l=>{const e=[];for(const s of Array.from(l.querySelectorAll('[role="dialog"], [aria-modal="true"], dialog[open], .modal, [class*="modal"]')).slice(0,30)){const n=s.querySelectorAll('a[href], button, input, select, textarea, [tabindex]:not([tabindex="-1"])');e.push({selector:D(s),kind:s.getAttribute("role")||s.tagName.toLowerCase(),ariaModal:s.getAttribute("aria-modal"),focusableCount:n.length,firstFocusable:n[0]?D(n[0]):void 0,note:n.length===0?"Modal container has NO focusable elements — keyboard users are trapped.":void 0})}const t=l.querySelectorAll("[tabindex]>0");for(const s of Array.from(t).slice(0,20))e.push({selector:D(s),kind:"positive-tabindex",note:`tabindex=${s.tabIndex} breaks natural tab order.`});return k("detect_focus_traps",`${e.length} focus-management issue(s)/container(s)`,e.length,e,[],!1)},infer_responsive_breakpoints:l=>{const e=l.defaultView,t=[],s=new Set;for(const o of Array.from(l.querySelectorAll("style"))){const a=o.textContent||"",c=/@media[^{]*?\(\s*(?:min|max)-width\s*:\s*(\d+)(?:\.\d+)?px/g;let u;for(;u=c.exec(a);)s.add(parseInt(u[1],10))}for(const o of Array.from(l.querySelectorAll('link[rel="stylesheet"]')).slice(0,10)){const a=o.getAttribute("href")||"";if(/^\d+px$/.test(a)||a.includes("width=")){const c=a.match(/width=(\d+)/);c&&s.add(parseInt(c[1],10))}}for(const o of Array.from(l.querySelectorAll("img[srcset], source[srcset]")).slice(0,50)){const a=o.getAttribute("srcset")||"";for(const c of a.matchAll(/(\d+)w/g))s.add(parseInt(c[1],10))}e!=null&&e.matchMedia||t.push("matchMedia unavailable — live breakpoint probing skipped.");const n=Array.from(s).sort((o,a)=>o-a),i=n.map(o=>({breakpoint:o,note:o<=768?"mobile-class":o<=1024?"tablet-class":"desktop-class"})),r=e==null?void 0:e.innerWidth;if(r){const o=n.filter(a=>a<=r);i.unshift({breakpoint:`current viewport: ${r}px`,note:o.length?`below breakpoints: ${o.join(", ")}`:"no declared breakpoint below current width"})}return k("infer_responsive_breakpoints",`${n.length} breakpoint(s) inferred from CSS/srcset`,i.length,i,t,!1)},get_selection_state:l=>{var i;const e=l.defaultView,t=(i=e==null?void 0:e.getSelection)==null?void 0:i.call(e),s=l.activeElement,n=[{hasSelection:!!(t!=null&&t.toString()),selectedText:(t==null?void 0:t.toString().slice(0,200))||"",selectionRanges:(t==null?void 0:t.rangeCount)||0,activeElement:s?{tag:s.tagName.toLowerCase(),selector:D(s),editable:s.isContentEditable||["INPUT","TEXTAREA"].includes(s.tagName)}:null}];return k("get_selection_state",t!=null&&t.toString()?`Selection: "${t.toString().slice(0,40)}…"`:"No text selection",1,n,[],!1)}};function vt(l,e,t){const s=_e[l];return s?s(e,t):{analyzer:l,summary:`Unknown analyzer "${l}". Available: ${Object.keys(_e).join(", ")}`,count:0,items:[],warnings:[],truncated:!1}}const wt=2e3;class St{constructor(e=wt){f(this,"events",[]);f(this,"cap");f(this,"counter",0);this.cap=Math.max(10,e)}record(e,t,s={}){this.counter++;const n={eventId:`evt_${Date.now().toString(36)}_${this.counter}`,timestamp:Date.now(),kind:e,operationId:s.operationId,sessionId:s.sessionId,detail:t,data:s.data};return this.events.push(n),this.events.length>this.cap&&this.events.splice(0,this.events.length-this.cap),n}query(e){let t=this.events;e.kind&&(t=t.filter(n=>n.kind===e.kind)),e.operationId&&(t=t.filter(n=>n.operationId===e.operationId)),e.sinceTimestamp&&(t=t.filter(n=>n.timestamp>=e.sinceTimestamp));const s=e.limit&&e.limit>0?e.limit:200;return t.slice(-s)}size(){return this.events.length}toJSON(){return[...this.events]}}class Tt{constructor(){f(this,"counter",0);f(this,"operations",new Map)}begin(e){this.counter++;const t=`op_${Date.now().toString(36)}_${this.counter}`;return this.operations.set(t,{operationId:t,tool:e,startedAt:Date.now(),status:"RUNNING",timelineEventIds:[]}),t}end(e,t,s){const n=this.operations.get(e);n&&(n.endedAt=Date.now(),n.status=t,n.relatedError=s)}attachEvent(e,t){const s=this.operations.get(e);s&&s.timelineEventIds.push(t)}trace(e){const t=this.operations.get(e);return t?{...t,durationMs:t.endedAt?t.endedAt-t.startedAt:void 0}:null}recent(e=100){return Array.from(this.operations.values()).slice(-e).map(t=>({...t,durationMs:t.endedAt?t.endedAt-t.startedAt:void 0}))}}const xe=100;class Ct{constructor(e){f(this,"sessionId");f(this,"timeline",new St);f(this,"operations",new Tt);f(this,"tabs",new Map);f(this,"activeTabId",null);f(this,"startedAt",Date.now());f(this,"snapshots",[]);f(this,"commandHistory",[]);f(this,"annotationCount",0);f(this,"projectId");f(this,"tabCounter",0);f(this,"commandCounter",0);this.sessionId=e||`sess_${Date.now().toString(36)}`}registerTab(e,t,s){const n=e!==void 0?Array.from(this.tabs.values()).find(o=>o.browserTabId===e):void 0;if(n)return n.lastSeenAt=Date.now(),n.status="OPEN",n.url=t||n.url,n.title=s||n.title,n;this.tabCounter++;const i=`stab_${this.tabCounter}_${Date.now().toString(36)}`,r={sessionTabId:i,browserTabId:e,url:t,title:s,createdAt:Date.now(),lastSeenAt:Date.now(),status:"OPEN"};return this.tabs.set(i,r),this.timeline.record("TAB_OPENED",`tab ${i} registered (${t||"no url"})`,{sessionId:this.sessionId}),r}closeTab(e){const t=this.tabs.get(e);return t?(t.status="CLOSED",t.lastSeenAt=Date.now(),this.timeline.record("TAB_CLOSED",`tab ${e} closed`,{sessionId:this.sessionId}),!0):!1}switchTab(e){const t=this.tabs.get(e);return!t||t.status==="CLOSED"?!1:(this.activeTabId=e,this.timeline.record("TAB_SWITCHED",`active tab → ${e}`,{sessionId:this.sessionId}),!0)}getTabs(){return Array.from(this.tabs.values())}getActiveTab(){if(this.activeTabId){const e=this.tabs.get(this.activeTabId);if(e&&e.status==="OPEN")return e}return Array.from(this.tabs.values()).find(e=>e.status==="OPEN")||null}markAllStale(){let e=0;for(const t of this.tabs.values())t.status==="OPEN"&&(t.status="STALE",e++);return e}captureSnapshot(e,t,s){var a,c,u;const n=e.defaultView,i=((a=e.documentElement)==null?void 0:a.outerHTML)||"",r=e.querySelectorAll('a[href], button, input, select, textarea, [role="button"]').length,o={snapshotId:`snap_${Date.now().toString(36)}_${this.snapshots.length+1}`,timestamp:Date.now(),url:((c=n==null?void 0:n.location)==null?void 0:c.href)||((u=e.location)==null?void 0:u.href)||"",title:e.title||"",viewport:{width:(n==null?void 0:n.innerWidth)||0,height:(n==null?void 0:n.innerHeight)||0,scrollX:(n==null?void 0:n.scrollX)||0,scrollY:(n==null?void 0:n.scrollY)||0,devicePixelRatio:(n==null?void 0:n.devicePixelRatio)||1},domLength:i.length,domHash:ve(i),interactiveCount:r,selectedRegions:[],extensionEnabled:t,pendingMutations:s,annotationCount:this.annotationCount};return this.snapshots.push(o),this.snapshots.length>xe&&this.snapshots.splice(0,this.snapshots.length-xe),this.timeline.record("SNAPSHOT_CREATED",`snapshot ${o.snapshotId} (dom ${o.domLength}b)`,{sessionId:this.sessionId}),o}getSnapshot(e){return e?this.snapshots.find(t=>t.snapshotId===e)||null:this.snapshots[this.snapshots.length-1]||null}listSnapshots(){return this.snapshots.map(e=>({snapshotId:e.snapshotId,timestamp:e.timestamp,url:e.url,title:e.title,domLength:e.domLength,domHash:e.domHash}))}compareSnapshots(e,t){const s=["url","title","domLength","domHash","interactiveCount","extensionEnabled","annotationCount"],n=[];for(const r of s)e[r]!==t[r]&&n.push({field:r,before:e[r],after:t[r]});(e.viewport.width!==t.viewport.width||e.viewport.height!==t.viewport.height)&&n.push({field:"viewport",before:`${e.viewport.width}x${e.viewport.height}`,after:`${t.viewport.width}x${t.viewport.height}`});const i=t.domLength-e.domLength;return{identical:n.length===0,changes:n,domDelta:{beforeLength:e.domLength,afterLength:t.domLength,delta:i},summary:n.length===0?"States are identical.":`${n.length} field(s) changed; DOM size ${i>=0?"+":""}${i} bytes.`}}recordCommand(e,t,s,n,i){this.commandCounter++;const r=`cmd_${this.commandCounter}_${Date.now().toString(36)}`;return this.commandHistory.push({commandId:r,tool:e,args:t,outcome:s,timestamp:Date.now(),durationMs:n,error:i}),this.timeline.record("COMMAND_EXECUTED",`${e} → ${s}${i?` (${i})`:""}`,{sessionId:this.sessionId,data:{commandId:r}}),r}getCommandHistory(e=100){return this.commandHistory.slice(-e)}noteAnnotations(e){this.annotationCount=e}bindProject(e){this.projectId=e}getProjectId(){return this.projectId}summary(e,t,s,n){var i,r,o;return{sessionId:this.sessionId,startedAt:this.startedAt,url:((r=(i=e.defaultView)==null?void 0:i.location)==null?void 0:r.href)||((o=e.location)==null?void 0:o.href)||"",title:e.title||"",tabs:this.getTabs(),activeTabId:this.activeTabId,viewport:{width:t.width,height:t.height,isModified:t.isModified},extensionEnabled:s,snapshotCount:this.snapshots.length,commandCount:this.commandHistory.length,annotationCount:this.annotationCount,mutationHistoryCount:n.length,timelineEventCount:this.timeline.size(),projectId:this.projectId}}}const At=l=>{var e,t;try{const s=l.getBoundingClientRect();if(s.width===0&&s.height===0)return null;const n=((t=(e=l.ownerDocument)==null?void 0:e.defaultView)==null?void 0:t.innerWidth)||1920;return s.yn*1.5?"bottom":s.xn*.8?"right":"center"}catch{return null}},It={navigation:"navigation",banner:"header",contentinfo:"footer",complementary:"sidebar",main:"main",form:"form",search:"search",region:"section",dialog:"modal",alertdialog:"modal",table:"table",list:"list",combobox:"dropdown",button:"button",link:"link",textbox:"input",checkbox:"checkbox",radio:"radio",img:"image",article:"article"},_t={nav:"navigation",header:"header",footer:"footer",aside:"sidebar",main:"main",section:"section",article:"article",form:"form",table:"table",ul:"list",ol:"list",figure:"figure",dialog:"modal",button:"button",input:"input",select:"dropdown",textarea:"textarea",canvas:"canvas",video:"video",img:"image",h1:"heading",h2:"heading",h3:"heading"};function ee(l){return l.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"").replace(/_{2,}/g,"_").slice(0,48).replace(/_$/,"")}class xt{generate(e){return this.generateFromMeta({tagName:e.tagName.toLowerCase(),role:e.getAttribute("role")||void 0,text:B(e).trim(),ariaLabel:e.getAttribute("aria-label")||void 0,stableClass:Array.from(e.classList||[]).find(t=>/^[a-z][a-z0-9-]{2,}$/i.test(t)&&!Nt.has(t)),position:At(e),nearbyHeading:this.nearbyHeading(e)})}generateFromMeta(e){const t=[],s=[],n=e.role||Rt(e.tagName);if(n){const r=It[n]||n;s.push(r),t.push(`role=${n}`)}else{const r=_t[e.tagName]||e.tagName;s.push(r),t.push(`tag=${e.tagName}`)}if(e.ariaLabel&&(s.unshift(ee(e.ariaLabel)),t.push(`aria-label="${e.ariaLabel.slice(0,30)}"`)),e.text&&e.text.length<=40){const r=ee(e.text.split(/\s+/).slice(0,3).join(" "));r&&r.length>=2&&(s.push(r),t.push(`text="${e.text.slice(0,30)}"`))}if(e.nearbyHeading){const r=ee(e.nearbyHeading.split(/\s+/).slice(0,3).join(" "));r&&!s.includes(r)&&(s.push(r),t.push(`nearby-heading="${e.nearbyHeading.slice(0,30)}"`))}e.stableClass&&s.length<3&&(s.push(ee(e.stableClass)),t.push(`class=${e.stableClass}`)),e.tagName==="input"&&(s.some(r=>r.includes("input"))||(s.push("input"),t.push("tag=input"))),s.join("_").length<12&&e.position&&(s.push(e.position),t.push(`position=${e.position}`));let i=ee(s.join("_"))||"unnamed_region";return/^\d/.test(i)&&(i=`el_${i}`),{name:i,evidence:t}}nearbyHeading(e){let t=e.parentElement;for(let n=0;t&&n<4;n++){const i=t.querySelector('h1, h2, h3, h4, [role="heading"]');if(i)return B(i).trim().slice(0,40)||null;t=t.parentElement}let s=e.previousElementSibling;for(let n=0;s&&n<4;n++){if(/^H[1-4]$/.test(s.tagName)){const i=B(s).trim();if(i)return i.slice(0,40)}s=s.previousElementSibling}return null}}const Nt=new Set(["active","open","visible","hidden","selected","disabled","container","wrapper","root","item","col","row","flex","box","main","div","span","block"]);function Rt(l){switch(l){case"nav":return"navigation";case"header":return"banner";case"footer":return"contentinfo";case"aside":return"complementary";case"main":return"main";case"form":return"form";case"table":return"table";case"button":return"button";case"a":return"link";case"input":return"textbox";case"select":return"combobox";case"textarea":return"textbox";case"img":return"img";default:return null}}const Mt=["display","position","flex-direction","grid-template-columns","width","height","background-color","color","font-size","border-radius","overflow"];class kt{constructor(){f(this,"naming",new xt)}capture(e){const t=e.ownerDocument,s=new Z(t),n=new re,i=s.generateCandidates(e),r=s.bestSelector(e),o=n.fingerprint(e);let a=e,c=0,u="self";for(let g=0;g<3;g++){const b=a.parentElement;if(!b||b===t.body||b===t.documentElement)break;if(this.isMeaningfulContainer(b)){a=b,c=g+1,u="meaningful-ancestor";break}a=b,c=g+1}if(a===e){const g=e.parentElement;g&&g!==t.body&&e.querySelectorAll("*").length<4&&(a=g,c=1,u="direct-parent-fallback")}const d=this.boundedHtml(e,6e4),h=this.boundedHtml(a,12e4);L.inspectElement(e);const p=e.getBoundingClientRect(),y=t.defaultView,v={};if(y!=null&&y.getComputedStyle){const g=y.getComputedStyle(e);for(const b of Mt){const T=g.getPropertyValue(b);T&&T!=="none"&&T!=="auto"&&(v[b]=T)}}const m=e.parentElement;return{regionHtml:d,contextHtml:h,boundary:{strategy:u,ancestorLevels:c,note:c===0?"Region captured standalone (no meaningful ancestor within 3 levels).":`Context includes ${c} ancestor level(s) up to a meaningful container.`},selectorCandidates:i,bestSelector:r.selector,xpath:s.buildXPath(e),fingerprintHash:o.hash,dimensions:{width:Math.round(p.width),height:Math.round(p.height)},position:{x:Math.round(p.x),y:Math.round(p.y)},relevantStyles:v,parentInfo:m?{tag:m.tagName.toLowerCase(),selector:Ot(m),text:B(m).slice(0,60)}:void 0,childrenCount:e.children.length,childTags:Array.from(e.children).slice(0,12).map(g=>g.tagName.toLowerCase()),nameHint:this.naming.generate(e),fingerprintVolatility:o.volatilityRisk,volatilityReasons:o.volatilityReasons}}isMeaningfulContainer(e){const t=e.tagName.toLowerCase();if(["section","article","aside","main","nav","header","footer","form"].includes(t)||e.hasAttribute("id")||e.hasAttribute("data-testid")||e.getAttribute("role")||e.children.length>1&&e.querySelector(":scope > *:nth-child(3)"))return!0;const s=e.getAttribute("style")||"";return!!(s.includes("grid")||s.includes("flex"))}boundedHtml(e,t){const s=e.outerHTML;return s.length<=t?s:s.slice(0,t)+` -`}}function Ot(l){try{return new Z(l.ownerDocument).bestSelector(l).selector}catch{return l.tagName.toLowerCase()}}class Lt{constructor(e){f(this,"nodeRegistry");f(this,"snapshotEngine");f(this,"picker");f(this,"interactionEngine");f(this,"observer");f(this,"mutationEngines",new WeakMap);f(this,"viewportControllers",new WeakMap);f(this,"targetingEngines",new WeakMap);f(this,"jsEngine",new Fe);f(this,"fingerprintEngine",new re);f(this,"humanInteraction",new rt);f(this,"session",new Ct);f(this,"simulationTabs",[]);f(this,"simulationTabCounter",0);f(this,"simulationExtensions",[{id:"teledom@teledom",name:"TeleDOM Browser Intelligence Platform",version:"4.1.0",description:"The TeleDOM platform extension itself",enabled:!0,installType:"development",isApp:!1}]);f(this,"regionCapture",new kt);this.nodeRegistry=e||new z;const t=new se,s=new oe;this.snapshotEngine=new me(this.nodeRegistry,t,s),this.picker=new Ue({nodeRegistry:this.nodeRegistry}),this.interactionEngine=new De(this.nodeRegistry),this.observer=new Pe(this.nodeRegistry),this.picker.initGlobalShortcutListener(),this.interactionEngine.setTimingHook(async n=>{const i=this.humanInteraction.delay(n);i>0&&await new Promise(r=>setTimeout(r,i))})}getMutationEngine(e){let t=this.mutationEngines.get(e);return t||(t=new He(e,this.nodeRegistry),this.mutationEngines.set(e,t)),t}getViewportController(e){let t=this.viewportControllers.get(e);return t||(t=new ze(e),this.viewportControllers.set(e,t)),t}getTargetingEngine(e){let t=this.targetingEngines.get(e);return t||(t=new st(e,this.nodeRegistry),this.targetingEngines.set(e,t)),t}isSimulation(){return typeof globalThis.__FORENSIC_SIMULATION__<"u"}getPicker(){return this.picker}getInteractionEngine(){return this.interactionEngine}getObserver(){return this.observer}getNodeRegistry(){return this.nodeRegistry}async handleCommand(e,t=typeof document<"u"?document:{}){var o,a,c,u,d,h,p,y,v;const s=Date.now(),{id:n,command:i,payload:r}=e;try{switch(i){case"LIVE_PAGE_INSPECT":{const m=L.inspectPage(t);return this.success(n,i,m,s)}case"LIVE_ELEMENT_INSPECT":{const m=this.resolveTarget(r,t),g=L.inspectElement(m,this.nodeRegistry);return this.success(n,i,g,s)}case"GET_SELECTED_ELEMENT":{const m=this.picker.getLastSelectedElement();return this.success(n,i,m,s)}case"ELEMENT_PICKER_START":return this.picker.startPicker(),this.success(n,i,{pickerActive:!0},s);case"ELEMENT_PICKER_STOP":return this.picker.stopPicker(),this.success(n,i,{pickerActive:!1},s);case"LIVE_ELEMENT_INTERACT":{const m=r,g=await this.interactionEngine.interact(m,t);return this.success(n,i,g,s)}case"ELEMENT_OBSERVATION_START":{const m=this.resolveTarget(r,t),g=this.observer.startObservation(m,t);return this.success(n,i,g,s)}case"ELEMENT_OBSERVATION_STOP":{const m=this.observer.stopObservation(t);return this.success(n,i,m,s)}case"LIVE_DOM_SNAPSHOT":{if(((r==null?void 0:r.format)||"html")==="html"){const b=((o=t.documentElement)==null?void 0:o.outerHTML)||"";return this.success(n,i,{html:b},s)}const g=this.snapshotEngine.captureSnapshot(t,"live_session");return this.success(n,i,g,s)}case"LIVE_DOM_SUBTREE":{const m=this.resolveTarget(r,t),g=m.outerHTML||"",b=L.inspectElement(m,this.nodeRegistry);return this.success(n,i,{html:g,element:b},s)}case"GET_ELEMENT_VISUAL_STATE":{const m=this.resolveTarget(r,t),g=L.inspectVisualState(m);return this.success(n,i,g,s)}case"LIVE_PAGE_SCREENSHOT":case"LIVE_ELEMENT_SCREENSHOT":{const m=await this.handleScreenshotCapture(i,r,t);return this.success(n,i,m,s)}case"GET_TAB_CONSOLE_LOGS":{const{level:m,searchQuery:g,limit:b=100,clearAfterRead:T}=r||{};let w=typeof window<"u"&&window.__FORENSIC_CONSOLE_BUFFER__||[];if(m&&m!=="all"&&(w=w.filter(E=>E.level===m)),g){const E=String(g).toLowerCase();w=w.filter(C=>{var N,I;return((N=C.text)==null?void 0:N.toLowerCase().includes(E))||((I=C.source)==null?void 0:I.toLowerCase().includes(E))})}return b>0&&(w=w.slice(-b)),T&&typeof window<"u"&&window.__FORENSIC_CONSOLE_BUFFER__&&(window.__FORENSIC_CONSOLE_BUFFER__.length=0),this.success(n,i,{url:typeof window<"u"?window.location.href:"",title:t.title||"",totalCaptured:typeof window<"u"&&((a=window.__FORENSIC_CONSOLE_BUFFER__)==null?void 0:a.length)||w.length,returnedCount:w.length,logs:w},s)}case"GET_TAB_NETWORK_REQUESTS":{const{method:m,searchQuery:g,status:b,onlyErrors:T,limit:w=100,clearAfterRead:E}=r||{};let C=typeof window<"u"&&window.__FORENSIC_NETWORK_BUFFER__||[];if(m&&(C=C.filter(N=>{var I;return((I=N.method)==null?void 0:I.toUpperCase())===String(m).toUpperCase()})),b&&(C=C.filter(N=>N.status===Number(b))),T&&(C=C.filter(N=>N.error||N.status&&N.status>=400)),g){const N=String(g).toLowerCase();C=C.filter(I=>{var R;return(R=I.url)==null?void 0:R.toLowerCase().includes(N)})}return w>0&&(C=C.slice(-w)),E&&typeof window<"u"&&window.__FORENSIC_NETWORK_BUFFER__&&(window.__FORENSIC_NETWORK_BUFFER__.length=0),this.success(n,i,{url:typeof window<"u"?window.location.href:"",title:t.title||"",totalCaptured:typeof window<"u"&&((c=window.__FORENSIC_NETWORK_BUFFER__)==null?void 0:c.length)||C.length,returnedCount:C.length,requests:C},s)}case"CLOSE_TAB":{if(typeof globalThis.chrome<"u"&&((u=globalThis.chrome.runtime)!=null&&u.sendMessage)){const m=await new Promise(g=>{globalThis.chrome.runtime.sendMessage({type:"BROWSER_COMMAND_REQUEST",id:n,command:i,payload:r},b=>g(b))});if(m)return m}return this.isSimulation()?this.simulationCloseTab(r,t,n,i,s):typeof window<"u"?(setTimeout(()=>window.close(),100),this.success(n,i,{closed:!0,url:window.location.href,title:t.title},s)):this.success(n,i,{closed:!0},s)}case"RELOAD_TAB":{if(typeof globalThis.chrome<"u"&&((d=globalThis.chrome.runtime)!=null&&d.sendMessage)){const m=await new Promise(g=>{globalThis.chrome.runtime.sendMessage({type:"BROWSER_COMMAND_REQUEST",id:n,command:i,payload:r},b=>g(b))});if(m)return m}if(this.isSimulation()){const m=(r==null?void 0:r.mode)||"soft";return this.session.timeline.record("NAVIGATED",`tab reloaded (${m} mode)`),this.success(n,i,{reloaded:!0,mode:m,simulated:!0,url:((p=(h=t.defaultView)==null?void 0:h.location)==null?void 0:p.href)||"",title:t.title,note:"Node simulation context: DOM fixture retained; no real navigation occurs."},s)}return typeof window<"u"?(setTimeout(()=>window.location.reload(),100),this.success(n,i,{reloaded:!0,url:window.location.href,title:t.title},s)):this.success(n,i,{reloaded:!0},s)}case"OPEN_TAB":case"LIST_TABS":case"FOCUS_TAB":case"LIST_EXTENSIONS":case"RELOAD_EXTENSION":case"SET_EXTENSION_ENABLED":case"TOGGLE_EXTENSION":{if(this.isSimulation())return this.handleSimulationBackgroundCommand(n,i,r,t,s);if(typeof globalThis.chrome<"u"&&((y=globalThis.chrome.runtime)!=null&&y.sendMessage)){const m=await new Promise(g=>{globalThis.chrome.runtime.sendMessage({type:"BROWSER_COMMAND_REQUEST",id:n,command:i,payload:r},b=>g(b))});if(m)return m}return this.error(n,i,"BACKGROUND_EXECUTION_FAILED",`Command ${i} requires Chrome extension runtime`,s)}case"RESIZE_VIEWPORT":{const m=this.getViewportController(t);let g;if(r!=null&&r.preset)g=m.applyPreset(r.preset);else{const b=Number(r==null?void 0:r.width)||1280,T=Number(r==null?void 0:r.height)||800;g=m.resize(b,T)}return this.session.timeline.record("RESIZED",`viewport → ${g.applied.width}x${g.applied.height}`),this.success(n,i,g,s)}case"RESET_VIEWPORT":{const g=this.getViewportController(t).reset();return this.session.timeline.record("RESIZED",`viewport restored to ${g.applied.width}x${g.applied.height}`),this.success(n,i,g,s)}case"GET_VIEWPORT_STATE":{const m=this.getViewportController(t);return this.success(n,i,m.state(),s)}case"RUN_RESPONSIVE_TEST":{const m=this.getViewportController(t),g=(r==null?void 0:r.sizes)||Ut(),b=m.runResponsiveTest(g,{restore:(r==null?void 0:r.restore)!==!1});return this.success(n,i,b,s)}case"EMULATE_DEVICE":{const g=this.getViewportController(t).emulateDevice((r==null?void 0:r.device)||"pixel-7");return this.success(n,i,g,s)}case"EXECUTE_JS":case"EXECUTE_JS_AND_CAPTURE_CHANGES":{const m=String((r==null?void 0:r.code)||"");if(!m.trim())return this.error(n,i,"SCRIPT_EMPTY","payload.code is required.",s);const g=await this.jsEngine.execute(t,m,{timeoutMs:r==null?void 0:r.timeoutMs,world:(r==null?void 0:r.world)==="MAIN"?"MAIN":"ISOLATED"});return this.session.timeline.record("SCRIPT_EXECUTED",`${g.status} (${g.durationMs}ms)`),this.success(n,i,g,s)}case"DOM_MUTATE":{const g=this.getMutationEngine(t).mutate(r);return this.session.timeline.record("DOM_MUTATED",`${g.operation} on ${g.before.selector} → ${g.success?"OK":g.error}`),this.success(n,i,g,s)}case"DOM_MUTATE_TRANSACTION":{const m=this.getMutationEngine(t),g=(r==null?void 0:r.mode)||"begin";try{if(g==="begin"){const b=m.beginTransaction();return this.success(n,i,{transactionId:b,mode:g,open:!0},s)}if(g==="commit"){const b=m.commitTransaction();return this.session.timeline.record("DOM_MUTATED",`transaction ${b.transactionId} committed (${b.steps.length} steps)`),this.success(n,i,{...b,mode:g},s)}if(g==="rollback"){const b=m.rollbackTransaction(r==null?void 0:r.reason);return this.session.timeline.record("MUTATION_UNDONE",`transaction ${b.transactionId} rolled back`),this.success(n,i,{...b,mode:g},s)}return this.error(n,i,"INVALID_MODE",`mode must be begin|commit|rollback, got "${g}"`,s)}catch(b){return this.error(n,i,"DOM_MUTATION_FAILED",b.message,s)}}case"UNDO_DOM_MUTATION":{const g=this.getMutationEngine(t).undo();return g.success&&this.session.timeline.record("MUTATION_UNDONE",g.message),this.success(n,i,g,s)}case"REDO_DOM_MUTATION":{const g=this.getMutationEngine(t).redo();return g.success&&this.session.timeline.record("MUTATION_REDONE",g.message),this.success(n,i,g,s)}case"GET_MUTATION_HISTORY":{const m=this.getMutationEngine(t);return this.success(n,i,{entries:m.getHistory((r==null?void 0:r.limit)||100),undoDepth:m.getUndoDepth(),redoDepth:m.getRedoDepth(),openTransactionId:m.getOpenTransactionId()},s)}case"PREVIEW_DOM_MUTATION":{const g=this.getMutationEngine(t).preview(r);return this.success(n,i,g,s)}case"GENERATE_ELEMENT_TARGET":{const g=this.getTargetingEngine(t).resolveAndBuild((r==null?void 0:r.target)||(r==null?void 0:r.selector)||"");return"error"in g?this.error(n,i,"TARGET_NOT_FOUND",g.error,s):this.success(n,i,g.target,s)}case"RECOVER_SELECTOR":{const m=new it(t),g=(r==null?void 0:r.snapshot)||{},b=m.recover((r==null?void 0:r.selector)||"",g);return this.success(n,i,b,s)}case"GET_ELEMENT_ANCESTRY":{const m=this.resolveTarget(r,t);return this.success(n,i,Dt(m,t),s)}case"GET_ELEMENT_FINGERPRINT":{const m=this.resolveTarget(r,t),g=this.fingerprintEngine.fingerprint(m);return this.success(n,i,g,s)}case"GET_ELEMENT_RELATIONSHIPS":{const m=this.resolveTarget(r,t);return this.success(n,i,$t(m,t),s)}case"GET_ELEMENT_ACCESSIBILITY":{const m=this.resolveTarget(r,t);return this.success(n,i,qt(m),s)}case"GET_COMPUTED_STYLE":{const m=this.resolveTarget(r,t),g=t.defaultView;if(!(g!=null&&g.getComputedStyle))return this.error(n,i,"STYLE_UNAVAILABLE","getComputedStyle is unavailable in this context.",s);const b=g.getComputedStyle(m),T=Array.isArray(r==null?void 0:r.properties)&&r.properties.length?r.properties:["display","position","color","background-color","font-size","font-family","width","height","margin","padding","border","z-index","opacity","visibility","overflow","flex-direction","grid-template-columns"],w={};for(const E of T)w[E]=b.getPropertyValue(E);return this.success(n,i,{selector:L.inspectElement(m,this.nodeRegistry).bestSelector,styles:w},s)}case"ANALYZE_DOM":{const m=String((r==null?void 0:r.analyzer)||"");if(!m)return this.error(n,i,"ANALYZER_REQUIRED",'payload.analyzer is required (e.g. "analyze_forms").',s);const g=vt(m,t,r);return g.count===0&&g.warnings.length===0&&g.items.length===0&&g.summary.startsWith("Unknown analyzer")?this.error(n,i,"UNKNOWN_ANALYZER",g.summary,s):this.success(n,i,g,s)}case"DRAG_ELEMENT":{const m=this.resolveTarget(r==null?void 0:r.source,t),g=r!=null&&r.target?this.resolveTarget(r==null?void 0:r.target,t):null,b=await this.performDrag(m,g,r==null?void 0:r.offsets,t);return this.success(n,i,b,s)}case"SET_INPUT_CHECKED":{const g=this.resolveTarget(r,t);if(g.type!=="checkbox"&&g.type!=="radio")return this.error(n,i,"INPUT_TYPE_UNSUPPORTED",`Target input type "${g.type}" is not checkbox/radio.`,s);const b=g.checked;g.checked=(r==null?void 0:r.checked)!==!1;const T=[];for(const w of["input","change"])try{g.dispatchEvent(new t.defaultView.Event(w,{bubbles:!0})),T.push(w)}catch{}if(g.type==="radio"&&g.name)for(const w of Array.from(t.querySelectorAll(`input[type=radio][name="${g.name}"]`)))w!==g&&(w.checked=!1);return this.success(n,i,{success:!0,selector:L.inspectElement(g,this.nodeRegistry).bestSelector,inputType:g.type,checkedBefore:b,checkedAfter:g.checked,eventsFired:T},s)}case"PRESS_KEYBOARD_SHORTCUT":{const m=Array.isArray(r==null?void 0:r.keys)?r.keys:String((r==null?void 0:r.keys)||"Enter").split("+"),g=r!=null&&r.target?this.resolveTarget(r==null?void 0:r.target,t):t.activeElement||t.body;typeof g.focus=="function"&&g.focus();const b=[],T=t.defaultView;for(const w of m)for(const E of["keydown","keyup"])try{g.dispatchEvent(new((T==null?void 0:T.KeyboardEvent)||KeyboardEvent)(E,{key:w.trim(),bubbles:!0,cancelable:!0,ctrlKey:m.some(C=>/^(ctrl|control|cmd|meta)$/i.test(C))&&w!==m.find(C=>/^(ctrl|control|cmd|meta)$/i.test(C)),shiftKey:m.some(C=>/^shift$/i.test(C))&&w!=="Shift",altKey:m.some(C=>/^alt$/i.test(C))&&w!=="Alt"})),b.push(`${E}:${w}`)}catch{}return this.success(n,i,{success:!0,keys:m,targetSelector:L.inspectElement(g,this.nodeRegistry).bestSelector,eventsFired:b},s)}case"SCROLL_PAGE":{const m=t.defaultView;if(!m)return this.error(n,i,"NO_WINDOW","No window available for scrolling.",s);const g={x:m.scrollX||0,y:m.scrollY||0};let b;if(r!=null&&r.target||r!=null&&r.selector){const w=this.resolveTarget((r==null?void 0:r.target)||(r==null?void 0:r.selector),t);(v=w.scrollIntoView)==null||v.call(w,{behavior:(r==null?void 0:r.behavior)||"auto",block:"center"}),b=L.inspectElement(w,this.nodeRegistry).bestSelector}else m.scrollBy(Number(r==null?void 0:r.x)||0,Number(r==null?void 0:r.y)||0);const T={x:m.scrollX||0,y:m.scrollY||0};return this.success(n,i,{success:!0,scrollBefore:g,scrollAfter:T,requested:{x:Number(r==null?void 0:r.x)||0,y:Number(r==null?void 0:r.y)||0},targetSelector:b},s)}case"WAIT_FOR_CONDITION":return await this.waitForCondition(t,r||{},s,n,i);case"GET_PAGE_STATE":case"CAPTURE_PAGE_STATE":{const m=this.session.captureSnapshot(t,!0,this.getMutationEngine(t).getUndoDepth());return this.success(n,i,m,s)}case"CAPTURE_REGION":{const m=this.resolveTarget((r==null?void 0:r.target)||(r==null?void 0:r.selector),t),g=this.regionCapture.capture(m);return this.success(n,i,g,s)}case"GET_SIMULATION_TAB_STATE":return this.isSimulation()?this.success(n,i,{simulated:!0,tabs:this.simulationTabs,sessionSummary:this.session.getTabs()},s):this.error(n,i,"NOT_SIMULATION","Simulation tab state is only available in the Node simulation context.",s);default:return this.error(n,i,"UNKNOWN_COMMAND",`Unsupported command '${i}'`,s)}}catch(m){return this.error(n,i,"COMMAND_EXECUTION_FAILED",m.message,s,m.details)}}resolveTarget(e,t){if(!e)throw new Error("Target specifier must be provided");return typeof e=="string"?this.interactionEngine.resolveTarget({selector:e},t):typeof e=="number"?this.interactionEngine.resolveTarget({nodeId:e},t):this.interactionEngine.resolveTarget(e,t)}async performDrag(e,t,s,n){const i=n.defaultView,r=[],o=(p,y,v={})=>{try{const m=(i==null?void 0:i.MouseEvent)||(typeof MouseEvent<"u"?MouseEvent:null);m&&(p.dispatchEvent(new m(y,{bubbles:!0,cancelable:!0,...v})),r.push(y))}catch{}},a=e.getBoundingClientRect(),c=a.x+a.width/2,u=a.y+a.height/2;let d=c+((s==null?void 0:s.x)||0),h=u+((s==null?void 0:s.y)||0);if(t){const p=t.getBoundingClientRect();d=p.x+p.width/2,h=p.y+p.height/2}return o(e,"pointerdown",{button:1,clientX:c,clientY:u}),o(e,"mousedown",{button:1,clientX:c,clientY:u}),o(e,"dragstart",{clientX:c,clientY:u}),t&&(o(t,"dragenter",{clientX:d,clientY:h}),o(t,"dragover",{clientX:d,clientY:h}),o(t,"drop",{clientX:d,clientY:h})),o(e,"dragend",{clientX:d,clientY:h}),o(e,"pointerup",{button:1,clientX:d,clientY:h}),o(e,"mouseup",{button:1,clientX:d,clientY:h}),{success:r.length>0,sourceSelector:L.inspectElement(e,this.nodeRegistry).bestSelector,targetSelector:t?L.inspectElement(t,this.nodeRegistry).bestSelector:"(offset drop)",eventsFired:r,finalPosition:{x:Math.round(d),y:Math.round(h)},html5DndUsed:r.includes("dragstart")}}async waitForCondition(e,t,s,n,i){var p,y;const r=t.kind||"dom_stable",o=Math.min(Math.max(Number(t.timeoutMs)||5e3,100),3e4),a=Math.min(Math.max(Number(t.pollIntervalMs)||100,20),1e3),c=Date.now(),u=()=>{var v,m,g,b,T;switch(r){case"dom_stable":return{satisfied:!0,detail:`dom length ${((v=e.documentElement)==null?void 0:v.outerHTML.length)||0}`};case"selector_present":{const w=t.selector?e.querySelectorAll(t.selector).length:0;return{satisfied:w>0,detail:`"${t.selector}" matches ${w} element(s)`}}case"selector_visible":{if(!t.selector)return{satisfied:!1,detail:"no selector supplied"};const w=e.querySelector(t.selector);if(!w)return{satisfied:!1,detail:`"${t.selector}" not present`};try{const E=L.inspectElement(w).visibility.isVisible;return{satisfied:E,detail:`visibility=${E}`}}catch{return{satisfied:!1,detail:"inspection failed"}}}case"selector_absent":{const w=t.selector?e.querySelectorAll(t.selector).length:0;return{satisfied:w===0,detail:`"${t.selector}" matches ${w} element(s)`}}case"text_present":{const w=((m=e.body)==null?void 0:m.innerText)||((g=e.body)==null?void 0:g.textContent)||"",E=t.text?w.includes(String(t.text)):!1;return{satisfied:E,detail:`text "${String(t.text).slice(0,30)}" ${E?"found":"not found"}`}}case"url_contains":{const w=((T=(b=e.defaultView)==null?void 0:b.location)==null?void 0:T.href)||"";return{satisfied:t.text?w.includes(String(t.text)):!1,detail:w}}case"element_count":{const w=t.selector?e.querySelectorAll(t.selector).length:0,E=Number(t.count)||0;return{satisfied:w===E,detail:`${w}/${E} elements`}}case"readiness_state":return{satisfied:e.readyState===(t.state||"complete"),detail:`readyState=${e.readyState}`};default:return{satisfied:!1,detail:`unknown condition kind "${r}"`}}};if(r==="dom_stable"){let v=((p=e.documentElement)==null?void 0:p.outerHTML.length)||0,m=!1,g=0;for(;Date.now()-csetTimeout(w,a));const T=((y=e.documentElement)==null?void 0:y.outerHTML.length)||0;if(g++,T===v){m=!0;break}v=T}const b=Date.now()-c;return m&&this.session.timeline.record("WAIT_SATISFIED",`dom_stable after ${b}ms (${g} polls)`),this.success(n,i,{satisfied:m,condition:r,waitedMs:b,timeoutMs:o,detail:`dom length ${v}, ${g} polls`},s)}let d=u();for(;!d.satisfied&&Date.now()-csetTimeout(v,a)),d=u();const h=Date.now()-c;return d.satisfied&&this.session.timeline.record("WAIT_SATISFIED",`${r} after ${h}ms`),this.success(n,i,{satisfied:d.satisfied,condition:r,waitedMs:h,timeoutMs:o,detail:d.detail},s)}simulationCloseTab(e,t,s,n,i){const r=Number(e==null?void 0:e.tabId),o=Number.isFinite(r)?this.simulationTabs.findIndex(c=>c.browserTabId===r):this.simulationTabs.findIndex(c=>c.active);if(o<0)return this.error(s,n,"TAB_NOT_FOUND",`No simulated tab matches tabId=${r}`,i);const a=this.simulationTabs.splice(o,1)[0];return this.session.closeTab(a.sessionTabId),a.active&&this.simulationTabs.length&&(this.simulationTabs[0].active=!0,this.session.switchTab(this.simulationTabs[0].sessionTabId)),this.success(s,n,{closed:!0,closedTab:{id:a.browserTabId,url:a.url,title:a.title},simulated:!0,remaining:this.simulationTabs.length},i)}handleSimulationBackgroundCommand(e,t,s,n,i){const r=()=>{var o,a;if(!this.simulationTabs.length){this.simulationTabCounter++;const c={sessionTabId:`stab_${this.simulationTabCounter}`,browserTabId:this.simulationTabCounter,url:((a=(o=n.defaultView)==null?void 0:o.location)==null?void 0:a.href)||"about:blank",title:n.title||"Simulated Tab",active:!0,createdAt:Date.now()};this.simulationTabs.push(c),this.session.registerTab(c.browserTabId,c.url,c.title),this.session.switchTab(c.sessionTabId)}};switch(t){case"LIST_TABS":return r(),this.success(e,t,{simulated:!0,environment:"node-simulation",tabs:this.simulationTabs.map((o,a)=>({id:o.browserTabId,index:a,windowId:1,title:o.title,url:o.url,active:o.active,status:"complete",pinned:!1,audited:!1})),note:"Deterministic simulated tab state — a real browser tab list requires the Chrome extension connection."},i);case"OPEN_TAB":{const o=String((s==null?void 0:s.url)||"about:blank");this.simulationTabCounter++;const a={sessionTabId:`stab_${this.simulationTabCounter}`,browserTabId:this.simulationTabCounter,url:o,title:(s==null?void 0:s.title)||`Simulated Tab ${this.simulationTabCounter}`,active:!0,createdAt:Date.now()};this.simulationTabs.forEach(u=>u.active=!1),this.simulationTabs.push(a);const c=this.session.registerTab(a.browserTabId,o,a.title);return this.session.switchTab(c.sessionTabId),this.session.timeline.record("TAB_OPENED",`simulation tab ${a.browserTabId} → ${o}`),this.success(e,t,{opened:!0,tabId:a.browserTabId,url:o,simulated:!0,totalTabs:this.simulationTabs.length},i)}case"FOCUS_TAB":{r();const o=Number(s==null?void 0:s.tabId),a=this.simulationTabs.find(c=>c.browserTabId===o)||this.simulationTabs[0];return a?(this.simulationTabs.forEach(c=>c.active=!1),a.active=!0,this.session.switchTab(a.sessionTabId),this.session.timeline.record("TAB_SWITCHED",`simulation tab ${a.browserTabId} focused`),this.success(e,t,{focused:!0,tabId:a.browserTabId,url:a.url,simulated:!0},i)):this.error(e,t,"TAB_NOT_FOUND",`No simulated tab with tabId=${o}`,i)}case"LIST_EXTENSIONS":return this.success(e,t,{simulated:!0,extensions:this.simulationExtensions.map(o=>({...o,permissions:["activeTab","scripting","storage","tabs","management"]})),note:"Deterministic simulated extension state."},i);case"SET_EXTENSION_ENABLED":{const o=String((s==null?void 0:s.extensionId)||""),a=this.simulationExtensions.find(c=>c.id===o||c.name.toLowerCase().includes(o.toLowerCase()));return a?(a.enabled=!!(s!=null&&s.enabled),this.session.timeline.record("EXTENSION_STATE_CHANGED",`${a.id} → ${a.enabled?"enabled":"disabled"}`),this.success(e,t,{extensionId:a.id,enabled:a.enabled,simulated:!0},i)):this.error(e,t,"EXTENSION_NOT_FOUND",`No simulated extension matches "${o}". Known: ${this.simulationExtensions.map(c=>c.id).join(", ")}`,i)}case"TOGGLE_EXTENSION":{const o=String((s==null?void 0:s.extensionId)||""),a=this.simulationExtensions.find(c=>c.id===o||c.name.toLowerCase().includes(o.toLowerCase()));return a?(a.enabled=!a.enabled,this.session.timeline.record("EXTENSION_STATE_CHANGED",`${a.id} → ${a.enabled?"enabled":"disabled"}`),this.success(e,t,{extensionId:a.id,enabled:a.enabled,simulated:!0},i)):this.error(e,t,"EXTENSION_NOT_FOUND",`No simulated extension matches "${o}".`,i)}case"RELOAD_EXTENSION":{const o=String((s==null?void 0:s.extensionId)||this.simulationExtensions[0].id),a=this.simulationExtensions.find(c=>c.id===o||c.name.toLowerCase().includes(o.toLowerCase()));return a?this.success(e,t,{reloaded:!0,extensionId:a.id,simulated:!0,note:"Simulated reload: extension state preserved."},i):this.error(e,t,"EXTENSION_NOT_FOUND",`No simulated extension matches "${o}".`,i)}default:return this.error(e,t,"UNKNOWN_COMMAND",`Unhandled simulation command '${t}'`,i)}}async handleScreenshotCapture(e,t,s){var y,v,m,g,b;const n=s.defaultView||(typeof window<"u"?window:{}),i=Date.now(),r=`scr_${i}_${Math.random().toString(36).slice(2,6)}`,o=n.devicePixelRatio||1,a={width:n.innerWidth||((y=s.documentElement)==null?void 0:y.clientWidth)||1920,height:n.innerHeight||((v=s.documentElement)==null?void 0:v.clientHeight)||1080,scrollX:n.scrollX||n.pageXOffset||0,scrollY:n.scrollY||n.pageYOffset||0,devicePixelRatio:o};let c,u,d,h={width:a.width,height:a.height};if(e==="LIVE_ELEMENT_SCREENSHOT"){const T=this.resolveTarget(t,s),w=L.inspectElement(T,this.nodeRegistry);c=w.bestSelector,u=((m=w.forensics)==null?void 0:m.logicalNodeId)||void 0,d={x:w.bounds.x,y:w.bounds.y,width:w.bounds.width,height:w.bounds.height},h={width:Math.max(1,Math.round(w.bounds.width*o)),height:Math.max(1,Math.round(w.bounds.height*o))}}let p=(t==null?void 0:t.dataUrl)||"";if(e==="LIVE_ELEMENT_SCREENSHOT"&&p&&d&&typeof Image<"u")try{const T=await new Promise(w=>{const E=new Image;E.onload=()=>{try{const C=s.createElement("canvas"),N=Math.max(0,Math.floor(d.x*o)),I=Math.max(0,Math.floor(d.y*o)),R=Math.max(1,Math.floor(d.width*o)),x=Math.max(1,Math.floor(d.height*o));C.width=R,C.height=x;const q=C.getContext("2d");if(q){q.drawImage(E,N,I,R,x,0,0,R,x),w(C.toDataURL("image/png"));return}}catch{}w(p)},E.onerror=()=>w(p),E.src=p});T&&(p=T)}catch{}if(!p){const T=e==="LIVE_ELEMENT_SCREENSHOT"?Math.max(120,h.width||320):Math.max(800,a.width||1280),w=e==="LIVE_ELEMENT_SCREENSHOT"?Math.max(60,h.height||180):Math.max(600,a.height||800);p=fe.createDataUrl({width:T,height:w,backgroundColor:e==="LIVE_ELEMENT_SCREENSHOT"?[30,41,59,255]:[15,23,42,255],headerColor:[56,189,248,255],borderColor:[99,102,241,255],label:c||(e==="LIVE_ELEMENT_SCREENSHOT"?"Element Screenshot":"Page Screenshot")})}return{screenshotId:r,timestamp:i,url:((g=n.location)==null?void 0:g.href)||((b=s.location)==null?void 0:b.href)||"",viewport:a,targetSelector:c,targetNodeId:u,targetBounds:d,dataUrl:p,imageFormat:"png",dimensions:h,captureType:e==="LIVE_ELEMENT_SCREENSHOT"?"ELEMENT":"FULL_PAGE"}}success(e,t,s,n){return{id:e,command:t,success:!0,data:s,timestamp:Date.now(),durationMs:Date.now()-n}}error(e,t,s,n,i,r){return{id:e,command:t,success:!1,error:{code:s,message:n,details:r},timestamp:Date.now(),durationMs:Date.now()-i}}}function Dt(l,e){const t=[];let s=l.parentElement,n=1;for(;s&&n<=10;){const d=s.parentElement,h=d?Array.from(d.children).filter(p=>p.tagName===s.tagName):[];t.push({tag:s.tagName.toLowerCase(),selector:V(s),role:s.getAttribute("role")||void 0,text:K(s).slice(0,40),childIndex:h.length?h.indexOf(s)+1:1,siblingCount:d?Array.from(d.children).length:0,distance:n}),s=s.parentElement,n++}const i=l.parentElement,r=[];if(i){const d=Array.from(i.children),h=d.indexOf(l);for(let p=h-1;p>=0&&p>=h-5;p--)r.push({tag:d[p].tagName.toLowerCase(),selector:V(d[p]),role:d[p].getAttribute("role")||void 0,text:K(d[p]).slice(0,30),position:"before",distance:h-p});for(let p=h+1;p{o=Math.max(o,h);for(const p of Array.from(d.children))a.push(p.tagName.toLowerCase()),p.matches('a[href], button, input, select, textarea, [role="button"], [onclick]')&&c.push(V(p)),h<6&&u(p,h+1)};return u(l,1),{selector:V(l),ancestors:t,siblings:r,descendants:{count:l.querySelectorAll("*").length,maxDepth:o,tags:Array.from(new Set(a)).slice(0,30),interactive:c.slice(0,30)}}}function $t(l,e){const t=[{id:"self",selector:V(l),tag:l.tagName.toLowerCase(),role:l.getAttribute("role")||void 0,label:K(l).slice(0,30)||l.tagName.toLowerCase(),relationship:"self",depth:0}],s=[];let n=l.parentElement,i=1;for(;n&&i<=4;){const o=`ancestor_${i}`;t.push({id:o,selector:V(n),tag:n.tagName.toLowerCase(),role:n.getAttribute("role")||void 0,label:K(n).slice(0,30)||n.tagName.toLowerCase(),relationship:"parent",depth:i}),s.push({from:o,to:i===1?"self":`ancestor_${i-1}`,relation:"parent-of"}),n=n.parentElement,i++}for(const o of Array.from(l.children).slice(0,12)){const a=`child_${t.length}`;t.push({id:a,selector:V(o),tag:o.tagName.toLowerCase(),role:o.getAttribute("role")||void 0,label:K(o).slice(0,30)||o.tagName.toLowerCase(),relationship:"child",depth:1}),s.push({from:"self",to:a,relation:"contains"})}const r=l.parentElement;if(r)for(const o of Array.from(r.children).slice(0,12)){if(o===l)continue;const a=`sibling_${t.length}`;t.push({id:a,selector:V(o),tag:o.tagName.toLowerCase(),role:o.getAttribute("role")||void 0,label:K(o).slice(0,30)||o.tagName.toLowerCase(),relationship:"sibling",depth:1}),s.push({from:"self",to:a,relation:"sibling-of"})}return{rootSelector:V(l),nodes:t,edges:s}}function qt(l){const e={};for(const v of Array.from(l.attributes))v.name.startsWith("aria-")&&(e[v.name]=v.value);const t=K(l).trim(),s=l.getAttribute("aria-label"),n=l.getAttribute("aria-labelledby");let i;n&&(i=n.split(/\s+/).map(m=>{var g,b,T;return(T=(b=(g=l.ownerDocument)==null?void 0:g.getElementById(m))==null?void 0:b.textContent)==null?void 0:T.trim()}).filter(Boolean).join(" ").slice(0,60)||void 0);const r=l.getAttribute("title"),o=l.tagName.toLowerCase(),a=[];let c="";s?(c=s,a.push("aria-label")):i?(c=i,a.push("aria-labelledby")):t?(c=t.slice(0,60),a.push("text content")):r&&(c=r,a.push("title"));const u=[];(l.disabled||l.hasAttribute("disabled"))&&u.push("disabled"),l.checked&&u.push("checked");const d=l;d.tagName==="SELECT"&&typeof d.selectedOptions<"u"&&d.selectedOptions.length>0&&u.push("selected"),l.getAttribute("aria-expanded")&&u.push(`expanded=${l.getAttribute("aria-expanded")}`),l.getAttribute("aria-pressed")&&u.push(`pressed=${l.getAttribute("aria-pressed")}`),l.getAttribute("aria-hidden")==="true"&&u.push("hidden"),l.hasAttribute("required")&&u.push("required"),l.readOnly&&u.push("readonly");const h=["a[href]","button","input","select","textarea","[tabindex]"].some(v=>{try{return l.matches(v)}catch{return!1}}),p=[];!c&&h&&p.push("Focusable element has no accessible name."),o==="img"&&!l.hasAttribute("alt")&&p.push("Image has no alt attribute.");const y=/^h([1-6])$/.exec(o);return y&&!t&&p.push(`Heading h${y[1]} is empty.`),{selector:V(l),role:l.getAttribute("role")||void 0,implicitRole:Pt(l),name:c,nameSources:a,description:l.getAttribute("aria-describedby")||void 0,value:l.value!==void 0&&(l.getAttribute("type")||"text")!=="password"?String(l.value).slice(0,40):void 0,states:u,level:y?parseInt(y[1],10):void 0,focusable:h,tabIndex:l.tabIndex,ariaAttributes:e,issues:p}}function Pt(l){switch(l.tagName.toLowerCase()){case"a":return l.getAttribute("href")?"link":void 0;case"button":return"button";case"nav":return"navigation";case"header":return"banner";case"footer":return"contentinfo";case"main":return"main";case"aside":return"complementary";case"article":return"article";case"form":return"form";case"input":{const t=l.getAttribute("type")||"text";return{checkbox:"checkbox",radio:"radio",button:"button",submit:"button",reset:"button",range:"slider",search:"searchbox",email:"textbox",text:"textbox",password:"textbox",tel:"textbox",url:"textbox",number:"spinbutton"}[t]||"textbox"}case"select":return l.hasAttribute("multiple")?"listbox":"combobox";case"textarea":return"textbox";case"img":return"img";case"table":return"table";case"ul":case"ol":return"list";case"li":return"listitem";case"h1":case"h2":case"h3":case"h4":case"h5":case"h6":return"heading";case"dialog":return"dialog";default:return}}function V(l){const e=l.getAttribute("id");if(e&&/^[a-zA-Z][\w-]*$/.test(e))return`#${e}`;const t=l.getAttribute("data-testid");if(t)return`${l.tagName.toLowerCase()}[data-testid="${t}"]`;const s=l.tagName.toLowerCase(),n=Array.from(l.classList||[]).slice(0,2);return n.length?`${s}.${n.join(".")}`:s}function K(l){return Array.from(l.childNodes).filter(e=>e.nodeType===3).map(e=>(e.textContent||"").trim()).join(" ").replace(/\s+/g," ")}function Ut(){return[{label:"desktop-1440x900",width:1440,height:900},{label:"laptop-1024x768",width:1024,height:768},{label:"tablet-768x1024",width:768,height:1024},{label:"mobile-375x667",width:375,height:667}]}class Ht{constructor(e){f(this,"hostElement",null);f(this,"shadowRoot",null);f(this,"callbacks");f(this,"isRecording",!1);f(this,"isPaused",!1);f(this,"isMinimized",!1);f(this,"startTime",0);f(this,"eventCount",0);f(this,"timerInterval",null);f(this,"isDragging",!1);f(this,"dragStartX",0);f(this,"dragStartY",0);f(this,"posX",window.innerWidth-340);f(this,"posY",40);this.callbacks=e,this.loadPosition()}mount(){this.hostElement&&document.body.contains(this.hostElement)||(this.hostElement=document.createElement("div"),this.hostElement.id="forensic-recorder-floating-host",this.hostElement.style.all="initial",this.hostElement.style.position="fixed",this.hostElement.style.zIndex="2147483647",this.hostElement.style.left=`${this.posX}px`,this.hostElement.style.top=`${this.posY}px`,this.shadowRoot=this.hostElement.attachShadow({mode:"open"}),this.render(),this.attachEvents(),(document.body||document.documentElement).appendChild(this.hostElement))}unmount(){this.timerInterval&&(clearInterval(this.timerInterval),this.timerInterval=null),this.hostElement&&this.hostElement.parentNode&&this.hostElement.parentNode.removeChild(this.hostElement),this.hostElement=null,this.shadowRoot=null}hide(){this.hostElement&&(this.hostElement.style.setProperty("display","none","important"),this.hostElement.style.setProperty("visibility","hidden","important"),this.hostElement.style.setProperty("opacity","0","important"))}show(){this.hostElement&&(this.hostElement.style.removeProperty("display"),this.hostElement.style.removeProperty("visibility"),this.hostElement.style.removeProperty("opacity"))}updateState(e,t=!1,s=0,n=0){this.isRecording=e,this.isPaused=t,this.startTime=s||(e?Date.now():0),this.eventCount=n,this.shadowRoot&&(this.render(),this.attachEvents()),this.isRecording&&!this.isPaused?this.startTimer():this.stopTimer()}incrementEventCount(){var t;this.eventCount++;const e=(t=this.shadowRoot)==null?void 0:t.querySelector("#evt-badge");e&&(e.textContent=`${this.eventCount} evts`)}startTimer(){this.stopTimer(),this.timerInterval=setInterval(()=>{var t;const e=(t=this.shadowRoot)==null?void 0:t.querySelector("#timer-display");if(e&&this.startTime){const s=(Date.now()-this.startTime)/1e3,n=Math.floor(s/60).toString().padStart(2,"0"),i=(s%60).toFixed(1).padStart(4,"0");e.textContent=`${n}:${i}`}},200)}stopTimer(){this.timerInterval&&(clearInterval(this.timerInterval),this.timerInterval=null)}savePosition(){try{sessionStorage.setItem("forensic_overlay_pos",JSON.stringify({x:this.posX,y:this.posY,min:this.isMinimized}))}catch{}}loadPosition(){try{const e=sessionStorage.getItem("forensic_overlay_pos");if(e){const t=JSON.parse(e);this.posX=Math.max(10,Math.min(window.innerWidth-300,t.x||this.posX)),this.posY=Math.max(10,Math.min(window.innerHeight-150,t.y||this.posY)),this.isMinimized=!!t.min}}catch{}}render(){if(!this.shadowRoot)return;const e=` +})()`,n=e;if(typeof n.eval!="function")return Promise.reject(new Error("BLOCKED_BY_CONTEXT: window.eval is unavailable in this context."));try{const i=n.eval(s);return i&&typeof i.then=="function"?i:Promise.resolve(i)}catch(i){return Promise.reject(i)}}hookConsole(e,t){var o;const s=["log","warn","error","info","debug"],n={},i=e,r=100;for(const a of s){const c=(o=i.console)==null?void 0:o[a];if(typeof c=="function"){n[a]=c;try{i.console[a]=(...u)=>{t.length{for(const a of s)if(n[a])try{i.console[a]=n[a]}catch{}}}serialize(e){if(e===void 0)return{text:"undefined"};if(e===null)return{text:"null"};try{if(typeof e=="string")return{text:e.slice(0,5e3)};const t=JSON.stringify(e,pe,1);return t===void 0?{serializationFailed:!0,message:"JSON.stringify returned undefined (circular or non-serializable structure)."}:{text:t.length>5e4?t.slice(0,5e4)+"…[truncated]":t}}catch(t){return{serializationFailed:!0,message:(t==null?void 0:t.message)||"Serialization failed."}}}result(e,t,s,n,i,r){return{status:t,executionId:e,durationMs:s,error:r,consoleOutput:i,domChanged:!1,domLengthBefore:0,domLengthAfter:0,world:"ISOLATED",timeoutMs:5e3,codePreview:n.length>300?n.slice(0,300)+"…":n}}}function pe(l,e){var t;if(e&&typeof e=="object"&&e.nodeType===1){const s=e;return{__element:!0,tag:s.tagName.toLowerCase(),id:s.getAttribute("id")||void 0,selector:s.tagName.toLowerCase()+(s.getAttribute("id")?`#${s.getAttribute("id")}`:""),text:(s.textContent||"").trim().slice(0,60)}}return typeof e=="function"?{__function:!0,name:e.name||"anonymous"}:e&&e.nodeType===9?{__document:!0,url:(t=e.location)==null?void 0:t.href}:e}function Ve(l){try{if(typeof l=="string")return l;if(l instanceof Error)return`${l.name}: ${l.message}`;const e=JSON.stringify(l,pe);return e===void 0?String(l):e}catch{return String(l)}}const me={"desktop-full-hd":{width:1920,height:1080,category:"desktop"},"desktop-hd":{width:1366,height:768,category:"desktop"},"desktop-laptop":{width:1440,height:900,category:"desktop"},"desktop-xga":{width:1280,height:1024,category:"desktop"},"desktop-1024":{width:1024,height:768,category:"desktop"},"tablet-ipad":{width:768,height:1024,category:"tablet"},"tablet-ipad-pro":{width:1024,height:1366,category:"tablet"},"tablet-portrait":{width:768,height:1024,category:"tablet"},"tablet-landscape":{width:1024,height:768,category:"tablet"},"mobile-iphone-se":{width:375,height:667,category:"mobile"},"mobile-iphone-12":{width:390,height:844,category:"mobile"},"mobile-iphone-14-pro-max":{width:430,height:932,category:"mobile"},"mobile-pixel-7":{width:412,height:915,category:"mobile"},"mobile-galaxy-s8":{width:360,height:740,category:"mobile"},"mobile-small":{width:320,height:568,category:"mobile"},"test-a4":{width:800,height:600,category:"test"},"test-square":{width:512,height:512,category:"test"}},fe={"iphone-13":{width:390,height:844,devicePixelRatio:3,userAgent:"Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1",touch:!0,category:"mobile"},"ipad-air":{width:820,height:1180,devicePixelRatio:2,userAgent:"Mozilla/5.0 (iPad; CPU OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1",touch:!0,category:"tablet"},"pixel-7":{width:412,height:915,devicePixelRatio:2.625,userAgent:"Mozilla/5.0 (Linux; Android 14; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36",touch:!0,category:"mobile"},"galaxy-s23":{width:384,height:800,devicePixelRatio:3,userAgent:"Mozilla/5.0 (Linux; Android 14; SM-S911B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36",touch:!0,category:"mobile"},"macbook-pro-16":{width:1728,height:1080,devicePixelRatio:2,userAgent:"Mozilla/5.0 (Macintosh; Intel Mac OS X 14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",touch:!1,category:"desktop"},"windows-desktop":{width:1920,height:1080,devicePixelRatio:1,userAgent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",touch:!1,category:"desktop"}};class Be{constructor(e){b(this,"original",null);b(this,"modified",!1);b(this,"activePreset",null);b(this,"activeDevice",null);this.doc=e}state(){const e=this.doc.defaultView;return{width:(e==null?void 0:e.innerWidth)||0,height:(e==null?void 0:e.innerHeight)||0,devicePixelRatio:(e==null?void 0:e.devicePixelRatio)||1,scrollX:(e==null?void 0:e.scrollX)||0,scrollY:(e==null?void 0:e.scrollY)||0,original:this.original,isModified:this.modified}}resize(e,t,s){const n=this.doc.defaultView,i={width:(n==null?void 0:n.innerWidth)||0,height:(n==null?void 0:n.innerHeight)||0},r=this.pageDigest();this.original||(this.original={...i});const o=this.applySize(e,t);this.modified=!0,this.activePreset=s||this.activePreset;const a=this.pageDigest();return{success:!0,applied:{width:o.width,height:o.height},previous:i,original:{...this.original},preset:s||void 0,beforeState:r,afterState:a,reversible:!0,mode:this.isSimulation()?"simulation":"browser-window"}}applyPreset(e){const t=me[e];if(!t)throw new Error(`UNKNOWN_PRESET: "${e}". Available: ${Object.keys(me).join(", ")}`);return this.resize(t.width,t.height,e)}emulateDevice(e){const t=fe[e];if(!t)throw new Error(`UNKNOWN_DEVICE: "${e}". Available: ${Object.keys(fe).join(", ")}`);const s=this.resize(t.width,t.height,`device:${e}`);this.activeDevice=e;const n=this.doc.defaultView;return n&&this.isSimulation()&&n.devicePixelRatio!==void 0&&(n.devicePixelRatio=t.devicePixelRatio),{device:e,resize:s,profile:{width:t.width,height:t.height,devicePixelRatio:t.devicePixelRatio,touch:t.touch,category:t.category},userAgentNote:this.isSimulation()?"User-Agent override requires the Chrome DevTools Protocol (real browser session); in this context the viewport, dpr and touch metadata are applied and the UA is reported but not enforced.":"User-Agent and touch behaviors are applied by the browser emulation layer.",userAgentApplied:!this.isSimulation()}}reset(){var s,n;const e={width:((s=this.doc.defaultView)==null?void 0:s.innerWidth)||0,height:((n=this.doc.defaultView)==null?void 0:n.innerHeight)||0},t=this.original?{...this.original}:{...e};return this.original&&this.applySize(this.original.width,this.original.height),this.modified=!1,this.activePreset=null,this.activeDevice=null,{success:!0,applied:{width:t.width,height:t.height},previous:e,original:{...t},reversible:!0,mode:this.isSimulation()?"simulation":"browser-window"}}runResponsiveTest(e,t={restore:!0}){var c,u,h,g;const s=t.restore!==!1,n=this.original?{...this.original}:{width:((c=this.doc.defaultView)==null?void 0:c.innerWidth)||0,height:((u=this.doc.defaultView)==null?void 0:u.innerHeight)||0};this.original||(this.original={...n});const i=e.map(p=>{this.applySize(p.width,p.height),this.modified=!0;const y=this.pageDigest();return{label:p.label,width:p.width,height:p.height,domLength:y.domLength,interactiveCount:y.interactiveCount,horizontalOverflow:this.hasHorizontalOverflow(),screenshotId:void 0}}),r=i.slice(1).map((p,y)=>({from:i[y].label,to:p.label,domLengthDelta:p.domLength-i[y].domLength,interactiveDelta:p.interactiveCount-i[y].interactiveCount}));let o={width:((h=i[i.length-1])==null?void 0:h.width)||0,height:((g=i[i.length-1])==null?void 0:g.height)||0},a=!1;return s&&(this.applySize(n.width,n.height),this.modified=!1,o={...n},a=!0),{success:!0,originalViewport:n,steps:i,restored:a,finalViewport:o,comparisons:r}}getActivePreset(){return this.activePreset}getActiveDevice(){return this.activeDevice}applySize(e,t){const s=Math.max(200,Math.min(7680,Math.round(e))),n=Math.max(200,Math.min(4320,Math.round(t))),i=this.doc.defaultView;return i&&(typeof i.innerWidth=="number"&&(i.innerWidth=s),typeof i.innerHeight=="number"&&(i.innerHeight=n),typeof i.outerWidth=="number"&&(i.outerWidth=s),typeof i.outerHeight=="number"&&(i.outerHeight=n)),{width:s,height:n}}pageDigest(){var t,s,n,i;const e=this.doc.querySelectorAll('a[href], button, input, select, textarea, [role="button"], [onclick]').length;return{url:((s=(t=this.doc.defaultView)==null?void 0:t.location)==null?void 0:s.href)||((n=this.doc.location)==null?void 0:n.href)||"",domLength:((i=this.doc.documentElement)==null?void 0:i.outerHTML.length)||0,interactiveCount:e}}hasHorizontalOverflow(){const e=this.doc.documentElement,t=this.doc.body,s=this.doc.defaultView;return!s||!e?!1:Math.max(e.scrollWidth||0,(t==null?void 0:t.scrollWidth)||0)>(s.innerWidth||e.clientWidth||0)+1}isSimulation(){return typeof globalThis.__FORENSIC_SIMULATION__<"u"}}const ze=[/^css-/,/^jsx-/,/^sc-[A-Za-z]/,/^emotion/,/^chakra-/,/^mantine-/i,/^_ng[a-z]/,/^ng-/i,/^v-/,/^(?=.*\d)[a-z0-9]{6,12}$/i,/^data-v-/],We=["id","name","data-testid","data-test","data-id","data-qa","data-cy","data-component","data-role","aria-label","aria-labelledby","aria-describedby","role","type","href","for","title","alt","rel","placeholder"];function be(l){let e=2166136261;for(let t=0;t>>0).toString(16).padStart(8,"0")}function ee(l){return ze.some(e=>e.test(l))}function Xe(l){return We.includes(l)}function re(l){const e=l.trim();return e?!!((e.match(/\d/g)||[]).length/e.length>.5||/^\d+[.,:\-/ ]+\d+/.test(e)||/\b\d{10,}\b/.test(e)):!1}function Ge(l,e=80){return Array.from(l.childNodes).filter(s=>s.nodeType===3).map(s=>(s.textContent||"").trim()).join(" ").replace(/\s+/g," ").slice(0,e)}function Ke(l,e){const t=[];let s=l;for(;s&&t.length!ee(f)),r=Ge(e),o=e.getBoundingClientRect(),a={width:Math.round(o.width),height:Math.round(o.height)},c=Ke(e,4),u=c.join(">"),g=Array.from(e.children||[]).slice(0,8).map(f=>f.tagName.toLowerCase()).join("|"),p=e.getAttribute("role")||(t!=null&&t.getComputedStyle,void 0)||Ye(e),y=be(JSON.stringify({t:e.tagName.toLowerCase(),a:s,c:i.slice(0,4),r:p||null,anc:u,desc:g,txt:re(r)?null:r.slice(0,40),d:a})),v=[];let m="low";return!s.id&&!s["data-testid"]&&!s.name&&(m="medium",v.push("no stable identity attribute")),n.length>0&&i.length===0&&(m=v.length?"high":"medium",v.push("all classes are framework-generated")),re(r)&&(v.push("text appears dynamic"),m==="low"&&(m="medium")),e.tagName.toLowerCase().includes("-")&&(v.push("custom element (web component)"),m==="low"&&(m="medium")),{fingerprintId:`fp_${y}`,hash:y,tagHierarchy:c,stableAttributes:s,meaningfulText:r,classes:i,role:p||void 0,dimensions:a,ancestorPattern:u,descendantPattern:g,volatilityRisk:m,volatilityReasons:v}}compare(e,t){const s=[],n=e.tagHierarchy[0]===t.tagHierarchy[0]?1:0;s.push({name:"tag",score:n,weight:.15});const i=ye(e.ancestorPattern.split(">"),t.ancestorPattern.split(">"));s.push({name:"ancestorPattern",score:i,weight:.2});const r=je(e.stableAttributes,t.stableAttributes);s.push({name:"stableAttributes",score:r,weight:.25});const o=ye(e.classes,t.classes);s.push({name:"classes",score:o,weight:.1});const a=(e.role||"")===(t.role||"")&&e.role?1:0;s.push({name:"role",score:a,weight:.1});const c=e.meaningfulText===t.meaningfulText&&e.meaningfulText?1:0;s.push({name:"text",score:c,weight:.1});const u=Ze(e.dimensions,t.dimensions);s.push({name:"dimensions",score:u,weight:.1});const h=s.reduce((g,p)=>g+p.score*p.weight,0);return{score:Math.round(h*1e3)/1e3,components:s}}}function Ye(l){switch(l.tagName.toLowerCase()){case"a":return l.getAttribute("href")?"link":void 0;case"button":return"button";case"nav":return"navigation";case"header":return"banner";case"footer":return"contentinfo";case"main":return"main";case"aside":return"complementary";case"article":return"article";case"form":return"form";case"input":{const t=l.getAttribute("type")||"text";return t==="checkbox"?"checkbox":t==="radio"?"radio":t==="button"||t==="submit"?"button":"textbox"}case"select":return"combobox";case"textarea":return"textbox";case"img":return"img";case"table":return"table";case"ul":case"ol":return"list";case"li":return"listitem";case"h1":case"h2":case"h3":case"h4":case"h5":case"h6":return"heading";default:return}}function ye(l,e){if(!l.length&&!e.length)return 1;if(!l.length||!e.length)return 0;const t=new Set(e);return l.filter(n=>t.has(n)).length/Math.max(l.length,e.length)}function je(l,e){const t=Object.keys(l),s=Object.keys(e);if(!t.length&&!s.length)return .5;if(!t.length||!s.length)return 0;let n=0,i=0;for(const r of t)r in e&&(i++,l[r]===e[r]&&n++);return i===0?0:n/Math.max(t.length,s.length)}function Ze(l,e){if(l.width===0&&l.height===0&&e.width===0&&e.height===0)return .5;const t=Ee(l.width,e.width),s=Ee(l.height,e.height);return(t+s)/2}function Ee(l,e){if(l===e)return 1;if(l===0||e===0)return 0;const t=Math.min(l,e)/Math.max(l,e);return t>.9?1:t>.7?.5:0}const Je=["data-testid","data-test","data-id","data-qa","data-cy","data-component","data-role","aria-label","name","id"],ve=/^[a-zA-Z][a-zA-Z0-9_-]*$/,Qe=/^[a-zA-Z0-9_ .:-]+$/;class Y{constructor(e){b(this,"doc");this.doc=e}generateCandidates(e){const t=[],s=e.tagName.toLowerCase(),n=e.getAttribute("id");if(n&&ve.test(n)){const u=`#${we(n)}`;t.push(this.evaluate(e,u,"id",1,["unique stable id"]))}for(const u of Je){if(u==="id")continue;const h=e.getAttribute(u);if(h&&Qe.test(h)&&h.length<100){const g=`${s}[${u}="${j(h)}"]`;t.push(this.evaluate(e,g,"semantic-attribute",.92,[`semantic attribute ${u}`]))}}const i=Array.from(e.classList||[]).filter(u=>!ee(u));if(i.length){const u=`${s}.${i.slice(0,3).map(we).join(".")}`;t.push(this.evaluate(e,u,"class",.72,i.length?["stable class names"]:[]))}const r=this.buildStructuralPath(e);r&&t.push(this.evaluate(e,r,"structural-path",.55,["position-based structural path"]));const o=q(e);if(o&&o.length>=2&&o.length<=60&&!re(o)){const u=`${s}:nth-of-type(1)`,h=this.buildTextXPath(e,o);h&&(t.push({selector:u,strategy:"text-derived-xpath",confidence:.6,unique:this.isXPathUnique(h),reasons:[`matches text "${o.slice(0,30)}"`]}),t[t.length-1].xpath=h)}const a=this.buildAttributeFingerprintSelector(e);a&&t.push(this.evaluate(e,a,"attribute-fingerprint",.68,["combination of stable attributes"]));const c=new Map;for(const u of t){const h=u.strategy==="text-derived-xpath"?`xpath:${u.xpath}`:u.selector,g=c.get(h);(!g||u.confidence>g.confidence)&&c.set(h,u)}return Array.from(c.values()).sort((u,h)=>h.confidence-u.confidence)}bestSelector(e){const t=this.generateCandidates(e),s=t.find(n=>n.unique&&n.confidence>=.7)||t[0];return{selector:(s==null?void 0:s.selector)||e.tagName.toLowerCase(),strategy:(s==null?void 0:s.strategy)||"tag",confidence:(s==null?void 0:s.confidence)||.3}}buildXPath(e){const t=[];let s=e;for(;s&&s!==this.doc.documentElement;){const n=s.getAttribute("id");if(n&&ve.test(n)){t.unshift(`*[@id="${j(n)}"]`);break}const i=s.parentElement;if(!i){t.unshift(s.tagName.toLowerCase());break}const o=Array.from(i.children).filter(a=>a.tagName===s.tagName).indexOf(s)+1;t.unshift(`${s.tagName.toLowerCase()}[${o}]`),s=i}return s===this.doc.documentElement&&(!t.length||!t[0].includes("@id"))&&t.unshift("html"),"//"+t.join("/")}buildTextXPath(e,t){try{const s=e.tagName.toLowerCase(),n=et(t);return`//${s}[normalize-space(text())=${n}]`}catch{return null}}buildStructuralPath(e,t=4){const s=[];let n=e;for(;n&&s.lengthc.tagName===n.tagName);if(a.length>1){const c=a.indexOf(n)+1;s.unshift(`${o}:nth-of-type(${c})`)}else s.unshift(o);if(n=r,n===this.doc.body){s.unshift("body");break}if(n===this.doc.documentElement)break}const i=s.join(" > ");return i.includes("body")?i:"body > "+i}buildAttributeFingerprintSelector(e){const t=e.tagName.toLowerCase(),s=[],n=e.getAttribute("type");n&&s.push(`type="${j(n)}"`);const i=e.getAttribute("href");i&&i.length<80&&!i.startsWith("javascript:")&&s.push(`href^="${j(i.slice(0,40))}"`);const r=e.getAttribute("placeholder");return r&&r.length<60&&s.push(`placeholder="${j(r)}"`),s.length>=2?`${t}[${s.join("][")}]`:null}evaluate(e,t,s,n,i){let r=!1,o=0;try{const c=this.doc.querySelectorAll(t);o=c.length,r=c.length===1&&c[0]===e}catch{return{selector:t,strategy:s,confidence:0,unique:!1,reasons:["invalid selector syntax"]}}let a=n;return o===0?(a=0,i.push("selector matched nothing (invalid candidate)")):o===1&&r?i.push("matches exactly this element"):(a=a*.4,i.push(`matches ${o} elements — ambiguous`)),{selector:t,strategy:s,confidence:Math.round(a*100)/100,unique:r,reasons:i}}isXPathUnique(e){try{return this.doc.evaluate(`count(${e})`,this.doc,null,4,null).numberValue===1}catch{return!1}}}function q(l){return Array.from(l.childNodes).filter(e=>e.nodeType===3).map(e=>(e.textContent||"").trim()).join(" ").replace(/\s+/g," ")}function we(l){return l.replace(/([^a-zA-Z0-9_\u00A0-\uFFFF-])/g,"\\$1")}function j(l){return l.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function et(l){return l.includes("'")?l.includes('"')?`concat(${l.split("'").map(e=>`'${e}'`).join(`, "'", `)})`:`"${l}"`:`'${l}'`}class tt{constructor(e,t){b(this,"fingerprintEngine",new te);b(this,"counter",0);this.doc=e,this.registry=t}buildTarget(e,t="selector"){var h;const s=new Y(this.doc),n=s.generateCandidates(e),i=s.bestSelector(e),r=this.fingerprintEngine.fingerprint(e),o=k.inspectElement(e,this.registry),a=e.getBoundingClientRect();let c=i.confidence*.6;return r.volatilityRisk==="low"?c+=.3:r.volatilityRisk==="medium"&&(c+=.15),n.find(g=>g.unique&&g.confidence>=.9)&&(c+=.1),c=Math.max(.05,Math.min(1,c)),this.counter++,{targetId:`tgt_${Date.now().toString(36)}_${this.counter}`,tag:e.tagName.toLowerCase(),role:o.role||r.role,selector:i.selector,selectorCandidates:n,xpath:s.buildXPath(e),domPath:(((h=o.context)==null?void 0:h.parentChain)||[]).concat(i.selector).join(" > "),textFingerprint:r.meaningfulText,attributeFingerprint:JSON.stringify(r.stableAttributes),structuralFingerprint:r.hash,attributes:o.attributes||{},confidence:Math.round(c*100)/100,bounds:{x:Math.round(a.x),y:Math.round(a.y),width:Math.round(a.width),height:Math.round(a.height)},resolvedFrom:t}}resolveAndBuild(e){let t=null,s="unknown";typeof e=="string"&&(e={selector:e});const n=e;if(n.selectedElementRef&&(s="selectedElementRef"),!t&&n.selector)try{const i=this.doc.querySelectorAll(n.selector);if(i.length===0)return{error:`TARGET_NOT_FOUND: selector "${n.selector}" matches no element`};i.length>1?(t=st(i,this.doc)||i[0],s+="+disambiguated"):(t=i[0],s="selector")}catch(i){return{error:`TARGET_INVALID: ${i.message}`}}if(!t&&n.xpath)try{t=this.doc.evaluate(n.xpath,this.doc,null,9,null).singleNodeValue,s="xpath"}catch(i){return{error:`TARGET_INVALID_XPATH: ${i.message}`}}if(!t&&typeof n.nodeId=="number"&&this.registry){const i=this.registry.getNode(n.nodeId);i&&i.nodeType===1&&this.doc.contains(i)&&(t=i,s="nodeId")}return!t&&n.coordinates&&(t=this.doc.elementFromPoint(n.coordinates.x,n.coordinates.y),s="coordinates"),t?{element:t,target:this.buildTarget(t,s)}:{error:"TARGET_NOT_FOUND: no usable resolution strategy succeeded"}}}function st(l,e){for(const t of Array.from(l)){const s=t;try{if(k.inspectElement(s).visibility.isVisible)return s}catch{}}return null}class nt{constructor(e){b(this,"fingerprintEngine",new te);this.doc=e}recover(e,t){var p;const s=[],n=[];let i=null;try{i=this.doc.querySelectorAll(e)}catch(y){s.push(`selector syntax error: ${y.message}`)}if(i&&i.length>0){s.push("selector still matches — no recovery needed");const y=i[0];return{recovered:!0,confidence:1,strategy:"original-selector",resolvedSelector:e,matchedElementInfo:Te(y),alternatives:[],diagnostics:s,recommendation:"Original selector works; the earlier failure was transient (likely a navigation or render race)."}}s.push("selector no longer matches any element");const o=this.collectCandidates(t,s).map(y=>({element:y,score:this.scoreMatch(y,t)})).filter(y=>y.score.score>.35).sort((y,v)=>v.score.score-y.score.score);for(const y of o.slice(0,5)){const v=new Y(this.doc).bestSelector(y.element);n.push({selector:v.selector,confidence:Math.round(y.score.score*100)/100,strategy:"recovery-match"})}if(!o.length)return{recovered:!1,confidence:0,strategy:"none",alternatives:n,diagnostics:s,recommendation:"No sufficiently similar element exists. The region may have been removed, or the page structure changed fundamentally. Re-inspect the page and capture a new target."};const a=o[0],c=o.length>1?a.score.score-o[1].score.score:1;s.push(`best candidate score: ${a.score.score.toFixed(3)} (margin ${c.toFixed(3)})`);for(const y of a.score.components)y.score>0&&s.push(` - ${y.name}: ${(y.score*100).toFixed(0)}%`);if(a.score.score<.62||o.length>1&&c<.15)return{recovered:!1,confidence:Math.round(a.score.score*100)/100,strategy:"recovery-refused",resolvedSelector:(p=n[0])==null?void 0:p.selector,alternatives:n,diagnostics:s,recommendation:"Recovery refused: best match is not confident enough or too close to a competing element. Inspect alternatives manually before acting — refusing to avoid acting on a wrong element."};const g=new Y(this.doc).bestSelector(a.element).selector;return{recovered:!0,confidence:Math.round(a.score.score*100)/100,strategy:"fingerprint-recovery",resolvedSelector:g,matchedElementInfo:Te(a.element),alternatives:n,diagnostics:s,recommendation:`Recovered target with ${(a.score.score*100).toFixed(0)}% confidence. Verify the resolved selector before destructive actions.`}}collectCandidates(e,t){var r,o;const s=new Set,n=this.doc.querySelectorAll(e.tag);let i=0;for(const a of Array.from(n))if(s.add(a),++i>=400)break;if((r=e.classes)!=null&&r.length){const a=e.classes.filter(c=>!ee(c));for(const c of a.slice(0,2))try{for(const u of Array.from(this.doc.querySelectorAll(`.${c}`)).slice(0,100))s.add(u)}catch{}}if((o=e.stableAttributes)!=null&&o.name)try{for(const a of Array.from(this.doc.querySelectorAll(`[name="${e.stableAttributes.name}"]`)))s.add(a)}catch{}if(e.parentSelector)try{for(const a of Array.from(this.doc.querySelectorAll(`${e.parentSelector} > ${e.tag}`)).slice(0,100))s.add(a)}catch{}return t.push(`collected ${s.size} candidate elements for scoring`),Array.from(s)}scoreMatch(e,t){const s=[],n=e.tagName.toLowerCase()===t.tag.toLowerCase()?1:0;s.push({name:"tag",score:n,weight:.15});const i=(t.text||"").trim().slice(0,40),r=q(e).slice(0,40),o=(e.textContent||"").trim().slice(0,40);let a=0;if(i){const d=r?r===i?1:oe(i,r):0,f=o?o===i?1:oe(i,o):0;a=Math.max(d,f)}s.push({name:"text",score:a,weight:.3});const c=new Set((t.classes||[]).filter(d=>!ee(d))),u=Array.from(e.classList||[]),h=c.size?u.filter(d=>c.has(d)).length/c.size:.5;s.push({name:"classes",score:h,weight:.2});const g=t.stableAttributes||{},p=Object.keys(g);let y=.5;if(p.length){let d=0;for(const f of p)e.getAttribute(f)===g[f]&&d++;y=d/p.length}s.push({name:"attributes",score:y,weight:.2});const v=t.childCount!==void 0?e.children.length===t.childCount?1:oe(String(t.childCount),String(e.children.length)):.5;if(s.push({name:"childCount",score:v,weight:.05}),t.fingerprintHash){const d={fingerprintId:"snapshot",hash:t.fingerprintHash,tagHierarchy:[t.tag],stableAttributes:g,meaningfulText:i,classes:t.classes||[],dimensions:{width:0,height:0},ancestorPattern:"",descendantPattern:"",volatilityRisk:"medium",volatilityReasons:[]},f=this.fingerprintEngine.fingerprint(e),w=this.fingerprintEngine.compare(d,f);s.push({name:"fingerprint",score:w.score,weight:.1})}const m=s.reduce((d,f)=>d+f.score*f.weight,0);return{score:Math.max(0,Math.min(1,m)),components:s}}diagnose(e){const t=[];let s=!0,n=0,i,r=[];try{n=this.doc.querySelectorAll(e).length}catch(o){s=!1,i=o.message,t.push("Selector is syntactically invalid CSS.")}if(s&&n===0){t.push("Selector parses but matches nothing — element may be removed, re-rendered, or inside a shadow root."),r=this.relaxSelector(e);for(const o of r)try{if(this.doc.querySelectorAll(o).length>0){t.push(`Relaxed form "${o}" matches — the over-specific part of the selector is stale.`);break}}catch{}}return s&&n>1&&t.push(`Selector matches ${n} elements — it is ambiguous; use a more specific form or index.`),{selector:e,valid:s,matches:n,parseError:i,closestWorkingSelectors:r.filter(o=>{try{return this.doc.querySelectorAll(o).length>0}catch{return!1}}),diagnosis:t}}relaxSelector(e){const t=[],s=e.split(/[ >]+/).filter(Boolean);s.length>1&&(t.push(s.slice(0,-1).join(" ")),t.push(s[s.length-1]));const n=e.replace(/:nth-of-type\(\d+\)/g,"").replace(/\.[^. >#:[]+/g,(i,r,o)=>o[r-1]==="\\"?i:"");return n!==e&&n.trim()&&t.push(n.trim()),t}}function oe(l,e){if(!l||!e)return 0;const t=Se(l),s=Se(e);if(t===s)return 1;if(t.includes(s)||s.includes(t))return .7;const n=new Set(t.split(/\s+/)),i=new Set(s.split(/\s+/));return Array.from(n).filter(o=>i.has(o)).length/Math.max(n.size,i.size)}function Se(l){return l.toLowerCase().replace(/[^a-z0-9 ]/g," ").replace(/\s+/g," ").trim()}function Te(l){return{tag:l.tagName.toLowerCase(),id:l.getAttribute("id")||void 0,text:q(l).slice(0,60),classes:Array.from(l.classList||[])}}class ae{constructor(e){b(this,"state");this.state=e>>>0,this.state===0&&(this.state=2654435769)}next(){this.state=this.state+1831565813>>>0;let e=this.state;return e=Math.imul(e^e>>>15,e|1),e^=e+Math.imul(e^e>>>7,e|61),((e^e>>>14)>>>0)/4294967296}range(e,t){return e+this.next()*(t-e)}int(e,t){return Math.floor(this.range(e,t+1))}chance(e){return this.next()setTimeout(t,e))}chance(){return this.rng.next()<.5}}const rt=[{ruleId:"red_key_password",kind:"key-pattern",pattern:"password|passwd|pwd",description:"Keys containing password/passwd/pwd",enabled:!0,userAdded:!1},{ruleId:"red_key_token",kind:"key-pattern",pattern:"token|jwt|bearer|auth|session.?id|secret|api.?key|client.?secret",description:"Keys containing token/jwt/auth/session-id/secret/api-key",enabled:!0,userAdded:!1},{ruleId:"red_key_credential",kind:"key-pattern",pattern:"credential|login|user.?pass|otp|2fa|mfa|verification",description:"Keys containing credential/login/otp/2fa/verification",enabled:!0,userAdded:!1},{ruleId:"red_key_payment",kind:"key-pattern",pattern:"card|payment|billing|iban|cvv|cvc|pan",description:"Keys containing card/payment/billing/iban/cvv",enabled:!0,userAdded:!1},{ruleId:"red_key_personal",kind:"key-pattern",pattern:"ssn|social.?security|national.?id|passport|tax.?id",description:"Keys containing personal identifier patterns",enabled:!0,userAdded:!1},{ruleId:"red_val_jwt",kind:"value-pattern",pattern:"eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+",description:"JWT-shaped tokens",enabled:!0,userAdded:!1},{ruleId:"red_val_bearer",kind:"value-pattern",pattern:"bearer\\s+[A-Za-z0-9._-]+",description:"Bearer tokens",enabled:!0,userAdded:!1},{ruleId:"red_val_long_hex",kind:"value-pattern",pattern:"\\b[a-f0-9]{32,}\\b",description:"32+ char hex strings (session/API ids)",enabled:!0,userAdded:!1},{ruleId:"red_val_sk",kind:"value-pattern",pattern:"\\b(sk|pk|rk)_[A-Za-z0-9_]{20,}\\b",description:"Stripe-style secret keys (sk_live_…)",enabled:!0,userAdded:!1},{ruleId:"red_attr_input_password",kind:"attribute-name",pattern:"value",description:"value attributes on password inputs handled by PrivacyEngine maskValue",enabled:!0,userAdded:!1},{ruleId:"red_attr_secret",kind:"attribute-name",pattern:"data-secret|data-token|data-api-key|secret|access.?token",description:"Secret-carrying attributes",enabled:!0,userAdded:!1}],ot=[{exclusionId:"excl_mcpdom_overlay",selector:"[data-mcpdom-internal], [data-forensic-internal], #forensic-recorder-floating-host, #forensic-inspect-highlighter",reason:"MCPDOM-injected UI must never contaminate captured DOM (§68 clean capture)",userAdded:!1},{exclusionId:"excl_mcpdom_ids",selector:'[id^="forensic-"], [id^="mcpdom-"]',reason:"MCPDOM-namespaced nodes",userAdded:!1}],ce="[REDACTED]";class le{constructor(e){b(this,"config");b(this,"base",new J);b(this,"compiledKeyPatterns",[]);b(this,"compiledValuePatterns",[]);b(this,"compiledAttrPatterns",[]);this.config={rules:[...rt],exclusions:[...ot],stubMode:!0,...e},this.recompile()}recompile(){this.compiledKeyPatterns=[],this.compiledValuePatterns=[],this.compiledAttrPatterns=[];for(const e of this.config.rules){if(!e.enabled)continue;const t="i";try{switch(e.kind){case"key-pattern":this.compiledKeyPatterns.push(new RegExp(e.pattern,t));break;case"value-pattern":this.compiledValuePatterns.push(new RegExp(e.pattern,"i"));break;case"attribute-name":this.compiledAttrPatterns.push(new RegExp(`^(${e.pattern})$`,"i"));break}}catch{}}}getRules(){return[...this.config.rules]}setRuleEnabled(e,t){const s=this.config.rules.find(n=>n.ruleId===e);return s?(s.enabled=t,this.recompile(),!0):!1}addRule(e){const t=`red_custom_${this.config.rules.length+1}_${Date.now().toString(36)}`,s={...e,ruleId:t,userAdded:!0};return this.config.rules.push(s),this.recompile(),s}removeRule(e){const t=this.config.rules.findIndex(s=>s.ruleId===e);return t<0||!this.config.rules[t].userAdded?!1:(this.config.rules.splice(t,1),this.recompile(),!0)}getExclusions(){return[...this.config.exclusions]}addExclusion(e,t){const n={exclusionId:`excl_custom_${this.config.exclusions.length+1}_${Date.now().toString(36)}`,selector:e,reason:t,userAdded:!0};return this.config.exclusions.push(n),n}removeExclusion(e){const t=this.config.exclusions.findIndex(s=>s.exclusionId===e);return t<0||!this.config.exclusions[t].userAdded?!1:(this.config.exclusions.splice(t,1),!0)}isSensitiveKey(e){return this.compiledKeyPatterns.some(t=>t.test(e))}redactValue(e){let t=e;for(const s of this.compiledValuePatterns)s.test(t)&&(t=t.replace(new RegExp(s.source,"gi"),ce));return t}redactByKeyValue(e,t){return this.isSensitiveKey(e)?this.config.stubMode?ce:t:this.redactValue(t)}isSensitiveAttribute(e){return this.compiledAttrPatterns.some(t=>t.test(e))}redactAttributes(e){const t={};for(const[s,n]of Object.entries(e))this.isSensitiveAttribute(s)?t[s]=ce:t[s]=this.redactValue(n);return t}cleanSubtree(e){const t=e.cloneNode(!0);for(const s of this.config.exclusions){let n=null;try{n=t.querySelectorAll(s.selector)}catch{continue}for(const i of Array.from(n))i.remove();try{if(t.matches(s.selector))return this.doclessEmptyStub(t)}catch{}}return t}isExcluded(e){for(const t of this.config.exclusions)try{if(e.matches(t.selector)||e.closest(t.selector))return!0}catch{}return!1}doclessEmptyStub(e){return e.innerHTML="",e.setAttribute("data-mcpdom-excluded","true"),e}toJSON(){return{rules:this.getRules(),exclusions:this.getExclusions(),stubMode:this.config.stubMode}}static fromJSON(e){return new le({rules:Array.isArray(e==null?void 0:e.rules)?e.rules:void 0,exclusions:Array.isArray(e==null?void 0:e.exclusions)?e.exclusions:void 0,stubMode:typeof(e==null?void 0:e.stubMode)=="boolean"?e.stubMode:void 0})}}const ue='a[href], button, input, select, textarea, [role="button"], [role="link"], [role="tab"], [onclick], [tabindex]';function F(l,e){return{items:l.slice(0,e),truncated:l.length>e}}function _(l,e,t,s,n,i){return{analyzer:l,summary:e,count:t,items:s,warnings:n,truncated:i}}function O(l){try{return k.inspectElement(l).bestSelector}catch{return l.tagName.toLowerCase()}}const at=l=>{const e=Array.from(l.querySelectorAll("form")),t=e.map(n=>{const i=Array.from(n.querySelectorAll("input, select, textarea")).map(r=>({tag:r.tagName.toLowerCase(),type:r.getAttribute("type")||(r.tagName.toLowerCase()==="textarea"?"textarea":r.tagName.toLowerCase()==="select"?"select":"text"),name:r.getAttribute("name")||void 0,id:r.getAttribute("id")||void 0,required:r.hasAttribute("required"),pattern:r.getAttribute("pattern")||void 0,maxLength:r.getAttribute("maxlength")||void 0,placeholder:r.getAttribute("placeholder")||void 0,ariaLabel:r.getAttribute("aria-label")||void 0,autocomplete:r.getAttribute("autocomplete")||void 0,hasLabel:!!(r.getAttribute("id")&&l.querySelector(`label[for="${r.getAttribute("id")}"]`))||!!r.closest("label"),defaultValue:r.value!==void 0&&(r.getAttribute("type")||"text")!=="password"?String(r.value).slice(0,40):void 0}));return{selector:O(n),action:n.getAttribute("action")||void 0,method:(n.getAttribute("method")||"GET").toUpperCase(),id:n.getAttribute("id")||void 0,fieldCount:i.length,submitButton:n.querySelector('button[type="submit"], input[type="submit"]')?O(n.querySelector('button[type="submit"], input[type="submit"]')):void 0,validationAttributes:i.filter(r=>r.required||r.pattern).length,fields:i}}),s=F(t,50);return _("analyze_forms",`${e.length} form(s) with ${t.reduce((n,i)=>n+i.fieldCount,0)} total fields`,e.length,s.items,[],s.truncated)},ct=l=>{const e=Array.from(l.querySelectorAll("a[href]")),t=e.map(n=>({href:n.getAttribute("href")||"",text:q(n).slice(0,60),selector:O(n),rel:n.getAttribute("rel")||void 0,target:n.getAttribute("target")||void 0,download:n.hasAttribute("download"),external:/^https?:\/\//i.test(n.getAttribute("href")||"")&&!lt(n.getAttribute("href")||"",l),anchorOnly:(n.getAttribute("href")||"").startsWith("#")})),s=F(t,200);return _("extract_links",`${e.length} link(s): ${t.filter(n=>n.external).length} external, ${t.filter(n=>n.anchorOnly).length} anchors`,e.length,s.items,[],s.truncated)};function lt(l,e){var t,s,n,i;try{return new URL(l,((s=(t=e.defaultView)==null?void 0:t.location)==null?void 0:s.href)||"http://localhost").origin===(((i=(n=e.defaultView)==null?void 0:n.location)==null?void 0:i.origin)||"")}catch{return!1}}const ut=l=>{const e=Array.from(l.querySelectorAll("img")),t=Array.from(l.querySelectorAll("video")),s=Array.from(l.querySelectorAll("audio")),n=Array.from(l.querySelectorAll("canvas")),i=[],r=[...e.map(c=>({kind:"img",selector:O(c),src:(c.getAttribute("src")||"").slice(0,150),alt:c.getAttribute("alt"),width:c.getAttribute("width")||void 0,height:c.getAttribute("height")||void 0,naturalWidth:c.naturalWidth||void 0,naturalHeight:c.naturalHeight||void 0,lazy:c.getAttribute("loading")==="lazy",missingAlt:!c.hasAttribute("alt")})),...t.map(c=>{var u;return{kind:"video",selector:O(c),src:(c.getAttribute("src")||((u=c.querySelector("source"))==null?void 0:u.getAttribute("src"))||"").slice(0,150),controls:c.hasAttribute("controls"),autoplay:c.hasAttribute("autoplay"),muted:c.hasAttribute("muted"),poster:c.getAttribute("poster")||void 0}}),...s.map(c=>{var u;return{kind:"audio",selector:O(c),src:(c.getAttribute("src")||((u=c.querySelector("source"))==null?void 0:u.getAttribute("src"))||"").slice(0,150),controls:c.hasAttribute("controls")}}),...n.map(c=>({kind:"canvas",selector:O(c),width:c.width,height:c.height}))],o=r.filter(c=>c.missingAlt).length;o&&i.push(`${o} image(s) missing alt text (accessibility risk).`);const a=F(r,200);return _("analyze_media",`${e.length} images, ${t.length} videos, ${s.length} audios, ${n.length} canvases`,r.length,a.items,i,a.truncated)},dt=l=>{const e=l.defaultView,t=[],s={};if(e!=null&&e.getComputedStyle){const i=e.getComputedStyle(l.documentElement);for(let r=0;r({name:i,value:r}));return _("get_css_variables",`${n.length} CSS custom properties found`,n.length,n,t,!1)},ht=l=>{const e=l.defaultView,t=[],s=new Map;if(e!=null&&e.getComputedStyle)for(const i of Array.from(l.querySelectorAll("body, body *")).slice(0,800)){const r=e.getComputedStyle(i),o=r.fontFamily||"",a=r.fontSize||"",c=`${o.split(",")[0].replace(/["']/g,"").trim()} @ ${a}`;s.set(c,(s.get(c)||0)+1)}else t.push("getComputedStyle unavailable — font usage analysis requires rendered styles.");const n=Array.from(s.entries()).map(([i,r])=>({font:i,usage:r})).sort((i,r)=>r.usage-i.usage);return _("analyze_fonts",`${n.length} distinct font/size combinations`,n.length,n,t,!1)},gt=l=>{const e=l.defaultView,t=[],s=new Map;if(e!=null&&e.getComputedStyle)for(const i of Array.from(l.querySelectorAll("body, body *")).slice(0,800)){const r=e.getComputedStyle(i);for(const o of["color","background-color","border-top-color"]){const a=r.getPropertyValue(o);a&&a!=="rgba(0, 0, 0, 0)"&&s.set(a,(s.get(a)||0)+1)}}else{for(const i of Array.from(l.querySelectorAll("[style]")).slice(0,300)){const r=i.getAttribute("style")||"",o=/(color)\s*:\s*([^;]+)/gi;let a;for(;a=o.exec(r);)s.set(a[2].trim(),(s.get(a[2].trim())||0)+1)}t.push("getComputedStyle unavailable — palette from inline styles only.")}const n=Array.from(s.entries()).map(([i,r])=>({color:i,usage:r})).sort((i,r)=>r.usage-i.usage).slice(0,40);return _("extract_color_palette",`${s.size} distinct colors in use`,s.size,n,t,!1)},pt=l=>{const e=l.defaultView,t=[],s=[];if(!(e!=null&&e.getComputedStyle))return t.push("getComputedStyle unavailable — z-index analysis requires rendered styles."),_("detect_zindex_conflicts","unavailable",0,[],t,!1);const n=[];for(const i of Array.from(l.querySelectorAll("body *")).slice(0,1e3)){const r=e.getComputedStyle(i),o=r.zIndex;o&&o!=="auto"&&parseInt(o,10)>0&&n.push({selector:O(i),z:parseInt(o,10),position:r.position,stacking:r.position==="fixed"||r.position==="sticky"||r.opacity!=="1"||r.transform!=="none"?"creates-stacking-context":"plain"})}for(let i=0;i1e5&&s.push({zIndex:n[i].z,elements:[n[i].selector],note:"extremely high z-index — competes with platform overlays (MCPDOM uses 2147483640+)."})}return _("detect_zindex_conflicts",`${n.length} z-indexed elements, ${s.length} potential conflict(s)`,s.length,F(s,40).items,t,s.length>40)},mt=l=>{const e=l.defaultView,t=[],s=l.documentElement,n=l.body,i=Math.max((s==null?void 0:s.scrollWidth)||0,(n==null?void 0:n.scrollWidth)||0),r=(e==null?void 0:e.innerWidth)||(s==null?void 0:s.clientWidth)||0,o=i>r+1;if(o&&(t.push({issue:"horizontal-overflow",detail:`document scrollWidth ${i} exceeds viewport ${r}`}),e!=null&&e.getComputedStyle))for(const c of Array.from(l.querySelectorAll("body *")).slice(0,600)){const u=c.getBoundingClientRect();if(u.right>r+2&&u.width>100&&(t.push({issue:"element-exceeds-viewport",selector:O(c),right:Math.round(u.right),width:Math.round(u.width)}),t.length>15))break}let a=0;for(const c of Array.from(l.querySelectorAll(ue)).slice(0,500)){const u=c.getBoundingClientRect();(u.width===0||u.height===0)&&a++}return a&&t.push({issue:"zero-size-interactive-elements",count:a}),_("detect_layout_issues",o?`HORIZONTAL OVERFLOW: page is ${i-r}px wider than viewport`:"No horizontal overflow detected",t.length,t,[],!1)},ft=l=>{const e=Array.from(l.querySelectorAll(ue)),t=new Map,s=e.slice(0,300).map(n=>{const i=de(n),r=i.role||n.tagName.toLowerCase();return t.set(r,(t.get(r)||0)+1),{selector:i.bestSelector,tag:i.tag,role:i.role,text:i.text.slice(0,40),visible:i.visibility.isVisible,disabled:n.disabled||n.hasAttribute("disabled"),inViewport:i.visibility.isInViewport}});return _("census_interactive_elements",`${e.length} interactive elements: ${Array.from(t.entries()).map(([n,i])=>`${n}×${i}`).join(", ")||"none"}`,e.length,s,[],e.length>300)};function de(l){try{return k.inspectElement(l)}catch{return{tag:l.tagName.toLowerCase(),role:void 0,text:"",bestSelector:l.tagName.toLowerCase(),bounds:{x:0,y:0,width:0,height:0,top:0,right:0,bottom:0,left:0},visibility:{isVisible:!1,isInViewport:!1}}}}const bt=l=>{const e=["header","nav","main","aside","footer","article","section","figure","figcaption","mark","time","address","details","summary","dialog"],t=[];for(const i of e){const r=Array.from(l.querySelectorAll(i));if(r.length)for(const o of r.slice(0,20))t.push({tag:i,selector:O(o),role:o.getAttribute("role")||yt(i),text:q(o).slice(0,50),childCount:o.children.length})}const s=t.filter(i=>["banner","navigation","main","complementary","contentinfo"].includes(i.role)),n=[];return t.find(i=>i.tag==="main")||n.push("No
element — page lacks a primary landmark."),l.querySelectorAll("header").length>1&&n.push("Multiple
elements outside sections — ambiguous banner landmark."),_("detect_semantic_elements",`${t.length} semantic elements, ${s.length} landmarks`,t.length,F(t,100).items,n,t.length>100)};function yt(l){return{header:"banner",nav:"navigation",main:"main",aside:"complementary",footer:"contentinfo",article:"article",section:"region",form:"form"}[l]}const Ce={analyze_forms:at,extract_links:ct,analyze_media:ut,get_css_variables:dt,analyze_fonts:ht,extract_color_palette:gt,detect_zindex_conflicts:pt,detect_layout_issues:mt,census_interactive_elements:ft,detect_semantic_elements:bt,scan_accessibility_issues:l=>{var i;const e=[];for(const r of Array.from(l.querySelectorAll("img")).slice(0,200))r.hasAttribute("alt")||e.push({rule:"img-alt",severity:"error",selector:O(r),message:"Image is missing the alt attribute."});for(const r of Array.from(l.querySelectorAll("input:not([type=hidden]):not([type=submit]):not([type=button])")).slice(0,200)){const o=r.getAttribute("id");o&&l.querySelector(`label[for="${o}"]`)||r.closest("label")||r.getAttribute("aria-label")||r.getAttribute("aria-labelledby")||e.push({rule:"input-label",severity:"error",selector:O(r),message:"Form input has no associated label, aria-label or aria-labelledby."})}for(const r of Array.from(l.querySelectorAll('button, a[href], [role="button"]')).slice(0,300)){const o=q(r).trim(),a=r.getAttribute("aria-label");!o&&!a&&e.push({rule:"accessible-name",severity:"error",selector:O(r),message:"Interactive element has no accessible name (no text, no aria-label).",hint:r.querySelector("img[alt]")?"Contains an image — consider alt text or aria-label.":void 0})}const t=Array.from(l.querySelectorAll("h1, h2, h3, h4, h5, h6")).slice(0,100);let s=0;for(const r of t){const o=parseInt(r.tagName[1],10);s&&o>s+1&&e.push({rule:"heading-order",severity:"warning",selector:O(r),message:`Heading level jumps from h${s} to h${o}.`}),s=o}(i=l.documentElement)!=null&&i.getAttribute("lang")||e.push({rule:"html-lang",severity:"warning",selector:"html",message:"The element has no lang attribute."});const n=e.filter(r=>r.severity==="error").length;return _("scan_accessibility_issues",`${e.length} issue(s): ${n} errors, ${e.length-n} warnings`,e.length,F(e,100).items,[],e.length>100)},detect_dead_click_targets:l=>{const e=l.defaultView,t=[];for(const s of Array.from(l.querySelectorAll(ue)).slice(0,500)){const n=s.getBoundingClientRect(),i=e!=null&&e.getComputedStyle?e.getComputedStyle(s):null,r=n.width===0||n.height===0,o=i?i.pointerEvents==="none":!1,a=i?i.display==="none"||i.visibility==="hidden":!1,c=s.getAttribute("aria-hidden")==="true";(r||o||a||c)&&t.push({selector:O(s),tag:s.tagName.toLowerCase(),text:q(s).slice(0,30),reasons:[r&&"zero-size",o&&"pointer-events:none",a&&`hidden (${i?i.display:"?"}/${i?i.visibility:"?"})`,c&&"aria-hidden"].filter(Boolean)})}return _("detect_dead_click_targets",`${t.length} unreachable interactive element(s)`,t.length,F(t,80).items,[],t.length>80)},inventory_animations:l=>{const e=l.defaultView,t=[],s=[];if(!(e!=null&&e.getComputedStyle))return t.push("getComputedStyle unavailable — animation inventory requires rendered styles."),_("inventory_animations","unavailable",0,[],t,!1);for(const i of Array.from(l.querySelectorAll("body *")).slice(0,800)){const r=e.getComputedStyle(i),o=r.animationName!=="none"?`${r.animationName} ${r.animationDuration}`:null,a=r.transitionProperty!=="none"&&r.transitionProperty!=="all"?`${r.transitionProperty} ${r.transitionDuration}`:r.transitionProperty==="all"?`all ${r.transitionDuration}`:null;(o||a)&&s.push({selector:O(i),animation:o,transition:a,transitionTiming:r.transitionTimingFunction||void 0})}const n=s.filter(i=>i.animation&&i.animation.includes("infinite"));return n.length>5&&t.push(`${n.length} infinitely looping animations — may indicate decorative spinners or a stuck loading state.`),_("inventory_animations",`${s.length} animated/transitioning elements`,s.length,F(s,80).items,t,s.length>80)},map_frame_tree:l=>{const e=[],t=(n,i,r)=>{const o=Array.from(n.querySelectorAll("iframe, frame"));for(const a of o){const c=a.getAttribute("src")||"(no src)";let u=!1,h=null;try{const g=a.contentDocument;g&&(u=!0,h=g.querySelectorAll("*").length,r<3&&t(g,`${i} > ${a.tagName.toLowerCase()}[${c.slice(0,50)}]`,r+1))}catch{u=!1}e.push({path:`${i} > ${a.tagName.toLowerCase()}`,selector:O(a),src:c.slice(0,120),title:a.getAttribute("title")||void 0,name:a.getAttribute("name")||void 0,sandbox:a.getAttribute("sandbox")||void 0,accessible:u,childCount:h,limitation:u?void 0:"Same-origin policy blocks contentDocument access (cross-origin frame)."})}};t(l,"document",0);const s=e.filter(n=>!n.accessible).length;return _("map_frame_tree",`${e.length} frame(s), ${s} inaccessible (cross-origin)`,e.length,e,[],!1)},inventory_shadow_roots:l=>{const e=[],t=(s,n,i)=>{const r=(s instanceof ShadowRoot,Array.from(s.querySelectorAll("*")));for(const o of r)if(o.shadowRoot){const a=o.shadowRoot,c=`${n} > ${o.tagName.toLowerCase()}::shadowRoot(${a.mode})`;e.push({path:c.slice(0,200),hostSelector:O(o),hostTag:o.tagName.toLowerCase(),mode:a.mode,childCount:a.querySelectorAll("*").length,styles:a.querySelectorAll("style").length}),i<4&&t(a,c,i+1)}};return t(l.documentElement,"document",0),_("inventory_shadow_roots",`${e.length} open shadow root(s) found`,e.length,e,[],!1)},inspect_page_storage:l=>{const e=l.defaultView,t=new le,s=[],n=[];if(!(e!=null&&e.localStorage)||!(e!=null&&e.sessionStorage))return _("inspect_page_storage","Web Storage API unavailable in this context",0,[],["localStorage/sessionStorage are not accessible here (JSDOM limitation or sandboxed iframe)."],!1);try{for(let r=0;rr+(o.size||0),0);return _("inspect_page_storage",`${n.length} storage entries (~${i} bytes), sensitive keys redacted`,n.length,F(n,100).items,s,n.length>100)},get_performance_metrics:l=>{var i,r,o,a;const e=l.defaultView,t=[],s=e==null?void 0:e.performance;if(!(s!=null&&s.timing)&&!(s!=null&&s.getEntriesByType))return _("get_performance_metrics","Performance API unavailable",0,[],["window.performance is not exposed in this context."],!1);const n=[];try{const c=(r=(i=s.getEntriesByType)==null?void 0:i.call(s,"navigation"))==null?void 0:r[0];if(c)n.push({metric:"navigation-timing",domContentLoaded:Math.round(c.domContentLoadedEventEnd),loadComplete:Math.round(c.loadEventEnd),domInteractive:Math.round(c.domInteractive),type:c.type,redirectCount:c.redirectCount,sizeTransfer:c.transferSize});else if(s.timing){const g=s.timing;n.push({metric:"navigation-timing-legacy",domContentLoaded:g.domContentLoadedEventEnd-g.navigationStart,loadComplete:g.loadEventEnd-g.navigationStart,domInteractive:g.domInteractive-g.navigationStart})}const u=((o=s.getEntriesByType)==null?void 0:o.call(s,"paint"))||[];for(const g of u)n.push({metric:g.name,startTime:Math.round(g.startTime)});const h=((a=s.getEntriesByType)==null?void 0:a.call(s,"resource"))||[];if(h.length){const g=h.reduce((y,v)=>y+v.duration,0),p=[...h].sort((y,v)=>v.duration-y.duration).slice(0,5).map(y=>({url:String(y.name).slice(0,100),duration:Math.round(y.duration)}));n.push({metric:"resource-summary",count:h.length,totalDuration:Math.round(g),slowest:p})}s.memory&&n.push({metric:"memory",usedJSHeapMB:Math.round(s.memory.usedJSHeapSize/1048576*10)/10,totalJSHeapMB:Math.round(s.memory.totalJSHeapSize/1048576*10)/10})}catch(c){t.push(`performance read failed: ${c.message}`)}return _("get_performance_metrics",`${n.length} metric group(s)`,n.length,n,t,!1)},extract_seo_metadata:l=>{var r,o,a;const e=c=>{var u;return((u=l.querySelector(`meta[name="${c}"]`))==null?void 0:u.getAttribute("content"))||void 0},t=c=>{var u;return((u=l.querySelector(`meta[property="${c}"]`))==null?void 0:u.getAttribute("content"))||void 0},s=[{field:"title",value:l.title||void 0},{field:"description",value:e("description")},{field:"canonical",value:(r=l.querySelector('link[rel="canonical"]'))==null?void 0:r.getAttribute("href")},{field:"robots",value:e("robots")},{field:"viewport",value:e("viewport")},{field:"charset",value:(o=l.querySelector("meta[charset]"))==null?void 0:o.getAttribute("charset")},{field:"og:title",value:t("og:title")},{field:"og:description",value:t("og:description")},{field:"og:image",value:t("og:image")},{field:"og:url",value:t("og:url")},{field:"twitter:card",value:e("twitter:card")},{field:"language",value:(a=l.documentElement)==null?void 0:a.getAttribute("lang")}],n=l.querySelectorAll("h1").length,i=[];return n===0&&i.push("No h1 — page lacks a primary heading."),n>1&&i.push(`Multiple h1 elements (${n}).`),e("description")||i.push("No meta description."),s.push({field:"h1Count",value:n}),_("extract_seo_metadata",`SEO metadata extracted; ${i.length} warning(s)`,s.length,s,i,!1)},extract_structured_data:l=>{var t;const e=[];for(const s of Array.from(l.querySelectorAll('script[type="application/ld+json"]')))try{const n=JSON.parse(s.textContent||"{}");e.push({format:"JSON-LD",type:n["@type"]||(Array.isArray(n)?"array":"unknown"),data:n})}catch(n){e.push({format:"JSON-LD",type:"invalid-json",error:n.message})}for(const s of Array.from(l.querySelectorAll("[itemscope]")).slice(0,30)){const n=s.getAttribute("itemtype")||"unknown",i={};for(const r of Array.from(s.querySelectorAll("[itemprop]"))){const o=r.getAttribute("itemprop")||"",a=r.getAttribute("content")||r.getAttribute("href")||((t=r.textContent)==null?void 0:t.trim())||"";i[o]=a.slice(0,100)}e.push({format:"microdata",type:n.split("/").pop()||n,data:i})}return _("extract_structured_data",`${e.length} structured data block(s)`,e.length,e,[],!1)},extract_tables:l=>{const e=Array.from(l.querySelectorAll("table")),t=e.slice(0,30).map(s=>{var a,c,u;const n=Array.from(s.querySelectorAll("thead th, tr:first-child th")).map(h=>{var g;return((g=h.textContent)==null?void 0:g.trim())||""}),i=Array.from(s.querySelectorAll("tbody tr, tr")).filter(h=>!h.querySelector("th")).slice(0,50),r=i.map(h=>Array.from(h.querySelectorAll("td")).map(g=>(g.textContent||"").trim().slice(0,60))),o=(c=(a=s.querySelector("caption"))==null?void 0:a.textContent)==null?void 0:c.trim();return{selector:O(s),caption:o,columnCount:n.length||((u=r[0])==null?void 0:u.length)||0,rowCount:i.length,headers:n,rows:r}});return _("extract_tables",`${e.length} table(s)`,e.length,t,[],e.length>30)},extract_lists:l=>{const e=Array.from(l.querySelectorAll("ul, ol")),t=e.slice(0,60).map(s=>{const n=Array.from(s.querySelectorAll(":scope > li")).slice(0,40);return{selector:O(s),kind:s.tagName.toLowerCase(),ordered:s.tagName.toLowerCase()==="ol",itemCount:n.length,items:n.map(i=>q(i).slice(0,60)),nested:s.querySelectorAll("ul, ol").length}});return _("extract_lists",`${e.length} list(s)`,e.length,t,[],e.length>60)},analyze_page_content:l=>{const e=l.body,t=(e==null?void 0:e.innerText)||(e==null?void 0:e.textContent)||"",s=t.trim()?t.trim().split(/\s+/).length:0,n=Array.from(l.querySelectorAll("h1, h2, h3, h4, h5, h6")).map(c=>({level:parseInt(c.tagName[1],10),text:q(c).slice(0,80)})),i=l.querySelectorAll("p").length,r=i?Math.round(s/i):0,o=Math.round(s/220*10)/10,a=[{metric:"wordCount",value:s},{metric:"paragraphCount",value:i},{metric:"avgParagraphWords",value:r},{metric:"estimatedReadingMinutes",value:o},{metric:"headingCount",value:n.length},{metric:"imageCount",value:l.querySelectorAll("img").length},{metric:"linkDensity",value:Math.round(l.querySelectorAll("a[href]").length/Math.max(1,s)*1e3)/1e3},{metric:"headings",value:n.slice(0,50)}];return _("analyze_page_content",`${s} words, ${i} paragraphs, ~${o} min read`,a.length,a,[],!1)},search_dom:(l,e)=>{const t=String((e==null?void 0:e.query)||"").trim();if(!t)return _("search_dom","No query supplied",0,[],["Provide a text query; optionally tag/attr filters."],!1);const s=t.toLowerCase(),n=[],i=Math.min((e==null?void 0:e.limit)||50,200),r=Array.from(l.querySelectorAll("*"));for(const o of r){if(n.length>=i)break;if(e!=null&&e.tag&&o.tagName.toLowerCase()!==String(e.tag).toLowerCase())continue;const a=q(o),c=Array.from(o.attributes);let u=0,h="";o.tagName.toLowerCase().includes(s)&&(u+=.2,h="tag match"),a.toLowerCase().includes(s)&&a.length<200&&(u+=.6,h="text match");for(const g of c)if(g.name.toLowerCase().includes(s)||g.value.length<100&&g.value.toLowerCase().includes(s)){u+=.4,h=`attribute ${g.name} match`;break}if(e!=null&&e.attr){const g=String(e.attr).toLowerCase(),p=e.attrValue?String(e.attrValue).toLowerCase():null;if(c.find(v=>v.name.toLowerCase()===g&&(!p||v.value.toLowerCase().includes(p))))u+=.5;else continue}if(u>0){const g=de(o);n.push({selector:g.bestSelector,tag:g.tag,role:g.role,text:g.text.slice(0,60),score:Math.round(u*100)/100,reason:h,visible:g.visibility.isVisible,bounds:{x:Math.round(g.bounds.x),y:Math.round(g.bounds.y),w:Math.round(g.bounds.width),h:Math.round(g.bounds.height)}})}}return n.sort((o,a)=>a.score-o.score),_("search_dom",`${n.length} element(s) match "${t}"`,n.length,n,[],n.length>=i)},inventory_ctas:l=>{var t;const e=[];for(const s of Array.from(l.querySelectorAll('button, a[class*="btn"], a[class*="button"], input[type="submit"], [role="button"]')).slice(0,100)){const n=de(s);e.push({selector:n.bestSelector,tag:n.tag,text:n.text.slice(0,50),styleHint:(t=s.getAttribute("class"))==null?void 0:t.slice(0,60),primary:/primary|cta|submit|main/i.test(s.getAttribute("class")||"")||s.type==="submit",visible:n.visibility.isVisible})}return _("inventory_ctas",`${e.length} call-to-action element(s)`,e.length,e,[],!1)},detect_focus_traps:l=>{const e=[];for(const s of Array.from(l.querySelectorAll('[role="dialog"], [aria-modal="true"], dialog[open], .modal, [class*="modal"]')).slice(0,30)){const n=s.querySelectorAll('a[href], button, input, select, textarea, [tabindex]:not([tabindex="-1"])');e.push({selector:O(s),kind:s.getAttribute("role")||s.tagName.toLowerCase(),ariaModal:s.getAttribute("aria-modal"),focusableCount:n.length,firstFocusable:n[0]?O(n[0]):void 0,note:n.length===0?"Modal container has NO focusable elements — keyboard users are trapped.":void 0})}const t=l.querySelectorAll("[tabindex]>0");for(const s of Array.from(t).slice(0,20))e.push({selector:O(s),kind:"positive-tabindex",note:`tabindex=${s.tabIndex} breaks natural tab order.`});return _("detect_focus_traps",`${e.length} focus-management issue(s)/container(s)`,e.length,e,[],!1)},infer_responsive_breakpoints:l=>{const e=l.defaultView,t=[],s=new Set;for(const o of Array.from(l.querySelectorAll("style"))){const a=o.textContent||"",c=/@media[^{]*?\(\s*(?:min|max)-width\s*:\s*(\d+)(?:\.\d+)?px/g;let u;for(;u=c.exec(a);)s.add(parseInt(u[1],10))}for(const o of Array.from(l.querySelectorAll('link[rel="stylesheet"]')).slice(0,10)){const a=o.getAttribute("href")||"";if(/^\d+px$/.test(a)||a.includes("width=")){const c=a.match(/width=(\d+)/);c&&s.add(parseInt(c[1],10))}}for(const o of Array.from(l.querySelectorAll("img[srcset], source[srcset]")).slice(0,50)){const a=o.getAttribute("srcset")||"";for(const c of a.matchAll(/(\d+)w/g))s.add(parseInt(c[1],10))}e!=null&&e.matchMedia||t.push("matchMedia unavailable — live breakpoint probing skipped.");const n=Array.from(s).sort((o,a)=>o-a),i=n.map(o=>({breakpoint:o,note:o<=768?"mobile-class":o<=1024?"tablet-class":"desktop-class"})),r=e==null?void 0:e.innerWidth;if(r){const o=n.filter(a=>a<=r);i.unshift({breakpoint:`current viewport: ${r}px`,note:o.length?`below breakpoints: ${o.join(", ")}`:"no declared breakpoint below current width"})}return _("infer_responsive_breakpoints",`${n.length} breakpoint(s) inferred from CSS/srcset`,i.length,i,t,!1)},get_selection_state:l=>{var i;const e=l.defaultView,t=(i=e==null?void 0:e.getSelection)==null?void 0:i.call(e),s=l.activeElement,n=[{hasSelection:!!(t!=null&&t.toString()),selectedText:(t==null?void 0:t.toString().slice(0,200))||"",selectionRanges:(t==null?void 0:t.rangeCount)||0,activeElement:s?{tag:s.tagName.toLowerCase(),selector:O(s),editable:s.isContentEditable||["INPUT","TEXTAREA"].includes(s.tagName)}:null}];return _("get_selection_state",t!=null&&t.toString()?`Selection: "${t.toString().slice(0,40)}…"`:"No text selection",1,n,[],!1)}};function Et(l,e,t){const s=Ce[l];return s?s(e,t):{analyzer:l,summary:`Unknown analyzer "${l}". Available: ${Object.keys(Ce).join(", ")}`,count:0,items:[],warnings:[],truncated:!1}}const vt=2e3;class wt{constructor(e=vt){b(this,"events",[]);b(this,"cap");b(this,"counter",0);this.cap=Math.max(10,e)}record(e,t,s={}){this.counter++;const n={eventId:`evt_${Date.now().toString(36)}_${this.counter}`,timestamp:Date.now(),kind:e,operationId:s.operationId,sessionId:s.sessionId,detail:t,data:s.data};return this.events.push(n),this.events.length>this.cap&&this.events.splice(0,this.events.length-this.cap),n}query(e){let t=this.events;e.kind&&(t=t.filter(n=>n.kind===e.kind)),e.operationId&&(t=t.filter(n=>n.operationId===e.operationId)),e.sinceTimestamp&&(t=t.filter(n=>n.timestamp>=e.sinceTimestamp));const s=e.limit&&e.limit>0?e.limit:200;return t.slice(-s)}size(){return this.events.length}toJSON(){return[...this.events]}}class St{constructor(){b(this,"counter",0);b(this,"operations",new Map)}begin(e){this.counter++;const t=`op_${Date.now().toString(36)}_${this.counter}`;return this.operations.set(t,{operationId:t,tool:e,startedAt:Date.now(),status:"RUNNING",timelineEventIds:[]}),t}end(e,t,s){const n=this.operations.get(e);n&&(n.endedAt=Date.now(),n.status=t,n.relatedError=s)}attachEvent(e,t){const s=this.operations.get(e);s&&s.timelineEventIds.push(t)}trace(e){const t=this.operations.get(e);return t?{...t,durationMs:t.endedAt?t.endedAt-t.startedAt:void 0}:null}recent(e=100){return Array.from(this.operations.values()).slice(-e).map(t=>({...t,durationMs:t.endedAt?t.endedAt-t.startedAt:void 0}))}}const Ie=100;class Tt{constructor(e){b(this,"sessionId");b(this,"timeline",new wt);b(this,"operations",new St);b(this,"tabs",new Map);b(this,"activeTabId",null);b(this,"startedAt",Date.now());b(this,"snapshots",[]);b(this,"commandHistory",[]);b(this,"annotationCount",0);b(this,"projectId");b(this,"tabCounter",0);b(this,"commandCounter",0);this.sessionId=e||`sess_${Date.now().toString(36)}`}registerTab(e,t,s){const n=e!==void 0?Array.from(this.tabs.values()).find(o=>o.browserTabId===e):void 0;if(n)return n.lastSeenAt=Date.now(),n.status="OPEN",n.url=t||n.url,n.title=s||n.title,n;this.tabCounter++;const i=`stab_${this.tabCounter}_${Date.now().toString(36)}`,r={sessionTabId:i,browserTabId:e,url:t,title:s,createdAt:Date.now(),lastSeenAt:Date.now(),status:"OPEN"};return this.tabs.set(i,r),this.timeline.record("TAB_OPENED",`tab ${i} registered (${t||"no url"})`,{sessionId:this.sessionId}),r}closeTab(e){const t=this.tabs.get(e);return t?(t.status="CLOSED",t.lastSeenAt=Date.now(),this.timeline.record("TAB_CLOSED",`tab ${e} closed`,{sessionId:this.sessionId}),!0):!1}switchTab(e){const t=this.tabs.get(e);return!t||t.status==="CLOSED"?!1:(this.activeTabId=e,this.timeline.record("TAB_SWITCHED",`active tab → ${e}`,{sessionId:this.sessionId}),!0)}getTabs(){return Array.from(this.tabs.values())}getActiveTab(){if(this.activeTabId){const e=this.tabs.get(this.activeTabId);if(e&&e.status==="OPEN")return e}return Array.from(this.tabs.values()).find(e=>e.status==="OPEN")||null}markAllStale(){let e=0;for(const t of this.tabs.values())t.status==="OPEN"&&(t.status="STALE",e++);return e}captureSnapshot(e,t,s){var a,c,u;const n=e.defaultView,i=((a=e.documentElement)==null?void 0:a.outerHTML)||"",r=e.querySelectorAll('a[href], button, input, select, textarea, [role="button"]').length,o={snapshotId:`snap_${Date.now().toString(36)}_${this.snapshots.length+1}`,timestamp:Date.now(),url:((c=n==null?void 0:n.location)==null?void 0:c.href)||((u=e.location)==null?void 0:u.href)||"",title:e.title||"",viewport:{width:(n==null?void 0:n.innerWidth)||0,height:(n==null?void 0:n.innerHeight)||0,scrollX:(n==null?void 0:n.scrollX)||0,scrollY:(n==null?void 0:n.scrollY)||0,devicePixelRatio:(n==null?void 0:n.devicePixelRatio)||1},domLength:i.length,domHash:be(i),interactiveCount:r,selectedRegions:[],extensionEnabled:t,pendingMutations:s,annotationCount:this.annotationCount};return this.snapshots.push(o),this.snapshots.length>Ie&&this.snapshots.splice(0,this.snapshots.length-Ie),this.timeline.record("SNAPSHOT_CREATED",`snapshot ${o.snapshotId} (dom ${o.domLength}b)`,{sessionId:this.sessionId}),o}getSnapshot(e){return e?this.snapshots.find(t=>t.snapshotId===e)||null:this.snapshots[this.snapshots.length-1]||null}listSnapshots(){return this.snapshots.map(e=>({snapshotId:e.snapshotId,timestamp:e.timestamp,url:e.url,title:e.title,domLength:e.domLength,domHash:e.domHash}))}compareSnapshots(e,t){const s=["url","title","domLength","domHash","interactiveCount","extensionEnabled","annotationCount"],n=[];for(const r of s)e[r]!==t[r]&&n.push({field:r,before:e[r],after:t[r]});(e.viewport.width!==t.viewport.width||e.viewport.height!==t.viewport.height)&&n.push({field:"viewport",before:`${e.viewport.width}x${e.viewport.height}`,after:`${t.viewport.width}x${t.viewport.height}`});const i=t.domLength-e.domLength;return{identical:n.length===0,changes:n,domDelta:{beforeLength:e.domLength,afterLength:t.domLength,delta:i},summary:n.length===0?"States are identical.":`${n.length} field(s) changed; DOM size ${i>=0?"+":""}${i} bytes.`}}recordCommand(e,t,s,n,i){this.commandCounter++;const r=`cmd_${this.commandCounter}_${Date.now().toString(36)}`;return this.commandHistory.push({commandId:r,tool:e,args:t,outcome:s,timestamp:Date.now(),durationMs:n,error:i}),this.timeline.record("COMMAND_EXECUTED",`${e} → ${s}${i?` (${i})`:""}`,{sessionId:this.sessionId,data:{commandId:r}}),r}getCommandHistory(e=100){return this.commandHistory.slice(-e)}noteAnnotations(e){this.annotationCount=e}bindProject(e){this.projectId=e}getProjectId(){return this.projectId}summary(e,t,s,n){var i,r,o;return{sessionId:this.sessionId,startedAt:this.startedAt,url:((r=(i=e.defaultView)==null?void 0:i.location)==null?void 0:r.href)||((o=e.location)==null?void 0:o.href)||"",title:e.title||"",tabs:this.getTabs(),activeTabId:this.activeTabId,viewport:{width:t.width,height:t.height,isModified:t.isModified},extensionEnabled:s,snapshotCount:this.snapshots.length,commandCount:this.commandHistory.length,annotationCount:this.annotationCount,mutationHistoryCount:n.length,timelineEventCount:this.timeline.size(),projectId:this.projectId}}}const Ct=l=>{var e,t;try{const s=l.getBoundingClientRect();if(s.width===0&&s.height===0)return null;const n=((t=(e=l.ownerDocument)==null?void 0:e.defaultView)==null?void 0:t.innerWidth)||1920;return s.yn*1.5?"bottom":s.xn*.8?"right":"center"}catch{return null}},It={navigation:"navigation",banner:"header",contentinfo:"footer",complementary:"sidebar",main:"main",form:"form",search:"search",region:"section",dialog:"modal",alertdialog:"modal",table:"table",list:"list",combobox:"dropdown",button:"button",link:"link",textbox:"input",checkbox:"checkbox",radio:"radio",img:"image",article:"article"},At={nav:"navigation",header:"header",footer:"footer",aside:"sidebar",main:"main",section:"section",article:"article",form:"form",table:"table",ul:"list",ol:"list",figure:"figure",dialog:"modal",button:"button",input:"input",select:"dropdown",textarea:"textarea",canvas:"canvas",video:"video",img:"image",h1:"heading",h2:"heading",h3:"heading"};function Z(l){return l.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"").replace(/_{2,}/g,"_").slice(0,48).replace(/_$/,"")}class xt{generate(e){return this.generateFromMeta({tagName:e.tagName.toLowerCase(),role:e.getAttribute("role")||void 0,text:q(e).trim(),ariaLabel:e.getAttribute("aria-label")||void 0,stableClass:Array.from(e.classList||[]).find(t=>/^[a-z][a-z0-9-]{2,}$/i.test(t)&&!_t.has(t)),position:Ct(e),nearbyHeading:this.nearbyHeading(e)})}generateFromMeta(e){const t=[],s=[],n=e.role||Nt(e.tagName);if(n){const r=It[n]||n;s.push(r),t.push(`role=${n}`)}else{const r=At[e.tagName]||e.tagName;s.push(r),t.push(`tag=${e.tagName}`)}if(e.ariaLabel&&(s.unshift(Z(e.ariaLabel)),t.push(`aria-label="${e.ariaLabel.slice(0,30)}"`)),e.text&&e.text.length<=40){const r=Z(e.text.split(/\s+/).slice(0,3).join(" "));r&&r.length>=2&&(s.push(r),t.push(`text="${e.text.slice(0,30)}"`))}if(e.nearbyHeading){const r=Z(e.nearbyHeading.split(/\s+/).slice(0,3).join(" "));r&&!s.includes(r)&&(s.push(r),t.push(`nearby-heading="${e.nearbyHeading.slice(0,30)}"`))}e.stableClass&&s.length<3&&(s.push(Z(e.stableClass)),t.push(`class=${e.stableClass}`)),e.tagName==="input"&&(s.some(r=>r.includes("input"))||(s.push("input"),t.push("tag=input"))),s.join("_").length<12&&e.position&&(s.push(e.position),t.push(`position=${e.position}`));let i=Z(s.join("_"))||"unnamed_region";return/^\d/.test(i)&&(i=`el_${i}`),{name:i,evidence:t}}nearbyHeading(e){let t=e.parentElement;for(let n=0;t&&n<4;n++){const i=t.querySelector('h1, h2, h3, h4, [role="heading"]');if(i)return q(i).trim().slice(0,40)||null;t=t.parentElement}let s=e.previousElementSibling;for(let n=0;s&&n<4;n++){if(/^H[1-4]$/.test(s.tagName)){const i=q(s).trim();if(i)return i.slice(0,40)}s=s.previousElementSibling}return null}}const _t=new Set(["active","open","visible","hidden","selected","disabled","container","wrapper","root","item","col","row","flex","box","main","div","span","block"]);function Nt(l){switch(l){case"nav":return"navigation";case"header":return"banner";case"footer":return"contentinfo";case"aside":return"complementary";case"main":return"main";case"form":return"form";case"table":return"table";case"button":return"button";case"a":return"link";case"input":return"textbox";case"select":return"combobox";case"textarea":return"textbox";case"img":return"img";default:return null}}const kt=["display","position","flex-direction","grid-template-columns","width","height","background-color","color","font-size","border-radius","overflow"];class Mt{constructor(){b(this,"naming",new xt)}capture(e){const t=e.ownerDocument,s=new Y(t),n=new te,i=s.generateCandidates(e),r=s.bestSelector(e),o=n.fingerprint(e);let a=e,c=0,u="self";for(let d=0;d<3;d++){const f=a.parentElement;if(!f||f===t.body||f===t.documentElement)break;if(this.isMeaningfulContainer(f)){a=f,c=d+1,u="meaningful-ancestor";break}a=f,c=d+1}if(a===e){const d=e.parentElement;d&&d!==t.body&&e.querySelectorAll("*").length<4&&(a=d,c=1,u="direct-parent-fallback")}const h=this.boundedHtml(e,6e4),g=this.boundedHtml(a,12e4);k.inspectElement(e);const p=e.getBoundingClientRect(),y=t.defaultView,v={};if(y!=null&&y.getComputedStyle){const d=y.getComputedStyle(e);for(const f of kt){const w=d.getPropertyValue(f);w&&w!=="none"&&w!=="auto"&&(v[f]=w)}}const m=e.parentElement;return{regionHtml:h,contextHtml:g,boundary:{strategy:u,ancestorLevels:c,note:c===0?"Region captured standalone (no meaningful ancestor within 3 levels).":`Context includes ${c} ancestor level(s) up to a meaningful container.`},selectorCandidates:i,bestSelector:r.selector,xpath:s.buildXPath(e),fingerprintHash:o.hash,dimensions:{width:Math.round(p.width),height:Math.round(p.height)},position:{x:Math.round(p.x),y:Math.round(p.y)},relevantStyles:v,parentInfo:m?{tag:m.tagName.toLowerCase(),selector:Rt(m),text:q(m).slice(0,60)}:void 0,childrenCount:e.children.length,childTags:Array.from(e.children).slice(0,12).map(d=>d.tagName.toLowerCase()),nameHint:this.naming.generate(e),fingerprintVolatility:o.volatilityRisk,volatilityReasons:o.volatilityReasons}}isMeaningfulContainer(e){const t=e.tagName.toLowerCase();if(["section","article","aside","main","nav","header","footer","form"].includes(t)||e.hasAttribute("id")||e.hasAttribute("data-testid")||e.getAttribute("role")||e.children.length>1&&e.querySelector(":scope > *:nth-child(3)"))return!0;const s=e.getAttribute("style")||"";return!!(s.includes("grid")||s.includes("flex"))}boundedHtml(e,t){const s=e.outerHTML;return s.length<=t?s:s.slice(0,t)+` +`}}function Rt(l){try{return new Y(l.ownerDocument).bestSelector(l).selector}catch{return l.tagName.toLowerCase()}}class Ot{constructor(e){b(this,"nodeRegistry");b(this,"snapshotEngine");b(this,"picker");b(this,"interactionEngine");b(this,"observer");b(this,"mutationEngines",new WeakMap);b(this,"viewportControllers",new WeakMap);b(this,"targetingEngines",new WeakMap);b(this,"jsEngine",new Fe);b(this,"fingerprintEngine",new te);b(this,"humanInteraction",new it);b(this,"session",new Tt);b(this,"simulationTabs",[]);b(this,"simulationTabCounter",0);b(this,"simulationExtensions",[{id:"teledom@teledom",name:"TeleDOM Browser Intelligence Platform",version:"4.1.0",description:"The TeleDOM platform extension itself",enabled:!0,installType:"development",isApp:!1}]);b(this,"regionCapture",new Mt);this.nodeRegistry=e||new H;const t=new J,s=new ne;this.snapshotEngine=new he(this.nodeRegistry,t,s),this.picker=new Pe({nodeRegistry:this.nodeRegistry}),this.interactionEngine=new Le(this.nodeRegistry),this.observer=new qe(this.nodeRegistry),this.picker.initGlobalShortcutListener(),this.interactionEngine.setTimingHook(async n=>{const i=this.humanInteraction.delay(n);i>0&&await new Promise(r=>setTimeout(r,i))})}getMutationEngine(e){let t=this.mutationEngines.get(e);return t||(t=new Ue(e,this.nodeRegistry),this.mutationEngines.set(e,t)),t}getViewportController(e){let t=this.viewportControllers.get(e);return t||(t=new Be(e),this.viewportControllers.set(e,t)),t}getTargetingEngine(e){let t=this.targetingEngines.get(e);return t||(t=new tt(e,this.nodeRegistry),this.targetingEngines.set(e,t)),t}isSimulation(){return typeof globalThis.__FORENSIC_SIMULATION__<"u"}getPicker(){return this.picker}getInteractionEngine(){return this.interactionEngine}getObserver(){return this.observer}getNodeRegistry(){return this.nodeRegistry}async handleCommand(e,t=typeof document<"u"?document:{}){var o,a,c,u,h,g,p,y,v;const s=Date.now(),{id:n,command:i,payload:r}=e;try{switch(i){case"LIVE_PAGE_INSPECT":{const m=k.inspectPage(t);return this.success(n,i,m,s)}case"LIVE_ELEMENT_INSPECT":{const m=this.resolveTarget(r,t),d=k.inspectElement(m,this.nodeRegistry);return this.success(n,i,d,s)}case"GET_SELECTED_ELEMENT":{const m=this.picker.getLastSelectedElement();return this.success(n,i,m,s)}case"ELEMENT_PICKER_START":return this.picker.startPicker(),this.success(n,i,{pickerActive:!0},s);case"ELEMENT_PICKER_STOP":return this.picker.stopPicker(),this.success(n,i,{pickerActive:!1},s);case"LIVE_ELEMENT_INTERACT":{const m=r,d=await this.interactionEngine.interact(m,t);return this.success(n,i,d,s)}case"ELEMENT_OBSERVATION_START":{const m=this.resolveTarget(r,t),d=this.observer.startObservation(m,t);return this.success(n,i,d,s)}case"ELEMENT_OBSERVATION_STOP":{const m=this.observer.stopObservation(t);return this.success(n,i,m,s)}case"LIVE_DOM_SNAPSHOT":{if(((r==null?void 0:r.format)||"html")==="html"){const f=((o=t.documentElement)==null?void 0:o.outerHTML)||"";return this.success(n,i,{html:f},s)}const d=this.snapshotEngine.captureSnapshot(t,"live_session");return this.success(n,i,d,s)}case"LIVE_DOM_SUBTREE":{const m=this.resolveTarget(r,t),d=m.outerHTML||"",f=k.inspectElement(m,this.nodeRegistry);return this.success(n,i,{html:d,element:f},s)}case"GET_ELEMENT_VISUAL_STATE":{const m=this.resolveTarget(r,t),d=k.inspectVisualState(m);return this.success(n,i,d,s)}case"LIVE_PAGE_SCREENSHOT":case"LIVE_ELEMENT_SCREENSHOT":{const m=await this.handleScreenshotCapture(i,r,t);return this.success(n,i,m,s)}case"GET_TAB_CONSOLE_LOGS":{const{level:m,searchQuery:d,limit:f=100,clearAfterRead:w}=r||{};let E=typeof window<"u"&&window.__FORENSIC_CONSOLE_BUFFER__||[];if(m&&m!=="all"&&(E=E.filter(S=>S.level===m)),d){const S=String(d).toLowerCase();E=E.filter(T=>{var x,N;return((x=T.text)==null?void 0:x.toLowerCase().includes(S))||((N=T.source)==null?void 0:N.toLowerCase().includes(S))})}return f>0&&(E=E.slice(-f)),w&&typeof window<"u"&&window.__FORENSIC_CONSOLE_BUFFER__&&(window.__FORENSIC_CONSOLE_BUFFER__.length=0),this.success(n,i,{url:typeof window<"u"?window.location.href:"",title:t.title||"",totalCaptured:typeof window<"u"&&((a=window.__FORENSIC_CONSOLE_BUFFER__)==null?void 0:a.length)||E.length,returnedCount:E.length,logs:E},s)}case"GET_TAB_NETWORK_REQUESTS":{const{method:m,searchQuery:d,status:f,onlyErrors:w,limit:E=100,clearAfterRead:S}=r||{};let T=typeof window<"u"&&window.__FORENSIC_NETWORK_BUFFER__||[];if(m&&(T=T.filter(x=>{var N;return((N=x.method)==null?void 0:N.toUpperCase())===String(m).toUpperCase()})),f&&(T=T.filter(x=>x.status===Number(f))),w&&(T=T.filter(x=>x.error||x.status&&x.status>=400)),d){const x=String(d).toLowerCase();T=T.filter(N=>{var D;return(D=N.url)==null?void 0:D.toLowerCase().includes(x)})}return E>0&&(T=T.slice(-E)),S&&typeof window<"u"&&window.__FORENSIC_NETWORK_BUFFER__&&(window.__FORENSIC_NETWORK_BUFFER__.length=0),this.success(n,i,{url:typeof window<"u"?window.location.href:"",title:t.title||"",totalCaptured:typeof window<"u"&&((c=window.__FORENSIC_NETWORK_BUFFER__)==null?void 0:c.length)||T.length,returnedCount:T.length,requests:T},s)}case"CLOSE_TAB":{if(typeof globalThis.chrome<"u"&&((u=globalThis.chrome.runtime)!=null&&u.sendMessage)){const m=await new Promise(d=>{globalThis.chrome.runtime.sendMessage({type:"BROWSER_COMMAND_REQUEST",id:n,command:i,payload:r},f=>d(f))});if(m)return m}return this.isSimulation()?this.simulationCloseTab(r,t,n,i,s):typeof window<"u"?(setTimeout(()=>window.close(),100),this.success(n,i,{closed:!0,url:window.location.href,title:t.title},s)):this.success(n,i,{closed:!0},s)}case"RELOAD_TAB":{if(typeof globalThis.chrome<"u"&&((h=globalThis.chrome.runtime)!=null&&h.sendMessage)){const m=await new Promise(d=>{globalThis.chrome.runtime.sendMessage({type:"BROWSER_COMMAND_REQUEST",id:n,command:i,payload:r},f=>d(f))});if(m)return m}if(this.isSimulation()){const m=(r==null?void 0:r.mode)||"soft";return this.session.timeline.record("NAVIGATED",`tab reloaded (${m} mode)`),this.success(n,i,{reloaded:!0,mode:m,simulated:!0,url:((p=(g=t.defaultView)==null?void 0:g.location)==null?void 0:p.href)||"",title:t.title,note:"Node simulation context: DOM fixture retained; no real navigation occurs."},s)}return typeof window<"u"?(setTimeout(()=>window.location.reload(),100),this.success(n,i,{reloaded:!0,url:window.location.href,title:t.title},s)):this.success(n,i,{reloaded:!0},s)}case"OPEN_TAB":case"LIST_TABS":case"FOCUS_TAB":case"LIST_EXTENSIONS":case"RELOAD_EXTENSION":case"SET_EXTENSION_ENABLED":case"TOGGLE_EXTENSION":{if(this.isSimulation())return this.handleSimulationBackgroundCommand(n,i,r,t,s);if(typeof globalThis.chrome<"u"&&((y=globalThis.chrome.runtime)!=null&&y.sendMessage)){const m=await new Promise(d=>{globalThis.chrome.runtime.sendMessage({type:"BROWSER_COMMAND_REQUEST",id:n,command:i,payload:r},f=>d(f))});if(m)return m}return this.error(n,i,"BACKGROUND_EXECUTION_FAILED",`Command ${i} requires Chrome extension runtime`,s)}case"RESIZE_VIEWPORT":{const m=this.getViewportController(t);let d;if(r!=null&&r.preset)d=m.applyPreset(r.preset);else{const f=Number(r==null?void 0:r.width)||1280,w=Number(r==null?void 0:r.height)||800;d=m.resize(f,w)}return this.session.timeline.record("RESIZED",`viewport → ${d.applied.width}x${d.applied.height}`),this.success(n,i,d,s)}case"RESET_VIEWPORT":{const d=this.getViewportController(t).reset();return this.session.timeline.record("RESIZED",`viewport restored to ${d.applied.width}x${d.applied.height}`),this.success(n,i,d,s)}case"GET_VIEWPORT_STATE":{const m=this.getViewportController(t);return this.success(n,i,m.state(),s)}case"RUN_RESPONSIVE_TEST":{const m=this.getViewportController(t),d=(r==null?void 0:r.sizes)||Pt(),f=m.runResponsiveTest(d,{restore:(r==null?void 0:r.restore)!==!1});return this.success(n,i,f,s)}case"EMULATE_DEVICE":{const d=this.getViewportController(t).emulateDevice((r==null?void 0:r.device)||"pixel-7");return this.success(n,i,d,s)}case"EXECUTE_JS":case"EXECUTE_JS_AND_CAPTURE_CHANGES":{const m=String((r==null?void 0:r.code)||"");if(!m.trim())return this.error(n,i,"SCRIPT_EMPTY","payload.code is required.",s);const d=await this.jsEngine.execute(t,m,{timeoutMs:r==null?void 0:r.timeoutMs,world:(r==null?void 0:r.world)==="MAIN"?"MAIN":"ISOLATED"});return this.session.timeline.record("SCRIPT_EXECUTED",`${d.status} (${d.durationMs}ms)`),this.success(n,i,d,s)}case"DOM_MUTATE":{const d=this.getMutationEngine(t).mutate(r);return this.session.timeline.record("DOM_MUTATED",`${d.operation} on ${d.before.selector} → ${d.success?"OK":d.error}`),this.success(n,i,d,s)}case"DOM_MUTATE_TRANSACTION":{const m=this.getMutationEngine(t),d=(r==null?void 0:r.mode)||"begin";try{if(d==="begin"){const f=m.beginTransaction();return this.success(n,i,{transactionId:f,mode:d,open:!0},s)}if(d==="commit"){const f=m.commitTransaction();return this.session.timeline.record("DOM_MUTATED",`transaction ${f.transactionId} committed (${f.steps.length} steps)`),this.success(n,i,{...f,mode:d},s)}if(d==="rollback"){const f=m.rollbackTransaction(r==null?void 0:r.reason);return this.session.timeline.record("MUTATION_UNDONE",`transaction ${f.transactionId} rolled back`),this.success(n,i,{...f,mode:d},s)}return this.error(n,i,"INVALID_MODE",`mode must be begin|commit|rollback, got "${d}"`,s)}catch(f){return this.error(n,i,"DOM_MUTATION_FAILED",f.message,s)}}case"UNDO_DOM_MUTATION":{const d=this.getMutationEngine(t).undo();return d.success&&this.session.timeline.record("MUTATION_UNDONE",d.message),this.success(n,i,d,s)}case"REDO_DOM_MUTATION":{const d=this.getMutationEngine(t).redo();return d.success&&this.session.timeline.record("MUTATION_REDONE",d.message),this.success(n,i,d,s)}case"GET_MUTATION_HISTORY":{const m=this.getMutationEngine(t);return this.success(n,i,{entries:m.getHistory((r==null?void 0:r.limit)||100),undoDepth:m.getUndoDepth(),redoDepth:m.getRedoDepth(),openTransactionId:m.getOpenTransactionId()},s)}case"PREVIEW_DOM_MUTATION":{const d=this.getMutationEngine(t).preview(r);return this.success(n,i,d,s)}case"GENERATE_ELEMENT_TARGET":{const d=this.getTargetingEngine(t).resolveAndBuild((r==null?void 0:r.target)||(r==null?void 0:r.selector)||"");return"error"in d?this.error(n,i,"TARGET_NOT_FOUND",d.error,s):this.success(n,i,d.target,s)}case"RECOVER_SELECTOR":{const m=new nt(t),d=(r==null?void 0:r.snapshot)||{},f=m.recover((r==null?void 0:r.selector)||"",d);return this.success(n,i,f,s)}case"GET_ELEMENT_ANCESTRY":{const m=this.resolveTarget(r,t);return this.success(n,i,Lt(m,t),s)}case"GET_ELEMENT_FINGERPRINT":{const m=this.resolveTarget(r,t),d=this.fingerprintEngine.fingerprint(m);return this.success(n,i,d,s)}case"GET_ELEMENT_RELATIONSHIPS":{const m=this.resolveTarget(r,t);return this.success(n,i,Dt(m,t),s)}case"GET_ELEMENT_ACCESSIBILITY":{const m=this.resolveTarget(r,t);return this.success(n,i,$t(m),s)}case"GET_COMPUTED_STYLE":{const m=this.resolveTarget(r,t),d=t.defaultView;if(!(d!=null&&d.getComputedStyle))return this.error(n,i,"STYLE_UNAVAILABLE","getComputedStyle is unavailable in this context.",s);const f=d.getComputedStyle(m),w=Array.isArray(r==null?void 0:r.properties)&&r.properties.length?r.properties:["display","position","color","background-color","font-size","font-family","width","height","margin","padding","border","z-index","opacity","visibility","overflow","flex-direction","grid-template-columns"],E={};for(const S of w)E[S]=f.getPropertyValue(S);return this.success(n,i,{selector:k.inspectElement(m,this.nodeRegistry).bestSelector,styles:E},s)}case"ANALYZE_DOM":{const m=String((r==null?void 0:r.analyzer)||"");if(!m)return this.error(n,i,"ANALYZER_REQUIRED",'payload.analyzer is required (e.g. "analyze_forms").',s);const d=Et(m,t,r);return d.count===0&&d.warnings.length===0&&d.items.length===0&&d.summary.startsWith("Unknown analyzer")?this.error(n,i,"UNKNOWN_ANALYZER",d.summary,s):this.success(n,i,d,s)}case"DRAG_ELEMENT":{const m=this.resolveTarget(r==null?void 0:r.source,t),d=r!=null&&r.target?this.resolveTarget(r==null?void 0:r.target,t):null,f=await this.performDrag(m,d,r==null?void 0:r.offsets,t);return this.success(n,i,f,s)}case"SET_INPUT_CHECKED":{const d=this.resolveTarget(r,t);if(d.type!=="checkbox"&&d.type!=="radio")return this.error(n,i,"INPUT_TYPE_UNSUPPORTED",`Target input type "${d.type}" is not checkbox/radio.`,s);const f=d.checked;d.checked=(r==null?void 0:r.checked)!==!1;const w=[];for(const E of["input","change"])try{d.dispatchEvent(new t.defaultView.Event(E,{bubbles:!0})),w.push(E)}catch{}if(d.type==="radio"&&d.name)for(const E of Array.from(t.querySelectorAll(`input[type=radio][name="${d.name}"]`)))E!==d&&(E.checked=!1);return this.success(n,i,{success:!0,selector:k.inspectElement(d,this.nodeRegistry).bestSelector,inputType:d.type,checkedBefore:f,checkedAfter:d.checked,eventsFired:w},s)}case"PRESS_KEYBOARD_SHORTCUT":{const m=Array.isArray(r==null?void 0:r.keys)?r.keys:String((r==null?void 0:r.keys)||"Enter").split("+"),d=r!=null&&r.target?this.resolveTarget(r==null?void 0:r.target,t):t.activeElement||t.body;typeof d.focus=="function"&&d.focus();const f=[],w=t.defaultView;for(const E of m)for(const S of["keydown","keyup"])try{d.dispatchEvent(new((w==null?void 0:w.KeyboardEvent)||KeyboardEvent)(S,{key:E.trim(),bubbles:!0,cancelable:!0,ctrlKey:m.some(T=>/^(ctrl|control|cmd|meta)$/i.test(T))&&E!==m.find(T=>/^(ctrl|control|cmd|meta)$/i.test(T)),shiftKey:m.some(T=>/^shift$/i.test(T))&&E!=="Shift",altKey:m.some(T=>/^alt$/i.test(T))&&E!=="Alt"})),f.push(`${S}:${E}`)}catch{}return this.success(n,i,{success:!0,keys:m,targetSelector:k.inspectElement(d,this.nodeRegistry).bestSelector,eventsFired:f},s)}case"SCROLL_PAGE":{const m=t.defaultView;if(!m)return this.error(n,i,"NO_WINDOW","No window available for scrolling.",s);const d={x:m.scrollX||0,y:m.scrollY||0};let f;if(r!=null&&r.target||r!=null&&r.selector){const E=this.resolveTarget((r==null?void 0:r.target)||(r==null?void 0:r.selector),t);(v=E.scrollIntoView)==null||v.call(E,{behavior:(r==null?void 0:r.behavior)||"auto",block:"center"}),f=k.inspectElement(E,this.nodeRegistry).bestSelector}else m.scrollBy(Number(r==null?void 0:r.x)||0,Number(r==null?void 0:r.y)||0);const w={x:m.scrollX||0,y:m.scrollY||0};return this.success(n,i,{success:!0,scrollBefore:d,scrollAfter:w,requested:{x:Number(r==null?void 0:r.x)||0,y:Number(r==null?void 0:r.y)||0},targetSelector:f},s)}case"WAIT_FOR_CONDITION":return await this.waitForCondition(t,r||{},s,n,i);case"GET_PAGE_STATE":case"CAPTURE_PAGE_STATE":{const m=this.session.captureSnapshot(t,!0,this.getMutationEngine(t).getUndoDepth());return this.success(n,i,m,s)}case"CAPTURE_REGION":{const m=this.resolveTarget((r==null?void 0:r.target)||(r==null?void 0:r.selector),t),d=this.regionCapture.capture(m);return this.success(n,i,d,s)}case"GET_SIMULATION_TAB_STATE":return this.isSimulation()?this.success(n,i,{simulated:!0,tabs:this.simulationTabs,sessionSummary:this.session.getTabs()},s):this.error(n,i,"NOT_SIMULATION","Simulation tab state is only available in the Node simulation context.",s);default:return this.error(n,i,"UNKNOWN_COMMAND",`Unsupported command '${i}'`,s)}}catch(m){return this.error(n,i,"COMMAND_EXECUTION_FAILED",m.message,s,m.details)}}resolveTarget(e,t){if(!e)throw new Error("Target specifier must be provided");return typeof e=="string"?this.interactionEngine.resolveTarget({selector:e},t):typeof e=="number"?this.interactionEngine.resolveTarget({nodeId:e},t):this.interactionEngine.resolveTarget(e,t)}async performDrag(e,t,s,n){const i=n.defaultView,r=[],o=(p,y,v={})=>{try{const m=(i==null?void 0:i.MouseEvent)||(typeof MouseEvent<"u"?MouseEvent:null);m&&(p.dispatchEvent(new m(y,{bubbles:!0,cancelable:!0,...v})),r.push(y))}catch{}},a=e.getBoundingClientRect(),c=a.x+a.width/2,u=a.y+a.height/2;let h=c+((s==null?void 0:s.x)||0),g=u+((s==null?void 0:s.y)||0);if(t){const p=t.getBoundingClientRect();h=p.x+p.width/2,g=p.y+p.height/2}return o(e,"pointerdown",{button:1,clientX:c,clientY:u}),o(e,"mousedown",{button:1,clientX:c,clientY:u}),o(e,"dragstart",{clientX:c,clientY:u}),t&&(o(t,"dragenter",{clientX:h,clientY:g}),o(t,"dragover",{clientX:h,clientY:g}),o(t,"drop",{clientX:h,clientY:g})),o(e,"dragend",{clientX:h,clientY:g}),o(e,"pointerup",{button:1,clientX:h,clientY:g}),o(e,"mouseup",{button:1,clientX:h,clientY:g}),{success:r.length>0,sourceSelector:k.inspectElement(e,this.nodeRegistry).bestSelector,targetSelector:t?k.inspectElement(t,this.nodeRegistry).bestSelector:"(offset drop)",eventsFired:r,finalPosition:{x:Math.round(h),y:Math.round(g)},html5DndUsed:r.includes("dragstart")}}async waitForCondition(e,t,s,n,i){var p,y;const r=t.kind||"dom_stable",o=Math.min(Math.max(Number(t.timeoutMs)||5e3,100),3e4),a=Math.min(Math.max(Number(t.pollIntervalMs)||100,20),1e3),c=Date.now(),u=()=>{var v,m,d,f,w;switch(r){case"dom_stable":return{satisfied:!0,detail:`dom length ${((v=e.documentElement)==null?void 0:v.outerHTML.length)||0}`};case"selector_present":{const E=t.selector?e.querySelectorAll(t.selector).length:0;return{satisfied:E>0,detail:`"${t.selector}" matches ${E} element(s)`}}case"selector_visible":{if(!t.selector)return{satisfied:!1,detail:"no selector supplied"};const E=e.querySelector(t.selector);if(!E)return{satisfied:!1,detail:`"${t.selector}" not present`};try{const S=k.inspectElement(E).visibility.isVisible;return{satisfied:S,detail:`visibility=${S}`}}catch{return{satisfied:!1,detail:"inspection failed"}}}case"selector_absent":{const E=t.selector?e.querySelectorAll(t.selector).length:0;return{satisfied:E===0,detail:`"${t.selector}" matches ${E} element(s)`}}case"text_present":{const E=((m=e.body)==null?void 0:m.innerText)||((d=e.body)==null?void 0:d.textContent)||"",S=t.text?E.includes(String(t.text)):!1;return{satisfied:S,detail:`text "${String(t.text).slice(0,30)}" ${S?"found":"not found"}`}}case"url_contains":{const E=((w=(f=e.defaultView)==null?void 0:f.location)==null?void 0:w.href)||"";return{satisfied:t.text?E.includes(String(t.text)):!1,detail:E}}case"element_count":{const E=t.selector?e.querySelectorAll(t.selector).length:0,S=Number(t.count)||0;return{satisfied:E===S,detail:`${E}/${S} elements`}}case"readiness_state":return{satisfied:e.readyState===(t.state||"complete"),detail:`readyState=${e.readyState}`};default:return{satisfied:!1,detail:`unknown condition kind "${r}"`}}};if(r==="dom_stable"){let v=((p=e.documentElement)==null?void 0:p.outerHTML.length)||0,m=!1,d=0;for(;Date.now()-csetTimeout(E,a));const w=((y=e.documentElement)==null?void 0:y.outerHTML.length)||0;if(d++,w===v){m=!0;break}v=w}const f=Date.now()-c;return m&&this.session.timeline.record("WAIT_SATISFIED",`dom_stable after ${f}ms (${d} polls)`),this.success(n,i,{satisfied:m,condition:r,waitedMs:f,timeoutMs:o,detail:`dom length ${v}, ${d} polls`},s)}let h=u();for(;!h.satisfied&&Date.now()-csetTimeout(v,a)),h=u();const g=Date.now()-c;return h.satisfied&&this.session.timeline.record("WAIT_SATISFIED",`${r} after ${g}ms`),this.success(n,i,{satisfied:h.satisfied,condition:r,waitedMs:g,timeoutMs:o,detail:h.detail},s)}simulationCloseTab(e,t,s,n,i){const r=Number(e==null?void 0:e.tabId),o=Number.isFinite(r)?this.simulationTabs.findIndex(c=>c.browserTabId===r):this.simulationTabs.findIndex(c=>c.active);if(o<0)return this.error(s,n,"TAB_NOT_FOUND",`No simulated tab matches tabId=${r}`,i);const a=this.simulationTabs.splice(o,1)[0];return this.session.closeTab(a.sessionTabId),a.active&&this.simulationTabs.length&&(this.simulationTabs[0].active=!0,this.session.switchTab(this.simulationTabs[0].sessionTabId)),this.success(s,n,{closed:!0,closedTab:{id:a.browserTabId,url:a.url,title:a.title},simulated:!0,remaining:this.simulationTabs.length},i)}handleSimulationBackgroundCommand(e,t,s,n,i){const r=()=>{var o,a;if(!this.simulationTabs.length){this.simulationTabCounter++;const c={sessionTabId:`stab_${this.simulationTabCounter}`,browserTabId:this.simulationTabCounter,url:((a=(o=n.defaultView)==null?void 0:o.location)==null?void 0:a.href)||"about:blank",title:n.title||"Simulated Tab",active:!0,createdAt:Date.now()};this.simulationTabs.push(c),this.session.registerTab(c.browserTabId,c.url,c.title),this.session.switchTab(c.sessionTabId)}};switch(t){case"LIST_TABS":return r(),this.success(e,t,{simulated:!0,environment:"node-simulation",tabs:this.simulationTabs.map((o,a)=>({id:o.browserTabId,index:a,windowId:1,title:o.title,url:o.url,active:o.active,status:"complete",pinned:!1,audited:!1})),note:"Deterministic simulated tab state — a real browser tab list requires the Chrome extension connection."},i);case"OPEN_TAB":{const o=String((s==null?void 0:s.url)||"about:blank");this.simulationTabCounter++;const a={sessionTabId:`stab_${this.simulationTabCounter}`,browserTabId:this.simulationTabCounter,url:o,title:(s==null?void 0:s.title)||`Simulated Tab ${this.simulationTabCounter}`,active:!0,createdAt:Date.now()};this.simulationTabs.forEach(u=>u.active=!1),this.simulationTabs.push(a);const c=this.session.registerTab(a.browserTabId,o,a.title);return this.session.switchTab(c.sessionTabId),this.session.timeline.record("TAB_OPENED",`simulation tab ${a.browserTabId} → ${o}`),this.success(e,t,{opened:!0,tabId:a.browserTabId,url:o,simulated:!0,totalTabs:this.simulationTabs.length},i)}case"FOCUS_TAB":{r();const o=Number(s==null?void 0:s.tabId),a=this.simulationTabs.find(c=>c.browserTabId===o)||this.simulationTabs[0];return a?(this.simulationTabs.forEach(c=>c.active=!1),a.active=!0,this.session.switchTab(a.sessionTabId),this.session.timeline.record("TAB_SWITCHED",`simulation tab ${a.browserTabId} focused`),this.success(e,t,{focused:!0,tabId:a.browserTabId,url:a.url,simulated:!0},i)):this.error(e,t,"TAB_NOT_FOUND",`No simulated tab with tabId=${o}`,i)}case"LIST_EXTENSIONS":return this.success(e,t,{simulated:!0,extensions:this.simulationExtensions.map(o=>({...o,permissions:["activeTab","scripting","storage","tabs","management"]})),note:"Deterministic simulated extension state."},i);case"SET_EXTENSION_ENABLED":{const o=String((s==null?void 0:s.extensionId)||""),a=this.simulationExtensions.find(c=>c.id===o||c.name.toLowerCase().includes(o.toLowerCase()));return a?(a.enabled=!!(s!=null&&s.enabled),this.session.timeline.record("EXTENSION_STATE_CHANGED",`${a.id} → ${a.enabled?"enabled":"disabled"}`),this.success(e,t,{extensionId:a.id,enabled:a.enabled,simulated:!0},i)):this.error(e,t,"EXTENSION_NOT_FOUND",`No simulated extension matches "${o}". Known: ${this.simulationExtensions.map(c=>c.id).join(", ")}`,i)}case"TOGGLE_EXTENSION":{const o=String((s==null?void 0:s.extensionId)||""),a=this.simulationExtensions.find(c=>c.id===o||c.name.toLowerCase().includes(o.toLowerCase()));return a?(a.enabled=!a.enabled,this.session.timeline.record("EXTENSION_STATE_CHANGED",`${a.id} → ${a.enabled?"enabled":"disabled"}`),this.success(e,t,{extensionId:a.id,enabled:a.enabled,simulated:!0},i)):this.error(e,t,"EXTENSION_NOT_FOUND",`No simulated extension matches "${o}".`,i)}case"RELOAD_EXTENSION":{const o=String((s==null?void 0:s.extensionId)||this.simulationExtensions[0].id),a=this.simulationExtensions.find(c=>c.id===o||c.name.toLowerCase().includes(o.toLowerCase()));return a?this.success(e,t,{reloaded:!0,extensionId:a.id,simulated:!0,note:"Simulated reload: extension state preserved."},i):this.error(e,t,"EXTENSION_NOT_FOUND",`No simulated extension matches "${o}".`,i)}default:return this.error(e,t,"UNKNOWN_COMMAND",`Unhandled simulation command '${t}'`,i)}}async handleScreenshotCapture(e,t,s){var y,v,m,d,f;const n=s.defaultView||(typeof window<"u"?window:{}),i=Date.now(),r=`scr_${i}_${Math.random().toString(36).slice(2,6)}`,o=n.devicePixelRatio||1,a={width:n.innerWidth||((y=s.documentElement)==null?void 0:y.clientWidth)||1920,height:n.innerHeight||((v=s.documentElement)==null?void 0:v.clientHeight)||1080,scrollX:n.scrollX||n.pageXOffset||0,scrollY:n.scrollY||n.pageYOffset||0,devicePixelRatio:o};let c,u,h,g={width:a.width,height:a.height};if(e==="LIVE_ELEMENT_SCREENSHOT"){const w=this.resolveTarget(t,s),E=k.inspectElement(w,this.nodeRegistry);c=E.bestSelector,u=((m=E.forensics)==null?void 0:m.logicalNodeId)||void 0,h={x:E.bounds.x,y:E.bounds.y,width:E.bounds.width,height:E.bounds.height},g={width:Math.max(1,Math.round(E.bounds.width*o)),height:Math.max(1,Math.round(E.bounds.height*o))}}let p=(t==null?void 0:t.dataUrl)||"";if(e==="LIVE_ELEMENT_SCREENSHOT"&&p&&h&&typeof Image<"u")try{const w=await new Promise(E=>{const S=new Image;S.onload=()=>{try{const T=s.createElement("canvas"),x=Math.max(0,Math.floor(h.x*o)),N=Math.max(0,Math.floor(h.y*o)),D=Math.max(1,Math.floor(h.width*o)),M=Math.max(1,Math.floor(h.height*o));T.width=D,T.height=M;const L=T.getContext("2d");if(L){L.drawImage(S,x,N,D,M,0,0,D,M),E(T.toDataURL("image/png"));return}}catch{}E(p)},S.onerror=()=>E(p),S.src=p});w&&(p=w)}catch{}if(!p){const w=e==="LIVE_ELEMENT_SCREENSHOT"?Math.max(120,g.width||320):Math.max(800,a.width||1280),E=e==="LIVE_ELEMENT_SCREENSHOT"?Math.max(60,g.height||180):Math.max(600,a.height||800);p=ge.createDataUrl({width:w,height:E,backgroundColor:e==="LIVE_ELEMENT_SCREENSHOT"?[30,41,59,255]:[15,23,42,255],headerColor:[56,189,248,255],borderColor:[99,102,241,255],label:c||(e==="LIVE_ELEMENT_SCREENSHOT"?"Element Screenshot":"Page Screenshot")})}return{screenshotId:r,timestamp:i,url:((d=n.location)==null?void 0:d.href)||((f=s.location)==null?void 0:f.href)||"",viewport:a,targetSelector:c,targetNodeId:u,targetBounds:h,dataUrl:p,imageFormat:"png",dimensions:g,captureType:e==="LIVE_ELEMENT_SCREENSHOT"?"ELEMENT":"FULL_PAGE"}}success(e,t,s,n){return{id:e,command:t,success:!0,data:s,timestamp:Date.now(),durationMs:Date.now()-n}}error(e,t,s,n,i,r){return{id:e,command:t,success:!1,error:{code:s,message:n,details:r},timestamp:Date.now(),durationMs:Date.now()-i}}}function Lt(l,e){const t=[];let s=l.parentElement,n=1;for(;s&&n<=10;){const h=s.parentElement,g=h?Array.from(h.children).filter(p=>p.tagName===s.tagName):[];t.push({tag:s.tagName.toLowerCase(),selector:U(s),role:s.getAttribute("role")||void 0,text:B(s).slice(0,40),childIndex:g.length?g.indexOf(s)+1:1,siblingCount:h?Array.from(h.children).length:0,distance:n}),s=s.parentElement,n++}const i=l.parentElement,r=[];if(i){const h=Array.from(i.children),g=h.indexOf(l);for(let p=g-1;p>=0&&p>=g-5;p--)r.push({tag:h[p].tagName.toLowerCase(),selector:U(h[p]),role:h[p].getAttribute("role")||void 0,text:B(h[p]).slice(0,30),position:"before",distance:g-p});for(let p=g+1;p{o=Math.max(o,g);for(const p of Array.from(h.children))a.push(p.tagName.toLowerCase()),p.matches('a[href], button, input, select, textarea, [role="button"], [onclick]')&&c.push(U(p)),g<6&&u(p,g+1)};return u(l,1),{selector:U(l),ancestors:t,siblings:r,descendants:{count:l.querySelectorAll("*").length,maxDepth:o,tags:Array.from(new Set(a)).slice(0,30),interactive:c.slice(0,30)}}}function Dt(l,e){const t=[{id:"self",selector:U(l),tag:l.tagName.toLowerCase(),role:l.getAttribute("role")||void 0,label:B(l).slice(0,30)||l.tagName.toLowerCase(),relationship:"self",depth:0}],s=[];let n=l.parentElement,i=1;for(;n&&i<=4;){const o=`ancestor_${i}`;t.push({id:o,selector:U(n),tag:n.tagName.toLowerCase(),role:n.getAttribute("role")||void 0,label:B(n).slice(0,30)||n.tagName.toLowerCase(),relationship:"parent",depth:i}),s.push({from:o,to:i===1?"self":`ancestor_${i-1}`,relation:"parent-of"}),n=n.parentElement,i++}for(const o of Array.from(l.children).slice(0,12)){const a=`child_${t.length}`;t.push({id:a,selector:U(o),tag:o.tagName.toLowerCase(),role:o.getAttribute("role")||void 0,label:B(o).slice(0,30)||o.tagName.toLowerCase(),relationship:"child",depth:1}),s.push({from:"self",to:a,relation:"contains"})}const r=l.parentElement;if(r)for(const o of Array.from(r.children).slice(0,12)){if(o===l)continue;const a=`sibling_${t.length}`;t.push({id:a,selector:U(o),tag:o.tagName.toLowerCase(),role:o.getAttribute("role")||void 0,label:B(o).slice(0,30)||o.tagName.toLowerCase(),relationship:"sibling",depth:1}),s.push({from:"self",to:a,relation:"sibling-of"})}return{rootSelector:U(l),nodes:t,edges:s}}function $t(l){const e={};for(const v of Array.from(l.attributes))v.name.startsWith("aria-")&&(e[v.name]=v.value);const t=B(l).trim(),s=l.getAttribute("aria-label"),n=l.getAttribute("aria-labelledby");let i;n&&(i=n.split(/\s+/).map(m=>{var d,f,w;return(w=(f=(d=l.ownerDocument)==null?void 0:d.getElementById(m))==null?void 0:f.textContent)==null?void 0:w.trim()}).filter(Boolean).join(" ").slice(0,60)||void 0);const r=l.getAttribute("title"),o=l.tagName.toLowerCase(),a=[];let c="";s?(c=s,a.push("aria-label")):i?(c=i,a.push("aria-labelledby")):t?(c=t.slice(0,60),a.push("text content")):r&&(c=r,a.push("title"));const u=[];(l.disabled||l.hasAttribute("disabled"))&&u.push("disabled"),l.checked&&u.push("checked");const h=l;h.tagName==="SELECT"&&typeof h.selectedOptions<"u"&&h.selectedOptions.length>0&&u.push("selected"),l.getAttribute("aria-expanded")&&u.push(`expanded=${l.getAttribute("aria-expanded")}`),l.getAttribute("aria-pressed")&&u.push(`pressed=${l.getAttribute("aria-pressed")}`),l.getAttribute("aria-hidden")==="true"&&u.push("hidden"),l.hasAttribute("required")&&u.push("required"),l.readOnly&&u.push("readonly");const g=["a[href]","button","input","select","textarea","[tabindex]"].some(v=>{try{return l.matches(v)}catch{return!1}}),p=[];!c&&g&&p.push("Focusable element has no accessible name."),o==="img"&&!l.hasAttribute("alt")&&p.push("Image has no alt attribute.");const y=/^h([1-6])$/.exec(o);return y&&!t&&p.push(`Heading h${y[1]} is empty.`),{selector:U(l),role:l.getAttribute("role")||void 0,implicitRole:qt(l),name:c,nameSources:a,description:l.getAttribute("aria-describedby")||void 0,value:l.value!==void 0&&(l.getAttribute("type")||"text")!=="password"?String(l.value).slice(0,40):void 0,states:u,level:y?parseInt(y[1],10):void 0,focusable:g,tabIndex:l.tabIndex,ariaAttributes:e,issues:p}}function qt(l){switch(l.tagName.toLowerCase()){case"a":return l.getAttribute("href")?"link":void 0;case"button":return"button";case"nav":return"navigation";case"header":return"banner";case"footer":return"contentinfo";case"main":return"main";case"aside":return"complementary";case"article":return"article";case"form":return"form";case"input":{const t=l.getAttribute("type")||"text";return{checkbox:"checkbox",radio:"radio",button:"button",submit:"button",reset:"button",range:"slider",search:"searchbox",email:"textbox",text:"textbox",password:"textbox",tel:"textbox",url:"textbox",number:"spinbutton"}[t]||"textbox"}case"select":return l.hasAttribute("multiple")?"listbox":"combobox";case"textarea":return"textbox";case"img":return"img";case"table":return"table";case"ul":case"ol":return"list";case"li":return"listitem";case"h1":case"h2":case"h3":case"h4":case"h5":case"h6":return"heading";case"dialog":return"dialog";default:return}}function U(l){const e=l.getAttribute("id");if(e&&/^[a-zA-Z][\w-]*$/.test(e))return`#${e}`;const t=l.getAttribute("data-testid");if(t)return`${l.tagName.toLowerCase()}[data-testid="${t}"]`;const s=l.tagName.toLowerCase(),n=Array.from(l.classList||[]).slice(0,2);return n.length?`${s}.${n.join(".")}`:s}function B(l){return Array.from(l.childNodes).filter(e=>e.nodeType===3).map(e=>(e.textContent||"").trim()).join(" ").replace(/\s+/g," ")}function Pt(){return[{label:"desktop-1440x900",width:1440,height:900},{label:"laptop-1024x768",width:1024,height:768},{label:"tablet-768x1024",width:768,height:1024},{label:"mobile-375x667",width:375,height:667}]}class Ut{constructor(e){b(this,"hostElement",null);b(this,"shadowRoot",null);b(this,"callbacks");b(this,"isRecording",!1);b(this,"isPaused",!1);b(this,"isMinimized",!1);b(this,"startTime",0);b(this,"eventCount",0);b(this,"timerInterval",null);b(this,"isDragging",!1);b(this,"dragStartX",0);b(this,"dragStartY",0);b(this,"posX",window.innerWidth-340);b(this,"posY",40);this.callbacks=e,this.loadPosition()}mount(){this.hostElement&&document.body.contains(this.hostElement)||(this.hostElement=document.createElement("div"),this.hostElement.id="forensic-recorder-floating-host",this.hostElement.style.all="initial",this.hostElement.style.position="fixed",this.hostElement.style.zIndex="2147483647",this.hostElement.style.left=`${this.posX}px`,this.hostElement.style.top=`${this.posY}px`,this.shadowRoot=this.hostElement.attachShadow({mode:"open"}),this.render(),this.attachEvents(),(document.body||document.documentElement).appendChild(this.hostElement))}unmount(){this.timerInterval&&(clearInterval(this.timerInterval),this.timerInterval=null),this.hostElement&&this.hostElement.parentNode&&this.hostElement.parentNode.removeChild(this.hostElement),this.hostElement=null,this.shadowRoot=null}hide(){this.hostElement&&(this.hostElement.style.setProperty("display","none","important"),this.hostElement.style.setProperty("visibility","hidden","important"),this.hostElement.style.setProperty("opacity","0","important"))}show(){this.hostElement&&(this.hostElement.style.removeProperty("display"),this.hostElement.style.removeProperty("visibility"),this.hostElement.style.removeProperty("opacity"))}updateState(e,t=!1,s=0,n=0){this.isRecording=e,this.isPaused=t,this.startTime=s||(e?Date.now():0),this.eventCount=n,this.shadowRoot&&(this.render(),this.attachEvents()),this.isRecording&&!this.isPaused?this.startTimer():this.stopTimer()}incrementEventCount(){var t;this.eventCount++;const e=(t=this.shadowRoot)==null?void 0:t.querySelector("#evt-badge");e&&(e.textContent=`${this.eventCount} evts`)}startTimer(){this.stopTimer(),this.timerInterval=setInterval(()=>{var t;const e=(t=this.shadowRoot)==null?void 0:t.querySelector("#timer-display");if(e&&this.startTime){const s=(Date.now()-this.startTime)/1e3,n=Math.floor(s/60).toString().padStart(2,"0"),i=(s%60).toFixed(1).padStart(4,"0");e.textContent=`${n}:${i}`}},200)}stopTimer(){this.timerInterval&&(clearInterval(this.timerInterval),this.timerInterval=null)}savePosition(){try{sessionStorage.setItem("forensic_overlay_pos",JSON.stringify({x:this.posX,y:this.posY,min:this.isMinimized}))}catch{}}loadPosition(){try{const e=sessionStorage.getItem("forensic_overlay_pos");if(e){const t=JSON.parse(e);this.posX=Math.max(10,Math.min(window.innerWidth-300,t.x||this.posX)),this.posY=Math.max(10,Math.min(window.innerHeight-150,t.y||this.posY)),this.isMinimized=!!t.min}}catch{}}render(){if(!this.shadowRoot)return;const e=` :host { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; font-size: 12px; @@ -288,4 +288,4 @@ ${t}
- `}attachEvents(){if(!this.shadowRoot)return;const e=this.shadowRoot.querySelector("#drag-header");e&&e.addEventListener("mousedown",c=>{this.isDragging=!0,this.dragStartX=c.clientX-this.posX,this.dragStartY=c.clientY-this.posY;const u=h=>{!this.isDragging||!this.hostElement||(this.posX=Math.max(10,Math.min(window.innerWidth-80,h.clientX-this.dragStartX)),this.posY=Math.max(10,Math.min(window.innerHeight-50,h.clientY-this.dragStartY)),this.hostElement.style.left=`${this.posX}px`,this.hostElement.style.top=`${this.posY}px`)},d=()=>{this.isDragging=!1,window.removeEventListener("mousemove",u),window.removeEventListener("mouseup",d),this.savePosition()};window.addEventListener("mousemove",u),window.addEventListener("mouseup",d)});const t=this.shadowRoot.querySelector("#btn-toggle-min");t==null||t.addEventListener("click",()=>{this.isMinimized=!this.isMinimized,this.savePosition(),this.render(),this.attachEvents()});const s=this.shadowRoot.querySelector("#btn-close");s==null||s.addEventListener("click",()=>{this.unmount()});const n=this.shadowRoot.querySelector("#btn-record");n==null||n.addEventListener("click",()=>{this.isRecording?this.callbacks.onStopRecord():this.callbacks.onStartRecord()});const i=this.shadowRoot.querySelector("#btn-checkpoint");i==null||i.addEventListener("click",()=>{if(this.callbacks.onCaptureCheckpoint(),i){const c=i.textContent;i.textContent="✔ Saved!",setTimeout(()=>i.textContent=c,1e3)}});const r=this.shadowRoot.querySelector("#btn-inspect");r==null||r.addEventListener("click",()=>{this.callbacks.onInspectElement()});const o=this.shadowRoot.querySelector("#btn-annotate");o==null||o.addEventListener("click",()=>{const c=prompt("Enter observation, bug note, or hypothesis at this exact moment:");c&&c.trim()&&this.callbacks.onAddAnnotation(c.trim())});const a=this.shadowRoot.querySelector("#btn-dashboard");a==null||a.addEventListener("click",()=>{this.callbacks.onOpenDashboard()})}}(function(){var w;let l=null;const e=new Lt;let t=[],s=null,n=null,i=!1;const r=500,o=[],a=[];window.addEventListener("message",E=>{var C;if(((C=E.data)==null?void 0:C._forensicOrigin)==="PAGE_MAIN"){const{type:N,payload:I}=E.data;if(N==="CONSOLE_ENTRY")o.push(I),o.length>r&&o.shift();else if(N==="NETWORK_ENTRY"){const R=a.findIndex(x=>x.requestId===I.requestId);R>=0?a[R]={...a[R],...I}:(a.push(I),a.length>r&&a.shift())}}});function c(){var E;try{if(typeof chrome<"u"&&((E=chrome.runtime)!=null&&E.getURL)){const C=document.createElement("script");C.src=chrome.runtime.getURL("dist/extension/page-script.js"),C.onload=()=>C.remove(),(document.head||document.documentElement).appendChild(C)}}catch{}}function u(){var C;if(t.length===0||!l)return;const E=[...t];t=[];try{typeof chrome<"u"&&((C=chrome.runtime)!=null&&C.sendMessage)&&chrome.runtime.sendMessage({type:"FORENSIC_EVENTS_CHUNK",sessionId:l.getSessionId(),events:E})}catch{}}function d(E,C,N){var R;if(l)return l.getMetadata();l=new Le({sessionId:C,sessionName:E||`Recording on ${document.title||window.location.hostname}`}),l.onEvent(x=>{t.push(x),n&&n.incrementEventCount(),t.length>=25&&u()}),l.onCheckpoint(x=>{var q;try{typeof chrome<"u"&&((q=chrome.runtime)!=null&&q.sendMessage)&&chrome.runtime.sendMessage({type:"FORENSIC_CHECKPOINT",sessionId:x.sessionId,checkpoint:x})}catch{}});const I=l.start(document);try{typeof chrome<"u"&&((R=chrome.runtime)!=null&&R.sendMessage)&&chrome.runtime.sendMessage({type:"FORENSIC_SESSION_START",metadata:l.getMetadata(),initialSnapshot:I})}catch{}return s||(s=setInterval(u,1e3)),n&&n.updateState(!0,!1,N||Date.now(),0),l.getMetadata()}function h(){var N;if(!l)return null;u(),s&&(clearInterval(s),s=null);const E=l.stop();try{typeof chrome<"u"&&((N=chrome.runtime)!=null&&N.sendMessage)&&chrome.runtime.sendMessage({type:"FORENSIC_SESSION_STOP",sessionId:E.id,metadata:E})}catch{}const C={...E};return l=null,n&&n.updateState(!1,!1,0,0),C}function p(){if(i){i=!1,document.body.style.cursor="default";return}i=!0,document.body.style.cursor="crosshair";const E=document.createElement("div");E.id="forensic-inspect-highlighter",E.style.position="fixed",E.style.pointerEvents="none",E.style.zIndex="2147483640",E.style.border="2px dashed #38bdf8",E.style.background="rgba(56, 189, 248, 0.15)",E.style.transition="all 0.05s ease",document.body.appendChild(E);const C=I=>{if(!i)return;const R=I.target;if(!R||R.id==="forensic-recorder-floating-host"||R.closest("#forensic-recorder-floating-host")){E.style.display="none";return}const x=R.getBoundingClientRect();E.style.display="block",E.style.left=`${x.left}px`,E.style.top=`${x.top}px`,E.style.width=`${x.width}px`,E.style.height=`${x.height}px`},N=I=>{if(!i)return;const R=I.target;if(!R.closest("#forensic-recorder-floating-host")&&(I.preventDefault(),I.stopPropagation(),i=!1,document.body.style.cursor="default",E.remove(),window.removeEventListener("mousemove",C,!0),window.removeEventListener("click",N,!0),l)){const x=R.id?`#${R.id}`:R.className?`.${R.className.split(" ")[0]}`:R.tagName.toLowerCase();l.addAnnotation("Inspect Element",`Inspected element <${R.tagName.toLowerCase()}> with selector '${x}'`,"USER"),alert(`🎯 Inspected element <${R.tagName.toLowerCase()}> recorded! Checkpoint saved.`)}};window.addEventListener("mousemove",C,!0),window.addEventListener("click",N,!0)}function y(){return n||(n=new Ht({onStartRecord:()=>{d()},onStopRecord:()=>{h()},onTogglePause:()=>{l&&(l.getMetadata().status==="recording"?l.pause():l.resume())},onCaptureCheckpoint:()=>{l&&l.captureCheckpoint("MANUAL",document)},onAddAnnotation:E=>{l&&l.addAnnotation("User Note",E,"USER")},onInspectElement:()=>{p()},onOpenDashboard:()=>{const E=l?l.getSessionId():void 0;chrome.runtime.sendMessage({type:"OPEN_DASHBOARD_TAB",sessionId:E})}})),n}function v(){var E;try{typeof chrome<"u"&&((E=chrome.runtime)!=null&&E.sendMessage)&&chrome.runtime.sendMessage({type:"GET_TAB_RECORDING_STATE"},C=>{chrome.runtime.lastError||!C||C.isRecording&&C.recording&&(y().mount(),d(C.recording.sessionName,C.recording.sessionId,C.recording.startTime))})}catch{}}typeof chrome<"u"&&((w=chrome.runtime)!=null&&w.onMessage)&&chrome.runtime.onMessage.addListener((E,C,N)=>{if(E.type==="HIDE_FORENSIC_OVERLAYS")return n&&n.hide(),document.querySelectorAll('#forensic-recorder-floating-host, #forensic-inspect-highlighter, [id^="forensic-"]').forEach(R=>{const x=R;x.style.setProperty("display","none","important"),x.style.setProperty("visibility","hidden","important"),x.style.setProperty("opacity","0","important")}),N({success:!0}),!0;if(E.type==="RESTORE_FORENSIC_OVERLAYS")return n&&n.show(),document.querySelectorAll('#forensic-recorder-floating-host, #forensic-inspect-highlighter, [id^="forensic-"]').forEach(R=>{const x=R;x.style.removeProperty("display"),x.style.removeProperty("visibility"),x.style.removeProperty("opacity")}),N({success:!0}),!0;if(E.type==="BROWSER_COMMAND_REQUEST"){if(["LIST_TABS","FOCUS_TAB","RELOAD_TAB","LIST_EXTENSIONS","RELOAD_EXTENSION","CLOSE_TAB","OPEN_TAB","RESIZE_VIEWPORT","RESET_VIEWPORT"].includes(E.command))return!1;if(E.command==="GET_TAB_CONSOLE_LOGS"){const{level:I,searchQuery:R,limit:x=100,clearAfterRead:q}=E.payload||{};let A=[...o];if(I&&I!=="all"&&(A=A.filter(S=>S.level===I)),R){const S=String(R).toLowerCase();A=A.filter(M=>{var O,_;return((O=M.text)==null?void 0:O.toLowerCase().includes(S))||((_=M.source)==null?void 0:_.toLowerCase().includes(S))})}return x>0&&(A=A.slice(-x)),q&&(o.length=0),N({id:E.id,command:E.command,success:!0,data:{url:window.location.href,title:document.title,totalCaptured:o.length,returnedCount:A.length,logs:A}}),!0}if(E.command==="GET_TAB_NETWORK_REQUESTS"){const{method:I,searchQuery:R,status:x,onlyErrors:q,limit:A=100,clearAfterRead:S}=E.payload||{};let M=[...a];if(I&&(M=M.filter(O=>{var _;return((_=O.method)==null?void 0:_.toUpperCase())===String(I).toUpperCase()})),x&&(M=M.filter(O=>O.status===Number(x))),q&&(M=M.filter(O=>O.error||O.status&&O.status>=400)),R){const O=String(R).toLowerCase();M=M.filter(_=>{var P;return(P=_.url)==null?void 0:P.toLowerCase().includes(O)})}return A>0&&(M=M.slice(-A)),S&&(a.length=0),N({id:E.id,command:E.command,success:!0,data:{url:window.location.href,title:document.title,totalCaptured:a.length,returnedCount:M.length,requests:M}}),!0}return e.handleCommand(E,document).then(I=>{N(I)}),!0}else if(E.type==="START_RECORDING"){const I=d(E.sessionName);y().mount(),N({success:!0,metadata:I})}else if(E.type==="STOP_RECORDING"){const I=h();N({success:!0,metadata:I})}else if(E.type==="TOGGLE_FLOATING_OVERLAY"){const I=y();document.getElementById("forensic-recorder-floating-host")?(I.unmount(),N({isOpen:!1})):(I.mount(),I.updateState((l==null?void 0:l.getMetadata().status)==="recording",!1,(l==null?void 0:l.getMetadata().startTime)||0,0),N({isOpen:!0}))}else if(E.type==="GET_RECORDER_STATUS")N({isRecording:(l==null?void 0:l.getMetadata().status)==="recording",metadata:(l==null?void 0:l.getMetadata())||null});else if(E.type==="CAPTURE_CHECKPOINT")if(l){const I=l.captureCheckpoint("MANUAL",document);N({success:!0,checkpoint:I})}else N({success:!1,error:"Not currently recording"});return!0});let m=null,g=null;function b(){if(!(typeof WebSocket>"u"))try{const E=new WebSocket("ws://127.0.0.1:3847");E.onopen=()=>{m=E,console.log("[Forensic ContentScript] Connected directly to MCP Bridge on ws://127.0.0.1:3847"),g&&(clearInterval(g),g=null),E.send(JSON.stringify({type:"REGISTER_CLIENT",clientType:"CONTENT_SCRIPT",url:window.location.href,title:document.title}))},E.onclose=()=>{m=null,T()},E.onerror=()=>{m=null,T()},E.onmessage=async C=>{var N;try{const I=JSON.parse(C.data.toString());if(I.type==="BROWSER_COMMAND_REQUEST"){const{id:R,command:x,payload:q}=I;if(["LIST_TABS","OPEN_TAB","LIST_EXTENSIONS","RELOAD_EXTENSION","CLOSE_TAB","FOCUS_TAB","RELOAD_TAB","RESIZE_VIEWPORT","RESET_VIEWPORT"].includes(x)){if(typeof chrome<"u"&&((N=chrome.runtime)!=null&&N.sendMessage)){chrome.runtime.sendMessage(I,S=>{if(chrome.runtime.lastError){if(x==="CLOSE_TAB"){E.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:R,command:x,success:!0,data:{closed:!0,url:window.location.href,title:document.title}})),setTimeout(()=>window.close(),100);return}if(x==="RELOAD_TAB"){E.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:R,command:x,success:!0,data:{reloaded:!0,url:window.location.href,title:document.title}})),setTimeout(()=>window.location.reload(),100);return}E.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:R,command:x,success:!1,error:{code:"FORWARD_ERROR",message:chrome.runtime.lastError.message}}))}else E.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",...S||{id:R,command:x,success:!0}}))});return}if(x==="CLOSE_TAB"){E.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:R,command:x,success:!0,data:{closed:!0,url:window.location.href,title:document.title}})),setTimeout(()=>window.close(),100);return}if(x==="RELOAD_TAB"){E.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:R,command:x,success:!0,data:{reloaded:!0,url:window.location.href,title:document.title}})),setTimeout(()=>window.location.reload(),100);return}}if(x==="GET_TAB_CONSOLE_LOGS"){const{level:S,searchQuery:M,limit:O=100,clearAfterRead:_}=q||{};let P=[...o];if(S&&S!=="all"&&(P=P.filter(H=>H.level===S)),M){const H=String(M).toLowerCase();P=P.filter($=>{var F,W;return((F=$.text)==null?void 0:F.toLowerCase().includes(H))||((W=$.source)==null?void 0:W.toLowerCase().includes(H))})}O>0&&(P=P.slice(-O)),_&&(o.length=0),E.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:R,command:x,success:!0,data:{url:window.location.href,title:document.title,totalCaptured:o.length,returnedCount:P.length,logs:P}}));return}if(x==="GET_TAB_NETWORK_REQUESTS"){const{method:S,searchQuery:M,status:O,onlyErrors:_,limit:P=100,clearAfterRead:H}=q||{};let $=[...a];if(S&&($=$.filter(F=>{var W;return((W=F.method)==null?void 0:W.toUpperCase())===String(S).toUpperCase()})),O&&($=$.filter(F=>F.status===Number(O))),_&&($=$.filter(F=>F.error||F.status&&F.status>=400)),M){const F=String(M).toLowerCase();$=$.filter(W=>{var te;return(te=W.url)==null?void 0:te.toLowerCase().includes(F)})}P>0&&($=$.slice(-P)),H&&(a.length=0),E.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:R,command:x,success:!0,data:{url:window.location.href,title:document.title,totalCaptured:a.length,returnedCount:$.length,requests:$}}));return}const A=await e.handleCommand(I,document);E.send(JSON.stringify(A))}}catch(I){console.error("[Forensic ContentScript] Bridge message error:",I)}}}catch{m=null,T()}}function T(){g||(g=setInterval(()=>{(!m||m.readyState!==WebSocket.OPEN)&&b()},4e3))}c(),b(),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",v):v()})()})(); + `}attachEvents(){if(!this.shadowRoot)return;const e=this.shadowRoot.querySelector("#drag-header");e&&e.addEventListener("mousedown",c=>{this.isDragging=!0,this.dragStartX=c.clientX-this.posX,this.dragStartY=c.clientY-this.posY;const u=g=>{!this.isDragging||!this.hostElement||(this.posX=Math.max(10,Math.min(window.innerWidth-80,g.clientX-this.dragStartX)),this.posY=Math.max(10,Math.min(window.innerHeight-50,g.clientY-this.dragStartY)),this.hostElement.style.left=`${this.posX}px`,this.hostElement.style.top=`${this.posY}px`)},h=()=>{this.isDragging=!1,window.removeEventListener("mousemove",u),window.removeEventListener("mouseup",h),this.savePosition()};window.addEventListener("mousemove",u),window.addEventListener("mouseup",h)});const t=this.shadowRoot.querySelector("#btn-toggle-min");t==null||t.addEventListener("click",()=>{this.isMinimized=!this.isMinimized,this.savePosition(),this.render(),this.attachEvents()});const s=this.shadowRoot.querySelector("#btn-close");s==null||s.addEventListener("click",()=>{this.unmount()});const n=this.shadowRoot.querySelector("#btn-record");n==null||n.addEventListener("click",()=>{this.isRecording?this.callbacks.onStopRecord():this.callbacks.onStartRecord()});const i=this.shadowRoot.querySelector("#btn-checkpoint");i==null||i.addEventListener("click",()=>{if(this.callbacks.onCaptureCheckpoint(),i){const c=i.textContent;i.textContent="✔ Saved!",setTimeout(()=>i.textContent=c,1e3)}});const r=this.shadowRoot.querySelector("#btn-inspect");r==null||r.addEventListener("click",()=>{this.callbacks.onInspectElement()});const o=this.shadowRoot.querySelector("#btn-annotate");o==null||o.addEventListener("click",()=>{const c=prompt("Enter observation, bug note, or hypothesis at this exact moment:");c&&c.trim()&&this.callbacks.onAddAnnotation(c.trim())});const a=this.shadowRoot.querySelector("#btn-dashboard");a==null||a.addEventListener("click",()=>{this.callbacks.onOpenDashboard()})}}(function(){var m;let l=null;const e=new Ot;let t=[],s=null,n=null,i=!1;const r=500,o=[],a=[];window.addEventListener("message",d=>{var f;if(((f=d.data)==null?void 0:f._forensicOrigin)==="PAGE_MAIN"){const{type:w,payload:E}=d.data;if(w==="CONSOLE_ENTRY")o.push(E),o.length>r&&o.shift();else if(w==="NETWORK_ENTRY"){const S=a.findIndex(T=>T.requestId===E.requestId);S>=0?a[S]={...a[S],...E}:(a.push(E),a.length>r&&a.shift())}}});function c(){var d;try{if(typeof chrome<"u"&&((d=chrome.runtime)!=null&&d.getURL)){const f=document.createElement("script");f.src=chrome.runtime.getURL("dist/extension/page-script.js"),f.onload=()=>f.remove(),(document.head||document.documentElement).appendChild(f)}}catch{}}function u(){var f;if(t.length===0||!l)return;const d=[...t];t=[];try{typeof chrome<"u"&&((f=chrome.runtime)!=null&&f.sendMessage)&&chrome.runtime.sendMessage({type:"FORENSIC_EVENTS_CHUNK",sessionId:l.getSessionId(),events:d})}catch{}}function h(d,f,w){var S;if(l)return l.getMetadata();l=new Oe({sessionId:f,sessionName:d||`Recording on ${document.title||window.location.hostname}`}),l.onEvent(T=>{t.push(T),n&&n.incrementEventCount(),t.length>=25&&u()}),l.onCheckpoint(T=>{var x;try{typeof chrome<"u"&&((x=chrome.runtime)!=null&&x.sendMessage)&&chrome.runtime.sendMessage({type:"FORENSIC_CHECKPOINT",sessionId:T.sessionId,checkpoint:T})}catch{}});const E=l.start(document);try{typeof chrome<"u"&&((S=chrome.runtime)!=null&&S.sendMessage)&&chrome.runtime.sendMessage({type:"FORENSIC_SESSION_START",metadata:l.getMetadata(),initialSnapshot:E})}catch{}return s||(s=setInterval(u,1e3)),n&&n.updateState(!0,!1,w||Date.now(),0),l.getMetadata()}function g(){var w;if(!l)return null;u(),s&&(clearInterval(s),s=null);const d=l.stop();try{typeof chrome<"u"&&((w=chrome.runtime)!=null&&w.sendMessage)&&chrome.runtime.sendMessage({type:"FORENSIC_SESSION_STOP",sessionId:d.id,metadata:d})}catch{}const f={...d};return l=null,n&&n.updateState(!1,!1,0,0),f}function p(){if(i){i=!1,document.body.style.cursor="default";return}i=!0,document.body.style.cursor="crosshair";const d=document.createElement("div");d.id="forensic-inspect-highlighter",d.style.position="fixed",d.style.pointerEvents="none",d.style.zIndex="2147483640",d.style.border="2px dashed #38bdf8",d.style.background="rgba(56, 189, 248, 0.15)",d.style.transition="all 0.05s ease",document.body.appendChild(d);const f=E=>{if(!i)return;const S=E.target;if(!S||S.id==="forensic-recorder-floating-host"||S.closest("#forensic-recorder-floating-host")){d.style.display="none";return}const T=S.getBoundingClientRect();d.style.display="block",d.style.left=`${T.left}px`,d.style.top=`${T.top}px`,d.style.width=`${T.width}px`,d.style.height=`${T.height}px`},w=E=>{if(!i)return;const S=E.target;if(!S.closest("#forensic-recorder-floating-host")&&(E.preventDefault(),E.stopPropagation(),i=!1,document.body.style.cursor="default",d.remove(),window.removeEventListener("mousemove",f,!0),window.removeEventListener("click",w,!0),l)){const T=S.id?`#${S.id}`:S.className?`.${S.className.split(" ")[0]}`:S.tagName.toLowerCase();l.addAnnotation("Inspect Element",`Inspected element <${S.tagName.toLowerCase()}> with selector '${T}'`,"USER"),alert(`🎯 Inspected element <${S.tagName.toLowerCase()}> recorded! Checkpoint saved.`)}};window.addEventListener("mousemove",f,!0),window.addEventListener("click",w,!0)}function y(){return n||(n=new Ut({onStartRecord:()=>{h()},onStopRecord:()=>{g()},onTogglePause:()=>{l&&(l.getMetadata().status==="recording"?l.pause():l.resume())},onCaptureCheckpoint:()=>{l&&l.captureCheckpoint("MANUAL",document)},onAddAnnotation:d=>{l&&l.addAnnotation("User Note",d,"USER")},onInspectElement:()=>{p()},onOpenDashboard:()=>{const d=l?l.getSessionId():void 0;chrome.runtime.sendMessage({type:"OPEN_DASHBOARD_TAB",sessionId:d})}})),n}function v(){var d;try{typeof chrome<"u"&&((d=chrome.runtime)!=null&&d.sendMessage)&&chrome.runtime.sendMessage({type:"GET_TAB_RECORDING_STATE"},f=>{chrome.runtime.lastError||!f||f.isRecording&&f.recording&&(y().mount(),h(f.recording.sessionName,f.recording.sessionId,f.recording.startTime))})}catch{}}typeof chrome<"u"&&((m=chrome.runtime)!=null&&m.onMessage)&&chrome.runtime.onMessage.addListener((d,f,w)=>{if(d.type==="HIDE_FORENSIC_OVERLAYS")return n&&n.hide(),document.querySelectorAll('#forensic-recorder-floating-host, #forensic-inspect-highlighter, [id^="forensic-"]').forEach(S=>{const T=S;T.style.setProperty("display","none","important"),T.style.setProperty("visibility","hidden","important"),T.style.setProperty("opacity","0","important")}),w({success:!0}),!0;if(d.type==="RESTORE_FORENSIC_OVERLAYS")return n&&n.show(),document.querySelectorAll('#forensic-recorder-floating-host, #forensic-inspect-highlighter, [id^="forensic-"]').forEach(S=>{const T=S;T.style.removeProperty("display"),T.style.removeProperty("visibility"),T.style.removeProperty("opacity")}),w({success:!0}),!0;if(d.type==="BROWSER_COMMAND_REQUEST"){if(["LIST_TABS","FOCUS_TAB","RELOAD_TAB","LIST_EXTENSIONS","RELOAD_EXTENSION","CLOSE_TAB","OPEN_TAB","RESIZE_VIEWPORT","RESET_VIEWPORT"].includes(d.command))return!1;if(d.command==="GET_TAB_CONSOLE_LOGS"){const{level:E,searchQuery:S,limit:T=100,clearAfterRead:x}=d.payload||{};let N=[...o];if(E&&E!=="all"&&(N=N.filter(D=>D.level===E)),S){const D=String(S).toLowerCase();N=N.filter(M=>{var L,I;return((L=M.text)==null?void 0:L.toLowerCase().includes(D))||((I=M.source)==null?void 0:I.toLowerCase().includes(D))})}return T>0&&(N=N.slice(-T)),x&&(o.length=0),w({id:d.id,command:d.command,success:!0,data:{url:window.location.href,title:document.title,totalCaptured:o.length,returnedCount:N.length,logs:N}}),!0}if(d.command==="GET_TAB_NETWORK_REQUESTS"){const{method:E,searchQuery:S,status:T,onlyErrors:x,limit:N=100,clearAfterRead:D}=d.payload||{};let M=[...a];if(E&&(M=M.filter(L=>{var I;return((I=L.method)==null?void 0:I.toUpperCase())===String(E).toUpperCase()})),T&&(M=M.filter(L=>L.status===Number(T))),x&&(M=M.filter(L=>L.error||L.status&&L.status>=400)),S){const L=String(S).toLowerCase();M=M.filter(I=>{var C;return(C=I.url)==null?void 0:C.toLowerCase().includes(L)})}return N>0&&(M=M.slice(-N)),D&&(a.length=0),w({id:d.id,command:d.command,success:!0,data:{url:window.location.href,title:document.title,totalCaptured:a.length,returnedCount:M.length,requests:M}}),!0}return e.handleCommand(d,document).then(E=>{w(E)}),!0}else if(d.type==="START_RECORDING"){const E=h(d.sessionName);y().mount(),w({success:!0,metadata:E})}else if(d.type==="STOP_RECORDING"){const E=g();w({success:!0,metadata:E})}else if(d.type==="TOGGLE_FLOATING_OVERLAY"){const E=y();document.getElementById("forensic-recorder-floating-host")?(E.unmount(),w({isOpen:!1})):(E.mount(),E.updateState((l==null?void 0:l.getMetadata().status)==="recording",!1,(l==null?void 0:l.getMetadata().startTime)||0,0),w({isOpen:!0}))}else if(d.type==="GET_RECORDER_STATUS")w({isRecording:(l==null?void 0:l.getMetadata().status)==="recording",metadata:(l==null?void 0:l.getMetadata())||null});else if(d.type==="CAPTURE_CHECKPOINT")if(l){const E=l.captureCheckpoint("MANUAL",document);w({success:!0,checkpoint:E})}else w({success:!1,error:"Not currently recording"});return!0}),c(),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",v):v()})()})(); diff --git a/chrome-extension/dist/extension/service-worker.js b/chrome-extension/dist/extension/service-worker.js index 8a07840c..3df46b93 100644 --- a/chrome-extension/dist/extension/service-worker.js +++ b/chrome-extension/dist/extension/service-worker.js @@ -1 +1 @@ -var v=Object.defineProperty;var P=(E,l,d)=>l in E?v(E,l,{enumerable:!0,configurable:!0,writable:!0,value:d}):E[l]=d;var b=(E,l,d)=>P(E,typeof l!="symbol"?l+"":l,d);(function(){"use strict";var T,_,p,R;class E{constructor(s="ForensicRecorderDB"){b(this,"dbName");b(this,"dbVersion",1);b(this,"db",null);this.dbName=s}async openDB(){if(this.db)return this.db;if(typeof indexedDB>"u")throw new Error("IndexedDB is not available in current runtime environment");return new Promise((s,e)=>{const r=indexedDB.open(this.dbName,this.dbVersion);r.onupgradeneeded=c=>{const t=c.target.result;if(t.objectStoreNames.contains("sessions")||t.createObjectStore("sessions",{keyPath:"id"}),!t.objectStoreNames.contains("events")){const n=t.createObjectStore("events",{keyPath:"id"});n.createIndex("sessionId","sessionId",{unique:!1}),n.createIndex("sequence","sequence",{unique:!1})}t.objectStoreNames.contains("checkpoints")||t.createObjectStore("checkpoints",{keyPath:"checkpointId"}).createIndex("sessionId","sessionId",{unique:!1}),t.objectStoreNames.contains("snapshots")||t.createObjectStore("snapshots",{keyPath:"sessionId"}),t.objectStoreNames.contains("annotations")||t.createObjectStore("annotations",{keyPath:"id"}).createIndex("sessionId","sessionId",{unique:!1})},r.onsuccess=()=>{this.db=r.result,s(this.db)},r.onerror=()=>e(r.error)})}async saveSession(s){const e=await this.openDB();return new Promise((r,c)=>{const t=e.transaction("sessions","readwrite");t.objectStore("sessions").put(s),t.oncomplete=()=>r(),t.onerror=()=>c(t.error)})}async getSession(s){const e=await this.openDB();return new Promise((r,c)=>{const o=e.transaction("sessions","readonly").objectStore("sessions").get(s);o.onsuccess=()=>r(o.result||null),o.onerror=()=>c(o.error)})}async listSessions(){const s=await this.openDB();return new Promise((e,r)=>{const n=s.transaction("sessions","readonly").objectStore("sessions").getAll();n.onsuccess=()=>{const o=n.result||[];o.sort((a,u)=>u.startTime-a.startTime),e(o)},n.onerror=()=>r(n.error)})}async deleteSession(s){const e=await this.openDB();return new Promise((r,c)=>{const t=e.transaction(["sessions","events","checkpoints","snapshots","annotations"],"readwrite");t.objectStore("sessions").delete(s),t.objectStore("snapshots").delete(s);const a=t.objectStore("events").index("sessionId").openCursor(IDBKeyRange.only(s));a.onsuccess=()=>{const u=a.result;u&&(u.delete(),u.continue())},t.oncomplete=()=>r(!0),t.onerror=()=>c(t.error)})}async appendEvents(s,e){if(e.length===0)return;const r=await this.openDB();return new Promise((c,t)=>{const n=r.transaction("events","readwrite"),o=n.objectStore("events");for(const a of e)o.put(a);n.oncomplete=()=>c(),n.onerror=()=>t(n.error)})}async getEvents(s,e){const r=await this.openDB();return new Promise((c,t)=>{const u=r.transaction("events","readonly").objectStore("events").index("sessionId").getAll(IDBKeyRange.only(s));u.onsuccess=()=>{let m=u.result||[];m.sort((h,f)=>h.sequence-f.sequence),e&&(m=m.filter(h=>!(e.category&&h.category!==e.category||e.type&&h.type!==e.type||typeof e.fromTimestamp=="number"&&h.timestampe.toTimestamp||typeof e.targetNodeId=="number"&&h.targetNodeId!==e.targetNodeId)),typeof e.offset=="number"&&(m=m.slice(e.offset)),typeof e.limit=="number"&&(m=m.slice(0,e.limit))),c(m)},u.onerror=()=>t(u.error)})}async getEventCount(s){const e=await this.openDB();return new Promise((r,c)=>{const a=e.transaction("events","readonly").objectStore("events").index("sessionId").count(IDBKeyRange.only(s));a.onsuccess=()=>r(a.result),a.onerror=()=>c(a.error)})}async saveCheckpoint(s){const e=await this.openDB();return new Promise((r,c)=>{const t=e.transaction("checkpoints","readwrite");t.objectStore("checkpoints").put(s),t.oncomplete=()=>r(),t.onerror=()=>c(t.error)})}async getCheckpoints(s){const e=await this.openDB();return new Promise((r,c)=>{const o=e.transaction("checkpoints","readonly").objectStore("checkpoints").index("sessionId").getAll(IDBKeyRange.only(s));o.onsuccess=()=>{const a=o.result||[];a.sort((u,m)=>u.sequence-m.sequence),r(a)},o.onerror=()=>c(o.error)})}async saveInitialSnapshot(s,e){const r=await this.openDB();return new Promise((c,t)=>{const n=r.transaction("snapshots","readwrite");n.objectStore("snapshots").put({sessionId:s,snapshot:e}),n.oncomplete=()=>c(),n.onerror=()=>t(n.error)})}async getInitialSnapshot(s){const e=await this.openDB();return new Promise((r,c)=>{const n=e.transaction("snapshots","readonly").objectStore("snapshots").get(s);n.onsuccess=()=>r(n.result?n.result.snapshot:null),n.onerror=()=>c(n.error)})}async addAnnotation(s){const e=await this.openDB();return new Promise((r,c)=>{const t=e.transaction("annotations","readwrite");t.objectStore("annotations").put(s),t.oncomplete=()=>r(),t.onerror=()=>c(t.error)})}async getAnnotations(s){const e=await this.openDB();return new Promise((r,c)=>{const o=e.transaction("annotations","readonly").objectStore("annotations").index("sessionId").getAll(IDBKeyRange.only(s));o.onsuccess=()=>r(o.result||[]),o.onerror=()=>c(o.error)})}}const l=new E("ForensicExtensionDB");let d=null,S=null;const w=new Map,g=new Map;async function A(){return new Promise(i=>{try{chrome.tabs.query({active:!0,currentWindow:!0},s=>{if(chrome.runtime.lastError||!s||s.length===0)return i(null);i(s[0].id??null)})}catch{i(null)}})}try{(_=(T=chrome.debugger)==null?void 0:T.onEvent)==null||_.addListener((i,s,e)=>{try{for(const[r,c]of g.entries())if((i==null?void 0:i.tabId)===c||(i==null?void 0:i.targetId)===`tab_${c}`){d==null||d.send(JSON.stringify({type:"CDP_EVENT",sessionId:r,method:s,params:e,timestamp:Date.now()}));return}}catch{}})}catch{}async function O(i,s){if(i==="LIST_TABS")return new Promise((e,r)=>{chrome.tabs.query({},c=>{if(chrome.runtime.lastError)return r(new Error(chrome.runtime.lastError.message));const t=(c||[]).map(n=>({id:n.id,index:n.index,windowId:n.windowId,title:n.title||"Untitled",url:n.url||"",active:!!n.active,status:n.status,pinned:!!n.pinned,favIconUrl:n.favIconUrl,audited:n.id?w.has(n.id):!1,incognito:!!n.incognito,width:n.width,height:n.height}));e({totalTabs:t.length,tabs:t})})});if(i==="FOCUS_TAB"){const e=Number(s==null?void 0:s.tabId);if(!e)throw new Error("tabId is required for focus_tab");return new Promise((r,c)=>{chrome.tabs.update(e,{active:!0},t=>{var n;if(chrome.runtime.lastError||!t)return c(new Error(((n=chrome.runtime.lastError)==null?void 0:n.message)||`Tab ${e} not found`));t.windowId?chrome.windows.update(t.windowId,{focused:!0},()=>{r({focused:!0,tab:{id:t.id,windowId:t.windowId,title:t.title,url:t.url,active:t.active}})}):r({focused:!0,tab:{id:t.id,title:t.title,url:t.url,active:t.active}})})})}if(i==="RELOAD_TAB"){const e=!!(s!=null&&s.bypassCache),r=s!=null&&s.tabId?Number(s.tabId):void 0;return new Promise((c,t)=>{const n=o=>{chrome.tabs.reload(o,{bypassCache:e},()=>{if(chrome.runtime.lastError)return t(new Error(chrome.runtime.lastError.message));chrome.tabs.get(o,a=>{c({reloaded:!0,tabId:o,bypassCache:e,url:a==null?void 0:a.url,title:a==null?void 0:a.title})})})};r?chrome.tabs.get(r,o=>{chrome.runtime.lastError||!o?chrome.tabs.query({active:!0,lastFocusedWindow:!0},a=>{const u=a&&a[0]?a[0]:null;u!=null&&u.id?n(u.id):t(new Error("No active tab found to reload"))}):n(r)}):chrome.tabs.query({active:!0,lastFocusedWindow:!0},o=>{const a=o&&o[0]?o[0]:null;if(!(a!=null&&a.id))return t(new Error("No active tab found to reload"));n(a.id)})})}if(i==="CLOSE_TAB"){const e=s!=null&&s.tabId?Number(s.tabId):void 0,r=s!=null&&s.url?String(s.url).toLowerCase():void 0;return new Promise((c,t)=>{const n=o=>{chrome.tabs.remove(o,()=>{if(chrome.runtime.lastError)return t(new Error(chrome.runtime.lastError.message));c({closed:!0,tabIds:o,count:o.length})})};e?n([e]):r?chrome.tabs.query({},o=>{const u=(o||[]).filter(m=>{var h,f;return((h=m.url)==null?void 0:h.toLowerCase().includes(r))||((f=m.title)==null?void 0:f.toLowerCase().includes(r))}).map(m=>m.id).filter(Boolean);if(u.length===0)return c({closed:!1,message:`No open tab matched '${r}'`});n(u)}):chrome.tabs.query({active:!0,lastFocusedWindow:!0},o=>{const a=o&&o[0]?o[0]:null;if(!(a!=null&&a.id))return t(new Error("No active tab found to close"));n([a.id])})})}if(i==="OPEN_TAB"){const e=s==null?void 0:s.url;if(!e)throw new Error("url is required for open_tab");let r=String(e).trim();!r.startsWith("http://")&&!r.startsWith("https://")&&!r.startsWith("file://")&&!r.startsWith("chrome://")&&!r.startsWith("about:")&&(r.includes("meet.google.com")||r.includes("localhost")||r.includes(".com")||r.includes(".org")||r.includes(".net")||r.includes(".ir")||r.includes(".io")||r.includes(".app"))&&(r="https://"+r);const c=s.active!==!1,t=!!s.pinned;return new Promise((n,o)=>{chrome.tabs.create({url:r,active:c,pinned:t},a=>{if(chrome.runtime.lastError)return o(new Error(chrome.runtime.lastError.message));n({opened:!0,tabId:a.id,windowId:a.windowId,url:a.url||r,title:a.title||"New Tab",active:a.active,status:a.status})})})}if(i==="LIST_EXTENSIONS")return new Promise((e,r)=>{var c;if(!((c=chrome.management)!=null&&c.getAll))return r(new Error("chrome.management API not available"));chrome.management.getAll(t=>{if(chrome.runtime.lastError)return r(new Error(chrome.runtime.lastError.message));const n=(t||[]).map(o=>({id:o.id,name:o.name,version:o.version,description:o.description,enabled:o.enabled,installType:o.installType,isApp:o.isApp,homepageUrl:o.homepageUrl,permissions:o.permissions}));e({totalExtensions:n.length,extensions:n})})});if(i==="SET_EXTENSION_ENABLED"){const e=s==null?void 0:s.extensionId,r=!!(s!=null&&s.enabled);if(!e)throw new Error("extensionId is required for SET_EXTENSION_ENABLED");return new Promise((c,t)=>{var n;if(!((n=chrome.management)!=null&&n.setEnabled))return t(new Error("chrome.management API not available"));chrome.management.setEnabled(e,r,()=>{if(chrome.runtime.lastError)return t(new Error(chrome.runtime.lastError.message||`Failed to set enabled state for ${e}`));c({success:!0,extensionId:e,enabled:r,message:`Extension ${e} successfully ${r?"enabled":"disabled"}.`})})})}if(i==="TOGGLE_EXTENSION"){const e=s==null?void 0:s.extensionId;if(!e)throw new Error("extensionId is required for TOGGLE_EXTENSION");return new Promise((r,c)=>{var t,n;if(!((t=chrome.management)!=null&&t.get)||!((n=chrome.management)!=null&&n.setEnabled))return c(new Error("chrome.management API not available"));chrome.management.get(e,o=>{var u;if(chrome.runtime.lastError||!o)return c(new Error(((u=chrome.runtime.lastError)==null?void 0:u.message)||`Extension ${e} not found`));const a=!o.enabled;chrome.management.setEnabled(e,a,()=>{if(chrome.runtime.lastError)return c(new Error(chrome.runtime.lastError.message||`Failed to toggle ${e}`));r({success:!0,extensionId:e,enabled:a,name:o.name,message:`Extension ${o.name} (${e}) toggled to ${a?"enabled":"disabled"}.`})})})})}if(i==="RESIZE_VIEWPORT"){const e=Math.max(200,Math.min(7680,Number(s==null?void 0:s.width)||1280)),r=Math.max(200,Math.min(4320,Number(s==null?void 0:s.height)||800));return new Promise((c,t)=>{chrome.windows.getCurrent({populate:!1},n=>{var o;if(chrome.runtime.lastError||!n)return t(new Error(((o=chrome.runtime.lastError)==null?void 0:o.message)||"No current window"));chrome.windows.update(n.id??chrome.windows.WINDOW_ID_CURRENT,{width:e,height:r,state:"normal"},a=>{var u;if(chrome.runtime.lastError||!a)return t(new Error(((u=chrome.runtime.lastError)==null?void 0:u.message)||"Window resize failed"));c({success:!0,applied:{width:a.width,height:a.height},previous:{width:n.width,height:n.height},original:{width:n.width,height:n.height},reversible:!0,mode:"browser-window",note:"Reset with reset_viewport — the content script tracks the original size."})})})})}if(i==="RESET_VIEWPORT")return new Promise((e,r)=>{chrome.windows.getCurrent({populate:!1},c=>{var t;if(chrome.runtime.lastError||!c)return r(new Error(((t=chrome.runtime.lastError)==null?void 0:t.message)||"No current window"));chrome.windows.update(c.id??chrome.windows.WINDOW_ID_CURRENT,{state:"maximized"},n=>{var o;if(chrome.runtime.lastError||!n)return r(new Error(((o=chrome.runtime.lastError)==null?void 0:o.message)||"Window restore failed"));e({success:!0,applied:{width:n.width,height:n.height},previous:{width:c.width,height:c.height},original:{width:n.width,height:n.height},reversible:!1,mode:"browser-window",note:"Window restored to maximized state."})})})});if(i==="RELOAD_EXTENSION"){const e=s==null?void 0:s.extensionId,r=chrome.runtime.id;return!e||e===r?(setTimeout(()=>chrome.runtime.reload(),150),{reloaded:!0,extensionId:r,isSelf:!0,message:"Forensic Recorder extension is reloading now."}):new Promise((c,t)=>{var n;if(!((n=chrome.management)!=null&&n.setEnabled))return t(new Error("chrome.management API not available"));chrome.management.setEnabled(e,!1,()=>{if(chrome.runtime.lastError)return t(new Error(chrome.runtime.lastError.message||`Failed to disable ${e}`));setTimeout(()=>{chrome.management.setEnabled(e,!0,()=>{if(chrome.runtime.lastError)return t(new Error(chrome.runtime.lastError.message||`Failed to re-enable ${e}`));c({reloaded:!0,extensionId:e,isSelf:!1,message:`Extension ${e} successfully reloaded.`})})},150)})})}if(i==="CDP_ATTACH"){const e=(s==null?void 0:s.tabId)!==void 0?Number(s.tabId):await A();if(e===null)throw new Error("No target tab available for CDP attach.");return new Promise((r,c)=>{var t;if(!((t=chrome.debugger)!=null&&t.attach))return c(new Error('CDP_UNAVAILABLE: chrome.debugger API not available (check the "debugger" permission).'));chrome.debugger.attach({tabId:e},"1.3",()=>{if(chrome.runtime.lastError)return c(new Error(`CDP_ATTACH failed: ${chrome.runtime.lastError.message}`));s!=null&&s.sessionId&&g.set(String(s.sessionId),e),chrome.debugger.getTargets(n=>{const o=(n||[]).find(a=>a.tabId===e)||{};r({attached:!0,sessionId:s==null?void 0:s.sessionId,tabId:e,targetId:o.id||`tab_${e}`,type:o.type||"page"})})})})}if(i==="CDP_COMMAND"){const{sessionId:e,method:r,params:c}=s||{};if(!r)throw new Error("CDP_COMMAND requires method");return new Promise((t,n)=>{var a;if(!((a=chrome.debugger)!=null&&a.sendCommand))return n(new Error('CDP_UNAVAILABLE: chrome.debugger API not available (check the "debugger" permission).'));const o=g.get(e);if(o===void 0)return n(new Error(`CDP_SESSION_NOT_FOUND: no tab bound to session '${e}' — attach first.`));chrome.debugger.sendCommand({tabId:o},r,c||{},u=>{if(chrome.runtime.lastError){t({__cdpError:!0,code:"CDP_PROTOCOL_ERROR",message:chrome.runtime.lastError.message,method:r});return}t({result:u??{}})})})}if(i==="CDP_DETACH"){const{sessionId:e}=s||{},r=g.get(e);return g.delete(e),r===void 0?{detached:!1,reason:"session not found"}:new Promise((c,t)=>{var n;if(!((n=chrome.debugger)!=null&&n.detach))return c({detached:!1,reason:"chrome.debugger unavailable"});chrome.debugger.detach({tabId:r},()=>{if(chrome.runtime.lastError)return c({detached:!1,reason:chrome.runtime.lastError.message});c({detached:!0,sessionId:e,tabId:r})})})}throw new Error(`Unsupported background command: ${i}`)}function I(){if(!(typeof WebSocket>"u"))try{const i=new WebSocket("ws://127.0.0.1:3847");let s=null;i.onopen=()=>{var e;d=i,console.log("[Forensic Extension] Connected to MCP Bridge on ws://127.0.0.1:3847"),S&&(clearInterval(S),S=null),i.send(JSON.stringify({type:"REGISTER_CLIENT",clientType:"SERVICE_WORKER",url:typeof chrome<"u"&&((e=chrome.runtime)!=null&&e.id)?`chrome-extension://${chrome.runtime.id}`:"service-worker",title:"Forensic Service Worker"})),s&&clearInterval(s),s=setInterval(()=>{if(i&&i.readyState===WebSocket.OPEN)try{i.send(JSON.stringify({type:"HEARTBEAT",timestamp:Date.now()}))}catch(r){console.warn("[TeleDOM SW] non-critical operation failed:",(r==null?void 0:r.message)??r)}},15e3)},i.onclose=()=>{s&&clearInterval(s),d=null,N()},i.onerror=()=>{s&&clearInterval(s),d=null,N()},i.onmessage=async e=>{try{const r=JSON.parse(e.data.toString());if(r.type==="BROWSER_COMMAND_REQUEST"){const{id:c,command:t,payload:n}=r;if(typeof chrome>"u"||!chrome.tabs){i.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!1,error:{code:"NO_CHROME_TABS_API",message:"chrome.tabs API not available in this context"}}));return}if(["LIST_TABS","FOCUS_TAB","RELOAD_TAB","CLOSE_TAB","OPEN_TAB","LIST_EXTENSIONS","RELOAD_EXTENSION","SET_EXTENSION_ENABLED","TOGGLE_EXTENSION","CDP_ATTACH","CDP_COMMAND","CDP_DETACH"].includes(t)){try{const u=await O(t,n);i.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!0,data:u}))}catch(u){i.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!1,error:{code:"COMMAND_ERROR",message:u.message}}))}return}const o=n!=null&&n.tabId?Number(n.tabId):void 0,a=u=>{if(t==="LIVE_PAGE_SCREENSHOT"||t==="LIVE_ELEMENT_SCREENSHOT"){chrome.tabs.sendMessage(u,{type:"HIDE_FORENSIC_OVERLAYS"},()=>{setTimeout(()=>{chrome.tabs.captureVisibleTab({format:"png"},m=>{var h;if(chrome.tabs.sendMessage(u,{type:"RESTORE_FORENSIC_OVERLAYS"}),chrome.runtime.lastError||!m){i.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!1,error:{code:"SCREENSHOT_FAILED",message:((h=chrome.runtime.lastError)==null?void 0:h.message)||"captureVisibleTab failed"}}));return}chrome.tabs.sendMessage(u,{type:"BROWSER_COMMAND_REQUEST",id:c,command:t,payload:{...n,dataUrl:m}},f=>{const C=f||{id:c,command:t,success:!0,data:{dataUrl:m,captureType:t==="LIVE_ELEMENT_SCREENSHOT"?"ELEMENT":"FULL_PAGE"}};i.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",...C}))})})},150)});return}chrome.tabs.sendMessage(u,r,m=>{if(chrome.runtime.lastError){i.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!1,error:{code:"CONTENT_SCRIPT_UNREACHABLE",message:chrome.runtime.lastError.message||`Content script unreachable on tab ${u}`}}));return}i.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",...m||{id:c,command:t,success:!0}}))})};o?a(o):chrome.tabs.query({active:!0,lastFocusedWindow:!0},async u=>{const m=u&&u[0]?u[0]:null,h=m==null?void 0:m.id;if(!h){i.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!1,error:{code:"NO_ACTIVE_TAB",message:"No active browser tab found"}}));return}a(h)})}}catch(r){console.error("[ServiceWorker] Bridge message handling error:",r)}}}catch{d=null,N()}}function N(){S||(S=setInterval(()=>{(!d||d.readyState!==WebSocket.OPEN)&&I()},5e3))}I(),typeof chrome<"u"&&((p=chrome.webNavigation)!=null&&p.onCommitted)&&chrome.webNavigation.onCommitted.addListener(async i=>{var t;if(i.frameId!==0)return;const s=i.tabId,e=w.get(s);if(!e||!e.isRecording)return;let r="NAV_OTHER";i.transitionType==="reload"?r="NAV_RELOAD":(t=i.transitionQualifiers)!=null&&t.includes("forward_back")?r="NAV_FORWARD_BACK":i.transitionType==="link"&&(r="NAV_LINK");const c={id:`nav_${Date.now()}_${Math.random().toString(36).slice(2,6)}`,sessionId:e.sessionId,timestamp:Date.now()-e.startTime,sequence:999999,wallClockTime:Date.now(),type:r,category:"NAVIGATION",source:"USER_INTERACTION",payload:{url:i.url,transitionType:i.transitionType,transitionQualifiers:i.transitionQualifiers,tabId:i.tabId}};try{await l.appendEvents(e.sessionId,[c]),d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify({type:"FORENSIC_EVENTS_CHUNK",sessionId:e.sessionId,events:[c]}))}catch{}}),typeof chrome<"u"&&((R=chrome.runtime)!=null&&R.onMessage)&&chrome.runtime.onMessage.addListener((i,s,e)=>((async()=>{var r,c,t;try{const n=((r=s.tab)==null?void 0:r.id)??i.tabId;if(i.type==="FORENSIC_SESSION_START")n&&w.set(n,{sessionId:i.metadata.id,sessionName:i.metadata.name,startTime:i.metadata.startTime,initialUrl:i.metadata.url,isRecording:!0}),await l.saveSession(i.metadata),i.initialSnapshot&&await l.saveInitialSnapshot(i.metadata.id,i.initialSnapshot),d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify(i)),e({success:!0,sessionId:i.metadata.id});else if(i.type==="GET_TAB_RECORDING_STATE"){const o=n?w.get(n):null;e({isRecording:!!(o!=null&&o.isRecording),recording:o||null})}else if(i.type==="FORENSIC_EVENTS_CHUNK")await l.appendEvents(i.sessionId,i.events),d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify(i)),e({success:!0});else if(i.type==="FORENSIC_CHECKPOINT")await l.saveCheckpoint(i.checkpoint),d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify(i)),e({success:!0});else if(i.type==="FORENSIC_SESSION_STOP"){n&&w.delete(n);const o=await l.getSession(i.sessionId);o&&(o.status="stopped",o.endTime=Date.now(),(c=i.metadata)!=null&&c.durationMs&&(o.durationMs=i.metadata.durationMs),await l.saveSession(o)),d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify(i)),e({success:!0})}else if(i.type==="OPEN_DASHBOARD_TAB"){const o=chrome.runtime.getURL(`dist/src/ui/index.html${i.sessionId?`?session=${i.sessionId}`:""}`);chrome.tabs.create({url:o}),e({success:!0,url:o})}else if(i.type==="CAPTURE_SCREENSHOT"){if((t=chrome.tabs)!=null&&t.captureVisibleTab){chrome.tabs.captureVisibleTab({format:"png"},o=>{e({success:!!o,dataUrl:o})});return}e({success:!1,error:"Screenshot capture unsupported"})}else if(i.type==="ELEMENT_SELECTED")d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify(i)),e({success:!0});else if(i.type==="BROWSER_COMMAND_REQUEST")try{const o=await O(i.command,i.payload);e({id:i.id,command:i.command,success:!0,data:o})}catch(o){e({id:i.id,command:i.command,success:!1,error:{code:"COMMAND_ERROR",message:o.message}})}}catch(n){e({success:!1,error:n.message})}})(),!0)),I()})(); +var v=Object.defineProperty;var P=(E,h,d)=>h in E?v(E,h,{enumerable:!0,configurable:!0,writable:!0,value:d}):E[h]=d;var I=(E,h,d)=>P(E,typeof h!="symbol"?h+"":h,d);(function(){"use strict";var T,_,p,A;class E{constructor(s="ForensicRecorderDB"){I(this,"dbName");I(this,"dbVersion",1);I(this,"db",null);this.dbName=s}async openDB(){if(this.db)return this.db;if(typeof indexedDB>"u")throw new Error("IndexedDB is not available in current runtime environment");return new Promise((s,e)=>{const n=indexedDB.open(this.dbName,this.dbVersion);n.onupgradeneeded=c=>{const t=c.target.result;if(t.objectStoreNames.contains("sessions")||t.createObjectStore("sessions",{keyPath:"id"}),!t.objectStoreNames.contains("events")){const r=t.createObjectStore("events",{keyPath:"id"});r.createIndex("sessionId","sessionId",{unique:!1}),r.createIndex("sequence","sequence",{unique:!1})}t.objectStoreNames.contains("checkpoints")||t.createObjectStore("checkpoints",{keyPath:"checkpointId"}).createIndex("sessionId","sessionId",{unique:!1}),t.objectStoreNames.contains("snapshots")||t.createObjectStore("snapshots",{keyPath:"sessionId"}),t.objectStoreNames.contains("annotations")||t.createObjectStore("annotations",{keyPath:"id"}).createIndex("sessionId","sessionId",{unique:!1})},n.onsuccess=()=>{this.db=n.result,s(this.db)},n.onerror=()=>e(n.error)})}async saveSession(s){const e=await this.openDB();return new Promise((n,c)=>{const t=e.transaction("sessions","readwrite");t.objectStore("sessions").put(s),t.oncomplete=()=>n(),t.onerror=()=>c(t.error)})}async getSession(s){const e=await this.openDB();return new Promise((n,c)=>{const i=e.transaction("sessions","readonly").objectStore("sessions").get(s);i.onsuccess=()=>n(i.result||null),i.onerror=()=>c(i.error)})}async listSessions(){const s=await this.openDB();return new Promise((e,n)=>{const r=s.transaction("sessions","readonly").objectStore("sessions").getAll();r.onsuccess=()=>{const i=r.result||[];i.sort((a,u)=>u.startTime-a.startTime),e(i)},r.onerror=()=>n(r.error)})}async deleteSession(s){const e=await this.openDB();return new Promise((n,c)=>{const t=e.transaction(["sessions","events","checkpoints","snapshots","annotations"],"readwrite");t.objectStore("sessions").delete(s),t.objectStore("snapshots").delete(s);const a=t.objectStore("events").index("sessionId").openCursor(IDBKeyRange.only(s));a.onsuccess=()=>{const u=a.result;u&&(u.delete(),u.continue())},t.oncomplete=()=>n(!0),t.onerror=()=>c(t.error)})}async appendEvents(s,e){if(e.length===0)return;const n=await this.openDB();return new Promise((c,t)=>{const r=n.transaction("events","readwrite"),i=r.objectStore("events");for(const a of e)i.put(a);r.oncomplete=()=>c(),r.onerror=()=>t(r.error)})}async getEvents(s,e){const n=await this.openDB();return new Promise((c,t)=>{const u=n.transaction("events","readonly").objectStore("events").index("sessionId").getAll(IDBKeyRange.only(s));u.onsuccess=()=>{let m=u.result||[];m.sort((l,f)=>l.sequence-f.sequence),e&&(m=m.filter(l=>!(e.category&&l.category!==e.category||e.type&&l.type!==e.type||typeof e.fromTimestamp=="number"&&l.timestampe.toTimestamp||typeof e.targetNodeId=="number"&&l.targetNodeId!==e.targetNodeId)),typeof e.offset=="number"&&(m=m.slice(e.offset)),typeof e.limit=="number"&&(m=m.slice(0,e.limit))),c(m)},u.onerror=()=>t(u.error)})}async getEventCount(s){const e=await this.openDB();return new Promise((n,c)=>{const a=e.transaction("events","readonly").objectStore("events").index("sessionId").count(IDBKeyRange.only(s));a.onsuccess=()=>n(a.result),a.onerror=()=>c(a.error)})}async saveCheckpoint(s){const e=await this.openDB();return new Promise((n,c)=>{const t=e.transaction("checkpoints","readwrite");t.objectStore("checkpoints").put(s),t.oncomplete=()=>n(),t.onerror=()=>c(t.error)})}async getCheckpoints(s){const e=await this.openDB();return new Promise((n,c)=>{const i=e.transaction("checkpoints","readonly").objectStore("checkpoints").index("sessionId").getAll(IDBKeyRange.only(s));i.onsuccess=()=>{const a=i.result||[];a.sort((u,m)=>u.sequence-m.sequence),n(a)},i.onerror=()=>c(i.error)})}async saveInitialSnapshot(s,e){const n=await this.openDB();return new Promise((c,t)=>{const r=n.transaction("snapshots","readwrite");r.objectStore("snapshots").put({sessionId:s,snapshot:e}),r.oncomplete=()=>c(),r.onerror=()=>t(r.error)})}async getInitialSnapshot(s){const e=await this.openDB();return new Promise((n,c)=>{const r=e.transaction("snapshots","readonly").objectStore("snapshots").get(s);r.onsuccess=()=>n(r.result?r.result.snapshot:null),r.onerror=()=>c(r.error)})}async addAnnotation(s){const e=await this.openDB();return new Promise((n,c)=>{const t=e.transaction("annotations","readwrite");t.objectStore("annotations").put(s),t.oncomplete=()=>n(),t.onerror=()=>c(t.error)})}async getAnnotations(s){const e=await this.openDB();return new Promise((n,c)=>{const i=e.transaction("annotations","readonly").objectStore("annotations").index("sessionId").getAll(IDBKeyRange.only(s));i.onsuccess=()=>n(i.result||[]),i.onerror=()=>c(i.error)})}}const h=new E("ForensicExtensionDB");let d=null,S=null;const w=new Map,g=new Map;async function R(){return new Promise(o=>{try{chrome.tabs.query({active:!0,currentWindow:!0},s=>{if(chrome.runtime.lastError||!s||s.length===0)return o(null);o(s[0].id??null)})}catch{o(null)}})}try{(_=(T=chrome.debugger)==null?void 0:T.onEvent)==null||_.addListener((o,s,e)=>{try{for(const[n,c]of g.entries())if((o==null?void 0:o.tabId)===c||(o==null?void 0:o.targetId)===`tab_${c}`){d==null||d.send(JSON.stringify({type:"CDP_EVENT",sessionId:n,method:s,params:e,timestamp:Date.now()}));return}}catch{}})}catch{}async function O(o,s){if(o==="LIST_TABS")return new Promise((e,n)=>{chrome.tabs.query({},c=>{if(chrome.runtime.lastError)return n(new Error(chrome.runtime.lastError.message));const t=(c||[]).map(r=>({id:r.id,index:r.index,windowId:r.windowId,title:r.title||"Untitled",url:r.url||"",active:!!r.active,status:r.status,pinned:!!r.pinned,favIconUrl:r.favIconUrl,audited:r.id?w.has(r.id):!1,incognito:!!r.incognito,width:r.width,height:r.height}));e({totalTabs:t.length,tabs:t})})});if(o==="FOCUS_TAB"){const e=Number(s==null?void 0:s.tabId);if(!e)throw new Error("tabId is required for focus_tab");return new Promise((n,c)=>{chrome.tabs.update(e,{active:!0},t=>{var r;if(chrome.runtime.lastError||!t)return c(new Error(((r=chrome.runtime.lastError)==null?void 0:r.message)||`Tab ${e} not found`));t.windowId?chrome.windows.update(t.windowId,{focused:!0},()=>{n({focused:!0,tab:{id:t.id,windowId:t.windowId,title:t.title,url:t.url,active:t.active}})}):n({focused:!0,tab:{id:t.id,title:t.title,url:t.url,active:t.active}})})})}if(o==="RELOAD_TAB"){const e=!!(s!=null&&s.bypassCache),n=s!=null&&s.tabId?Number(s.tabId):void 0;return new Promise((c,t)=>{const r=i=>{chrome.tabs.reload(i,{bypassCache:e},()=>{if(chrome.runtime.lastError)return t(new Error(chrome.runtime.lastError.message));chrome.tabs.get(i,a=>{c({reloaded:!0,tabId:i,bypassCache:e,url:a==null?void 0:a.url,title:a==null?void 0:a.title})})})};n?chrome.tabs.get(n,i=>{chrome.runtime.lastError||!i?chrome.tabs.query({active:!0,lastFocusedWindow:!0},a=>{const u=a&&a[0]?a[0]:null;u!=null&&u.id?r(u.id):t(new Error("No active tab found to reload"))}):r(n)}):chrome.tabs.query({active:!0,lastFocusedWindow:!0},i=>{const a=i&&i[0]?i[0]:null;if(!(a!=null&&a.id))return t(new Error("No active tab found to reload"));r(a.id)})})}if(o==="CLOSE_TAB"){const e=s!=null&&s.tabId?Number(s.tabId):void 0,n=s!=null&&s.url?String(s.url).toLowerCase():void 0;return new Promise((c,t)=>{const r=i=>{chrome.tabs.remove(i,()=>{if(chrome.runtime.lastError)return t(new Error(chrome.runtime.lastError.message));c({closed:!0,tabIds:i,count:i.length})})};e?r([e]):n?chrome.tabs.query({},i=>{const u=(i||[]).filter(m=>{var l,f;return((l=m.url)==null?void 0:l.toLowerCase().includes(n))||((f=m.title)==null?void 0:f.toLowerCase().includes(n))}).map(m=>m.id).filter(Boolean);if(u.length===0)return c({closed:!1,message:`No open tab matched '${n}'`});r(u)}):chrome.tabs.query({active:!0,lastFocusedWindow:!0},i=>{const a=i&&i[0]?i[0]:null;if(!(a!=null&&a.id))return t(new Error("No active tab found to close"));r([a.id])})})}if(o==="OPEN_TAB"){const e=s==null?void 0:s.url;if(!e)throw new Error("url is required for open_tab");let n=String(e).trim();!n.startsWith("http://")&&!n.startsWith("https://")&&!n.startsWith("file://")&&!n.startsWith("chrome://")&&!n.startsWith("about:")&&(n.includes("meet.google.com")||n.includes("localhost")||n.includes(".com")||n.includes(".org")||n.includes(".net")||n.includes(".ir")||n.includes(".io")||n.includes(".app"))&&(n="https://"+n);const c=s.active!==!1,t=!!s.pinned;return new Promise((r,i)=>{chrome.tabs.create({url:n,active:c,pinned:t},a=>{if(chrome.runtime.lastError)return i(new Error(chrome.runtime.lastError.message));r({opened:!0,tabId:a.id,windowId:a.windowId,url:a.url||n,title:a.title||"New Tab",active:a.active,status:a.status})})})}if(o==="LIST_EXTENSIONS")return new Promise((e,n)=>{var c;if(!((c=chrome.management)!=null&&c.getAll))return n(new Error("chrome.management API not available"));chrome.management.getAll(t=>{if(chrome.runtime.lastError)return n(new Error(chrome.runtime.lastError.message));const r=(t||[]).map(i=>({id:i.id,name:i.name,version:i.version,description:i.description,enabled:i.enabled,installType:i.installType,isApp:i.isApp,homepageUrl:i.homepageUrl,permissions:i.permissions}));e({totalExtensions:r.length,extensions:r})})});if(o==="SET_EXTENSION_ENABLED"){const e=s==null?void 0:s.extensionId,n=!!(s!=null&&s.enabled);if(!e)throw new Error("extensionId is required for SET_EXTENSION_ENABLED");return new Promise((c,t)=>{var r;if(!((r=chrome.management)!=null&&r.setEnabled))return t(new Error("chrome.management API not available"));chrome.management.setEnabled(e,n,()=>{if(chrome.runtime.lastError)return t(new Error(chrome.runtime.lastError.message||`Failed to set enabled state for ${e}`));c({success:!0,extensionId:e,enabled:n,message:`Extension ${e} successfully ${n?"enabled":"disabled"}.`})})})}if(o==="TOGGLE_EXTENSION"){const e=s==null?void 0:s.extensionId;if(!e)throw new Error("extensionId is required for TOGGLE_EXTENSION");return new Promise((n,c)=>{var t,r;if(!((t=chrome.management)!=null&&t.get)||!((r=chrome.management)!=null&&r.setEnabled))return c(new Error("chrome.management API not available"));chrome.management.get(e,i=>{var u;if(chrome.runtime.lastError||!i)return c(new Error(((u=chrome.runtime.lastError)==null?void 0:u.message)||`Extension ${e} not found`));const a=!i.enabled;chrome.management.setEnabled(e,a,()=>{if(chrome.runtime.lastError)return c(new Error(chrome.runtime.lastError.message||`Failed to toggle ${e}`));n({success:!0,extensionId:e,enabled:a,name:i.name,message:`Extension ${i.name} (${e}) toggled to ${a?"enabled":"disabled"}.`})})})})}if(o==="RESIZE_VIEWPORT"){const e=Math.max(200,Math.min(7680,Number(s==null?void 0:s.width)||1280)),n=Math.max(200,Math.min(4320,Number(s==null?void 0:s.height)||800));return new Promise((c,t)=>{chrome.windows.getCurrent({populate:!1},r=>{var i;if(chrome.runtime.lastError||!r)return t(new Error(((i=chrome.runtime.lastError)==null?void 0:i.message)||"No current window"));chrome.windows.update(r.id??chrome.windows.WINDOW_ID_CURRENT,{width:e,height:n,state:"normal"},a=>{var u;if(chrome.runtime.lastError||!a)return t(new Error(((u=chrome.runtime.lastError)==null?void 0:u.message)||"Window resize failed"));c({success:!0,applied:{width:a.width,height:a.height},previous:{width:r.width,height:r.height},original:{width:r.width,height:r.height},reversible:!0,mode:"browser-window",note:"Reset with reset_viewport — the content script tracks the original size."})})})})}if(o==="RESET_VIEWPORT")return new Promise((e,n)=>{chrome.windows.getCurrent({populate:!1},c=>{var t;if(chrome.runtime.lastError||!c)return n(new Error(((t=chrome.runtime.lastError)==null?void 0:t.message)||"No current window"));chrome.windows.update(c.id??chrome.windows.WINDOW_ID_CURRENT,{state:"maximized"},r=>{var i;if(chrome.runtime.lastError||!r)return n(new Error(((i=chrome.runtime.lastError)==null?void 0:i.message)||"Window restore failed"));e({success:!0,applied:{width:r.width,height:r.height},previous:{width:c.width,height:c.height},original:{width:r.width,height:r.height},reversible:!1,mode:"browser-window",note:"Window restored to maximized state."})})})});if(o==="RELOAD_EXTENSION"){const e=s==null?void 0:s.extensionId,n=chrome.runtime.id;return!e||e===n?(setTimeout(()=>chrome.runtime.reload(),150),{reloaded:!0,extensionId:n,isSelf:!0,message:"Forensic Recorder extension is reloading now."}):new Promise((c,t)=>{var r;if(!((r=chrome.management)!=null&&r.setEnabled))return t(new Error("chrome.management API not available"));chrome.management.setEnabled(e,!1,()=>{if(chrome.runtime.lastError)return t(new Error(chrome.runtime.lastError.message||`Failed to disable ${e}`));setTimeout(()=>{chrome.management.setEnabled(e,!0,()=>{if(chrome.runtime.lastError)return t(new Error(chrome.runtime.lastError.message||`Failed to re-enable ${e}`));c({reloaded:!0,extensionId:e,isSelf:!1,message:`Extension ${e} successfully reloaded.`})})},150)})})}if(o==="CDP_ATTACH"){const e=(s==null?void 0:s.tabId)!==void 0?Number(s.tabId):await R();if(e===null)throw new Error("No target tab available for CDP attach.");return new Promise((n,c)=>{var t;if(!((t=chrome.debugger)!=null&&t.attach))return c(new Error('CDP_UNAVAILABLE: chrome.debugger API not available (check the "debugger" permission).'));chrome.debugger.attach({tabId:e},"1.3",()=>{if(chrome.runtime.lastError){const r=chrome.runtime.lastError.message||"";return r.includes("Another debugger is already attached")?c(new Error(`CDP_ATTACH failed: Chrome DevTools (F12) is already open on tab ${e}. Please close the F12 panel on that tab so TeleDOM can attach.`)):c(new Error(`CDP_ATTACH failed: ${r}`))}s!=null&&s.sessionId&&g.set(String(s.sessionId),e),chrome.debugger.getTargets(r=>{const i=(r||[]).find(a=>a.tabId===e)||{};n({attached:!0,sessionId:s==null?void 0:s.sessionId,tabId:e,targetId:i.id||`tab_${e}`,type:i.type||"page"})})})})}if(o==="CDP_COMMAND"){const{sessionId:e,method:n,params:c}=s||{};if(!n)throw new Error("CDP_COMMAND requires method");return new Promise((t,r)=>{var a;if(!((a=chrome.debugger)!=null&&a.sendCommand))return r(new Error('CDP_UNAVAILABLE: chrome.debugger API not available (check the "debugger" permission).'));const i=g.get(e);if(i===void 0)return r(new Error(`CDP_SESSION_NOT_FOUND: no tab bound to session '${e}' — attach first.`));chrome.debugger.sendCommand({tabId:i},n,c||{},u=>{if(chrome.runtime.lastError){t({__cdpError:!0,code:"CDP_PROTOCOL_ERROR",message:chrome.runtime.lastError.message,method:n});return}t({result:u??{}})})})}if(o==="CDP_DETACH"){const{sessionId:e}=s||{},n=g.get(e);return g.delete(e),n===void 0?{detached:!1,reason:"session not found"}:new Promise((c,t)=>{var r;if(!((r=chrome.debugger)!=null&&r.detach))return c({detached:!1,reason:"chrome.debugger unavailable"});chrome.debugger.detach({tabId:n},()=>{if(chrome.runtime.lastError)return c({detached:!1,reason:chrome.runtime.lastError.message});c({detached:!0,sessionId:e,tabId:n})})})}throw new Error(`Unsupported background command: ${o}`)}function b(){if(!(typeof WebSocket>"u"))try{const o=new WebSocket("ws://127.0.0.1:3847");let s=null;o.onopen=()=>{var e;d=o,console.log("[Forensic Extension] Connected to MCP Bridge on ws://127.0.0.1:3847"),S&&(clearInterval(S),S=null),o.send(JSON.stringify({type:"REGISTER_CLIENT",clientType:"SERVICE_WORKER",url:typeof chrome<"u"&&((e=chrome.runtime)!=null&&e.id)?`chrome-extension://${chrome.runtime.id}`:"service-worker",title:"Forensic Service Worker"})),s&&clearInterval(s),s=setInterval(()=>{if(o&&o.readyState===WebSocket.OPEN)try{o.send(JSON.stringify({type:"HEARTBEAT",timestamp:Date.now()}))}catch(n){console.warn("[TeleDOM SW] non-critical operation failed:",(n==null?void 0:n.message)??n)}},15e3)},o.onclose=()=>{s&&clearInterval(s),d=null,N()},o.onerror=()=>{s&&clearInterval(s),d=null,N()},o.onmessage=async e=>{try{const n=JSON.parse(e.data.toString());if(n.type==="BROWSER_COMMAND_REQUEST"){const{id:c,command:t,payload:r}=n;if(typeof chrome>"u"||!chrome.tabs){o.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!1,error:{code:"NO_CHROME_TABS_API",message:"chrome.tabs API not available in this context"}}));return}if(["LIST_TABS","FOCUS_TAB","RELOAD_TAB","CLOSE_TAB","OPEN_TAB","LIST_EXTENSIONS","RELOAD_EXTENSION","SET_EXTENSION_ENABLED","TOGGLE_EXTENSION","CDP_ATTACH","CDP_COMMAND","CDP_DETACH"].includes(t)){try{const u=await O(t,r);o.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!0,data:u}))}catch(u){o.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!1,error:{code:"COMMAND_ERROR",message:u.message}}))}return}const i=r!=null&&r.tabId?Number(r.tabId):void 0,a=u=>{if(t==="LIVE_PAGE_SCREENSHOT"||t==="LIVE_ELEMENT_SCREENSHOT"){chrome.tabs.sendMessage(u,{type:"HIDE_FORENSIC_OVERLAYS"},()=>{setTimeout(()=>{chrome.tabs.captureVisibleTab({format:"png"},m=>{var l;if(chrome.tabs.sendMessage(u,{type:"RESTORE_FORENSIC_OVERLAYS"}),chrome.runtime.lastError||!m){o.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!1,error:{code:"SCREENSHOT_FAILED",message:((l=chrome.runtime.lastError)==null?void 0:l.message)||"captureVisibleTab failed"}}));return}chrome.tabs.sendMessage(u,{type:"BROWSER_COMMAND_REQUEST",id:c,command:t,payload:{...r,dataUrl:m}},f=>{const C=f||{id:c,command:t,success:!0,data:{dataUrl:m,captureType:t==="LIVE_ELEMENT_SCREENSHOT"?"ELEMENT":"FULL_PAGE"}};o.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",...C}))})})},150)});return}chrome.tabs.sendMessage(u,n,m=>{if(chrome.runtime.lastError){o.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!1,error:{code:"CONTENT_SCRIPT_UNREACHABLE",message:chrome.runtime.lastError.message||`Content script unreachable on tab ${u}`}}));return}o.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",...m||{id:c,command:t,success:!0}}))})};i?a(i):chrome.tabs.query({active:!0,lastFocusedWindow:!0},async u=>{const m=u&&u[0]?u[0]:null,l=m==null?void 0:m.id;if(!l){o.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!1,error:{code:"NO_ACTIVE_TAB",message:"No active browser tab found"}}));return}a(l)})}}catch(n){console.error("[ServiceWorker] Bridge message handling error:",n)}}}catch{d=null,N()}}function N(){S||(S=setInterval(()=>{(!d||d.readyState!==WebSocket.OPEN)&&b()},5e3))}if(typeof chrome<"u"&&chrome.alarms)try{chrome.alarms.create("teledom_bridge_keepalive",{periodInMinutes:.4}),chrome.alarms.onAlarm.addListener(o=>{if(o.name==="teledom_bridge_keepalive")if(!d||d.readyState!==WebSocket.OPEN)b();else try{d.send(JSON.stringify({type:"HEARTBEAT",timestamp:Date.now()}))}catch{b()}})}catch(o){console.warn("[ServiceWorker] Alarms keepalive setup failed:",o==null?void 0:o.message)}b(),typeof chrome<"u"&&((p=chrome.webNavigation)!=null&&p.onCommitted)&&chrome.webNavigation.onCommitted.addListener(async o=>{var t;if(o.frameId!==0)return;const s=o.tabId,e=w.get(s);if(!e||!e.isRecording)return;let n="NAV_OTHER";o.transitionType==="reload"?n="NAV_RELOAD":(t=o.transitionQualifiers)!=null&&t.includes("forward_back")?n="NAV_FORWARD_BACK":o.transitionType==="link"&&(n="NAV_LINK");const c={id:`nav_${Date.now()}_${Math.random().toString(36).slice(2,6)}`,sessionId:e.sessionId,timestamp:Date.now()-e.startTime,sequence:999999,wallClockTime:Date.now(),type:n,category:"NAVIGATION",source:"USER_INTERACTION",payload:{url:o.url,transitionType:o.transitionType,transitionQualifiers:o.transitionQualifiers,tabId:o.tabId}};try{await h.appendEvents(e.sessionId,[c]),d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify({type:"FORENSIC_EVENTS_CHUNK",sessionId:e.sessionId,events:[c]}))}catch{}}),typeof chrome<"u"&&((A=chrome.runtime)!=null&&A.onMessage)&&chrome.runtime.onMessage.addListener((o,s,e)=>((async()=>{var n,c,t;try{const r=((n=s.tab)==null?void 0:n.id)??o.tabId;if(o.type==="FORENSIC_SESSION_START")r&&w.set(r,{sessionId:o.metadata.id,sessionName:o.metadata.name,startTime:o.metadata.startTime,initialUrl:o.metadata.url,isRecording:!0}),await h.saveSession(o.metadata),o.initialSnapshot&&await h.saveInitialSnapshot(o.metadata.id,o.initialSnapshot),d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify(o)),e({success:!0,sessionId:o.metadata.id});else if(o.type==="GET_TAB_RECORDING_STATE"){const i=r?w.get(r):null;e({isRecording:!!(i!=null&&i.isRecording),recording:i||null})}else if(o.type==="FORENSIC_EVENTS_CHUNK")await h.appendEvents(o.sessionId,o.events),d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify(o)),e({success:!0});else if(o.type==="FORENSIC_CHECKPOINT")await h.saveCheckpoint(o.checkpoint),d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify(o)),e({success:!0});else if(o.type==="FORENSIC_SESSION_STOP"){r&&w.delete(r);const i=await h.getSession(o.sessionId);i&&(i.status="stopped",i.endTime=Date.now(),(c=o.metadata)!=null&&c.durationMs&&(i.durationMs=o.metadata.durationMs),await h.saveSession(i)),d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify(o)),e({success:!0})}else if(o.type==="OPEN_DASHBOARD_TAB"){const i=chrome.runtime.getURL(`dist/src/ui/index.html${o.sessionId?`?session=${o.sessionId}`:""}`);chrome.tabs.create({url:i}),e({success:!0,url:i})}else if(o.type==="CAPTURE_SCREENSHOT"){if((t=chrome.tabs)!=null&&t.captureVisibleTab){chrome.tabs.captureVisibleTab({format:"png"},i=>{e({success:!!i,dataUrl:i})});return}e({success:!1,error:"Screenshot capture unsupported"})}else if(o.type==="ELEMENT_SELECTED")d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify(o)),e({success:!0});else if(o.type==="BROWSER_COMMAND_REQUEST")try{const i=await O(o.command,o.payload);e({id:o.id,command:o.command,success:!0,data:i})}catch(i){e({id:o.id,command:o.command,success:!1,error:{code:"COMMAND_ERROR",message:i.message}})}}catch(r){e({success:!1,error:r.message})}})(),!0)),b()})(); diff --git a/chrome-extension/dist/server/bridge-server.js b/chrome-extension/dist/server/bridge-server.js index a5935064..67ebe9f7 100644 --- a/chrome-extension/dist/server/bridge-server.js +++ b/chrome-extension/dist/server/bridge-server.js @@ -123,41 +123,49 @@ class FileStorageProvider { async saveSession(metadata) { const dir = this.getSessionDir(metadata.id); const metaPath = path.join(dir, "metadata.json"); - fs.writeFileSync(metaPath, JSON.stringify(metadata, null, 2), "utf-8"); + await fs.promises.writeFile(metaPath, JSON.stringify(metadata, null, 2), "utf-8"); } async getSession(sessionId) { const dir = path.join(this.baseDir, sessionId); const metaPath = path.join(dir, "metadata.json"); - if (!fs.existsSync(metaPath)) return null; try { - const data = fs.readFileSync(metaPath, "utf-8"); + const data = await fs.promises.readFile(metaPath, "utf-8"); return JSON.parse(data); - } catch { + } catch (err) { + if (err?.code !== "ENOENT") { + console.warn(`[FileStorage] Warning: Failed to read session ${sessionId}: ${err?.message}`); + } return null; } } async listSessions() { if (!fs.existsSync(this.baseDir)) return []; - const entries = fs.readdirSync(this.baseDir, { withFileTypes: true }); - const sessions = []; - for (const entry of entries) { - if (entry.isDirectory()) { - const metaPath = path.join(this.baseDir, entry.name, "metadata.json"); - if (fs.existsSync(metaPath)) { + try { + const entries = await fs.promises.readdir(this.baseDir, { withFileTypes: true }); + const sessions = []; + for (const entry of entries) { + if (entry.isDirectory()) { + const metaPath = path.join(this.baseDir, entry.name, "metadata.json"); try { - const data = fs.readFileSync(metaPath, "utf-8"); + const data = await fs.promises.readFile(metaPath, "utf-8"); sessions.push(JSON.parse(data)); - } catch { + } catch (err) { + if (err?.code !== "ENOENT") { + console.warn(`[FileStorage] Warning: Corrupt or unreadable session metadata at ${metaPath}: ${err?.message}`); + } } } } + return sessions.sort((a, b) => b.startTime - a.startTime); + } catch (err) { + console.error(`[FileStorage] Failed to list sessions from ${this.baseDir}:`, err?.message); + return []; } - return sessions.sort((a, b) => b.startTime - a.startTime); } async deleteSession(sessionId) { const dir = path.join(this.baseDir, sessionId); if (fs.existsSync(dir)) { - fs.rmSync(dir, { recursive: true, force: true }); + await fs.promises.rm(dir, { recursive: true, force: true, maxRetries: 10, retryDelay: 50 }); return true; } return false; @@ -167,7 +175,7 @@ class FileStorageProvider { const dir = this.getSessionDir(sessionId); const eventsPath = path.join(dir, "events.jsonl"); const lines = events.map((e) => JSON.stringify(e)).join("\n") + "\n"; - fs.appendFileSync(eventsPath, lines, "utf-8"); + await fs.promises.appendFile(eventsPath, lines, "utf-8"); } async getEvents(sessionId, filter) { const dir = path.join(this.baseDir, sessionId); @@ -182,42 +190,46 @@ class FileStorageProvider { let matchedCount = 0; const offset = typeof filter?.offset === "number" ? filter.offset : 0; const limit = typeof filter?.limit === "number" ? filter.limit : Infinity; - for await (const line of rl) { - const trimmed = line.trim(); - if (!trimmed) continue; - let e; - try { - e = JSON.parse(trimmed); - } catch { - continue; - } - if (filter) { - if (filter.category && e.category !== filter.category) continue; - if (filter.type && e.type !== filter.type) continue; - if (typeof filter.fromTimestamp === "number" && e.timestamp < filter.fromTimestamp) continue; - if (typeof filter.toTimestamp === "number" && e.timestamp > filter.toTimestamp) continue; - if (typeof filter.fromSequence === "number" && e.sequence < filter.fromSequence) continue; - if (typeof filter.toSequence === "number" && e.sequence > filter.toSequence) continue; - if (typeof filter.targetNodeId === "number" && e.targetNodeId !== filter.targetNodeId) continue; - if (filter.targetSelector && e.targetSelector && !e.targetSelector.includes(filter.targetSelector)) continue; - if (filter.searchQuery) { - const query = filter.searchQuery.toLowerCase(); - const strPayload = JSON.stringify(e.payload || {}).toLowerCase(); - if (!strPayload.includes(query) && !e.type.toLowerCase().includes(query)) { - continue; + try { + for await (const line of rl) { + const trimmed = line.trim(); + if (!trimmed) continue; + let e; + try { + e = JSON.parse(trimmed); + } catch (parseErr) { + console.warn(`[FileStorage] Skipping malformed event line in session ${sessionId}:`, parseErr); + continue; + } + if (filter) { + if (filter.category && e.category !== filter.category) continue; + if (filter.type && e.type !== filter.type) continue; + if (typeof filter.fromTimestamp === "number" && e.timestamp < filter.fromTimestamp) continue; + if (typeof filter.toTimestamp === "number" && e.timestamp > filter.toTimestamp) continue; + if (typeof filter.fromSequence === "number" && e.sequence < filter.fromSequence) continue; + if (typeof filter.toSequence === "number" && e.sequence > filter.toSequence) continue; + if (typeof filter.targetNodeId === "number" && e.targetNodeId !== filter.targetNodeId) continue; + if (filter.targetSelector && e.targetSelector && !e.targetSelector.includes(filter.targetSelector)) continue; + if (filter.searchQuery) { + const query = filter.searchQuery.toLowerCase(); + const strPayload = JSON.stringify(e.payload || {}).toLowerCase(); + if (!strPayload.includes(query) && !e.type.toLowerCase().includes(query)) { + continue; + } } } + matchedCount++; + if (matchedCount <= offset) { + continue; + } + results.push(e); + if (results.length >= limit) { + break; + } } - matchedCount++; - if (matchedCount <= offset) { - continue; - } - results.push(e); - if (results.length >= limit) { - rl.close(); - fileStream.destroy(); - break; - } + } finally { + rl.close(); + fileStream.destroy(); } return results; } @@ -231,44 +243,59 @@ class FileStorageProvider { crlfDelay: Infinity }); let count = 0; - for await (const line of rl) { - if (line.trim()) count++; + try { + for await (const line of rl) { + if (line.trim()) count++; + } + } finally { + rl.close(); + fileStream.destroy(); } return count; } async saveCheckpoint(checkpoint) { const dir = this.getSessionDir(checkpoint.sessionId); const chkDir = path.join(dir, "checkpoints"); - if (!fs.existsSync(chkDir)) fs.mkdirSync(chkDir, { recursive: true }); + await fs.promises.mkdir(chkDir, { recursive: true }); const file = path.join(chkDir, `${checkpoint.checkpointId}.json`); - fs.writeFileSync(file, JSON.stringify(checkpoint, null, 2), "utf-8"); + await fs.promises.writeFile(file, JSON.stringify(checkpoint, null, 2), "utf-8"); } async getCheckpoints(sessionId) { const dir = path.join(this.baseDir, sessionId, "checkpoints"); - if (!fs.existsSync(dir)) return []; - const files = fs.readdirSync(dir).filter((f) => f.endsWith(".json")); - const checkpoints = []; - for (const f of files) { - try { - const data = fs.readFileSync(path.join(dir, f), "utf-8"); - checkpoints.push(JSON.parse(data)); - } catch { + try { + const files = (await fs.promises.readdir(dir)).filter((f) => f.endsWith(".json")); + const checkpoints = []; + for (const f of files) { + try { + const data = await fs.promises.readFile(path.join(dir, f), "utf-8"); + checkpoints.push(JSON.parse(data)); + } catch (err) { + console.warn(`[FileStorage] Failed to read/parse checkpoint file ${f} in session ${sessionId}:`, err); + } } + return checkpoints.sort((a, b) => a.sequence - b.sequence); + } catch (err) { + if (err?.code !== "ENOENT") { + console.warn(`[FileStorage] Error accessing checkpoints directory for session ${sessionId}:`, err); + } + return []; } - return checkpoints.sort((a, b) => a.sequence - b.sequence); } async saveInitialSnapshot(sessionId, snapshot) { const dir = this.getSessionDir(sessionId); const file = path.join(dir, "initial_snapshot.json"); - fs.writeFileSync(file, JSON.stringify(snapshot, null, 2), "utf-8"); + await fs.promises.writeFile(file, JSON.stringify(snapshot, null, 2), "utf-8"); } async getInitialSnapshot(sessionId) { const dir = path.join(this.baseDir, sessionId); const file = path.join(dir, "initial_snapshot.json"); - if (!fs.existsSync(file)) return null; try { - return JSON.parse(fs.readFileSync(file, "utf-8")); - } catch { + const content = await fs.promises.readFile(file, "utf-8"); + return JSON.parse(content); + } catch (err) { + if (err?.code !== "ENOENT") { + console.warn(`[FileStorage] Error reading initial snapshot for session ${sessionId}:`, err); + } return null; } } @@ -276,23 +303,28 @@ class FileStorageProvider { const dir = this.getSessionDir(annotation.sessionId); const annPath = path.join(dir, "annotations.json"); let list = []; - if (fs.existsSync(annPath)) { - try { - list = JSON.parse(fs.readFileSync(annPath, "utf-8")); - } catch { - list = []; + try { + const content = await fs.promises.readFile(annPath, "utf-8"); + list = JSON.parse(content); + } catch (err) { + if (err?.code !== "ENOENT") { + console.warn(`[FileStorage] Corrupted annotations file for session ${annotation.sessionId}, starting fresh:`, err); } + list = []; } list.push(annotation); - fs.writeFileSync(annPath, JSON.stringify(list, null, 2), "utf-8"); + await fs.promises.writeFile(annPath, JSON.stringify(list, null, 2), "utf-8"); } async getAnnotations(sessionId) { const dir = path.join(this.baseDir, sessionId); const annPath = path.join(dir, "annotations.json"); - if (!fs.existsSync(annPath)) return []; try { - return JSON.parse(fs.readFileSync(annPath, "utf-8")); - } catch { + const content = await fs.promises.readFile(annPath, "utf-8"); + return JSON.parse(content); + } catch (err) { + if (err?.code !== "ENOENT") { + console.warn(`[FileStorage] Failed to read annotations for session ${sessionId}:`, err); + } return []; } } @@ -8997,7 +9029,18 @@ class LiveToolsHandler { } ] }; - } catch { + } catch (saveErr) { + return { + content: [ + { + type: "text", + text: JSON.stringify({ + ...finalSummary, + fileSaveError: `Failed to write pipeline output to ${args.outputPath}: ${saveErr?.message || saveErr}` + }, null, 2) + } + ] + }; } } return { @@ -9403,7 +9446,8 @@ class ProjectManager { try { const manifest = JSON.parse(fs__default.readFileSync(manifestPath, "utf-8")); out.push({ ...manifest, projectDir: path__default.join(this.baseDir, entry.name), pageCount: manifest.pages?.length || 0 }); - } catch { + } catch (err) { + console.warn(`[ProjectManager] Warning: Skipped corrupt project manifest at ${manifestPath}:`, err); } } return out.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0)); @@ -9664,7 +9708,8 @@ class ProjectManager { if (fs__default.existsSync(p)) { try { out.push(JSON.parse(fs__default.readFileSync(p, "utf-8"))); - } catch { + } catch (err) { + console.warn(`[ProjectManager] Warning: Skipped corrupt region file ${p}:`, err); } } } @@ -10026,7 +10071,8 @@ class CommandRecordingStorage { try { const raw = JSON.parse(fs__default.readFileSync(file, "utf-8")); return raw.recording || raw; - } catch { + } catch (err) { + console.warn(`[RecordingStorage] Warning: Failed to parse recording file ${file}:`, err); return null; } } @@ -10054,7 +10100,8 @@ class CommandRecordingStorage { tags: rec.tags || [], file: path__default.join(this.baseDir, entry.name) }); - } catch { + } catch (err) { + console.warn(`[RecordingStorage] Warning: Skipped corrupt recording file ${entry.name}:`, err); } } return out.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0)); @@ -10471,6 +10518,111 @@ function buildToolCatalog() { } return catalog; } +const TELEDOM_PROFILE_TOOLS = { + // Minimal profile: strictly essential browser actions (~22 tools, ~2.5k tokens) + minimal: [ + "td_browser_navigate", + "td_browser_back", + "td_browser_forward", + "td_browser_refresh", + "td_dom_inspect", + "td_dom_query", + "td_dom_extract", + "td_dom_snapshot", + "td_target_find", + "td_target_check", + "td_action_click", + "td_action_type", + "td_action_select", + "td_action_press", + "td_action_scroll", + "td_wait", + "td_screenshot", + "td_execute_script", + "list_tabs", + "focus_tab", + "close_tab", + "open_tab" + ], + // Core profile: browser primitives + workflow runtime + target memory (~44 tools, ~4.8k tokens) + core: [ + "td_browser_navigate", + "td_browser_back", + "td_browser_forward", + "td_browser_refresh", + "td_dom_inspect", + "td_dom_query", + "td_dom_extract", + "td_dom_snapshot", + "td_target_find", + "td_target_check", + "td_target_describe", + "td_action_click", + "td_action_type", + "td_action_select", + "td_action_hover", + "td_action_press", + "td_action_scroll", + "td_wait", + "td_screenshot", + "td_execute_script", + "td_network_inspect", + "td_console_read", + "td_workflow_save", + "td_workflow_get", + "td_workflow_list", + "td_workflow_update", + "td_workflow_delete", + "td_workflow_validate", + "td_workflow_run", + "td_workflow_runs", + "td_workflow_replay", + "td_target_memory_save", + "td_target_memory_get", + "td_target_memory_list", + "td_target_memory_delete", + "list_tabs", + "focus_tab", + "reload_tab", + "close_tab", + "open_tab", + "inspect_live_page", + "inspect_live_element" + ], + // Forensics profile: historical forensics + diffs + causality + live inspection (~50 tools) + forensics: [ + "list_sessions", + "get_session", + "export_session", + "import_session", + "delete_session", + "get_timeline", + "get_events", + "get_events_around", + "get_dom_state", + "get_dom_node", + "get_dom_subtree", + "diff_dom", + "trace_element", + "find_disappearing_elements", + "why_did_element_disappear", + "get_diagnostics", + "get_network_events", + "get_screenshots", + "td_browser_navigate", + "td_dom_inspect", + "td_dom_query", + "td_dom_extract", + "td_screenshot", + "td_action_click", + "td_action_type", + "td_workflow_run", + "list_tabs", + "focus_tab" + ], + // Full profile: all 350 tools (null means no filtering) + full: null +}; const MCPDOM_V3_TOOLS = [ // ================================================================== // Targeting & forensics @@ -18593,7 +18745,8 @@ class ForensicsToolsHandler { try { const res = await unifiedRuntime.bridgeCommand("LIVE_DOM_SNAPSHOT", { format: "json" }); return { snapshot: res }; - } catch { + } catch (err) { + console.warn(`[ForensicsHandler] Could not capture live snapshot: ${err?.message || err}`); return { snapshot: null }; } } @@ -18602,7 +18755,8 @@ async function runInPageSafe(code, tabId) { try { const { runInPage: runInPage2 } = await Promise.resolve().then(() => interactionCore); return await runInPage2(code, tabId); - } catch { + } catch (err) { + console.warn(`[ForensicsHandler] runInPageSafe failed for tab ${tabId}: ${err?.message || err}`); return null; } } @@ -22506,14 +22660,20 @@ class AgentStore { readJson(file) { try { return JSON.parse(fs.readFileSync(file, "utf-8")); - } catch { + } catch (err) { + if (err?.code !== "ENOENT") { + console.warn(`[WorkflowStore] Warning: Failed to read or parse ${file}:`, err?.message || err); + } return null; } } listJsonNames(dir) { try { return fs.readdirSync(dir).filter((f) => f.endsWith(".json")).sort(); - } catch { + } catch (err) { + if (err?.code !== "ENOENT") { + console.warn(`[WorkflowStore] Warning: Failed to list directory ${dir}:`, err?.message || err); + } return []; } } @@ -25415,12 +25575,14 @@ class MCPBridgeServer { if (targets.length === 0) { for (const [sock, meta] of this.socketMetadata.entries()) { if (meta.clientType === "CONTENT_SCRIPT" && sock.readyState === WebSocket.OPEN) { - targets.push(sock); + targets = [sock]; + break; } } } - if (targets.length === 0) { - targets = Array.from(this.activeSockets); + if (targets.length === 0 && this.activeSockets.size > 0) { + const first = Array.from(this.activeSockets).find((s) => s.readyState === WebSocket.OPEN); + if (first) targets = [first]; } let sentCount = 0; for (const ws of targets) { @@ -25443,17 +25605,53 @@ class MCPBridgeServer { } start() { return new Promise((resolve, reject) => { + const isTrustedOrigin = (origin) => { + if (!origin) return true; + if (origin.startsWith("chrome-extension://")) return true; + if (/^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/.test(origin)) return true; + return false; + }; this.httpServer = http.createServer(async (req, res) => { - res.setHeader("Access-Control-Allow-Origin", "*"); + const origin = req.headers.origin; + if (origin) { + if (isTrustedOrigin(origin)) { + res.setHeader("Access-Control-Allow-Origin", origin); + res.setHeader("Access-Control-Allow-Credentials", "true"); + res.setHeader("Vary", "Origin"); + } else if (req.method === "OPTIONS") { + res.writeHead(403, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ error: "CORS Forbidden: Untrusted cross-origin request rejected" })); + return; + } + } res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); - res.setHeader("Access-Control-Allow-Headers", "Content-Type"); + res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, x-teledom-token"); if (req.method === "OPTIONS") { res.writeHead(204); res.end(); return; } const url = req.url || ""; - if (url === "/health" && req.method === "GET") { + const isAuthValid = () => { + if (!isTrustedOrigin(origin)) return false; + const expectedToken = process.env.TELEDOM_BRIDGE_TOKEN; + if (!expectedToken) return true; + const authHeader = req.headers.authorization; + const tokenHeader = req.headers["x-teledom-token"]; + let queryToken = null; + try { + const parsed = new URL(url, "http://127.0.0.1"); + queryToken = parsed.searchParams.get("token"); + } catch { + } + if (authHeader && authHeader.startsWith("Bearer ")) { + return authHeader.slice(7).trim() === expectedToken; + } + if (tokenHeader && tokenHeader === expectedToken) return true; + if (queryToken && queryToken === expectedToken) return true; + return false; + }; + if (url.startsWith("/health") && req.method === "GET") { res.writeHead(200, { "Content-Type": "application/json" }); res.end( JSON.stringify({ @@ -25465,6 +25663,13 @@ class MCPBridgeServer { ); return; } + if (["/api/mcp/tool", "/api/tabs/close", "/api/sessions/upload"].some((p) => url.startsWith(p))) { + if (!isAuthValid()) { + res.writeHead(403, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ error: "Forbidden: Invalid or missing authorization credentials" })); + return; + } + } const MAX_PAYLOAD_BYTES = 50 * 1024 * 1024; if (url === "/api/sessions/upload" && req.method === "POST") { let body = ""; @@ -25583,7 +25788,13 @@ class MCPBridgeServer { } }, 3e4); this.healthSweepInterval?.unref?.(); - this.wss.on("connection", (ws) => { + this.wss.on("connection", (ws, req) => { + const origin = req?.headers?.origin; + if (origin && !isTrustedOrigin(origin)) { + console.error(`[MCP Bridge] WebSocket connection rejected from untrusted origin: ${origin}`); + ws.close(4403, "Forbidden origin"); + return; + } this.activeSockets.add(ws); console.error(`[MCP Bridge] Client connected. Total active clients: ${this.activeSockets.size}`); ws.on("close", () => { @@ -25711,8 +25922,10 @@ export { FORENSICS_TOOLS as F, MCPDOM_V3_TOOLS as M, MCPBridgeServer, + PNGBuilder as P, TELEDOM_INTELLIGENCE_TOOLS as T, TELEDOM_VERSION as a, FileStorageProvider as b, - MCPToolsHandler as c + MCPToolsHandler as c, + TELEDOM_PROFILE_TOOLS as d }; diff --git a/chrome-extension/dist/server/mcp-server.js b/chrome-extension/dist/server/mcp-server.js index bf9f2d9e..4f33d5fa 100644 --- a/chrome-extension/dist/server/mcp-server.js +++ b/chrome-extension/dist/server/mcp-server.js @@ -1,6 +1,7 @@ import * as readline from "readline"; import * as fs from "fs"; -import { M as MCPDOM_V3_TOOLS, D as DEVTOOLS_TOOLS, F as FORENSICS_TOOLS, T as TELEDOM_INTELLIGENCE_TOOLS, a as TELEDOM_VERSION, b as FileStorageProvider, c as MCPToolsHandler, MCPBridgeServer } from "./bridge-server.js"; +import { M as MCPDOM_V3_TOOLS, D as DEVTOOLS_TOOLS, F as FORENSICS_TOOLS, T as TELEDOM_INTELLIGENCE_TOOLS, a as TELEDOM_VERSION, b as FileStorageProvider, c as MCPToolsHandler, MCPBridgeServer, d as TELEDOM_PROFILE_TOOLS } from "./bridge-server.js"; +import { P } from "./bridge-server.js"; import "http"; import "ws"; import "path"; @@ -872,9 +873,15 @@ class ForensicMCPServer { const disableDevTools = process.env.FORENSIC_DISABLE_DEVTOOLS === "true"; const disableForensics = process.env.FORENSIC_DISABLE_FORENSICS === "true"; const disableIntelligence = process.env.FORENSIC_DISABLE_INTELLIGENCE === "true"; - const tools = FORENSIC_MCP_TOOLS.filter( + const profile = (process.env.TELEDOM_PROFILE || "full").toLowerCase(); + const profileAllowed = TELEDOM_PROFILE_TOOLS[profile]; + let tools = FORENSIC_MCP_TOOLS.filter( (t) => !(disableDevTools && t.name.startsWith("dt_")) && !(disableForensics && t.name.startsWith("fx_")) && !(disableIntelligence && t.name.startsWith("td_")) ); + if (profileAllowed && Array.isArray(profileAllowed)) { + const allowedSet = new Set(profileAllowed); + tools = tools.filter((t) => allowedSet.has(t.name)); + } return { jsonrpc: "2.0", id, @@ -1077,5 +1084,7 @@ export { FORENSIC_MCP_TOOLS, FileStorageProvider, ForensicMCPServer, - MCPToolsHandler + MCPToolsHandler, + P as PNGBuilder, + TELEDOM_PROFILE_TOOLS }; diff --git a/chrome-extension/dist/src/extension/devtools/devtools.html b/chrome-extension/dist/src/extension/devtools/devtools.html index e5ead51c..ec623abe 100644 --- a/chrome-extension/dist/src/extension/devtools/devtools.html +++ b/chrome-extension/dist/src/extension/devtools/devtools.html @@ -1,10 +1,10 @@ - - - - + + + + - - - - + + + + diff --git a/chrome-extension/dist/src/extension/popup/popup.html b/chrome-extension/dist/src/extension/popup/popup.html index 9f991f9c..6b4f597e 100644 --- a/chrome-extension/dist/src/extension/popup/popup.html +++ b/chrome-extension/dist/src/extension/popup/popup.html @@ -1,54 +1,54 @@ - - - - - Forensic Recorder + + + + + Forensic Recorder - - - - - + + + + + diff --git a/chrome-extension/dist/src/ui/index.html b/chrome-extension/dist/src/ui/index.html index e82ee8a9..0412e036 100644 --- a/chrome-extension/dist/src/ui/index.html +++ b/chrome-extension/dist/src/ui/index.html @@ -1,243 +1,243 @@ - - - - - - Browser Forensic Recorder & Time-Travel Debugger + + + + + + Browser Forensic Recorder & Time-Travel Debugger - - - -
-
-
-
- Browser Forensic Debugger - v2.0 MCP -
-
- -
-
- - -
-
- -
- - - - - - - -
-
- - -
- -
-
-
- T: 0.0ms | URL: - -
-
-
-
- - -
- - -
- -
-
-
-
Load or record a session to inspect DOM.
-
-
-
Select an element from the DOM tree or replay viewport.
-
-
-
- - -
-
-
- - - - - - -
-
-
-
Select timestamps and click Compare States.
-
-
-
- - -
-
-
-

Disappearing UI Forensic Diagnosis

-
- - -
-
-
-
Enter a CSS selector or node ID to run root-cause diagnosis.
-
-
-
- - -
-
-
No console or error events recorded.
-
-
- - -
-
-
No network events recorded.
-
-
- - -
-
-
- - -
-
-
-
- - -
-
-
-
-
⚡ Agent-Owned Workflows
-
TeleDOM stores and executes; the agent designs and repairs. Teach once · Reuse forever · Prove what happened.
-
- -
-
-
Recent Runs
-
-
-
-
-
-
- - -
-
-
- - - - - -
- -
- 0.0ms - / 0.0ms -
- -
- - -
-
- -
-
-
-
-
DOM Mut
-
-
-
-
User Act
-
-
-
-
Errors
-
-
-
-
Network
-
-
-
-
- - - - - - - - + + + +
+
+
+
+ Browser Forensic Debugger + v2.0 MCP +
+
+ +
+
+ + +
+
+ +
+ + + + + + + +
+
+ + +
+ +
+
+
+ T: 0.0ms | URL: - +
+
+
+
+ + +
+ + +
+ +
+
+
+
Load or record a session to inspect DOM.
+
+
+
Select an element from the DOM tree or replay viewport.
+
+
+
+ + +
+
+
+ + + + + + +
+
+
+
Select timestamps and click Compare States.
+
+
+
+ + +
+
+
+

Disappearing UI Forensic Diagnosis

+
+ + +
+
+
+
Enter a CSS selector or node ID to run root-cause diagnosis.
+
+
+
+ + +
+
+
No console or error events recorded.
+
+
+ + +
+
+
No network events recorded.
+
+
+ + +
+
+
+ + +
+
+
+
+ + +
+
+
+
+
⚡ Agent-Owned Workflows
+
TeleDOM stores and executes; the agent designs and repairs. Teach once · Reuse forever · Prove what happened.
+
+ +
+
+
Recent Runs
+
+
+
+
+
+
+ + +
+
+
+ + + + + +
+ +
+ 0.0ms + / 0.0ms +
+ +
+ + +
+
+ +
+
+
+
+
DOM Mut
+
+
+
+
User Act
+
+
+
+
Errors
+
+
+
+
Network
+
+
+
+
+ + + + + + + + diff --git a/chrome-extension/manifest.json b/chrome-extension/manifest.json index 63066493..5c230ce8 100644 --- a/chrome-extension/manifest.json +++ b/chrome-extension/manifest.json @@ -16,7 +16,8 @@ "tabs", "webNavigation", "management", - "debugger" + "debugger", + "alarms" ], "host_permissions": [ "" diff --git a/dist/extension/content-script.js b/dist/extension/content-script.js index 85ef3552..faa564d3 100644 --- a/dist/extension/content-script.js +++ b/dist/extension/content-script.js @@ -1,10 +1,10 @@ -var Bt=Object.defineProperty;var Ft=(U,z,Y)=>z in U?Bt(U,z,{enumerable:!0,configurable:!0,writable:!0,value:Y}):U[z]=Y;var f=(U,z,Y)=>Ft(U,typeof z!="symbol"?z+"":z,Y);(function(){"use strict";var U=(l=>(l[l.ELEMENT_NODE=1]="ELEMENT_NODE",l[l.ATTRIBUTE_NODE=2]="ATTRIBUTE_NODE",l[l.TEXT_NODE=3]="TEXT_NODE",l[l.CDATA_SECTION_NODE=4]="CDATA_SECTION_NODE",l[l.PROCESSING_INSTRUCTION_NODE=7]="PROCESSING_INSTRUCTION_NODE",l[l.COMMENT_NODE=8]="COMMENT_NODE",l[l.DOCUMENT_NODE=9]="DOCUMENT_NODE",l[l.DOCUMENT_TYPE_NODE=10]="DOCUMENT_TYPE_NODE",l[l.DOCUMENT_FRAGMENT_NODE=11]="DOCUMENT_FRAGMENT_NODE",l))(U||{});class z{constructor(){f(this,"nextId",1);f(this,"nodeToIdMap",new WeakMap);f(this,"idToNodeMap",new Map);f(this,"identities",new Map);f(this,"parentHistory",new Map)}getOrCreateId(e,t=0){if(this.nodeToIdMap.has(e))return this.nodeToIdMap.get(e);const s=this.nextId++;this.nodeToIdMap.set(e,s),this.idToNodeMap.set(s,e);const i=e.nodeType===U.ELEMENT_NODE||e.nodeType===1?e:null,r=i&&i.tagName?i.tagName.toLowerCase():void 0,o=r?r.includes("-"):!1,a={id:s,nodeType:e.nodeType,tagName:r,createdAt:t,initialSelectorHint:i?this.computeSelector(i):void 0,isCustomElement:o};return this.identities.set(s,a),s}getId(e){return this.nodeToIdMap.get(e)}getNode(e){return this.idToNodeMap.get(e)}getIdentity(e){return this.identities.get(e)}recordParent(e,t){if(!t)return;const s=this.parentHistory.get(e)||[];s[s.length-1]!==t&&(s.push(t),this.parentHistory.set(e,s))}getParentHistory(e){return this.parentHistory.get(e)||[]}computeSelector(e){try{const t=typeof e.id=="string"?e.id:e.getAttribute?e.getAttribute("id"):"";if(t&&/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(t))return`#${t}`;const s=e.tagName?e.tagName.toLowerCase():"element";if(s==="body"||s==="html"||s==="head")return s;let n=[];e.classList&&typeof e.classList.forEach=="function"?n=Array.from(e.classList):typeof e.className=="string"?n=e.className.split(/\s+/):e.className&&typeof e.className.baseVal=="string"&&(n=e.className.baseVal.split(/\s+/));let i="";if(n.length>0){const r=n.filter(o=>typeof o=="string"&&/^[a-zA-Z0-9_-]+$/.test(o)&&!o.startsWith("ng-")&&!o.startsWith("_ng")).slice(0,3);r.length>0&&(i="."+r.join("."))}if(e.parentElement&&e.parentElement.children){const r=Array.from(e.parentElement.children).filter(o=>o.tagName&&o.tagName.toLowerCase()===s);if(r.length>1){const o=r.indexOf(e)+1;if(o>0)return`${s}${i}:nth-of-type(${o})`}}return`${s}${i}`}catch{return e.tagName?e.tagName.toLowerCase():"element"}}computeFullSelectorPath(e){const t=[];let s=e;for(;s&&s.tagName&&s.tagName.toLowerCase()!=="html";){const n=this.computeSelector(s);if(t.unshift(n),s.id&&/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(s.id))break;s=s.parentElement}return t.join(" > ")}removeNode(e){this.idToNodeMap.get(e)&&this.idToNodeMap.delete(e)}reset(){this.nextId=1,this.nodeToIdMap=new WeakMap,this.idToNodeMap.clear(),this.identities.clear(),this.parentHistory.clear()}}const Y={maskAllInputs:!1,maskInputTypes:["password","hidden","tel","email"],maskSelectors:["[data-private]",".private-data",".sensitive",'[data-testid="sensitive"]'],blockSelectors:[".recording-blocked","[data-recording-ignore]"],redactHeaders:["authorization","cookie","set-cookie","x-api-key","proxy-authorization","token"],redactQueryParams:["token","key","auth","secret","password","access_token","apiKey","bearer"],maxTextLength:1e5};class se{constructor(e={}){f(this,"config");this.config={...Y,...e}}shouldBlockNode(e){if(!e||!e.matches)return!1;for(const t of this.config.blockSelectors)try{if(e.matches(t)||e.closest(t))return!0}catch{}return!1}shouldMaskText(e){if(!e||!e.matches)return!1;for(const t of this.config.maskSelectors)try{if(e.matches(t)||e.closest(t))return!0}catch{}return!1}maskValue(e,t,s){return e&&(this.config.maskAllInputs?"*".repeat(Math.min(e.length,12)):t&&this.config.maskInputTypes.includes(t.toLowerCase())||s&&/(password|token|secret|cvv|credit|auth|ssn)/i.test(s)?"••••••••":e)}sanitizeText(e,t=!1){return e&&(t?e.replace(/[^\s\n\r\t]/g,"*"):e.length>this.config.maxTextLength?e.substring(0,this.config.maxTextLength)+"... [TRUNCATED]":e)}sanitizeHeaders(e){if(!e)return;const t={};for(const[s,n]of Object.entries(e)){const i=s.toLowerCase();this.config.redactHeaders.some(r=>i.includes(r))?t[s]="[REDACTED]":t[s]=n}return t}sanitizeUrl(e){try{const t=new URL(e);for(const s of this.config.redactQueryParams)t.searchParams.has(s)&&t.searchParams.set(s,"[REDACTED]");return t.toString()}catch{return e}}}class oe{constructor(){f(this,"currentSequence",0);f(this,"sessionStartTime");f(this,"sessionStartWallClock");this.sessionStartTime=typeof performance<"u"?performance.now():0,this.sessionStartWallClock=Date.now()}nextSequence(){return this.currentSequence+=1,this.currentSequence}getSequence(){return this.currentSequence}getRelativeTimestamp(){return typeof performance<"u"?Math.round((performance.now()-this.sessionStartTime)*100)/100:Date.now()-this.sessionStartWallClock}getWallClock(){return Date.now()}generateEventId(e="evt",t){const s=t!==void 0?t:this.nextSequence(),n=Math.random().toString(36).substring(2,8);return`${e}_${s}_${n}`}reset(){this.currentSequence=0,this.sessionStartTime=typeof performance<"u"?performance.now():0,this.sessionStartWallClock=Date.now()}}class me{constructor(e,t,s){f(this,"registry");f(this,"privacy");f(this,"sequenceCounter");this.registry=e,this.privacy=t,this.sequenceCounter=s}captureSnapshot(e=document,t=""){const s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.nextSequence(),i={},r=e.documentElement||e.body,o=this.registry.getOrCreateId(e,s);if(i[o]={id:o,nodeType:U.DOCUMENT_NODE,tagName:"#document",children:[],parentId:null},e.doctype){const c=this.registry.getOrCreateId(e.doctype,s);i[c]={id:c,nodeType:U.DOCUMENT_TYPE_NODE,tagName:e.doctype.name||"html",parentId:o},i[o].children.push(c)}if(r){const c=this.serializeNode(r,o,i,s);c&&i[o].children.push(c)}const a=this.getViewportInfo();return{snapshotId:`snap_${n}_${Date.now()}`,sessionId:t,timestamp:s,sequence:n,rootId:o,nodes:i,title:e.title||"",url:typeof window<"u"?window.location.href:"",origin:typeof window<"u"?window.location.origin:"",viewport:a,doctype:e.doctype?e.doctype.name:void 0,totalNodeCount:Object.keys(i).length}}serializeNode(e,t,s,n){if(!e||e.nodeType===Node.ELEMENT_NODE&&this.privacy.shouldBlockNode(e))return null;const i=this.registry.getOrCreateId(e,n);this.registry.recordParent(i,t);const r={id:i,nodeType:e.nodeType,parentId:t};if(e.nodeType===Node.ELEMENT_NODE){const o=e;r.tagName=o.tagName.toLowerCase(),r.isCustomElement=r.tagName.includes("-"),r.namespaceURI=o.namespaceURI;const a={};if(o.attributes)for(let c=0;c"u"?{width:1920,height:1080,scrollX:0,scrollY:0,devicePixelRatio:1}:{width:window.innerWidth||((e=document.documentElement)==null?void 0:e.clientWidth)||1920,height:window.innerHeight||((t=document.documentElement)==null?void 0:t.clientHeight)||1080,scrollX:window.scrollX||window.pageXOffset||0,scrollY:window.scrollY||window.pageYOffset||0,devicePixelRatio:window.devicePixelRatio||1}}}class Re{constructor(e,t,s,n,i,r=""){f(this,"observer",null);f(this,"registry");f(this,"privacy");f(this,"sequenceCounter");f(this,"snapshotEngine");f(this,"callback");f(this,"sessionId");f(this,"isObserving",!1);this.registry=e,this.privacy=t,this.sequenceCounter=s,this.snapshotEngine=n,this.callback=i,this.sessionId=r}setSessionId(e){this.sessionId=e}start(e=document){this.isObserving||typeof MutationObserver>"u"||(this.observer=new MutationObserver(this.handleMutations.bind(this)),this.observer.observe(e,{childList:!0,attributes:!0,characterData:!0,subtree:!0,attributeOldValue:!0,characterDataOldValue:!0}),this.isObserving=!0)}stop(){this.observer&&(this.observer.disconnect(),this.observer=null),this.isObserving=!1}takeRecords(){if(this.observer){const e=this.observer.takeRecords();e.length>0&&this.handleMutations(e)}}handleMutations(e){const t=this.sequenceCounter.getRelativeTimestamp(),s=this.sequenceCounter.getWallClock();for(let n=0;n0)for(let o=0;o0)for(let o=0;o"u"||typeof document>"u"||(this.isListening=!0,this.cleanups=[],this.attachUserEventListeners(),this.attachNavigationListeners(),this.attachViewportListeners())}stop(){this.cleanups.forEach(e=>{try{e()}catch{}}),this.cleanups=[],this.isListening=!1}attachUserEventListeners(){[{type:"click",handler:t=>this.handlePointerEvent(t,"USER_CLICK"),options:{capture:!0,passive:!0}},{type:"dblclick",handler:t=>this.handlePointerEvent(t,"USER_DBLCLICK"),options:{capture:!0,passive:!0}},{type:"input",handler:t=>this.handleInputEvent(t),options:{capture:!0,passive:!0}},{type:"change",handler:t=>this.handleInputEvent(t,"USER_CHANGE"),options:{capture:!0,passive:!0}},{type:"submit",handler:t=>this.handleSubmitEvent(t),options:{capture:!0,passive:!0}},{type:"keydown",handler:t=>this.handleKeyboardEvent(t,"USER_KEYDOWN"),options:{capture:!0,passive:!0}},{type:"keyup",handler:t=>this.handleKeyboardEvent(t,"USER_KEYUP"),options:{capture:!0,passive:!0}},{type:"focus",handler:t=>this.handleFocusBlurEvent(t,"USER_FOCUS"),options:{capture:!0,passive:!0}},{type:"blur",handler:t=>this.handleFocusBlurEvent(t,"USER_BLUR"),options:{capture:!0,passive:!0}}].forEach(({type:t,handler:s,options:n})=>{document.addEventListener(t,s,n),this.cleanups.push(()=>document.removeEventListener(t,s,n))})}handlePointerEvent(e,t){const s=e,n=e.target,i=this.sequenceCounter.getRelativeTimestamp(),r=this.sequenceCounter.getWallClock(),o=n?this.registry.getOrCreateId(n,i):void 0,a=n&&n.nodeType===Node.ELEMENT_NODE?this.registry.computeSelector(n):void 0,c=this.sequenceCounter.nextSequence(),u={id:this.sequenceCounter.generateEventId("usr_clk",c),sessionId:this.sessionId,timestamp:i,sequence:c,wallClockTime:r,type:t,category:"USER",source:"USER_INTERACTION",targetNodeId:o,targetSelector:a,payload:{eventType:e.type,targetNodeId:o,targetSelector:a,clientX:s.clientX,clientY:s.clientY,button:s.button,isTrusted:e.isTrusted}};this.callback(u)}handleInputEvent(e,t="USER_INPUT"){const s=e.target;if(!s)return;const n=this.sequenceCounter.getRelativeTimestamp(),i=this.sequenceCounter.getWallClock(),r=this.registry.getOrCreateId(s,n),o=this.registry.computeSelector(s);let a="";if(s.tagName.toLowerCase()==="input"){const d=s;a=this.privacy.maskValue(d.value,d.type,d.name)}else if(s.tagName.toLowerCase()==="textarea"){const d=s;a=this.privacy.maskValue(d.value,"textarea",d.name)}else s.tagName.toLowerCase()==="select"&&(a=s.value);const c=this.sequenceCounter.nextSequence(),u={id:this.sequenceCounter.generateEventId("usr_inp",c),sessionId:this.sessionId,timestamp:n,sequence:c,wallClockTime:i,type:t,category:"USER",source:"USER_INTERACTION",targetNodeId:r,targetSelector:o,payload:{eventType:e.type,targetNodeId:r,targetSelector:o,inputValue:a,isTrusted:e.isTrusted}};this.callback(u)}handleSubmitEvent(e){const t=e.target,s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.getWallClock(),i=t?this.registry.getOrCreateId(t,s):void 0,r=t?this.registry.computeSelector(t):void 0,o=this.sequenceCounter.nextSequence(),a={id:this.sequenceCounter.generateEventId("usr_sub",o),sessionId:this.sessionId,timestamp:s,sequence:o,wallClockTime:n,type:"USER_SUBMIT",category:"USER",source:"USER_INTERACTION",targetNodeId:i,targetSelector:r,payload:{eventType:"submit",targetNodeId:i,targetSelector:r}};this.callback(a)}handleKeyboardEvent(e,t){const s=e.target,n=this.sequenceCounter.getRelativeTimestamp(),i=this.sequenceCounter.getWallClock(),r=s?this.registry.getOrCreateId(s,n):void 0,o=s?this.registry.computeSelector(s):void 0;let a=e.key;s&&s.tagName.toLowerCase()==="input"&&s.type==="password"&&(a="*");const c=this.sequenceCounter.nextSequence(),u={id:this.sequenceCounter.generateEventId("usr_key",c),sessionId:this.sessionId,timestamp:n,sequence:c,wallClockTime:i,type:t,category:"USER",source:"USER_INTERACTION",targetNodeId:r,targetSelector:o,payload:{eventType:e.type,targetNodeId:r,targetSelector:o,key:a,code:e.code,isTrusted:e.isTrusted}};this.callback(u)}handleFocusBlurEvent(e,t){const s=e.target,n=this.sequenceCounter.getRelativeTimestamp(),i=this.sequenceCounter.getWallClock(),r=s?this.registry.getOrCreateId(s,n):void 0,o=s?this.registry.computeSelector(s):void 0,a=this.sequenceCounter.nextSequence(),c={id:this.sequenceCounter.generateEventId("usr_foc",a),sessionId:this.sessionId,timestamp:n,sequence:a,wallClockTime:i,type:t,category:"USER",source:"USER_INTERACTION",targetNodeId:r,targetSelector:o,payload:{eventType:e.type,targetNodeId:r,targetSelector:o}};this.callback(c)}attachNavigationListeners(){if(typeof window>"u"||!window.history)return;const e=window.history.pushState,t=window.history.replaceState;window.history.pushState=(...r)=>{const o=e.apply(window.history,r);return this.recordNavigation("pushState",window.location.href,r[0],r[2]?String(r[2]):void 0),o},window.history.replaceState=(...r)=>{const o=t.apply(window.history,r);return this.recordNavigation("replaceState",window.location.href,r[0],r[2]?String(r[2]):void 0),o};const s=r=>{this.recordNavigation("popstate",window.location.href,r.state)};window.addEventListener("popstate",s);const n=r=>{this.recordNavigation("hashchange",r.newURL,void 0,void 0,r.oldURL)};window.addEventListener("hashchange",n);const i=()=>{this.recordNavigation("visibilitychange",window.location.href,{visibilityState:document.visibilityState,hidden:document.hidden})};document.addEventListener("visibilitychange",i),this.cleanups.push(()=>{window.history.pushState=e,window.history.replaceState=t,window.removeEventListener("popstate",s),window.removeEventListener("hashchange",n),document.removeEventListener("visibilitychange",i)})}recordNavigation(e,t,s,n,i){const r=this.sequenceCounter.getRelativeTimestamp(),o=this.sequenceCounter.getWallClock(),a=this.sequenceCounter.nextSequence(),c={id:this.sequenceCounter.generateEventId("nav",a),sessionId:this.sessionId,timestamp:r,sequence:a,wallClockTime:o,type:`NAV_${e.toUpperCase()}`,category:"NAVIGATION",source:"PAGE",payload:{navigationType:e,url:this.privacy.sanitizeUrl(t),previousUrl:i?this.privacy.sanitizeUrl(i):void 0,state:s,title:n||document.title}};this.callback(c)}attachViewportListeners(){if(typeof window>"u")return;let e=null;const t=()=>{e&&clearTimeout(e),e=setTimeout(()=>{const i=this.sequenceCounter.getRelativeTimestamp(),r=this.sequenceCounter.getWallClock(),o=this.sequenceCounter.nextSequence(),a={id:this.sequenceCounter.generateEventId("vp_res",o),sessionId:this.sessionId,timestamp:i,sequence:o,wallClockTime:r,type:"VIEWPORT_RESIZE",category:"VIEWPORT",source:"BROWSER_RUNTIME",payload:{width:window.innerWidth,height:window.innerHeight,devicePixelRatio:window.devicePixelRatio}};this.callback(a)},100)};window.addEventListener("resize",t,{passive:!0});let s=null;const n=()=>{s&&clearTimeout(s),s=setTimeout(()=>{const i=this.sequenceCounter.getRelativeTimestamp(),r=this.sequenceCounter.getWallClock(),o=this.sequenceCounter.nextSequence(),a={id:this.sequenceCounter.generateEventId("vp_scr",o),sessionId:this.sessionId,timestamp:i,sequence:o,wallClockTime:r,type:"VIEWPORT_SCROLL",category:"VIEWPORT",source:"BROWSER_RUNTIME",payload:{scrollX:window.scrollX,scrollY:window.scrollY}};this.callback(a)},100)};window.addEventListener("scroll",n,{passive:!0}),this.cleanups.push(()=>{e&&clearTimeout(e),s&&clearTimeout(s),window.removeEventListener("resize",t),window.removeEventListener("scroll",n)})}}class ke{constructor(e,t,s,n=""){f(this,"privacy");f(this,"sequenceCounter");f(this,"callback");f(this,"sessionId");f(this,"isInstrumented",!1);f(this,"originalConsole",{});f(this,"originalOnError",null);f(this,"cleanups",[]);this.privacy=e,this.sequenceCounter=t,this.callback=s,this.sessionId=n}setSessionId(e){this.sessionId=e}start(){this.isInstrumented||typeof window>"u"||(this.isInstrumented=!0,this.cleanups=[],this.instrumentConsole(),this.instrumentGlobalErrors(),this.instrumentUnhandledRejections())}stop(){this.cleanups.forEach(e=>{try{e()}catch{}}),this.cleanups=[],this.isInstrumented=!1}instrumentConsole(){if(typeof console>"u")return;["log","warn","error","info","debug"].forEach(t=>{const s=console[t];s&&(this.originalConsole[t]=s,console[t]=(...n)=>{try{this.recordConsole(t,n)}catch{}return s.apply(console,n)},this.cleanups.push(()=>{console[t]=s}))})}recordConsole(e,t){const s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.getWallClock(),i=this.sequenceCounter.nextSequence(),r=t.map(u=>{const d=typeof u;let h="";try{u instanceof Error?h=`${u.name}: ${u.message} -${u.stack||""}`:d==="object"&&u!==null?h=JSON.stringify(u,(p,y)=>typeof y=="function"?"[Function]":y):h=String(u)}catch{h="[Unserializable Object]"}return{type:d,value:this.privacy.sanitizeText(h)}}),o=r.map(u=>u.value).join(" ");let a;try{const u=new Error().stack;u&&(a=u.split(` +var Ft=Object.defineProperty;var Vt=($,H,W)=>H in $?Ft($,H,{enumerable:!0,configurable:!0,writable:!0,value:W}):$[H]=W;var b=($,H,W)=>Vt($,typeof H!="symbol"?H+"":H,W);(function(){"use strict";var $=(l=>(l[l.ELEMENT_NODE=1]="ELEMENT_NODE",l[l.ATTRIBUTE_NODE=2]="ATTRIBUTE_NODE",l[l.TEXT_NODE=3]="TEXT_NODE",l[l.CDATA_SECTION_NODE=4]="CDATA_SECTION_NODE",l[l.PROCESSING_INSTRUCTION_NODE=7]="PROCESSING_INSTRUCTION_NODE",l[l.COMMENT_NODE=8]="COMMENT_NODE",l[l.DOCUMENT_NODE=9]="DOCUMENT_NODE",l[l.DOCUMENT_TYPE_NODE=10]="DOCUMENT_TYPE_NODE",l[l.DOCUMENT_FRAGMENT_NODE=11]="DOCUMENT_FRAGMENT_NODE",l))($||{});class H{constructor(){b(this,"nextId",1);b(this,"nodeToIdMap",new WeakMap);b(this,"idToNodeMap",new Map);b(this,"identities",new Map);b(this,"parentHistory",new Map)}getOrCreateId(e,t=0){if(this.nodeToIdMap.has(e))return this.nodeToIdMap.get(e);const s=this.nextId++;this.nodeToIdMap.set(e,s),this.idToNodeMap.set(s,e);const i=e.nodeType===$.ELEMENT_NODE||e.nodeType===1?e:null,r=i&&i.tagName?i.tagName.toLowerCase():void 0,o=r?r.includes("-"):!1,a={id:s,nodeType:e.nodeType,tagName:r,createdAt:t,initialSelectorHint:i?this.computeSelector(i):void 0,isCustomElement:o};return this.identities.set(s,a),s}getId(e){return this.nodeToIdMap.get(e)}getNode(e){return this.idToNodeMap.get(e)}getIdentity(e){return this.identities.get(e)}recordParent(e,t){if(!t)return;const s=this.parentHistory.get(e)||[];s[s.length-1]!==t&&(s.push(t),this.parentHistory.set(e,s))}getParentHistory(e){return this.parentHistory.get(e)||[]}computeSelector(e){try{const t=typeof e.id=="string"?e.id:e.getAttribute?e.getAttribute("id"):"";if(t&&/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(t))return`#${t}`;const s=e.tagName?e.tagName.toLowerCase():"element";if(s==="body"||s==="html"||s==="head")return s;let n=[];e.classList&&typeof e.classList.forEach=="function"?n=Array.from(e.classList):typeof e.className=="string"?n=e.className.split(/\s+/):e.className&&typeof e.className.baseVal=="string"&&(n=e.className.baseVal.split(/\s+/));let i="";if(n.length>0){const r=n.filter(o=>typeof o=="string"&&/^[a-zA-Z0-9_-]+$/.test(o)&&!o.startsWith("ng-")&&!o.startsWith("_ng")).slice(0,3);r.length>0&&(i="."+r.join("."))}if(e.parentElement&&e.parentElement.children){const r=Array.from(e.parentElement.children).filter(o=>o.tagName&&o.tagName.toLowerCase()===s);if(r.length>1){const o=r.indexOf(e)+1;if(o>0)return`${s}${i}:nth-of-type(${o})`}}return`${s}${i}`}catch{return e.tagName?e.tagName.toLowerCase():"element"}}computeFullSelectorPath(e){const t=[];let s=e;for(;s&&s.tagName&&s.tagName.toLowerCase()!=="html";){const n=this.computeSelector(s);if(t.unshift(n),s.id&&/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(s.id))break;s=s.parentElement}return t.join(" > ")}removeNode(e){this.idToNodeMap.get(e)&&this.idToNodeMap.delete(e)}reset(){this.nextId=1,this.nodeToIdMap=new WeakMap,this.idToNodeMap.clear(),this.identities.clear(),this.parentHistory.clear()}}const W={maskAllInputs:!1,maskInputTypes:["password","hidden","tel","email"],maskSelectors:["[data-private]",".private-data",".sensitive",'[data-testid="sensitive"]'],blockSelectors:[".recording-blocked","[data-recording-ignore]"],redactHeaders:["authorization","cookie","set-cookie","x-api-key","proxy-authorization","token"],redactQueryParams:["token","key","auth","secret","password","access_token","apiKey","bearer"],maxTextLength:1e5};class J{constructor(e={}){b(this,"config");this.config={...W,...e}}shouldBlockNode(e){if(!e||!e.matches)return!1;for(const t of this.config.blockSelectors)try{if(e.matches(t)||e.closest(t))return!0}catch{}return!1}shouldMaskText(e){if(!e||!e.matches)return!1;for(const t of this.config.maskSelectors)try{if(e.matches(t)||e.closest(t))return!0}catch{}return!1}maskValue(e,t,s){return e&&(this.config.maskAllInputs?"*".repeat(Math.min(e.length,12)):t&&this.config.maskInputTypes.includes(t.toLowerCase())||s&&/(password|token|secret|cvv|credit|auth|ssn)/i.test(s)?"••••••••":e)}sanitizeText(e,t=!1){return e&&(t?e.replace(/[^\s\n\r\t]/g,"*"):e.length>this.config.maxTextLength?e.substring(0,this.config.maxTextLength)+"... [TRUNCATED]":e)}sanitizeHeaders(e){if(!e)return;const t={};for(const[s,n]of Object.entries(e)){const i=s.toLowerCase();this.config.redactHeaders.some(r=>i.includes(r))?t[s]="[REDACTED]":t[s]=n}return t}sanitizeUrl(e){try{const t=new URL(e);for(const s of this.config.redactQueryParams)t.searchParams.has(s)&&t.searchParams.set(s,"[REDACTED]");return t.toString()}catch{return e}}}class ne{constructor(){b(this,"currentSequence",0);b(this,"sessionStartTime");b(this,"sessionStartWallClock");this.sessionStartTime=typeof performance<"u"?performance.now():0,this.sessionStartWallClock=Date.now()}nextSequence(){return this.currentSequence+=1,this.currentSequence}getSequence(){return this.currentSequence}getRelativeTimestamp(){return typeof performance<"u"?Math.round((performance.now()-this.sessionStartTime)*100)/100:Date.now()-this.sessionStartWallClock}getWallClock(){return Date.now()}generateEventId(e="evt",t){const s=t!==void 0?t:this.nextSequence(),n=Math.random().toString(36).substring(2,8);return`${e}_${s}_${n}`}reset(){this.currentSequence=0,this.sessionStartTime=typeof performance<"u"?performance.now():0,this.sessionStartWallClock=Date.now()}}class he{constructor(e,t,s){b(this,"registry");b(this,"privacy");b(this,"sequenceCounter");this.registry=e,this.privacy=t,this.sequenceCounter=s}captureSnapshot(e=document,t=""){const s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.nextSequence(),i={},r=e.documentElement||e.body,o=this.registry.getOrCreateId(e,s);if(i[o]={id:o,nodeType:$.DOCUMENT_NODE,tagName:"#document",children:[],parentId:null},e.doctype){const c=this.registry.getOrCreateId(e.doctype,s);i[c]={id:c,nodeType:$.DOCUMENT_TYPE_NODE,tagName:e.doctype.name||"html",parentId:o},i[o].children.push(c)}if(r){const c=this.serializeNode(r,o,i,s);c&&i[o].children.push(c)}const a=this.getViewportInfo();return{snapshotId:`snap_${n}_${Date.now()}`,sessionId:t,timestamp:s,sequence:n,rootId:o,nodes:i,title:e.title||"",url:typeof window<"u"?window.location.href:"",origin:typeof window<"u"?window.location.origin:"",viewport:a,doctype:e.doctype?e.doctype.name:void 0,totalNodeCount:Object.keys(i).length}}serializeNode(e,t,s,n){if(!e||e.nodeType===Node.ELEMENT_NODE&&this.privacy.shouldBlockNode(e))return null;const i=this.registry.getOrCreateId(e,n);this.registry.recordParent(i,t);const r={id:i,nodeType:e.nodeType,parentId:t};if(e.nodeType===Node.ELEMENT_NODE){const o=e;r.tagName=o.tagName.toLowerCase(),r.isCustomElement=r.tagName.includes("-"),r.namespaceURI=o.namespaceURI;const a={};if(o.attributes)for(let c=0;c"u"?{width:1920,height:1080,scrollX:0,scrollY:0,devicePixelRatio:1}:{width:window.innerWidth||((e=document.documentElement)==null?void 0:e.clientWidth)||1920,height:window.innerHeight||((t=document.documentElement)==null?void 0:t.clientHeight)||1080,scrollX:window.scrollX||window.pageXOffset||0,scrollY:window.scrollY||window.pageYOffset||0,devicePixelRatio:window.devicePixelRatio||1}}}class Ne{constructor(e,t,s,n,i,r=""){b(this,"observer",null);b(this,"registry");b(this,"privacy");b(this,"sequenceCounter");b(this,"snapshotEngine");b(this,"callback");b(this,"sessionId");b(this,"isObserving",!1);this.registry=e,this.privacy=t,this.sequenceCounter=s,this.snapshotEngine=n,this.callback=i,this.sessionId=r}setSessionId(e){this.sessionId=e}start(e=document){this.isObserving||typeof MutationObserver>"u"||(this.observer=new MutationObserver(this.handleMutations.bind(this)),this.observer.observe(e,{childList:!0,attributes:!0,characterData:!0,subtree:!0,attributeOldValue:!0,characterDataOldValue:!0}),this.isObserving=!0)}stop(){this.observer&&(this.observer.disconnect(),this.observer=null),this.isObserving=!1}takeRecords(){if(this.observer){const e=this.observer.takeRecords();e.length>0&&this.handleMutations(e)}}handleMutations(e){const t=this.sequenceCounter.getRelativeTimestamp(),s=this.sequenceCounter.getWallClock();for(let n=0;n0)for(let o=0;o0)for(let o=0;o"u"||typeof document>"u"||(this.isListening=!0,this.cleanups=[],this.attachUserEventListeners(),this.attachNavigationListeners(),this.attachViewportListeners())}stop(){this.cleanups.forEach(e=>{try{e()}catch{}}),this.cleanups=[],this.isListening=!1}attachUserEventListeners(){[{type:"click",handler:t=>this.handlePointerEvent(t,"USER_CLICK"),options:{capture:!0,passive:!0}},{type:"dblclick",handler:t=>this.handlePointerEvent(t,"USER_DBLCLICK"),options:{capture:!0,passive:!0}},{type:"input",handler:t=>this.handleInputEvent(t),options:{capture:!0,passive:!0}},{type:"change",handler:t=>this.handleInputEvent(t,"USER_CHANGE"),options:{capture:!0,passive:!0}},{type:"submit",handler:t=>this.handleSubmitEvent(t),options:{capture:!0,passive:!0}},{type:"keydown",handler:t=>this.handleKeyboardEvent(t,"USER_KEYDOWN"),options:{capture:!0,passive:!0}},{type:"keyup",handler:t=>this.handleKeyboardEvent(t,"USER_KEYUP"),options:{capture:!0,passive:!0}},{type:"focus",handler:t=>this.handleFocusBlurEvent(t,"USER_FOCUS"),options:{capture:!0,passive:!0}},{type:"blur",handler:t=>this.handleFocusBlurEvent(t,"USER_BLUR"),options:{capture:!0,passive:!0}}].forEach(({type:t,handler:s,options:n})=>{document.addEventListener(t,s,n),this.cleanups.push(()=>document.removeEventListener(t,s,n))})}handlePointerEvent(e,t){const s=e,n=e.target,i=this.sequenceCounter.getRelativeTimestamp(),r=this.sequenceCounter.getWallClock(),o=n?this.registry.getOrCreateId(n,i):void 0,a=n&&n.nodeType===Node.ELEMENT_NODE?this.registry.computeSelector(n):void 0,c=this.sequenceCounter.nextSequence(),u={id:this.sequenceCounter.generateEventId("usr_clk",c),sessionId:this.sessionId,timestamp:i,sequence:c,wallClockTime:r,type:t,category:"USER",source:"USER_INTERACTION",targetNodeId:o,targetSelector:a,payload:{eventType:e.type,targetNodeId:o,targetSelector:a,clientX:s.clientX,clientY:s.clientY,button:s.button,isTrusted:e.isTrusted}};this.callback(u)}handleInputEvent(e,t="USER_INPUT"){const s=e.target;if(!s)return;const n=this.sequenceCounter.getRelativeTimestamp(),i=this.sequenceCounter.getWallClock(),r=this.registry.getOrCreateId(s,n),o=this.registry.computeSelector(s);let a="";if(s.tagName.toLowerCase()==="input"){const h=s;a=this.privacy.maskValue(h.value,h.type,h.name)}else if(s.tagName.toLowerCase()==="textarea"){const h=s;a=this.privacy.maskValue(h.value,"textarea",h.name)}else s.tagName.toLowerCase()==="select"&&(a=s.value);const c=this.sequenceCounter.nextSequence(),u={id:this.sequenceCounter.generateEventId("usr_inp",c),sessionId:this.sessionId,timestamp:n,sequence:c,wallClockTime:i,type:t,category:"USER",source:"USER_INTERACTION",targetNodeId:r,targetSelector:o,payload:{eventType:e.type,targetNodeId:r,targetSelector:o,inputValue:a,isTrusted:e.isTrusted}};this.callback(u)}handleSubmitEvent(e){const t=e.target,s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.getWallClock(),i=t?this.registry.getOrCreateId(t,s):void 0,r=t?this.registry.computeSelector(t):void 0,o=this.sequenceCounter.nextSequence(),a={id:this.sequenceCounter.generateEventId("usr_sub",o),sessionId:this.sessionId,timestamp:s,sequence:o,wallClockTime:n,type:"USER_SUBMIT",category:"USER",source:"USER_INTERACTION",targetNodeId:i,targetSelector:r,payload:{eventType:"submit",targetNodeId:i,targetSelector:r}};this.callback(a)}handleKeyboardEvent(e,t){const s=e.target,n=this.sequenceCounter.getRelativeTimestamp(),i=this.sequenceCounter.getWallClock(),r=s?this.registry.getOrCreateId(s,n):void 0,o=s?this.registry.computeSelector(s):void 0;let a=e.key;s&&s.tagName.toLowerCase()==="input"&&s.type==="password"&&(a="*");const c=this.sequenceCounter.nextSequence(),u={id:this.sequenceCounter.generateEventId("usr_key",c),sessionId:this.sessionId,timestamp:n,sequence:c,wallClockTime:i,type:t,category:"USER",source:"USER_INTERACTION",targetNodeId:r,targetSelector:o,payload:{eventType:e.type,targetNodeId:r,targetSelector:o,key:a,code:e.code,isTrusted:e.isTrusted}};this.callback(u)}handleFocusBlurEvent(e,t){const s=e.target,n=this.sequenceCounter.getRelativeTimestamp(),i=this.sequenceCounter.getWallClock(),r=s?this.registry.getOrCreateId(s,n):void 0,o=s?this.registry.computeSelector(s):void 0,a=this.sequenceCounter.nextSequence(),c={id:this.sequenceCounter.generateEventId("usr_foc",a),sessionId:this.sessionId,timestamp:n,sequence:a,wallClockTime:i,type:t,category:"USER",source:"USER_INTERACTION",targetNodeId:r,targetSelector:o,payload:{eventType:e.type,targetNodeId:r,targetSelector:o}};this.callback(c)}attachNavigationListeners(){if(typeof window>"u"||!window.history)return;const e=window.history.pushState,t=window.history.replaceState;window.history.pushState=(...r)=>{const o=e.apply(window.history,r);return this.recordNavigation("pushState",window.location.href,r[0],r[2]?String(r[2]):void 0),o},window.history.replaceState=(...r)=>{const o=t.apply(window.history,r);return this.recordNavigation("replaceState",window.location.href,r[0],r[2]?String(r[2]):void 0),o};const s=r=>{this.recordNavigation("popstate",window.location.href,r.state)};window.addEventListener("popstate",s);const n=r=>{this.recordNavigation("hashchange",r.newURL,void 0,void 0,r.oldURL)};window.addEventListener("hashchange",n);const i=()=>{this.recordNavigation("visibilitychange",window.location.href,{visibilityState:document.visibilityState,hidden:document.hidden})};document.addEventListener("visibilitychange",i),this.cleanups.push(()=>{window.history.pushState=e,window.history.replaceState=t,window.removeEventListener("popstate",s),window.removeEventListener("hashchange",n),document.removeEventListener("visibilitychange",i)})}recordNavigation(e,t,s,n,i){const r=this.sequenceCounter.getRelativeTimestamp(),o=this.sequenceCounter.getWallClock(),a=this.sequenceCounter.nextSequence(),c={id:this.sequenceCounter.generateEventId("nav",a),sessionId:this.sessionId,timestamp:r,sequence:a,wallClockTime:o,type:`NAV_${e.toUpperCase()}`,category:"NAVIGATION",source:"PAGE",payload:{navigationType:e,url:this.privacy.sanitizeUrl(t),previousUrl:i?this.privacy.sanitizeUrl(i):void 0,state:s,title:n||document.title}};this.callback(c)}attachViewportListeners(){if(typeof window>"u")return;let e=null;const t=()=>{e&&clearTimeout(e),e=setTimeout(()=>{const i=this.sequenceCounter.getRelativeTimestamp(),r=this.sequenceCounter.getWallClock(),o=this.sequenceCounter.nextSequence(),a={id:this.sequenceCounter.generateEventId("vp_res",o),sessionId:this.sessionId,timestamp:i,sequence:o,wallClockTime:r,type:"VIEWPORT_RESIZE",category:"VIEWPORT",source:"BROWSER_RUNTIME",payload:{width:window.innerWidth,height:window.innerHeight,devicePixelRatio:window.devicePixelRatio}};this.callback(a)},100)};window.addEventListener("resize",t,{passive:!0});let s=null;const n=()=>{s&&clearTimeout(s),s=setTimeout(()=>{const i=this.sequenceCounter.getRelativeTimestamp(),r=this.sequenceCounter.getWallClock(),o=this.sequenceCounter.nextSequence(),a={id:this.sequenceCounter.generateEventId("vp_scr",o),sessionId:this.sessionId,timestamp:i,sequence:o,wallClockTime:r,type:"VIEWPORT_SCROLL",category:"VIEWPORT",source:"BROWSER_RUNTIME",payload:{scrollX:window.scrollX,scrollY:window.scrollY}};this.callback(a)},100)};window.addEventListener("scroll",n,{passive:!0}),this.cleanups.push(()=>{e&&clearTimeout(e),s&&clearTimeout(s),window.removeEventListener("resize",t),window.removeEventListener("scroll",n)})}}class Me{constructor(e,t,s,n=""){b(this,"privacy");b(this,"sequenceCounter");b(this,"callback");b(this,"sessionId");b(this,"isInstrumented",!1);b(this,"originalConsole",{});b(this,"originalOnError",null);b(this,"cleanups",[]);this.privacy=e,this.sequenceCounter=t,this.callback=s,this.sessionId=n}setSessionId(e){this.sessionId=e}start(){this.isInstrumented||typeof window>"u"||(this.isInstrumented=!0,this.cleanups=[],this.instrumentConsole(),this.instrumentGlobalErrors(),this.instrumentUnhandledRejections())}stop(){this.cleanups.forEach(e=>{try{e()}catch{}}),this.cleanups=[],this.isInstrumented=!1}instrumentConsole(){if(typeof console>"u")return;["log","warn","error","info","debug"].forEach(t=>{const s=console[t];s&&(this.originalConsole[t]=s,console[t]=(...n)=>{try{this.recordConsole(t,n)}catch{}return s.apply(console,n)},this.cleanups.push(()=>{console[t]=s}))})}recordConsole(e,t){const s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.getWallClock(),i=this.sequenceCounter.nextSequence(),r=t.map(u=>{const h=typeof u;let g="";try{u instanceof Error?g=`${u.name}: ${u.message} +${u.stack||""}`:h==="object"&&u!==null?g=JSON.stringify(u,(p,y)=>typeof y=="function"?"[Function]":y):g=String(u)}catch{g="[Unserializable Object]"}return{type:h,value:this.privacy.sanitizeText(g)}}),o=r.map(u=>u.value).join(" ");let a;try{const u=new Error().stack;u&&(a=u.split(` `).slice(2,8).join(` -`))}catch{}const c={id:this.sequenceCounter.generateEventId("con",i),sessionId:this.sessionId,timestamp:s,sequence:i,wallClockTime:n,type:`RUNTIME_CONSOLE_${e.toUpperCase()}`,category:e==="error"?"ERROR":"CONSOLE",source:"PAGE",payload:{level:e,args:r,formattedMessage:o,stackTrace:a}};this.callback(c)}instrumentGlobalErrors(){if(typeof window>"u")return;const e=t=>{var o,a;const s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.getWallClock(),i=this.sequenceCounter.nextSequence(),r={id:this.sequenceCounter.generateEventId("err",i),sessionId:this.sessionId,timestamp:s,sequence:i,wallClockTime:n,type:"RUNTIME_ERROR",category:"ERROR",source:"PAGE",payload:{message:t.message||"Unknown runtime error",filename:t.filename,lineno:t.lineno,colno:t.colno,stack:((o=t.error)==null?void 0:o.stack)||void 0,name:((a=t.error)==null?void 0:a.name)||"Error"}};this.callback(r)};window.addEventListener("error",e),this.cleanups.push(()=>window.removeEventListener("error",e))}instrumentUnhandledRejections(){if(typeof window>"u")return;const e=t=>{const s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.getWallClock(),i=this.sequenceCounter.nextSequence();let r="Unhandled Promise Rejection",o;if(t.reason instanceof Error)r=t.reason.message,o=t.reason.stack;else if(typeof t.reason=="string")r=t.reason;else if(t.reason)try{r=JSON.stringify(t.reason)}catch{r=String(t.reason)}const a={id:this.sequenceCounter.generateEventId("rej",i),sessionId:this.sessionId,timestamp:s,sequence:i,wallClockTime:n,type:"RUNTIME_UNHANDLED_REJECTION",category:"ERROR",source:"PAGE",payload:{message:r,stack:o,isUnhandledRejection:!0}};this.callback(a)};window.addEventListener("unhandledrejection",e),this.cleanups.push(()=>window.removeEventListener("unhandledrejection",e))}}class Oe{constructor(e,t,s,n=""){f(this,"privacy");f(this,"sequenceCounter");f(this,"callback");f(this,"sessionId");f(this,"isInstrumented",!1);f(this,"originalFetch",null);f(this,"originalXHROpen",null);f(this,"originalXHRSend",null);f(this,"cleanups",[]);this.privacy=e,this.sequenceCounter=t,this.callback=s,this.sessionId=n}setSessionId(e){this.sessionId=e}start(){this.isInstrumented||typeof window>"u"||(this.isInstrumented=!0,this.cleanups=[],this.instrumentFetch(),this.instrumentXHR())}stop(){this.cleanups.forEach(e=>{try{e()}catch{}}),this.cleanups=[],this.isInstrumented=!1}instrumentFetch(){if(typeof window.fetch!="function")return;this.originalFetch=window.fetch;const e=this;window.fetch=async function(...t){const s=e.sequenceCounter.generateEventId("req_f"),n=t[0],i=t[1];let r="";typeof n=="string"?r=n:n instanceof URL?r=n.toString():n&&typeof n=="object"&&"url"in n&&(r=n.url);const o=((i==null?void 0:i.method)||(typeof n=="object"&&"method"in n?n.method:"GET")).toUpperCase(),a=e.privacy.sanitizeUrl(r),c=e.sequenceCounter.getRelativeTimestamp(),u=e.sequenceCounter.getWallClock(),d=e.sequenceCounter.nextSequence(),h={id:s,sessionId:e.sessionId,timestamp:c,sequence:d,wallClockTime:u,type:"NETWORK_REQUEST_START",category:"NETWORK",source:"PAGE",payload:{requestId:s,url:a,method:o,resourceType:"fetch",hasBody:!!(i!=null&&i.body)}};e.callback(h);try{const p=await e.originalFetch.apply(this,t),y=e.sequenceCounter.getRelativeTimestamp(),v=e.sequenceCounter.getWallClock(),m=e.sequenceCounter.nextSequence(),g=Math.max(0,Math.round((y-c)*100)/100),b={id:e.sequenceCounter.generateEventId("res_f",m),sessionId:e.sessionId,timestamp:y,sequence:m,wallClockTime:v,type:"NETWORK_RESPONSE_COMPLETE",category:"NETWORK",source:"PAGE",causality:{triggeredBy:s,precededBy:s},payload:{requestId:s,url:a,method:o,status:p.status,statusText:p.statusText,durationMs:g}};return e.callback(b),p}catch(p){const y=e.sequenceCounter.getRelativeTimestamp(),v=e.sequenceCounter.getWallClock(),m=e.sequenceCounter.nextSequence(),g=Math.max(0,Math.round((y-c)*100)/100),b={id:e.sequenceCounter.generateEventId("res_err",m),sessionId:e.sessionId,timestamp:y,sequence:m,wallClockTime:v,type:"NETWORK_REQUEST_FAILED",category:"NETWORK",source:"PAGE",causality:{triggeredBy:s,precededBy:s},payload:{requestId:s,url:a,method:o,status:0,statusText:"Failed",durationMs:g,error:(p==null?void 0:p.message)||"Network request failed"}};throw e.callback(b),p}},this.cleanups.push(()=>{this.originalFetch&&(window.fetch=this.originalFetch)})}instrumentXHR(){if(typeof XMLHttpRequest>"u")return;this.originalXHROpen=XMLHttpRequest.prototype.open,this.originalXHRSend=XMLHttpRequest.prototype.send;const e=this;XMLHttpRequest.prototype.open=function(t,s,...n){return this._forensicRequestId=e.sequenceCounter.generateEventId("req_x"),this._forensicMethod=(t||"GET").toUpperCase(),this._forensicUrl=typeof s=="string"?s:s.toString(),e.originalXHROpen.apply(this,[t,s,...n])},XMLHttpRequest.prototype.send=function(t){const s=this._forensicRequestId||e.sequenceCounter.generateEventId("req_x"),n=this._forensicMethod||"GET",i=e.privacy.sanitizeUrl(this._forensicUrl||""),r=e.sequenceCounter.getRelativeTimestamp(),o=e.sequenceCounter.getWallClock(),a=e.sequenceCounter.nextSequence();this._forensicStartTime=r;const c={id:s,sessionId:e.sessionId,timestamp:r,sequence:a,wallClockTime:o,type:"NETWORK_REQUEST_START",category:"NETWORK",source:"PAGE",payload:{requestId:s,url:i,method:n,resourceType:"xhr",hasBody:!!t}};e.callback(c);const u=()=>{const d=e.sequenceCounter.getRelativeTimestamp(),h=e.sequenceCounter.getWallClock(),p=e.sequenceCounter.nextSequence(),y=Math.max(0,Math.round((d-(this._forensicStartTime||r))*100)/100),v={id:e.sequenceCounter.generateEventId("res_x",p),sessionId:e.sessionId,timestamp:d,sequence:p,wallClockTime:h,type:this.status>=200&&this.status<400?"NETWORK_RESPONSE_COMPLETE":"NETWORK_REQUEST_FAILED",category:"NETWORK",source:"PAGE",causality:{triggeredBy:s,precededBy:s},payload:{requestId:s,url:i,method:n,status:this.status,statusText:this.statusText,durationMs:y,error:this.status===0?"XHR Network Error or Aborted":void 0}};e.callback(v)};return this.addEventListener("load",u),this.addEventListener("error",u),this.addEventListener("abort",u),e.originalXHRSend.apply(this,[t])},this.cleanups.push(()=>{this.originalXHROpen&&(XMLHttpRequest.prototype.open=this.originalXHROpen),this.originalXHRSend&&(XMLHttpRequest.prototype.send=this.originalXHRSend)})}}class Le{constructor(e={}){f(this,"sequenceCounter");f(this,"registry");f(this,"privacy");f(this,"snapshotEngine");f(this,"mutationObserver");f(this,"eventCollector");f(this,"diagnostics");f(this,"networkMonitor");f(this,"metadata");f(this,"isRecording",!1);f(this,"isPaused",!1);f(this,"eventListeners",new Set);f(this,"checkpointListeners",new Set);f(this,"lastCheckpointSequence",0);f(this,"lastCheckpointTimestamp",0);f(this,"checkpointTimer",null);f(this,"checkpointIntervalEvents",200);f(this,"checkpointIntervalMs",3e4);this.sequenceCounter=new oe,this.registry=new z,this.privacy=new se(e.privacy),this.snapshotEngine=new me(this.registry,this.privacy,this.sequenceCounter);const t=n=>this.handleEvent(n);this.mutationObserver=new Re(this.registry,this.privacy,this.sequenceCounter,this.snapshotEngine,t),this.eventCollector=new Me(this.registry,this.privacy,this.sequenceCounter,t),this.diagnostics=new ke(this.privacy,this.sequenceCounter,t),this.networkMonitor=new Oe(this.privacy,this.sequenceCounter,t),e.checkpointIntervalEvents&&(this.checkpointIntervalEvents=e.checkpointIntervalEvents),e.checkpointIntervalMs&&(this.checkpointIntervalMs=e.checkpointIntervalMs);const s=e.sessionId||`session_${Date.now()}_${Math.random().toString(36).substring(2,7)}`;this.metadata=this.createInitialMetadata(s,e.sessionName)}getSessionId(){return this.metadata.id}getMetadata(){return{...this.metadata,durationMs:this.sequenceCounter.getRelativeTimestamp(),endTime:this.metadata.endTime||Date.now()}}getRegistry(){return this.registry}onEvent(e){return this.eventListeners.add(e),()=>this.eventListeners.delete(e)}onCheckpoint(e){return this.checkpointListeners.add(e),()=>this.checkpointListeners.delete(e)}start(e=typeof document<"u"?document:{}){if(this.isRecording)throw new Error(`Recorder session ${this.metadata.id} is already active`);this.sequenceCounter.reset(),this.registry.reset(),this.isRecording=!0,this.isPaused=!1,this.metadata.status="recording",this.metadata.startTime=Date.now(),this.mutationObserver.setSessionId(this.metadata.id),this.eventCollector.setSessionId(this.metadata.id),this.diagnostics.setSessionId(this.metadata.id),this.networkMonitor.setSessionId(this.metadata.id);const t=this.snapshotEngine.captureSnapshot(e,this.metadata.id);this.metadata.stats.nodeCount=t.totalNodeCount;const s={id:this.sequenceCounter.generateEventId("snap_init",t.sequence),sessionId:this.metadata.id,timestamp:t.timestamp,sequence:t.sequence,wallClockTime:Date.now(),type:"DOM_SNAPSHOT",category:"DOM",source:"PAGE",payload:{snapshot:t}};return this.createCheckpoint(t,"INITIAL"),this.mutationObserver.start(e),this.eventCollector.start(),this.diagnostics.start(),this.networkMonitor.start(),this.handleEvent(s),this.checkpointIntervalMs>0&&typeof setInterval<"u"&&(this.checkpointTimer=setInterval(()=>{this.isRecording&&!this.isPaused&&this.captureCheckpoint("PERIODIC",e)},this.checkpointIntervalMs)),t}stop(){return this.isRecording?(this.mutationObserver.takeRecords(),this.mutationObserver.stop(),this.eventCollector.stop(),this.diagnostics.stop(),this.networkMonitor.stop(),this.checkpointTimer&&(clearInterval(this.checkpointTimer),this.checkpointTimer=null),this.isRecording=!1,this.metadata.status="stopped",this.metadata.endTime=Date.now(),this.metadata.durationMs=this.sequenceCounter.getRelativeTimestamp(),this.getMetadata()):this.getMetadata()}pause(){!this.isRecording||this.isPaused||(this.isPaused=!0,this.metadata.status="paused")}resume(){!this.isRecording||!this.isPaused||(this.isPaused=!1,this.metadata.status="recording")}captureCheckpoint(e="MANUAL",t=document){if(!this.isRecording)return null;const s=this.snapshotEngine.captureSnapshot(t,this.metadata.id);return this.createCheckpoint(s,e)}recordCustomEvent(e,t,s,n){const i=this.sequenceCounter.getRelativeTimestamp(),r=this.sequenceCounter.getWallClock(),o=this.sequenceCounter.nextSequence(),a={id:this.sequenceCounter.generateEventId("ext",o),sessionId:this.metadata.id,timestamp:i,sequence:o,wallClockTime:r,type:e,category:"EXTENSION",source:"CONTENT_SCRIPT",targetNodeId:s,targetSelector:n,payload:t};return this.handleEvent(a),a}recordScreenshot(e,t="MANUAL"){const s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.getWallClock(),i=this.sequenceCounter.nextSequence(),r={id:this.sequenceCounter.generateEventId("scr",i),sessionId:this.metadata.id,timestamp:s,sequence:i,wallClockTime:n,type:"SCREENSHOT_CHECKPOINT",category:"SCREENSHOT",source:"BROWSER_RUNTIME",payload:{screenshotId:`shot_${i}`,dataUrl:e,viewport:{width:typeof window<"u"?window.innerWidth:1920,height:typeof window<"u"?window.innerHeight:1080,scrollX:typeof window<"u"?window.scrollX:0,scrollY:typeof window<"u"?window.scrollY:0,devicePixelRatio:typeof window<"u"?window.devicePixelRatio:1},triggerReason:t}};return this.handleEvent(r),r}addAnnotation(e,t,s="AGENT",n){const i=this.sequenceCounter.getRelativeTimestamp(),r=this.sequenceCounter.nextSequence(),o={id:`ann_${r}_${Math.random().toString(36).substring(2,6)}`,sessionId:this.metadata.id,timestamp:i,sequence:r,nodeId:n,author:s,label:e,comment:t,createdAt:Date.now()},a={id:o.id,sessionId:this.metadata.id,timestamp:i,sequence:r,wallClockTime:Date.now(),type:"ANNOTATION",category:"ANNOTATION",source:s==="USER"?"USER_INTERACTION":"BROWSER_RUNTIME",targetNodeId:n,payload:{annotation:o}};return this.handleEvent(a),o}createCheckpoint(e,t){const s=this.sequenceCounter.getSequence()-this.lastCheckpointSequence;this.lastCheckpointSequence=this.sequenceCounter.getSequence(),this.lastCheckpointTimestamp=e.timestamp,this.metadata.stats.checkpointCount+=1;const n={checkpointId:`chk_${e.sequence}_${Date.now()}`,sessionId:this.metadata.id,timestamp:e.timestamp,sequence:e.sequence,wallClockTime:Date.now(),snapshot:e,eventIndex:this.metadata.stats.eventCount,eventsSinceLastCheckpoint:s,trigger:t},i={id:n.checkpointId,sessionId:this.metadata.id,timestamp:e.timestamp,sequence:e.sequence,wallClockTime:n.wallClockTime,type:"CHECKPOINT",category:"CHECKPOINT",source:"BROWSER_RUNTIME",payload:{checkpointId:n.checkpointId,snapshot:e,eventsSinceLastCheckpoint:s,totalEventsSoFar:this.metadata.stats.eventCount}};return this.checkpointListeners.forEach(r=>{try{r(n)}catch(o){console.error("[ForensicRecorder] Checkpoint listener error:",o)}}),this.handleEvent(i),n}handleEvent(e){this.isPaused&&e.type!=="CHECKPOINT"&&e.type!=="ANNOTATION"||(this.metadata.stats.eventCount+=1,e.category==="DOM"&&(this.metadata.stats.mutationCount+=1),e.category==="ERROR"&&(this.metadata.stats.errorCount+=1),e.category==="CONSOLE"&&(this.metadata.stats.consoleCount+=1),e.category==="NETWORK"&&(this.metadata.stats.networkCount+=1),e.category==="SCREENSHOT"&&(this.metadata.stats.screenshotCount+=1),this.isRecording&&e.type!=="CHECKPOINT"&&e.type!=="DOM_SNAPSHOT"&&this.sequenceCounter.getSequence()-this.lastCheckpointSequence>=this.checkpointIntervalEvents&&typeof document<"u"&&this.captureCheckpoint("PERIODIC"),this.eventListeners.forEach(t=>{try{t(e)}catch(s){console.error("[ForensicRecorder] Event listener error:",s)}}))}createInitialMetadata(e,t){const s={domRecording:typeof MutationObserver<"u"?"HEALTHY":"UNAVAILABLE",userEvents:typeof window<"u"?"HEALTHY":"UNAVAILABLE",console:typeof console<"u"?"HEALTHY":"UNAVAILABLE",network:typeof window<"u"&&typeof window.fetch<"u"?"HEALTHY":"PARTIAL",screenshots:"HEALTHY",shadowDom:typeof Element<"u"&&"attachShadow"in Element.prototype?"HEALTHY":"RESTRICTED",iframes:"PARTIAL"},n={eventCount:0,mutationCount:0,errorCount:0,consoleCount:0,networkCount:0,checkpointCount:0,screenshotCount:0,nodeCount:0};return{id:e,name:t||`Recording ${new Date().toLocaleTimeString()}`,url:typeof window<"u"?window.location.href:"about:blank",origin:typeof window<"u"?window.location.origin:"",title:typeof document<"u"?document.title:"Forensic Session",userAgent:typeof navigator<"u"?navigator.userAgent:"Node.js/ForensicAgent",schemaVersion:"2.0.0",recorderVersion:"2.0.0",extensionVersion:"2.0.0",startTime:Date.now(),status:"recording",health:s,stats:n}}}class L{static inspectPage(e=document){var n,i,r,o,a,c,u,d,h,p,y,v,m,g;const t=e.defaultView||(typeof window<"u"?window:{}),s=e.activeElement;return{url:((n=t.location)==null?void 0:n.href)||((i=e.location)==null?void 0:i.href)||"",title:e.title||"",origin:((r=t.location)==null?void 0:r.origin)||"",viewport:{width:t.innerWidth||((o=e.documentElement)==null?void 0:o.clientWidth)||1920,height:t.innerHeight||((a=e.documentElement)==null?void 0:a.clientHeight)||1080,scrollX:t.scrollX||t.pageXOffset||((c=e.documentElement)==null?void 0:c.scrollLeft)||0,scrollY:t.scrollY||t.pageYOffset||((u=e.documentElement)==null?void 0:u.scrollTop)||0,devicePixelRatio:t.devicePixelRatio||1},documentDimensions:{width:Math.max(((d=e.body)==null?void 0:d.scrollWidth)||0,((h=e.documentElement)==null?void 0:h.scrollWidth)||0),height:Math.max(((p=e.body)==null?void 0:p.scrollHeight)||0,((y=e.documentElement)==null?void 0:y.scrollHeight)||0)},activeElement:s?{tag:((v=s.tagName)==null?void 0:v.toLowerCase())||"",selector:this.computeBestSelector(s),text:(m=s.textContent)==null?void 0:m.slice(0,100).trim()}:void 0,focusedElement:typeof e.hasFocus=="function"&&e.hasFocus()&&s?{tag:((g=s.tagName)==null?void 0:g.toLowerCase())||"",selector:this.computeBestSelector(s)}:void 0,visibilityState:e.visibilityState||"visible",readyState:e.readyState||"complete",framesCount:e.querySelectorAll?e.querySelectorAll("iframe, frame").length:0}}static inspectElement(e,t){var te,Ne;const s=e.ownerDocument||document,n=s.defaultView||(typeof window<"u"?window:{}),i=e,r=e.tagName?e.tagName.toLowerCase():"element",o=this.extractClasses(e),{bestSelector:a,candidates:c}=this.generateSelectorCandidates(e),u={},d={};if(e.attributes)for(let G=0;G0||w.height>0||w.right>0||w.bottom>0,M=!S||w.right>0&&w.bottom>0&&w.left=q||w.top>=A),_=!O&&C!=="none"&&N!=="hidden"&&I>0&&M,P={disabled:i.disabled??e.hasAttribute("disabled"),readOnly:i.readOnly??e.hasAttribute("readonly"),checked:i.checked,selected:i.selected,focused:s.activeElement===e,isShadowHost:!!e.shadowRoot,hasShadowRoot:!!e.shadowRoot},H=[];let $=e.parentElement;for(;$&&$.tagName&&$.tagName.toLowerCase()!=="html";)H.push(this.computeBestSelector($)),$=$.parentElement;const F={count:e.children?e.children.length:0,tags:e.children?Array.from(e.children).slice(0,10).map(G=>G.tagName.toLowerCase()):[]};let W;if(t){const G=t.getId(e);W={logicalNodeId:G??null,creationSequence:null,lastMutationSequence:null,eventCount:0,isRecorded:G!=null}}return{tag:r,id:e.id||void 0,classes:o,role:h||void 0,ariaAttributes:Object.keys(d).length>0?d:void 0,text:v.slice(0,200),normalizedText:m.slice(0,200),value:g,type:b.type||void 0,selector:a,bestSelector:a,selectorCandidates:c,bounds:w,visibility:{isVisible:_,display:C,visibility:N,opacity:I,pointerEvents:R,isClipped:O,isInViewport:M,zIndex:x},computedStyle:E?{display:C,visibility:N,opacity:String(I),position:E.position,zIndex:String(x),pointerEvents:R,overflow:E.overflow,boxSizing:E.boxSizing,color:E.color,backgroundColor:E.backgroundColor,fontSize:E.fontSize}:{},attributes:u,state:P,context:{parentChain:H,parentSelector:H[0]||void 0,childrenSummary:F,containingBlock:(E==null?void 0:E.position)==="fixed"?"viewport":H[0]||void 0,iframe:null,shadowRoot:e.shadowRoot?"open":null},forensics:W}}static inspectVisualState(e){var b,T;const t=e.ownerDocument||document,s=t.defaultView||(typeof window<"u"?window:{}),n=e.getBoundingClientRect?e.getBoundingClientRect():{x:0,y:0,width:0,height:0,top:0,right:0,bottom:0,left:0},i=s.getComputedStyle?s.getComputedStyle(e):null,r=s.innerWidth||((b=t.documentElement)==null?void 0:b.clientWidth)||1920,o=s.innerHeight||((T=t.documentElement)==null?void 0:T.clientHeight)||1080,a=s.scrollX||s.pageXOffset||0,c=s.scrollY||s.pageYOffset||0,u=s.devicePixelRatio||1,d=(i==null?void 0:i.display)||"block",h=(i==null?void 0:i.visibility)||"visible",p=i&&parseFloat(i.opacity)||1,y=n.right>0&&n.bottom>0&&n.left=r||n.top>=o;let g=null;if(t.elementFromPoint&&y&&!v&&d!=="none"){const w=Math.max(0,Math.min(r-1,n.left+n.width/2)),E=Math.max(0,Math.min(o-1,n.top+n.height/2));try{const C=t.elementFromPoint(w,E);C&&C!==e&&!e.contains(C)&&!C.contains(e)&&(g=this.computeBestSelector(C))}catch{}}return{selector:this.computeBestSelector(e),bounds:{x:n.x??n.left??0,y:n.y??n.top??0,width:n.width??0,height:n.height??0,top:n.top??0,right:n.right??0,bottom:n.bottom??0,left:n.left??0},viewport:{scrollX:a,scrollY:c,width:r,height:o,devicePixelRatio:u},layout:{display:d,position:(i==null?void 0:i.position)||"static",zIndex:(i==null?void 0:i.zIndex)||"auto",opacity:p,visibility:h,overflow:(i==null?void 0:i.overflow)||"visible",boxSizing:(i==null?void 0:i.boxSizing)||"content-box",pointerEvents:(i==null?void 0:i.pointerEvents)||"auto"},occlusion:{isInViewport:y,isClipped:v||m,isZeroDimension:v,isTransparent:p===0,isDisplayNone:d==="none",isVisibilityHidden:h==="hidden",isOffscreen:m,occludedBy:g},computedStyleSummary:i?{display:d,position:i.position,zIndex:i.zIndex,opacity:String(p),visibility:h,pointerEvents:i.pointerEvents}:{}}}static generateSelectorCandidates(e){const t=e.ownerDocument||document,s=e.tagName?e.tagName.toLowerCase():"element",n=[];if(e.id&&/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(e.id)){const c=`#${e.id}`;try{t.querySelectorAll&&t.querySelectorAll(c).length===1&&n.push(c)}catch{n.push(c)}}const i=["data-testid","data-test","data-id","data-qa","data-cy","aria-label","name"];for(const c of i){const u=e.getAttribute(c);if(u&&/^[a-zA-Z0-9_-]+$/.test(u)){const d=`${s}[${c}="${u}"]`;try{t.querySelectorAll&&t.querySelectorAll(d).length===1&&n.push(d)}catch{n.push(d)}}}const r=this.extractClasses(e).filter(c=>/^[a-zA-Z0-9_-]+$/.test(c)&&!c.startsWith("ng-")&&!c.startsWith("_ng"));if(r.length>0){const c=`${s}.${r.slice(0,3).join(".")}`;try{t.querySelectorAll&&t.querySelectorAll(c).length===1&&n.push(c)}catch{n.push(c)}}if(e.parentElement&&e.parentElement.children){const c=Array.from(e.parentElement.children).filter(u=>u.tagName&&u.tagName.toLowerCase()===s);if(c.length>1){const u=c.indexOf(e)+1;if(u>0){const d=this.computeBestSelector(e.parentElement);n.push(`${d} > ${s}:nth-of-type(${u})`)}}}const o=r.length>0?`${s}.${r[0]}`:s;return n.push(o),{bestSelector:n[0]||s,candidates:n}}static computeBestSelector(e){return this.generateSelectorCandidates(e).bestSelector}static extractClasses(e){return e.classList&&typeof e.classList.forEach=="function"?Array.from(e.classList):typeof e.className=="string"?e.className.split(/\s+/).filter(Boolean):e.className&&typeof e.className.baseVal=="string"?e.className.baseVal.split(/\s+/).filter(Boolean):[]}static inferImplicitRole(e){switch(e.tagName?e.tagName.toLowerCase():""){case"a":return e.hasAttribute("href")?"link":void 0;case"button":return"button";case"input":{const s=e.type||"text";return s==="button"||s==="submit"||s==="reset"?"button":s==="checkbox"?"checkbox":s==="radio"?"radio":"textbox"}case"select":return"combobox";case"textarea":return"textbox";case"nav":return"navigation";case"header":return"banner";case"footer":return"contentinfo";case"main":return"main";case"article":return"article";case"section":return"region";default:return}}}f(L,"privacyEngine",new se);class De{constructor(e){f(this,"registry");f(this,"lastSelectedElementRef");f(this,"timingHook",null);f(this,"lastTrajectory",[]);this.registry=e}setLastSelectedElement(e){this.lastSelectedElementRef=e}setTimingHook(e){this.timingHook=e}getLastTrajectory(){return this.lastTrajectory}async timing(e){this.timingHook&&await this.timingHook(e)}resolveTarget(e,t=document){if(e.selectedElementRef&&this.lastSelectedElementRef&&t.contains(this.lastSelectedElementRef))return this.lastSelectedElementRef;if(typeof e.nodeId=="number"&&this.registry){const s=this.registry.getNode(e.nodeId);if(s&&s instanceof Element&&t.contains(s))return s}if(e.selector)try{const s=t.querySelectorAll(e.selector);if(s.length>1){for(let n=0;n{r+=T.length});try{d.observe(t.body||t.documentElement,{childList:!0,attributes:!0,characterData:!0,subtree:!0})}catch{}const h=T=>{o.push(T.message||"Runtime Error")};typeof window<"u"&&window.addEventListener("error",h);try{await this.dispatchAction(n,e)}finally{typeof window<"u"&&window.removeEventListener("error",h)}let p=!0;if((b=e.options)!=null&&b.waitForStabilization){const T=e.options.stabilizationTimeoutMs||300;await new Promise(w=>setTimeout(w,Math.min(2e3,T)))}d.disconnect();let y;t.contains(n)&&(y=L.inspectElement(n,this.registry));const v=Date.now()-s,m=a!=null&&a.__FORENSIC_CONSOLE_BUFFER__?a.__FORENSIC_CONSOLE_BUFFER__.slice(c).filter(T=>(T==null?void 0:T.level)==="error").length:0,g=a!=null&&a.__FORENSIC_NETWORK_BUFFER__?a.__FORENSIC_NETWORK_BUFFER__.slice(u).length:0;return{success:!0,action:e.action,target:y||i,beforeState:i,afterState:y,effects:{domMutations:r,consoleErrors:m,networkRequests:g,runtimeErrors:o},durationMs:v,stabilized:p}}async dispatchAction(e,t){var n,i,r,o,a,c;const s=e;switch(t.action){case"click":{this.scrollIntoViewIfNeeded(e),await this.timing("move"),await this.timing("click"),this.dispatchMouseEvent(e,"pointerdown"),this.dispatchMouseEvent(e,"mousedown"),typeof s.focus=="function"&&s.focus(),this.dispatchMouseEvent(e,"pointerup"),this.dispatchMouseEvent(e,"mouseup"),typeof s.click=="function"?s.click():this.dispatchMouseEvent(e,"click");break}case"double_click":{this.scrollIntoViewIfNeeded(e),await this.timing("click"),this.dispatchMouseEvent(e,"click"),await this.timing("click"),this.dispatchMouseEvent(e,"click"),this.dispatchMouseEvent(e,"dblclick");break}case"right_click":{this.scrollIntoViewIfNeeded(e),await this.timing("click"),this.dispatchMouseEvent(e,"pointerdown",{button:2}),this.dispatchMouseEvent(e,"mousedown",{button:2}),this.dispatchMouseEvent(e,"contextmenu",{button:2});break}case"hover":{await this.timing("move"),this.dispatchMouseEvent(e,"pointerenter"),this.dispatchMouseEvent(e,"mouseenter"),this.dispatchMouseEvent(e,"mouseover"),await this.timing("move"),this.dispatchMouseEvent(e,"mousemove");break}case"focus":{typeof s.focus=="function"&&s.focus(),e.dispatchEvent(new FocusEvent("focus",{bubbles:!0}));break}case"blur":{typeof s.blur=="function"&&s.blur(),e.dispatchEvent(new FocusEvent("blur",{bubbles:!0}));break}case"type":{const u=t.text||"",d=e,h=((n=e.ownerDocument)==null?void 0:n.defaultView)||(typeof window<"u"?window:null);typeof s.focus=="function"&&s.focus();for(const y of u){await this.timing("type");const v=g=>{try{const T=(h==null?void 0:h.KeyboardEvent)||(typeof KeyboardEvent<"u"?KeyboardEvent:null);if(T)return new T(g,{key:y,bubbles:!0})}catch{}const b=(h==null?void 0:h.CustomEvent)||(h==null?void 0:h.Event)||CustomEvent;return new b(g,{bubbles:!0,cancelable:!0})},m=(g,b)=>{try{const w=(h==null?void 0:h.InputEvent)||(typeof InputEvent<"u"?InputEvent:null);if(w)return new w(g,b)}catch{}const T=(h==null?void 0:h.CustomEvent)||(h==null?void 0:h.Event)||CustomEvent;return new T(g,{bubbles:!0,cancelable:!0})};e.dispatchEvent(v("keydown")),e.dispatchEvent(v("keypress")),"value"in d&&(d.value=(d.value||"")+y),e.dispatchEvent(m("input",{data:y,inputType:"insertText",bubbles:!0})),e.dispatchEvent(v("keyup"))}const p=(h==null?void 0:h.Event)||Event;e.dispatchEvent(new p("change",{bubbles:!0}));break}case"clear":{const u=e,d=((i=e.ownerDocument)==null?void 0:i.defaultView)||(typeof window<"u"?window:null);if("value"in u){u.value="";const h=(y,v)=>{try{const g=(d==null?void 0:d.InputEvent)||(typeof InputEvent<"u"?InputEvent:null);if(g)return new g(y,v)}catch{}const m=(d==null?void 0:d.CustomEvent)||(d==null?void 0:d.Event)||CustomEvent;return new m(y,{bubbles:!0,cancelable:!0})};e.dispatchEvent(h("input",{inputType:"deleteContentBackward",bubbles:!0}));const p=(d==null?void 0:d.Event)||Event;e.dispatchEvent(new p("change",{bubbles:!0}))}break}case"press_key":{const u=t.key||"Enter",d=((r=e.ownerDocument)==null?void 0:r.defaultView)||(typeof window<"u"?window:null),h=p=>{try{const v=(d==null?void 0:d.KeyboardEvent)||(typeof KeyboardEvent<"u"?KeyboardEvent:null);if(v)return new v(p,{key:u,bubbles:!0})}catch{}const y=(d==null?void 0:d.CustomEvent)||(d==null?void 0:d.Event)||CustomEvent;return new y(p,{bubbles:!0,cancelable:!0})};e.dispatchEvent(h("keydown")),e.dispatchEvent(h("keypress")),e.dispatchEvent(h("keyup"));break}case"select_option":{const u=e;((o=u.tagName)==null?void 0:o.toLowerCase())==="select"&&t.optionValue&&(u.value=t.optionValue,e.dispatchEvent(new Event("change",{bubbles:!0})));break}case"scroll_into_view":{this.scrollIntoViewIfNeeded(e,!0);break}case"scroll":{const u=((a=t.scrollDelta)==null?void 0:a.x)||0,d=((c=t.scrollDelta)==null?void 0:c.y)||0;typeof e.scrollBy=="function"&&e.scrollBy(u,d);break}default:throw new Error(`Unsupported interaction action: ${t.action}`)}}scrollIntoViewIfNeeded(e,t=!1){if(typeof e.scrollIntoView=="function")try{e.scrollIntoView({behavior:"auto",block:"center",inline:"center"})}catch{e.scrollIntoView(t)}}dispatchMouseEvent(e,t,s={}){const n=e.getBoundingClientRect?e.getBoundingClientRect():{left:0,top:0,width:0,height:0},i=n.left+n.width/2,r=n.top+n.height/2,o=new MouseEvent(t,{bubbles:s.bubbles!==void 0?s.bubbles:!0,cancelable:s.cancelable!==void 0?s.cancelable:!0,clientX:i,clientY:r,button:s.button||0,buttons:s.button===2?2:1});e.dispatchEvent(o)}}class ae{static matches(e,t){if(!e||e.nodeType!==U.ELEMENT_NODE)return!1;const s=t.trim();return s?s.includes(",")?s.split(",").some(n=>this.matchesSimple(e,n.trim())):this.matchesCompound(e,s):!1}static querySelector(e,t,s){const n=this.querySelectorAll(e,t,s,1);return n.length>0?n[0]:null}static querySelectorAll(e,t,s,n=1/0){const i=[],r=s[t];if(!r)return i;const o=[...r.children||[]],a=new Set;for(;o.length>0&&i.length=n))break;u.children&&u.children.length>0&&o.push(...u.children)}}return i}static getElementById(e,t){for(const s of Object.values(t))if(s.nodeType===U.ELEMENT_NODE&&!s.isDetached&&s.attributes&&s.attributes.id===e&&this.isNodeConnected(s,t))return s;return null}static isNodeConnected(e,t){if(e.isDetached)return!1;let s=e;const n=new Set;for(;s&&s.parentId;){if(n.has(s.id))return!1;n.add(s.id);const i=t[s.parentId];if(!i||i.isDetached)return!1;s=i}return!0}static computeSelector(e,t){var r,o;if(!e)return"";if(e.nodeType!==U.ELEMENT_NODE)return e.tagName||`#node-${e.id}`;if((r=e.attributes)!=null&&r.id)return`#${e.attributes.id}`;const s=e.tagName||"div",n=(((o=e.attributes)==null?void 0:o.class)||"").split(/\s+/).filter(a=>a&&!a.startsWith("ng-")).slice(0,2),i=n.length>0?"."+n.join("."):"";if(e.parentId&&t[e.parentId]){const c=(t[e.parentId].children||[]).map(u=>t[u]).filter(u=>u&&u.nodeType===U.ELEMENT_NODE&&u.tagName===s);if(c.length>1){const u=c.findIndex(d=>d.id===e.id)+1;return`${s}${i}:nth-of-type(${u})`}}return`${s}${i}`}static matchesCompound(e,t){return this.matchesSimple(e,t)}static matchesSimple(e,t){var i,r,o,a,c,u,d;const s=((i=e.tagName)==null?void 0:i.toLowerCase())||"";if(t==="*")return!0;if(t.startsWith("#")){const h=t.substring(1);return((r=e.attributes)==null?void 0:r.id)===h}if(t.startsWith(".")){const h=t.substring(1);return(((o=e.attributes)==null?void 0:o.class)||"").split(/\s+/).includes(h)}if(t.startsWith("[")&&t.endsWith("]")){const h=t.substring(1,t.length-1);if(h.includes("=")){const[p,y]=h.split("="),v=y.replace(/^["']|["']$/g,"");return((a=e.attributes)==null?void 0:a[p.trim()])===v}return!!((c=e.attributes)!=null&&c[h.trim()])}const n=t.match(/^([a-zA-Z0-9_-]+)(.*)$/);if(n){const h=n[1].toLowerCase(),p=n[2];if(h!==s&&h!=="*")return!1;if(!p)return!0;if(p.startsWith("#"))return((u=e.attributes)==null?void 0:u.id)===p.substring(1);if(p.startsWith("."))return(((d=e.attributes)==null?void 0:d.class)||"").split(/\s+/).includes(p.substring(1));if(p.startsWith("["))return this.matchesSimple(e,p)}return!1}}class $e{static traceElement(e,t,s){var x,q;const n=[...t].sort((A,S)=>A.sequence-S.sequence);let i=e.nodeId,r="unknown",o=e.selector||"",a={},c=0,u=0,d="init";if(!i&&e.selector&&s){const A=ae.querySelector(e.selector,s.rootId,s.nodes);A&&(i=A.id,r=A.tagName||"element",a={...A.attributes||{}},o=e.selector)}if(!i&&e.selector){for(const A of n)if(A.type==="DOM_MUTATION_ADD"){const S=A.payload;if(S.node&&ae.matches(S.node,e.selector)){i=S.node.id,r=S.node.tagName||"element",a={...S.node.attributes||{}},c=A.timestamp,u=A.sequence,d=A.id;break}}}if(!i)return null;const h=[];let p=!0,y=null,v=null,m,g=0;if(s&&s.nodes[i]){const A=s.nodes[i];r=A.tagName||r,a={...A.attributes||{}},o||(o=ae.computeSelector(A,s.nodes)),h.push({timestamp:s.timestamp,sequence:s.sequence,wallClockTime:Date.now(),stage:"CREATED",eventId:s.snapshotId,eventType:"DOM_SNAPSHOT",description:`Element <${r}> existed in initial baseline snapshot [ID: ${i}]`,details:{initialParentId:A.parentId,attributes:a},nodeSnapshot:A})}const b=new Map;if(s)for(const[A,S]of Object.entries(s.nodes))b.set(Number(A),S.parentId??null);const T=(A,S)=>{let M=b.get(S);const O=new Set;for(;M&&!O.has(M);){if(M===A)return!0;O.add(M),M=b.get(M)}return!1};for(const A of n){const S=A.timestamp,M=A.sequence,O=A.wallClockTime;if(A.type==="DOM_MUTATION_ADD"){const _=A.payload;(x=_.node)!=null&&x.id&&b.set(_.node.id,_.parentId??null),((q=_.node)==null?void 0:q.id)===i&&(p=!0,r=_.node.tagName||r,c=S,u=M,d=A.id,a={..._.node.attributes||{}},h.push({timestamp:S,sequence:M,wallClockTime:O,stage:"ATTACHED_TO_DOM",eventId:A.id,eventType:A.type,description:`Element <${r}> added to DOM under parent ID ${_.parentId}`,details:{parentId:_.parentId,index:_.index},nodeSnapshot:_.node}))}if(A.type==="DOM_MUTATION_REMOVE"){const _=A.payload;_.nodeId===i?(p=!1,y=S,v=M,m=A.id,h.push({timestamp:S,sequence:M,wallClockTime:O,stage:"REMOVED_FROM_DOM",eventId:A.id,eventType:A.type,description:`Element <${r}> explicitly removed from parent ID ${_.parentId}`,details:{parentId:_.parentId,removedIndex:_.index}})):T(_.nodeId,i)&&(p=!1,y=S,v=M,m=A.id,h.push({timestamp:S,sequence:M,wallClockTime:O,stage:"PARENT_SUBTREE_REPLACED",eventId:A.id,eventType:A.type,description:`Ancestor element [ID: ${_.nodeId}] was removed, causing target element [ID: ${i}] to detach from DOM`,details:{removedAncestorId:_.nodeId,parentId:_.parentId}}))}if(A.type==="DOM_MUTATION_MOVE"){const _=A.payload;_.nodeId&&b.set(_.nodeId,_.newParentId??null),_.nodeId===i&&(g++,h.push({timestamp:S,sequence:M,wallClockTime:O,stage:"REPARENTED",eventId:A.id,eventType:A.type,description:`Element reparented from parent ${_.oldParentId} to ${_.newParentId}`,details:{oldParentId:_.oldParentId,newParentId:_.newParentId}}))}if(A.type==="DOM_MUTATION_ATTR"){const _=A.payload;if(_.nodeId===i){g++;const P=_.attributeName.toLowerCase();let H="ATTRIBUTE_MODIFIED";P==="class"&&(H="CLASS_MODIFIED"),P==="style"&&(H="STYLE_MODIFIED"),h.push({timestamp:S,sequence:M,wallClockTime:O,stage:H,eventId:A.id,eventType:A.type,description:`Attribute '${_.attributeName}' changed from '${_.oldValue??""}' to '${_.newValue??""}'`,details:{attributeName:_.attributeName,oldValue:_.oldValue,newValue:_.newValue}})}}if(A.type==="DOM_MUTATION_TEXT"){const _=A.payload;_.nodeId===i&&(g++,h.push({timestamp:S,sequence:M,wallClockTime:O,stage:"TEXT_MODIFIED",eventId:A.id,eventType:A.type,description:`Text content changed: "${_.oldText}" → "${_.newText}"`,details:{oldText:_.oldText,newText:_.newText}}))}}const w=y??c,E=500,C=n.filter(A=>(A.category==="ERROR"||A.category==="CONSOLE")&&Math.abs(A.timestamp-w)<=E),N=n.filter(A=>A.category==="NETWORK"&&Math.abs(A.timestamp-w)<=E),I=n.length>0?n[n.length-1].timestamp:c,R=Math.max(0,(y??I)-c);return{targetNodeId:i,tagName:r,selectorHint:o,initialAttributes:a,createdAt:c,createdSequence:u,createdEventId:d,removedAt:y,removedSequence:v,removedEventId:m,isCurrentlyAlive:p,lifespanMs:Math.round(R*100)/100,mutationCount:g,entries:h,correlatedDiagnostics:C,correlatedNetwork:N}}}class qe{static analyze(e,t,s){var R,x,q,A;const n=typeof e=="number"?{nodeId:e}:{selector:e},i=$e.traceElement(n,t,s);if(!i)return{targetQuery:e,found:!1,disappearanceMechanism:"UNKNOWN",likelyRootCause:"Target element could not be found in recording baseline or event stream",confidenceScore:0,detailedExplanation:`No element matching "${e}" was ever created, recorded in the initial DOM snapshot, or observed in mutation events.`,evidentiaryTrail:[],precedingEvents:[],followingEvents:[],correlatedErrors:[],correlatedNetworkCalls:[],alternativeHypotheses:[{hypothesis:"Element was injected into an unmonitored isolated iframe or ShadowRoot closed mode",likelihood:40,evidenceFor:["Element query yielded zero matches in monitored document"],evidenceAgainst:["Iframes/ShadowRoots were accessible in this session"]},{hypothesis:"Selector typo or timing mismatch",likelihood:60,evidenceFor:["Target selector did not match any recorded tag or class"],evidenceAgainst:[]}]};const r=[...t].sort((S,M)=>S.sequence-M.sequence),o=[],a=[];let c="UNKNOWN",u="Unknown disappearance mechanism",d=50,h="",p=i.removedAt??void 0;const y=i.entries.find(S=>S.stage==="REMOVED_FROM_DOM"),v=i.entries.find(S=>S.stage==="PARENT_SUBTREE_REPLACED"),m=i.entries.find(S=>S.stage==="CLASS_MODIFIED"&&/\b(hidden|hide|d-none|invisible|collapsed)\b/i.test(String(S.details.newValue||""))),g=i.entries.find(S=>S.stage==="STYLE_MODIFIED"&&/display\s*:\s*none|visibility\s*:\s*hidden|opacity\s*:\s*0/i.test(String(S.details.newValue||"")));y?(c="DIRECT_NODE_REMOVAL",p=y.timestamp,u=`Element [ID: ${i.targetNodeId}] <${i.tagName}> was directly removed from its parent [ID: ${y.details.parentId}] via DOM removeChild/replaceChild`,d=95,o.push({timestamp:y.timestamp,sequence:y.sequence,eventId:y.eventId,eventType:y.eventType,evidenceType:"DIRECT",description:`Direct DOM removal mutation: element detached from parent ID ${y.details.parentId}`,confidenceContribution:50})):v?(c="PARENT_SUBTREE_REPLACED",p=v.timestamp,u=`Host framework (e.g. React/Vue re-render) destroyed and replaced Ancestor container [ID: ${v.details.removedAncestorId}], causing injected element to be unmounted`,d=92,o.push({timestamp:v.timestamp,sequence:v.sequence,eventId:v.eventId,eventType:v.eventType,evidenceType:"DIRECT",description:`Ancestor container [ID: ${v.details.removedAncestorId}] was removed, wiping out all child subtrees`,confidenceContribution:50})):g?(c="STYLE_DISPLAY_NONE",p=g.timestamp,u=`Element was visually hidden by an inline style modification: "${g.details.newValue}"`,d=88,o.push({timestamp:g.timestamp,sequence:g.sequence,eventId:g.eventId,eventType:g.eventType,evidenceType:"DIRECT",description:`Inline style changed to "${g.details.newValue}"`,confidenceContribution:45})):m?(c="CLASS_TRIGGERED_HIDDEN",p=m.timestamp,u=`Element was visually hidden because its CSS class list was modified to include "${m.details.newValue}"`,d=85,o.push({timestamp:m.timestamp,sequence:m.sequence,eventId:m.eventId,eventType:m.eventType,evidenceType:"DIRECT",description:`Class list changed from "${m.details.oldValue??""}" to "${m.details.newValue??""}"`,confidenceContribution:45})):i.isCurrentlyAlive&&(c="UNKNOWN",u=`Element [ID: ${i.targetNodeId}] is currently alive and attached to the DOM tree (no unmount mutation detected)`,d=70,h="The element exists in the current DOM state. If it is not visible on screen, it may be clipped by viewport boundaries, z-index stacking context, or 0x0 pixel dimensions.");const b=p??i.createdAt,T=500,w=r.filter(S=>S.timestamp>=b-T&&S.timestampS.timestamp>b&&S.timestamp<=b+T),C=w.filter(S=>S.category==="ERROR");if(C.length>0){const S=C[0],M=((R=S.payload)==null?void 0:R.message)||"Unknown runtime error";o.push({timestamp:S.timestamp,sequence:S.sequence,eventId:S.id,eventType:S.type,evidenceType:"PRECEDING",description:`Runtime error occurred ${(b-S.timestamp).toFixed(1)}ms before disappearance: "${M}"`,confidenceContribution:20,rawEvent:S}),u+=` (preceded by runtime error: "${M}")`}const N=w.filter(S=>S.type==="NETWORK_RESPONSE_COMPLETE"||S.type==="NETWORK_REQUEST_FAILED");if(N.length>0){const S=N[0],M=((x=S.payload)==null?void 0:x.url)||"network request";o.push({timestamp:S.timestamp,sequence:S.sequence,eventId:S.id,eventType:S.type,evidenceType:"PRECEDING",description:`Network response completed ${(b-S.timestamp).toFixed(1)}ms before disappearance: ${M}`,confidenceContribution:15,rawEvent:S})}const I=w.filter(S=>S.category==="NAVIGATION");if(I.length>0){const S=I[0];o.push({timestamp:S.timestamp,sequence:S.sequence,eventId:S.id,eventType:S.type,evidenceType:"PRECEDING",description:`Navigation event (${(q=S.payload)==null?void 0:q.navigationType}) occurred ${(b-S.timestamp).toFixed(1)}ms before disappearance`,confidenceContribution:25,rawEvent:S}),u+=` following SPA navigation to "${(A=S.payload)==null?void 0:A.url}"`}return h||(h=[`Element <${i.tagName}> (Logical ID: ${i.targetNodeId}, selector: "${i.selectorHint}") was created at ${i.createdAt.toFixed(1)}ms.`,`It remained alive in the DOM for ${i.lifespanMs.toFixed(1)}ms and experienced ${i.mutationCount} mutations.`,`At timestamp ${b.toFixed(1)}ms, it disappeared via [${c}].`,`Diagnosis: ${u}.`].join(" ")),c==="PARENT_SUBTREE_REPLACED"?(a.push({hypothesis:"Direct cleanup called by extension code",likelihood:25,evidenceFor:["Element was unmounted shortly after creation"],evidenceAgainst:["Ancestor container mutation was recorded from host page context"]}),a.push({hypothesis:"Host single-page app route change destroyed component tree",likelihood:35,evidenceFor:I.length>0?["Preceding navigation event recorded"]:[],evidenceAgainst:I.length===0?["No navigation events occurred in temporal window"]:[]})):c==="DIRECT_NODE_REMOVAL"&&a.push({hypothesis:"Third-party script or ad-blocker removed the injected node",likelihood:30,evidenceFor:["Direct node removal occurred without ancestor replacement"],evidenceAgainst:["No ad-blocker signatures or extension error logs observed"]}),{targetQuery:e,targetNodeId:i.targetNodeId,found:!0,tagName:i.tagName,selectorHint:i.selectorHint,createdAt:i.createdAt,firstVisibleAt:i.createdAt,lastKnownGoodStateAt:Math.max(0,b-1),disappearedAt:p,lifespanMs:i.lifespanMs,disappearanceMechanism:c,likelyRootCause:u,confidenceScore:Math.min(99,d),detailedExplanation:h,evidentiaryTrail:o,precedingEvents:w,followingEvents:E,correlatedErrors:C,correlatedNetworkCalls:N,alternativeHypotheses:a}}}class Pe{constructor(e){f(this,"activeObservation",null);f(this,"registry");f(this,"sequenceCounter");this.registry=e,this.sequenceCounter=new oe}isObserving(){return this.activeObservation!==null}startObservation(e,t=document){this.activeObservation&&this.stopObservation(t);const s=`obs_${Date.now()}_${Math.random().toString(36).slice(2,6)}`,n=Date.now(),i=L.inspectElement(e,this.registry),r=i.bestSelector,o=[],a=this.registry?this.registry.getOrCreateId(e,0):100;o.push({id:`evt_init_${s}`,sessionId:s,timestamp:0,sequence:1,wallClockTime:n,type:"DOM_MUTATION_ADD",category:"DOM",source:"BROWSER_RUNTIME",targetNodeId:a,targetSelector:r,payload:{node:{id:a,nodeType:1,tagName:i.tag,attributes:i.attributes,textContent:i.text,children:[],parentId:null},parentId:null,index:0}});const c=new MutationObserver(u=>{const d=Date.now()-n;for(const h of u)if(h.type==="childList"){for(let p=0;p0&&(m=qe.analyze(n,a)),{observationId:t,targetSelector:n,targetNodeId:((g=r.forensics)==null?void 0:g.logicalNodeId)||void 0,startTime:i,endTime:u,durationMs:d,initialState:r,finalState:p,disappeared:y,disappearanceReason:v,mutations:a.filter(b=>b.category==="DOM"),diagnostics:a.filter(b=>b.category==="ERROR"||b.category==="CONSOLE"),networkEvents:a.filter(b=>b.category==="NETWORK"),screenshots:c,correlationReport:m}}}class Ue{constructor(e={}){f(this,"isExplicitModeActive",!1);f(this,"isGlobalShortcutActive",!1);f(this,"highlighterEl",null);f(this,"badgeEl",null);f(this,"lastSelectedElement",null);f(this,"options",{});f(this,"onMouseMoveBound");f(this,"onClickBound");f(this,"onKeyDownBound");f(this,"onGlobalClickBound");this.options=e,this.onMouseMoveBound=this.handleMouseMove.bind(this),this.onClickBound=this.handleClick.bind(this),this.onKeyDownBound=this.handleKeyDown.bind(this),this.onGlobalClickBound=this.handleGlobalCtrlShiftClick.bind(this),this.initGlobalShortcutListener()}initGlobalShortcutListener(){typeof window>"u"||this.isGlobalShortcutActive||(window.addEventListener("click",this.onGlobalClickBound,!0),this.isGlobalShortcutActive=!0)}startPicker(e){typeof document>"u"||(e&&(this.options={...this.options,...e}),!this.isExplicitModeActive&&(this.isExplicitModeActive=!0,this.ensureHighlighter(),document.body&&(document.body.style.cursor="crosshair"),window.addEventListener("mousemove",this.onMouseMoveBound,!0),window.addEventListener("click",this.onClickBound,!0),window.addEventListener("keydown",this.onKeyDownBound,!0)))}stopPicker(){this.isExplicitModeActive&&(this.isExplicitModeActive=!1,typeof document<"u"&&document.body&&(document.body.style.cursor="default"),this.removeHighlighter(),typeof window<"u"&&(window.removeEventListener("mousemove",this.onMouseMoveBound,!0),window.removeEventListener("click",this.onClickBound,!0),window.removeEventListener("keydown",this.onKeyDownBound,!0)))}getLastSelectedElement(){return this.lastSelectedElement}setSelectedElement(e){let t;return"tag"in e&&"bestSelector"in e&&typeof e.getAttribute!="function"?t=e:(t=L.inspectElement(e,this.options.nodeRegistry),this.flashSelection(e)),this.lastSelectedElement=t,this.options.onSelected&&this.options.onSelected(t),t}handleGlobalCtrlShiftClick(e){if(!e.ctrlKey||!e.shiftKey)return;const t=e.target;if(!t||this.isExtensionOwned(t))return;e.preventDefault(),e.stopPropagation(),e.stopImmediatePropagation();const s=this.setSelectedElement(t);this.notifyExtension(s)}handleMouseMove(e){if(!this.isExplicitModeActive)return;const t=e.target;if(!t||this.isExtensionOwned(t)){this.hideHighlighter();return}this.updateHighlighter(t)}handleClick(e){if(!this.isExplicitModeActive)return;const t=e.target;if(!t||this.isExtensionOwned(t))return;e.preventDefault(),e.stopPropagation(),e.stopImmediatePropagation();const s=this.setSelectedElement(t);this.notifyExtension(s),this.stopPicker()}handleKeyDown(e){e.key==="Escape"&&this.isExplicitModeActive&&(e.preventDefault(),this.stopPicker(),this.options.onCanceled&&this.options.onCanceled())}isExtensionOwned(e){return!!(e.id==="forensic-recorder-floating-host"||e.id==="forensic-inspect-highlighter"||e.closest("#forensic-recorder-floating-host")||e.closest("#forensic-inspect-highlighter")||e.hasAttribute("data-forensic-internal")||e.closest("[data-forensic-internal]"))}ensureHighlighter(){if(typeof document>"u"||this.highlighterEl)return;const e=this.options.highlightColor||"#0ea5e9",t=document.createElement("div");t.id="forensic-inspect-highlighter",t.setAttribute("data-forensic-internal","true"),t.style.position="fixed",t.style.pointerEvents="none",t.style.zIndex="2147483640",t.style.border=`2px solid ${e}`,t.style.background="rgba(14, 165, 233, 0.18)",t.style.borderRadius="3px",t.style.boxShadow=`0 0 12px ${e}88`,t.style.transition="all 0.05s ease-out",t.style.display="none";const s=document.createElement("div");s.setAttribute("data-forensic-internal","true"),s.style.position="absolute",s.style.bottom="100%",s.style.left="0",s.style.transform="translateY(-4px)",s.style.background="#0f172a",s.style.color="#38bdf8",s.style.fontSize="11px",s.style.fontFamily="monospace",s.style.fontWeight="bold",s.style.padding="2px 6px",s.style.borderRadius="3px",s.style.boxShadow="0 2px 6px rgba(0,0,0,0.5)",s.style.whiteSpace="nowrap",s.style.pointerEvents="none",t.appendChild(s),document.body.appendChild(t),this.highlighterEl=t,this.badgeEl=s}updateHighlighter(e){if(this.ensureHighlighter(),!this.highlighterEl||!this.badgeEl)return;const t=e.getBoundingClientRect();this.highlighterEl.style.display="block",this.highlighterEl.style.left=`${t.left}px`,this.highlighterEl.style.top=`${t.top}px`,this.highlighterEl.style.width=`${Math.max(1,t.width)}px`,this.highlighterEl.style.height=`${Math.max(1,t.height)}px`;const s=e.tagName.toLowerCase(),n=e.id?`#${e.id}`:"",i=e.className&&typeof e.className=="string"?"."+e.className.split(/\s+/)[0]:"",r=`${Math.round(t.width)}×${Math.round(t.height)}`;this.badgeEl.textContent=`<${s}${n}${i}> [${r}]`}hideHighlighter(){this.highlighterEl&&(this.highlighterEl.style.display="none")}removeHighlighter(){this.highlighterEl&&this.highlighterEl.parentElement&&this.highlighterEl.remove(),this.highlighterEl=null,this.badgeEl=null}flashSelection(e){if(typeof document>"u"||!e.getBoundingClientRect)return;const t=e.getBoundingClientRect(),s=document.createElement("div");s.setAttribute("data-forensic-internal","true"),s.style.position="fixed",s.style.left=`${t.left}px`,s.style.top=`${t.top}px`,s.style.width=`${Math.max(1,t.width)}px`,s.style.height=`${Math.max(1,t.height)}px`,s.style.border="2px solid #22c55e",s.style.background="rgba(34, 197, 94, 0.25)",s.style.zIndex="2147483645",s.style.pointerEvents="none",s.style.transition="opacity 0.6s ease-out",document.body.appendChild(s),setTimeout(()=>{s.style.opacity="0",setTimeout(()=>s.remove(),600)},400)}notifyExtension(e){var t;try{typeof chrome<"u"&&((t=chrome.runtime)!=null&&t.sendMessage)&&chrome.runtime.sendMessage({type:"ELEMENT_SELECTED",elementInfo:e,timestamp:Date.now()})}catch{}}destroy(){this.stopPicker(),typeof window<"u"&&window.removeEventListener("click",this.onGlobalClickBound,!0),this.isGlobalShortcutActive=!1}}class fe{static getCrcTable(){if(this.crcTable)return this.crcTable;const e=new Uint32Array(256);for(let t=0;t<256;t++){let s=t;for(let n=0;n<8;n++)s=s&1?3988292384^s>>>1:s>>>1;e[t]=s>>>0}return this.crcTable=e,e}static crc32(e,t=0,s=e.length){const n=this.getCrcTable();let i=4294967295;for(let r=t;r>>8^n[(i^e[r])&255];return(i^4294967295)>>>0}static adler32(e){let t=1,s=0;for(let n=0;n>>0}static createPNG(e){const t=Math.max(1,Math.min(1920,Math.floor(e.width))),s=Math.max(1,Math.min(1080,Math.floor(e.height))),n=e.backgroundColor||[15,23,42,255],i=e.headerColor||[56,189,248,255],r=e.borderColor||[99,102,241,255],o=1+t*4,a=new Uint8Array(o*s),c=Math.min(30,Math.floor(s*.2));for(let g=0;g=e.length,h=new Uint8Array(5+u);h[0]=d?1:0,h[1]=u&255,h[2]=u>>>8&255;const p=~u&65535;h[3]=p&255,h[4]=p>>>8&255,h.set(e.subarray(n,n+u),5),t.push(h),n+=u}const i=t.reduce((c,u)=>c+u.length,0)+2+4,r=new Uint8Array(i);let o=0;r[o++]=120,r[o++]=1;for(const c of t)r.set(c,o),o+=c.length;const a=this.adler32(e);return r[o++]=a>>>24&255,r[o++]=a>>>16&255,r[o++]=a>>>8&255,r[o++]=a&255,r}static writeChunk(e,t,s,n){const i=n.length,r=new DataView(e.buffer,e.byteOffset,e.byteLength);r.setUint32(t,i,!1),t+=4;const o=new Uint8Array(4+i);for(let c=0;c<4;c++){const u=s.charCodeAt(c);e[t+c]=u,o[c]=u}t+=4,i>0&&(e.set(n,t),o.set(n,4),t+=i);const a=this.crc32(o);return r.setUint32(t,a,!1),t+=4,t}}f(fe,"crcTable",null);const ne=500;class He{constructor(e,t){f(this,"history",[]);f(this,"undoStack",[]);f(this,"redoStack",[]);f(this,"counter",0);f(this,"transaction",null);this.doc=e,this.registry=t}mutate(e){var d;const t=`mut_${Date.now().toString(36)}_${++this.counter}`,s=Date.now();let n;try{n=this.resolveTarget(e.target)}catch(h){return this.failure(t,e,null,h.message,Date.now()-s)}const i=this.snapshotState(n);let r=null,o=null,a,c=!0;try{const h=this.applyOperation(t,e,n);h&&(this.transaction?this.transaction.undoRecords.push(h):(this.undoStack.push(h),this.redoStack=[]));const y=(n.isConnected!==void 0?n.isConnected:this.doc.contains(n))?n:this.doc.querySelector(i.selector)||n;r=this.snapshotState(y),o=this.quickDiff(i,r,n)}catch(h){c=!1,a=h.message,r=null}const u={mutationId:t,operation:e.operation,success:c,before:i,after:r,diff:o,affectedSelector:c?i.selector:null,durationMs:Date.now()-s,error:a,undoable:c&&(this.transaction?this.transaction.undoRecords.length>0:this.undoStack.length>0)};return this.transaction&&this.transaction.steps.push({stepId:`step_${this.transaction.steps.length+1}`,mutation:u}),this.pushHistory({mutationId:t,transactionId:(d=this.transaction)==null?void 0:d.id,timestamp:Date.now(),operation:e.operation,targetSelector:i.selector,success:c,summary:`${e.operation} on ${i.selector}${o?` (+${o.added}/-${o.removed}/~${o.changed})`:""}`,undoApplied:!1,redoApplied:!1}),u}beginTransaction(){if(this.transaction)throw new Error(`TRANSACTION_ALREADY_OPEN: ${this.transaction.id} — commit or rollback first.`);return this.transaction={id:`tx_${Date.now().toString(36)}_${++this.counter}`,steps:[],undoRecords:[]},this.transaction.id}commitTransaction(e){if(!this.transaction)throw new Error("NO_OPEN_TRANSACTION: begin a transaction before committing.");const t=this.transaction,s=Date.now();let n=!0,i;if(e)try{n=e({id:t.id,steps:t.steps})!==!1,n||(i="VERIFY_FAILED: caller verification rejected the transaction state.")}catch(o){n=!1,i=`VERIFY_ERROR: ${o.message}`}if(!n)return this.rollbackInternal(t,i||"VERIFY_FAILED",s);this.undoStack.push(...t.undoRecords),this.undoStack.length>ne&&this.undoStack.splice(0,this.undoStack.length-ne),this.redoStack=[];const r=this.summaryOf(t);return this.transaction=null,{transactionId:t.id,committed:!0,rolledBack:!1,steps:t.steps,durationMs:Date.now()-s,finalStateSummary:r}}rollbackTransaction(e){if(!this.transaction)throw new Error("NO_OPEN_TRANSACTION: begin a transaction before rolling back.");const t=this.transaction;return this.rollbackInternal(t,e||"ROLLBACK_REQUESTED",Date.now())}rollbackInternal(e,t,s){for(const i of[...e.undoRecords].reverse())try{this.applyUndo(i)}catch{}const n=this.summaryOf(e);return this.transaction=null,{transactionId:e.id,committed:!1,rolledBack:!0,steps:e.steps,error:t,durationMs:Date.now()-s,finalStateSummary:n}}undo(){const e=this.transaction?this.transaction.undoRecords:this.undoStack,t=e.pop();if(!t)return{success:!1,message:"Nothing to undo — the mutation history is empty."};try{this.applyUndo(t)}catch(s){return e.push(t),{success:!1,mutationId:t.mutationId,message:`UNDO_FAILED: ${s.message}`}}return this.redoStack.push(t),this.markHistory(t.mutationId,"undo"),{success:!0,mutationId:t.mutationId,message:`Undid ${t.operation} on ${t.targetSelector}.`}}redo(){const e=this.redoStack.pop();if(!e)return{success:!1,message:"Nothing to redo — no undone mutation is pending."};try{const t=this.resolveTarget({selector:e.targetSelector}),s={operation:e.operation,target:{selector:e.targetSelector}};return this.reapplyRecord(e,t,s)?((this.transaction?this.transaction.undoRecords:this.undoStack).push(e),this.markHistory(e.mutationId,"redo"),{success:!0,mutationId:e.mutationId,message:`Redid ${e.operation} on ${e.targetSelector}.`}):(this.redoStack.push(e),{success:!1,mutationId:e.mutationId,message:"REDO_FAILED: target state diverged — cannot safely reapply."})}catch(t){return this.redoStack.push(e),{success:!1,mutationId:e.mutationId,message:`REDO_FAILED: ${t.message}`}}}getHistory(e=100){return this.history.slice(-e)}getUndoDepth(){return this.transaction?this.transaction.undoRecords.length:this.undoStack.length}getRedoDepth(){return this.redoStack.length}getOpenTransactionId(){var e;return((e=this.transaction)==null?void 0:e.id)||null}preview(e){var t;try{const s=this.resolveTarget(e.target),n=[];let i=1;(e.operation==="set_inner_html"||e.operation==="set_outer_html")&&(n.push("HTML replacement can destroy descendant node identity — captured regions targeting children may become stale."),i=s.querySelectorAll("*").length+1),(e.operation==="remove_element"||e.operation==="unwrap_element")&&(n.push("Removal is destructive; the undo record preserves the full serialized subtree."),i=s.querySelectorAll("*").length+1),e.operation==="move_element"&&!e.parent&&n.push("No parent target supplied — move requires payload.parent."),e.operation==="wrap_element"&&!e.newElementHtml&&n.push("No wrapper HTML supplied — a neutral
wrapper will be generated.");const r=Be(e,s);return{valid:n.filter(o=>o.includes("requires")||o.includes("No parent")).length===0,operation:e.operation,target:{selector:this.snapshotState(s).selector,tag:s.tagName.toLowerCase()},expectedChange:r,affectedNodes:i,warnings:n}}catch(s){return{valid:!1,operation:e.operation,target:{selector:String(((t=e.target)==null?void 0:t.selector)||""),tag:""},expectedChange:"—",affectedNodes:0,warnings:[],error:s.message}}}applyOperation(e,t,s){var r;const n=this.snapshotState(s).selector,i=t.operation;switch(i){case"set_attribute":{if(!t.attribute)throw new Error("ATTRIBUTE_REQUIRED: payload.attribute is missing.");const o=s.getAttribute(t.attribute);return s.setAttribute(t.attribute,t.value??""),this.undoFor(e,i,n,{kind:o===null?"remove-attribute":"restore-attribute",attribute:t.attribute,value:o})}case"remove_attribute":{if(!t.attribute)throw new Error("ATTRIBUTE_REQUIRED: payload.attribute is missing.");const o=s.getAttribute(t.attribute);if(o===null)throw new Error(`ATTRIBUTE_NOT_PRESENT: "${t.attribute}" is not set on ${n}.`);return s.removeAttribute(t.attribute),this.undoFor(e,i,n,{kind:"restore-attribute",attribute:t.attribute,value:o})}case"set_text":{const o=s.textContent||"";return s.textContent=t.text??"",this.undoFor(e,i,n,{kind:"restore-text",text:o})}case"replace_text":{if(!t.text||!t.replacement)throw new Error("TEXT_PATTERNS_REQUIRED: payload.text (search) and payload.replacement are required.");const o=s.textContent||"";return s.textContent=o.split(t.text).join(t.replacement),this.undoFor(e,i,n,{kind:"restore-text",text:o})}case"set_inner_html":{const o=s.innerHTML;return s.innerHTML=t.html??"",this.undoFor(e,i,n,{kind:"restore-outer-html",outerHtml:s.outerHTML.replace(t.html??"",o)||void 0,text:o,attribute:"__inner"})}case"set_outer_html":{const o=s.outerHTML,a=s.parentElement;if(!a)throw new Error("ORPHAN_ELEMENT: element has no parent — cannot replace outer HTML.");const c=this.doc.createComment(`mcpdom_undo_${e}`);s.replaceWith(c);const u=this.doc.createElement("template");u.innerHTML=t.html??"";const d=u.content.firstElementChild;return d?c.replaceWith(d):c.replaceWith(this.doc.createTextNode(t.html??"")),this.undoFor(e,i,n,{kind:"reinsert-node",outerHtml:o,parentSelector:this.snapshotState(a).selector,nextSiblingSelector:this.siblingSelector(d||s)})}case"add_class":{const o=Array.from(s.classList);for(const a of t.classes||[])s.classList.add(a);return this.undoFor(e,i,n,{kind:"restore-classes",classes:o})}case"remove_class":{const o=Array.from(s.classList);for(const a of t.classes||[])s.classList.remove(a);return this.undoFor(e,i,n,{kind:"restore-classes",classes:o})}case"replace_class":{const o=Array.from(s.classList);for(const a of t.classes||[])s.classList.remove(a);return t.value&&s.classList.add(t.value),this.undoFor(e,i,n,{kind:"restore-classes",classes:o})}case"set_style":{const o=this.doc.defaultView;if(!(o!=null&&o.getComputedStyle))throw new Error("STYLE_UNAVAILABLE: computed style API is unavailable in this context.");const a={};for(const c of Object.keys(t.style||{}))a[c]=o.getComputedStyle(s).getPropertyValue(c),s.style.setProperty(c,t.style[c]);return this.undoFor(e,i,n,{kind:"restore-style",style:a})}case"remove_style":{const o={};for(const a of t.classes||[])o[a]=s.style.getPropertyValue(a),s.style.removeProperty(a);return this.undoFor(e,i,n,{kind:"restore-style",style:o})}case"add_element":{const o=t.parent?this.resolveTarget(t.parent):s,a=this.doc.createElement("template");a.innerHTML=t.newElementHtml??"
";const c=a.content.firstElementChild;if(!c)throw new Error("INVALID_HTML: payload.newElementHtml does not produce an element.");switch(t.position||"append"){case"before":s.before(c);break;case"after":s.after(c);break;case"prepend":o.prepend(c);break;default:o.appendChild(c)}return this.undoFor(e,i,n,{kind:"remove-node",attribute:this.snapshotState(c).selector})}case"remove_element":{const o=s.outerHTML,a=s.parentElement,c=s.nextElementSibling;return s.remove(),this.undoFor(e,i,n,{kind:"reinsert-node",outerHtml:o,parentSelector:a?this.snapshotState(a).selector:void 0,nextSiblingSelector:c?this.snapshotState(c).selector:null})}case"replace_element":{const o=s.outerHTML,a=s.parentElement,c=this.doc.createElement("template");c.innerHTML=t.newElementHtml??"
";const u=c.content.firstElementChild;if(!u)throw new Error("INVALID_HTML: payload.newElementHtml does not produce an element.");const d=s.nextElementSibling;return s.replaceWith(u),this.undoFor(e,i,n,{kind:"reinsert-node",outerHtml:o,parentSelector:a?this.snapshotState(a).selector:void 0,nextSiblingSelector:d?this.snapshotState(d).selector:null})}case"move_element":{if(!t.parent)throw new Error("PARENT_REQUIRED: payload.parent is required for move_element.");const o=this.resolveTarget(t.parent),a=s.outerHTML,c=s.parentElement,u=s.nextElementSibling,d=t.position==="before"||t.position==="prepend"?o.firstElementChild:null;return o[t.position==="prepend"?"prepend":"appendChild"](s),this.undoFor(e,i,n,{kind:"restore-position",parentSelector:c?this.snapshotState(c).selector:void 0,nextSiblingSelector:u?this.snapshotState(u).selector:d?this.snapshotState(d).selector:null,outerHtml:a})}case"wrap_element":{const o=this.doc.createElement("template");o.innerHTML=t.newElementHtml||'
';const a=o.content.firstElementChild;if(!a)throw new Error("INVALID_HTML: wrapper template produced no element.");const c=s.parentElement,u=s.nextElementSibling;return s.replaceWith(a),a.appendChild(s),this.undoFor(e,i,n,{kind:"restore-position",parentSelector:c?this.snapshotState(c).selector:void 0,nextSiblingSelector:u?this.snapshotState(u).selector:null})}case"unwrap_element":{const o=s.outerHTML,a=s.parentElement;if(!a)throw new Error("ORPHAN_ELEMENT: cannot unwrap a root-level element.");const c=s.nextElementSibling,u=Array.from(s.children);for(const d of u)a.insertBefore(d,s);return s.remove(),this.undoFor(e,i,n,{kind:"reinsert-node",outerHtml:o,parentSelector:this.snapshotState(a).selector,nextSiblingSelector:c?this.snapshotState(c).selector:null})}case"clone_subtree":{const o=t.parent?this.resolveTarget(t.parent):s.parentElement||s,a=s.cloneNode(!0);if(t.copyAttributes!==!1)for(const c of Array.from(a.attributes))c.name==="id"&&a.removeAttribute("id");return(r=o.appendChild)==null||r.call(o,a),this.undoFor(e,i,n,{kind:"remove-node",attribute:this.snapshotState(a).selector})}default:throw new Error(`UNKNOWN_OPERATION: ${i} is not a supported DOM mutation.`)}}applyUndo(e){const t=e.inverse;switch(t.kind){case"restore-outer-html":{const s=this.resolveTarget({selector:e.targetSelector});if(t.outerHtml!==void 0){const n=this.doc.createElement("template");n.innerHTML=t.outerHtml;const i=n.content.firstElementChild;i&&s.replaceWith(i)}else t.attribute==="__inner"&&(s.innerHTML=t.text||"");break}case"reinsert-node":{const s=t.parentSelector?this.resolveTarget({selector:t.parentSelector}):this.doc.body,n=this.doc.createElement("template");n.innerHTML=t.outerHtml||"";const i=n.content.firstElementChild;if(!i)throw new Error("UNDO_CORRUPT: serialized subtree could not be restored.");const r=t.nextSiblingSelector?this.safeResolve(t.nextSiblingSelector):null;s.insertBefore(i,r);break}case"remove-node":{const s=this.safeResolve(t.attribute||e.targetSelector);s&&s.remove();break}case"restore-attribute":{this.resolveTarget({selector:e.targetSelector}).setAttribute(t.attribute,t.value??"");break}case"remove-attribute":{this.resolveTarget({selector:e.targetSelector}).removeAttribute(t.attribute);break}case"restore-text":{const s=this.resolveTarget({selector:e.targetSelector});s.textContent=t.text||"";break}case"restore-classes":{const s=this.resolveTarget({selector:e.targetSelector});s.removeAttribute("class");for(const n of t.classes||[])s.classList.add(n);break}case"restore-style":{const s=this.resolveTarget({selector:e.targetSelector});s.style.removeProperty("all");for(const[n,i]of Object.entries(t.style||{}))s.style.setProperty(n,i);break}case"restore-position":{const s=this.doc.createElement("template");s.innerHTML=t.outerHtml||"";const n=s.content.firstElementChild;if(!n)throw new Error("UNDO_CORRUPT: serialized subtree could not be restored.");const i=this.safeResolve(e.targetSelector);i&&i.remove();const r=t.parentSelector?this.safeResolve(t.parentSelector):this.doc.body,o=t.nextSiblingSelector?this.safeResolve(t.nextSiblingSelector):null;(r||this.doc.body).insertBefore(n,o);break}}}reapplyRecord(e,t,s){var i;const n=e.inverse;switch(e.operation){case"set_attribute":return(n.kind==="restore-attribute"||n.kind==="remove-attribute")&&s.value!==void 0?(t.setAttribute(s.attribute||n.attribute||"",s.value),!0):!1;case"add_class":{for(const r of s.classes||[])t.classList.add(r);return(((i=s.classes)==null?void 0:i.length)||0)>0}case"remove_class":{for(const r of s.classes||n.classes||[])t.classList.remove(r);return!0}case"set_text":return s.text!==void 0?(t.textContent=s.text,!0):!1;case"set_inner_html":return s.html!==void 0?(t.innerHTML=s.html,!0):!1;default:return!1}}resolveTarget(e){if(!e)throw new Error("TARGET_REQUIRED: mutation requires a target.");if(typeof e=="string"&&(e={selector:e}),e.selector){try{const t=this.doc.querySelectorAll(e.selector);if(t.length===1)return t[0];if(t.length>1)return Array.from(t).find(n=>{try{return L.inspectElement(n).visibility.isVisible}catch{return!1}})||t[0]}catch(t){throw new Error(`TARGET_INVALID: ${t.message}`)}throw new Error(`TARGET_NOT_FOUND: selector "${e.selector}" matches no element.`)}if(e.xpath){try{const s=this.doc.evaluate(e.xpath,this.doc,null,9,null).singleNodeValue;if(s)return s}catch(t){throw new Error(`TARGET_INVALID_XPATH: ${t.message}`)}throw new Error("TARGET_NOT_FOUND: xpath matches no element.")}if(typeof e.nodeId=="number"&&this.registry){const t=this.registry.getNode(e.nodeId);if(t&&t.nodeType===1&&this.doc.contains(t))return t;throw new Error("TARGET_STALE: logical node id no longer resolves to an attached element.")}throw new Error("TARGET_INVALID: target has neither selector, xpath nor nodeId.")}safeResolve(e){try{return this.doc.querySelector(e)}catch{return null}}snapshotState(e){const t=L.inspectElement(e,this.registry),s=e.outerHTML.length>2e4?e.outerHTML.slice(0,2e4)+"…[truncated]":e.outerHTML;return{selector:t.bestSelector,outerHtml:s,attributes:this.attrsOf(e)}}attrsOf(e){const t={};for(const s of Array.from(e.attributes))t[s.name]=s.value.length>300?s.value.slice(0,300)+"…":s.value;return t}quickDiff(e,t,s){if(!t)return null;let n=0,i=0,r=0;const o=new Set(Object.keys(e.attributes)),a=new Set(Object.keys(t.attributes||{}));for(const u of o)a.has(u)||i++;for(const u of a)o.has(u)?e.attributes[u]!==t.attributes[u]&&r++:n++;e.outerHtml!==t.outerHtml&&n+i+r===0&&r++;const c=s.querySelectorAll?s.querySelectorAll("*").length:0;return{added:n,removed:i,changed:r,summary:`attributes +${n}/-${i}/~${r}; subtree nodes: ${c}`}}undoFor(e,t,s,n){return{mutationId:e,operation:t,targetSelector:s,inverse:n}}siblingSelector(e){try{return this.snapshotState(e).selector}catch{return null}}pushHistory(e){this.history.push(e),this.history.length>ne&&this.history.splice(0,this.history.length-ne)}markHistory(e,t){for(let s=this.history.length-1;s>=0;s--)if(this.history[s].mutationId===e){t==="undo"?this.history[s].undoApplied=!0:this.history[s].redoApplied=!0;return}}summaryOf(e){var n;const t=((n=this.doc.documentElement)==null?void 0:n.outerHTML.length)||0,s=e.steps.filter(i=>i.mutation.success).length;return{domLength:t,diffSummary:`${s}/${e.steps.length} mutations applied`}}failure(e,t,s,n,i){var r;return{mutationId:e,operation:t.operation,success:!1,before:s||{selector:String(((r=t.target)==null?void 0:r.selector)||"?"),outerHtml:"",attributes:{}},after:null,diff:null,affectedSelector:null,durationMs:i,error:n,undoable:!1}}}function Be(l,e){switch(l.operation){case"set_attribute":return`attribute "${l.attribute}" will be set to "${(l.value??"").slice(0,40)}"`;case"remove_attribute":return`attribute "${l.attribute}" will be removed`;case"set_text":return`text content will be replaced (${(l.text||"").length} chars)`;case"replace_text":return`every occurrence of "${l.text}" will become "${l.replacement}"`;case"set_inner_html":return`inner HTML will be replaced (${(l.html||"").length} chars)`;case"set_outer_html":return"element (and subtree) will be replaced with provided HTML";case"add_class":return`classes ${(l.classes||[]).join(", ")} will be added`;case"remove_class":return`classes ${(l.classes||[]).join(", ")} will be removed`;case"replace_class":return`classes ${(l.classes||[]).join(", ")} will be replaced with "${l.value}"`;case"set_style":return`inline styles ${Object.keys(l.style||{}).join(", ")} will be set`;case"remove_style":return`inline styles ${(l.classes||[]).join(", ")} will be removed`;case"add_element":return`a new element will be inserted ${l.position||"append"} the target`;case"remove_element":return"the element and its subtree will be removed";case"replace_element":return"the element will be replaced with new HTML";case"move_element":return"the element will be moved into the specified parent";case"wrap_element":return"the element will be wrapped in a new container";case"unwrap_element":return"children will be lifted out and the wrapper removed";case"clone_subtree":return"a deep clone of the subtree will be appended";default:return"unknown operation"}}class Fe{constructor(){f(this,"executionCounter",0)}async execute(e,t,s={}){const n=Math.min(Math.max(s.timeoutMs??5e3,100),3e4),i=`js_${Date.now().toString(36)}_${++this.executionCounter}`,r=e.defaultView;if(!r)return this.result(i,"BLOCKED_BY_CONTEXT",0,t,[],{name:"NoWindow",message:"The document has no associated window — execution context unavailable."});const o=e.documentElement?e.documentElement.outerHTML.length:0,a=[],c=this.hookConsole(r,a);let u="EXECUTED_SUCCESSFULLY",d,h,p=o,y=!1;const v=Date.now();try{const b=this.buildRunner(r,t),T=new Promise((w,E)=>{var N;const C=setTimeout(()=>{y=!0,E(new Error(`Script timed out after ${n}ms`))},n);(N=C==null?void 0:C.unref)==null||N.call(C)});d=await Promise.race([b,T])}catch(b){y?u="TIMED_OUT":u="EXECUTED_WITH_ERROR",h={name:(b==null?void 0:b.name)||"Error",message:(b==null?void 0:b.message)||String(b),stack:b!=null&&b.stack?String(b.stack).slice(0,2e3):void 0}}const m=Date.now()-v;p=e.documentElement?e.documentElement.outerHTML.length:0,c();const g=this.serialize(d);return u==="EXECUTED_SUCCESSFULLY"&&g.serializationFailed&&(u="SERIALIZATION_FAILED",h={name:"SerializationError",message:g.message||"Result could not be serialized."}),{status:u,executionId:i,durationMs:m,result:u==="EXECUTED_SUCCESSFULLY"?g.text:void 0,error:h,consoleOutput:a.slice(0,100),domChanged:o!==p,domLengthBefore:o,domLengthAfter:p,world:s.world||"ISOLATED",timeoutMs:n,codePreview:t.length>300?t.slice(0,300)+"…":t}}buildRunner(e,t){const s=`(async function() { +`))}catch{}const c={id:this.sequenceCounter.generateEventId("con",i),sessionId:this.sessionId,timestamp:s,sequence:i,wallClockTime:n,type:`RUNTIME_CONSOLE_${e.toUpperCase()}`,category:e==="error"?"ERROR":"CONSOLE",source:"PAGE",payload:{level:e,args:r,formattedMessage:o,stackTrace:a}};this.callback(c)}instrumentGlobalErrors(){if(typeof window>"u")return;const e=t=>{var o,a;const s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.getWallClock(),i=this.sequenceCounter.nextSequence(),r={id:this.sequenceCounter.generateEventId("err",i),sessionId:this.sessionId,timestamp:s,sequence:i,wallClockTime:n,type:"RUNTIME_ERROR",category:"ERROR",source:"PAGE",payload:{message:t.message||"Unknown runtime error",filename:t.filename,lineno:t.lineno,colno:t.colno,stack:((o=t.error)==null?void 0:o.stack)||void 0,name:((a=t.error)==null?void 0:a.name)||"Error"}};this.callback(r)};window.addEventListener("error",e),this.cleanups.push(()=>window.removeEventListener("error",e))}instrumentUnhandledRejections(){if(typeof window>"u")return;const e=t=>{const s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.getWallClock(),i=this.sequenceCounter.nextSequence();let r="Unhandled Promise Rejection",o;if(t.reason instanceof Error)r=t.reason.message,o=t.reason.stack;else if(typeof t.reason=="string")r=t.reason;else if(t.reason)try{r=JSON.stringify(t.reason)}catch{r=String(t.reason)}const a={id:this.sequenceCounter.generateEventId("rej",i),sessionId:this.sessionId,timestamp:s,sequence:i,wallClockTime:n,type:"RUNTIME_UNHANDLED_REJECTION",category:"ERROR",source:"PAGE",payload:{message:r,stack:o,isUnhandledRejection:!0}};this.callback(a)};window.addEventListener("unhandledrejection",e),this.cleanups.push(()=>window.removeEventListener("unhandledrejection",e))}}class Re{constructor(e,t,s,n=""){b(this,"privacy");b(this,"sequenceCounter");b(this,"callback");b(this,"sessionId");b(this,"isInstrumented",!1);b(this,"originalFetch",null);b(this,"originalXHROpen",null);b(this,"originalXHRSend",null);b(this,"cleanups",[]);this.privacy=e,this.sequenceCounter=t,this.callback=s,this.sessionId=n}setSessionId(e){this.sessionId=e}start(){this.isInstrumented||typeof window>"u"||(this.isInstrumented=!0,this.cleanups=[],this.instrumentFetch(),this.instrumentXHR())}stop(){this.cleanups.forEach(e=>{try{e()}catch{}}),this.cleanups=[],this.isInstrumented=!1}instrumentFetch(){if(typeof window.fetch!="function")return;this.originalFetch=window.fetch;const e=this;window.fetch=async function(...t){const s=e.sequenceCounter.generateEventId("req_f"),n=t[0],i=t[1];let r="";typeof n=="string"?r=n:n instanceof URL?r=n.toString():n&&typeof n=="object"&&"url"in n&&(r=n.url);const o=((i==null?void 0:i.method)||(typeof n=="object"&&"method"in n?n.method:"GET")).toUpperCase(),a=e.privacy.sanitizeUrl(r),c=e.sequenceCounter.getRelativeTimestamp(),u=e.sequenceCounter.getWallClock(),h=e.sequenceCounter.nextSequence(),g={id:s,sessionId:e.sessionId,timestamp:c,sequence:h,wallClockTime:u,type:"NETWORK_REQUEST_START",category:"NETWORK",source:"PAGE",payload:{requestId:s,url:a,method:o,resourceType:"fetch",hasBody:!!(i!=null&&i.body)}};e.callback(g);try{const p=await e.originalFetch.apply(this,t),y=e.sequenceCounter.getRelativeTimestamp(),v=e.sequenceCounter.getWallClock(),m=e.sequenceCounter.nextSequence(),d=Math.max(0,Math.round((y-c)*100)/100),f={id:e.sequenceCounter.generateEventId("res_f",m),sessionId:e.sessionId,timestamp:y,sequence:m,wallClockTime:v,type:"NETWORK_RESPONSE_COMPLETE",category:"NETWORK",source:"PAGE",causality:{triggeredBy:s,precededBy:s},payload:{requestId:s,url:a,method:o,status:p.status,statusText:p.statusText,durationMs:d}};return e.callback(f),p}catch(p){const y=e.sequenceCounter.getRelativeTimestamp(),v=e.sequenceCounter.getWallClock(),m=e.sequenceCounter.nextSequence(),d=Math.max(0,Math.round((y-c)*100)/100),f={id:e.sequenceCounter.generateEventId("res_err",m),sessionId:e.sessionId,timestamp:y,sequence:m,wallClockTime:v,type:"NETWORK_REQUEST_FAILED",category:"NETWORK",source:"PAGE",causality:{triggeredBy:s,precededBy:s},payload:{requestId:s,url:a,method:o,status:0,statusText:"Failed",durationMs:d,error:(p==null?void 0:p.message)||"Network request failed"}};throw e.callback(f),p}},this.cleanups.push(()=>{this.originalFetch&&(window.fetch=this.originalFetch)})}instrumentXHR(){if(typeof XMLHttpRequest>"u")return;this.originalXHROpen=XMLHttpRequest.prototype.open,this.originalXHRSend=XMLHttpRequest.prototype.send;const e=this;XMLHttpRequest.prototype.open=function(t,s,...n){return this._forensicRequestId=e.sequenceCounter.generateEventId("req_x"),this._forensicMethod=(t||"GET").toUpperCase(),this._forensicUrl=typeof s=="string"?s:s.toString(),e.originalXHROpen.apply(this,[t,s,...n])},XMLHttpRequest.prototype.send=function(t){const s=this._forensicRequestId||e.sequenceCounter.generateEventId("req_x"),n=this._forensicMethod||"GET",i=e.privacy.sanitizeUrl(this._forensicUrl||""),r=e.sequenceCounter.getRelativeTimestamp(),o=e.sequenceCounter.getWallClock(),a=e.sequenceCounter.nextSequence();this._forensicStartTime=r;const c={id:s,sessionId:e.sessionId,timestamp:r,sequence:a,wallClockTime:o,type:"NETWORK_REQUEST_START",category:"NETWORK",source:"PAGE",payload:{requestId:s,url:i,method:n,resourceType:"xhr",hasBody:!!t}};e.callback(c);const u=()=>{const h=e.sequenceCounter.getRelativeTimestamp(),g=e.sequenceCounter.getWallClock(),p=e.sequenceCounter.nextSequence(),y=Math.max(0,Math.round((h-(this._forensicStartTime||r))*100)/100),v={id:e.sequenceCounter.generateEventId("res_x",p),sessionId:e.sessionId,timestamp:h,sequence:p,wallClockTime:g,type:this.status>=200&&this.status<400?"NETWORK_RESPONSE_COMPLETE":"NETWORK_REQUEST_FAILED",category:"NETWORK",source:"PAGE",causality:{triggeredBy:s,precededBy:s},payload:{requestId:s,url:i,method:n,status:this.status,statusText:this.statusText,durationMs:y,error:this.status===0?"XHR Network Error or Aborted":void 0}};e.callback(v)};return this.addEventListener("load",u),this.addEventListener("error",u),this.addEventListener("abort",u),e.originalXHRSend.apply(this,[t])},this.cleanups.push(()=>{this.originalXHROpen&&(XMLHttpRequest.prototype.open=this.originalXHROpen),this.originalXHRSend&&(XMLHttpRequest.prototype.send=this.originalXHRSend)})}}class Oe{constructor(e={}){b(this,"sequenceCounter");b(this,"registry");b(this,"privacy");b(this,"snapshotEngine");b(this,"mutationObserver");b(this,"eventCollector");b(this,"diagnostics");b(this,"networkMonitor");b(this,"metadata");b(this,"isRecording",!1);b(this,"isPaused",!1);b(this,"eventListeners",new Set);b(this,"checkpointListeners",new Set);b(this,"lastCheckpointSequence",0);b(this,"lastCheckpointTimestamp",0);b(this,"checkpointTimer",null);b(this,"checkpointIntervalEvents",200);b(this,"checkpointIntervalMs",3e4);this.sequenceCounter=new ne,this.registry=new H,this.privacy=new J(e.privacy),this.snapshotEngine=new he(this.registry,this.privacy,this.sequenceCounter);const t=n=>this.handleEvent(n);this.mutationObserver=new Ne(this.registry,this.privacy,this.sequenceCounter,this.snapshotEngine,t),this.eventCollector=new ke(this.registry,this.privacy,this.sequenceCounter,t),this.diagnostics=new Me(this.privacy,this.sequenceCounter,t),this.networkMonitor=new Re(this.privacy,this.sequenceCounter,t),e.checkpointIntervalEvents&&(this.checkpointIntervalEvents=e.checkpointIntervalEvents),e.checkpointIntervalMs&&(this.checkpointIntervalMs=e.checkpointIntervalMs);const s=e.sessionId||`session_${Date.now()}_${Math.random().toString(36).substring(2,7)}`;this.metadata=this.createInitialMetadata(s,e.sessionName)}getSessionId(){return this.metadata.id}getMetadata(){return{...this.metadata,durationMs:this.sequenceCounter.getRelativeTimestamp(),endTime:this.metadata.endTime||Date.now()}}getRegistry(){return this.registry}onEvent(e){return this.eventListeners.add(e),()=>this.eventListeners.delete(e)}onCheckpoint(e){return this.checkpointListeners.add(e),()=>this.checkpointListeners.delete(e)}start(e=typeof document<"u"?document:{}){if(this.isRecording)throw new Error(`Recorder session ${this.metadata.id} is already active`);this.sequenceCounter.reset(),this.registry.reset(),this.isRecording=!0,this.isPaused=!1,this.metadata.status="recording",this.metadata.startTime=Date.now(),this.mutationObserver.setSessionId(this.metadata.id),this.eventCollector.setSessionId(this.metadata.id),this.diagnostics.setSessionId(this.metadata.id),this.networkMonitor.setSessionId(this.metadata.id);const t=this.snapshotEngine.captureSnapshot(e,this.metadata.id);this.metadata.stats.nodeCount=t.totalNodeCount;const s={id:this.sequenceCounter.generateEventId("snap_init",t.sequence),sessionId:this.metadata.id,timestamp:t.timestamp,sequence:t.sequence,wallClockTime:Date.now(),type:"DOM_SNAPSHOT",category:"DOM",source:"PAGE",payload:{snapshot:t}};return this.createCheckpoint(t,"INITIAL"),this.mutationObserver.start(e),this.eventCollector.start(),this.diagnostics.start(),this.networkMonitor.start(),this.handleEvent(s),this.checkpointIntervalMs>0&&typeof setInterval<"u"&&(this.checkpointTimer=setInterval(()=>{this.isRecording&&!this.isPaused&&this.captureCheckpoint("PERIODIC",e)},this.checkpointIntervalMs)),t}stop(){return this.isRecording?(this.mutationObserver.takeRecords(),this.mutationObserver.stop(),this.eventCollector.stop(),this.diagnostics.stop(),this.networkMonitor.stop(),this.checkpointTimer&&(clearInterval(this.checkpointTimer),this.checkpointTimer=null),this.isRecording=!1,this.metadata.status="stopped",this.metadata.endTime=Date.now(),this.metadata.durationMs=this.sequenceCounter.getRelativeTimestamp(),this.getMetadata()):this.getMetadata()}pause(){!this.isRecording||this.isPaused||(this.isPaused=!0,this.metadata.status="paused")}resume(){!this.isRecording||!this.isPaused||(this.isPaused=!1,this.metadata.status="recording")}captureCheckpoint(e="MANUAL",t=document){if(!this.isRecording)return null;const s=this.snapshotEngine.captureSnapshot(t,this.metadata.id);return this.createCheckpoint(s,e)}recordCustomEvent(e,t,s,n){const i=this.sequenceCounter.getRelativeTimestamp(),r=this.sequenceCounter.getWallClock(),o=this.sequenceCounter.nextSequence(),a={id:this.sequenceCounter.generateEventId("ext",o),sessionId:this.metadata.id,timestamp:i,sequence:o,wallClockTime:r,type:e,category:"EXTENSION",source:"CONTENT_SCRIPT",targetNodeId:s,targetSelector:n,payload:t};return this.handleEvent(a),a}recordScreenshot(e,t="MANUAL"){const s=this.sequenceCounter.getRelativeTimestamp(),n=this.sequenceCounter.getWallClock(),i=this.sequenceCounter.nextSequence(),r={id:this.sequenceCounter.generateEventId("scr",i),sessionId:this.metadata.id,timestamp:s,sequence:i,wallClockTime:n,type:"SCREENSHOT_CHECKPOINT",category:"SCREENSHOT",source:"BROWSER_RUNTIME",payload:{screenshotId:`shot_${i}`,dataUrl:e,viewport:{width:typeof window<"u"?window.innerWidth:1920,height:typeof window<"u"?window.innerHeight:1080,scrollX:typeof window<"u"?window.scrollX:0,scrollY:typeof window<"u"?window.scrollY:0,devicePixelRatio:typeof window<"u"?window.devicePixelRatio:1},triggerReason:t}};return this.handleEvent(r),r}addAnnotation(e,t,s="AGENT",n){const i=this.sequenceCounter.getRelativeTimestamp(),r=this.sequenceCounter.nextSequence(),o={id:`ann_${r}_${Math.random().toString(36).substring(2,6)}`,sessionId:this.metadata.id,timestamp:i,sequence:r,nodeId:n,author:s,label:e,comment:t,createdAt:Date.now()},a={id:o.id,sessionId:this.metadata.id,timestamp:i,sequence:r,wallClockTime:Date.now(),type:"ANNOTATION",category:"ANNOTATION",source:s==="USER"?"USER_INTERACTION":"BROWSER_RUNTIME",targetNodeId:n,payload:{annotation:o}};return this.handleEvent(a),o}createCheckpoint(e,t){const s=this.sequenceCounter.getSequence()-this.lastCheckpointSequence;this.lastCheckpointSequence=this.sequenceCounter.getSequence(),this.lastCheckpointTimestamp=e.timestamp,this.metadata.stats.checkpointCount+=1;const n={checkpointId:`chk_${e.sequence}_${Date.now()}`,sessionId:this.metadata.id,timestamp:e.timestamp,sequence:e.sequence,wallClockTime:Date.now(),snapshot:e,eventIndex:this.metadata.stats.eventCount,eventsSinceLastCheckpoint:s,trigger:t},i={id:n.checkpointId,sessionId:this.metadata.id,timestamp:e.timestamp,sequence:e.sequence,wallClockTime:n.wallClockTime,type:"CHECKPOINT",category:"CHECKPOINT",source:"BROWSER_RUNTIME",payload:{checkpointId:n.checkpointId,snapshot:e,eventsSinceLastCheckpoint:s,totalEventsSoFar:this.metadata.stats.eventCount}};return this.checkpointListeners.forEach(r=>{try{r(n)}catch(o){console.error("[ForensicRecorder] Checkpoint listener error:",o)}}),this.handleEvent(i),n}handleEvent(e){this.isPaused&&e.type!=="CHECKPOINT"&&e.type!=="ANNOTATION"||(this.metadata.stats.eventCount+=1,e.category==="DOM"&&(this.metadata.stats.mutationCount+=1),e.category==="ERROR"&&(this.metadata.stats.errorCount+=1),e.category==="CONSOLE"&&(this.metadata.stats.consoleCount+=1),e.category==="NETWORK"&&(this.metadata.stats.networkCount+=1),e.category==="SCREENSHOT"&&(this.metadata.stats.screenshotCount+=1),this.isRecording&&e.type!=="CHECKPOINT"&&e.type!=="DOM_SNAPSHOT"&&this.sequenceCounter.getSequence()-this.lastCheckpointSequence>=this.checkpointIntervalEvents&&typeof document<"u"&&this.captureCheckpoint("PERIODIC"),this.eventListeners.forEach(t=>{try{t(e)}catch(s){console.error("[ForensicRecorder] Event listener error:",s)}}))}createInitialMetadata(e,t){const s={domRecording:typeof MutationObserver<"u"?"HEALTHY":"UNAVAILABLE",userEvents:typeof window<"u"?"HEALTHY":"UNAVAILABLE",console:typeof console<"u"?"HEALTHY":"UNAVAILABLE",network:typeof window<"u"&&typeof window.fetch<"u"?"HEALTHY":"PARTIAL",screenshots:"HEALTHY",shadowDom:typeof Element<"u"&&"attachShadow"in Element.prototype?"HEALTHY":"RESTRICTED",iframes:"PARTIAL"},n={eventCount:0,mutationCount:0,errorCount:0,consoleCount:0,networkCount:0,checkpointCount:0,screenshotCount:0,nodeCount:0};return{id:e,name:t||`Recording ${new Date().toLocaleTimeString()}`,url:typeof window<"u"?window.location.href:"about:blank",origin:typeof window<"u"?window.location.origin:"",title:typeof document<"u"?document.title:"Forensic Session",userAgent:typeof navigator<"u"?navigator.userAgent:"Node.js/ForensicAgent",schemaVersion:"2.0.0",recorderVersion:"2.0.0",extensionVersion:"2.0.0",startTime:Date.now(),status:"recording",health:s,stats:n}}}class k{static inspectPage(e=document){var n,i,r,o,a,c,u,h,g,p,y,v,m,d;const t=e.defaultView||(typeof window<"u"?window:{}),s=e.activeElement;return{url:((n=t.location)==null?void 0:n.href)||((i=e.location)==null?void 0:i.href)||"",title:e.title||"",origin:((r=t.location)==null?void 0:r.origin)||"",viewport:{width:t.innerWidth||((o=e.documentElement)==null?void 0:o.clientWidth)||1920,height:t.innerHeight||((a=e.documentElement)==null?void 0:a.clientHeight)||1080,scrollX:t.scrollX||t.pageXOffset||((c=e.documentElement)==null?void 0:c.scrollLeft)||0,scrollY:t.scrollY||t.pageYOffset||((u=e.documentElement)==null?void 0:u.scrollTop)||0,devicePixelRatio:t.devicePixelRatio||1},documentDimensions:{width:Math.max(((h=e.body)==null?void 0:h.scrollWidth)||0,((g=e.documentElement)==null?void 0:g.scrollWidth)||0),height:Math.max(((p=e.body)==null?void 0:p.scrollHeight)||0,((y=e.documentElement)==null?void 0:y.scrollHeight)||0)},activeElement:s?{tag:((v=s.tagName)==null?void 0:v.toLowerCase())||"",selector:this.computeBestSelector(s),text:(m=s.textContent)==null?void 0:m.slice(0,100).trim()}:void 0,focusedElement:typeof e.hasFocus=="function"&&e.hasFocus()&&s?{tag:((d=s.tagName)==null?void 0:d.toLowerCase())||"",selector:this.computeBestSelector(s)}:void 0,visibilityState:e.visibilityState||"visible",readyState:e.readyState||"complete",framesCount:e.querySelectorAll?e.querySelectorAll("iframe, frame").length:0}}static inspectElement(e,t){var xe,_e;const s=e.ownerDocument||document,n=s.defaultView||(typeof window<"u"?window:{}),i=e,r=e.tagName?e.tagName.toLowerCase():"element",o=this.extractClasses(e),{bestSelector:a,candidates:c}=this.generateSelectorCandidates(e),u={},h={};if(e.attributes)for(let V=0;V0||E.height>0||E.right>0||E.bottom>0,R=!C||E.right>0&&E.bottom>0&&E.left=L||E.top>=I),A=!P&&T!=="none"&&x!=="hidden"&&N>0&&R,se={disabled:i.disabled??e.hasAttribute("disabled"),readOnly:i.readOnly??e.hasAttribute("readonly"),checked:i.checked,selected:i.selected,focused:s.activeElement===e,isShadowHost:!!e.shadowRoot,hasShadowRoot:!!e.shadowRoot},z=[];let G=e.parentElement;for(;G&&G.tagName&&G.tagName.toLowerCase()!=="html";)z.push(this.computeBestSelector(G)),G=G.parentElement;const Ht={count:e.children?e.children.length:0,tags:e.children?Array.from(e.children).slice(0,10).map(V=>V.tagName.toLowerCase()):[]};let Ae;if(t){const V=t.getId(e);Ae={logicalNodeId:V??null,creationSequence:null,lastMutationSequence:null,eventCount:0,isRecorded:V!=null}}return{tag:r,id:e.id||void 0,classes:o,role:g||void 0,ariaAttributes:Object.keys(h).length>0?h:void 0,text:v.slice(0,200),normalizedText:m.slice(0,200),value:d,type:f.type||void 0,selector:a,bestSelector:a,selectorCandidates:c,bounds:E,visibility:{isVisible:A,display:T,visibility:x,opacity:N,pointerEvents:D,isClipped:P,isInViewport:R,zIndex:M},computedStyle:S?{display:T,visibility:x,opacity:String(N),position:S.position,zIndex:String(M),pointerEvents:D,overflow:S.overflow,boxSizing:S.boxSizing,color:S.color,backgroundColor:S.backgroundColor,fontSize:S.fontSize}:{},attributes:u,state:se,context:{parentChain:z,parentSelector:z[0]||void 0,childrenSummary:Ht,containingBlock:(S==null?void 0:S.position)==="fixed"?"viewport":z[0]||void 0,iframe:null,shadowRoot:e.shadowRoot?"open":null},forensics:Ae}}static inspectVisualState(e){var f,w;const t=e.ownerDocument||document,s=t.defaultView||(typeof window<"u"?window:{}),n=e.getBoundingClientRect?e.getBoundingClientRect():{x:0,y:0,width:0,height:0,top:0,right:0,bottom:0,left:0},i=s.getComputedStyle?s.getComputedStyle(e):null,r=s.innerWidth||((f=t.documentElement)==null?void 0:f.clientWidth)||1920,o=s.innerHeight||((w=t.documentElement)==null?void 0:w.clientHeight)||1080,a=s.scrollX||s.pageXOffset||0,c=s.scrollY||s.pageYOffset||0,u=s.devicePixelRatio||1,h=(i==null?void 0:i.display)||"block",g=(i==null?void 0:i.visibility)||"visible",p=i&&parseFloat(i.opacity)||1,y=n.right>0&&n.bottom>0&&n.left=r||n.top>=o;let d=null;if(t.elementFromPoint&&y&&!v&&h!=="none"){const E=Math.max(0,Math.min(r-1,n.left+n.width/2)),S=Math.max(0,Math.min(o-1,n.top+n.height/2));try{const T=t.elementFromPoint(E,S);T&&T!==e&&!e.contains(T)&&!T.contains(e)&&(d=this.computeBestSelector(T))}catch{}}return{selector:this.computeBestSelector(e),bounds:{x:n.x??n.left??0,y:n.y??n.top??0,width:n.width??0,height:n.height??0,top:n.top??0,right:n.right??0,bottom:n.bottom??0,left:n.left??0},viewport:{scrollX:a,scrollY:c,width:r,height:o,devicePixelRatio:u},layout:{display:h,position:(i==null?void 0:i.position)||"static",zIndex:(i==null?void 0:i.zIndex)||"auto",opacity:p,visibility:g,overflow:(i==null?void 0:i.overflow)||"visible",boxSizing:(i==null?void 0:i.boxSizing)||"content-box",pointerEvents:(i==null?void 0:i.pointerEvents)||"auto"},occlusion:{isInViewport:y,isClipped:v||m,isZeroDimension:v,isTransparent:p===0,isDisplayNone:h==="none",isVisibilityHidden:g==="hidden",isOffscreen:m,occludedBy:d},computedStyleSummary:i?{display:h,position:i.position,zIndex:i.zIndex,opacity:String(p),visibility:g,pointerEvents:i.pointerEvents}:{}}}static generateSelectorCandidates(e){const t=e.ownerDocument||document,s=e.tagName?e.tagName.toLowerCase():"element",n=[];if(e.id&&/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(e.id)){const c=`#${e.id}`;try{t.querySelectorAll&&t.querySelectorAll(c).length===1&&n.push(c)}catch{n.push(c)}}const i=["data-testid","data-test","data-id","data-qa","data-cy","aria-label","name"];for(const c of i){const u=e.getAttribute(c);if(u&&/^[a-zA-Z0-9_-]+$/.test(u)){const h=`${s}[${c}="${u}"]`;try{t.querySelectorAll&&t.querySelectorAll(h).length===1&&n.push(h)}catch{n.push(h)}}}const r=this.extractClasses(e).filter(c=>/^[a-zA-Z0-9_-]+$/.test(c)&&!c.startsWith("ng-")&&!c.startsWith("_ng"));if(r.length>0){const c=`${s}.${r.slice(0,3).join(".")}`;try{t.querySelectorAll&&t.querySelectorAll(c).length===1&&n.push(c)}catch{n.push(c)}}if(e.parentElement&&e.parentElement.children){const c=Array.from(e.parentElement.children).filter(u=>u.tagName&&u.tagName.toLowerCase()===s);if(c.length>1){const u=c.indexOf(e)+1;if(u>0){const h=this.computeBestSelector(e.parentElement);n.push(`${h} > ${s}:nth-of-type(${u})`)}}}const o=r.length>0?`${s}.${r[0]}`:s;return n.push(o),{bestSelector:n[0]||s,candidates:n}}static computeBestSelector(e){return this.generateSelectorCandidates(e).bestSelector}static extractClasses(e){return e.classList&&typeof e.classList.forEach=="function"?Array.from(e.classList):typeof e.className=="string"?e.className.split(/\s+/).filter(Boolean):e.className&&typeof e.className.baseVal=="string"?e.className.baseVal.split(/\s+/).filter(Boolean):[]}static inferImplicitRole(e){switch(e.tagName?e.tagName.toLowerCase():""){case"a":return e.hasAttribute("href")?"link":void 0;case"button":return"button";case"input":{const s=e.type||"text";return s==="button"||s==="submit"||s==="reset"?"button":s==="checkbox"?"checkbox":s==="radio"?"radio":"textbox"}case"select":return"combobox";case"textarea":return"textbox";case"nav":return"navigation";case"header":return"banner";case"footer":return"contentinfo";case"main":return"main";case"article":return"article";case"section":return"region";default:return}}}b(k,"privacyEngine",new J);class Le{constructor(e){b(this,"registry");b(this,"lastSelectedElementRef");b(this,"timingHook",null);b(this,"lastTrajectory",[]);this.registry=e}setLastSelectedElement(e){this.lastSelectedElementRef=e}setTimingHook(e){this.timingHook=e}getLastTrajectory(){return this.lastTrajectory}async timing(e){this.timingHook&&await this.timingHook(e)}resolveTarget(e,t=document){if(e.selectedElementRef&&this.lastSelectedElementRef&&t.contains(this.lastSelectedElementRef))return this.lastSelectedElementRef;if(typeof e.nodeId=="number"&&this.registry){const s=this.registry.getNode(e.nodeId);if(s&&s instanceof Element&&t.contains(s))return s}if(e.selector)try{const s=t.querySelectorAll(e.selector);if(s.length>1){for(let n=0;n{r+=w.length});try{h.observe(t.body||t.documentElement,{childList:!0,attributes:!0,characterData:!0,subtree:!0})}catch{}const g=w=>{o.push(w.message||"Runtime Error")};typeof window<"u"&&window.addEventListener("error",g);try{await this.dispatchAction(n,e)}finally{typeof window<"u"&&window.removeEventListener("error",g)}let p=!0;if((f=e.options)!=null&&f.waitForStabilization){const w=e.options.stabilizationTimeoutMs||300;await new Promise(E=>setTimeout(E,Math.min(2e3,w)))}h.disconnect();let y;t.contains(n)&&(y=k.inspectElement(n,this.registry));const v=Date.now()-s,m=a!=null&&a.__FORENSIC_CONSOLE_BUFFER__?a.__FORENSIC_CONSOLE_BUFFER__.slice(c).filter(w=>(w==null?void 0:w.level)==="error").length:0,d=a!=null&&a.__FORENSIC_NETWORK_BUFFER__?a.__FORENSIC_NETWORK_BUFFER__.slice(u).length:0;return{success:!0,action:e.action,target:y||i,beforeState:i,afterState:y,effects:{domMutations:r,consoleErrors:m,networkRequests:d,runtimeErrors:o},durationMs:v,stabilized:p}}async dispatchAction(e,t){var n,i,r,o,a,c;const s=e;switch(t.action){case"click":{this.scrollIntoViewIfNeeded(e),await this.timing("move"),await this.timing("click"),this.dispatchMouseEvent(e,"pointerdown"),this.dispatchMouseEvent(e,"mousedown"),typeof s.focus=="function"&&s.focus(),this.dispatchMouseEvent(e,"pointerup"),this.dispatchMouseEvent(e,"mouseup"),typeof s.click=="function"?s.click():this.dispatchMouseEvent(e,"click");break}case"double_click":{this.scrollIntoViewIfNeeded(e),await this.timing("click"),this.dispatchMouseEvent(e,"click"),await this.timing("click"),this.dispatchMouseEvent(e,"click"),this.dispatchMouseEvent(e,"dblclick");break}case"right_click":{this.scrollIntoViewIfNeeded(e),await this.timing("click"),this.dispatchMouseEvent(e,"pointerdown",{button:2}),this.dispatchMouseEvent(e,"mousedown",{button:2}),this.dispatchMouseEvent(e,"contextmenu",{button:2});break}case"hover":{await this.timing("move"),this.dispatchMouseEvent(e,"pointerenter"),this.dispatchMouseEvent(e,"mouseenter"),this.dispatchMouseEvent(e,"mouseover"),await this.timing("move"),this.dispatchMouseEvent(e,"mousemove");break}case"focus":{typeof s.focus=="function"&&s.focus(),e.dispatchEvent(new FocusEvent("focus",{bubbles:!0}));break}case"blur":{typeof s.blur=="function"&&s.blur(),e.dispatchEvent(new FocusEvent("blur",{bubbles:!0}));break}case"type":{const u=t.text||"",h=e,g=((n=e.ownerDocument)==null?void 0:n.defaultView)||(typeof window<"u"?window:null);typeof s.focus=="function"&&s.focus();for(const y of u){await this.timing("type");const v=d=>{try{const w=(g==null?void 0:g.KeyboardEvent)||(typeof KeyboardEvent<"u"?KeyboardEvent:null);if(w)return new w(d,{key:y,bubbles:!0})}catch{}const f=(g==null?void 0:g.CustomEvent)||(g==null?void 0:g.Event)||CustomEvent;return new f(d,{bubbles:!0,cancelable:!0})},m=(d,f)=>{try{const E=(g==null?void 0:g.InputEvent)||(typeof InputEvent<"u"?InputEvent:null);if(E)return new E(d,f)}catch{}const w=(g==null?void 0:g.CustomEvent)||(g==null?void 0:g.Event)||CustomEvent;return new w(d,{bubbles:!0,cancelable:!0})};e.dispatchEvent(v("keydown")),e.dispatchEvent(v("keypress")),"value"in h&&(h.value=(h.value||"")+y),e.dispatchEvent(m("input",{data:y,inputType:"insertText",bubbles:!0})),e.dispatchEvent(v("keyup"))}const p=(g==null?void 0:g.Event)||Event;e.dispatchEvent(new p("change",{bubbles:!0}));break}case"clear":{const u=e,h=((i=e.ownerDocument)==null?void 0:i.defaultView)||(typeof window<"u"?window:null);if("value"in u){u.value="";const g=(y,v)=>{try{const d=(h==null?void 0:h.InputEvent)||(typeof InputEvent<"u"?InputEvent:null);if(d)return new d(y,v)}catch{}const m=(h==null?void 0:h.CustomEvent)||(h==null?void 0:h.Event)||CustomEvent;return new m(y,{bubbles:!0,cancelable:!0})};e.dispatchEvent(g("input",{inputType:"deleteContentBackward",bubbles:!0}));const p=(h==null?void 0:h.Event)||Event;e.dispatchEvent(new p("change",{bubbles:!0}))}break}case"press_key":{const u=t.key||"Enter",h=((r=e.ownerDocument)==null?void 0:r.defaultView)||(typeof window<"u"?window:null),g=p=>{try{const v=(h==null?void 0:h.KeyboardEvent)||(typeof KeyboardEvent<"u"?KeyboardEvent:null);if(v)return new v(p,{key:u,bubbles:!0})}catch{}const y=(h==null?void 0:h.CustomEvent)||(h==null?void 0:h.Event)||CustomEvent;return new y(p,{bubbles:!0,cancelable:!0})};e.dispatchEvent(g("keydown")),e.dispatchEvent(g("keypress")),e.dispatchEvent(g("keyup"));break}case"select_option":{const u=e;((o=u.tagName)==null?void 0:o.toLowerCase())==="select"&&t.optionValue&&(u.value=t.optionValue,e.dispatchEvent(new Event("change",{bubbles:!0})));break}case"scroll_into_view":{this.scrollIntoViewIfNeeded(e,!0);break}case"scroll":{const u=((a=t.scrollDelta)==null?void 0:a.x)||0,h=((c=t.scrollDelta)==null?void 0:c.y)||0;typeof e.scrollBy=="function"&&e.scrollBy(u,h);break}default:throw new Error(`Unsupported interaction action: ${t.action}`)}}scrollIntoViewIfNeeded(e,t=!1){if(typeof e.scrollIntoView=="function")try{e.scrollIntoView({behavior:"auto",block:"center",inline:"center"})}catch{e.scrollIntoView(t)}}dispatchMouseEvent(e,t,s={}){const n=e.getBoundingClientRect?e.getBoundingClientRect():{left:0,top:0,width:0,height:0},i=n.left+n.width/2,r=n.top+n.height/2,o=new MouseEvent(t,{bubbles:s.bubbles!==void 0?s.bubbles:!0,cancelable:s.cancelable!==void 0?s.cancelable:!0,clientX:i,clientY:r,button:s.button||0,buttons:s.button===2?2:1});e.dispatchEvent(o)}}class ie{static matches(e,t){if(!e||e.nodeType!==$.ELEMENT_NODE)return!1;const s=t.trim();return s?s.includes(",")?s.split(",").some(n=>this.matchesSimple(e,n.trim())):this.matchesCompound(e,s):!1}static querySelector(e,t,s){const n=this.querySelectorAll(e,t,s,1);return n.length>0?n[0]:null}static querySelectorAll(e,t,s,n=1/0){const i=[],r=s[t];if(!r)return i;const o=[...r.children||[]],a=new Set;for(;o.length>0&&i.length=n))break;u.children&&u.children.length>0&&o.push(...u.children)}}return i}static getElementById(e,t){for(const s of Object.values(t))if(s.nodeType===$.ELEMENT_NODE&&!s.isDetached&&s.attributes&&s.attributes.id===e&&this.isNodeConnected(s,t))return s;return null}static isNodeConnected(e,t){if(e.isDetached)return!1;let s=e;const n=new Set;for(;s&&s.parentId;){if(n.has(s.id))return!1;n.add(s.id);const i=t[s.parentId];if(!i||i.isDetached)return!1;s=i}return!0}static computeSelector(e,t){var r,o;if(!e)return"";if(e.nodeType!==$.ELEMENT_NODE)return e.tagName||`#node-${e.id}`;if((r=e.attributes)!=null&&r.id)return`#${e.attributes.id}`;const s=e.tagName||"div",n=(((o=e.attributes)==null?void 0:o.class)||"").split(/\s+/).filter(a=>a&&!a.startsWith("ng-")).slice(0,2),i=n.length>0?"."+n.join("."):"";if(e.parentId&&t[e.parentId]){const c=(t[e.parentId].children||[]).map(u=>t[u]).filter(u=>u&&u.nodeType===$.ELEMENT_NODE&&u.tagName===s);if(c.length>1){const u=c.findIndex(h=>h.id===e.id)+1;return`${s}${i}:nth-of-type(${u})`}}return`${s}${i}`}static matchesCompound(e,t){return this.matchesSimple(e,t)}static matchesSimple(e,t){var i,r,o,a,c,u,h;const s=((i=e.tagName)==null?void 0:i.toLowerCase())||"";if(t==="*")return!0;if(t.startsWith("#")){const g=t.substring(1);return((r=e.attributes)==null?void 0:r.id)===g}if(t.startsWith(".")){const g=t.substring(1);return(((o=e.attributes)==null?void 0:o.class)||"").split(/\s+/).includes(g)}if(t.startsWith("[")&&t.endsWith("]")){const g=t.substring(1,t.length-1);if(g.includes("=")){const[p,y]=g.split("="),v=y.replace(/^["']|["']$/g,"");return((a=e.attributes)==null?void 0:a[p.trim()])===v}return!!((c=e.attributes)!=null&&c[g.trim()])}const n=t.match(/^([a-zA-Z0-9_-]+)(.*)$/);if(n){const g=n[1].toLowerCase(),p=n[2];if(g!==s&&g!=="*")return!1;if(!p)return!0;if(p.startsWith("#"))return((u=e.attributes)==null?void 0:u.id)===p.substring(1);if(p.startsWith("."))return(((h=e.attributes)==null?void 0:h.class)||"").split(/\s+/).includes(p.substring(1));if(p.startsWith("["))return this.matchesSimple(e,p)}return!1}}class De{static traceElement(e,t,s){var M,L;const n=[...t].sort((I,C)=>I.sequence-C.sequence);let i=e.nodeId,r="unknown",o=e.selector||"",a={},c=0,u=0,h="init";if(!i&&e.selector&&s){const I=ie.querySelector(e.selector,s.rootId,s.nodes);I&&(i=I.id,r=I.tagName||"element",a={...I.attributes||{}},o=e.selector)}if(!i&&e.selector){for(const I of n)if(I.type==="DOM_MUTATION_ADD"){const C=I.payload;if(C.node&&ie.matches(C.node,e.selector)){i=C.node.id,r=C.node.tagName||"element",a={...C.node.attributes||{}},c=I.timestamp,u=I.sequence,h=I.id;break}}}if(!i)return null;const g=[];let p=!0,y=null,v=null,m,d=0;if(s&&s.nodes[i]){const I=s.nodes[i];r=I.tagName||r,a={...I.attributes||{}},o||(o=ie.computeSelector(I,s.nodes)),g.push({timestamp:s.timestamp,sequence:s.sequence,wallClockTime:Date.now(),stage:"CREATED",eventId:s.snapshotId,eventType:"DOM_SNAPSHOT",description:`Element <${r}> existed in initial baseline snapshot [ID: ${i}]`,details:{initialParentId:I.parentId,attributes:a},nodeSnapshot:I})}const f=new Map;if(s)for(const[I,C]of Object.entries(s.nodes))f.set(Number(I),C.parentId??null);const w=(I,C)=>{let R=f.get(C);const P=new Set;for(;R&&!P.has(R);){if(R===I)return!0;P.add(R),R=f.get(R)}return!1};for(const I of n){const C=I.timestamp,R=I.sequence,P=I.wallClockTime;if(I.type==="DOM_MUTATION_ADD"){const A=I.payload;(M=A.node)!=null&&M.id&&f.set(A.node.id,A.parentId??null),((L=A.node)==null?void 0:L.id)===i&&(p=!0,r=A.node.tagName||r,c=C,u=R,h=I.id,a={...A.node.attributes||{}},g.push({timestamp:C,sequence:R,wallClockTime:P,stage:"ATTACHED_TO_DOM",eventId:I.id,eventType:I.type,description:`Element <${r}> added to DOM under parent ID ${A.parentId}`,details:{parentId:A.parentId,index:A.index},nodeSnapshot:A.node}))}if(I.type==="DOM_MUTATION_REMOVE"){const A=I.payload;A.nodeId===i?(p=!1,y=C,v=R,m=I.id,g.push({timestamp:C,sequence:R,wallClockTime:P,stage:"REMOVED_FROM_DOM",eventId:I.id,eventType:I.type,description:`Element <${r}> explicitly removed from parent ID ${A.parentId}`,details:{parentId:A.parentId,removedIndex:A.index}})):w(A.nodeId,i)&&(p=!1,y=C,v=R,m=I.id,g.push({timestamp:C,sequence:R,wallClockTime:P,stage:"PARENT_SUBTREE_REPLACED",eventId:I.id,eventType:I.type,description:`Ancestor element [ID: ${A.nodeId}] was removed, causing target element [ID: ${i}] to detach from DOM`,details:{removedAncestorId:A.nodeId,parentId:A.parentId}}))}if(I.type==="DOM_MUTATION_MOVE"){const A=I.payload;A.nodeId&&f.set(A.nodeId,A.newParentId??null),A.nodeId===i&&(d++,g.push({timestamp:C,sequence:R,wallClockTime:P,stage:"REPARENTED",eventId:I.id,eventType:I.type,description:`Element reparented from parent ${A.oldParentId} to ${A.newParentId}`,details:{oldParentId:A.oldParentId,newParentId:A.newParentId}}))}if(I.type==="DOM_MUTATION_ATTR"){const A=I.payload;if(A.nodeId===i){d++;const se=A.attributeName.toLowerCase();let z="ATTRIBUTE_MODIFIED";se==="class"&&(z="CLASS_MODIFIED"),se==="style"&&(z="STYLE_MODIFIED"),g.push({timestamp:C,sequence:R,wallClockTime:P,stage:z,eventId:I.id,eventType:I.type,description:`Attribute '${A.attributeName}' changed from '${A.oldValue??""}' to '${A.newValue??""}'`,details:{attributeName:A.attributeName,oldValue:A.oldValue,newValue:A.newValue}})}}if(I.type==="DOM_MUTATION_TEXT"){const A=I.payload;A.nodeId===i&&(d++,g.push({timestamp:C,sequence:R,wallClockTime:P,stage:"TEXT_MODIFIED",eventId:I.id,eventType:I.type,description:`Text content changed: "${A.oldText}" → "${A.newText}"`,details:{oldText:A.oldText,newText:A.newText}}))}}const E=y??c,S=500,T=n.filter(I=>(I.category==="ERROR"||I.category==="CONSOLE")&&Math.abs(I.timestamp-E)<=S),x=n.filter(I=>I.category==="NETWORK"&&Math.abs(I.timestamp-E)<=S),N=n.length>0?n[n.length-1].timestamp:c,D=Math.max(0,(y??N)-c);return{targetNodeId:i,tagName:r,selectorHint:o,initialAttributes:a,createdAt:c,createdSequence:u,createdEventId:h,removedAt:y,removedSequence:v,removedEventId:m,isCurrentlyAlive:p,lifespanMs:Math.round(D*100)/100,mutationCount:d,entries:g,correlatedDiagnostics:T,correlatedNetwork:x}}}class $e{static analyze(e,t,s){var D,M,L,I;const n=typeof e=="number"?{nodeId:e}:{selector:e},i=De.traceElement(n,t,s);if(!i)return{targetQuery:e,found:!1,disappearanceMechanism:"UNKNOWN",likelyRootCause:"Target element could not be found in recording baseline or event stream",confidenceScore:0,detailedExplanation:`No element matching "${e}" was ever created, recorded in the initial DOM snapshot, or observed in mutation events.`,evidentiaryTrail:[],precedingEvents:[],followingEvents:[],correlatedErrors:[],correlatedNetworkCalls:[],alternativeHypotheses:[{hypothesis:"Element was injected into an unmonitored isolated iframe or ShadowRoot closed mode",likelihood:40,evidenceFor:["Element query yielded zero matches in monitored document"],evidenceAgainst:["Iframes/ShadowRoots were accessible in this session"]},{hypothesis:"Selector typo or timing mismatch",likelihood:60,evidenceFor:["Target selector did not match any recorded tag or class"],evidenceAgainst:[]}]};const r=[...t].sort((C,R)=>C.sequence-R.sequence),o=[],a=[];let c="UNKNOWN",u="Unknown disappearance mechanism",h=50,g="",p=i.removedAt??void 0;const y=i.entries.find(C=>C.stage==="REMOVED_FROM_DOM"),v=i.entries.find(C=>C.stage==="PARENT_SUBTREE_REPLACED"),m=i.entries.find(C=>C.stage==="CLASS_MODIFIED"&&/\b(hidden|hide|d-none|invisible|collapsed)\b/i.test(String(C.details.newValue||""))),d=i.entries.find(C=>C.stage==="STYLE_MODIFIED"&&/display\s*:\s*none|visibility\s*:\s*hidden|opacity\s*:\s*0/i.test(String(C.details.newValue||"")));y?(c="DIRECT_NODE_REMOVAL",p=y.timestamp,u=`Element [ID: ${i.targetNodeId}] <${i.tagName}> was directly removed from its parent [ID: ${y.details.parentId}] via DOM removeChild/replaceChild`,h=95,o.push({timestamp:y.timestamp,sequence:y.sequence,eventId:y.eventId,eventType:y.eventType,evidenceType:"DIRECT",description:`Direct DOM removal mutation: element detached from parent ID ${y.details.parentId}`,confidenceContribution:50})):v?(c="PARENT_SUBTREE_REPLACED",p=v.timestamp,u=`Host framework (e.g. React/Vue re-render) destroyed and replaced Ancestor container [ID: ${v.details.removedAncestorId}], causing injected element to be unmounted`,h=92,o.push({timestamp:v.timestamp,sequence:v.sequence,eventId:v.eventId,eventType:v.eventType,evidenceType:"DIRECT",description:`Ancestor container [ID: ${v.details.removedAncestorId}] was removed, wiping out all child subtrees`,confidenceContribution:50})):d?(c="STYLE_DISPLAY_NONE",p=d.timestamp,u=`Element was visually hidden by an inline style modification: "${d.details.newValue}"`,h=88,o.push({timestamp:d.timestamp,sequence:d.sequence,eventId:d.eventId,eventType:d.eventType,evidenceType:"DIRECT",description:`Inline style changed to "${d.details.newValue}"`,confidenceContribution:45})):m?(c="CLASS_TRIGGERED_HIDDEN",p=m.timestamp,u=`Element was visually hidden because its CSS class list was modified to include "${m.details.newValue}"`,h=85,o.push({timestamp:m.timestamp,sequence:m.sequence,eventId:m.eventId,eventType:m.eventType,evidenceType:"DIRECT",description:`Class list changed from "${m.details.oldValue??""}" to "${m.details.newValue??""}"`,confidenceContribution:45})):i.isCurrentlyAlive&&(c="UNKNOWN",u=`Element [ID: ${i.targetNodeId}] is currently alive and attached to the DOM tree (no unmount mutation detected)`,h=70,g="The element exists in the current DOM state. If it is not visible on screen, it may be clipped by viewport boundaries, z-index stacking context, or 0x0 pixel dimensions.");const f=p??i.createdAt,w=500,E=r.filter(C=>C.timestamp>=f-w&&C.timestampC.timestamp>f&&C.timestamp<=f+w),T=E.filter(C=>C.category==="ERROR");if(T.length>0){const C=T[0],R=((D=C.payload)==null?void 0:D.message)||"Unknown runtime error";o.push({timestamp:C.timestamp,sequence:C.sequence,eventId:C.id,eventType:C.type,evidenceType:"PRECEDING",description:`Runtime error occurred ${(f-C.timestamp).toFixed(1)}ms before disappearance: "${R}"`,confidenceContribution:20,rawEvent:C}),u+=` (preceded by runtime error: "${R}")`}const x=E.filter(C=>C.type==="NETWORK_RESPONSE_COMPLETE"||C.type==="NETWORK_REQUEST_FAILED");if(x.length>0){const C=x[0],R=((M=C.payload)==null?void 0:M.url)||"network request";o.push({timestamp:C.timestamp,sequence:C.sequence,eventId:C.id,eventType:C.type,evidenceType:"PRECEDING",description:`Network response completed ${(f-C.timestamp).toFixed(1)}ms before disappearance: ${R}`,confidenceContribution:15,rawEvent:C})}const N=E.filter(C=>C.category==="NAVIGATION");if(N.length>0){const C=N[0];o.push({timestamp:C.timestamp,sequence:C.sequence,eventId:C.id,eventType:C.type,evidenceType:"PRECEDING",description:`Navigation event (${(L=C.payload)==null?void 0:L.navigationType}) occurred ${(f-C.timestamp).toFixed(1)}ms before disappearance`,confidenceContribution:25,rawEvent:C}),u+=` following SPA navigation to "${(I=C.payload)==null?void 0:I.url}"`}return g||(g=[`Element <${i.tagName}> (Logical ID: ${i.targetNodeId}, selector: "${i.selectorHint}") was created at ${i.createdAt.toFixed(1)}ms.`,`It remained alive in the DOM for ${i.lifespanMs.toFixed(1)}ms and experienced ${i.mutationCount} mutations.`,`At timestamp ${f.toFixed(1)}ms, it disappeared via [${c}].`,`Diagnosis: ${u}.`].join(" ")),c==="PARENT_SUBTREE_REPLACED"?(a.push({hypothesis:"Direct cleanup called by extension code",likelihood:25,evidenceFor:["Element was unmounted shortly after creation"],evidenceAgainst:["Ancestor container mutation was recorded from host page context"]}),a.push({hypothesis:"Host single-page app route change destroyed component tree",likelihood:35,evidenceFor:N.length>0?["Preceding navigation event recorded"]:[],evidenceAgainst:N.length===0?["No navigation events occurred in temporal window"]:[]})):c==="DIRECT_NODE_REMOVAL"&&a.push({hypothesis:"Third-party script or ad-blocker removed the injected node",likelihood:30,evidenceFor:["Direct node removal occurred without ancestor replacement"],evidenceAgainst:["No ad-blocker signatures or extension error logs observed"]}),{targetQuery:e,targetNodeId:i.targetNodeId,found:!0,tagName:i.tagName,selectorHint:i.selectorHint,createdAt:i.createdAt,firstVisibleAt:i.createdAt,lastKnownGoodStateAt:Math.max(0,f-1),disappearedAt:p,lifespanMs:i.lifespanMs,disappearanceMechanism:c,likelyRootCause:u,confidenceScore:Math.min(99,h),detailedExplanation:g,evidentiaryTrail:o,precedingEvents:E,followingEvents:S,correlatedErrors:T,correlatedNetworkCalls:x,alternativeHypotheses:a}}}class qe{constructor(e){b(this,"activeObservation",null);b(this,"registry");b(this,"sequenceCounter");this.registry=e,this.sequenceCounter=new ne}isObserving(){return this.activeObservation!==null}startObservation(e,t=document){this.activeObservation&&this.stopObservation(t);const s=`obs_${Date.now()}_${Math.random().toString(36).slice(2,6)}`,n=Date.now(),i=k.inspectElement(e,this.registry),r=i.bestSelector,o=[],a=this.registry?this.registry.getOrCreateId(e,0):100;o.push({id:`evt_init_${s}`,sessionId:s,timestamp:0,sequence:1,wallClockTime:n,type:"DOM_MUTATION_ADD",category:"DOM",source:"BROWSER_RUNTIME",targetNodeId:a,targetSelector:r,payload:{node:{id:a,nodeType:1,tagName:i.tag,attributes:i.attributes,textContent:i.text,children:[],parentId:null},parentId:null,index:0}});const c=new MutationObserver(u=>{const h=Date.now()-n;for(const g of u)if(g.type==="childList"){for(let p=0;p0&&(m=$e.analyze(n,a)),{observationId:t,targetSelector:n,targetNodeId:((d=r.forensics)==null?void 0:d.logicalNodeId)||void 0,startTime:i,endTime:u,durationMs:h,initialState:r,finalState:p,disappeared:y,disappearanceReason:v,mutations:a.filter(f=>f.category==="DOM"),diagnostics:a.filter(f=>f.category==="ERROR"||f.category==="CONSOLE"),networkEvents:a.filter(f=>f.category==="NETWORK"),screenshots:c,correlationReport:m}}}class Pe{constructor(e={}){b(this,"isExplicitModeActive",!1);b(this,"isGlobalShortcutActive",!1);b(this,"highlighterEl",null);b(this,"badgeEl",null);b(this,"lastSelectedElement",null);b(this,"options",{});b(this,"onMouseMoveBound");b(this,"onClickBound");b(this,"onKeyDownBound");b(this,"onGlobalClickBound");this.options=e,this.onMouseMoveBound=this.handleMouseMove.bind(this),this.onClickBound=this.handleClick.bind(this),this.onKeyDownBound=this.handleKeyDown.bind(this),this.onGlobalClickBound=this.handleGlobalCtrlShiftClick.bind(this),this.initGlobalShortcutListener()}initGlobalShortcutListener(){typeof window>"u"||this.isGlobalShortcutActive||(window.addEventListener("click",this.onGlobalClickBound,!0),this.isGlobalShortcutActive=!0)}startPicker(e){typeof document>"u"||(e&&(this.options={...this.options,...e}),!this.isExplicitModeActive&&(this.isExplicitModeActive=!0,this.ensureHighlighter(),document.body&&(document.body.style.cursor="crosshair"),window.addEventListener("mousemove",this.onMouseMoveBound,!0),window.addEventListener("click",this.onClickBound,!0),window.addEventListener("keydown",this.onKeyDownBound,!0)))}stopPicker(){this.isExplicitModeActive&&(this.isExplicitModeActive=!1,typeof document<"u"&&document.body&&(document.body.style.cursor="default"),this.removeHighlighter(),typeof window<"u"&&(window.removeEventListener("mousemove",this.onMouseMoveBound,!0),window.removeEventListener("click",this.onClickBound,!0),window.removeEventListener("keydown",this.onKeyDownBound,!0)))}getLastSelectedElement(){return this.lastSelectedElement}setSelectedElement(e){let t;return"tag"in e&&"bestSelector"in e&&typeof e.getAttribute!="function"?t=e:(t=k.inspectElement(e,this.options.nodeRegistry),this.flashSelection(e)),this.lastSelectedElement=t,this.options.onSelected&&this.options.onSelected(t),t}handleGlobalCtrlShiftClick(e){if(!e.ctrlKey||!e.shiftKey)return;const t=e.target;if(!t||this.isExtensionOwned(t))return;e.preventDefault(),e.stopPropagation(),e.stopImmediatePropagation();const s=this.setSelectedElement(t);this.notifyExtension(s)}handleMouseMove(e){if(!this.isExplicitModeActive)return;const t=e.target;if(!t||this.isExtensionOwned(t)){this.hideHighlighter();return}this.updateHighlighter(t)}handleClick(e){if(!this.isExplicitModeActive)return;const t=e.target;if(!t||this.isExtensionOwned(t))return;e.preventDefault(),e.stopPropagation(),e.stopImmediatePropagation();const s=this.setSelectedElement(t);this.notifyExtension(s),this.stopPicker()}handleKeyDown(e){e.key==="Escape"&&this.isExplicitModeActive&&(e.preventDefault(),this.stopPicker(),this.options.onCanceled&&this.options.onCanceled())}isExtensionOwned(e){return!!(e.id==="forensic-recorder-floating-host"||e.id==="forensic-inspect-highlighter"||e.closest("#forensic-recorder-floating-host")||e.closest("#forensic-inspect-highlighter")||e.hasAttribute("data-forensic-internal")||e.closest("[data-forensic-internal]"))}ensureHighlighter(){if(typeof document>"u"||this.highlighterEl)return;const e=this.options.highlightColor||"#0ea5e9",t=document.createElement("div");t.id="forensic-inspect-highlighter",t.setAttribute("data-forensic-internal","true"),t.style.position="fixed",t.style.pointerEvents="none",t.style.zIndex="2147483640",t.style.border=`2px solid ${e}`,t.style.background="rgba(14, 165, 233, 0.18)",t.style.borderRadius="3px",t.style.boxShadow=`0 0 12px ${e}88`,t.style.transition="all 0.05s ease-out",t.style.display="none";const s=document.createElement("div");s.setAttribute("data-forensic-internal","true"),s.style.position="absolute",s.style.bottom="100%",s.style.left="0",s.style.transform="translateY(-4px)",s.style.background="#0f172a",s.style.color="#38bdf8",s.style.fontSize="11px",s.style.fontFamily="monospace",s.style.fontWeight="bold",s.style.padding="2px 6px",s.style.borderRadius="3px",s.style.boxShadow="0 2px 6px rgba(0,0,0,0.5)",s.style.whiteSpace="nowrap",s.style.pointerEvents="none",t.appendChild(s),document.body.appendChild(t),this.highlighterEl=t,this.badgeEl=s}updateHighlighter(e){if(this.ensureHighlighter(),!this.highlighterEl||!this.badgeEl)return;const t=e.getBoundingClientRect();this.highlighterEl.style.display="block",this.highlighterEl.style.left=`${t.left}px`,this.highlighterEl.style.top=`${t.top}px`,this.highlighterEl.style.width=`${Math.max(1,t.width)}px`,this.highlighterEl.style.height=`${Math.max(1,t.height)}px`;const s=e.tagName.toLowerCase(),n=e.id?`#${e.id}`:"",i=e.className&&typeof e.className=="string"?"."+e.className.split(/\s+/)[0]:"",r=`${Math.round(t.width)}×${Math.round(t.height)}`;this.badgeEl.textContent=`<${s}${n}${i}> [${r}]`}hideHighlighter(){this.highlighterEl&&(this.highlighterEl.style.display="none")}removeHighlighter(){this.highlighterEl&&this.highlighterEl.parentElement&&this.highlighterEl.remove(),this.highlighterEl=null,this.badgeEl=null}flashSelection(e){if(typeof document>"u"||!e.getBoundingClientRect)return;const t=e.getBoundingClientRect(),s=document.createElement("div");s.setAttribute("data-forensic-internal","true"),s.style.position="fixed",s.style.left=`${t.left}px`,s.style.top=`${t.top}px`,s.style.width=`${Math.max(1,t.width)}px`,s.style.height=`${Math.max(1,t.height)}px`,s.style.border="2px solid #22c55e",s.style.background="rgba(34, 197, 94, 0.25)",s.style.zIndex="2147483645",s.style.pointerEvents="none",s.style.transition="opacity 0.6s ease-out",document.body.appendChild(s),setTimeout(()=>{s.style.opacity="0",setTimeout(()=>s.remove(),600)},400)}notifyExtension(e){var t;try{typeof chrome<"u"&&((t=chrome.runtime)!=null&&t.sendMessage)&&chrome.runtime.sendMessage({type:"ELEMENT_SELECTED",elementInfo:e,timestamp:Date.now()})}catch{}}destroy(){this.stopPicker(),typeof window<"u"&&window.removeEventListener("click",this.onGlobalClickBound,!0),this.isGlobalShortcutActive=!1}}class ge{static getCrcTable(){if(this.crcTable)return this.crcTable;const e=new Uint32Array(256);for(let t=0;t<256;t++){let s=t;for(let n=0;n<8;n++)s=s&1?3988292384^s>>>1:s>>>1;e[t]=s>>>0}return this.crcTable=e,e}static crc32(e,t=0,s=e.length){const n=this.getCrcTable();let i=4294967295;for(let r=t;r>>8^n[(i^e[r])&255];return(i^4294967295)>>>0}static adler32(e){let t=1,s=0;for(let n=0;n>>0}static createPNG(e){const t=Math.max(1,Math.min(1920,Math.floor(e.width))),s=Math.max(1,Math.min(1080,Math.floor(e.height))),n=e.backgroundColor||[15,23,42,255],i=e.headerColor||[56,189,248,255],r=e.borderColor||[99,102,241,255],o=1+t*4,a=new Uint8Array(o*s),c=Math.min(30,Math.floor(s*.2));for(let d=0;d=e.length,g=new Uint8Array(5+u);g[0]=h?1:0,g[1]=u&255,g[2]=u>>>8&255;const p=~u&65535;g[3]=p&255,g[4]=p>>>8&255,g.set(e.subarray(n,n+u),5),t.push(g),n+=u}const i=t.reduce((c,u)=>c+u.length,0)+2+4,r=new Uint8Array(i);let o=0;r[o++]=120,r[o++]=1;for(const c of t)r.set(c,o),o+=c.length;const a=this.adler32(e);return r[o++]=a>>>24&255,r[o++]=a>>>16&255,r[o++]=a>>>8&255,r[o++]=a&255,r}static writeChunk(e,t,s,n){const i=n.length,r=new DataView(e.buffer,e.byteOffset,e.byteLength);r.setUint32(t,i,!1),t+=4;const o=new Uint8Array(4+i);for(let c=0;c<4;c++){const u=s.charCodeAt(c);e[t+c]=u,o[c]=u}t+=4,i>0&&(e.set(n,t),o.set(n,4),t+=i);const a=this.crc32(o);return r.setUint32(t,a,!1),t+=4,t}}b(ge,"crcTable",null);const Q=500;class Ue{constructor(e,t){b(this,"history",[]);b(this,"undoStack",[]);b(this,"redoStack",[]);b(this,"counter",0);b(this,"transaction",null);this.doc=e,this.registry=t}mutate(e){var h;const t=`mut_${Date.now().toString(36)}_${++this.counter}`,s=Date.now();let n;try{n=this.resolveTarget(e.target)}catch(g){return this.failure(t,e,null,g.message,Date.now()-s)}const i=this.snapshotState(n);let r=null,o=null,a,c=!0;try{const g=this.applyOperation(t,e,n);g&&(this.transaction?this.transaction.undoRecords.push(g):(this.undoStack.push(g),this.redoStack=[]));const y=(n.isConnected!==void 0?n.isConnected:this.doc.contains(n))?n:this.doc.querySelector(i.selector)||n;r=this.snapshotState(y),o=this.quickDiff(i,r,n)}catch(g){c=!1,a=g.message,r=null}const u={mutationId:t,operation:e.operation,success:c,before:i,after:r,diff:o,affectedSelector:c?i.selector:null,durationMs:Date.now()-s,error:a,undoable:c&&(this.transaction?this.transaction.undoRecords.length>0:this.undoStack.length>0)};return this.transaction&&this.transaction.steps.push({stepId:`step_${this.transaction.steps.length+1}`,mutation:u}),this.pushHistory({mutationId:t,transactionId:(h=this.transaction)==null?void 0:h.id,timestamp:Date.now(),operation:e.operation,targetSelector:i.selector,success:c,summary:`${e.operation} on ${i.selector}${o?` (+${o.added}/-${o.removed}/~${o.changed})`:""}`,undoApplied:!1,redoApplied:!1}),u}beginTransaction(){if(this.transaction)throw new Error(`TRANSACTION_ALREADY_OPEN: ${this.transaction.id} — commit or rollback first.`);return this.transaction={id:`tx_${Date.now().toString(36)}_${++this.counter}`,steps:[],undoRecords:[]},this.transaction.id}commitTransaction(e){if(!this.transaction)throw new Error("NO_OPEN_TRANSACTION: begin a transaction before committing.");const t=this.transaction,s=Date.now();let n=!0,i;if(e)try{n=e({id:t.id,steps:t.steps})!==!1,n||(i="VERIFY_FAILED: caller verification rejected the transaction state.")}catch(o){n=!1,i=`VERIFY_ERROR: ${o.message}`}if(!n)return this.rollbackInternal(t,i||"VERIFY_FAILED",s);this.undoStack.push(...t.undoRecords),this.undoStack.length>Q&&this.undoStack.splice(0,this.undoStack.length-Q),this.redoStack=[];const r=this.summaryOf(t);return this.transaction=null,{transactionId:t.id,committed:!0,rolledBack:!1,steps:t.steps,durationMs:Date.now()-s,finalStateSummary:r}}rollbackTransaction(e){if(!this.transaction)throw new Error("NO_OPEN_TRANSACTION: begin a transaction before rolling back.");const t=this.transaction;return this.rollbackInternal(t,e||"ROLLBACK_REQUESTED",Date.now())}rollbackInternal(e,t,s){for(const i of[...e.undoRecords].reverse())try{this.applyUndo(i)}catch{}const n=this.summaryOf(e);return this.transaction=null,{transactionId:e.id,committed:!1,rolledBack:!0,steps:e.steps,error:t,durationMs:Date.now()-s,finalStateSummary:n}}undo(){const e=this.transaction?this.transaction.undoRecords:this.undoStack,t=e.pop();if(!t)return{success:!1,message:"Nothing to undo — the mutation history is empty."};try{this.applyUndo(t)}catch(s){return e.push(t),{success:!1,mutationId:t.mutationId,message:`UNDO_FAILED: ${s.message}`}}return this.redoStack.push(t),this.markHistory(t.mutationId,"undo"),{success:!0,mutationId:t.mutationId,message:`Undid ${t.operation} on ${t.targetSelector}.`}}redo(){const e=this.redoStack.pop();if(!e)return{success:!1,message:"Nothing to redo — no undone mutation is pending."};try{const t=this.resolveTarget({selector:e.targetSelector}),s={operation:e.operation,target:{selector:e.targetSelector}};return this.reapplyRecord(e,t,s)?((this.transaction?this.transaction.undoRecords:this.undoStack).push(e),this.markHistory(e.mutationId,"redo"),{success:!0,mutationId:e.mutationId,message:`Redid ${e.operation} on ${e.targetSelector}.`}):(this.redoStack.push(e),{success:!1,mutationId:e.mutationId,message:"REDO_FAILED: target state diverged — cannot safely reapply."})}catch(t){return this.redoStack.push(e),{success:!1,mutationId:e.mutationId,message:`REDO_FAILED: ${t.message}`}}}getHistory(e=100){return this.history.slice(-e)}getUndoDepth(){return this.transaction?this.transaction.undoRecords.length:this.undoStack.length}getRedoDepth(){return this.redoStack.length}getOpenTransactionId(){var e;return((e=this.transaction)==null?void 0:e.id)||null}preview(e){var t;try{const s=this.resolveTarget(e.target),n=[];let i=1;(e.operation==="set_inner_html"||e.operation==="set_outer_html")&&(n.push("HTML replacement can destroy descendant node identity — captured regions targeting children may become stale."),i=s.querySelectorAll("*").length+1),(e.operation==="remove_element"||e.operation==="unwrap_element")&&(n.push("Removal is destructive; the undo record preserves the full serialized subtree."),i=s.querySelectorAll("*").length+1),e.operation==="move_element"&&!e.parent&&n.push("No parent target supplied — move requires payload.parent."),e.operation==="wrap_element"&&!e.newElementHtml&&n.push("No wrapper HTML supplied — a neutral
wrapper will be generated.");const r=He(e,s);return{valid:n.filter(o=>o.includes("requires")||o.includes("No parent")).length===0,operation:e.operation,target:{selector:this.snapshotState(s).selector,tag:s.tagName.toLowerCase()},expectedChange:r,affectedNodes:i,warnings:n}}catch(s){return{valid:!1,operation:e.operation,target:{selector:String(((t=e.target)==null?void 0:t.selector)||""),tag:""},expectedChange:"—",affectedNodes:0,warnings:[],error:s.message}}}applyOperation(e,t,s){var r;const n=this.snapshotState(s).selector,i=t.operation;switch(i){case"set_attribute":{if(!t.attribute)throw new Error("ATTRIBUTE_REQUIRED: payload.attribute is missing.");const o=s.getAttribute(t.attribute);return s.setAttribute(t.attribute,t.value??""),this.undoFor(e,i,n,{kind:o===null?"remove-attribute":"restore-attribute",attribute:t.attribute,value:o})}case"remove_attribute":{if(!t.attribute)throw new Error("ATTRIBUTE_REQUIRED: payload.attribute is missing.");const o=s.getAttribute(t.attribute);if(o===null)throw new Error(`ATTRIBUTE_NOT_PRESENT: "${t.attribute}" is not set on ${n}.`);return s.removeAttribute(t.attribute),this.undoFor(e,i,n,{kind:"restore-attribute",attribute:t.attribute,value:o})}case"set_text":{const o=s.textContent||"";return s.textContent=t.text??"",this.undoFor(e,i,n,{kind:"restore-text",text:o})}case"replace_text":{if(!t.text||!t.replacement)throw new Error("TEXT_PATTERNS_REQUIRED: payload.text (search) and payload.replacement are required.");const o=s.textContent||"";return s.textContent=o.split(t.text).join(t.replacement),this.undoFor(e,i,n,{kind:"restore-text",text:o})}case"set_inner_html":{const o=s.innerHTML;return s.innerHTML=t.html??"",this.undoFor(e,i,n,{kind:"restore-outer-html",outerHtml:s.outerHTML.replace(t.html??"",o)||void 0,text:o,attribute:"__inner"})}case"set_outer_html":{const o=s.outerHTML,a=s.parentElement;if(!a)throw new Error("ORPHAN_ELEMENT: element has no parent — cannot replace outer HTML.");const c=this.doc.createComment(`mcpdom_undo_${e}`);s.replaceWith(c);const u=this.doc.createElement("template");u.innerHTML=t.html??"";const h=u.content.firstElementChild;return h?c.replaceWith(h):c.replaceWith(this.doc.createTextNode(t.html??"")),this.undoFor(e,i,n,{kind:"reinsert-node",outerHtml:o,parentSelector:this.snapshotState(a).selector,nextSiblingSelector:this.siblingSelector(h||s)})}case"add_class":{const o=Array.from(s.classList);for(const a of t.classes||[])s.classList.add(a);return this.undoFor(e,i,n,{kind:"restore-classes",classes:o})}case"remove_class":{const o=Array.from(s.classList);for(const a of t.classes||[])s.classList.remove(a);return this.undoFor(e,i,n,{kind:"restore-classes",classes:o})}case"replace_class":{const o=Array.from(s.classList);for(const a of t.classes||[])s.classList.remove(a);return t.value&&s.classList.add(t.value),this.undoFor(e,i,n,{kind:"restore-classes",classes:o})}case"set_style":{const o=this.doc.defaultView;if(!(o!=null&&o.getComputedStyle))throw new Error("STYLE_UNAVAILABLE: computed style API is unavailable in this context.");const a={};for(const c of Object.keys(t.style||{}))a[c]=o.getComputedStyle(s).getPropertyValue(c),s.style.setProperty(c,t.style[c]);return this.undoFor(e,i,n,{kind:"restore-style",style:a})}case"remove_style":{const o={};for(const a of t.classes||[])o[a]=s.style.getPropertyValue(a),s.style.removeProperty(a);return this.undoFor(e,i,n,{kind:"restore-style",style:o})}case"add_element":{const o=t.parent?this.resolveTarget(t.parent):s,a=this.doc.createElement("template");a.innerHTML=t.newElementHtml??"
";const c=a.content.firstElementChild;if(!c)throw new Error("INVALID_HTML: payload.newElementHtml does not produce an element.");switch(t.position||"append"){case"before":s.before(c);break;case"after":s.after(c);break;case"prepend":o.prepend(c);break;default:o.appendChild(c)}return this.undoFor(e,i,n,{kind:"remove-node",attribute:this.snapshotState(c).selector})}case"remove_element":{const o=s.outerHTML,a=s.parentElement,c=s.nextElementSibling;return s.remove(),this.undoFor(e,i,n,{kind:"reinsert-node",outerHtml:o,parentSelector:a?this.snapshotState(a).selector:void 0,nextSiblingSelector:c?this.snapshotState(c).selector:null})}case"replace_element":{const o=s.outerHTML,a=s.parentElement,c=this.doc.createElement("template");c.innerHTML=t.newElementHtml??"
";const u=c.content.firstElementChild;if(!u)throw new Error("INVALID_HTML: payload.newElementHtml does not produce an element.");const h=s.nextElementSibling;return s.replaceWith(u),this.undoFor(e,i,n,{kind:"reinsert-node",outerHtml:o,parentSelector:a?this.snapshotState(a).selector:void 0,nextSiblingSelector:h?this.snapshotState(h).selector:null})}case"move_element":{if(!t.parent)throw new Error("PARENT_REQUIRED: payload.parent is required for move_element.");const o=this.resolveTarget(t.parent),a=s.outerHTML,c=s.parentElement,u=s.nextElementSibling,h=t.position==="before"||t.position==="prepend"?o.firstElementChild:null;return o[t.position==="prepend"?"prepend":"appendChild"](s),this.undoFor(e,i,n,{kind:"restore-position",parentSelector:c?this.snapshotState(c).selector:void 0,nextSiblingSelector:u?this.snapshotState(u).selector:h?this.snapshotState(h).selector:null,outerHtml:a})}case"wrap_element":{const o=this.doc.createElement("template");o.innerHTML=t.newElementHtml||'
';const a=o.content.firstElementChild;if(!a)throw new Error("INVALID_HTML: wrapper template produced no element.");const c=s.parentElement,u=s.nextElementSibling;return s.replaceWith(a),a.appendChild(s),this.undoFor(e,i,n,{kind:"restore-position",parentSelector:c?this.snapshotState(c).selector:void 0,nextSiblingSelector:u?this.snapshotState(u).selector:null})}case"unwrap_element":{const o=s.outerHTML,a=s.parentElement;if(!a)throw new Error("ORPHAN_ELEMENT: cannot unwrap a root-level element.");const c=s.nextElementSibling,u=Array.from(s.children);for(const h of u)a.insertBefore(h,s);return s.remove(),this.undoFor(e,i,n,{kind:"reinsert-node",outerHtml:o,parentSelector:this.snapshotState(a).selector,nextSiblingSelector:c?this.snapshotState(c).selector:null})}case"clone_subtree":{const o=t.parent?this.resolveTarget(t.parent):s.parentElement||s,a=s.cloneNode(!0);if(t.copyAttributes!==!1)for(const c of Array.from(a.attributes))c.name==="id"&&a.removeAttribute("id");return(r=o.appendChild)==null||r.call(o,a),this.undoFor(e,i,n,{kind:"remove-node",attribute:this.snapshotState(a).selector})}default:throw new Error(`UNKNOWN_OPERATION: ${i} is not a supported DOM mutation.`)}}applyUndo(e){const t=e.inverse;switch(t.kind){case"restore-outer-html":{const s=this.resolveTarget({selector:e.targetSelector});if(t.outerHtml!==void 0){const n=this.doc.createElement("template");n.innerHTML=t.outerHtml;const i=n.content.firstElementChild;i&&s.replaceWith(i)}else t.attribute==="__inner"&&(s.innerHTML=t.text||"");break}case"reinsert-node":{const s=t.parentSelector?this.resolveTarget({selector:t.parentSelector}):this.doc.body,n=this.doc.createElement("template");n.innerHTML=t.outerHtml||"";const i=n.content.firstElementChild;if(!i)throw new Error("UNDO_CORRUPT: serialized subtree could not be restored.");const r=t.nextSiblingSelector?this.safeResolve(t.nextSiblingSelector):null;s.insertBefore(i,r);break}case"remove-node":{const s=this.safeResolve(t.attribute||e.targetSelector);s&&s.remove();break}case"restore-attribute":{this.resolveTarget({selector:e.targetSelector}).setAttribute(t.attribute,t.value??"");break}case"remove-attribute":{this.resolveTarget({selector:e.targetSelector}).removeAttribute(t.attribute);break}case"restore-text":{const s=this.resolveTarget({selector:e.targetSelector});s.textContent=t.text||"";break}case"restore-classes":{const s=this.resolveTarget({selector:e.targetSelector});s.removeAttribute("class");for(const n of t.classes||[])s.classList.add(n);break}case"restore-style":{const s=this.resolveTarget({selector:e.targetSelector});s.style.removeProperty("all");for(const[n,i]of Object.entries(t.style||{}))s.style.setProperty(n,i);break}case"restore-position":{const s=this.doc.createElement("template");s.innerHTML=t.outerHtml||"";const n=s.content.firstElementChild;if(!n)throw new Error("UNDO_CORRUPT: serialized subtree could not be restored.");const i=this.safeResolve(e.targetSelector);i&&i.remove();const r=t.parentSelector?this.safeResolve(t.parentSelector):this.doc.body,o=t.nextSiblingSelector?this.safeResolve(t.nextSiblingSelector):null;(r||this.doc.body).insertBefore(n,o);break}}}reapplyRecord(e,t,s){var i;const n=e.inverse;switch(e.operation){case"set_attribute":return(n.kind==="restore-attribute"||n.kind==="remove-attribute")&&s.value!==void 0?(t.setAttribute(s.attribute||n.attribute||"",s.value),!0):!1;case"add_class":{for(const r of s.classes||[])t.classList.add(r);return(((i=s.classes)==null?void 0:i.length)||0)>0}case"remove_class":{for(const r of s.classes||n.classes||[])t.classList.remove(r);return!0}case"set_text":return s.text!==void 0?(t.textContent=s.text,!0):!1;case"set_inner_html":return s.html!==void 0?(t.innerHTML=s.html,!0):!1;default:return!1}}resolveTarget(e){if(!e)throw new Error("TARGET_REQUIRED: mutation requires a target.");if(typeof e=="string"&&(e={selector:e}),e.selector){try{const t=this.doc.querySelectorAll(e.selector);if(t.length===1)return t[0];if(t.length>1)return Array.from(t).find(n=>{try{return k.inspectElement(n).visibility.isVisible}catch{return!1}})||t[0]}catch(t){throw new Error(`TARGET_INVALID: ${t.message}`)}throw new Error(`TARGET_NOT_FOUND: selector "${e.selector}" matches no element.`)}if(e.xpath){try{const s=this.doc.evaluate(e.xpath,this.doc,null,9,null).singleNodeValue;if(s)return s}catch(t){throw new Error(`TARGET_INVALID_XPATH: ${t.message}`)}throw new Error("TARGET_NOT_FOUND: xpath matches no element.")}if(typeof e.nodeId=="number"&&this.registry){const t=this.registry.getNode(e.nodeId);if(t&&t.nodeType===1&&this.doc.contains(t))return t;throw new Error("TARGET_STALE: logical node id no longer resolves to an attached element.")}throw new Error("TARGET_INVALID: target has neither selector, xpath nor nodeId.")}safeResolve(e){try{return this.doc.querySelector(e)}catch{return null}}snapshotState(e){const t=k.inspectElement(e,this.registry),s=e.outerHTML.length>2e4?e.outerHTML.slice(0,2e4)+"…[truncated]":e.outerHTML;return{selector:t.bestSelector,outerHtml:s,attributes:this.attrsOf(e)}}attrsOf(e){const t={};for(const s of Array.from(e.attributes))t[s.name]=s.value.length>300?s.value.slice(0,300)+"…":s.value;return t}quickDiff(e,t,s){if(!t)return null;let n=0,i=0,r=0;const o=new Set(Object.keys(e.attributes)),a=new Set(Object.keys(t.attributes||{}));for(const u of o)a.has(u)||i++;for(const u of a)o.has(u)?e.attributes[u]!==t.attributes[u]&&r++:n++;e.outerHtml!==t.outerHtml&&n+i+r===0&&r++;const c=s.querySelectorAll?s.querySelectorAll("*").length:0;return{added:n,removed:i,changed:r,summary:`attributes +${n}/-${i}/~${r}; subtree nodes: ${c}`}}undoFor(e,t,s,n){return{mutationId:e,operation:t,targetSelector:s,inverse:n}}siblingSelector(e){try{return this.snapshotState(e).selector}catch{return null}}pushHistory(e){this.history.push(e),this.history.length>Q&&this.history.splice(0,this.history.length-Q)}markHistory(e,t){for(let s=this.history.length-1;s>=0;s--)if(this.history[s].mutationId===e){t==="undo"?this.history[s].undoApplied=!0:this.history[s].redoApplied=!0;return}}summaryOf(e){var n;const t=((n=this.doc.documentElement)==null?void 0:n.outerHTML.length)||0,s=e.steps.filter(i=>i.mutation.success).length;return{domLength:t,diffSummary:`${s}/${e.steps.length} mutations applied`}}failure(e,t,s,n,i){var r;return{mutationId:e,operation:t.operation,success:!1,before:s||{selector:String(((r=t.target)==null?void 0:r.selector)||"?"),outerHtml:"",attributes:{}},after:null,diff:null,affectedSelector:null,durationMs:i,error:n,undoable:!1}}}function He(l,e){switch(l.operation){case"set_attribute":return`attribute "${l.attribute}" will be set to "${(l.value??"").slice(0,40)}"`;case"remove_attribute":return`attribute "${l.attribute}" will be removed`;case"set_text":return`text content will be replaced (${(l.text||"").length} chars)`;case"replace_text":return`every occurrence of "${l.text}" will become "${l.replacement}"`;case"set_inner_html":return`inner HTML will be replaced (${(l.html||"").length} chars)`;case"set_outer_html":return"element (and subtree) will be replaced with provided HTML";case"add_class":return`classes ${(l.classes||[]).join(", ")} will be added`;case"remove_class":return`classes ${(l.classes||[]).join(", ")} will be removed`;case"replace_class":return`classes ${(l.classes||[]).join(", ")} will be replaced with "${l.value}"`;case"set_style":return`inline styles ${Object.keys(l.style||{}).join(", ")} will be set`;case"remove_style":return`inline styles ${(l.classes||[]).join(", ")} will be removed`;case"add_element":return`a new element will be inserted ${l.position||"append"} the target`;case"remove_element":return"the element and its subtree will be removed";case"replace_element":return"the element will be replaced with new HTML";case"move_element":return"the element will be moved into the specified parent";case"wrap_element":return"the element will be wrapped in a new container";case"unwrap_element":return"children will be lifted out and the wrapper removed";case"clone_subtree":return"a deep clone of the subtree will be appended";default:return"unknown operation"}}class Fe{constructor(){b(this,"executionCounter",0)}async execute(e,t,s={}){const n=Math.min(Math.max(s.timeoutMs??5e3,100),3e4),i=`js_${Date.now().toString(36)}_${++this.executionCounter}`,r=e.defaultView;if(!r)return this.result(i,"BLOCKED_BY_CONTEXT",0,t,[],{name:"NoWindow",message:"The document has no associated window — execution context unavailable."});const o=e.documentElement?e.documentElement.outerHTML.length:0,a=[],c=this.hookConsole(r,a);let u="EXECUTED_SUCCESSFULLY",h,g,p=o,y=!1;const v=Date.now();try{const f=this.buildRunner(r,t),w=new Promise((E,S)=>{var x;const T=setTimeout(()=>{y=!0,S(new Error(`Script timed out after ${n}ms`))},n);(x=T==null?void 0:T.unref)==null||x.call(T)});h=await Promise.race([f,w])}catch(f){y?u="TIMED_OUT":u="EXECUTED_WITH_ERROR",g={name:(f==null?void 0:f.name)||"Error",message:(f==null?void 0:f.message)||String(f),stack:f!=null&&f.stack?String(f.stack).slice(0,2e3):void 0}}const m=Date.now()-v;p=e.documentElement?e.documentElement.outerHTML.length:0,c();const d=this.serialize(h);return u==="EXECUTED_SUCCESSFULLY"&&d.serializationFailed&&(u="SERIALIZATION_FAILED",g={name:"SerializationError",message:d.message||"Result could not be serialized."}),{status:u,executionId:i,durationMs:m,result:u==="EXECUTED_SUCCESSFULLY"?d.text:void 0,error:g,consoleOutput:a.slice(0,100),domChanged:o!==p,domLengthBefore:o,domLengthAfter:p,world:s.world||"ISOLATED",timeoutMs:n,codePreview:t.length>300?t.slice(0,300)+"…":t}}buildRunner(e,t){const s=`(async function() { ${t} -})()`,n=e;if(typeof n.eval!="function")return Promise.reject(new Error("BLOCKED_BY_CONTEXT: window.eval is unavailable in this context."));try{const i=n.eval(s);return i&&typeof i.then=="function"?i:Promise.resolve(i)}catch(i){return Promise.reject(i)}}hookConsole(e,t){var o;const s=["log","warn","error","info","debug"],n={},i=e,r=100;for(const a of s){const c=(o=i.console)==null?void 0:o[a];if(typeof c=="function"){n[a]=c;try{i.console[a]=(...u)=>{t.length{for(const a of s)if(n[a])try{i.console[a]=n[a]}catch{}}}serialize(e){if(e===void 0)return{text:"undefined"};if(e===null)return{text:"null"};try{if(typeof e=="string")return{text:e.slice(0,5e3)};const t=JSON.stringify(e,be,1);return t===void 0?{serializationFailed:!0,message:"JSON.stringify returned undefined (circular or non-serializable structure)."}:{text:t.length>5e4?t.slice(0,5e4)+"…[truncated]":t}}catch(t){return{serializationFailed:!0,message:(t==null?void 0:t.message)||"Serialization failed."}}}result(e,t,s,n,i,r){return{status:t,executionId:e,durationMs:s,error:r,consoleOutput:i,domChanged:!1,domLengthBefore:0,domLengthAfter:0,world:"ISOLATED",timeoutMs:5e3,codePreview:n.length>300?n.slice(0,300)+"…":n}}}function be(l,e){var t;if(e&&typeof e=="object"&&e.nodeType===1){const s=e;return{__element:!0,tag:s.tagName.toLowerCase(),id:s.getAttribute("id")||void 0,selector:s.tagName.toLowerCase()+(s.getAttribute("id")?`#${s.getAttribute("id")}`:""),text:(s.textContent||"").trim().slice(0,60)}}return typeof e=="function"?{__function:!0,name:e.name||"anonymous"}:e&&e.nodeType===9?{__document:!0,url:(t=e.location)==null?void 0:t.href}:e}function Ve(l){try{if(typeof l=="string")return l;if(l instanceof Error)return`${l.name}: ${l.message}`;const e=JSON.stringify(l,be);return e===void 0?String(l):e}catch{return String(l)}}const ye={"desktop-full-hd":{width:1920,height:1080,category:"desktop"},"desktop-hd":{width:1366,height:768,category:"desktop"},"desktop-laptop":{width:1440,height:900,category:"desktop"},"desktop-xga":{width:1280,height:1024,category:"desktop"},"desktop-1024":{width:1024,height:768,category:"desktop"},"tablet-ipad":{width:768,height:1024,category:"tablet"},"tablet-ipad-pro":{width:1024,height:1366,category:"tablet"},"tablet-portrait":{width:768,height:1024,category:"tablet"},"tablet-landscape":{width:1024,height:768,category:"tablet"},"mobile-iphone-se":{width:375,height:667,category:"mobile"},"mobile-iphone-12":{width:390,height:844,category:"mobile"},"mobile-iphone-14-pro-max":{width:430,height:932,category:"mobile"},"mobile-pixel-7":{width:412,height:915,category:"mobile"},"mobile-galaxy-s8":{width:360,height:740,category:"mobile"},"mobile-small":{width:320,height:568,category:"mobile"},"test-a4":{width:800,height:600,category:"test"},"test-square":{width:512,height:512,category:"test"}},Ee={"iphone-13":{width:390,height:844,devicePixelRatio:3,userAgent:"Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1",touch:!0,category:"mobile"},"ipad-air":{width:820,height:1180,devicePixelRatio:2,userAgent:"Mozilla/5.0 (iPad; CPU OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1",touch:!0,category:"tablet"},"pixel-7":{width:412,height:915,devicePixelRatio:2.625,userAgent:"Mozilla/5.0 (Linux; Android 14; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36",touch:!0,category:"mobile"},"galaxy-s23":{width:384,height:800,devicePixelRatio:3,userAgent:"Mozilla/5.0 (Linux; Android 14; SM-S911B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36",touch:!0,category:"mobile"},"macbook-pro-16":{width:1728,height:1080,devicePixelRatio:2,userAgent:"Mozilla/5.0 (Macintosh; Intel Mac OS X 14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",touch:!1,category:"desktop"},"windows-desktop":{width:1920,height:1080,devicePixelRatio:1,userAgent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",touch:!1,category:"desktop"}};class ze{constructor(e){f(this,"original",null);f(this,"modified",!1);f(this,"activePreset",null);f(this,"activeDevice",null);this.doc=e}state(){const e=this.doc.defaultView;return{width:(e==null?void 0:e.innerWidth)||0,height:(e==null?void 0:e.innerHeight)||0,devicePixelRatio:(e==null?void 0:e.devicePixelRatio)||1,scrollX:(e==null?void 0:e.scrollX)||0,scrollY:(e==null?void 0:e.scrollY)||0,original:this.original,isModified:this.modified}}resize(e,t,s){const n=this.doc.defaultView,i={width:(n==null?void 0:n.innerWidth)||0,height:(n==null?void 0:n.innerHeight)||0},r=this.pageDigest();this.original||(this.original={...i});const o=this.applySize(e,t);this.modified=!0,this.activePreset=s||this.activePreset;const a=this.pageDigest();return{success:!0,applied:{width:o.width,height:o.height},previous:i,original:{...this.original},preset:s||void 0,beforeState:r,afterState:a,reversible:!0,mode:this.isSimulation()?"simulation":"browser-window"}}applyPreset(e){const t=ye[e];if(!t)throw new Error(`UNKNOWN_PRESET: "${e}". Available: ${Object.keys(ye).join(", ")}`);return this.resize(t.width,t.height,e)}emulateDevice(e){const t=Ee[e];if(!t)throw new Error(`UNKNOWN_DEVICE: "${e}". Available: ${Object.keys(Ee).join(", ")}`);const s=this.resize(t.width,t.height,`device:${e}`);this.activeDevice=e;const n=this.doc.defaultView;return n&&this.isSimulation()&&n.devicePixelRatio!==void 0&&(n.devicePixelRatio=t.devicePixelRatio),{device:e,resize:s,profile:{width:t.width,height:t.height,devicePixelRatio:t.devicePixelRatio,touch:t.touch,category:t.category},userAgentNote:this.isSimulation()?"User-Agent override requires the Chrome DevTools Protocol (real browser session); in this context the viewport, dpr and touch metadata are applied and the UA is reported but not enforced.":"User-Agent and touch behaviors are applied by the browser emulation layer.",userAgentApplied:!this.isSimulation()}}reset(){var s,n;const e={width:((s=this.doc.defaultView)==null?void 0:s.innerWidth)||0,height:((n=this.doc.defaultView)==null?void 0:n.innerHeight)||0},t=this.original?{...this.original}:{...e};return this.original&&this.applySize(this.original.width,this.original.height),this.modified=!1,this.activePreset=null,this.activeDevice=null,{success:!0,applied:{width:t.width,height:t.height},previous:e,original:{...t},reversible:!0,mode:this.isSimulation()?"simulation":"browser-window"}}runResponsiveTest(e,t={restore:!0}){var c,u,d,h;const s=t.restore!==!1,n=this.original?{...this.original}:{width:((c=this.doc.defaultView)==null?void 0:c.innerWidth)||0,height:((u=this.doc.defaultView)==null?void 0:u.innerHeight)||0};this.original||(this.original={...n});const i=e.map(p=>{this.applySize(p.width,p.height),this.modified=!0;const y=this.pageDigest();return{label:p.label,width:p.width,height:p.height,domLength:y.domLength,interactiveCount:y.interactiveCount,horizontalOverflow:this.hasHorizontalOverflow(),screenshotId:void 0}}),r=i.slice(1).map((p,y)=>({from:i[y].label,to:p.label,domLengthDelta:p.domLength-i[y].domLength,interactiveDelta:p.interactiveCount-i[y].interactiveCount}));let o={width:((d=i[i.length-1])==null?void 0:d.width)||0,height:((h=i[i.length-1])==null?void 0:h.height)||0},a=!1;return s&&(this.applySize(n.width,n.height),this.modified=!1,o={...n},a=!0),{success:!0,originalViewport:n,steps:i,restored:a,finalViewport:o,comparisons:r}}getActivePreset(){return this.activePreset}getActiveDevice(){return this.activeDevice}applySize(e,t){const s=Math.max(200,Math.min(7680,Math.round(e))),n=Math.max(200,Math.min(4320,Math.round(t))),i=this.doc.defaultView;return i&&(typeof i.innerWidth=="number"&&(i.innerWidth=s),typeof i.innerHeight=="number"&&(i.innerHeight=n),typeof i.outerWidth=="number"&&(i.outerWidth=s),typeof i.outerHeight=="number"&&(i.outerHeight=n)),{width:s,height:n}}pageDigest(){var t,s,n,i;const e=this.doc.querySelectorAll('a[href], button, input, select, textarea, [role="button"], [onclick]').length;return{url:((s=(t=this.doc.defaultView)==null?void 0:t.location)==null?void 0:s.href)||((n=this.doc.location)==null?void 0:n.href)||"",domLength:((i=this.doc.documentElement)==null?void 0:i.outerHTML.length)||0,interactiveCount:e}}hasHorizontalOverflow(){const e=this.doc.documentElement,t=this.doc.body,s=this.doc.defaultView;return!s||!e?!1:Math.max(e.scrollWidth||0,(t==null?void 0:t.scrollWidth)||0)>(s.innerWidth||e.clientWidth||0)+1}isSimulation(){return typeof globalThis.__FORENSIC_SIMULATION__<"u"}}const We=[/^css-/,/^jsx-/,/^sc-[A-Za-z]/,/^emotion/,/^chakra-/,/^mantine-/i,/^_ng[a-z]/,/^ng-/i,/^v-/,/^(?=.*\d)[a-z0-9]{6,12}$/i,/^data-v-/],Xe=["id","name","data-testid","data-test","data-id","data-qa","data-cy","data-component","data-role","aria-label","aria-labelledby","aria-describedby","role","type","href","for","title","alt","rel","placeholder"];function ve(l){let e=2166136261;for(let t=0;t>>0).toString(16).padStart(8,"0")}function ie(l){return We.some(e=>e.test(l))}function Ge(l){return Xe.includes(l)}function ce(l){const e=l.trim();return e?!!((e.match(/\d/g)||[]).length/e.length>.5||/^\d+[.,:\-/ ]+\d+/.test(e)||/\b\d{10,}\b/.test(e)):!1}function Ke(l,e=80){return Array.from(l.childNodes).filter(s=>s.nodeType===3).map(s=>(s.textContent||"").trim()).join(" ").replace(/\s+/g," ").slice(0,e)}function Ye(l,e){const t=[];let s=l;for(;s&&t.length!ie(b)),r=Ke(e),o=e.getBoundingClientRect(),a={width:Math.round(o.width),height:Math.round(o.height)},c=Ye(e,4),u=c.join(">"),h=Array.from(e.children||[]).slice(0,8).map(b=>b.tagName.toLowerCase()).join("|"),p=e.getAttribute("role")||(t!=null&&t.getComputedStyle,void 0)||je(e),y=ve(JSON.stringify({t:e.tagName.toLowerCase(),a:s,c:i.slice(0,4),r:p||null,anc:u,desc:h,txt:ce(r)?null:r.slice(0,40),d:a})),v=[];let m="low";return!s.id&&!s["data-testid"]&&!s.name&&(m="medium",v.push("no stable identity attribute")),n.length>0&&i.length===0&&(m=v.length?"high":"medium",v.push("all classes are framework-generated")),ce(r)&&(v.push("text appears dynamic"),m==="low"&&(m="medium")),e.tagName.toLowerCase().includes("-")&&(v.push("custom element (web component)"),m==="low"&&(m="medium")),{fingerprintId:`fp_${y}`,hash:y,tagHierarchy:c,stableAttributes:s,meaningfulText:r,classes:i,role:p||void 0,dimensions:a,ancestorPattern:u,descendantPattern:h,volatilityRisk:m,volatilityReasons:v}}compare(e,t){const s=[],n=e.tagHierarchy[0]===t.tagHierarchy[0]?1:0;s.push({name:"tag",score:n,weight:.15});const i=we(e.ancestorPattern.split(">"),t.ancestorPattern.split(">"));s.push({name:"ancestorPattern",score:i,weight:.2});const r=Je(e.stableAttributes,t.stableAttributes);s.push({name:"stableAttributes",score:r,weight:.25});const o=we(e.classes,t.classes);s.push({name:"classes",score:o,weight:.1});const a=(e.role||"")===(t.role||"")&&e.role?1:0;s.push({name:"role",score:a,weight:.1});const c=e.meaningfulText===t.meaningfulText&&e.meaningfulText?1:0;s.push({name:"text",score:c,weight:.1});const u=Ze(e.dimensions,t.dimensions);s.push({name:"dimensions",score:u,weight:.1});const d=s.reduce((h,p)=>h+p.score*p.weight,0);return{score:Math.round(d*1e3)/1e3,components:s}}}function je(l){switch(l.tagName.toLowerCase()){case"a":return l.getAttribute("href")?"link":void 0;case"button":return"button";case"nav":return"navigation";case"header":return"banner";case"footer":return"contentinfo";case"main":return"main";case"aside":return"complementary";case"article":return"article";case"form":return"form";case"input":{const t=l.getAttribute("type")||"text";return t==="checkbox"?"checkbox":t==="radio"?"radio":t==="button"||t==="submit"?"button":"textbox"}case"select":return"combobox";case"textarea":return"textbox";case"img":return"img";case"table":return"table";case"ul":case"ol":return"list";case"li":return"listitem";case"h1":case"h2":case"h3":case"h4":case"h5":case"h6":return"heading";default:return}}function we(l,e){if(!l.length&&!e.length)return 1;if(!l.length||!e.length)return 0;const t=new Set(e);return l.filter(n=>t.has(n)).length/Math.max(l.length,e.length)}function Je(l,e){const t=Object.keys(l),s=Object.keys(e);if(!t.length&&!s.length)return .5;if(!t.length||!s.length)return 0;let n=0,i=0;for(const r of t)r in e&&(i++,l[r]===e[r]&&n++);return i===0?0:n/Math.max(t.length,s.length)}function Ze(l,e){if(l.width===0&&l.height===0&&e.width===0&&e.height===0)return .5;const t=Se(l.width,e.width),s=Se(l.height,e.height);return(t+s)/2}function Se(l,e){if(l===e)return 1;if(l===0||e===0)return 0;const t=Math.min(l,e)/Math.max(l,e);return t>.9?1:t>.7?.5:0}const Qe=["data-testid","data-test","data-id","data-qa","data-cy","data-component","data-role","aria-label","name","id"],Te=/^[a-zA-Z][a-zA-Z0-9_-]*$/,et=/^[a-zA-Z0-9_ .:-]+$/;class Z{constructor(e){f(this,"doc");this.doc=e}generateCandidates(e){const t=[],s=e.tagName.toLowerCase(),n=e.getAttribute("id");if(n&&Te.test(n)){const u=`#${Ce(n)}`;t.push(this.evaluate(e,u,"id",1,["unique stable id"]))}for(const u of Qe){if(u==="id")continue;const d=e.getAttribute(u);if(d&&et.test(d)&&d.length<100){const h=`${s}[${u}="${Q(d)}"]`;t.push(this.evaluate(e,h,"semantic-attribute",.92,[`semantic attribute ${u}`]))}}const i=Array.from(e.classList||[]).filter(u=>!ie(u));if(i.length){const u=`${s}.${i.slice(0,3).map(Ce).join(".")}`;t.push(this.evaluate(e,u,"class",.72,i.length?["stable class names"]:[]))}const r=this.buildStructuralPath(e);r&&t.push(this.evaluate(e,r,"structural-path",.55,["position-based structural path"]));const o=B(e);if(o&&o.length>=2&&o.length<=60&&!ce(o)){const u=`${s}:nth-of-type(1)`,d=this.buildTextXPath(e,o);d&&(t.push({selector:u,strategy:"text-derived-xpath",confidence:.6,unique:this.isXPathUnique(d),reasons:[`matches text "${o.slice(0,30)}"`]}),t[t.length-1].xpath=d)}const a=this.buildAttributeFingerprintSelector(e);a&&t.push(this.evaluate(e,a,"attribute-fingerprint",.68,["combination of stable attributes"]));const c=new Map;for(const u of t){const d=u.strategy==="text-derived-xpath"?`xpath:${u.xpath}`:u.selector,h=c.get(d);(!h||u.confidence>h.confidence)&&c.set(d,u)}return Array.from(c.values()).sort((u,d)=>d.confidence-u.confidence)}bestSelector(e){const t=this.generateCandidates(e),s=t.find(n=>n.unique&&n.confidence>=.7)||t[0];return{selector:(s==null?void 0:s.selector)||e.tagName.toLowerCase(),strategy:(s==null?void 0:s.strategy)||"tag",confidence:(s==null?void 0:s.confidence)||.3}}buildXPath(e){const t=[];let s=e;for(;s&&s!==this.doc.documentElement;){const n=s.getAttribute("id");if(n&&Te.test(n)){t.unshift(`*[@id="${Q(n)}"]`);break}const i=s.parentElement;if(!i){t.unshift(s.tagName.toLowerCase());break}const o=Array.from(i.children).filter(a=>a.tagName===s.tagName).indexOf(s)+1;t.unshift(`${s.tagName.toLowerCase()}[${o}]`),s=i}return s===this.doc.documentElement&&(!t.length||!t[0].includes("@id"))&&t.unshift("html"),"//"+t.join("/")}buildTextXPath(e,t){try{const s=e.tagName.toLowerCase(),n=tt(t);return`//${s}[normalize-space(text())=${n}]`}catch{return null}}buildStructuralPath(e,t=4){const s=[];let n=e;for(;n&&s.lengthc.tagName===n.tagName);if(a.length>1){const c=a.indexOf(n)+1;s.unshift(`${o}:nth-of-type(${c})`)}else s.unshift(o);if(n=r,n===this.doc.body){s.unshift("body");break}if(n===this.doc.documentElement)break}const i=s.join(" > ");return i.includes("body")?i:"body > "+i}buildAttributeFingerprintSelector(e){const t=e.tagName.toLowerCase(),s=[],n=e.getAttribute("type");n&&s.push(`type="${Q(n)}"`);const i=e.getAttribute("href");i&&i.length<80&&!i.startsWith("javascript:")&&s.push(`href^="${Q(i.slice(0,40))}"`);const r=e.getAttribute("placeholder");return r&&r.length<60&&s.push(`placeholder="${Q(r)}"`),s.length>=2?`${t}[${s.join("][")}]`:null}evaluate(e,t,s,n,i){let r=!1,o=0;try{const c=this.doc.querySelectorAll(t);o=c.length,r=c.length===1&&c[0]===e}catch{return{selector:t,strategy:s,confidence:0,unique:!1,reasons:["invalid selector syntax"]}}let a=n;return o===0?(a=0,i.push("selector matched nothing (invalid candidate)")):o===1&&r?i.push("matches exactly this element"):(a=a*.4,i.push(`matches ${o} elements — ambiguous`)),{selector:t,strategy:s,confidence:Math.round(a*100)/100,unique:r,reasons:i}}isXPathUnique(e){try{return this.doc.evaluate(`count(${e})`,this.doc,null,4,null).numberValue===1}catch{return!1}}}function B(l){return Array.from(l.childNodes).filter(e=>e.nodeType===3).map(e=>(e.textContent||"").trim()).join(" ").replace(/\s+/g," ")}function Ce(l){return l.replace(/([^a-zA-Z0-9_\u00A0-\uFFFF-])/g,"\\$1")}function Q(l){return l.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function tt(l){return l.includes("'")?l.includes('"')?`concat(${l.split("'").map(e=>`'${e}'`).join(`, "'", `)})`:`"${l}"`:`'${l}'`}class st{constructor(e,t){f(this,"fingerprintEngine",new re);f(this,"counter",0);this.doc=e,this.registry=t}buildTarget(e,t="selector"){var d;const s=new Z(this.doc),n=s.generateCandidates(e),i=s.bestSelector(e),r=this.fingerprintEngine.fingerprint(e),o=L.inspectElement(e,this.registry),a=e.getBoundingClientRect();let c=i.confidence*.6;return r.volatilityRisk==="low"?c+=.3:r.volatilityRisk==="medium"&&(c+=.15),n.find(h=>h.unique&&h.confidence>=.9)&&(c+=.1),c=Math.max(.05,Math.min(1,c)),this.counter++,{targetId:`tgt_${Date.now().toString(36)}_${this.counter}`,tag:e.tagName.toLowerCase(),role:o.role||r.role,selector:i.selector,selectorCandidates:n,xpath:s.buildXPath(e),domPath:(((d=o.context)==null?void 0:d.parentChain)||[]).concat(i.selector).join(" > "),textFingerprint:r.meaningfulText,attributeFingerprint:JSON.stringify(r.stableAttributes),structuralFingerprint:r.hash,attributes:o.attributes||{},confidence:Math.round(c*100)/100,bounds:{x:Math.round(a.x),y:Math.round(a.y),width:Math.round(a.width),height:Math.round(a.height)},resolvedFrom:t}}resolveAndBuild(e){let t=null,s="unknown";typeof e=="string"&&(e={selector:e});const n=e;if(n.selectedElementRef&&(s="selectedElementRef"),!t&&n.selector)try{const i=this.doc.querySelectorAll(n.selector);if(i.length===0)return{error:`TARGET_NOT_FOUND: selector "${n.selector}" matches no element`};i.length>1?(t=nt(i,this.doc)||i[0],s+="+disambiguated"):(t=i[0],s="selector")}catch(i){return{error:`TARGET_INVALID: ${i.message}`}}if(!t&&n.xpath)try{t=this.doc.evaluate(n.xpath,this.doc,null,9,null).singleNodeValue,s="xpath"}catch(i){return{error:`TARGET_INVALID_XPATH: ${i.message}`}}if(!t&&typeof n.nodeId=="number"&&this.registry){const i=this.registry.getNode(n.nodeId);i&&i.nodeType===1&&this.doc.contains(i)&&(t=i,s="nodeId")}return!t&&n.coordinates&&(t=this.doc.elementFromPoint(n.coordinates.x,n.coordinates.y),s="coordinates"),t?{element:t,target:this.buildTarget(t,s)}:{error:"TARGET_NOT_FOUND: no usable resolution strategy succeeded"}}}function nt(l,e){for(const t of Array.from(l)){const s=t;try{if(L.inspectElement(s).visibility.isVisible)return s}catch{}}return null}class it{constructor(e){f(this,"fingerprintEngine",new re);this.doc=e}recover(e,t){var p;const s=[],n=[];let i=null;try{i=this.doc.querySelectorAll(e)}catch(y){s.push(`selector syntax error: ${y.message}`)}if(i&&i.length>0){s.push("selector still matches — no recovery needed");const y=i[0];return{recovered:!0,confidence:1,strategy:"original-selector",resolvedSelector:e,matchedElementInfo:Ie(y),alternatives:[],diagnostics:s,recommendation:"Original selector works; the earlier failure was transient (likely a navigation or render race)."}}s.push("selector no longer matches any element");const o=this.collectCandidates(t,s).map(y=>({element:y,score:this.scoreMatch(y,t)})).filter(y=>y.score.score>.35).sort((y,v)=>v.score.score-y.score.score);for(const y of o.slice(0,5)){const v=new Z(this.doc).bestSelector(y.element);n.push({selector:v.selector,confidence:Math.round(y.score.score*100)/100,strategy:"recovery-match"})}if(!o.length)return{recovered:!1,confidence:0,strategy:"none",alternatives:n,diagnostics:s,recommendation:"No sufficiently similar element exists. The region may have been removed, or the page structure changed fundamentally. Re-inspect the page and capture a new target."};const a=o[0],c=o.length>1?a.score.score-o[1].score.score:1;s.push(`best candidate score: ${a.score.score.toFixed(3)} (margin ${c.toFixed(3)})`);for(const y of a.score.components)y.score>0&&s.push(` - ${y.name}: ${(y.score*100).toFixed(0)}%`);if(a.score.score<.62||o.length>1&&c<.15)return{recovered:!1,confidence:Math.round(a.score.score*100)/100,strategy:"recovery-refused",resolvedSelector:(p=n[0])==null?void 0:p.selector,alternatives:n,diagnostics:s,recommendation:"Recovery refused: best match is not confident enough or too close to a competing element. Inspect alternatives manually before acting — refusing to avoid acting on a wrong element."};const h=new Z(this.doc).bestSelector(a.element).selector;return{recovered:!0,confidence:Math.round(a.score.score*100)/100,strategy:"fingerprint-recovery",resolvedSelector:h,matchedElementInfo:Ie(a.element),alternatives:n,diagnostics:s,recommendation:`Recovered target with ${(a.score.score*100).toFixed(0)}% confidence. Verify the resolved selector before destructive actions.`}}collectCandidates(e,t){var r,o;const s=new Set,n=this.doc.querySelectorAll(e.tag);let i=0;for(const a of Array.from(n))if(s.add(a),++i>=400)break;if((r=e.classes)!=null&&r.length){const a=e.classes.filter(c=>!ie(c));for(const c of a.slice(0,2))try{for(const u of Array.from(this.doc.querySelectorAll(`.${c}`)).slice(0,100))s.add(u)}catch{}}if((o=e.stableAttributes)!=null&&o.name)try{for(const a of Array.from(this.doc.querySelectorAll(`[name="${e.stableAttributes.name}"]`)))s.add(a)}catch{}if(e.parentSelector)try{for(const a of Array.from(this.doc.querySelectorAll(`${e.parentSelector} > ${e.tag}`)).slice(0,100))s.add(a)}catch{}return t.push(`collected ${s.size} candidate elements for scoring`),Array.from(s)}scoreMatch(e,t){const s=[],n=e.tagName.toLowerCase()===t.tag.toLowerCase()?1:0;s.push({name:"tag",score:n,weight:.15});const i=(t.text||"").trim().slice(0,40),r=B(e).slice(0,40),o=(e.textContent||"").trim().slice(0,40);let a=0;if(i){const g=r?r===i?1:le(i,r):0,b=o?o===i?1:le(i,o):0;a=Math.max(g,b)}s.push({name:"text",score:a,weight:.3});const c=new Set((t.classes||[]).filter(g=>!ie(g))),u=Array.from(e.classList||[]),d=c.size?u.filter(g=>c.has(g)).length/c.size:.5;s.push({name:"classes",score:d,weight:.2});const h=t.stableAttributes||{},p=Object.keys(h);let y=.5;if(p.length){let g=0;for(const b of p)e.getAttribute(b)===h[b]&&g++;y=g/p.length}s.push({name:"attributes",score:y,weight:.2});const v=t.childCount!==void 0?e.children.length===t.childCount?1:le(String(t.childCount),String(e.children.length)):.5;if(s.push({name:"childCount",score:v,weight:.05}),t.fingerprintHash){const g={fingerprintId:"snapshot",hash:t.fingerprintHash,tagHierarchy:[t.tag],stableAttributes:h,meaningfulText:i,classes:t.classes||[],dimensions:{width:0,height:0},ancestorPattern:"",descendantPattern:"",volatilityRisk:"medium",volatilityReasons:[]},b=this.fingerprintEngine.fingerprint(e),T=this.fingerprintEngine.compare(g,b);s.push({name:"fingerprint",score:T.score,weight:.1})}const m=s.reduce((g,b)=>g+b.score*b.weight,0);return{score:Math.max(0,Math.min(1,m)),components:s}}diagnose(e){const t=[];let s=!0,n=0,i,r=[];try{n=this.doc.querySelectorAll(e).length}catch(o){s=!1,i=o.message,t.push("Selector is syntactically invalid CSS.")}if(s&&n===0){t.push("Selector parses but matches nothing — element may be removed, re-rendered, or inside a shadow root."),r=this.relaxSelector(e);for(const o of r)try{if(this.doc.querySelectorAll(o).length>0){t.push(`Relaxed form "${o}" matches — the over-specific part of the selector is stale.`);break}}catch{}}return s&&n>1&&t.push(`Selector matches ${n} elements — it is ambiguous; use a more specific form or index.`),{selector:e,valid:s,matches:n,parseError:i,closestWorkingSelectors:r.filter(o=>{try{return this.doc.querySelectorAll(o).length>0}catch{return!1}}),diagnosis:t}}relaxSelector(e){const t=[],s=e.split(/[ >]+/).filter(Boolean);s.length>1&&(t.push(s.slice(0,-1).join(" ")),t.push(s[s.length-1]));const n=e.replace(/:nth-of-type\(\d+\)/g,"").replace(/\.[^. >#:[]+/g,(i,r,o)=>o[r-1]==="\\"?i:"");return n!==e&&n.trim()&&t.push(n.trim()),t}}function le(l,e){if(!l||!e)return 0;const t=Ae(l),s=Ae(e);if(t===s)return 1;if(t.includes(s)||s.includes(t))return .7;const n=new Set(t.split(/\s+/)),i=new Set(s.split(/\s+/));return Array.from(n).filter(o=>i.has(o)).length/Math.max(n.size,i.size)}function Ae(l){return l.toLowerCase().replace(/[^a-z0-9 ]/g," ").replace(/\s+/g," ").trim()}function Ie(l){return{tag:l.tagName.toLowerCase(),id:l.getAttribute("id")||void 0,text:B(l).slice(0,60),classes:Array.from(l.classList||[])}}class ue{constructor(e){f(this,"state");this.state=e>>>0,this.state===0&&(this.state=2654435769)}next(){this.state=this.state+1831565813>>>0;let e=this.state;return e=Math.imul(e^e>>>15,e|1),e^=e+Math.imul(e^e>>>7,e|61),((e^e>>>14)>>>0)/4294967296}range(e,t){return e+this.next()*(t-e)}int(e,t){return Math.floor(this.range(e,t+1))}chance(e){return this.next()setTimeout(t,e))}chance(){return this.rng.next()<.5}}const ot=[{ruleId:"red_key_password",kind:"key-pattern",pattern:"password|passwd|pwd",description:"Keys containing password/passwd/pwd",enabled:!0,userAdded:!1},{ruleId:"red_key_token",kind:"key-pattern",pattern:"token|jwt|bearer|auth|session.?id|secret|api.?key|client.?secret",description:"Keys containing token/jwt/auth/session-id/secret/api-key",enabled:!0,userAdded:!1},{ruleId:"red_key_credential",kind:"key-pattern",pattern:"credential|login|user.?pass|otp|2fa|mfa|verification",description:"Keys containing credential/login/otp/2fa/verification",enabled:!0,userAdded:!1},{ruleId:"red_key_payment",kind:"key-pattern",pattern:"card|payment|billing|iban|cvv|cvc|pan",description:"Keys containing card/payment/billing/iban/cvv",enabled:!0,userAdded:!1},{ruleId:"red_key_personal",kind:"key-pattern",pattern:"ssn|social.?security|national.?id|passport|tax.?id",description:"Keys containing personal identifier patterns",enabled:!0,userAdded:!1},{ruleId:"red_val_jwt",kind:"value-pattern",pattern:"eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+",description:"JWT-shaped tokens",enabled:!0,userAdded:!1},{ruleId:"red_val_bearer",kind:"value-pattern",pattern:"bearer\\s+[A-Za-z0-9._-]+",description:"Bearer tokens",enabled:!0,userAdded:!1},{ruleId:"red_val_long_hex",kind:"value-pattern",pattern:"\\b[a-f0-9]{32,}\\b",description:"32+ char hex strings (session/API ids)",enabled:!0,userAdded:!1},{ruleId:"red_val_sk",kind:"value-pattern",pattern:"\\b(sk|pk|rk)_[A-Za-z0-9_]{20,}\\b",description:"Stripe-style secret keys (sk_live_…)",enabled:!0,userAdded:!1},{ruleId:"red_attr_input_password",kind:"attribute-name",pattern:"value",description:"value attributes on password inputs handled by PrivacyEngine maskValue",enabled:!0,userAdded:!1},{ruleId:"red_attr_secret",kind:"attribute-name",pattern:"data-secret|data-token|data-api-key|secret|access.?token",description:"Secret-carrying attributes",enabled:!0,userAdded:!1}],at=[{exclusionId:"excl_mcpdom_overlay",selector:"[data-mcpdom-internal], [data-forensic-internal], #forensic-recorder-floating-host, #forensic-inspect-highlighter",reason:"MCPDOM-injected UI must never contaminate captured DOM (§68 clean capture)",userAdded:!1},{exclusionId:"excl_mcpdom_ids",selector:'[id^="forensic-"], [id^="mcpdom-"]',reason:"MCPDOM-namespaced nodes",userAdded:!1}],de="[REDACTED]";class he{constructor(e){f(this,"config");f(this,"base",new se);f(this,"compiledKeyPatterns",[]);f(this,"compiledValuePatterns",[]);f(this,"compiledAttrPatterns",[]);this.config={rules:[...ot],exclusions:[...at],stubMode:!0,...e},this.recompile()}recompile(){this.compiledKeyPatterns=[],this.compiledValuePatterns=[],this.compiledAttrPatterns=[];for(const e of this.config.rules){if(!e.enabled)continue;const t="i";try{switch(e.kind){case"key-pattern":this.compiledKeyPatterns.push(new RegExp(e.pattern,t));break;case"value-pattern":this.compiledValuePatterns.push(new RegExp(e.pattern,"i"));break;case"attribute-name":this.compiledAttrPatterns.push(new RegExp(`^(${e.pattern})$`,"i"));break}}catch{}}}getRules(){return[...this.config.rules]}setRuleEnabled(e,t){const s=this.config.rules.find(n=>n.ruleId===e);return s?(s.enabled=t,this.recompile(),!0):!1}addRule(e){const t=`red_custom_${this.config.rules.length+1}_${Date.now().toString(36)}`,s={...e,ruleId:t,userAdded:!0};return this.config.rules.push(s),this.recompile(),s}removeRule(e){const t=this.config.rules.findIndex(s=>s.ruleId===e);return t<0||!this.config.rules[t].userAdded?!1:(this.config.rules.splice(t,1),this.recompile(),!0)}getExclusions(){return[...this.config.exclusions]}addExclusion(e,t){const n={exclusionId:`excl_custom_${this.config.exclusions.length+1}_${Date.now().toString(36)}`,selector:e,reason:t,userAdded:!0};return this.config.exclusions.push(n),n}removeExclusion(e){const t=this.config.exclusions.findIndex(s=>s.exclusionId===e);return t<0||!this.config.exclusions[t].userAdded?!1:(this.config.exclusions.splice(t,1),!0)}isSensitiveKey(e){return this.compiledKeyPatterns.some(t=>t.test(e))}redactValue(e){let t=e;for(const s of this.compiledValuePatterns)s.test(t)&&(t=t.replace(new RegExp(s.source,"gi"),de));return t}redactByKeyValue(e,t){return this.isSensitiveKey(e)?this.config.stubMode?de:t:this.redactValue(t)}isSensitiveAttribute(e){return this.compiledAttrPatterns.some(t=>t.test(e))}redactAttributes(e){const t={};for(const[s,n]of Object.entries(e))this.isSensitiveAttribute(s)?t[s]=de:t[s]=this.redactValue(n);return t}cleanSubtree(e){const t=e.cloneNode(!0);for(const s of this.config.exclusions){let n=null;try{n=t.querySelectorAll(s.selector)}catch{continue}for(const i of Array.from(n))i.remove();try{if(t.matches(s.selector))return this.doclessEmptyStub(t)}catch{}}return t}isExcluded(e){for(const t of this.config.exclusions)try{if(e.matches(t.selector)||e.closest(t.selector))return!0}catch{}return!1}doclessEmptyStub(e){return e.innerHTML="",e.setAttribute("data-mcpdom-excluded","true"),e}toJSON(){return{rules:this.getRules(),exclusions:this.getExclusions(),stubMode:this.config.stubMode}}static fromJSON(e){return new he({rules:Array.isArray(e==null?void 0:e.rules)?e.rules:void 0,exclusions:Array.isArray(e==null?void 0:e.exclusions)?e.exclusions:void 0,stubMode:typeof(e==null?void 0:e.stubMode)=="boolean"?e.stubMode:void 0})}}const ge='a[href], button, input, select, textarea, [role="button"], [role="link"], [role="tab"], [onclick], [tabindex]';function X(l,e){return{items:l.slice(0,e),truncated:l.length>e}}function k(l,e,t,s,n,i){return{analyzer:l,summary:e,count:t,items:s,warnings:n,truncated:i}}function D(l){try{return L.inspectElement(l).bestSelector}catch{return l.tagName.toLowerCase()}}const ct=l=>{const e=Array.from(l.querySelectorAll("form")),t=e.map(n=>{const i=Array.from(n.querySelectorAll("input, select, textarea")).map(r=>({tag:r.tagName.toLowerCase(),type:r.getAttribute("type")||(r.tagName.toLowerCase()==="textarea"?"textarea":r.tagName.toLowerCase()==="select"?"select":"text"),name:r.getAttribute("name")||void 0,id:r.getAttribute("id")||void 0,required:r.hasAttribute("required"),pattern:r.getAttribute("pattern")||void 0,maxLength:r.getAttribute("maxlength")||void 0,placeholder:r.getAttribute("placeholder")||void 0,ariaLabel:r.getAttribute("aria-label")||void 0,autocomplete:r.getAttribute("autocomplete")||void 0,hasLabel:!!(r.getAttribute("id")&&l.querySelector(`label[for="${r.getAttribute("id")}"]`))||!!r.closest("label"),defaultValue:r.value!==void 0&&(r.getAttribute("type")||"text")!=="password"?String(r.value).slice(0,40):void 0}));return{selector:D(n),action:n.getAttribute("action")||void 0,method:(n.getAttribute("method")||"GET").toUpperCase(),id:n.getAttribute("id")||void 0,fieldCount:i.length,submitButton:n.querySelector('button[type="submit"], input[type="submit"]')?D(n.querySelector('button[type="submit"], input[type="submit"]')):void 0,validationAttributes:i.filter(r=>r.required||r.pattern).length,fields:i}}),s=X(t,50);return k("analyze_forms",`${e.length} form(s) with ${t.reduce((n,i)=>n+i.fieldCount,0)} total fields`,e.length,s.items,[],s.truncated)},lt=l=>{const e=Array.from(l.querySelectorAll("a[href]")),t=e.map(n=>({href:n.getAttribute("href")||"",text:B(n).slice(0,60),selector:D(n),rel:n.getAttribute("rel")||void 0,target:n.getAttribute("target")||void 0,download:n.hasAttribute("download"),external:/^https?:\/\//i.test(n.getAttribute("href")||"")&&!ut(n.getAttribute("href")||"",l),anchorOnly:(n.getAttribute("href")||"").startsWith("#")})),s=X(t,200);return k("extract_links",`${e.length} link(s): ${t.filter(n=>n.external).length} external, ${t.filter(n=>n.anchorOnly).length} anchors`,e.length,s.items,[],s.truncated)};function ut(l,e){var t,s,n,i;try{return new URL(l,((s=(t=e.defaultView)==null?void 0:t.location)==null?void 0:s.href)||"http://localhost").origin===(((i=(n=e.defaultView)==null?void 0:n.location)==null?void 0:i.origin)||"")}catch{return!1}}const dt=l=>{const e=Array.from(l.querySelectorAll("img")),t=Array.from(l.querySelectorAll("video")),s=Array.from(l.querySelectorAll("audio")),n=Array.from(l.querySelectorAll("canvas")),i=[],r=[...e.map(c=>({kind:"img",selector:D(c),src:(c.getAttribute("src")||"").slice(0,150),alt:c.getAttribute("alt"),width:c.getAttribute("width")||void 0,height:c.getAttribute("height")||void 0,naturalWidth:c.naturalWidth||void 0,naturalHeight:c.naturalHeight||void 0,lazy:c.getAttribute("loading")==="lazy",missingAlt:!c.hasAttribute("alt")})),...t.map(c=>{var u;return{kind:"video",selector:D(c),src:(c.getAttribute("src")||((u=c.querySelector("source"))==null?void 0:u.getAttribute("src"))||"").slice(0,150),controls:c.hasAttribute("controls"),autoplay:c.hasAttribute("autoplay"),muted:c.hasAttribute("muted"),poster:c.getAttribute("poster")||void 0}}),...s.map(c=>{var u;return{kind:"audio",selector:D(c),src:(c.getAttribute("src")||((u=c.querySelector("source"))==null?void 0:u.getAttribute("src"))||"").slice(0,150),controls:c.hasAttribute("controls")}}),...n.map(c=>({kind:"canvas",selector:D(c),width:c.width,height:c.height}))],o=r.filter(c=>c.missingAlt).length;o&&i.push(`${o} image(s) missing alt text (accessibility risk).`);const a=X(r,200);return k("analyze_media",`${e.length} images, ${t.length} videos, ${s.length} audios, ${n.length} canvases`,r.length,a.items,i,a.truncated)},ht=l=>{const e=l.defaultView,t=[],s={};if(e!=null&&e.getComputedStyle){const i=e.getComputedStyle(l.documentElement);for(let r=0;r({name:i,value:r}));return k("get_css_variables",`${n.length} CSS custom properties found`,n.length,n,t,!1)},gt=l=>{const e=l.defaultView,t=[],s=new Map;if(e!=null&&e.getComputedStyle)for(const i of Array.from(l.querySelectorAll("body, body *")).slice(0,800)){const r=e.getComputedStyle(i),o=r.fontFamily||"",a=r.fontSize||"",c=`${o.split(",")[0].replace(/["']/g,"").trim()} @ ${a}`;s.set(c,(s.get(c)||0)+1)}else t.push("getComputedStyle unavailable — font usage analysis requires rendered styles.");const n=Array.from(s.entries()).map(([i,r])=>({font:i,usage:r})).sort((i,r)=>r.usage-i.usage);return k("analyze_fonts",`${n.length} distinct font/size combinations`,n.length,n,t,!1)},pt=l=>{const e=l.defaultView,t=[],s=new Map;if(e!=null&&e.getComputedStyle)for(const i of Array.from(l.querySelectorAll("body, body *")).slice(0,800)){const r=e.getComputedStyle(i);for(const o of["color","background-color","border-top-color"]){const a=r.getPropertyValue(o);a&&a!=="rgba(0, 0, 0, 0)"&&s.set(a,(s.get(a)||0)+1)}}else{for(const i of Array.from(l.querySelectorAll("[style]")).slice(0,300)){const r=i.getAttribute("style")||"",o=/(color)\s*:\s*([^;]+)/gi;let a;for(;a=o.exec(r);)s.set(a[2].trim(),(s.get(a[2].trim())||0)+1)}t.push("getComputedStyle unavailable — palette from inline styles only.")}const n=Array.from(s.entries()).map(([i,r])=>({color:i,usage:r})).sort((i,r)=>r.usage-i.usage).slice(0,40);return k("extract_color_palette",`${s.size} distinct colors in use`,s.size,n,t,!1)},mt=l=>{const e=l.defaultView,t=[],s=[];if(!(e!=null&&e.getComputedStyle))return t.push("getComputedStyle unavailable — z-index analysis requires rendered styles."),k("detect_zindex_conflicts","unavailable",0,[],t,!1);const n=[];for(const i of Array.from(l.querySelectorAll("body *")).slice(0,1e3)){const r=e.getComputedStyle(i),o=r.zIndex;o&&o!=="auto"&&parseInt(o,10)>0&&n.push({selector:D(i),z:parseInt(o,10),position:r.position,stacking:r.position==="fixed"||r.position==="sticky"||r.opacity!=="1"||r.transform!=="none"?"creates-stacking-context":"plain"})}for(let i=0;i1e5&&s.push({zIndex:n[i].z,elements:[n[i].selector],note:"extremely high z-index — competes with platform overlays (MCPDOM uses 2147483640+)."})}return k("detect_zindex_conflicts",`${n.length} z-indexed elements, ${s.length} potential conflict(s)`,s.length,X(s,40).items,t,s.length>40)},ft=l=>{const e=l.defaultView,t=[],s=l.documentElement,n=l.body,i=Math.max((s==null?void 0:s.scrollWidth)||0,(n==null?void 0:n.scrollWidth)||0),r=(e==null?void 0:e.innerWidth)||(s==null?void 0:s.clientWidth)||0,o=i>r+1;if(o&&(t.push({issue:"horizontal-overflow",detail:`document scrollWidth ${i} exceeds viewport ${r}`}),e!=null&&e.getComputedStyle))for(const c of Array.from(l.querySelectorAll("body *")).slice(0,600)){const u=c.getBoundingClientRect();if(u.right>r+2&&u.width>100&&(t.push({issue:"element-exceeds-viewport",selector:D(c),right:Math.round(u.right),width:Math.round(u.width)}),t.length>15))break}let a=0;for(const c of Array.from(l.querySelectorAll(ge)).slice(0,500)){const u=c.getBoundingClientRect();(u.width===0||u.height===0)&&a++}return a&&t.push({issue:"zero-size-interactive-elements",count:a}),k("detect_layout_issues",o?`HORIZONTAL OVERFLOW: page is ${i-r}px wider than viewport`:"No horizontal overflow detected",t.length,t,[],!1)},bt=l=>{const e=Array.from(l.querySelectorAll(ge)),t=new Map,s=e.slice(0,300).map(n=>{const i=pe(n),r=i.role||n.tagName.toLowerCase();return t.set(r,(t.get(r)||0)+1),{selector:i.bestSelector,tag:i.tag,role:i.role,text:i.text.slice(0,40),visible:i.visibility.isVisible,disabled:n.disabled||n.hasAttribute("disabled"),inViewport:i.visibility.isInViewport}});return k("census_interactive_elements",`${e.length} interactive elements: ${Array.from(t.entries()).map(([n,i])=>`${n}×${i}`).join(", ")||"none"}`,e.length,s,[],e.length>300)};function pe(l){try{return L.inspectElement(l)}catch{return{tag:l.tagName.toLowerCase(),role:void 0,text:"",bestSelector:l.tagName.toLowerCase(),bounds:{x:0,y:0,width:0,height:0,top:0,right:0,bottom:0,left:0},visibility:{isVisible:!1,isInViewport:!1}}}}const yt=l=>{const e=["header","nav","main","aside","footer","article","section","figure","figcaption","mark","time","address","details","summary","dialog"],t=[];for(const i of e){const r=Array.from(l.querySelectorAll(i));if(r.length)for(const o of r.slice(0,20))t.push({tag:i,selector:D(o),role:o.getAttribute("role")||Et(i),text:B(o).slice(0,50),childCount:o.children.length})}const s=t.filter(i=>["banner","navigation","main","complementary","contentinfo"].includes(i.role)),n=[];return t.find(i=>i.tag==="main")||n.push("No
element — page lacks a primary landmark."),l.querySelectorAll("header").length>1&&n.push("Multiple
elements outside sections — ambiguous banner landmark."),k("detect_semantic_elements",`${t.length} semantic elements, ${s.length} landmarks`,t.length,X(t,100).items,n,t.length>100)};function Et(l){return{header:"banner",nav:"navigation",main:"main",aside:"complementary",footer:"contentinfo",article:"article",section:"region",form:"form"}[l]}const _e={analyze_forms:ct,extract_links:lt,analyze_media:dt,get_css_variables:ht,analyze_fonts:gt,extract_color_palette:pt,detect_zindex_conflicts:mt,detect_layout_issues:ft,census_interactive_elements:bt,detect_semantic_elements:yt,scan_accessibility_issues:l=>{var i;const e=[];for(const r of Array.from(l.querySelectorAll("img")).slice(0,200))r.hasAttribute("alt")||e.push({rule:"img-alt",severity:"error",selector:D(r),message:"Image is missing the alt attribute."});for(const r of Array.from(l.querySelectorAll("input:not([type=hidden]):not([type=submit]):not([type=button])")).slice(0,200)){const o=r.getAttribute("id");o&&l.querySelector(`label[for="${o}"]`)||r.closest("label")||r.getAttribute("aria-label")||r.getAttribute("aria-labelledby")||e.push({rule:"input-label",severity:"error",selector:D(r),message:"Form input has no associated label, aria-label or aria-labelledby."})}for(const r of Array.from(l.querySelectorAll('button, a[href], [role="button"]')).slice(0,300)){const o=B(r).trim(),a=r.getAttribute("aria-label");!o&&!a&&e.push({rule:"accessible-name",severity:"error",selector:D(r),message:"Interactive element has no accessible name (no text, no aria-label).",hint:r.querySelector("img[alt]")?"Contains an image — consider alt text or aria-label.":void 0})}const t=Array.from(l.querySelectorAll("h1, h2, h3, h4, h5, h6")).slice(0,100);let s=0;for(const r of t){const o=parseInt(r.tagName[1],10);s&&o>s+1&&e.push({rule:"heading-order",severity:"warning",selector:D(r),message:`Heading level jumps from h${s} to h${o}.`}),s=o}(i=l.documentElement)!=null&&i.getAttribute("lang")||e.push({rule:"html-lang",severity:"warning",selector:"html",message:"The element has no lang attribute."});const n=e.filter(r=>r.severity==="error").length;return k("scan_accessibility_issues",`${e.length} issue(s): ${n} errors, ${e.length-n} warnings`,e.length,X(e,100).items,[],e.length>100)},detect_dead_click_targets:l=>{const e=l.defaultView,t=[];for(const s of Array.from(l.querySelectorAll(ge)).slice(0,500)){const n=s.getBoundingClientRect(),i=e!=null&&e.getComputedStyle?e.getComputedStyle(s):null,r=n.width===0||n.height===0,o=i?i.pointerEvents==="none":!1,a=i?i.display==="none"||i.visibility==="hidden":!1,c=s.getAttribute("aria-hidden")==="true";(r||o||a||c)&&t.push({selector:D(s),tag:s.tagName.toLowerCase(),text:B(s).slice(0,30),reasons:[r&&"zero-size",o&&"pointer-events:none",a&&`hidden (${i?i.display:"?"}/${i?i.visibility:"?"})`,c&&"aria-hidden"].filter(Boolean)})}return k("detect_dead_click_targets",`${t.length} unreachable interactive element(s)`,t.length,X(t,80).items,[],t.length>80)},inventory_animations:l=>{const e=l.defaultView,t=[],s=[];if(!(e!=null&&e.getComputedStyle))return t.push("getComputedStyle unavailable — animation inventory requires rendered styles."),k("inventory_animations","unavailable",0,[],t,!1);for(const i of Array.from(l.querySelectorAll("body *")).slice(0,800)){const r=e.getComputedStyle(i),o=r.animationName!=="none"?`${r.animationName} ${r.animationDuration}`:null,a=r.transitionProperty!=="none"&&r.transitionProperty!=="all"?`${r.transitionProperty} ${r.transitionDuration}`:r.transitionProperty==="all"?`all ${r.transitionDuration}`:null;(o||a)&&s.push({selector:D(i),animation:o,transition:a,transitionTiming:r.transitionTimingFunction||void 0})}const n=s.filter(i=>i.animation&&i.animation.includes("infinite"));return n.length>5&&t.push(`${n.length} infinitely looping animations — may indicate decorative spinners or a stuck loading state.`),k("inventory_animations",`${s.length} animated/transitioning elements`,s.length,X(s,80).items,t,s.length>80)},map_frame_tree:l=>{const e=[],t=(n,i,r)=>{const o=Array.from(n.querySelectorAll("iframe, frame"));for(const a of o){const c=a.getAttribute("src")||"(no src)";let u=!1,d=null;try{const h=a.contentDocument;h&&(u=!0,d=h.querySelectorAll("*").length,r<3&&t(h,`${i} > ${a.tagName.toLowerCase()}[${c.slice(0,50)}]`,r+1))}catch{u=!1}e.push({path:`${i} > ${a.tagName.toLowerCase()}`,selector:D(a),src:c.slice(0,120),title:a.getAttribute("title")||void 0,name:a.getAttribute("name")||void 0,sandbox:a.getAttribute("sandbox")||void 0,accessible:u,childCount:d,limitation:u?void 0:"Same-origin policy blocks contentDocument access (cross-origin frame)."})}};t(l,"document",0);const s=e.filter(n=>!n.accessible).length;return k("map_frame_tree",`${e.length} frame(s), ${s} inaccessible (cross-origin)`,e.length,e,[],!1)},inventory_shadow_roots:l=>{const e=[],t=(s,n,i)=>{const r=(s instanceof ShadowRoot,Array.from(s.querySelectorAll("*")));for(const o of r)if(o.shadowRoot){const a=o.shadowRoot,c=`${n} > ${o.tagName.toLowerCase()}::shadowRoot(${a.mode})`;e.push({path:c.slice(0,200),hostSelector:D(o),hostTag:o.tagName.toLowerCase(),mode:a.mode,childCount:a.querySelectorAll("*").length,styles:a.querySelectorAll("style").length}),i<4&&t(a,c,i+1)}};return t(l.documentElement,"document",0),k("inventory_shadow_roots",`${e.length} open shadow root(s) found`,e.length,e,[],!1)},inspect_page_storage:l=>{const e=l.defaultView,t=new he,s=[],n=[];if(!(e!=null&&e.localStorage)||!(e!=null&&e.sessionStorage))return k("inspect_page_storage","Web Storage API unavailable in this context",0,[],["localStorage/sessionStorage are not accessible here (JSDOM limitation or sandboxed iframe)."],!1);try{for(let r=0;rr+(o.size||0),0);return k("inspect_page_storage",`${n.length} storage entries (~${i} bytes), sensitive keys redacted`,n.length,X(n,100).items,s,n.length>100)},get_performance_metrics:l=>{var i,r,o,a;const e=l.defaultView,t=[],s=e==null?void 0:e.performance;if(!(s!=null&&s.timing)&&!(s!=null&&s.getEntriesByType))return k("get_performance_metrics","Performance API unavailable",0,[],["window.performance is not exposed in this context."],!1);const n=[];try{const c=(r=(i=s.getEntriesByType)==null?void 0:i.call(s,"navigation"))==null?void 0:r[0];if(c)n.push({metric:"navigation-timing",domContentLoaded:Math.round(c.domContentLoadedEventEnd),loadComplete:Math.round(c.loadEventEnd),domInteractive:Math.round(c.domInteractive),type:c.type,redirectCount:c.redirectCount,sizeTransfer:c.transferSize});else if(s.timing){const h=s.timing;n.push({metric:"navigation-timing-legacy",domContentLoaded:h.domContentLoadedEventEnd-h.navigationStart,loadComplete:h.loadEventEnd-h.navigationStart,domInteractive:h.domInteractive-h.navigationStart})}const u=((o=s.getEntriesByType)==null?void 0:o.call(s,"paint"))||[];for(const h of u)n.push({metric:h.name,startTime:Math.round(h.startTime)});const d=((a=s.getEntriesByType)==null?void 0:a.call(s,"resource"))||[];if(d.length){const h=d.reduce((y,v)=>y+v.duration,0),p=[...d].sort((y,v)=>v.duration-y.duration).slice(0,5).map(y=>({url:String(y.name).slice(0,100),duration:Math.round(y.duration)}));n.push({metric:"resource-summary",count:d.length,totalDuration:Math.round(h),slowest:p})}s.memory&&n.push({metric:"memory",usedJSHeapMB:Math.round(s.memory.usedJSHeapSize/1048576*10)/10,totalJSHeapMB:Math.round(s.memory.totalJSHeapSize/1048576*10)/10})}catch(c){t.push(`performance read failed: ${c.message}`)}return k("get_performance_metrics",`${n.length} metric group(s)`,n.length,n,t,!1)},extract_seo_metadata:l=>{var r,o,a;const e=c=>{var u;return((u=l.querySelector(`meta[name="${c}"]`))==null?void 0:u.getAttribute("content"))||void 0},t=c=>{var u;return((u=l.querySelector(`meta[property="${c}"]`))==null?void 0:u.getAttribute("content"))||void 0},s=[{field:"title",value:l.title||void 0},{field:"description",value:e("description")},{field:"canonical",value:(r=l.querySelector('link[rel="canonical"]'))==null?void 0:r.getAttribute("href")},{field:"robots",value:e("robots")},{field:"viewport",value:e("viewport")},{field:"charset",value:(o=l.querySelector("meta[charset]"))==null?void 0:o.getAttribute("charset")},{field:"og:title",value:t("og:title")},{field:"og:description",value:t("og:description")},{field:"og:image",value:t("og:image")},{field:"og:url",value:t("og:url")},{field:"twitter:card",value:e("twitter:card")},{field:"language",value:(a=l.documentElement)==null?void 0:a.getAttribute("lang")}],n=l.querySelectorAll("h1").length,i=[];return n===0&&i.push("No h1 — page lacks a primary heading."),n>1&&i.push(`Multiple h1 elements (${n}).`),e("description")||i.push("No meta description."),s.push({field:"h1Count",value:n}),k("extract_seo_metadata",`SEO metadata extracted; ${i.length} warning(s)`,s.length,s,i,!1)},extract_structured_data:l=>{var t;const e=[];for(const s of Array.from(l.querySelectorAll('script[type="application/ld+json"]')))try{const n=JSON.parse(s.textContent||"{}");e.push({format:"JSON-LD",type:n["@type"]||(Array.isArray(n)?"array":"unknown"),data:n})}catch(n){e.push({format:"JSON-LD",type:"invalid-json",error:n.message})}for(const s of Array.from(l.querySelectorAll("[itemscope]")).slice(0,30)){const n=s.getAttribute("itemtype")||"unknown",i={};for(const r of Array.from(s.querySelectorAll("[itemprop]"))){const o=r.getAttribute("itemprop")||"",a=r.getAttribute("content")||r.getAttribute("href")||((t=r.textContent)==null?void 0:t.trim())||"";i[o]=a.slice(0,100)}e.push({format:"microdata",type:n.split("/").pop()||n,data:i})}return k("extract_structured_data",`${e.length} structured data block(s)`,e.length,e,[],!1)},extract_tables:l=>{const e=Array.from(l.querySelectorAll("table")),t=e.slice(0,30).map(s=>{var a,c,u;const n=Array.from(s.querySelectorAll("thead th, tr:first-child th")).map(d=>{var h;return((h=d.textContent)==null?void 0:h.trim())||""}),i=Array.from(s.querySelectorAll("tbody tr, tr")).filter(d=>!d.querySelector("th")).slice(0,50),r=i.map(d=>Array.from(d.querySelectorAll("td")).map(h=>(h.textContent||"").trim().slice(0,60))),o=(c=(a=s.querySelector("caption"))==null?void 0:a.textContent)==null?void 0:c.trim();return{selector:D(s),caption:o,columnCount:n.length||((u=r[0])==null?void 0:u.length)||0,rowCount:i.length,headers:n,rows:r}});return k("extract_tables",`${e.length} table(s)`,e.length,t,[],e.length>30)},extract_lists:l=>{const e=Array.from(l.querySelectorAll("ul, ol")),t=e.slice(0,60).map(s=>{const n=Array.from(s.querySelectorAll(":scope > li")).slice(0,40);return{selector:D(s),kind:s.tagName.toLowerCase(),ordered:s.tagName.toLowerCase()==="ol",itemCount:n.length,items:n.map(i=>B(i).slice(0,60)),nested:s.querySelectorAll("ul, ol").length}});return k("extract_lists",`${e.length} list(s)`,e.length,t,[],e.length>60)},analyze_page_content:l=>{const e=l.body,t=(e==null?void 0:e.innerText)||(e==null?void 0:e.textContent)||"",s=t.trim()?t.trim().split(/\s+/).length:0,n=Array.from(l.querySelectorAll("h1, h2, h3, h4, h5, h6")).map(c=>({level:parseInt(c.tagName[1],10),text:B(c).slice(0,80)})),i=l.querySelectorAll("p").length,r=i?Math.round(s/i):0,o=Math.round(s/220*10)/10,a=[{metric:"wordCount",value:s},{metric:"paragraphCount",value:i},{metric:"avgParagraphWords",value:r},{metric:"estimatedReadingMinutes",value:o},{metric:"headingCount",value:n.length},{metric:"imageCount",value:l.querySelectorAll("img").length},{metric:"linkDensity",value:Math.round(l.querySelectorAll("a[href]").length/Math.max(1,s)*1e3)/1e3},{metric:"headings",value:n.slice(0,50)}];return k("analyze_page_content",`${s} words, ${i} paragraphs, ~${o} min read`,a.length,a,[],!1)},search_dom:(l,e)=>{const t=String((e==null?void 0:e.query)||"").trim();if(!t)return k("search_dom","No query supplied",0,[],["Provide a text query; optionally tag/attr filters."],!1);const s=t.toLowerCase(),n=[],i=Math.min((e==null?void 0:e.limit)||50,200),r=Array.from(l.querySelectorAll("*"));for(const o of r){if(n.length>=i)break;if(e!=null&&e.tag&&o.tagName.toLowerCase()!==String(e.tag).toLowerCase())continue;const a=B(o),c=Array.from(o.attributes);let u=0,d="";o.tagName.toLowerCase().includes(s)&&(u+=.2,d="tag match"),a.toLowerCase().includes(s)&&a.length<200&&(u+=.6,d="text match");for(const h of c)if(h.name.toLowerCase().includes(s)||h.value.length<100&&h.value.toLowerCase().includes(s)){u+=.4,d=`attribute ${h.name} match`;break}if(e!=null&&e.attr){const h=String(e.attr).toLowerCase(),p=e.attrValue?String(e.attrValue).toLowerCase():null;if(c.find(v=>v.name.toLowerCase()===h&&(!p||v.value.toLowerCase().includes(p))))u+=.5;else continue}if(u>0){const h=pe(o);n.push({selector:h.bestSelector,tag:h.tag,role:h.role,text:h.text.slice(0,60),score:Math.round(u*100)/100,reason:d,visible:h.visibility.isVisible,bounds:{x:Math.round(h.bounds.x),y:Math.round(h.bounds.y),w:Math.round(h.bounds.width),h:Math.round(h.bounds.height)}})}}return n.sort((o,a)=>a.score-o.score),k("search_dom",`${n.length} element(s) match "${t}"`,n.length,n,[],n.length>=i)},inventory_ctas:l=>{var t;const e=[];for(const s of Array.from(l.querySelectorAll('button, a[class*="btn"], a[class*="button"], input[type="submit"], [role="button"]')).slice(0,100)){const n=pe(s);e.push({selector:n.bestSelector,tag:n.tag,text:n.text.slice(0,50),styleHint:(t=s.getAttribute("class"))==null?void 0:t.slice(0,60),primary:/primary|cta|submit|main/i.test(s.getAttribute("class")||"")||s.type==="submit",visible:n.visibility.isVisible})}return k("inventory_ctas",`${e.length} call-to-action element(s)`,e.length,e,[],!1)},detect_focus_traps:l=>{const e=[];for(const s of Array.from(l.querySelectorAll('[role="dialog"], [aria-modal="true"], dialog[open], .modal, [class*="modal"]')).slice(0,30)){const n=s.querySelectorAll('a[href], button, input, select, textarea, [tabindex]:not([tabindex="-1"])');e.push({selector:D(s),kind:s.getAttribute("role")||s.tagName.toLowerCase(),ariaModal:s.getAttribute("aria-modal"),focusableCount:n.length,firstFocusable:n[0]?D(n[0]):void 0,note:n.length===0?"Modal container has NO focusable elements — keyboard users are trapped.":void 0})}const t=l.querySelectorAll("[tabindex]>0");for(const s of Array.from(t).slice(0,20))e.push({selector:D(s),kind:"positive-tabindex",note:`tabindex=${s.tabIndex} breaks natural tab order.`});return k("detect_focus_traps",`${e.length} focus-management issue(s)/container(s)`,e.length,e,[],!1)},infer_responsive_breakpoints:l=>{const e=l.defaultView,t=[],s=new Set;for(const o of Array.from(l.querySelectorAll("style"))){const a=o.textContent||"",c=/@media[^{]*?\(\s*(?:min|max)-width\s*:\s*(\d+)(?:\.\d+)?px/g;let u;for(;u=c.exec(a);)s.add(parseInt(u[1],10))}for(const o of Array.from(l.querySelectorAll('link[rel="stylesheet"]')).slice(0,10)){const a=o.getAttribute("href")||"";if(/^\d+px$/.test(a)||a.includes("width=")){const c=a.match(/width=(\d+)/);c&&s.add(parseInt(c[1],10))}}for(const o of Array.from(l.querySelectorAll("img[srcset], source[srcset]")).slice(0,50)){const a=o.getAttribute("srcset")||"";for(const c of a.matchAll(/(\d+)w/g))s.add(parseInt(c[1],10))}e!=null&&e.matchMedia||t.push("matchMedia unavailable — live breakpoint probing skipped.");const n=Array.from(s).sort((o,a)=>o-a),i=n.map(o=>({breakpoint:o,note:o<=768?"mobile-class":o<=1024?"tablet-class":"desktop-class"})),r=e==null?void 0:e.innerWidth;if(r){const o=n.filter(a=>a<=r);i.unshift({breakpoint:`current viewport: ${r}px`,note:o.length?`below breakpoints: ${o.join(", ")}`:"no declared breakpoint below current width"})}return k("infer_responsive_breakpoints",`${n.length} breakpoint(s) inferred from CSS/srcset`,i.length,i,t,!1)},get_selection_state:l=>{var i;const e=l.defaultView,t=(i=e==null?void 0:e.getSelection)==null?void 0:i.call(e),s=l.activeElement,n=[{hasSelection:!!(t!=null&&t.toString()),selectedText:(t==null?void 0:t.toString().slice(0,200))||"",selectionRanges:(t==null?void 0:t.rangeCount)||0,activeElement:s?{tag:s.tagName.toLowerCase(),selector:D(s),editable:s.isContentEditable||["INPUT","TEXTAREA"].includes(s.tagName)}:null}];return k("get_selection_state",t!=null&&t.toString()?`Selection: "${t.toString().slice(0,40)}…"`:"No text selection",1,n,[],!1)}};function vt(l,e,t){const s=_e[l];return s?s(e,t):{analyzer:l,summary:`Unknown analyzer "${l}". Available: ${Object.keys(_e).join(", ")}`,count:0,items:[],warnings:[],truncated:!1}}const wt=2e3;class St{constructor(e=wt){f(this,"events",[]);f(this,"cap");f(this,"counter",0);this.cap=Math.max(10,e)}record(e,t,s={}){this.counter++;const n={eventId:`evt_${Date.now().toString(36)}_${this.counter}`,timestamp:Date.now(),kind:e,operationId:s.operationId,sessionId:s.sessionId,detail:t,data:s.data};return this.events.push(n),this.events.length>this.cap&&this.events.splice(0,this.events.length-this.cap),n}query(e){let t=this.events;e.kind&&(t=t.filter(n=>n.kind===e.kind)),e.operationId&&(t=t.filter(n=>n.operationId===e.operationId)),e.sinceTimestamp&&(t=t.filter(n=>n.timestamp>=e.sinceTimestamp));const s=e.limit&&e.limit>0?e.limit:200;return t.slice(-s)}size(){return this.events.length}toJSON(){return[...this.events]}}class Tt{constructor(){f(this,"counter",0);f(this,"operations",new Map)}begin(e){this.counter++;const t=`op_${Date.now().toString(36)}_${this.counter}`;return this.operations.set(t,{operationId:t,tool:e,startedAt:Date.now(),status:"RUNNING",timelineEventIds:[]}),t}end(e,t,s){const n=this.operations.get(e);n&&(n.endedAt=Date.now(),n.status=t,n.relatedError=s)}attachEvent(e,t){const s=this.operations.get(e);s&&s.timelineEventIds.push(t)}trace(e){const t=this.operations.get(e);return t?{...t,durationMs:t.endedAt?t.endedAt-t.startedAt:void 0}:null}recent(e=100){return Array.from(this.operations.values()).slice(-e).map(t=>({...t,durationMs:t.endedAt?t.endedAt-t.startedAt:void 0}))}}const xe=100;class Ct{constructor(e){f(this,"sessionId");f(this,"timeline",new St);f(this,"operations",new Tt);f(this,"tabs",new Map);f(this,"activeTabId",null);f(this,"startedAt",Date.now());f(this,"snapshots",[]);f(this,"commandHistory",[]);f(this,"annotationCount",0);f(this,"projectId");f(this,"tabCounter",0);f(this,"commandCounter",0);this.sessionId=e||`sess_${Date.now().toString(36)}`}registerTab(e,t,s){const n=e!==void 0?Array.from(this.tabs.values()).find(o=>o.browserTabId===e):void 0;if(n)return n.lastSeenAt=Date.now(),n.status="OPEN",n.url=t||n.url,n.title=s||n.title,n;this.tabCounter++;const i=`stab_${this.tabCounter}_${Date.now().toString(36)}`,r={sessionTabId:i,browserTabId:e,url:t,title:s,createdAt:Date.now(),lastSeenAt:Date.now(),status:"OPEN"};return this.tabs.set(i,r),this.timeline.record("TAB_OPENED",`tab ${i} registered (${t||"no url"})`,{sessionId:this.sessionId}),r}closeTab(e){const t=this.tabs.get(e);return t?(t.status="CLOSED",t.lastSeenAt=Date.now(),this.timeline.record("TAB_CLOSED",`tab ${e} closed`,{sessionId:this.sessionId}),!0):!1}switchTab(e){const t=this.tabs.get(e);return!t||t.status==="CLOSED"?!1:(this.activeTabId=e,this.timeline.record("TAB_SWITCHED",`active tab → ${e}`,{sessionId:this.sessionId}),!0)}getTabs(){return Array.from(this.tabs.values())}getActiveTab(){if(this.activeTabId){const e=this.tabs.get(this.activeTabId);if(e&&e.status==="OPEN")return e}return Array.from(this.tabs.values()).find(e=>e.status==="OPEN")||null}markAllStale(){let e=0;for(const t of this.tabs.values())t.status==="OPEN"&&(t.status="STALE",e++);return e}captureSnapshot(e,t,s){var a,c,u;const n=e.defaultView,i=((a=e.documentElement)==null?void 0:a.outerHTML)||"",r=e.querySelectorAll('a[href], button, input, select, textarea, [role="button"]').length,o={snapshotId:`snap_${Date.now().toString(36)}_${this.snapshots.length+1}`,timestamp:Date.now(),url:((c=n==null?void 0:n.location)==null?void 0:c.href)||((u=e.location)==null?void 0:u.href)||"",title:e.title||"",viewport:{width:(n==null?void 0:n.innerWidth)||0,height:(n==null?void 0:n.innerHeight)||0,scrollX:(n==null?void 0:n.scrollX)||0,scrollY:(n==null?void 0:n.scrollY)||0,devicePixelRatio:(n==null?void 0:n.devicePixelRatio)||1},domLength:i.length,domHash:ve(i),interactiveCount:r,selectedRegions:[],extensionEnabled:t,pendingMutations:s,annotationCount:this.annotationCount};return this.snapshots.push(o),this.snapshots.length>xe&&this.snapshots.splice(0,this.snapshots.length-xe),this.timeline.record("SNAPSHOT_CREATED",`snapshot ${o.snapshotId} (dom ${o.domLength}b)`,{sessionId:this.sessionId}),o}getSnapshot(e){return e?this.snapshots.find(t=>t.snapshotId===e)||null:this.snapshots[this.snapshots.length-1]||null}listSnapshots(){return this.snapshots.map(e=>({snapshotId:e.snapshotId,timestamp:e.timestamp,url:e.url,title:e.title,domLength:e.domLength,domHash:e.domHash}))}compareSnapshots(e,t){const s=["url","title","domLength","domHash","interactiveCount","extensionEnabled","annotationCount"],n=[];for(const r of s)e[r]!==t[r]&&n.push({field:r,before:e[r],after:t[r]});(e.viewport.width!==t.viewport.width||e.viewport.height!==t.viewport.height)&&n.push({field:"viewport",before:`${e.viewport.width}x${e.viewport.height}`,after:`${t.viewport.width}x${t.viewport.height}`});const i=t.domLength-e.domLength;return{identical:n.length===0,changes:n,domDelta:{beforeLength:e.domLength,afterLength:t.domLength,delta:i},summary:n.length===0?"States are identical.":`${n.length} field(s) changed; DOM size ${i>=0?"+":""}${i} bytes.`}}recordCommand(e,t,s,n,i){this.commandCounter++;const r=`cmd_${this.commandCounter}_${Date.now().toString(36)}`;return this.commandHistory.push({commandId:r,tool:e,args:t,outcome:s,timestamp:Date.now(),durationMs:n,error:i}),this.timeline.record("COMMAND_EXECUTED",`${e} → ${s}${i?` (${i})`:""}`,{sessionId:this.sessionId,data:{commandId:r}}),r}getCommandHistory(e=100){return this.commandHistory.slice(-e)}noteAnnotations(e){this.annotationCount=e}bindProject(e){this.projectId=e}getProjectId(){return this.projectId}summary(e,t,s,n){var i,r,o;return{sessionId:this.sessionId,startedAt:this.startedAt,url:((r=(i=e.defaultView)==null?void 0:i.location)==null?void 0:r.href)||((o=e.location)==null?void 0:o.href)||"",title:e.title||"",tabs:this.getTabs(),activeTabId:this.activeTabId,viewport:{width:t.width,height:t.height,isModified:t.isModified},extensionEnabled:s,snapshotCount:this.snapshots.length,commandCount:this.commandHistory.length,annotationCount:this.annotationCount,mutationHistoryCount:n.length,timelineEventCount:this.timeline.size(),projectId:this.projectId}}}const At=l=>{var e,t;try{const s=l.getBoundingClientRect();if(s.width===0&&s.height===0)return null;const n=((t=(e=l.ownerDocument)==null?void 0:e.defaultView)==null?void 0:t.innerWidth)||1920;return s.yn*1.5?"bottom":s.xn*.8?"right":"center"}catch{return null}},It={navigation:"navigation",banner:"header",contentinfo:"footer",complementary:"sidebar",main:"main",form:"form",search:"search",region:"section",dialog:"modal",alertdialog:"modal",table:"table",list:"list",combobox:"dropdown",button:"button",link:"link",textbox:"input",checkbox:"checkbox",radio:"radio",img:"image",article:"article"},_t={nav:"navigation",header:"header",footer:"footer",aside:"sidebar",main:"main",section:"section",article:"article",form:"form",table:"table",ul:"list",ol:"list",figure:"figure",dialog:"modal",button:"button",input:"input",select:"dropdown",textarea:"textarea",canvas:"canvas",video:"video",img:"image",h1:"heading",h2:"heading",h3:"heading"};function ee(l){return l.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"").replace(/_{2,}/g,"_").slice(0,48).replace(/_$/,"")}class xt{generate(e){return this.generateFromMeta({tagName:e.tagName.toLowerCase(),role:e.getAttribute("role")||void 0,text:B(e).trim(),ariaLabel:e.getAttribute("aria-label")||void 0,stableClass:Array.from(e.classList||[]).find(t=>/^[a-z][a-z0-9-]{2,}$/i.test(t)&&!Nt.has(t)),position:At(e),nearbyHeading:this.nearbyHeading(e)})}generateFromMeta(e){const t=[],s=[],n=e.role||Rt(e.tagName);if(n){const r=It[n]||n;s.push(r),t.push(`role=${n}`)}else{const r=_t[e.tagName]||e.tagName;s.push(r),t.push(`tag=${e.tagName}`)}if(e.ariaLabel&&(s.unshift(ee(e.ariaLabel)),t.push(`aria-label="${e.ariaLabel.slice(0,30)}"`)),e.text&&e.text.length<=40){const r=ee(e.text.split(/\s+/).slice(0,3).join(" "));r&&r.length>=2&&(s.push(r),t.push(`text="${e.text.slice(0,30)}"`))}if(e.nearbyHeading){const r=ee(e.nearbyHeading.split(/\s+/).slice(0,3).join(" "));r&&!s.includes(r)&&(s.push(r),t.push(`nearby-heading="${e.nearbyHeading.slice(0,30)}"`))}e.stableClass&&s.length<3&&(s.push(ee(e.stableClass)),t.push(`class=${e.stableClass}`)),e.tagName==="input"&&(s.some(r=>r.includes("input"))||(s.push("input"),t.push("tag=input"))),s.join("_").length<12&&e.position&&(s.push(e.position),t.push(`position=${e.position}`));let i=ee(s.join("_"))||"unnamed_region";return/^\d/.test(i)&&(i=`el_${i}`),{name:i,evidence:t}}nearbyHeading(e){let t=e.parentElement;for(let n=0;t&&n<4;n++){const i=t.querySelector('h1, h2, h3, h4, [role="heading"]');if(i)return B(i).trim().slice(0,40)||null;t=t.parentElement}let s=e.previousElementSibling;for(let n=0;s&&n<4;n++){if(/^H[1-4]$/.test(s.tagName)){const i=B(s).trim();if(i)return i.slice(0,40)}s=s.previousElementSibling}return null}}const Nt=new Set(["active","open","visible","hidden","selected","disabled","container","wrapper","root","item","col","row","flex","box","main","div","span","block"]);function Rt(l){switch(l){case"nav":return"navigation";case"header":return"banner";case"footer":return"contentinfo";case"aside":return"complementary";case"main":return"main";case"form":return"form";case"table":return"table";case"button":return"button";case"a":return"link";case"input":return"textbox";case"select":return"combobox";case"textarea":return"textbox";case"img":return"img";default:return null}}const Mt=["display","position","flex-direction","grid-template-columns","width","height","background-color","color","font-size","border-radius","overflow"];class kt{constructor(){f(this,"naming",new xt)}capture(e){const t=e.ownerDocument,s=new Z(t),n=new re,i=s.generateCandidates(e),r=s.bestSelector(e),o=n.fingerprint(e);let a=e,c=0,u="self";for(let g=0;g<3;g++){const b=a.parentElement;if(!b||b===t.body||b===t.documentElement)break;if(this.isMeaningfulContainer(b)){a=b,c=g+1,u="meaningful-ancestor";break}a=b,c=g+1}if(a===e){const g=e.parentElement;g&&g!==t.body&&e.querySelectorAll("*").length<4&&(a=g,c=1,u="direct-parent-fallback")}const d=this.boundedHtml(e,6e4),h=this.boundedHtml(a,12e4);L.inspectElement(e);const p=e.getBoundingClientRect(),y=t.defaultView,v={};if(y!=null&&y.getComputedStyle){const g=y.getComputedStyle(e);for(const b of Mt){const T=g.getPropertyValue(b);T&&T!=="none"&&T!=="auto"&&(v[b]=T)}}const m=e.parentElement;return{regionHtml:d,contextHtml:h,boundary:{strategy:u,ancestorLevels:c,note:c===0?"Region captured standalone (no meaningful ancestor within 3 levels).":`Context includes ${c} ancestor level(s) up to a meaningful container.`},selectorCandidates:i,bestSelector:r.selector,xpath:s.buildXPath(e),fingerprintHash:o.hash,dimensions:{width:Math.round(p.width),height:Math.round(p.height)},position:{x:Math.round(p.x),y:Math.round(p.y)},relevantStyles:v,parentInfo:m?{tag:m.tagName.toLowerCase(),selector:Ot(m),text:B(m).slice(0,60)}:void 0,childrenCount:e.children.length,childTags:Array.from(e.children).slice(0,12).map(g=>g.tagName.toLowerCase()),nameHint:this.naming.generate(e),fingerprintVolatility:o.volatilityRisk,volatilityReasons:o.volatilityReasons}}isMeaningfulContainer(e){const t=e.tagName.toLowerCase();if(["section","article","aside","main","nav","header","footer","form"].includes(t)||e.hasAttribute("id")||e.hasAttribute("data-testid")||e.getAttribute("role")||e.children.length>1&&e.querySelector(":scope > *:nth-child(3)"))return!0;const s=e.getAttribute("style")||"";return!!(s.includes("grid")||s.includes("flex"))}boundedHtml(e,t){const s=e.outerHTML;return s.length<=t?s:s.slice(0,t)+` -`}}function Ot(l){try{return new Z(l.ownerDocument).bestSelector(l).selector}catch{return l.tagName.toLowerCase()}}class Lt{constructor(e){f(this,"nodeRegistry");f(this,"snapshotEngine");f(this,"picker");f(this,"interactionEngine");f(this,"observer");f(this,"mutationEngines",new WeakMap);f(this,"viewportControllers",new WeakMap);f(this,"targetingEngines",new WeakMap);f(this,"jsEngine",new Fe);f(this,"fingerprintEngine",new re);f(this,"humanInteraction",new rt);f(this,"session",new Ct);f(this,"simulationTabs",[]);f(this,"simulationTabCounter",0);f(this,"simulationExtensions",[{id:"teledom@teledom",name:"TeleDOM Browser Intelligence Platform",version:"4.1.0",description:"The TeleDOM platform extension itself",enabled:!0,installType:"development",isApp:!1}]);f(this,"regionCapture",new kt);this.nodeRegistry=e||new z;const t=new se,s=new oe;this.snapshotEngine=new me(this.nodeRegistry,t,s),this.picker=new Ue({nodeRegistry:this.nodeRegistry}),this.interactionEngine=new De(this.nodeRegistry),this.observer=new Pe(this.nodeRegistry),this.picker.initGlobalShortcutListener(),this.interactionEngine.setTimingHook(async n=>{const i=this.humanInteraction.delay(n);i>0&&await new Promise(r=>setTimeout(r,i))})}getMutationEngine(e){let t=this.mutationEngines.get(e);return t||(t=new He(e,this.nodeRegistry),this.mutationEngines.set(e,t)),t}getViewportController(e){let t=this.viewportControllers.get(e);return t||(t=new ze(e),this.viewportControllers.set(e,t)),t}getTargetingEngine(e){let t=this.targetingEngines.get(e);return t||(t=new st(e,this.nodeRegistry),this.targetingEngines.set(e,t)),t}isSimulation(){return typeof globalThis.__FORENSIC_SIMULATION__<"u"}getPicker(){return this.picker}getInteractionEngine(){return this.interactionEngine}getObserver(){return this.observer}getNodeRegistry(){return this.nodeRegistry}async handleCommand(e,t=typeof document<"u"?document:{}){var o,a,c,u,d,h,p,y,v;const s=Date.now(),{id:n,command:i,payload:r}=e;try{switch(i){case"LIVE_PAGE_INSPECT":{const m=L.inspectPage(t);return this.success(n,i,m,s)}case"LIVE_ELEMENT_INSPECT":{const m=this.resolveTarget(r,t),g=L.inspectElement(m,this.nodeRegistry);return this.success(n,i,g,s)}case"GET_SELECTED_ELEMENT":{const m=this.picker.getLastSelectedElement();return this.success(n,i,m,s)}case"ELEMENT_PICKER_START":return this.picker.startPicker(),this.success(n,i,{pickerActive:!0},s);case"ELEMENT_PICKER_STOP":return this.picker.stopPicker(),this.success(n,i,{pickerActive:!1},s);case"LIVE_ELEMENT_INTERACT":{const m=r,g=await this.interactionEngine.interact(m,t);return this.success(n,i,g,s)}case"ELEMENT_OBSERVATION_START":{const m=this.resolveTarget(r,t),g=this.observer.startObservation(m,t);return this.success(n,i,g,s)}case"ELEMENT_OBSERVATION_STOP":{const m=this.observer.stopObservation(t);return this.success(n,i,m,s)}case"LIVE_DOM_SNAPSHOT":{if(((r==null?void 0:r.format)||"html")==="html"){const b=((o=t.documentElement)==null?void 0:o.outerHTML)||"";return this.success(n,i,{html:b},s)}const g=this.snapshotEngine.captureSnapshot(t,"live_session");return this.success(n,i,g,s)}case"LIVE_DOM_SUBTREE":{const m=this.resolveTarget(r,t),g=m.outerHTML||"",b=L.inspectElement(m,this.nodeRegistry);return this.success(n,i,{html:g,element:b},s)}case"GET_ELEMENT_VISUAL_STATE":{const m=this.resolveTarget(r,t),g=L.inspectVisualState(m);return this.success(n,i,g,s)}case"LIVE_PAGE_SCREENSHOT":case"LIVE_ELEMENT_SCREENSHOT":{const m=await this.handleScreenshotCapture(i,r,t);return this.success(n,i,m,s)}case"GET_TAB_CONSOLE_LOGS":{const{level:m,searchQuery:g,limit:b=100,clearAfterRead:T}=r||{};let w=typeof window<"u"&&window.__FORENSIC_CONSOLE_BUFFER__||[];if(m&&m!=="all"&&(w=w.filter(E=>E.level===m)),g){const E=String(g).toLowerCase();w=w.filter(C=>{var N,I;return((N=C.text)==null?void 0:N.toLowerCase().includes(E))||((I=C.source)==null?void 0:I.toLowerCase().includes(E))})}return b>0&&(w=w.slice(-b)),T&&typeof window<"u"&&window.__FORENSIC_CONSOLE_BUFFER__&&(window.__FORENSIC_CONSOLE_BUFFER__.length=0),this.success(n,i,{url:typeof window<"u"?window.location.href:"",title:t.title||"",totalCaptured:typeof window<"u"&&((a=window.__FORENSIC_CONSOLE_BUFFER__)==null?void 0:a.length)||w.length,returnedCount:w.length,logs:w},s)}case"GET_TAB_NETWORK_REQUESTS":{const{method:m,searchQuery:g,status:b,onlyErrors:T,limit:w=100,clearAfterRead:E}=r||{};let C=typeof window<"u"&&window.__FORENSIC_NETWORK_BUFFER__||[];if(m&&(C=C.filter(N=>{var I;return((I=N.method)==null?void 0:I.toUpperCase())===String(m).toUpperCase()})),b&&(C=C.filter(N=>N.status===Number(b))),T&&(C=C.filter(N=>N.error||N.status&&N.status>=400)),g){const N=String(g).toLowerCase();C=C.filter(I=>{var R;return(R=I.url)==null?void 0:R.toLowerCase().includes(N)})}return w>0&&(C=C.slice(-w)),E&&typeof window<"u"&&window.__FORENSIC_NETWORK_BUFFER__&&(window.__FORENSIC_NETWORK_BUFFER__.length=0),this.success(n,i,{url:typeof window<"u"?window.location.href:"",title:t.title||"",totalCaptured:typeof window<"u"&&((c=window.__FORENSIC_NETWORK_BUFFER__)==null?void 0:c.length)||C.length,returnedCount:C.length,requests:C},s)}case"CLOSE_TAB":{if(typeof globalThis.chrome<"u"&&((u=globalThis.chrome.runtime)!=null&&u.sendMessage)){const m=await new Promise(g=>{globalThis.chrome.runtime.sendMessage({type:"BROWSER_COMMAND_REQUEST",id:n,command:i,payload:r},b=>g(b))});if(m)return m}return this.isSimulation()?this.simulationCloseTab(r,t,n,i,s):typeof window<"u"?(setTimeout(()=>window.close(),100),this.success(n,i,{closed:!0,url:window.location.href,title:t.title},s)):this.success(n,i,{closed:!0},s)}case"RELOAD_TAB":{if(typeof globalThis.chrome<"u"&&((d=globalThis.chrome.runtime)!=null&&d.sendMessage)){const m=await new Promise(g=>{globalThis.chrome.runtime.sendMessage({type:"BROWSER_COMMAND_REQUEST",id:n,command:i,payload:r},b=>g(b))});if(m)return m}if(this.isSimulation()){const m=(r==null?void 0:r.mode)||"soft";return this.session.timeline.record("NAVIGATED",`tab reloaded (${m} mode)`),this.success(n,i,{reloaded:!0,mode:m,simulated:!0,url:((p=(h=t.defaultView)==null?void 0:h.location)==null?void 0:p.href)||"",title:t.title,note:"Node simulation context: DOM fixture retained; no real navigation occurs."},s)}return typeof window<"u"?(setTimeout(()=>window.location.reload(),100),this.success(n,i,{reloaded:!0,url:window.location.href,title:t.title},s)):this.success(n,i,{reloaded:!0},s)}case"OPEN_TAB":case"LIST_TABS":case"FOCUS_TAB":case"LIST_EXTENSIONS":case"RELOAD_EXTENSION":case"SET_EXTENSION_ENABLED":case"TOGGLE_EXTENSION":{if(this.isSimulation())return this.handleSimulationBackgroundCommand(n,i,r,t,s);if(typeof globalThis.chrome<"u"&&((y=globalThis.chrome.runtime)!=null&&y.sendMessage)){const m=await new Promise(g=>{globalThis.chrome.runtime.sendMessage({type:"BROWSER_COMMAND_REQUEST",id:n,command:i,payload:r},b=>g(b))});if(m)return m}return this.error(n,i,"BACKGROUND_EXECUTION_FAILED",`Command ${i} requires Chrome extension runtime`,s)}case"RESIZE_VIEWPORT":{const m=this.getViewportController(t);let g;if(r!=null&&r.preset)g=m.applyPreset(r.preset);else{const b=Number(r==null?void 0:r.width)||1280,T=Number(r==null?void 0:r.height)||800;g=m.resize(b,T)}return this.session.timeline.record("RESIZED",`viewport → ${g.applied.width}x${g.applied.height}`),this.success(n,i,g,s)}case"RESET_VIEWPORT":{const g=this.getViewportController(t).reset();return this.session.timeline.record("RESIZED",`viewport restored to ${g.applied.width}x${g.applied.height}`),this.success(n,i,g,s)}case"GET_VIEWPORT_STATE":{const m=this.getViewportController(t);return this.success(n,i,m.state(),s)}case"RUN_RESPONSIVE_TEST":{const m=this.getViewportController(t),g=(r==null?void 0:r.sizes)||Ut(),b=m.runResponsiveTest(g,{restore:(r==null?void 0:r.restore)!==!1});return this.success(n,i,b,s)}case"EMULATE_DEVICE":{const g=this.getViewportController(t).emulateDevice((r==null?void 0:r.device)||"pixel-7");return this.success(n,i,g,s)}case"EXECUTE_JS":case"EXECUTE_JS_AND_CAPTURE_CHANGES":{const m=String((r==null?void 0:r.code)||"");if(!m.trim())return this.error(n,i,"SCRIPT_EMPTY","payload.code is required.",s);const g=await this.jsEngine.execute(t,m,{timeoutMs:r==null?void 0:r.timeoutMs,world:(r==null?void 0:r.world)==="MAIN"?"MAIN":"ISOLATED"});return this.session.timeline.record("SCRIPT_EXECUTED",`${g.status} (${g.durationMs}ms)`),this.success(n,i,g,s)}case"DOM_MUTATE":{const g=this.getMutationEngine(t).mutate(r);return this.session.timeline.record("DOM_MUTATED",`${g.operation} on ${g.before.selector} → ${g.success?"OK":g.error}`),this.success(n,i,g,s)}case"DOM_MUTATE_TRANSACTION":{const m=this.getMutationEngine(t),g=(r==null?void 0:r.mode)||"begin";try{if(g==="begin"){const b=m.beginTransaction();return this.success(n,i,{transactionId:b,mode:g,open:!0},s)}if(g==="commit"){const b=m.commitTransaction();return this.session.timeline.record("DOM_MUTATED",`transaction ${b.transactionId} committed (${b.steps.length} steps)`),this.success(n,i,{...b,mode:g},s)}if(g==="rollback"){const b=m.rollbackTransaction(r==null?void 0:r.reason);return this.session.timeline.record("MUTATION_UNDONE",`transaction ${b.transactionId} rolled back`),this.success(n,i,{...b,mode:g},s)}return this.error(n,i,"INVALID_MODE",`mode must be begin|commit|rollback, got "${g}"`,s)}catch(b){return this.error(n,i,"DOM_MUTATION_FAILED",b.message,s)}}case"UNDO_DOM_MUTATION":{const g=this.getMutationEngine(t).undo();return g.success&&this.session.timeline.record("MUTATION_UNDONE",g.message),this.success(n,i,g,s)}case"REDO_DOM_MUTATION":{const g=this.getMutationEngine(t).redo();return g.success&&this.session.timeline.record("MUTATION_REDONE",g.message),this.success(n,i,g,s)}case"GET_MUTATION_HISTORY":{const m=this.getMutationEngine(t);return this.success(n,i,{entries:m.getHistory((r==null?void 0:r.limit)||100),undoDepth:m.getUndoDepth(),redoDepth:m.getRedoDepth(),openTransactionId:m.getOpenTransactionId()},s)}case"PREVIEW_DOM_MUTATION":{const g=this.getMutationEngine(t).preview(r);return this.success(n,i,g,s)}case"GENERATE_ELEMENT_TARGET":{const g=this.getTargetingEngine(t).resolveAndBuild((r==null?void 0:r.target)||(r==null?void 0:r.selector)||"");return"error"in g?this.error(n,i,"TARGET_NOT_FOUND",g.error,s):this.success(n,i,g.target,s)}case"RECOVER_SELECTOR":{const m=new it(t),g=(r==null?void 0:r.snapshot)||{},b=m.recover((r==null?void 0:r.selector)||"",g);return this.success(n,i,b,s)}case"GET_ELEMENT_ANCESTRY":{const m=this.resolveTarget(r,t);return this.success(n,i,Dt(m,t),s)}case"GET_ELEMENT_FINGERPRINT":{const m=this.resolveTarget(r,t),g=this.fingerprintEngine.fingerprint(m);return this.success(n,i,g,s)}case"GET_ELEMENT_RELATIONSHIPS":{const m=this.resolveTarget(r,t);return this.success(n,i,$t(m,t),s)}case"GET_ELEMENT_ACCESSIBILITY":{const m=this.resolveTarget(r,t);return this.success(n,i,qt(m),s)}case"GET_COMPUTED_STYLE":{const m=this.resolveTarget(r,t),g=t.defaultView;if(!(g!=null&&g.getComputedStyle))return this.error(n,i,"STYLE_UNAVAILABLE","getComputedStyle is unavailable in this context.",s);const b=g.getComputedStyle(m),T=Array.isArray(r==null?void 0:r.properties)&&r.properties.length?r.properties:["display","position","color","background-color","font-size","font-family","width","height","margin","padding","border","z-index","opacity","visibility","overflow","flex-direction","grid-template-columns"],w={};for(const E of T)w[E]=b.getPropertyValue(E);return this.success(n,i,{selector:L.inspectElement(m,this.nodeRegistry).bestSelector,styles:w},s)}case"ANALYZE_DOM":{const m=String((r==null?void 0:r.analyzer)||"");if(!m)return this.error(n,i,"ANALYZER_REQUIRED",'payload.analyzer is required (e.g. "analyze_forms").',s);const g=vt(m,t,r);return g.count===0&&g.warnings.length===0&&g.items.length===0&&g.summary.startsWith("Unknown analyzer")?this.error(n,i,"UNKNOWN_ANALYZER",g.summary,s):this.success(n,i,g,s)}case"DRAG_ELEMENT":{const m=this.resolveTarget(r==null?void 0:r.source,t),g=r!=null&&r.target?this.resolveTarget(r==null?void 0:r.target,t):null,b=await this.performDrag(m,g,r==null?void 0:r.offsets,t);return this.success(n,i,b,s)}case"SET_INPUT_CHECKED":{const g=this.resolveTarget(r,t);if(g.type!=="checkbox"&&g.type!=="radio")return this.error(n,i,"INPUT_TYPE_UNSUPPORTED",`Target input type "${g.type}" is not checkbox/radio.`,s);const b=g.checked;g.checked=(r==null?void 0:r.checked)!==!1;const T=[];for(const w of["input","change"])try{g.dispatchEvent(new t.defaultView.Event(w,{bubbles:!0})),T.push(w)}catch{}if(g.type==="radio"&&g.name)for(const w of Array.from(t.querySelectorAll(`input[type=radio][name="${g.name}"]`)))w!==g&&(w.checked=!1);return this.success(n,i,{success:!0,selector:L.inspectElement(g,this.nodeRegistry).bestSelector,inputType:g.type,checkedBefore:b,checkedAfter:g.checked,eventsFired:T},s)}case"PRESS_KEYBOARD_SHORTCUT":{const m=Array.isArray(r==null?void 0:r.keys)?r.keys:String((r==null?void 0:r.keys)||"Enter").split("+"),g=r!=null&&r.target?this.resolveTarget(r==null?void 0:r.target,t):t.activeElement||t.body;typeof g.focus=="function"&&g.focus();const b=[],T=t.defaultView;for(const w of m)for(const E of["keydown","keyup"])try{g.dispatchEvent(new((T==null?void 0:T.KeyboardEvent)||KeyboardEvent)(E,{key:w.trim(),bubbles:!0,cancelable:!0,ctrlKey:m.some(C=>/^(ctrl|control|cmd|meta)$/i.test(C))&&w!==m.find(C=>/^(ctrl|control|cmd|meta)$/i.test(C)),shiftKey:m.some(C=>/^shift$/i.test(C))&&w!=="Shift",altKey:m.some(C=>/^alt$/i.test(C))&&w!=="Alt"})),b.push(`${E}:${w}`)}catch{}return this.success(n,i,{success:!0,keys:m,targetSelector:L.inspectElement(g,this.nodeRegistry).bestSelector,eventsFired:b},s)}case"SCROLL_PAGE":{const m=t.defaultView;if(!m)return this.error(n,i,"NO_WINDOW","No window available for scrolling.",s);const g={x:m.scrollX||0,y:m.scrollY||0};let b;if(r!=null&&r.target||r!=null&&r.selector){const w=this.resolveTarget((r==null?void 0:r.target)||(r==null?void 0:r.selector),t);(v=w.scrollIntoView)==null||v.call(w,{behavior:(r==null?void 0:r.behavior)||"auto",block:"center"}),b=L.inspectElement(w,this.nodeRegistry).bestSelector}else m.scrollBy(Number(r==null?void 0:r.x)||0,Number(r==null?void 0:r.y)||0);const T={x:m.scrollX||0,y:m.scrollY||0};return this.success(n,i,{success:!0,scrollBefore:g,scrollAfter:T,requested:{x:Number(r==null?void 0:r.x)||0,y:Number(r==null?void 0:r.y)||0},targetSelector:b},s)}case"WAIT_FOR_CONDITION":return await this.waitForCondition(t,r||{},s,n,i);case"GET_PAGE_STATE":case"CAPTURE_PAGE_STATE":{const m=this.session.captureSnapshot(t,!0,this.getMutationEngine(t).getUndoDepth());return this.success(n,i,m,s)}case"CAPTURE_REGION":{const m=this.resolveTarget((r==null?void 0:r.target)||(r==null?void 0:r.selector),t),g=this.regionCapture.capture(m);return this.success(n,i,g,s)}case"GET_SIMULATION_TAB_STATE":return this.isSimulation()?this.success(n,i,{simulated:!0,tabs:this.simulationTabs,sessionSummary:this.session.getTabs()},s):this.error(n,i,"NOT_SIMULATION","Simulation tab state is only available in the Node simulation context.",s);default:return this.error(n,i,"UNKNOWN_COMMAND",`Unsupported command '${i}'`,s)}}catch(m){return this.error(n,i,"COMMAND_EXECUTION_FAILED",m.message,s,m.details)}}resolveTarget(e,t){if(!e)throw new Error("Target specifier must be provided");return typeof e=="string"?this.interactionEngine.resolveTarget({selector:e},t):typeof e=="number"?this.interactionEngine.resolveTarget({nodeId:e},t):this.interactionEngine.resolveTarget(e,t)}async performDrag(e,t,s,n){const i=n.defaultView,r=[],o=(p,y,v={})=>{try{const m=(i==null?void 0:i.MouseEvent)||(typeof MouseEvent<"u"?MouseEvent:null);m&&(p.dispatchEvent(new m(y,{bubbles:!0,cancelable:!0,...v})),r.push(y))}catch{}},a=e.getBoundingClientRect(),c=a.x+a.width/2,u=a.y+a.height/2;let d=c+((s==null?void 0:s.x)||0),h=u+((s==null?void 0:s.y)||0);if(t){const p=t.getBoundingClientRect();d=p.x+p.width/2,h=p.y+p.height/2}return o(e,"pointerdown",{button:1,clientX:c,clientY:u}),o(e,"mousedown",{button:1,clientX:c,clientY:u}),o(e,"dragstart",{clientX:c,clientY:u}),t&&(o(t,"dragenter",{clientX:d,clientY:h}),o(t,"dragover",{clientX:d,clientY:h}),o(t,"drop",{clientX:d,clientY:h})),o(e,"dragend",{clientX:d,clientY:h}),o(e,"pointerup",{button:1,clientX:d,clientY:h}),o(e,"mouseup",{button:1,clientX:d,clientY:h}),{success:r.length>0,sourceSelector:L.inspectElement(e,this.nodeRegistry).bestSelector,targetSelector:t?L.inspectElement(t,this.nodeRegistry).bestSelector:"(offset drop)",eventsFired:r,finalPosition:{x:Math.round(d),y:Math.round(h)},html5DndUsed:r.includes("dragstart")}}async waitForCondition(e,t,s,n,i){var p,y;const r=t.kind||"dom_stable",o=Math.min(Math.max(Number(t.timeoutMs)||5e3,100),3e4),a=Math.min(Math.max(Number(t.pollIntervalMs)||100,20),1e3),c=Date.now(),u=()=>{var v,m,g,b,T;switch(r){case"dom_stable":return{satisfied:!0,detail:`dom length ${((v=e.documentElement)==null?void 0:v.outerHTML.length)||0}`};case"selector_present":{const w=t.selector?e.querySelectorAll(t.selector).length:0;return{satisfied:w>0,detail:`"${t.selector}" matches ${w} element(s)`}}case"selector_visible":{if(!t.selector)return{satisfied:!1,detail:"no selector supplied"};const w=e.querySelector(t.selector);if(!w)return{satisfied:!1,detail:`"${t.selector}" not present`};try{const E=L.inspectElement(w).visibility.isVisible;return{satisfied:E,detail:`visibility=${E}`}}catch{return{satisfied:!1,detail:"inspection failed"}}}case"selector_absent":{const w=t.selector?e.querySelectorAll(t.selector).length:0;return{satisfied:w===0,detail:`"${t.selector}" matches ${w} element(s)`}}case"text_present":{const w=((m=e.body)==null?void 0:m.innerText)||((g=e.body)==null?void 0:g.textContent)||"",E=t.text?w.includes(String(t.text)):!1;return{satisfied:E,detail:`text "${String(t.text).slice(0,30)}" ${E?"found":"not found"}`}}case"url_contains":{const w=((T=(b=e.defaultView)==null?void 0:b.location)==null?void 0:T.href)||"";return{satisfied:t.text?w.includes(String(t.text)):!1,detail:w}}case"element_count":{const w=t.selector?e.querySelectorAll(t.selector).length:0,E=Number(t.count)||0;return{satisfied:w===E,detail:`${w}/${E} elements`}}case"readiness_state":return{satisfied:e.readyState===(t.state||"complete"),detail:`readyState=${e.readyState}`};default:return{satisfied:!1,detail:`unknown condition kind "${r}"`}}};if(r==="dom_stable"){let v=((p=e.documentElement)==null?void 0:p.outerHTML.length)||0,m=!1,g=0;for(;Date.now()-csetTimeout(w,a));const T=((y=e.documentElement)==null?void 0:y.outerHTML.length)||0;if(g++,T===v){m=!0;break}v=T}const b=Date.now()-c;return m&&this.session.timeline.record("WAIT_SATISFIED",`dom_stable after ${b}ms (${g} polls)`),this.success(n,i,{satisfied:m,condition:r,waitedMs:b,timeoutMs:o,detail:`dom length ${v}, ${g} polls`},s)}let d=u();for(;!d.satisfied&&Date.now()-csetTimeout(v,a)),d=u();const h=Date.now()-c;return d.satisfied&&this.session.timeline.record("WAIT_SATISFIED",`${r} after ${h}ms`),this.success(n,i,{satisfied:d.satisfied,condition:r,waitedMs:h,timeoutMs:o,detail:d.detail},s)}simulationCloseTab(e,t,s,n,i){const r=Number(e==null?void 0:e.tabId),o=Number.isFinite(r)?this.simulationTabs.findIndex(c=>c.browserTabId===r):this.simulationTabs.findIndex(c=>c.active);if(o<0)return this.error(s,n,"TAB_NOT_FOUND",`No simulated tab matches tabId=${r}`,i);const a=this.simulationTabs.splice(o,1)[0];return this.session.closeTab(a.sessionTabId),a.active&&this.simulationTabs.length&&(this.simulationTabs[0].active=!0,this.session.switchTab(this.simulationTabs[0].sessionTabId)),this.success(s,n,{closed:!0,closedTab:{id:a.browserTabId,url:a.url,title:a.title},simulated:!0,remaining:this.simulationTabs.length},i)}handleSimulationBackgroundCommand(e,t,s,n,i){const r=()=>{var o,a;if(!this.simulationTabs.length){this.simulationTabCounter++;const c={sessionTabId:`stab_${this.simulationTabCounter}`,browserTabId:this.simulationTabCounter,url:((a=(o=n.defaultView)==null?void 0:o.location)==null?void 0:a.href)||"about:blank",title:n.title||"Simulated Tab",active:!0,createdAt:Date.now()};this.simulationTabs.push(c),this.session.registerTab(c.browserTabId,c.url,c.title),this.session.switchTab(c.sessionTabId)}};switch(t){case"LIST_TABS":return r(),this.success(e,t,{simulated:!0,environment:"node-simulation",tabs:this.simulationTabs.map((o,a)=>({id:o.browserTabId,index:a,windowId:1,title:o.title,url:o.url,active:o.active,status:"complete",pinned:!1,audited:!1})),note:"Deterministic simulated tab state — a real browser tab list requires the Chrome extension connection."},i);case"OPEN_TAB":{const o=String((s==null?void 0:s.url)||"about:blank");this.simulationTabCounter++;const a={sessionTabId:`stab_${this.simulationTabCounter}`,browserTabId:this.simulationTabCounter,url:o,title:(s==null?void 0:s.title)||`Simulated Tab ${this.simulationTabCounter}`,active:!0,createdAt:Date.now()};this.simulationTabs.forEach(u=>u.active=!1),this.simulationTabs.push(a);const c=this.session.registerTab(a.browserTabId,o,a.title);return this.session.switchTab(c.sessionTabId),this.session.timeline.record("TAB_OPENED",`simulation tab ${a.browserTabId} → ${o}`),this.success(e,t,{opened:!0,tabId:a.browserTabId,url:o,simulated:!0,totalTabs:this.simulationTabs.length},i)}case"FOCUS_TAB":{r();const o=Number(s==null?void 0:s.tabId),a=this.simulationTabs.find(c=>c.browserTabId===o)||this.simulationTabs[0];return a?(this.simulationTabs.forEach(c=>c.active=!1),a.active=!0,this.session.switchTab(a.sessionTabId),this.session.timeline.record("TAB_SWITCHED",`simulation tab ${a.browserTabId} focused`),this.success(e,t,{focused:!0,tabId:a.browserTabId,url:a.url,simulated:!0},i)):this.error(e,t,"TAB_NOT_FOUND",`No simulated tab with tabId=${o}`,i)}case"LIST_EXTENSIONS":return this.success(e,t,{simulated:!0,extensions:this.simulationExtensions.map(o=>({...o,permissions:["activeTab","scripting","storage","tabs","management"]})),note:"Deterministic simulated extension state."},i);case"SET_EXTENSION_ENABLED":{const o=String((s==null?void 0:s.extensionId)||""),a=this.simulationExtensions.find(c=>c.id===o||c.name.toLowerCase().includes(o.toLowerCase()));return a?(a.enabled=!!(s!=null&&s.enabled),this.session.timeline.record("EXTENSION_STATE_CHANGED",`${a.id} → ${a.enabled?"enabled":"disabled"}`),this.success(e,t,{extensionId:a.id,enabled:a.enabled,simulated:!0},i)):this.error(e,t,"EXTENSION_NOT_FOUND",`No simulated extension matches "${o}". Known: ${this.simulationExtensions.map(c=>c.id).join(", ")}`,i)}case"TOGGLE_EXTENSION":{const o=String((s==null?void 0:s.extensionId)||""),a=this.simulationExtensions.find(c=>c.id===o||c.name.toLowerCase().includes(o.toLowerCase()));return a?(a.enabled=!a.enabled,this.session.timeline.record("EXTENSION_STATE_CHANGED",`${a.id} → ${a.enabled?"enabled":"disabled"}`),this.success(e,t,{extensionId:a.id,enabled:a.enabled,simulated:!0},i)):this.error(e,t,"EXTENSION_NOT_FOUND",`No simulated extension matches "${o}".`,i)}case"RELOAD_EXTENSION":{const o=String((s==null?void 0:s.extensionId)||this.simulationExtensions[0].id),a=this.simulationExtensions.find(c=>c.id===o||c.name.toLowerCase().includes(o.toLowerCase()));return a?this.success(e,t,{reloaded:!0,extensionId:a.id,simulated:!0,note:"Simulated reload: extension state preserved."},i):this.error(e,t,"EXTENSION_NOT_FOUND",`No simulated extension matches "${o}".`,i)}default:return this.error(e,t,"UNKNOWN_COMMAND",`Unhandled simulation command '${t}'`,i)}}async handleScreenshotCapture(e,t,s){var y,v,m,g,b;const n=s.defaultView||(typeof window<"u"?window:{}),i=Date.now(),r=`scr_${i}_${Math.random().toString(36).slice(2,6)}`,o=n.devicePixelRatio||1,a={width:n.innerWidth||((y=s.documentElement)==null?void 0:y.clientWidth)||1920,height:n.innerHeight||((v=s.documentElement)==null?void 0:v.clientHeight)||1080,scrollX:n.scrollX||n.pageXOffset||0,scrollY:n.scrollY||n.pageYOffset||0,devicePixelRatio:o};let c,u,d,h={width:a.width,height:a.height};if(e==="LIVE_ELEMENT_SCREENSHOT"){const T=this.resolveTarget(t,s),w=L.inspectElement(T,this.nodeRegistry);c=w.bestSelector,u=((m=w.forensics)==null?void 0:m.logicalNodeId)||void 0,d={x:w.bounds.x,y:w.bounds.y,width:w.bounds.width,height:w.bounds.height},h={width:Math.max(1,Math.round(w.bounds.width*o)),height:Math.max(1,Math.round(w.bounds.height*o))}}let p=(t==null?void 0:t.dataUrl)||"";if(e==="LIVE_ELEMENT_SCREENSHOT"&&p&&d&&typeof Image<"u")try{const T=await new Promise(w=>{const E=new Image;E.onload=()=>{try{const C=s.createElement("canvas"),N=Math.max(0,Math.floor(d.x*o)),I=Math.max(0,Math.floor(d.y*o)),R=Math.max(1,Math.floor(d.width*o)),x=Math.max(1,Math.floor(d.height*o));C.width=R,C.height=x;const q=C.getContext("2d");if(q){q.drawImage(E,N,I,R,x,0,0,R,x),w(C.toDataURL("image/png"));return}}catch{}w(p)},E.onerror=()=>w(p),E.src=p});T&&(p=T)}catch{}if(!p){const T=e==="LIVE_ELEMENT_SCREENSHOT"?Math.max(120,h.width||320):Math.max(800,a.width||1280),w=e==="LIVE_ELEMENT_SCREENSHOT"?Math.max(60,h.height||180):Math.max(600,a.height||800);p=fe.createDataUrl({width:T,height:w,backgroundColor:e==="LIVE_ELEMENT_SCREENSHOT"?[30,41,59,255]:[15,23,42,255],headerColor:[56,189,248,255],borderColor:[99,102,241,255],label:c||(e==="LIVE_ELEMENT_SCREENSHOT"?"Element Screenshot":"Page Screenshot")})}return{screenshotId:r,timestamp:i,url:((g=n.location)==null?void 0:g.href)||((b=s.location)==null?void 0:b.href)||"",viewport:a,targetSelector:c,targetNodeId:u,targetBounds:d,dataUrl:p,imageFormat:"png",dimensions:h,captureType:e==="LIVE_ELEMENT_SCREENSHOT"?"ELEMENT":"FULL_PAGE"}}success(e,t,s,n){return{id:e,command:t,success:!0,data:s,timestamp:Date.now(),durationMs:Date.now()-n}}error(e,t,s,n,i,r){return{id:e,command:t,success:!1,error:{code:s,message:n,details:r},timestamp:Date.now(),durationMs:Date.now()-i}}}function Dt(l,e){const t=[];let s=l.parentElement,n=1;for(;s&&n<=10;){const d=s.parentElement,h=d?Array.from(d.children).filter(p=>p.tagName===s.tagName):[];t.push({tag:s.tagName.toLowerCase(),selector:V(s),role:s.getAttribute("role")||void 0,text:K(s).slice(0,40),childIndex:h.length?h.indexOf(s)+1:1,siblingCount:d?Array.from(d.children).length:0,distance:n}),s=s.parentElement,n++}const i=l.parentElement,r=[];if(i){const d=Array.from(i.children),h=d.indexOf(l);for(let p=h-1;p>=0&&p>=h-5;p--)r.push({tag:d[p].tagName.toLowerCase(),selector:V(d[p]),role:d[p].getAttribute("role")||void 0,text:K(d[p]).slice(0,30),position:"before",distance:h-p});for(let p=h+1;p{o=Math.max(o,h);for(const p of Array.from(d.children))a.push(p.tagName.toLowerCase()),p.matches('a[href], button, input, select, textarea, [role="button"], [onclick]')&&c.push(V(p)),h<6&&u(p,h+1)};return u(l,1),{selector:V(l),ancestors:t,siblings:r,descendants:{count:l.querySelectorAll("*").length,maxDepth:o,tags:Array.from(new Set(a)).slice(0,30),interactive:c.slice(0,30)}}}function $t(l,e){const t=[{id:"self",selector:V(l),tag:l.tagName.toLowerCase(),role:l.getAttribute("role")||void 0,label:K(l).slice(0,30)||l.tagName.toLowerCase(),relationship:"self",depth:0}],s=[];let n=l.parentElement,i=1;for(;n&&i<=4;){const o=`ancestor_${i}`;t.push({id:o,selector:V(n),tag:n.tagName.toLowerCase(),role:n.getAttribute("role")||void 0,label:K(n).slice(0,30)||n.tagName.toLowerCase(),relationship:"parent",depth:i}),s.push({from:o,to:i===1?"self":`ancestor_${i-1}`,relation:"parent-of"}),n=n.parentElement,i++}for(const o of Array.from(l.children).slice(0,12)){const a=`child_${t.length}`;t.push({id:a,selector:V(o),tag:o.tagName.toLowerCase(),role:o.getAttribute("role")||void 0,label:K(o).slice(0,30)||o.tagName.toLowerCase(),relationship:"child",depth:1}),s.push({from:"self",to:a,relation:"contains"})}const r=l.parentElement;if(r)for(const o of Array.from(r.children).slice(0,12)){if(o===l)continue;const a=`sibling_${t.length}`;t.push({id:a,selector:V(o),tag:o.tagName.toLowerCase(),role:o.getAttribute("role")||void 0,label:K(o).slice(0,30)||o.tagName.toLowerCase(),relationship:"sibling",depth:1}),s.push({from:"self",to:a,relation:"sibling-of"})}return{rootSelector:V(l),nodes:t,edges:s}}function qt(l){const e={};for(const v of Array.from(l.attributes))v.name.startsWith("aria-")&&(e[v.name]=v.value);const t=K(l).trim(),s=l.getAttribute("aria-label"),n=l.getAttribute("aria-labelledby");let i;n&&(i=n.split(/\s+/).map(m=>{var g,b,T;return(T=(b=(g=l.ownerDocument)==null?void 0:g.getElementById(m))==null?void 0:b.textContent)==null?void 0:T.trim()}).filter(Boolean).join(" ").slice(0,60)||void 0);const r=l.getAttribute("title"),o=l.tagName.toLowerCase(),a=[];let c="";s?(c=s,a.push("aria-label")):i?(c=i,a.push("aria-labelledby")):t?(c=t.slice(0,60),a.push("text content")):r&&(c=r,a.push("title"));const u=[];(l.disabled||l.hasAttribute("disabled"))&&u.push("disabled"),l.checked&&u.push("checked");const d=l;d.tagName==="SELECT"&&typeof d.selectedOptions<"u"&&d.selectedOptions.length>0&&u.push("selected"),l.getAttribute("aria-expanded")&&u.push(`expanded=${l.getAttribute("aria-expanded")}`),l.getAttribute("aria-pressed")&&u.push(`pressed=${l.getAttribute("aria-pressed")}`),l.getAttribute("aria-hidden")==="true"&&u.push("hidden"),l.hasAttribute("required")&&u.push("required"),l.readOnly&&u.push("readonly");const h=["a[href]","button","input","select","textarea","[tabindex]"].some(v=>{try{return l.matches(v)}catch{return!1}}),p=[];!c&&h&&p.push("Focusable element has no accessible name."),o==="img"&&!l.hasAttribute("alt")&&p.push("Image has no alt attribute.");const y=/^h([1-6])$/.exec(o);return y&&!t&&p.push(`Heading h${y[1]} is empty.`),{selector:V(l),role:l.getAttribute("role")||void 0,implicitRole:Pt(l),name:c,nameSources:a,description:l.getAttribute("aria-describedby")||void 0,value:l.value!==void 0&&(l.getAttribute("type")||"text")!=="password"?String(l.value).slice(0,40):void 0,states:u,level:y?parseInt(y[1],10):void 0,focusable:h,tabIndex:l.tabIndex,ariaAttributes:e,issues:p}}function Pt(l){switch(l.tagName.toLowerCase()){case"a":return l.getAttribute("href")?"link":void 0;case"button":return"button";case"nav":return"navigation";case"header":return"banner";case"footer":return"contentinfo";case"main":return"main";case"aside":return"complementary";case"article":return"article";case"form":return"form";case"input":{const t=l.getAttribute("type")||"text";return{checkbox:"checkbox",radio:"radio",button:"button",submit:"button",reset:"button",range:"slider",search:"searchbox",email:"textbox",text:"textbox",password:"textbox",tel:"textbox",url:"textbox",number:"spinbutton"}[t]||"textbox"}case"select":return l.hasAttribute("multiple")?"listbox":"combobox";case"textarea":return"textbox";case"img":return"img";case"table":return"table";case"ul":case"ol":return"list";case"li":return"listitem";case"h1":case"h2":case"h3":case"h4":case"h5":case"h6":return"heading";case"dialog":return"dialog";default:return}}function V(l){const e=l.getAttribute("id");if(e&&/^[a-zA-Z][\w-]*$/.test(e))return`#${e}`;const t=l.getAttribute("data-testid");if(t)return`${l.tagName.toLowerCase()}[data-testid="${t}"]`;const s=l.tagName.toLowerCase(),n=Array.from(l.classList||[]).slice(0,2);return n.length?`${s}.${n.join(".")}`:s}function K(l){return Array.from(l.childNodes).filter(e=>e.nodeType===3).map(e=>(e.textContent||"").trim()).join(" ").replace(/\s+/g," ")}function Ut(){return[{label:"desktop-1440x900",width:1440,height:900},{label:"laptop-1024x768",width:1024,height:768},{label:"tablet-768x1024",width:768,height:1024},{label:"mobile-375x667",width:375,height:667}]}class Ht{constructor(e){f(this,"hostElement",null);f(this,"shadowRoot",null);f(this,"callbacks");f(this,"isRecording",!1);f(this,"isPaused",!1);f(this,"isMinimized",!1);f(this,"startTime",0);f(this,"eventCount",0);f(this,"timerInterval",null);f(this,"isDragging",!1);f(this,"dragStartX",0);f(this,"dragStartY",0);f(this,"posX",window.innerWidth-340);f(this,"posY",40);this.callbacks=e,this.loadPosition()}mount(){this.hostElement&&document.body.contains(this.hostElement)||(this.hostElement=document.createElement("div"),this.hostElement.id="forensic-recorder-floating-host",this.hostElement.style.all="initial",this.hostElement.style.position="fixed",this.hostElement.style.zIndex="2147483647",this.hostElement.style.left=`${this.posX}px`,this.hostElement.style.top=`${this.posY}px`,this.shadowRoot=this.hostElement.attachShadow({mode:"open"}),this.render(),this.attachEvents(),(document.body||document.documentElement).appendChild(this.hostElement))}unmount(){this.timerInterval&&(clearInterval(this.timerInterval),this.timerInterval=null),this.hostElement&&this.hostElement.parentNode&&this.hostElement.parentNode.removeChild(this.hostElement),this.hostElement=null,this.shadowRoot=null}hide(){this.hostElement&&(this.hostElement.style.setProperty("display","none","important"),this.hostElement.style.setProperty("visibility","hidden","important"),this.hostElement.style.setProperty("opacity","0","important"))}show(){this.hostElement&&(this.hostElement.style.removeProperty("display"),this.hostElement.style.removeProperty("visibility"),this.hostElement.style.removeProperty("opacity"))}updateState(e,t=!1,s=0,n=0){this.isRecording=e,this.isPaused=t,this.startTime=s||(e?Date.now():0),this.eventCount=n,this.shadowRoot&&(this.render(),this.attachEvents()),this.isRecording&&!this.isPaused?this.startTimer():this.stopTimer()}incrementEventCount(){var t;this.eventCount++;const e=(t=this.shadowRoot)==null?void 0:t.querySelector("#evt-badge");e&&(e.textContent=`${this.eventCount} evts`)}startTimer(){this.stopTimer(),this.timerInterval=setInterval(()=>{var t;const e=(t=this.shadowRoot)==null?void 0:t.querySelector("#timer-display");if(e&&this.startTime){const s=(Date.now()-this.startTime)/1e3,n=Math.floor(s/60).toString().padStart(2,"0"),i=(s%60).toFixed(1).padStart(4,"0");e.textContent=`${n}:${i}`}},200)}stopTimer(){this.timerInterval&&(clearInterval(this.timerInterval),this.timerInterval=null)}savePosition(){try{sessionStorage.setItem("forensic_overlay_pos",JSON.stringify({x:this.posX,y:this.posY,min:this.isMinimized}))}catch{}}loadPosition(){try{const e=sessionStorage.getItem("forensic_overlay_pos");if(e){const t=JSON.parse(e);this.posX=Math.max(10,Math.min(window.innerWidth-300,t.x||this.posX)),this.posY=Math.max(10,Math.min(window.innerHeight-150,t.y||this.posY)),this.isMinimized=!!t.min}}catch{}}render(){if(!this.shadowRoot)return;const e=` +})()`,n=e;if(typeof n.eval!="function")return Promise.reject(new Error("BLOCKED_BY_CONTEXT: window.eval is unavailable in this context."));try{const i=n.eval(s);return i&&typeof i.then=="function"?i:Promise.resolve(i)}catch(i){return Promise.reject(i)}}hookConsole(e,t){var o;const s=["log","warn","error","info","debug"],n={},i=e,r=100;for(const a of s){const c=(o=i.console)==null?void 0:o[a];if(typeof c=="function"){n[a]=c;try{i.console[a]=(...u)=>{t.length{for(const a of s)if(n[a])try{i.console[a]=n[a]}catch{}}}serialize(e){if(e===void 0)return{text:"undefined"};if(e===null)return{text:"null"};try{if(typeof e=="string")return{text:e.slice(0,5e3)};const t=JSON.stringify(e,pe,1);return t===void 0?{serializationFailed:!0,message:"JSON.stringify returned undefined (circular or non-serializable structure)."}:{text:t.length>5e4?t.slice(0,5e4)+"…[truncated]":t}}catch(t){return{serializationFailed:!0,message:(t==null?void 0:t.message)||"Serialization failed."}}}result(e,t,s,n,i,r){return{status:t,executionId:e,durationMs:s,error:r,consoleOutput:i,domChanged:!1,domLengthBefore:0,domLengthAfter:0,world:"ISOLATED",timeoutMs:5e3,codePreview:n.length>300?n.slice(0,300)+"…":n}}}function pe(l,e){var t;if(e&&typeof e=="object"&&e.nodeType===1){const s=e;return{__element:!0,tag:s.tagName.toLowerCase(),id:s.getAttribute("id")||void 0,selector:s.tagName.toLowerCase()+(s.getAttribute("id")?`#${s.getAttribute("id")}`:""),text:(s.textContent||"").trim().slice(0,60)}}return typeof e=="function"?{__function:!0,name:e.name||"anonymous"}:e&&e.nodeType===9?{__document:!0,url:(t=e.location)==null?void 0:t.href}:e}function Ve(l){try{if(typeof l=="string")return l;if(l instanceof Error)return`${l.name}: ${l.message}`;const e=JSON.stringify(l,pe);return e===void 0?String(l):e}catch{return String(l)}}const me={"desktop-full-hd":{width:1920,height:1080,category:"desktop"},"desktop-hd":{width:1366,height:768,category:"desktop"},"desktop-laptop":{width:1440,height:900,category:"desktop"},"desktop-xga":{width:1280,height:1024,category:"desktop"},"desktop-1024":{width:1024,height:768,category:"desktop"},"tablet-ipad":{width:768,height:1024,category:"tablet"},"tablet-ipad-pro":{width:1024,height:1366,category:"tablet"},"tablet-portrait":{width:768,height:1024,category:"tablet"},"tablet-landscape":{width:1024,height:768,category:"tablet"},"mobile-iphone-se":{width:375,height:667,category:"mobile"},"mobile-iphone-12":{width:390,height:844,category:"mobile"},"mobile-iphone-14-pro-max":{width:430,height:932,category:"mobile"},"mobile-pixel-7":{width:412,height:915,category:"mobile"},"mobile-galaxy-s8":{width:360,height:740,category:"mobile"},"mobile-small":{width:320,height:568,category:"mobile"},"test-a4":{width:800,height:600,category:"test"},"test-square":{width:512,height:512,category:"test"}},fe={"iphone-13":{width:390,height:844,devicePixelRatio:3,userAgent:"Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1",touch:!0,category:"mobile"},"ipad-air":{width:820,height:1180,devicePixelRatio:2,userAgent:"Mozilla/5.0 (iPad; CPU OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1",touch:!0,category:"tablet"},"pixel-7":{width:412,height:915,devicePixelRatio:2.625,userAgent:"Mozilla/5.0 (Linux; Android 14; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36",touch:!0,category:"mobile"},"galaxy-s23":{width:384,height:800,devicePixelRatio:3,userAgent:"Mozilla/5.0 (Linux; Android 14; SM-S911B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36",touch:!0,category:"mobile"},"macbook-pro-16":{width:1728,height:1080,devicePixelRatio:2,userAgent:"Mozilla/5.0 (Macintosh; Intel Mac OS X 14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",touch:!1,category:"desktop"},"windows-desktop":{width:1920,height:1080,devicePixelRatio:1,userAgent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",touch:!1,category:"desktop"}};class Be{constructor(e){b(this,"original",null);b(this,"modified",!1);b(this,"activePreset",null);b(this,"activeDevice",null);this.doc=e}state(){const e=this.doc.defaultView;return{width:(e==null?void 0:e.innerWidth)||0,height:(e==null?void 0:e.innerHeight)||0,devicePixelRatio:(e==null?void 0:e.devicePixelRatio)||1,scrollX:(e==null?void 0:e.scrollX)||0,scrollY:(e==null?void 0:e.scrollY)||0,original:this.original,isModified:this.modified}}resize(e,t,s){const n=this.doc.defaultView,i={width:(n==null?void 0:n.innerWidth)||0,height:(n==null?void 0:n.innerHeight)||0},r=this.pageDigest();this.original||(this.original={...i});const o=this.applySize(e,t);this.modified=!0,this.activePreset=s||this.activePreset;const a=this.pageDigest();return{success:!0,applied:{width:o.width,height:o.height},previous:i,original:{...this.original},preset:s||void 0,beforeState:r,afterState:a,reversible:!0,mode:this.isSimulation()?"simulation":"browser-window"}}applyPreset(e){const t=me[e];if(!t)throw new Error(`UNKNOWN_PRESET: "${e}". Available: ${Object.keys(me).join(", ")}`);return this.resize(t.width,t.height,e)}emulateDevice(e){const t=fe[e];if(!t)throw new Error(`UNKNOWN_DEVICE: "${e}". Available: ${Object.keys(fe).join(", ")}`);const s=this.resize(t.width,t.height,`device:${e}`);this.activeDevice=e;const n=this.doc.defaultView;return n&&this.isSimulation()&&n.devicePixelRatio!==void 0&&(n.devicePixelRatio=t.devicePixelRatio),{device:e,resize:s,profile:{width:t.width,height:t.height,devicePixelRatio:t.devicePixelRatio,touch:t.touch,category:t.category},userAgentNote:this.isSimulation()?"User-Agent override requires the Chrome DevTools Protocol (real browser session); in this context the viewport, dpr and touch metadata are applied and the UA is reported but not enforced.":"User-Agent and touch behaviors are applied by the browser emulation layer.",userAgentApplied:!this.isSimulation()}}reset(){var s,n;const e={width:((s=this.doc.defaultView)==null?void 0:s.innerWidth)||0,height:((n=this.doc.defaultView)==null?void 0:n.innerHeight)||0},t=this.original?{...this.original}:{...e};return this.original&&this.applySize(this.original.width,this.original.height),this.modified=!1,this.activePreset=null,this.activeDevice=null,{success:!0,applied:{width:t.width,height:t.height},previous:e,original:{...t},reversible:!0,mode:this.isSimulation()?"simulation":"browser-window"}}runResponsiveTest(e,t={restore:!0}){var c,u,h,g;const s=t.restore!==!1,n=this.original?{...this.original}:{width:((c=this.doc.defaultView)==null?void 0:c.innerWidth)||0,height:((u=this.doc.defaultView)==null?void 0:u.innerHeight)||0};this.original||(this.original={...n});const i=e.map(p=>{this.applySize(p.width,p.height),this.modified=!0;const y=this.pageDigest();return{label:p.label,width:p.width,height:p.height,domLength:y.domLength,interactiveCount:y.interactiveCount,horizontalOverflow:this.hasHorizontalOverflow(),screenshotId:void 0}}),r=i.slice(1).map((p,y)=>({from:i[y].label,to:p.label,domLengthDelta:p.domLength-i[y].domLength,interactiveDelta:p.interactiveCount-i[y].interactiveCount}));let o={width:((h=i[i.length-1])==null?void 0:h.width)||0,height:((g=i[i.length-1])==null?void 0:g.height)||0},a=!1;return s&&(this.applySize(n.width,n.height),this.modified=!1,o={...n},a=!0),{success:!0,originalViewport:n,steps:i,restored:a,finalViewport:o,comparisons:r}}getActivePreset(){return this.activePreset}getActiveDevice(){return this.activeDevice}applySize(e,t){const s=Math.max(200,Math.min(7680,Math.round(e))),n=Math.max(200,Math.min(4320,Math.round(t))),i=this.doc.defaultView;return i&&(typeof i.innerWidth=="number"&&(i.innerWidth=s),typeof i.innerHeight=="number"&&(i.innerHeight=n),typeof i.outerWidth=="number"&&(i.outerWidth=s),typeof i.outerHeight=="number"&&(i.outerHeight=n)),{width:s,height:n}}pageDigest(){var t,s,n,i;const e=this.doc.querySelectorAll('a[href], button, input, select, textarea, [role="button"], [onclick]').length;return{url:((s=(t=this.doc.defaultView)==null?void 0:t.location)==null?void 0:s.href)||((n=this.doc.location)==null?void 0:n.href)||"",domLength:((i=this.doc.documentElement)==null?void 0:i.outerHTML.length)||0,interactiveCount:e}}hasHorizontalOverflow(){const e=this.doc.documentElement,t=this.doc.body,s=this.doc.defaultView;return!s||!e?!1:Math.max(e.scrollWidth||0,(t==null?void 0:t.scrollWidth)||0)>(s.innerWidth||e.clientWidth||0)+1}isSimulation(){return typeof globalThis.__FORENSIC_SIMULATION__<"u"}}const ze=[/^css-/,/^jsx-/,/^sc-[A-Za-z]/,/^emotion/,/^chakra-/,/^mantine-/i,/^_ng[a-z]/,/^ng-/i,/^v-/,/^(?=.*\d)[a-z0-9]{6,12}$/i,/^data-v-/],We=["id","name","data-testid","data-test","data-id","data-qa","data-cy","data-component","data-role","aria-label","aria-labelledby","aria-describedby","role","type","href","for","title","alt","rel","placeholder"];function be(l){let e=2166136261;for(let t=0;t>>0).toString(16).padStart(8,"0")}function ee(l){return ze.some(e=>e.test(l))}function Xe(l){return We.includes(l)}function re(l){const e=l.trim();return e?!!((e.match(/\d/g)||[]).length/e.length>.5||/^\d+[.,:\-/ ]+\d+/.test(e)||/\b\d{10,}\b/.test(e)):!1}function Ge(l,e=80){return Array.from(l.childNodes).filter(s=>s.nodeType===3).map(s=>(s.textContent||"").trim()).join(" ").replace(/\s+/g," ").slice(0,e)}function Ke(l,e){const t=[];let s=l;for(;s&&t.length!ee(f)),r=Ge(e),o=e.getBoundingClientRect(),a={width:Math.round(o.width),height:Math.round(o.height)},c=Ke(e,4),u=c.join(">"),g=Array.from(e.children||[]).slice(0,8).map(f=>f.tagName.toLowerCase()).join("|"),p=e.getAttribute("role")||(t!=null&&t.getComputedStyle,void 0)||Ye(e),y=be(JSON.stringify({t:e.tagName.toLowerCase(),a:s,c:i.slice(0,4),r:p||null,anc:u,desc:g,txt:re(r)?null:r.slice(0,40),d:a})),v=[];let m="low";return!s.id&&!s["data-testid"]&&!s.name&&(m="medium",v.push("no stable identity attribute")),n.length>0&&i.length===0&&(m=v.length?"high":"medium",v.push("all classes are framework-generated")),re(r)&&(v.push("text appears dynamic"),m==="low"&&(m="medium")),e.tagName.toLowerCase().includes("-")&&(v.push("custom element (web component)"),m==="low"&&(m="medium")),{fingerprintId:`fp_${y}`,hash:y,tagHierarchy:c,stableAttributes:s,meaningfulText:r,classes:i,role:p||void 0,dimensions:a,ancestorPattern:u,descendantPattern:g,volatilityRisk:m,volatilityReasons:v}}compare(e,t){const s=[],n=e.tagHierarchy[0]===t.tagHierarchy[0]?1:0;s.push({name:"tag",score:n,weight:.15});const i=ye(e.ancestorPattern.split(">"),t.ancestorPattern.split(">"));s.push({name:"ancestorPattern",score:i,weight:.2});const r=je(e.stableAttributes,t.stableAttributes);s.push({name:"stableAttributes",score:r,weight:.25});const o=ye(e.classes,t.classes);s.push({name:"classes",score:o,weight:.1});const a=(e.role||"")===(t.role||"")&&e.role?1:0;s.push({name:"role",score:a,weight:.1});const c=e.meaningfulText===t.meaningfulText&&e.meaningfulText?1:0;s.push({name:"text",score:c,weight:.1});const u=Ze(e.dimensions,t.dimensions);s.push({name:"dimensions",score:u,weight:.1});const h=s.reduce((g,p)=>g+p.score*p.weight,0);return{score:Math.round(h*1e3)/1e3,components:s}}}function Ye(l){switch(l.tagName.toLowerCase()){case"a":return l.getAttribute("href")?"link":void 0;case"button":return"button";case"nav":return"navigation";case"header":return"banner";case"footer":return"contentinfo";case"main":return"main";case"aside":return"complementary";case"article":return"article";case"form":return"form";case"input":{const t=l.getAttribute("type")||"text";return t==="checkbox"?"checkbox":t==="radio"?"radio":t==="button"||t==="submit"?"button":"textbox"}case"select":return"combobox";case"textarea":return"textbox";case"img":return"img";case"table":return"table";case"ul":case"ol":return"list";case"li":return"listitem";case"h1":case"h2":case"h3":case"h4":case"h5":case"h6":return"heading";default:return}}function ye(l,e){if(!l.length&&!e.length)return 1;if(!l.length||!e.length)return 0;const t=new Set(e);return l.filter(n=>t.has(n)).length/Math.max(l.length,e.length)}function je(l,e){const t=Object.keys(l),s=Object.keys(e);if(!t.length&&!s.length)return .5;if(!t.length||!s.length)return 0;let n=0,i=0;for(const r of t)r in e&&(i++,l[r]===e[r]&&n++);return i===0?0:n/Math.max(t.length,s.length)}function Ze(l,e){if(l.width===0&&l.height===0&&e.width===0&&e.height===0)return .5;const t=Ee(l.width,e.width),s=Ee(l.height,e.height);return(t+s)/2}function Ee(l,e){if(l===e)return 1;if(l===0||e===0)return 0;const t=Math.min(l,e)/Math.max(l,e);return t>.9?1:t>.7?.5:0}const Je=["data-testid","data-test","data-id","data-qa","data-cy","data-component","data-role","aria-label","name","id"],ve=/^[a-zA-Z][a-zA-Z0-9_-]*$/,Qe=/^[a-zA-Z0-9_ .:-]+$/;class Y{constructor(e){b(this,"doc");this.doc=e}generateCandidates(e){const t=[],s=e.tagName.toLowerCase(),n=e.getAttribute("id");if(n&&ve.test(n)){const u=`#${we(n)}`;t.push(this.evaluate(e,u,"id",1,["unique stable id"]))}for(const u of Je){if(u==="id")continue;const h=e.getAttribute(u);if(h&&Qe.test(h)&&h.length<100){const g=`${s}[${u}="${j(h)}"]`;t.push(this.evaluate(e,g,"semantic-attribute",.92,[`semantic attribute ${u}`]))}}const i=Array.from(e.classList||[]).filter(u=>!ee(u));if(i.length){const u=`${s}.${i.slice(0,3).map(we).join(".")}`;t.push(this.evaluate(e,u,"class",.72,i.length?["stable class names"]:[]))}const r=this.buildStructuralPath(e);r&&t.push(this.evaluate(e,r,"structural-path",.55,["position-based structural path"]));const o=q(e);if(o&&o.length>=2&&o.length<=60&&!re(o)){const u=`${s}:nth-of-type(1)`,h=this.buildTextXPath(e,o);h&&(t.push({selector:u,strategy:"text-derived-xpath",confidence:.6,unique:this.isXPathUnique(h),reasons:[`matches text "${o.slice(0,30)}"`]}),t[t.length-1].xpath=h)}const a=this.buildAttributeFingerprintSelector(e);a&&t.push(this.evaluate(e,a,"attribute-fingerprint",.68,["combination of stable attributes"]));const c=new Map;for(const u of t){const h=u.strategy==="text-derived-xpath"?`xpath:${u.xpath}`:u.selector,g=c.get(h);(!g||u.confidence>g.confidence)&&c.set(h,u)}return Array.from(c.values()).sort((u,h)=>h.confidence-u.confidence)}bestSelector(e){const t=this.generateCandidates(e),s=t.find(n=>n.unique&&n.confidence>=.7)||t[0];return{selector:(s==null?void 0:s.selector)||e.tagName.toLowerCase(),strategy:(s==null?void 0:s.strategy)||"tag",confidence:(s==null?void 0:s.confidence)||.3}}buildXPath(e){const t=[];let s=e;for(;s&&s!==this.doc.documentElement;){const n=s.getAttribute("id");if(n&&ve.test(n)){t.unshift(`*[@id="${j(n)}"]`);break}const i=s.parentElement;if(!i){t.unshift(s.tagName.toLowerCase());break}const o=Array.from(i.children).filter(a=>a.tagName===s.tagName).indexOf(s)+1;t.unshift(`${s.tagName.toLowerCase()}[${o}]`),s=i}return s===this.doc.documentElement&&(!t.length||!t[0].includes("@id"))&&t.unshift("html"),"//"+t.join("/")}buildTextXPath(e,t){try{const s=e.tagName.toLowerCase(),n=et(t);return`//${s}[normalize-space(text())=${n}]`}catch{return null}}buildStructuralPath(e,t=4){const s=[];let n=e;for(;n&&s.lengthc.tagName===n.tagName);if(a.length>1){const c=a.indexOf(n)+1;s.unshift(`${o}:nth-of-type(${c})`)}else s.unshift(o);if(n=r,n===this.doc.body){s.unshift("body");break}if(n===this.doc.documentElement)break}const i=s.join(" > ");return i.includes("body")?i:"body > "+i}buildAttributeFingerprintSelector(e){const t=e.tagName.toLowerCase(),s=[],n=e.getAttribute("type");n&&s.push(`type="${j(n)}"`);const i=e.getAttribute("href");i&&i.length<80&&!i.startsWith("javascript:")&&s.push(`href^="${j(i.slice(0,40))}"`);const r=e.getAttribute("placeholder");return r&&r.length<60&&s.push(`placeholder="${j(r)}"`),s.length>=2?`${t}[${s.join("][")}]`:null}evaluate(e,t,s,n,i){let r=!1,o=0;try{const c=this.doc.querySelectorAll(t);o=c.length,r=c.length===1&&c[0]===e}catch{return{selector:t,strategy:s,confidence:0,unique:!1,reasons:["invalid selector syntax"]}}let a=n;return o===0?(a=0,i.push("selector matched nothing (invalid candidate)")):o===1&&r?i.push("matches exactly this element"):(a=a*.4,i.push(`matches ${o} elements — ambiguous`)),{selector:t,strategy:s,confidence:Math.round(a*100)/100,unique:r,reasons:i}}isXPathUnique(e){try{return this.doc.evaluate(`count(${e})`,this.doc,null,4,null).numberValue===1}catch{return!1}}}function q(l){return Array.from(l.childNodes).filter(e=>e.nodeType===3).map(e=>(e.textContent||"").trim()).join(" ").replace(/\s+/g," ")}function we(l){return l.replace(/([^a-zA-Z0-9_\u00A0-\uFFFF-])/g,"\\$1")}function j(l){return l.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function et(l){return l.includes("'")?l.includes('"')?`concat(${l.split("'").map(e=>`'${e}'`).join(`, "'", `)})`:`"${l}"`:`'${l}'`}class tt{constructor(e,t){b(this,"fingerprintEngine",new te);b(this,"counter",0);this.doc=e,this.registry=t}buildTarget(e,t="selector"){var h;const s=new Y(this.doc),n=s.generateCandidates(e),i=s.bestSelector(e),r=this.fingerprintEngine.fingerprint(e),o=k.inspectElement(e,this.registry),a=e.getBoundingClientRect();let c=i.confidence*.6;return r.volatilityRisk==="low"?c+=.3:r.volatilityRisk==="medium"&&(c+=.15),n.find(g=>g.unique&&g.confidence>=.9)&&(c+=.1),c=Math.max(.05,Math.min(1,c)),this.counter++,{targetId:`tgt_${Date.now().toString(36)}_${this.counter}`,tag:e.tagName.toLowerCase(),role:o.role||r.role,selector:i.selector,selectorCandidates:n,xpath:s.buildXPath(e),domPath:(((h=o.context)==null?void 0:h.parentChain)||[]).concat(i.selector).join(" > "),textFingerprint:r.meaningfulText,attributeFingerprint:JSON.stringify(r.stableAttributes),structuralFingerprint:r.hash,attributes:o.attributes||{},confidence:Math.round(c*100)/100,bounds:{x:Math.round(a.x),y:Math.round(a.y),width:Math.round(a.width),height:Math.round(a.height)},resolvedFrom:t}}resolveAndBuild(e){let t=null,s="unknown";typeof e=="string"&&(e={selector:e});const n=e;if(n.selectedElementRef&&(s="selectedElementRef"),!t&&n.selector)try{const i=this.doc.querySelectorAll(n.selector);if(i.length===0)return{error:`TARGET_NOT_FOUND: selector "${n.selector}" matches no element`};i.length>1?(t=st(i,this.doc)||i[0],s+="+disambiguated"):(t=i[0],s="selector")}catch(i){return{error:`TARGET_INVALID: ${i.message}`}}if(!t&&n.xpath)try{t=this.doc.evaluate(n.xpath,this.doc,null,9,null).singleNodeValue,s="xpath"}catch(i){return{error:`TARGET_INVALID_XPATH: ${i.message}`}}if(!t&&typeof n.nodeId=="number"&&this.registry){const i=this.registry.getNode(n.nodeId);i&&i.nodeType===1&&this.doc.contains(i)&&(t=i,s="nodeId")}return!t&&n.coordinates&&(t=this.doc.elementFromPoint(n.coordinates.x,n.coordinates.y),s="coordinates"),t?{element:t,target:this.buildTarget(t,s)}:{error:"TARGET_NOT_FOUND: no usable resolution strategy succeeded"}}}function st(l,e){for(const t of Array.from(l)){const s=t;try{if(k.inspectElement(s).visibility.isVisible)return s}catch{}}return null}class nt{constructor(e){b(this,"fingerprintEngine",new te);this.doc=e}recover(e,t){var p;const s=[],n=[];let i=null;try{i=this.doc.querySelectorAll(e)}catch(y){s.push(`selector syntax error: ${y.message}`)}if(i&&i.length>0){s.push("selector still matches — no recovery needed");const y=i[0];return{recovered:!0,confidence:1,strategy:"original-selector",resolvedSelector:e,matchedElementInfo:Te(y),alternatives:[],diagnostics:s,recommendation:"Original selector works; the earlier failure was transient (likely a navigation or render race)."}}s.push("selector no longer matches any element");const o=this.collectCandidates(t,s).map(y=>({element:y,score:this.scoreMatch(y,t)})).filter(y=>y.score.score>.35).sort((y,v)=>v.score.score-y.score.score);for(const y of o.slice(0,5)){const v=new Y(this.doc).bestSelector(y.element);n.push({selector:v.selector,confidence:Math.round(y.score.score*100)/100,strategy:"recovery-match"})}if(!o.length)return{recovered:!1,confidence:0,strategy:"none",alternatives:n,diagnostics:s,recommendation:"No sufficiently similar element exists. The region may have been removed, or the page structure changed fundamentally. Re-inspect the page and capture a new target."};const a=o[0],c=o.length>1?a.score.score-o[1].score.score:1;s.push(`best candidate score: ${a.score.score.toFixed(3)} (margin ${c.toFixed(3)})`);for(const y of a.score.components)y.score>0&&s.push(` - ${y.name}: ${(y.score*100).toFixed(0)}%`);if(a.score.score<.62||o.length>1&&c<.15)return{recovered:!1,confidence:Math.round(a.score.score*100)/100,strategy:"recovery-refused",resolvedSelector:(p=n[0])==null?void 0:p.selector,alternatives:n,diagnostics:s,recommendation:"Recovery refused: best match is not confident enough or too close to a competing element. Inspect alternatives manually before acting — refusing to avoid acting on a wrong element."};const g=new Y(this.doc).bestSelector(a.element).selector;return{recovered:!0,confidence:Math.round(a.score.score*100)/100,strategy:"fingerprint-recovery",resolvedSelector:g,matchedElementInfo:Te(a.element),alternatives:n,diagnostics:s,recommendation:`Recovered target with ${(a.score.score*100).toFixed(0)}% confidence. Verify the resolved selector before destructive actions.`}}collectCandidates(e,t){var r,o;const s=new Set,n=this.doc.querySelectorAll(e.tag);let i=0;for(const a of Array.from(n))if(s.add(a),++i>=400)break;if((r=e.classes)!=null&&r.length){const a=e.classes.filter(c=>!ee(c));for(const c of a.slice(0,2))try{for(const u of Array.from(this.doc.querySelectorAll(`.${c}`)).slice(0,100))s.add(u)}catch{}}if((o=e.stableAttributes)!=null&&o.name)try{for(const a of Array.from(this.doc.querySelectorAll(`[name="${e.stableAttributes.name}"]`)))s.add(a)}catch{}if(e.parentSelector)try{for(const a of Array.from(this.doc.querySelectorAll(`${e.parentSelector} > ${e.tag}`)).slice(0,100))s.add(a)}catch{}return t.push(`collected ${s.size} candidate elements for scoring`),Array.from(s)}scoreMatch(e,t){const s=[],n=e.tagName.toLowerCase()===t.tag.toLowerCase()?1:0;s.push({name:"tag",score:n,weight:.15});const i=(t.text||"").trim().slice(0,40),r=q(e).slice(0,40),o=(e.textContent||"").trim().slice(0,40);let a=0;if(i){const d=r?r===i?1:oe(i,r):0,f=o?o===i?1:oe(i,o):0;a=Math.max(d,f)}s.push({name:"text",score:a,weight:.3});const c=new Set((t.classes||[]).filter(d=>!ee(d))),u=Array.from(e.classList||[]),h=c.size?u.filter(d=>c.has(d)).length/c.size:.5;s.push({name:"classes",score:h,weight:.2});const g=t.stableAttributes||{},p=Object.keys(g);let y=.5;if(p.length){let d=0;for(const f of p)e.getAttribute(f)===g[f]&&d++;y=d/p.length}s.push({name:"attributes",score:y,weight:.2});const v=t.childCount!==void 0?e.children.length===t.childCount?1:oe(String(t.childCount),String(e.children.length)):.5;if(s.push({name:"childCount",score:v,weight:.05}),t.fingerprintHash){const d={fingerprintId:"snapshot",hash:t.fingerprintHash,tagHierarchy:[t.tag],stableAttributes:g,meaningfulText:i,classes:t.classes||[],dimensions:{width:0,height:0},ancestorPattern:"",descendantPattern:"",volatilityRisk:"medium",volatilityReasons:[]},f=this.fingerprintEngine.fingerprint(e),w=this.fingerprintEngine.compare(d,f);s.push({name:"fingerprint",score:w.score,weight:.1})}const m=s.reduce((d,f)=>d+f.score*f.weight,0);return{score:Math.max(0,Math.min(1,m)),components:s}}diagnose(e){const t=[];let s=!0,n=0,i,r=[];try{n=this.doc.querySelectorAll(e).length}catch(o){s=!1,i=o.message,t.push("Selector is syntactically invalid CSS.")}if(s&&n===0){t.push("Selector parses but matches nothing — element may be removed, re-rendered, or inside a shadow root."),r=this.relaxSelector(e);for(const o of r)try{if(this.doc.querySelectorAll(o).length>0){t.push(`Relaxed form "${o}" matches — the over-specific part of the selector is stale.`);break}}catch{}}return s&&n>1&&t.push(`Selector matches ${n} elements — it is ambiguous; use a more specific form or index.`),{selector:e,valid:s,matches:n,parseError:i,closestWorkingSelectors:r.filter(o=>{try{return this.doc.querySelectorAll(o).length>0}catch{return!1}}),diagnosis:t}}relaxSelector(e){const t=[],s=e.split(/[ >]+/).filter(Boolean);s.length>1&&(t.push(s.slice(0,-1).join(" ")),t.push(s[s.length-1]));const n=e.replace(/:nth-of-type\(\d+\)/g,"").replace(/\.[^. >#:[]+/g,(i,r,o)=>o[r-1]==="\\"?i:"");return n!==e&&n.trim()&&t.push(n.trim()),t}}function oe(l,e){if(!l||!e)return 0;const t=Se(l),s=Se(e);if(t===s)return 1;if(t.includes(s)||s.includes(t))return .7;const n=new Set(t.split(/\s+/)),i=new Set(s.split(/\s+/));return Array.from(n).filter(o=>i.has(o)).length/Math.max(n.size,i.size)}function Se(l){return l.toLowerCase().replace(/[^a-z0-9 ]/g," ").replace(/\s+/g," ").trim()}function Te(l){return{tag:l.tagName.toLowerCase(),id:l.getAttribute("id")||void 0,text:q(l).slice(0,60),classes:Array.from(l.classList||[])}}class ae{constructor(e){b(this,"state");this.state=e>>>0,this.state===0&&(this.state=2654435769)}next(){this.state=this.state+1831565813>>>0;let e=this.state;return e=Math.imul(e^e>>>15,e|1),e^=e+Math.imul(e^e>>>7,e|61),((e^e>>>14)>>>0)/4294967296}range(e,t){return e+this.next()*(t-e)}int(e,t){return Math.floor(this.range(e,t+1))}chance(e){return this.next()setTimeout(t,e))}chance(){return this.rng.next()<.5}}const rt=[{ruleId:"red_key_password",kind:"key-pattern",pattern:"password|passwd|pwd",description:"Keys containing password/passwd/pwd",enabled:!0,userAdded:!1},{ruleId:"red_key_token",kind:"key-pattern",pattern:"token|jwt|bearer|auth|session.?id|secret|api.?key|client.?secret",description:"Keys containing token/jwt/auth/session-id/secret/api-key",enabled:!0,userAdded:!1},{ruleId:"red_key_credential",kind:"key-pattern",pattern:"credential|login|user.?pass|otp|2fa|mfa|verification",description:"Keys containing credential/login/otp/2fa/verification",enabled:!0,userAdded:!1},{ruleId:"red_key_payment",kind:"key-pattern",pattern:"card|payment|billing|iban|cvv|cvc|pan",description:"Keys containing card/payment/billing/iban/cvv",enabled:!0,userAdded:!1},{ruleId:"red_key_personal",kind:"key-pattern",pattern:"ssn|social.?security|national.?id|passport|tax.?id",description:"Keys containing personal identifier patterns",enabled:!0,userAdded:!1},{ruleId:"red_val_jwt",kind:"value-pattern",pattern:"eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+",description:"JWT-shaped tokens",enabled:!0,userAdded:!1},{ruleId:"red_val_bearer",kind:"value-pattern",pattern:"bearer\\s+[A-Za-z0-9._-]+",description:"Bearer tokens",enabled:!0,userAdded:!1},{ruleId:"red_val_long_hex",kind:"value-pattern",pattern:"\\b[a-f0-9]{32,}\\b",description:"32+ char hex strings (session/API ids)",enabled:!0,userAdded:!1},{ruleId:"red_val_sk",kind:"value-pattern",pattern:"\\b(sk|pk|rk)_[A-Za-z0-9_]{20,}\\b",description:"Stripe-style secret keys (sk_live_…)",enabled:!0,userAdded:!1},{ruleId:"red_attr_input_password",kind:"attribute-name",pattern:"value",description:"value attributes on password inputs handled by PrivacyEngine maskValue",enabled:!0,userAdded:!1},{ruleId:"red_attr_secret",kind:"attribute-name",pattern:"data-secret|data-token|data-api-key|secret|access.?token",description:"Secret-carrying attributes",enabled:!0,userAdded:!1}],ot=[{exclusionId:"excl_mcpdom_overlay",selector:"[data-mcpdom-internal], [data-forensic-internal], #forensic-recorder-floating-host, #forensic-inspect-highlighter",reason:"MCPDOM-injected UI must never contaminate captured DOM (§68 clean capture)",userAdded:!1},{exclusionId:"excl_mcpdom_ids",selector:'[id^="forensic-"], [id^="mcpdom-"]',reason:"MCPDOM-namespaced nodes",userAdded:!1}],ce="[REDACTED]";class le{constructor(e){b(this,"config");b(this,"base",new J);b(this,"compiledKeyPatterns",[]);b(this,"compiledValuePatterns",[]);b(this,"compiledAttrPatterns",[]);this.config={rules:[...rt],exclusions:[...ot],stubMode:!0,...e},this.recompile()}recompile(){this.compiledKeyPatterns=[],this.compiledValuePatterns=[],this.compiledAttrPatterns=[];for(const e of this.config.rules){if(!e.enabled)continue;const t="i";try{switch(e.kind){case"key-pattern":this.compiledKeyPatterns.push(new RegExp(e.pattern,t));break;case"value-pattern":this.compiledValuePatterns.push(new RegExp(e.pattern,"i"));break;case"attribute-name":this.compiledAttrPatterns.push(new RegExp(`^(${e.pattern})$`,"i"));break}}catch{}}}getRules(){return[...this.config.rules]}setRuleEnabled(e,t){const s=this.config.rules.find(n=>n.ruleId===e);return s?(s.enabled=t,this.recompile(),!0):!1}addRule(e){const t=`red_custom_${this.config.rules.length+1}_${Date.now().toString(36)}`,s={...e,ruleId:t,userAdded:!0};return this.config.rules.push(s),this.recompile(),s}removeRule(e){const t=this.config.rules.findIndex(s=>s.ruleId===e);return t<0||!this.config.rules[t].userAdded?!1:(this.config.rules.splice(t,1),this.recompile(),!0)}getExclusions(){return[...this.config.exclusions]}addExclusion(e,t){const n={exclusionId:`excl_custom_${this.config.exclusions.length+1}_${Date.now().toString(36)}`,selector:e,reason:t,userAdded:!0};return this.config.exclusions.push(n),n}removeExclusion(e){const t=this.config.exclusions.findIndex(s=>s.exclusionId===e);return t<0||!this.config.exclusions[t].userAdded?!1:(this.config.exclusions.splice(t,1),!0)}isSensitiveKey(e){return this.compiledKeyPatterns.some(t=>t.test(e))}redactValue(e){let t=e;for(const s of this.compiledValuePatterns)s.test(t)&&(t=t.replace(new RegExp(s.source,"gi"),ce));return t}redactByKeyValue(e,t){return this.isSensitiveKey(e)?this.config.stubMode?ce:t:this.redactValue(t)}isSensitiveAttribute(e){return this.compiledAttrPatterns.some(t=>t.test(e))}redactAttributes(e){const t={};for(const[s,n]of Object.entries(e))this.isSensitiveAttribute(s)?t[s]=ce:t[s]=this.redactValue(n);return t}cleanSubtree(e){const t=e.cloneNode(!0);for(const s of this.config.exclusions){let n=null;try{n=t.querySelectorAll(s.selector)}catch{continue}for(const i of Array.from(n))i.remove();try{if(t.matches(s.selector))return this.doclessEmptyStub(t)}catch{}}return t}isExcluded(e){for(const t of this.config.exclusions)try{if(e.matches(t.selector)||e.closest(t.selector))return!0}catch{}return!1}doclessEmptyStub(e){return e.innerHTML="",e.setAttribute("data-mcpdom-excluded","true"),e}toJSON(){return{rules:this.getRules(),exclusions:this.getExclusions(),stubMode:this.config.stubMode}}static fromJSON(e){return new le({rules:Array.isArray(e==null?void 0:e.rules)?e.rules:void 0,exclusions:Array.isArray(e==null?void 0:e.exclusions)?e.exclusions:void 0,stubMode:typeof(e==null?void 0:e.stubMode)=="boolean"?e.stubMode:void 0})}}const ue='a[href], button, input, select, textarea, [role="button"], [role="link"], [role="tab"], [onclick], [tabindex]';function F(l,e){return{items:l.slice(0,e),truncated:l.length>e}}function _(l,e,t,s,n,i){return{analyzer:l,summary:e,count:t,items:s,warnings:n,truncated:i}}function O(l){try{return k.inspectElement(l).bestSelector}catch{return l.tagName.toLowerCase()}}const at=l=>{const e=Array.from(l.querySelectorAll("form")),t=e.map(n=>{const i=Array.from(n.querySelectorAll("input, select, textarea")).map(r=>({tag:r.tagName.toLowerCase(),type:r.getAttribute("type")||(r.tagName.toLowerCase()==="textarea"?"textarea":r.tagName.toLowerCase()==="select"?"select":"text"),name:r.getAttribute("name")||void 0,id:r.getAttribute("id")||void 0,required:r.hasAttribute("required"),pattern:r.getAttribute("pattern")||void 0,maxLength:r.getAttribute("maxlength")||void 0,placeholder:r.getAttribute("placeholder")||void 0,ariaLabel:r.getAttribute("aria-label")||void 0,autocomplete:r.getAttribute("autocomplete")||void 0,hasLabel:!!(r.getAttribute("id")&&l.querySelector(`label[for="${r.getAttribute("id")}"]`))||!!r.closest("label"),defaultValue:r.value!==void 0&&(r.getAttribute("type")||"text")!=="password"?String(r.value).slice(0,40):void 0}));return{selector:O(n),action:n.getAttribute("action")||void 0,method:(n.getAttribute("method")||"GET").toUpperCase(),id:n.getAttribute("id")||void 0,fieldCount:i.length,submitButton:n.querySelector('button[type="submit"], input[type="submit"]')?O(n.querySelector('button[type="submit"], input[type="submit"]')):void 0,validationAttributes:i.filter(r=>r.required||r.pattern).length,fields:i}}),s=F(t,50);return _("analyze_forms",`${e.length} form(s) with ${t.reduce((n,i)=>n+i.fieldCount,0)} total fields`,e.length,s.items,[],s.truncated)},ct=l=>{const e=Array.from(l.querySelectorAll("a[href]")),t=e.map(n=>({href:n.getAttribute("href")||"",text:q(n).slice(0,60),selector:O(n),rel:n.getAttribute("rel")||void 0,target:n.getAttribute("target")||void 0,download:n.hasAttribute("download"),external:/^https?:\/\//i.test(n.getAttribute("href")||"")&&!lt(n.getAttribute("href")||"",l),anchorOnly:(n.getAttribute("href")||"").startsWith("#")})),s=F(t,200);return _("extract_links",`${e.length} link(s): ${t.filter(n=>n.external).length} external, ${t.filter(n=>n.anchorOnly).length} anchors`,e.length,s.items,[],s.truncated)};function lt(l,e){var t,s,n,i;try{return new URL(l,((s=(t=e.defaultView)==null?void 0:t.location)==null?void 0:s.href)||"http://localhost").origin===(((i=(n=e.defaultView)==null?void 0:n.location)==null?void 0:i.origin)||"")}catch{return!1}}const ut=l=>{const e=Array.from(l.querySelectorAll("img")),t=Array.from(l.querySelectorAll("video")),s=Array.from(l.querySelectorAll("audio")),n=Array.from(l.querySelectorAll("canvas")),i=[],r=[...e.map(c=>({kind:"img",selector:O(c),src:(c.getAttribute("src")||"").slice(0,150),alt:c.getAttribute("alt"),width:c.getAttribute("width")||void 0,height:c.getAttribute("height")||void 0,naturalWidth:c.naturalWidth||void 0,naturalHeight:c.naturalHeight||void 0,lazy:c.getAttribute("loading")==="lazy",missingAlt:!c.hasAttribute("alt")})),...t.map(c=>{var u;return{kind:"video",selector:O(c),src:(c.getAttribute("src")||((u=c.querySelector("source"))==null?void 0:u.getAttribute("src"))||"").slice(0,150),controls:c.hasAttribute("controls"),autoplay:c.hasAttribute("autoplay"),muted:c.hasAttribute("muted"),poster:c.getAttribute("poster")||void 0}}),...s.map(c=>{var u;return{kind:"audio",selector:O(c),src:(c.getAttribute("src")||((u=c.querySelector("source"))==null?void 0:u.getAttribute("src"))||"").slice(0,150),controls:c.hasAttribute("controls")}}),...n.map(c=>({kind:"canvas",selector:O(c),width:c.width,height:c.height}))],o=r.filter(c=>c.missingAlt).length;o&&i.push(`${o} image(s) missing alt text (accessibility risk).`);const a=F(r,200);return _("analyze_media",`${e.length} images, ${t.length} videos, ${s.length} audios, ${n.length} canvases`,r.length,a.items,i,a.truncated)},dt=l=>{const e=l.defaultView,t=[],s={};if(e!=null&&e.getComputedStyle){const i=e.getComputedStyle(l.documentElement);for(let r=0;r({name:i,value:r}));return _("get_css_variables",`${n.length} CSS custom properties found`,n.length,n,t,!1)},ht=l=>{const e=l.defaultView,t=[],s=new Map;if(e!=null&&e.getComputedStyle)for(const i of Array.from(l.querySelectorAll("body, body *")).slice(0,800)){const r=e.getComputedStyle(i),o=r.fontFamily||"",a=r.fontSize||"",c=`${o.split(",")[0].replace(/["']/g,"").trim()} @ ${a}`;s.set(c,(s.get(c)||0)+1)}else t.push("getComputedStyle unavailable — font usage analysis requires rendered styles.");const n=Array.from(s.entries()).map(([i,r])=>({font:i,usage:r})).sort((i,r)=>r.usage-i.usage);return _("analyze_fonts",`${n.length} distinct font/size combinations`,n.length,n,t,!1)},gt=l=>{const e=l.defaultView,t=[],s=new Map;if(e!=null&&e.getComputedStyle)for(const i of Array.from(l.querySelectorAll("body, body *")).slice(0,800)){const r=e.getComputedStyle(i);for(const o of["color","background-color","border-top-color"]){const a=r.getPropertyValue(o);a&&a!=="rgba(0, 0, 0, 0)"&&s.set(a,(s.get(a)||0)+1)}}else{for(const i of Array.from(l.querySelectorAll("[style]")).slice(0,300)){const r=i.getAttribute("style")||"",o=/(color)\s*:\s*([^;]+)/gi;let a;for(;a=o.exec(r);)s.set(a[2].trim(),(s.get(a[2].trim())||0)+1)}t.push("getComputedStyle unavailable — palette from inline styles only.")}const n=Array.from(s.entries()).map(([i,r])=>({color:i,usage:r})).sort((i,r)=>r.usage-i.usage).slice(0,40);return _("extract_color_palette",`${s.size} distinct colors in use`,s.size,n,t,!1)},pt=l=>{const e=l.defaultView,t=[],s=[];if(!(e!=null&&e.getComputedStyle))return t.push("getComputedStyle unavailable — z-index analysis requires rendered styles."),_("detect_zindex_conflicts","unavailable",0,[],t,!1);const n=[];for(const i of Array.from(l.querySelectorAll("body *")).slice(0,1e3)){const r=e.getComputedStyle(i),o=r.zIndex;o&&o!=="auto"&&parseInt(o,10)>0&&n.push({selector:O(i),z:parseInt(o,10),position:r.position,stacking:r.position==="fixed"||r.position==="sticky"||r.opacity!=="1"||r.transform!=="none"?"creates-stacking-context":"plain"})}for(let i=0;i1e5&&s.push({zIndex:n[i].z,elements:[n[i].selector],note:"extremely high z-index — competes with platform overlays (MCPDOM uses 2147483640+)."})}return _("detect_zindex_conflicts",`${n.length} z-indexed elements, ${s.length} potential conflict(s)`,s.length,F(s,40).items,t,s.length>40)},mt=l=>{const e=l.defaultView,t=[],s=l.documentElement,n=l.body,i=Math.max((s==null?void 0:s.scrollWidth)||0,(n==null?void 0:n.scrollWidth)||0),r=(e==null?void 0:e.innerWidth)||(s==null?void 0:s.clientWidth)||0,o=i>r+1;if(o&&(t.push({issue:"horizontal-overflow",detail:`document scrollWidth ${i} exceeds viewport ${r}`}),e!=null&&e.getComputedStyle))for(const c of Array.from(l.querySelectorAll("body *")).slice(0,600)){const u=c.getBoundingClientRect();if(u.right>r+2&&u.width>100&&(t.push({issue:"element-exceeds-viewport",selector:O(c),right:Math.round(u.right),width:Math.round(u.width)}),t.length>15))break}let a=0;for(const c of Array.from(l.querySelectorAll(ue)).slice(0,500)){const u=c.getBoundingClientRect();(u.width===0||u.height===0)&&a++}return a&&t.push({issue:"zero-size-interactive-elements",count:a}),_("detect_layout_issues",o?`HORIZONTAL OVERFLOW: page is ${i-r}px wider than viewport`:"No horizontal overflow detected",t.length,t,[],!1)},ft=l=>{const e=Array.from(l.querySelectorAll(ue)),t=new Map,s=e.slice(0,300).map(n=>{const i=de(n),r=i.role||n.tagName.toLowerCase();return t.set(r,(t.get(r)||0)+1),{selector:i.bestSelector,tag:i.tag,role:i.role,text:i.text.slice(0,40),visible:i.visibility.isVisible,disabled:n.disabled||n.hasAttribute("disabled"),inViewport:i.visibility.isInViewport}});return _("census_interactive_elements",`${e.length} interactive elements: ${Array.from(t.entries()).map(([n,i])=>`${n}×${i}`).join(", ")||"none"}`,e.length,s,[],e.length>300)};function de(l){try{return k.inspectElement(l)}catch{return{tag:l.tagName.toLowerCase(),role:void 0,text:"",bestSelector:l.tagName.toLowerCase(),bounds:{x:0,y:0,width:0,height:0,top:0,right:0,bottom:0,left:0},visibility:{isVisible:!1,isInViewport:!1}}}}const bt=l=>{const e=["header","nav","main","aside","footer","article","section","figure","figcaption","mark","time","address","details","summary","dialog"],t=[];for(const i of e){const r=Array.from(l.querySelectorAll(i));if(r.length)for(const o of r.slice(0,20))t.push({tag:i,selector:O(o),role:o.getAttribute("role")||yt(i),text:q(o).slice(0,50),childCount:o.children.length})}const s=t.filter(i=>["banner","navigation","main","complementary","contentinfo"].includes(i.role)),n=[];return t.find(i=>i.tag==="main")||n.push("No
element — page lacks a primary landmark."),l.querySelectorAll("header").length>1&&n.push("Multiple
elements outside sections — ambiguous banner landmark."),_("detect_semantic_elements",`${t.length} semantic elements, ${s.length} landmarks`,t.length,F(t,100).items,n,t.length>100)};function yt(l){return{header:"banner",nav:"navigation",main:"main",aside:"complementary",footer:"contentinfo",article:"article",section:"region",form:"form"}[l]}const Ce={analyze_forms:at,extract_links:ct,analyze_media:ut,get_css_variables:dt,analyze_fonts:ht,extract_color_palette:gt,detect_zindex_conflicts:pt,detect_layout_issues:mt,census_interactive_elements:ft,detect_semantic_elements:bt,scan_accessibility_issues:l=>{var i;const e=[];for(const r of Array.from(l.querySelectorAll("img")).slice(0,200))r.hasAttribute("alt")||e.push({rule:"img-alt",severity:"error",selector:O(r),message:"Image is missing the alt attribute."});for(const r of Array.from(l.querySelectorAll("input:not([type=hidden]):not([type=submit]):not([type=button])")).slice(0,200)){const o=r.getAttribute("id");o&&l.querySelector(`label[for="${o}"]`)||r.closest("label")||r.getAttribute("aria-label")||r.getAttribute("aria-labelledby")||e.push({rule:"input-label",severity:"error",selector:O(r),message:"Form input has no associated label, aria-label or aria-labelledby."})}for(const r of Array.from(l.querySelectorAll('button, a[href], [role="button"]')).slice(0,300)){const o=q(r).trim(),a=r.getAttribute("aria-label");!o&&!a&&e.push({rule:"accessible-name",severity:"error",selector:O(r),message:"Interactive element has no accessible name (no text, no aria-label).",hint:r.querySelector("img[alt]")?"Contains an image — consider alt text or aria-label.":void 0})}const t=Array.from(l.querySelectorAll("h1, h2, h3, h4, h5, h6")).slice(0,100);let s=0;for(const r of t){const o=parseInt(r.tagName[1],10);s&&o>s+1&&e.push({rule:"heading-order",severity:"warning",selector:O(r),message:`Heading level jumps from h${s} to h${o}.`}),s=o}(i=l.documentElement)!=null&&i.getAttribute("lang")||e.push({rule:"html-lang",severity:"warning",selector:"html",message:"The element has no lang attribute."});const n=e.filter(r=>r.severity==="error").length;return _("scan_accessibility_issues",`${e.length} issue(s): ${n} errors, ${e.length-n} warnings`,e.length,F(e,100).items,[],e.length>100)},detect_dead_click_targets:l=>{const e=l.defaultView,t=[];for(const s of Array.from(l.querySelectorAll(ue)).slice(0,500)){const n=s.getBoundingClientRect(),i=e!=null&&e.getComputedStyle?e.getComputedStyle(s):null,r=n.width===0||n.height===0,o=i?i.pointerEvents==="none":!1,a=i?i.display==="none"||i.visibility==="hidden":!1,c=s.getAttribute("aria-hidden")==="true";(r||o||a||c)&&t.push({selector:O(s),tag:s.tagName.toLowerCase(),text:q(s).slice(0,30),reasons:[r&&"zero-size",o&&"pointer-events:none",a&&`hidden (${i?i.display:"?"}/${i?i.visibility:"?"})`,c&&"aria-hidden"].filter(Boolean)})}return _("detect_dead_click_targets",`${t.length} unreachable interactive element(s)`,t.length,F(t,80).items,[],t.length>80)},inventory_animations:l=>{const e=l.defaultView,t=[],s=[];if(!(e!=null&&e.getComputedStyle))return t.push("getComputedStyle unavailable — animation inventory requires rendered styles."),_("inventory_animations","unavailable",0,[],t,!1);for(const i of Array.from(l.querySelectorAll("body *")).slice(0,800)){const r=e.getComputedStyle(i),o=r.animationName!=="none"?`${r.animationName} ${r.animationDuration}`:null,a=r.transitionProperty!=="none"&&r.transitionProperty!=="all"?`${r.transitionProperty} ${r.transitionDuration}`:r.transitionProperty==="all"?`all ${r.transitionDuration}`:null;(o||a)&&s.push({selector:O(i),animation:o,transition:a,transitionTiming:r.transitionTimingFunction||void 0})}const n=s.filter(i=>i.animation&&i.animation.includes("infinite"));return n.length>5&&t.push(`${n.length} infinitely looping animations — may indicate decorative spinners or a stuck loading state.`),_("inventory_animations",`${s.length} animated/transitioning elements`,s.length,F(s,80).items,t,s.length>80)},map_frame_tree:l=>{const e=[],t=(n,i,r)=>{const o=Array.from(n.querySelectorAll("iframe, frame"));for(const a of o){const c=a.getAttribute("src")||"(no src)";let u=!1,h=null;try{const g=a.contentDocument;g&&(u=!0,h=g.querySelectorAll("*").length,r<3&&t(g,`${i} > ${a.tagName.toLowerCase()}[${c.slice(0,50)}]`,r+1))}catch{u=!1}e.push({path:`${i} > ${a.tagName.toLowerCase()}`,selector:O(a),src:c.slice(0,120),title:a.getAttribute("title")||void 0,name:a.getAttribute("name")||void 0,sandbox:a.getAttribute("sandbox")||void 0,accessible:u,childCount:h,limitation:u?void 0:"Same-origin policy blocks contentDocument access (cross-origin frame)."})}};t(l,"document",0);const s=e.filter(n=>!n.accessible).length;return _("map_frame_tree",`${e.length} frame(s), ${s} inaccessible (cross-origin)`,e.length,e,[],!1)},inventory_shadow_roots:l=>{const e=[],t=(s,n,i)=>{const r=(s instanceof ShadowRoot,Array.from(s.querySelectorAll("*")));for(const o of r)if(o.shadowRoot){const a=o.shadowRoot,c=`${n} > ${o.tagName.toLowerCase()}::shadowRoot(${a.mode})`;e.push({path:c.slice(0,200),hostSelector:O(o),hostTag:o.tagName.toLowerCase(),mode:a.mode,childCount:a.querySelectorAll("*").length,styles:a.querySelectorAll("style").length}),i<4&&t(a,c,i+1)}};return t(l.documentElement,"document",0),_("inventory_shadow_roots",`${e.length} open shadow root(s) found`,e.length,e,[],!1)},inspect_page_storage:l=>{const e=l.defaultView,t=new le,s=[],n=[];if(!(e!=null&&e.localStorage)||!(e!=null&&e.sessionStorage))return _("inspect_page_storage","Web Storage API unavailable in this context",0,[],["localStorage/sessionStorage are not accessible here (JSDOM limitation or sandboxed iframe)."],!1);try{for(let r=0;rr+(o.size||0),0);return _("inspect_page_storage",`${n.length} storage entries (~${i} bytes), sensitive keys redacted`,n.length,F(n,100).items,s,n.length>100)},get_performance_metrics:l=>{var i,r,o,a;const e=l.defaultView,t=[],s=e==null?void 0:e.performance;if(!(s!=null&&s.timing)&&!(s!=null&&s.getEntriesByType))return _("get_performance_metrics","Performance API unavailable",0,[],["window.performance is not exposed in this context."],!1);const n=[];try{const c=(r=(i=s.getEntriesByType)==null?void 0:i.call(s,"navigation"))==null?void 0:r[0];if(c)n.push({metric:"navigation-timing",domContentLoaded:Math.round(c.domContentLoadedEventEnd),loadComplete:Math.round(c.loadEventEnd),domInteractive:Math.round(c.domInteractive),type:c.type,redirectCount:c.redirectCount,sizeTransfer:c.transferSize});else if(s.timing){const g=s.timing;n.push({metric:"navigation-timing-legacy",domContentLoaded:g.domContentLoadedEventEnd-g.navigationStart,loadComplete:g.loadEventEnd-g.navigationStart,domInteractive:g.domInteractive-g.navigationStart})}const u=((o=s.getEntriesByType)==null?void 0:o.call(s,"paint"))||[];for(const g of u)n.push({metric:g.name,startTime:Math.round(g.startTime)});const h=((a=s.getEntriesByType)==null?void 0:a.call(s,"resource"))||[];if(h.length){const g=h.reduce((y,v)=>y+v.duration,0),p=[...h].sort((y,v)=>v.duration-y.duration).slice(0,5).map(y=>({url:String(y.name).slice(0,100),duration:Math.round(y.duration)}));n.push({metric:"resource-summary",count:h.length,totalDuration:Math.round(g),slowest:p})}s.memory&&n.push({metric:"memory",usedJSHeapMB:Math.round(s.memory.usedJSHeapSize/1048576*10)/10,totalJSHeapMB:Math.round(s.memory.totalJSHeapSize/1048576*10)/10})}catch(c){t.push(`performance read failed: ${c.message}`)}return _("get_performance_metrics",`${n.length} metric group(s)`,n.length,n,t,!1)},extract_seo_metadata:l=>{var r,o,a;const e=c=>{var u;return((u=l.querySelector(`meta[name="${c}"]`))==null?void 0:u.getAttribute("content"))||void 0},t=c=>{var u;return((u=l.querySelector(`meta[property="${c}"]`))==null?void 0:u.getAttribute("content"))||void 0},s=[{field:"title",value:l.title||void 0},{field:"description",value:e("description")},{field:"canonical",value:(r=l.querySelector('link[rel="canonical"]'))==null?void 0:r.getAttribute("href")},{field:"robots",value:e("robots")},{field:"viewport",value:e("viewport")},{field:"charset",value:(o=l.querySelector("meta[charset]"))==null?void 0:o.getAttribute("charset")},{field:"og:title",value:t("og:title")},{field:"og:description",value:t("og:description")},{field:"og:image",value:t("og:image")},{field:"og:url",value:t("og:url")},{field:"twitter:card",value:e("twitter:card")},{field:"language",value:(a=l.documentElement)==null?void 0:a.getAttribute("lang")}],n=l.querySelectorAll("h1").length,i=[];return n===0&&i.push("No h1 — page lacks a primary heading."),n>1&&i.push(`Multiple h1 elements (${n}).`),e("description")||i.push("No meta description."),s.push({field:"h1Count",value:n}),_("extract_seo_metadata",`SEO metadata extracted; ${i.length} warning(s)`,s.length,s,i,!1)},extract_structured_data:l=>{var t;const e=[];for(const s of Array.from(l.querySelectorAll('script[type="application/ld+json"]')))try{const n=JSON.parse(s.textContent||"{}");e.push({format:"JSON-LD",type:n["@type"]||(Array.isArray(n)?"array":"unknown"),data:n})}catch(n){e.push({format:"JSON-LD",type:"invalid-json",error:n.message})}for(const s of Array.from(l.querySelectorAll("[itemscope]")).slice(0,30)){const n=s.getAttribute("itemtype")||"unknown",i={};for(const r of Array.from(s.querySelectorAll("[itemprop]"))){const o=r.getAttribute("itemprop")||"",a=r.getAttribute("content")||r.getAttribute("href")||((t=r.textContent)==null?void 0:t.trim())||"";i[o]=a.slice(0,100)}e.push({format:"microdata",type:n.split("/").pop()||n,data:i})}return _("extract_structured_data",`${e.length} structured data block(s)`,e.length,e,[],!1)},extract_tables:l=>{const e=Array.from(l.querySelectorAll("table")),t=e.slice(0,30).map(s=>{var a,c,u;const n=Array.from(s.querySelectorAll("thead th, tr:first-child th")).map(h=>{var g;return((g=h.textContent)==null?void 0:g.trim())||""}),i=Array.from(s.querySelectorAll("tbody tr, tr")).filter(h=>!h.querySelector("th")).slice(0,50),r=i.map(h=>Array.from(h.querySelectorAll("td")).map(g=>(g.textContent||"").trim().slice(0,60))),o=(c=(a=s.querySelector("caption"))==null?void 0:a.textContent)==null?void 0:c.trim();return{selector:O(s),caption:o,columnCount:n.length||((u=r[0])==null?void 0:u.length)||0,rowCount:i.length,headers:n,rows:r}});return _("extract_tables",`${e.length} table(s)`,e.length,t,[],e.length>30)},extract_lists:l=>{const e=Array.from(l.querySelectorAll("ul, ol")),t=e.slice(0,60).map(s=>{const n=Array.from(s.querySelectorAll(":scope > li")).slice(0,40);return{selector:O(s),kind:s.tagName.toLowerCase(),ordered:s.tagName.toLowerCase()==="ol",itemCount:n.length,items:n.map(i=>q(i).slice(0,60)),nested:s.querySelectorAll("ul, ol").length}});return _("extract_lists",`${e.length} list(s)`,e.length,t,[],e.length>60)},analyze_page_content:l=>{const e=l.body,t=(e==null?void 0:e.innerText)||(e==null?void 0:e.textContent)||"",s=t.trim()?t.trim().split(/\s+/).length:0,n=Array.from(l.querySelectorAll("h1, h2, h3, h4, h5, h6")).map(c=>({level:parseInt(c.tagName[1],10),text:q(c).slice(0,80)})),i=l.querySelectorAll("p").length,r=i?Math.round(s/i):0,o=Math.round(s/220*10)/10,a=[{metric:"wordCount",value:s},{metric:"paragraphCount",value:i},{metric:"avgParagraphWords",value:r},{metric:"estimatedReadingMinutes",value:o},{metric:"headingCount",value:n.length},{metric:"imageCount",value:l.querySelectorAll("img").length},{metric:"linkDensity",value:Math.round(l.querySelectorAll("a[href]").length/Math.max(1,s)*1e3)/1e3},{metric:"headings",value:n.slice(0,50)}];return _("analyze_page_content",`${s} words, ${i} paragraphs, ~${o} min read`,a.length,a,[],!1)},search_dom:(l,e)=>{const t=String((e==null?void 0:e.query)||"").trim();if(!t)return _("search_dom","No query supplied",0,[],["Provide a text query; optionally tag/attr filters."],!1);const s=t.toLowerCase(),n=[],i=Math.min((e==null?void 0:e.limit)||50,200),r=Array.from(l.querySelectorAll("*"));for(const o of r){if(n.length>=i)break;if(e!=null&&e.tag&&o.tagName.toLowerCase()!==String(e.tag).toLowerCase())continue;const a=q(o),c=Array.from(o.attributes);let u=0,h="";o.tagName.toLowerCase().includes(s)&&(u+=.2,h="tag match"),a.toLowerCase().includes(s)&&a.length<200&&(u+=.6,h="text match");for(const g of c)if(g.name.toLowerCase().includes(s)||g.value.length<100&&g.value.toLowerCase().includes(s)){u+=.4,h=`attribute ${g.name} match`;break}if(e!=null&&e.attr){const g=String(e.attr).toLowerCase(),p=e.attrValue?String(e.attrValue).toLowerCase():null;if(c.find(v=>v.name.toLowerCase()===g&&(!p||v.value.toLowerCase().includes(p))))u+=.5;else continue}if(u>0){const g=de(o);n.push({selector:g.bestSelector,tag:g.tag,role:g.role,text:g.text.slice(0,60),score:Math.round(u*100)/100,reason:h,visible:g.visibility.isVisible,bounds:{x:Math.round(g.bounds.x),y:Math.round(g.bounds.y),w:Math.round(g.bounds.width),h:Math.round(g.bounds.height)}})}}return n.sort((o,a)=>a.score-o.score),_("search_dom",`${n.length} element(s) match "${t}"`,n.length,n,[],n.length>=i)},inventory_ctas:l=>{var t;const e=[];for(const s of Array.from(l.querySelectorAll('button, a[class*="btn"], a[class*="button"], input[type="submit"], [role="button"]')).slice(0,100)){const n=de(s);e.push({selector:n.bestSelector,tag:n.tag,text:n.text.slice(0,50),styleHint:(t=s.getAttribute("class"))==null?void 0:t.slice(0,60),primary:/primary|cta|submit|main/i.test(s.getAttribute("class")||"")||s.type==="submit",visible:n.visibility.isVisible})}return _("inventory_ctas",`${e.length} call-to-action element(s)`,e.length,e,[],!1)},detect_focus_traps:l=>{const e=[];for(const s of Array.from(l.querySelectorAll('[role="dialog"], [aria-modal="true"], dialog[open], .modal, [class*="modal"]')).slice(0,30)){const n=s.querySelectorAll('a[href], button, input, select, textarea, [tabindex]:not([tabindex="-1"])');e.push({selector:O(s),kind:s.getAttribute("role")||s.tagName.toLowerCase(),ariaModal:s.getAttribute("aria-modal"),focusableCount:n.length,firstFocusable:n[0]?O(n[0]):void 0,note:n.length===0?"Modal container has NO focusable elements — keyboard users are trapped.":void 0})}const t=l.querySelectorAll("[tabindex]>0");for(const s of Array.from(t).slice(0,20))e.push({selector:O(s),kind:"positive-tabindex",note:`tabindex=${s.tabIndex} breaks natural tab order.`});return _("detect_focus_traps",`${e.length} focus-management issue(s)/container(s)`,e.length,e,[],!1)},infer_responsive_breakpoints:l=>{const e=l.defaultView,t=[],s=new Set;for(const o of Array.from(l.querySelectorAll("style"))){const a=o.textContent||"",c=/@media[^{]*?\(\s*(?:min|max)-width\s*:\s*(\d+)(?:\.\d+)?px/g;let u;for(;u=c.exec(a);)s.add(parseInt(u[1],10))}for(const o of Array.from(l.querySelectorAll('link[rel="stylesheet"]')).slice(0,10)){const a=o.getAttribute("href")||"";if(/^\d+px$/.test(a)||a.includes("width=")){const c=a.match(/width=(\d+)/);c&&s.add(parseInt(c[1],10))}}for(const o of Array.from(l.querySelectorAll("img[srcset], source[srcset]")).slice(0,50)){const a=o.getAttribute("srcset")||"";for(const c of a.matchAll(/(\d+)w/g))s.add(parseInt(c[1],10))}e!=null&&e.matchMedia||t.push("matchMedia unavailable — live breakpoint probing skipped.");const n=Array.from(s).sort((o,a)=>o-a),i=n.map(o=>({breakpoint:o,note:o<=768?"mobile-class":o<=1024?"tablet-class":"desktop-class"})),r=e==null?void 0:e.innerWidth;if(r){const o=n.filter(a=>a<=r);i.unshift({breakpoint:`current viewport: ${r}px`,note:o.length?`below breakpoints: ${o.join(", ")}`:"no declared breakpoint below current width"})}return _("infer_responsive_breakpoints",`${n.length} breakpoint(s) inferred from CSS/srcset`,i.length,i,t,!1)},get_selection_state:l=>{var i;const e=l.defaultView,t=(i=e==null?void 0:e.getSelection)==null?void 0:i.call(e),s=l.activeElement,n=[{hasSelection:!!(t!=null&&t.toString()),selectedText:(t==null?void 0:t.toString().slice(0,200))||"",selectionRanges:(t==null?void 0:t.rangeCount)||0,activeElement:s?{tag:s.tagName.toLowerCase(),selector:O(s),editable:s.isContentEditable||["INPUT","TEXTAREA"].includes(s.tagName)}:null}];return _("get_selection_state",t!=null&&t.toString()?`Selection: "${t.toString().slice(0,40)}…"`:"No text selection",1,n,[],!1)}};function Et(l,e,t){const s=Ce[l];return s?s(e,t):{analyzer:l,summary:`Unknown analyzer "${l}". Available: ${Object.keys(Ce).join(", ")}`,count:0,items:[],warnings:[],truncated:!1}}const vt=2e3;class wt{constructor(e=vt){b(this,"events",[]);b(this,"cap");b(this,"counter",0);this.cap=Math.max(10,e)}record(e,t,s={}){this.counter++;const n={eventId:`evt_${Date.now().toString(36)}_${this.counter}`,timestamp:Date.now(),kind:e,operationId:s.operationId,sessionId:s.sessionId,detail:t,data:s.data};return this.events.push(n),this.events.length>this.cap&&this.events.splice(0,this.events.length-this.cap),n}query(e){let t=this.events;e.kind&&(t=t.filter(n=>n.kind===e.kind)),e.operationId&&(t=t.filter(n=>n.operationId===e.operationId)),e.sinceTimestamp&&(t=t.filter(n=>n.timestamp>=e.sinceTimestamp));const s=e.limit&&e.limit>0?e.limit:200;return t.slice(-s)}size(){return this.events.length}toJSON(){return[...this.events]}}class St{constructor(){b(this,"counter",0);b(this,"operations",new Map)}begin(e){this.counter++;const t=`op_${Date.now().toString(36)}_${this.counter}`;return this.operations.set(t,{operationId:t,tool:e,startedAt:Date.now(),status:"RUNNING",timelineEventIds:[]}),t}end(e,t,s){const n=this.operations.get(e);n&&(n.endedAt=Date.now(),n.status=t,n.relatedError=s)}attachEvent(e,t){const s=this.operations.get(e);s&&s.timelineEventIds.push(t)}trace(e){const t=this.operations.get(e);return t?{...t,durationMs:t.endedAt?t.endedAt-t.startedAt:void 0}:null}recent(e=100){return Array.from(this.operations.values()).slice(-e).map(t=>({...t,durationMs:t.endedAt?t.endedAt-t.startedAt:void 0}))}}const Ie=100;class Tt{constructor(e){b(this,"sessionId");b(this,"timeline",new wt);b(this,"operations",new St);b(this,"tabs",new Map);b(this,"activeTabId",null);b(this,"startedAt",Date.now());b(this,"snapshots",[]);b(this,"commandHistory",[]);b(this,"annotationCount",0);b(this,"projectId");b(this,"tabCounter",0);b(this,"commandCounter",0);this.sessionId=e||`sess_${Date.now().toString(36)}`}registerTab(e,t,s){const n=e!==void 0?Array.from(this.tabs.values()).find(o=>o.browserTabId===e):void 0;if(n)return n.lastSeenAt=Date.now(),n.status="OPEN",n.url=t||n.url,n.title=s||n.title,n;this.tabCounter++;const i=`stab_${this.tabCounter}_${Date.now().toString(36)}`,r={sessionTabId:i,browserTabId:e,url:t,title:s,createdAt:Date.now(),lastSeenAt:Date.now(),status:"OPEN"};return this.tabs.set(i,r),this.timeline.record("TAB_OPENED",`tab ${i} registered (${t||"no url"})`,{sessionId:this.sessionId}),r}closeTab(e){const t=this.tabs.get(e);return t?(t.status="CLOSED",t.lastSeenAt=Date.now(),this.timeline.record("TAB_CLOSED",`tab ${e} closed`,{sessionId:this.sessionId}),!0):!1}switchTab(e){const t=this.tabs.get(e);return!t||t.status==="CLOSED"?!1:(this.activeTabId=e,this.timeline.record("TAB_SWITCHED",`active tab → ${e}`,{sessionId:this.sessionId}),!0)}getTabs(){return Array.from(this.tabs.values())}getActiveTab(){if(this.activeTabId){const e=this.tabs.get(this.activeTabId);if(e&&e.status==="OPEN")return e}return Array.from(this.tabs.values()).find(e=>e.status==="OPEN")||null}markAllStale(){let e=0;for(const t of this.tabs.values())t.status==="OPEN"&&(t.status="STALE",e++);return e}captureSnapshot(e,t,s){var a,c,u;const n=e.defaultView,i=((a=e.documentElement)==null?void 0:a.outerHTML)||"",r=e.querySelectorAll('a[href], button, input, select, textarea, [role="button"]').length,o={snapshotId:`snap_${Date.now().toString(36)}_${this.snapshots.length+1}`,timestamp:Date.now(),url:((c=n==null?void 0:n.location)==null?void 0:c.href)||((u=e.location)==null?void 0:u.href)||"",title:e.title||"",viewport:{width:(n==null?void 0:n.innerWidth)||0,height:(n==null?void 0:n.innerHeight)||0,scrollX:(n==null?void 0:n.scrollX)||0,scrollY:(n==null?void 0:n.scrollY)||0,devicePixelRatio:(n==null?void 0:n.devicePixelRatio)||1},domLength:i.length,domHash:be(i),interactiveCount:r,selectedRegions:[],extensionEnabled:t,pendingMutations:s,annotationCount:this.annotationCount};return this.snapshots.push(o),this.snapshots.length>Ie&&this.snapshots.splice(0,this.snapshots.length-Ie),this.timeline.record("SNAPSHOT_CREATED",`snapshot ${o.snapshotId} (dom ${o.domLength}b)`,{sessionId:this.sessionId}),o}getSnapshot(e){return e?this.snapshots.find(t=>t.snapshotId===e)||null:this.snapshots[this.snapshots.length-1]||null}listSnapshots(){return this.snapshots.map(e=>({snapshotId:e.snapshotId,timestamp:e.timestamp,url:e.url,title:e.title,domLength:e.domLength,domHash:e.domHash}))}compareSnapshots(e,t){const s=["url","title","domLength","domHash","interactiveCount","extensionEnabled","annotationCount"],n=[];for(const r of s)e[r]!==t[r]&&n.push({field:r,before:e[r],after:t[r]});(e.viewport.width!==t.viewport.width||e.viewport.height!==t.viewport.height)&&n.push({field:"viewport",before:`${e.viewport.width}x${e.viewport.height}`,after:`${t.viewport.width}x${t.viewport.height}`});const i=t.domLength-e.domLength;return{identical:n.length===0,changes:n,domDelta:{beforeLength:e.domLength,afterLength:t.domLength,delta:i},summary:n.length===0?"States are identical.":`${n.length} field(s) changed; DOM size ${i>=0?"+":""}${i} bytes.`}}recordCommand(e,t,s,n,i){this.commandCounter++;const r=`cmd_${this.commandCounter}_${Date.now().toString(36)}`;return this.commandHistory.push({commandId:r,tool:e,args:t,outcome:s,timestamp:Date.now(),durationMs:n,error:i}),this.timeline.record("COMMAND_EXECUTED",`${e} → ${s}${i?` (${i})`:""}`,{sessionId:this.sessionId,data:{commandId:r}}),r}getCommandHistory(e=100){return this.commandHistory.slice(-e)}noteAnnotations(e){this.annotationCount=e}bindProject(e){this.projectId=e}getProjectId(){return this.projectId}summary(e,t,s,n){var i,r,o;return{sessionId:this.sessionId,startedAt:this.startedAt,url:((r=(i=e.defaultView)==null?void 0:i.location)==null?void 0:r.href)||((o=e.location)==null?void 0:o.href)||"",title:e.title||"",tabs:this.getTabs(),activeTabId:this.activeTabId,viewport:{width:t.width,height:t.height,isModified:t.isModified},extensionEnabled:s,snapshotCount:this.snapshots.length,commandCount:this.commandHistory.length,annotationCount:this.annotationCount,mutationHistoryCount:n.length,timelineEventCount:this.timeline.size(),projectId:this.projectId}}}const Ct=l=>{var e,t;try{const s=l.getBoundingClientRect();if(s.width===0&&s.height===0)return null;const n=((t=(e=l.ownerDocument)==null?void 0:e.defaultView)==null?void 0:t.innerWidth)||1920;return s.yn*1.5?"bottom":s.xn*.8?"right":"center"}catch{return null}},It={navigation:"navigation",banner:"header",contentinfo:"footer",complementary:"sidebar",main:"main",form:"form",search:"search",region:"section",dialog:"modal",alertdialog:"modal",table:"table",list:"list",combobox:"dropdown",button:"button",link:"link",textbox:"input",checkbox:"checkbox",radio:"radio",img:"image",article:"article"},At={nav:"navigation",header:"header",footer:"footer",aside:"sidebar",main:"main",section:"section",article:"article",form:"form",table:"table",ul:"list",ol:"list",figure:"figure",dialog:"modal",button:"button",input:"input",select:"dropdown",textarea:"textarea",canvas:"canvas",video:"video",img:"image",h1:"heading",h2:"heading",h3:"heading"};function Z(l){return l.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"").replace(/_{2,}/g,"_").slice(0,48).replace(/_$/,"")}class xt{generate(e){return this.generateFromMeta({tagName:e.tagName.toLowerCase(),role:e.getAttribute("role")||void 0,text:q(e).trim(),ariaLabel:e.getAttribute("aria-label")||void 0,stableClass:Array.from(e.classList||[]).find(t=>/^[a-z][a-z0-9-]{2,}$/i.test(t)&&!_t.has(t)),position:Ct(e),nearbyHeading:this.nearbyHeading(e)})}generateFromMeta(e){const t=[],s=[],n=e.role||Nt(e.tagName);if(n){const r=It[n]||n;s.push(r),t.push(`role=${n}`)}else{const r=At[e.tagName]||e.tagName;s.push(r),t.push(`tag=${e.tagName}`)}if(e.ariaLabel&&(s.unshift(Z(e.ariaLabel)),t.push(`aria-label="${e.ariaLabel.slice(0,30)}"`)),e.text&&e.text.length<=40){const r=Z(e.text.split(/\s+/).slice(0,3).join(" "));r&&r.length>=2&&(s.push(r),t.push(`text="${e.text.slice(0,30)}"`))}if(e.nearbyHeading){const r=Z(e.nearbyHeading.split(/\s+/).slice(0,3).join(" "));r&&!s.includes(r)&&(s.push(r),t.push(`nearby-heading="${e.nearbyHeading.slice(0,30)}"`))}e.stableClass&&s.length<3&&(s.push(Z(e.stableClass)),t.push(`class=${e.stableClass}`)),e.tagName==="input"&&(s.some(r=>r.includes("input"))||(s.push("input"),t.push("tag=input"))),s.join("_").length<12&&e.position&&(s.push(e.position),t.push(`position=${e.position}`));let i=Z(s.join("_"))||"unnamed_region";return/^\d/.test(i)&&(i=`el_${i}`),{name:i,evidence:t}}nearbyHeading(e){let t=e.parentElement;for(let n=0;t&&n<4;n++){const i=t.querySelector('h1, h2, h3, h4, [role="heading"]');if(i)return q(i).trim().slice(0,40)||null;t=t.parentElement}let s=e.previousElementSibling;for(let n=0;s&&n<4;n++){if(/^H[1-4]$/.test(s.tagName)){const i=q(s).trim();if(i)return i.slice(0,40)}s=s.previousElementSibling}return null}}const _t=new Set(["active","open","visible","hidden","selected","disabled","container","wrapper","root","item","col","row","flex","box","main","div","span","block"]);function Nt(l){switch(l){case"nav":return"navigation";case"header":return"banner";case"footer":return"contentinfo";case"aside":return"complementary";case"main":return"main";case"form":return"form";case"table":return"table";case"button":return"button";case"a":return"link";case"input":return"textbox";case"select":return"combobox";case"textarea":return"textbox";case"img":return"img";default:return null}}const kt=["display","position","flex-direction","grid-template-columns","width","height","background-color","color","font-size","border-radius","overflow"];class Mt{constructor(){b(this,"naming",new xt)}capture(e){const t=e.ownerDocument,s=new Y(t),n=new te,i=s.generateCandidates(e),r=s.bestSelector(e),o=n.fingerprint(e);let a=e,c=0,u="self";for(let d=0;d<3;d++){const f=a.parentElement;if(!f||f===t.body||f===t.documentElement)break;if(this.isMeaningfulContainer(f)){a=f,c=d+1,u="meaningful-ancestor";break}a=f,c=d+1}if(a===e){const d=e.parentElement;d&&d!==t.body&&e.querySelectorAll("*").length<4&&(a=d,c=1,u="direct-parent-fallback")}const h=this.boundedHtml(e,6e4),g=this.boundedHtml(a,12e4);k.inspectElement(e);const p=e.getBoundingClientRect(),y=t.defaultView,v={};if(y!=null&&y.getComputedStyle){const d=y.getComputedStyle(e);for(const f of kt){const w=d.getPropertyValue(f);w&&w!=="none"&&w!=="auto"&&(v[f]=w)}}const m=e.parentElement;return{regionHtml:h,contextHtml:g,boundary:{strategy:u,ancestorLevels:c,note:c===0?"Region captured standalone (no meaningful ancestor within 3 levels).":`Context includes ${c} ancestor level(s) up to a meaningful container.`},selectorCandidates:i,bestSelector:r.selector,xpath:s.buildXPath(e),fingerprintHash:o.hash,dimensions:{width:Math.round(p.width),height:Math.round(p.height)},position:{x:Math.round(p.x),y:Math.round(p.y)},relevantStyles:v,parentInfo:m?{tag:m.tagName.toLowerCase(),selector:Rt(m),text:q(m).slice(0,60)}:void 0,childrenCount:e.children.length,childTags:Array.from(e.children).slice(0,12).map(d=>d.tagName.toLowerCase()),nameHint:this.naming.generate(e),fingerprintVolatility:o.volatilityRisk,volatilityReasons:o.volatilityReasons}}isMeaningfulContainer(e){const t=e.tagName.toLowerCase();if(["section","article","aside","main","nav","header","footer","form"].includes(t)||e.hasAttribute("id")||e.hasAttribute("data-testid")||e.getAttribute("role")||e.children.length>1&&e.querySelector(":scope > *:nth-child(3)"))return!0;const s=e.getAttribute("style")||"";return!!(s.includes("grid")||s.includes("flex"))}boundedHtml(e,t){const s=e.outerHTML;return s.length<=t?s:s.slice(0,t)+` +`}}function Rt(l){try{return new Y(l.ownerDocument).bestSelector(l).selector}catch{return l.tagName.toLowerCase()}}class Ot{constructor(e){b(this,"nodeRegistry");b(this,"snapshotEngine");b(this,"picker");b(this,"interactionEngine");b(this,"observer");b(this,"mutationEngines",new WeakMap);b(this,"viewportControllers",new WeakMap);b(this,"targetingEngines",new WeakMap);b(this,"jsEngine",new Fe);b(this,"fingerprintEngine",new te);b(this,"humanInteraction",new it);b(this,"session",new Tt);b(this,"simulationTabs",[]);b(this,"simulationTabCounter",0);b(this,"simulationExtensions",[{id:"teledom@teledom",name:"TeleDOM Browser Intelligence Platform",version:"4.1.0",description:"The TeleDOM platform extension itself",enabled:!0,installType:"development",isApp:!1}]);b(this,"regionCapture",new Mt);this.nodeRegistry=e||new H;const t=new J,s=new ne;this.snapshotEngine=new he(this.nodeRegistry,t,s),this.picker=new Pe({nodeRegistry:this.nodeRegistry}),this.interactionEngine=new Le(this.nodeRegistry),this.observer=new qe(this.nodeRegistry),this.picker.initGlobalShortcutListener(),this.interactionEngine.setTimingHook(async n=>{const i=this.humanInteraction.delay(n);i>0&&await new Promise(r=>setTimeout(r,i))})}getMutationEngine(e){let t=this.mutationEngines.get(e);return t||(t=new Ue(e,this.nodeRegistry),this.mutationEngines.set(e,t)),t}getViewportController(e){let t=this.viewportControllers.get(e);return t||(t=new Be(e),this.viewportControllers.set(e,t)),t}getTargetingEngine(e){let t=this.targetingEngines.get(e);return t||(t=new tt(e,this.nodeRegistry),this.targetingEngines.set(e,t)),t}isSimulation(){return typeof globalThis.__FORENSIC_SIMULATION__<"u"}getPicker(){return this.picker}getInteractionEngine(){return this.interactionEngine}getObserver(){return this.observer}getNodeRegistry(){return this.nodeRegistry}async handleCommand(e,t=typeof document<"u"?document:{}){var o,a,c,u,h,g,p,y,v;const s=Date.now(),{id:n,command:i,payload:r}=e;try{switch(i){case"LIVE_PAGE_INSPECT":{const m=k.inspectPage(t);return this.success(n,i,m,s)}case"LIVE_ELEMENT_INSPECT":{const m=this.resolveTarget(r,t),d=k.inspectElement(m,this.nodeRegistry);return this.success(n,i,d,s)}case"GET_SELECTED_ELEMENT":{const m=this.picker.getLastSelectedElement();return this.success(n,i,m,s)}case"ELEMENT_PICKER_START":return this.picker.startPicker(),this.success(n,i,{pickerActive:!0},s);case"ELEMENT_PICKER_STOP":return this.picker.stopPicker(),this.success(n,i,{pickerActive:!1},s);case"LIVE_ELEMENT_INTERACT":{const m=r,d=await this.interactionEngine.interact(m,t);return this.success(n,i,d,s)}case"ELEMENT_OBSERVATION_START":{const m=this.resolveTarget(r,t),d=this.observer.startObservation(m,t);return this.success(n,i,d,s)}case"ELEMENT_OBSERVATION_STOP":{const m=this.observer.stopObservation(t);return this.success(n,i,m,s)}case"LIVE_DOM_SNAPSHOT":{if(((r==null?void 0:r.format)||"html")==="html"){const f=((o=t.documentElement)==null?void 0:o.outerHTML)||"";return this.success(n,i,{html:f},s)}const d=this.snapshotEngine.captureSnapshot(t,"live_session");return this.success(n,i,d,s)}case"LIVE_DOM_SUBTREE":{const m=this.resolveTarget(r,t),d=m.outerHTML||"",f=k.inspectElement(m,this.nodeRegistry);return this.success(n,i,{html:d,element:f},s)}case"GET_ELEMENT_VISUAL_STATE":{const m=this.resolveTarget(r,t),d=k.inspectVisualState(m);return this.success(n,i,d,s)}case"LIVE_PAGE_SCREENSHOT":case"LIVE_ELEMENT_SCREENSHOT":{const m=await this.handleScreenshotCapture(i,r,t);return this.success(n,i,m,s)}case"GET_TAB_CONSOLE_LOGS":{const{level:m,searchQuery:d,limit:f=100,clearAfterRead:w}=r||{};let E=typeof window<"u"&&window.__FORENSIC_CONSOLE_BUFFER__||[];if(m&&m!=="all"&&(E=E.filter(S=>S.level===m)),d){const S=String(d).toLowerCase();E=E.filter(T=>{var x,N;return((x=T.text)==null?void 0:x.toLowerCase().includes(S))||((N=T.source)==null?void 0:N.toLowerCase().includes(S))})}return f>0&&(E=E.slice(-f)),w&&typeof window<"u"&&window.__FORENSIC_CONSOLE_BUFFER__&&(window.__FORENSIC_CONSOLE_BUFFER__.length=0),this.success(n,i,{url:typeof window<"u"?window.location.href:"",title:t.title||"",totalCaptured:typeof window<"u"&&((a=window.__FORENSIC_CONSOLE_BUFFER__)==null?void 0:a.length)||E.length,returnedCount:E.length,logs:E},s)}case"GET_TAB_NETWORK_REQUESTS":{const{method:m,searchQuery:d,status:f,onlyErrors:w,limit:E=100,clearAfterRead:S}=r||{};let T=typeof window<"u"&&window.__FORENSIC_NETWORK_BUFFER__||[];if(m&&(T=T.filter(x=>{var N;return((N=x.method)==null?void 0:N.toUpperCase())===String(m).toUpperCase()})),f&&(T=T.filter(x=>x.status===Number(f))),w&&(T=T.filter(x=>x.error||x.status&&x.status>=400)),d){const x=String(d).toLowerCase();T=T.filter(N=>{var D;return(D=N.url)==null?void 0:D.toLowerCase().includes(x)})}return E>0&&(T=T.slice(-E)),S&&typeof window<"u"&&window.__FORENSIC_NETWORK_BUFFER__&&(window.__FORENSIC_NETWORK_BUFFER__.length=0),this.success(n,i,{url:typeof window<"u"?window.location.href:"",title:t.title||"",totalCaptured:typeof window<"u"&&((c=window.__FORENSIC_NETWORK_BUFFER__)==null?void 0:c.length)||T.length,returnedCount:T.length,requests:T},s)}case"CLOSE_TAB":{if(typeof globalThis.chrome<"u"&&((u=globalThis.chrome.runtime)!=null&&u.sendMessage)){const m=await new Promise(d=>{globalThis.chrome.runtime.sendMessage({type:"BROWSER_COMMAND_REQUEST",id:n,command:i,payload:r},f=>d(f))});if(m)return m}return this.isSimulation()?this.simulationCloseTab(r,t,n,i,s):typeof window<"u"?(setTimeout(()=>window.close(),100),this.success(n,i,{closed:!0,url:window.location.href,title:t.title},s)):this.success(n,i,{closed:!0},s)}case"RELOAD_TAB":{if(typeof globalThis.chrome<"u"&&((h=globalThis.chrome.runtime)!=null&&h.sendMessage)){const m=await new Promise(d=>{globalThis.chrome.runtime.sendMessage({type:"BROWSER_COMMAND_REQUEST",id:n,command:i,payload:r},f=>d(f))});if(m)return m}if(this.isSimulation()){const m=(r==null?void 0:r.mode)||"soft";return this.session.timeline.record("NAVIGATED",`tab reloaded (${m} mode)`),this.success(n,i,{reloaded:!0,mode:m,simulated:!0,url:((p=(g=t.defaultView)==null?void 0:g.location)==null?void 0:p.href)||"",title:t.title,note:"Node simulation context: DOM fixture retained; no real navigation occurs."},s)}return typeof window<"u"?(setTimeout(()=>window.location.reload(),100),this.success(n,i,{reloaded:!0,url:window.location.href,title:t.title},s)):this.success(n,i,{reloaded:!0},s)}case"OPEN_TAB":case"LIST_TABS":case"FOCUS_TAB":case"LIST_EXTENSIONS":case"RELOAD_EXTENSION":case"SET_EXTENSION_ENABLED":case"TOGGLE_EXTENSION":{if(this.isSimulation())return this.handleSimulationBackgroundCommand(n,i,r,t,s);if(typeof globalThis.chrome<"u"&&((y=globalThis.chrome.runtime)!=null&&y.sendMessage)){const m=await new Promise(d=>{globalThis.chrome.runtime.sendMessage({type:"BROWSER_COMMAND_REQUEST",id:n,command:i,payload:r},f=>d(f))});if(m)return m}return this.error(n,i,"BACKGROUND_EXECUTION_FAILED",`Command ${i} requires Chrome extension runtime`,s)}case"RESIZE_VIEWPORT":{const m=this.getViewportController(t);let d;if(r!=null&&r.preset)d=m.applyPreset(r.preset);else{const f=Number(r==null?void 0:r.width)||1280,w=Number(r==null?void 0:r.height)||800;d=m.resize(f,w)}return this.session.timeline.record("RESIZED",`viewport → ${d.applied.width}x${d.applied.height}`),this.success(n,i,d,s)}case"RESET_VIEWPORT":{const d=this.getViewportController(t).reset();return this.session.timeline.record("RESIZED",`viewport restored to ${d.applied.width}x${d.applied.height}`),this.success(n,i,d,s)}case"GET_VIEWPORT_STATE":{const m=this.getViewportController(t);return this.success(n,i,m.state(),s)}case"RUN_RESPONSIVE_TEST":{const m=this.getViewportController(t),d=(r==null?void 0:r.sizes)||Pt(),f=m.runResponsiveTest(d,{restore:(r==null?void 0:r.restore)!==!1});return this.success(n,i,f,s)}case"EMULATE_DEVICE":{const d=this.getViewportController(t).emulateDevice((r==null?void 0:r.device)||"pixel-7");return this.success(n,i,d,s)}case"EXECUTE_JS":case"EXECUTE_JS_AND_CAPTURE_CHANGES":{const m=String((r==null?void 0:r.code)||"");if(!m.trim())return this.error(n,i,"SCRIPT_EMPTY","payload.code is required.",s);const d=await this.jsEngine.execute(t,m,{timeoutMs:r==null?void 0:r.timeoutMs,world:(r==null?void 0:r.world)==="MAIN"?"MAIN":"ISOLATED"});return this.session.timeline.record("SCRIPT_EXECUTED",`${d.status} (${d.durationMs}ms)`),this.success(n,i,d,s)}case"DOM_MUTATE":{const d=this.getMutationEngine(t).mutate(r);return this.session.timeline.record("DOM_MUTATED",`${d.operation} on ${d.before.selector} → ${d.success?"OK":d.error}`),this.success(n,i,d,s)}case"DOM_MUTATE_TRANSACTION":{const m=this.getMutationEngine(t),d=(r==null?void 0:r.mode)||"begin";try{if(d==="begin"){const f=m.beginTransaction();return this.success(n,i,{transactionId:f,mode:d,open:!0},s)}if(d==="commit"){const f=m.commitTransaction();return this.session.timeline.record("DOM_MUTATED",`transaction ${f.transactionId} committed (${f.steps.length} steps)`),this.success(n,i,{...f,mode:d},s)}if(d==="rollback"){const f=m.rollbackTransaction(r==null?void 0:r.reason);return this.session.timeline.record("MUTATION_UNDONE",`transaction ${f.transactionId} rolled back`),this.success(n,i,{...f,mode:d},s)}return this.error(n,i,"INVALID_MODE",`mode must be begin|commit|rollback, got "${d}"`,s)}catch(f){return this.error(n,i,"DOM_MUTATION_FAILED",f.message,s)}}case"UNDO_DOM_MUTATION":{const d=this.getMutationEngine(t).undo();return d.success&&this.session.timeline.record("MUTATION_UNDONE",d.message),this.success(n,i,d,s)}case"REDO_DOM_MUTATION":{const d=this.getMutationEngine(t).redo();return d.success&&this.session.timeline.record("MUTATION_REDONE",d.message),this.success(n,i,d,s)}case"GET_MUTATION_HISTORY":{const m=this.getMutationEngine(t);return this.success(n,i,{entries:m.getHistory((r==null?void 0:r.limit)||100),undoDepth:m.getUndoDepth(),redoDepth:m.getRedoDepth(),openTransactionId:m.getOpenTransactionId()},s)}case"PREVIEW_DOM_MUTATION":{const d=this.getMutationEngine(t).preview(r);return this.success(n,i,d,s)}case"GENERATE_ELEMENT_TARGET":{const d=this.getTargetingEngine(t).resolveAndBuild((r==null?void 0:r.target)||(r==null?void 0:r.selector)||"");return"error"in d?this.error(n,i,"TARGET_NOT_FOUND",d.error,s):this.success(n,i,d.target,s)}case"RECOVER_SELECTOR":{const m=new nt(t),d=(r==null?void 0:r.snapshot)||{},f=m.recover((r==null?void 0:r.selector)||"",d);return this.success(n,i,f,s)}case"GET_ELEMENT_ANCESTRY":{const m=this.resolveTarget(r,t);return this.success(n,i,Lt(m,t),s)}case"GET_ELEMENT_FINGERPRINT":{const m=this.resolveTarget(r,t),d=this.fingerprintEngine.fingerprint(m);return this.success(n,i,d,s)}case"GET_ELEMENT_RELATIONSHIPS":{const m=this.resolveTarget(r,t);return this.success(n,i,Dt(m,t),s)}case"GET_ELEMENT_ACCESSIBILITY":{const m=this.resolveTarget(r,t);return this.success(n,i,$t(m),s)}case"GET_COMPUTED_STYLE":{const m=this.resolveTarget(r,t),d=t.defaultView;if(!(d!=null&&d.getComputedStyle))return this.error(n,i,"STYLE_UNAVAILABLE","getComputedStyle is unavailable in this context.",s);const f=d.getComputedStyle(m),w=Array.isArray(r==null?void 0:r.properties)&&r.properties.length?r.properties:["display","position","color","background-color","font-size","font-family","width","height","margin","padding","border","z-index","opacity","visibility","overflow","flex-direction","grid-template-columns"],E={};for(const S of w)E[S]=f.getPropertyValue(S);return this.success(n,i,{selector:k.inspectElement(m,this.nodeRegistry).bestSelector,styles:E},s)}case"ANALYZE_DOM":{const m=String((r==null?void 0:r.analyzer)||"");if(!m)return this.error(n,i,"ANALYZER_REQUIRED",'payload.analyzer is required (e.g. "analyze_forms").',s);const d=Et(m,t,r);return d.count===0&&d.warnings.length===0&&d.items.length===0&&d.summary.startsWith("Unknown analyzer")?this.error(n,i,"UNKNOWN_ANALYZER",d.summary,s):this.success(n,i,d,s)}case"DRAG_ELEMENT":{const m=this.resolveTarget(r==null?void 0:r.source,t),d=r!=null&&r.target?this.resolveTarget(r==null?void 0:r.target,t):null,f=await this.performDrag(m,d,r==null?void 0:r.offsets,t);return this.success(n,i,f,s)}case"SET_INPUT_CHECKED":{const d=this.resolveTarget(r,t);if(d.type!=="checkbox"&&d.type!=="radio")return this.error(n,i,"INPUT_TYPE_UNSUPPORTED",`Target input type "${d.type}" is not checkbox/radio.`,s);const f=d.checked;d.checked=(r==null?void 0:r.checked)!==!1;const w=[];for(const E of["input","change"])try{d.dispatchEvent(new t.defaultView.Event(E,{bubbles:!0})),w.push(E)}catch{}if(d.type==="radio"&&d.name)for(const E of Array.from(t.querySelectorAll(`input[type=radio][name="${d.name}"]`)))E!==d&&(E.checked=!1);return this.success(n,i,{success:!0,selector:k.inspectElement(d,this.nodeRegistry).bestSelector,inputType:d.type,checkedBefore:f,checkedAfter:d.checked,eventsFired:w},s)}case"PRESS_KEYBOARD_SHORTCUT":{const m=Array.isArray(r==null?void 0:r.keys)?r.keys:String((r==null?void 0:r.keys)||"Enter").split("+"),d=r!=null&&r.target?this.resolveTarget(r==null?void 0:r.target,t):t.activeElement||t.body;typeof d.focus=="function"&&d.focus();const f=[],w=t.defaultView;for(const E of m)for(const S of["keydown","keyup"])try{d.dispatchEvent(new((w==null?void 0:w.KeyboardEvent)||KeyboardEvent)(S,{key:E.trim(),bubbles:!0,cancelable:!0,ctrlKey:m.some(T=>/^(ctrl|control|cmd|meta)$/i.test(T))&&E!==m.find(T=>/^(ctrl|control|cmd|meta)$/i.test(T)),shiftKey:m.some(T=>/^shift$/i.test(T))&&E!=="Shift",altKey:m.some(T=>/^alt$/i.test(T))&&E!=="Alt"})),f.push(`${S}:${E}`)}catch{}return this.success(n,i,{success:!0,keys:m,targetSelector:k.inspectElement(d,this.nodeRegistry).bestSelector,eventsFired:f},s)}case"SCROLL_PAGE":{const m=t.defaultView;if(!m)return this.error(n,i,"NO_WINDOW","No window available for scrolling.",s);const d={x:m.scrollX||0,y:m.scrollY||0};let f;if(r!=null&&r.target||r!=null&&r.selector){const E=this.resolveTarget((r==null?void 0:r.target)||(r==null?void 0:r.selector),t);(v=E.scrollIntoView)==null||v.call(E,{behavior:(r==null?void 0:r.behavior)||"auto",block:"center"}),f=k.inspectElement(E,this.nodeRegistry).bestSelector}else m.scrollBy(Number(r==null?void 0:r.x)||0,Number(r==null?void 0:r.y)||0);const w={x:m.scrollX||0,y:m.scrollY||0};return this.success(n,i,{success:!0,scrollBefore:d,scrollAfter:w,requested:{x:Number(r==null?void 0:r.x)||0,y:Number(r==null?void 0:r.y)||0},targetSelector:f},s)}case"WAIT_FOR_CONDITION":return await this.waitForCondition(t,r||{},s,n,i);case"GET_PAGE_STATE":case"CAPTURE_PAGE_STATE":{const m=this.session.captureSnapshot(t,!0,this.getMutationEngine(t).getUndoDepth());return this.success(n,i,m,s)}case"CAPTURE_REGION":{const m=this.resolveTarget((r==null?void 0:r.target)||(r==null?void 0:r.selector),t),d=this.regionCapture.capture(m);return this.success(n,i,d,s)}case"GET_SIMULATION_TAB_STATE":return this.isSimulation()?this.success(n,i,{simulated:!0,tabs:this.simulationTabs,sessionSummary:this.session.getTabs()},s):this.error(n,i,"NOT_SIMULATION","Simulation tab state is only available in the Node simulation context.",s);default:return this.error(n,i,"UNKNOWN_COMMAND",`Unsupported command '${i}'`,s)}}catch(m){return this.error(n,i,"COMMAND_EXECUTION_FAILED",m.message,s,m.details)}}resolveTarget(e,t){if(!e)throw new Error("Target specifier must be provided");return typeof e=="string"?this.interactionEngine.resolveTarget({selector:e},t):typeof e=="number"?this.interactionEngine.resolveTarget({nodeId:e},t):this.interactionEngine.resolveTarget(e,t)}async performDrag(e,t,s,n){const i=n.defaultView,r=[],o=(p,y,v={})=>{try{const m=(i==null?void 0:i.MouseEvent)||(typeof MouseEvent<"u"?MouseEvent:null);m&&(p.dispatchEvent(new m(y,{bubbles:!0,cancelable:!0,...v})),r.push(y))}catch{}},a=e.getBoundingClientRect(),c=a.x+a.width/2,u=a.y+a.height/2;let h=c+((s==null?void 0:s.x)||0),g=u+((s==null?void 0:s.y)||0);if(t){const p=t.getBoundingClientRect();h=p.x+p.width/2,g=p.y+p.height/2}return o(e,"pointerdown",{button:1,clientX:c,clientY:u}),o(e,"mousedown",{button:1,clientX:c,clientY:u}),o(e,"dragstart",{clientX:c,clientY:u}),t&&(o(t,"dragenter",{clientX:h,clientY:g}),o(t,"dragover",{clientX:h,clientY:g}),o(t,"drop",{clientX:h,clientY:g})),o(e,"dragend",{clientX:h,clientY:g}),o(e,"pointerup",{button:1,clientX:h,clientY:g}),o(e,"mouseup",{button:1,clientX:h,clientY:g}),{success:r.length>0,sourceSelector:k.inspectElement(e,this.nodeRegistry).bestSelector,targetSelector:t?k.inspectElement(t,this.nodeRegistry).bestSelector:"(offset drop)",eventsFired:r,finalPosition:{x:Math.round(h),y:Math.round(g)},html5DndUsed:r.includes("dragstart")}}async waitForCondition(e,t,s,n,i){var p,y;const r=t.kind||"dom_stable",o=Math.min(Math.max(Number(t.timeoutMs)||5e3,100),3e4),a=Math.min(Math.max(Number(t.pollIntervalMs)||100,20),1e3),c=Date.now(),u=()=>{var v,m,d,f,w;switch(r){case"dom_stable":return{satisfied:!0,detail:`dom length ${((v=e.documentElement)==null?void 0:v.outerHTML.length)||0}`};case"selector_present":{const E=t.selector?e.querySelectorAll(t.selector).length:0;return{satisfied:E>0,detail:`"${t.selector}" matches ${E} element(s)`}}case"selector_visible":{if(!t.selector)return{satisfied:!1,detail:"no selector supplied"};const E=e.querySelector(t.selector);if(!E)return{satisfied:!1,detail:`"${t.selector}" not present`};try{const S=k.inspectElement(E).visibility.isVisible;return{satisfied:S,detail:`visibility=${S}`}}catch{return{satisfied:!1,detail:"inspection failed"}}}case"selector_absent":{const E=t.selector?e.querySelectorAll(t.selector).length:0;return{satisfied:E===0,detail:`"${t.selector}" matches ${E} element(s)`}}case"text_present":{const E=((m=e.body)==null?void 0:m.innerText)||((d=e.body)==null?void 0:d.textContent)||"",S=t.text?E.includes(String(t.text)):!1;return{satisfied:S,detail:`text "${String(t.text).slice(0,30)}" ${S?"found":"not found"}`}}case"url_contains":{const E=((w=(f=e.defaultView)==null?void 0:f.location)==null?void 0:w.href)||"";return{satisfied:t.text?E.includes(String(t.text)):!1,detail:E}}case"element_count":{const E=t.selector?e.querySelectorAll(t.selector).length:0,S=Number(t.count)||0;return{satisfied:E===S,detail:`${E}/${S} elements`}}case"readiness_state":return{satisfied:e.readyState===(t.state||"complete"),detail:`readyState=${e.readyState}`};default:return{satisfied:!1,detail:`unknown condition kind "${r}"`}}};if(r==="dom_stable"){let v=((p=e.documentElement)==null?void 0:p.outerHTML.length)||0,m=!1,d=0;for(;Date.now()-csetTimeout(E,a));const w=((y=e.documentElement)==null?void 0:y.outerHTML.length)||0;if(d++,w===v){m=!0;break}v=w}const f=Date.now()-c;return m&&this.session.timeline.record("WAIT_SATISFIED",`dom_stable after ${f}ms (${d} polls)`),this.success(n,i,{satisfied:m,condition:r,waitedMs:f,timeoutMs:o,detail:`dom length ${v}, ${d} polls`},s)}let h=u();for(;!h.satisfied&&Date.now()-csetTimeout(v,a)),h=u();const g=Date.now()-c;return h.satisfied&&this.session.timeline.record("WAIT_SATISFIED",`${r} after ${g}ms`),this.success(n,i,{satisfied:h.satisfied,condition:r,waitedMs:g,timeoutMs:o,detail:h.detail},s)}simulationCloseTab(e,t,s,n,i){const r=Number(e==null?void 0:e.tabId),o=Number.isFinite(r)?this.simulationTabs.findIndex(c=>c.browserTabId===r):this.simulationTabs.findIndex(c=>c.active);if(o<0)return this.error(s,n,"TAB_NOT_FOUND",`No simulated tab matches tabId=${r}`,i);const a=this.simulationTabs.splice(o,1)[0];return this.session.closeTab(a.sessionTabId),a.active&&this.simulationTabs.length&&(this.simulationTabs[0].active=!0,this.session.switchTab(this.simulationTabs[0].sessionTabId)),this.success(s,n,{closed:!0,closedTab:{id:a.browserTabId,url:a.url,title:a.title},simulated:!0,remaining:this.simulationTabs.length},i)}handleSimulationBackgroundCommand(e,t,s,n,i){const r=()=>{var o,a;if(!this.simulationTabs.length){this.simulationTabCounter++;const c={sessionTabId:`stab_${this.simulationTabCounter}`,browserTabId:this.simulationTabCounter,url:((a=(o=n.defaultView)==null?void 0:o.location)==null?void 0:a.href)||"about:blank",title:n.title||"Simulated Tab",active:!0,createdAt:Date.now()};this.simulationTabs.push(c),this.session.registerTab(c.browserTabId,c.url,c.title),this.session.switchTab(c.sessionTabId)}};switch(t){case"LIST_TABS":return r(),this.success(e,t,{simulated:!0,environment:"node-simulation",tabs:this.simulationTabs.map((o,a)=>({id:o.browserTabId,index:a,windowId:1,title:o.title,url:o.url,active:o.active,status:"complete",pinned:!1,audited:!1})),note:"Deterministic simulated tab state — a real browser tab list requires the Chrome extension connection."},i);case"OPEN_TAB":{const o=String((s==null?void 0:s.url)||"about:blank");this.simulationTabCounter++;const a={sessionTabId:`stab_${this.simulationTabCounter}`,browserTabId:this.simulationTabCounter,url:o,title:(s==null?void 0:s.title)||`Simulated Tab ${this.simulationTabCounter}`,active:!0,createdAt:Date.now()};this.simulationTabs.forEach(u=>u.active=!1),this.simulationTabs.push(a);const c=this.session.registerTab(a.browserTabId,o,a.title);return this.session.switchTab(c.sessionTabId),this.session.timeline.record("TAB_OPENED",`simulation tab ${a.browserTabId} → ${o}`),this.success(e,t,{opened:!0,tabId:a.browserTabId,url:o,simulated:!0,totalTabs:this.simulationTabs.length},i)}case"FOCUS_TAB":{r();const o=Number(s==null?void 0:s.tabId),a=this.simulationTabs.find(c=>c.browserTabId===o)||this.simulationTabs[0];return a?(this.simulationTabs.forEach(c=>c.active=!1),a.active=!0,this.session.switchTab(a.sessionTabId),this.session.timeline.record("TAB_SWITCHED",`simulation tab ${a.browserTabId} focused`),this.success(e,t,{focused:!0,tabId:a.browserTabId,url:a.url,simulated:!0},i)):this.error(e,t,"TAB_NOT_FOUND",`No simulated tab with tabId=${o}`,i)}case"LIST_EXTENSIONS":return this.success(e,t,{simulated:!0,extensions:this.simulationExtensions.map(o=>({...o,permissions:["activeTab","scripting","storage","tabs","management"]})),note:"Deterministic simulated extension state."},i);case"SET_EXTENSION_ENABLED":{const o=String((s==null?void 0:s.extensionId)||""),a=this.simulationExtensions.find(c=>c.id===o||c.name.toLowerCase().includes(o.toLowerCase()));return a?(a.enabled=!!(s!=null&&s.enabled),this.session.timeline.record("EXTENSION_STATE_CHANGED",`${a.id} → ${a.enabled?"enabled":"disabled"}`),this.success(e,t,{extensionId:a.id,enabled:a.enabled,simulated:!0},i)):this.error(e,t,"EXTENSION_NOT_FOUND",`No simulated extension matches "${o}". Known: ${this.simulationExtensions.map(c=>c.id).join(", ")}`,i)}case"TOGGLE_EXTENSION":{const o=String((s==null?void 0:s.extensionId)||""),a=this.simulationExtensions.find(c=>c.id===o||c.name.toLowerCase().includes(o.toLowerCase()));return a?(a.enabled=!a.enabled,this.session.timeline.record("EXTENSION_STATE_CHANGED",`${a.id} → ${a.enabled?"enabled":"disabled"}`),this.success(e,t,{extensionId:a.id,enabled:a.enabled,simulated:!0},i)):this.error(e,t,"EXTENSION_NOT_FOUND",`No simulated extension matches "${o}".`,i)}case"RELOAD_EXTENSION":{const o=String((s==null?void 0:s.extensionId)||this.simulationExtensions[0].id),a=this.simulationExtensions.find(c=>c.id===o||c.name.toLowerCase().includes(o.toLowerCase()));return a?this.success(e,t,{reloaded:!0,extensionId:a.id,simulated:!0,note:"Simulated reload: extension state preserved."},i):this.error(e,t,"EXTENSION_NOT_FOUND",`No simulated extension matches "${o}".`,i)}default:return this.error(e,t,"UNKNOWN_COMMAND",`Unhandled simulation command '${t}'`,i)}}async handleScreenshotCapture(e,t,s){var y,v,m,d,f;const n=s.defaultView||(typeof window<"u"?window:{}),i=Date.now(),r=`scr_${i}_${Math.random().toString(36).slice(2,6)}`,o=n.devicePixelRatio||1,a={width:n.innerWidth||((y=s.documentElement)==null?void 0:y.clientWidth)||1920,height:n.innerHeight||((v=s.documentElement)==null?void 0:v.clientHeight)||1080,scrollX:n.scrollX||n.pageXOffset||0,scrollY:n.scrollY||n.pageYOffset||0,devicePixelRatio:o};let c,u,h,g={width:a.width,height:a.height};if(e==="LIVE_ELEMENT_SCREENSHOT"){const w=this.resolveTarget(t,s),E=k.inspectElement(w,this.nodeRegistry);c=E.bestSelector,u=((m=E.forensics)==null?void 0:m.logicalNodeId)||void 0,h={x:E.bounds.x,y:E.bounds.y,width:E.bounds.width,height:E.bounds.height},g={width:Math.max(1,Math.round(E.bounds.width*o)),height:Math.max(1,Math.round(E.bounds.height*o))}}let p=(t==null?void 0:t.dataUrl)||"";if(e==="LIVE_ELEMENT_SCREENSHOT"&&p&&h&&typeof Image<"u")try{const w=await new Promise(E=>{const S=new Image;S.onload=()=>{try{const T=s.createElement("canvas"),x=Math.max(0,Math.floor(h.x*o)),N=Math.max(0,Math.floor(h.y*o)),D=Math.max(1,Math.floor(h.width*o)),M=Math.max(1,Math.floor(h.height*o));T.width=D,T.height=M;const L=T.getContext("2d");if(L){L.drawImage(S,x,N,D,M,0,0,D,M),E(T.toDataURL("image/png"));return}}catch{}E(p)},S.onerror=()=>E(p),S.src=p});w&&(p=w)}catch{}if(!p){const w=e==="LIVE_ELEMENT_SCREENSHOT"?Math.max(120,g.width||320):Math.max(800,a.width||1280),E=e==="LIVE_ELEMENT_SCREENSHOT"?Math.max(60,g.height||180):Math.max(600,a.height||800);p=ge.createDataUrl({width:w,height:E,backgroundColor:e==="LIVE_ELEMENT_SCREENSHOT"?[30,41,59,255]:[15,23,42,255],headerColor:[56,189,248,255],borderColor:[99,102,241,255],label:c||(e==="LIVE_ELEMENT_SCREENSHOT"?"Element Screenshot":"Page Screenshot")})}return{screenshotId:r,timestamp:i,url:((d=n.location)==null?void 0:d.href)||((f=s.location)==null?void 0:f.href)||"",viewport:a,targetSelector:c,targetNodeId:u,targetBounds:h,dataUrl:p,imageFormat:"png",dimensions:g,captureType:e==="LIVE_ELEMENT_SCREENSHOT"?"ELEMENT":"FULL_PAGE"}}success(e,t,s,n){return{id:e,command:t,success:!0,data:s,timestamp:Date.now(),durationMs:Date.now()-n}}error(e,t,s,n,i,r){return{id:e,command:t,success:!1,error:{code:s,message:n,details:r},timestamp:Date.now(),durationMs:Date.now()-i}}}function Lt(l,e){const t=[];let s=l.parentElement,n=1;for(;s&&n<=10;){const h=s.parentElement,g=h?Array.from(h.children).filter(p=>p.tagName===s.tagName):[];t.push({tag:s.tagName.toLowerCase(),selector:U(s),role:s.getAttribute("role")||void 0,text:B(s).slice(0,40),childIndex:g.length?g.indexOf(s)+1:1,siblingCount:h?Array.from(h.children).length:0,distance:n}),s=s.parentElement,n++}const i=l.parentElement,r=[];if(i){const h=Array.from(i.children),g=h.indexOf(l);for(let p=g-1;p>=0&&p>=g-5;p--)r.push({tag:h[p].tagName.toLowerCase(),selector:U(h[p]),role:h[p].getAttribute("role")||void 0,text:B(h[p]).slice(0,30),position:"before",distance:g-p});for(let p=g+1;p{o=Math.max(o,g);for(const p of Array.from(h.children))a.push(p.tagName.toLowerCase()),p.matches('a[href], button, input, select, textarea, [role="button"], [onclick]')&&c.push(U(p)),g<6&&u(p,g+1)};return u(l,1),{selector:U(l),ancestors:t,siblings:r,descendants:{count:l.querySelectorAll("*").length,maxDepth:o,tags:Array.from(new Set(a)).slice(0,30),interactive:c.slice(0,30)}}}function Dt(l,e){const t=[{id:"self",selector:U(l),tag:l.tagName.toLowerCase(),role:l.getAttribute("role")||void 0,label:B(l).slice(0,30)||l.tagName.toLowerCase(),relationship:"self",depth:0}],s=[];let n=l.parentElement,i=1;for(;n&&i<=4;){const o=`ancestor_${i}`;t.push({id:o,selector:U(n),tag:n.tagName.toLowerCase(),role:n.getAttribute("role")||void 0,label:B(n).slice(0,30)||n.tagName.toLowerCase(),relationship:"parent",depth:i}),s.push({from:o,to:i===1?"self":`ancestor_${i-1}`,relation:"parent-of"}),n=n.parentElement,i++}for(const o of Array.from(l.children).slice(0,12)){const a=`child_${t.length}`;t.push({id:a,selector:U(o),tag:o.tagName.toLowerCase(),role:o.getAttribute("role")||void 0,label:B(o).slice(0,30)||o.tagName.toLowerCase(),relationship:"child",depth:1}),s.push({from:"self",to:a,relation:"contains"})}const r=l.parentElement;if(r)for(const o of Array.from(r.children).slice(0,12)){if(o===l)continue;const a=`sibling_${t.length}`;t.push({id:a,selector:U(o),tag:o.tagName.toLowerCase(),role:o.getAttribute("role")||void 0,label:B(o).slice(0,30)||o.tagName.toLowerCase(),relationship:"sibling",depth:1}),s.push({from:"self",to:a,relation:"sibling-of"})}return{rootSelector:U(l),nodes:t,edges:s}}function $t(l){const e={};for(const v of Array.from(l.attributes))v.name.startsWith("aria-")&&(e[v.name]=v.value);const t=B(l).trim(),s=l.getAttribute("aria-label"),n=l.getAttribute("aria-labelledby");let i;n&&(i=n.split(/\s+/).map(m=>{var d,f,w;return(w=(f=(d=l.ownerDocument)==null?void 0:d.getElementById(m))==null?void 0:f.textContent)==null?void 0:w.trim()}).filter(Boolean).join(" ").slice(0,60)||void 0);const r=l.getAttribute("title"),o=l.tagName.toLowerCase(),a=[];let c="";s?(c=s,a.push("aria-label")):i?(c=i,a.push("aria-labelledby")):t?(c=t.slice(0,60),a.push("text content")):r&&(c=r,a.push("title"));const u=[];(l.disabled||l.hasAttribute("disabled"))&&u.push("disabled"),l.checked&&u.push("checked");const h=l;h.tagName==="SELECT"&&typeof h.selectedOptions<"u"&&h.selectedOptions.length>0&&u.push("selected"),l.getAttribute("aria-expanded")&&u.push(`expanded=${l.getAttribute("aria-expanded")}`),l.getAttribute("aria-pressed")&&u.push(`pressed=${l.getAttribute("aria-pressed")}`),l.getAttribute("aria-hidden")==="true"&&u.push("hidden"),l.hasAttribute("required")&&u.push("required"),l.readOnly&&u.push("readonly");const g=["a[href]","button","input","select","textarea","[tabindex]"].some(v=>{try{return l.matches(v)}catch{return!1}}),p=[];!c&&g&&p.push("Focusable element has no accessible name."),o==="img"&&!l.hasAttribute("alt")&&p.push("Image has no alt attribute.");const y=/^h([1-6])$/.exec(o);return y&&!t&&p.push(`Heading h${y[1]} is empty.`),{selector:U(l),role:l.getAttribute("role")||void 0,implicitRole:qt(l),name:c,nameSources:a,description:l.getAttribute("aria-describedby")||void 0,value:l.value!==void 0&&(l.getAttribute("type")||"text")!=="password"?String(l.value).slice(0,40):void 0,states:u,level:y?parseInt(y[1],10):void 0,focusable:g,tabIndex:l.tabIndex,ariaAttributes:e,issues:p}}function qt(l){switch(l.tagName.toLowerCase()){case"a":return l.getAttribute("href")?"link":void 0;case"button":return"button";case"nav":return"navigation";case"header":return"banner";case"footer":return"contentinfo";case"main":return"main";case"aside":return"complementary";case"article":return"article";case"form":return"form";case"input":{const t=l.getAttribute("type")||"text";return{checkbox:"checkbox",radio:"radio",button:"button",submit:"button",reset:"button",range:"slider",search:"searchbox",email:"textbox",text:"textbox",password:"textbox",tel:"textbox",url:"textbox",number:"spinbutton"}[t]||"textbox"}case"select":return l.hasAttribute("multiple")?"listbox":"combobox";case"textarea":return"textbox";case"img":return"img";case"table":return"table";case"ul":case"ol":return"list";case"li":return"listitem";case"h1":case"h2":case"h3":case"h4":case"h5":case"h6":return"heading";case"dialog":return"dialog";default:return}}function U(l){const e=l.getAttribute("id");if(e&&/^[a-zA-Z][\w-]*$/.test(e))return`#${e}`;const t=l.getAttribute("data-testid");if(t)return`${l.tagName.toLowerCase()}[data-testid="${t}"]`;const s=l.tagName.toLowerCase(),n=Array.from(l.classList||[]).slice(0,2);return n.length?`${s}.${n.join(".")}`:s}function B(l){return Array.from(l.childNodes).filter(e=>e.nodeType===3).map(e=>(e.textContent||"").trim()).join(" ").replace(/\s+/g," ")}function Pt(){return[{label:"desktop-1440x900",width:1440,height:900},{label:"laptop-1024x768",width:1024,height:768},{label:"tablet-768x1024",width:768,height:1024},{label:"mobile-375x667",width:375,height:667}]}class Ut{constructor(e){b(this,"hostElement",null);b(this,"shadowRoot",null);b(this,"callbacks");b(this,"isRecording",!1);b(this,"isPaused",!1);b(this,"isMinimized",!1);b(this,"startTime",0);b(this,"eventCount",0);b(this,"timerInterval",null);b(this,"isDragging",!1);b(this,"dragStartX",0);b(this,"dragStartY",0);b(this,"posX",window.innerWidth-340);b(this,"posY",40);this.callbacks=e,this.loadPosition()}mount(){this.hostElement&&document.body.contains(this.hostElement)||(this.hostElement=document.createElement("div"),this.hostElement.id="forensic-recorder-floating-host",this.hostElement.style.all="initial",this.hostElement.style.position="fixed",this.hostElement.style.zIndex="2147483647",this.hostElement.style.left=`${this.posX}px`,this.hostElement.style.top=`${this.posY}px`,this.shadowRoot=this.hostElement.attachShadow({mode:"open"}),this.render(),this.attachEvents(),(document.body||document.documentElement).appendChild(this.hostElement))}unmount(){this.timerInterval&&(clearInterval(this.timerInterval),this.timerInterval=null),this.hostElement&&this.hostElement.parentNode&&this.hostElement.parentNode.removeChild(this.hostElement),this.hostElement=null,this.shadowRoot=null}hide(){this.hostElement&&(this.hostElement.style.setProperty("display","none","important"),this.hostElement.style.setProperty("visibility","hidden","important"),this.hostElement.style.setProperty("opacity","0","important"))}show(){this.hostElement&&(this.hostElement.style.removeProperty("display"),this.hostElement.style.removeProperty("visibility"),this.hostElement.style.removeProperty("opacity"))}updateState(e,t=!1,s=0,n=0){this.isRecording=e,this.isPaused=t,this.startTime=s||(e?Date.now():0),this.eventCount=n,this.shadowRoot&&(this.render(),this.attachEvents()),this.isRecording&&!this.isPaused?this.startTimer():this.stopTimer()}incrementEventCount(){var t;this.eventCount++;const e=(t=this.shadowRoot)==null?void 0:t.querySelector("#evt-badge");e&&(e.textContent=`${this.eventCount} evts`)}startTimer(){this.stopTimer(),this.timerInterval=setInterval(()=>{var t;const e=(t=this.shadowRoot)==null?void 0:t.querySelector("#timer-display");if(e&&this.startTime){const s=(Date.now()-this.startTime)/1e3,n=Math.floor(s/60).toString().padStart(2,"0"),i=(s%60).toFixed(1).padStart(4,"0");e.textContent=`${n}:${i}`}},200)}stopTimer(){this.timerInterval&&(clearInterval(this.timerInterval),this.timerInterval=null)}savePosition(){try{sessionStorage.setItem("forensic_overlay_pos",JSON.stringify({x:this.posX,y:this.posY,min:this.isMinimized}))}catch{}}loadPosition(){try{const e=sessionStorage.getItem("forensic_overlay_pos");if(e){const t=JSON.parse(e);this.posX=Math.max(10,Math.min(window.innerWidth-300,t.x||this.posX)),this.posY=Math.max(10,Math.min(window.innerHeight-150,t.y||this.posY)),this.isMinimized=!!t.min}}catch{}}render(){if(!this.shadowRoot)return;const e=` :host { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; font-size: 12px; @@ -288,4 +288,4 @@ ${t}
- `}attachEvents(){if(!this.shadowRoot)return;const e=this.shadowRoot.querySelector("#drag-header");e&&e.addEventListener("mousedown",c=>{this.isDragging=!0,this.dragStartX=c.clientX-this.posX,this.dragStartY=c.clientY-this.posY;const u=h=>{!this.isDragging||!this.hostElement||(this.posX=Math.max(10,Math.min(window.innerWidth-80,h.clientX-this.dragStartX)),this.posY=Math.max(10,Math.min(window.innerHeight-50,h.clientY-this.dragStartY)),this.hostElement.style.left=`${this.posX}px`,this.hostElement.style.top=`${this.posY}px`)},d=()=>{this.isDragging=!1,window.removeEventListener("mousemove",u),window.removeEventListener("mouseup",d),this.savePosition()};window.addEventListener("mousemove",u),window.addEventListener("mouseup",d)});const t=this.shadowRoot.querySelector("#btn-toggle-min");t==null||t.addEventListener("click",()=>{this.isMinimized=!this.isMinimized,this.savePosition(),this.render(),this.attachEvents()});const s=this.shadowRoot.querySelector("#btn-close");s==null||s.addEventListener("click",()=>{this.unmount()});const n=this.shadowRoot.querySelector("#btn-record");n==null||n.addEventListener("click",()=>{this.isRecording?this.callbacks.onStopRecord():this.callbacks.onStartRecord()});const i=this.shadowRoot.querySelector("#btn-checkpoint");i==null||i.addEventListener("click",()=>{if(this.callbacks.onCaptureCheckpoint(),i){const c=i.textContent;i.textContent="✔ Saved!",setTimeout(()=>i.textContent=c,1e3)}});const r=this.shadowRoot.querySelector("#btn-inspect");r==null||r.addEventListener("click",()=>{this.callbacks.onInspectElement()});const o=this.shadowRoot.querySelector("#btn-annotate");o==null||o.addEventListener("click",()=>{const c=prompt("Enter observation, bug note, or hypothesis at this exact moment:");c&&c.trim()&&this.callbacks.onAddAnnotation(c.trim())});const a=this.shadowRoot.querySelector("#btn-dashboard");a==null||a.addEventListener("click",()=>{this.callbacks.onOpenDashboard()})}}(function(){var w;let l=null;const e=new Lt;let t=[],s=null,n=null,i=!1;const r=500,o=[],a=[];window.addEventListener("message",E=>{var C;if(((C=E.data)==null?void 0:C._forensicOrigin)==="PAGE_MAIN"){const{type:N,payload:I}=E.data;if(N==="CONSOLE_ENTRY")o.push(I),o.length>r&&o.shift();else if(N==="NETWORK_ENTRY"){const R=a.findIndex(x=>x.requestId===I.requestId);R>=0?a[R]={...a[R],...I}:(a.push(I),a.length>r&&a.shift())}}});function c(){var E;try{if(typeof chrome<"u"&&((E=chrome.runtime)!=null&&E.getURL)){const C=document.createElement("script");C.src=chrome.runtime.getURL("dist/extension/page-script.js"),C.onload=()=>C.remove(),(document.head||document.documentElement).appendChild(C)}}catch{}}function u(){var C;if(t.length===0||!l)return;const E=[...t];t=[];try{typeof chrome<"u"&&((C=chrome.runtime)!=null&&C.sendMessage)&&chrome.runtime.sendMessage({type:"FORENSIC_EVENTS_CHUNK",sessionId:l.getSessionId(),events:E})}catch{}}function d(E,C,N){var R;if(l)return l.getMetadata();l=new Le({sessionId:C,sessionName:E||`Recording on ${document.title||window.location.hostname}`}),l.onEvent(x=>{t.push(x),n&&n.incrementEventCount(),t.length>=25&&u()}),l.onCheckpoint(x=>{var q;try{typeof chrome<"u"&&((q=chrome.runtime)!=null&&q.sendMessage)&&chrome.runtime.sendMessage({type:"FORENSIC_CHECKPOINT",sessionId:x.sessionId,checkpoint:x})}catch{}});const I=l.start(document);try{typeof chrome<"u"&&((R=chrome.runtime)!=null&&R.sendMessage)&&chrome.runtime.sendMessage({type:"FORENSIC_SESSION_START",metadata:l.getMetadata(),initialSnapshot:I})}catch{}return s||(s=setInterval(u,1e3)),n&&n.updateState(!0,!1,N||Date.now(),0),l.getMetadata()}function h(){var N;if(!l)return null;u(),s&&(clearInterval(s),s=null);const E=l.stop();try{typeof chrome<"u"&&((N=chrome.runtime)!=null&&N.sendMessage)&&chrome.runtime.sendMessage({type:"FORENSIC_SESSION_STOP",sessionId:E.id,metadata:E})}catch{}const C={...E};return l=null,n&&n.updateState(!1,!1,0,0),C}function p(){if(i){i=!1,document.body.style.cursor="default";return}i=!0,document.body.style.cursor="crosshair";const E=document.createElement("div");E.id="forensic-inspect-highlighter",E.style.position="fixed",E.style.pointerEvents="none",E.style.zIndex="2147483640",E.style.border="2px dashed #38bdf8",E.style.background="rgba(56, 189, 248, 0.15)",E.style.transition="all 0.05s ease",document.body.appendChild(E);const C=I=>{if(!i)return;const R=I.target;if(!R||R.id==="forensic-recorder-floating-host"||R.closest("#forensic-recorder-floating-host")){E.style.display="none";return}const x=R.getBoundingClientRect();E.style.display="block",E.style.left=`${x.left}px`,E.style.top=`${x.top}px`,E.style.width=`${x.width}px`,E.style.height=`${x.height}px`},N=I=>{if(!i)return;const R=I.target;if(!R.closest("#forensic-recorder-floating-host")&&(I.preventDefault(),I.stopPropagation(),i=!1,document.body.style.cursor="default",E.remove(),window.removeEventListener("mousemove",C,!0),window.removeEventListener("click",N,!0),l)){const x=R.id?`#${R.id}`:R.className?`.${R.className.split(" ")[0]}`:R.tagName.toLowerCase();l.addAnnotation("Inspect Element",`Inspected element <${R.tagName.toLowerCase()}> with selector '${x}'`,"USER"),alert(`🎯 Inspected element <${R.tagName.toLowerCase()}> recorded! Checkpoint saved.`)}};window.addEventListener("mousemove",C,!0),window.addEventListener("click",N,!0)}function y(){return n||(n=new Ht({onStartRecord:()=>{d()},onStopRecord:()=>{h()},onTogglePause:()=>{l&&(l.getMetadata().status==="recording"?l.pause():l.resume())},onCaptureCheckpoint:()=>{l&&l.captureCheckpoint("MANUAL",document)},onAddAnnotation:E=>{l&&l.addAnnotation("User Note",E,"USER")},onInspectElement:()=>{p()},onOpenDashboard:()=>{const E=l?l.getSessionId():void 0;chrome.runtime.sendMessage({type:"OPEN_DASHBOARD_TAB",sessionId:E})}})),n}function v(){var E;try{typeof chrome<"u"&&((E=chrome.runtime)!=null&&E.sendMessage)&&chrome.runtime.sendMessage({type:"GET_TAB_RECORDING_STATE"},C=>{chrome.runtime.lastError||!C||C.isRecording&&C.recording&&(y().mount(),d(C.recording.sessionName,C.recording.sessionId,C.recording.startTime))})}catch{}}typeof chrome<"u"&&((w=chrome.runtime)!=null&&w.onMessage)&&chrome.runtime.onMessage.addListener((E,C,N)=>{if(E.type==="HIDE_FORENSIC_OVERLAYS")return n&&n.hide(),document.querySelectorAll('#forensic-recorder-floating-host, #forensic-inspect-highlighter, [id^="forensic-"]').forEach(R=>{const x=R;x.style.setProperty("display","none","important"),x.style.setProperty("visibility","hidden","important"),x.style.setProperty("opacity","0","important")}),N({success:!0}),!0;if(E.type==="RESTORE_FORENSIC_OVERLAYS")return n&&n.show(),document.querySelectorAll('#forensic-recorder-floating-host, #forensic-inspect-highlighter, [id^="forensic-"]').forEach(R=>{const x=R;x.style.removeProperty("display"),x.style.removeProperty("visibility"),x.style.removeProperty("opacity")}),N({success:!0}),!0;if(E.type==="BROWSER_COMMAND_REQUEST"){if(["LIST_TABS","FOCUS_TAB","RELOAD_TAB","LIST_EXTENSIONS","RELOAD_EXTENSION","CLOSE_TAB","OPEN_TAB","RESIZE_VIEWPORT","RESET_VIEWPORT"].includes(E.command))return!1;if(E.command==="GET_TAB_CONSOLE_LOGS"){const{level:I,searchQuery:R,limit:x=100,clearAfterRead:q}=E.payload||{};let A=[...o];if(I&&I!=="all"&&(A=A.filter(S=>S.level===I)),R){const S=String(R).toLowerCase();A=A.filter(M=>{var O,_;return((O=M.text)==null?void 0:O.toLowerCase().includes(S))||((_=M.source)==null?void 0:_.toLowerCase().includes(S))})}return x>0&&(A=A.slice(-x)),q&&(o.length=0),N({id:E.id,command:E.command,success:!0,data:{url:window.location.href,title:document.title,totalCaptured:o.length,returnedCount:A.length,logs:A}}),!0}if(E.command==="GET_TAB_NETWORK_REQUESTS"){const{method:I,searchQuery:R,status:x,onlyErrors:q,limit:A=100,clearAfterRead:S}=E.payload||{};let M=[...a];if(I&&(M=M.filter(O=>{var _;return((_=O.method)==null?void 0:_.toUpperCase())===String(I).toUpperCase()})),x&&(M=M.filter(O=>O.status===Number(x))),q&&(M=M.filter(O=>O.error||O.status&&O.status>=400)),R){const O=String(R).toLowerCase();M=M.filter(_=>{var P;return(P=_.url)==null?void 0:P.toLowerCase().includes(O)})}return A>0&&(M=M.slice(-A)),S&&(a.length=0),N({id:E.id,command:E.command,success:!0,data:{url:window.location.href,title:document.title,totalCaptured:a.length,returnedCount:M.length,requests:M}}),!0}return e.handleCommand(E,document).then(I=>{N(I)}),!0}else if(E.type==="START_RECORDING"){const I=d(E.sessionName);y().mount(),N({success:!0,metadata:I})}else if(E.type==="STOP_RECORDING"){const I=h();N({success:!0,metadata:I})}else if(E.type==="TOGGLE_FLOATING_OVERLAY"){const I=y();document.getElementById("forensic-recorder-floating-host")?(I.unmount(),N({isOpen:!1})):(I.mount(),I.updateState((l==null?void 0:l.getMetadata().status)==="recording",!1,(l==null?void 0:l.getMetadata().startTime)||0,0),N({isOpen:!0}))}else if(E.type==="GET_RECORDER_STATUS")N({isRecording:(l==null?void 0:l.getMetadata().status)==="recording",metadata:(l==null?void 0:l.getMetadata())||null});else if(E.type==="CAPTURE_CHECKPOINT")if(l){const I=l.captureCheckpoint("MANUAL",document);N({success:!0,checkpoint:I})}else N({success:!1,error:"Not currently recording"});return!0});let m=null,g=null;function b(){if(!(typeof WebSocket>"u"))try{const E=new WebSocket("ws://127.0.0.1:3847");E.onopen=()=>{m=E,console.log("[Forensic ContentScript] Connected directly to MCP Bridge on ws://127.0.0.1:3847"),g&&(clearInterval(g),g=null),E.send(JSON.stringify({type:"REGISTER_CLIENT",clientType:"CONTENT_SCRIPT",url:window.location.href,title:document.title}))},E.onclose=()=>{m=null,T()},E.onerror=()=>{m=null,T()},E.onmessage=async C=>{var N;try{const I=JSON.parse(C.data.toString());if(I.type==="BROWSER_COMMAND_REQUEST"){const{id:R,command:x,payload:q}=I;if(["LIST_TABS","OPEN_TAB","LIST_EXTENSIONS","RELOAD_EXTENSION","CLOSE_TAB","FOCUS_TAB","RELOAD_TAB","RESIZE_VIEWPORT","RESET_VIEWPORT"].includes(x)){if(typeof chrome<"u"&&((N=chrome.runtime)!=null&&N.sendMessage)){chrome.runtime.sendMessage(I,S=>{if(chrome.runtime.lastError){if(x==="CLOSE_TAB"){E.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:R,command:x,success:!0,data:{closed:!0,url:window.location.href,title:document.title}})),setTimeout(()=>window.close(),100);return}if(x==="RELOAD_TAB"){E.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:R,command:x,success:!0,data:{reloaded:!0,url:window.location.href,title:document.title}})),setTimeout(()=>window.location.reload(),100);return}E.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:R,command:x,success:!1,error:{code:"FORWARD_ERROR",message:chrome.runtime.lastError.message}}))}else E.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",...S||{id:R,command:x,success:!0}}))});return}if(x==="CLOSE_TAB"){E.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:R,command:x,success:!0,data:{closed:!0,url:window.location.href,title:document.title}})),setTimeout(()=>window.close(),100);return}if(x==="RELOAD_TAB"){E.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:R,command:x,success:!0,data:{reloaded:!0,url:window.location.href,title:document.title}})),setTimeout(()=>window.location.reload(),100);return}}if(x==="GET_TAB_CONSOLE_LOGS"){const{level:S,searchQuery:M,limit:O=100,clearAfterRead:_}=q||{};let P=[...o];if(S&&S!=="all"&&(P=P.filter(H=>H.level===S)),M){const H=String(M).toLowerCase();P=P.filter($=>{var F,W;return((F=$.text)==null?void 0:F.toLowerCase().includes(H))||((W=$.source)==null?void 0:W.toLowerCase().includes(H))})}O>0&&(P=P.slice(-O)),_&&(o.length=0),E.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:R,command:x,success:!0,data:{url:window.location.href,title:document.title,totalCaptured:o.length,returnedCount:P.length,logs:P}}));return}if(x==="GET_TAB_NETWORK_REQUESTS"){const{method:S,searchQuery:M,status:O,onlyErrors:_,limit:P=100,clearAfterRead:H}=q||{};let $=[...a];if(S&&($=$.filter(F=>{var W;return((W=F.method)==null?void 0:W.toUpperCase())===String(S).toUpperCase()})),O&&($=$.filter(F=>F.status===Number(O))),_&&($=$.filter(F=>F.error||F.status&&F.status>=400)),M){const F=String(M).toLowerCase();$=$.filter(W=>{var te;return(te=W.url)==null?void 0:te.toLowerCase().includes(F)})}P>0&&($=$.slice(-P)),H&&(a.length=0),E.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:R,command:x,success:!0,data:{url:window.location.href,title:document.title,totalCaptured:a.length,returnedCount:$.length,requests:$}}));return}const A=await e.handleCommand(I,document);E.send(JSON.stringify(A))}}catch(I){console.error("[Forensic ContentScript] Bridge message error:",I)}}}catch{m=null,T()}}function T(){g||(g=setInterval(()=>{(!m||m.readyState!==WebSocket.OPEN)&&b()},4e3))}c(),b(),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",v):v()})()})(); + `}attachEvents(){if(!this.shadowRoot)return;const e=this.shadowRoot.querySelector("#drag-header");e&&e.addEventListener("mousedown",c=>{this.isDragging=!0,this.dragStartX=c.clientX-this.posX,this.dragStartY=c.clientY-this.posY;const u=g=>{!this.isDragging||!this.hostElement||(this.posX=Math.max(10,Math.min(window.innerWidth-80,g.clientX-this.dragStartX)),this.posY=Math.max(10,Math.min(window.innerHeight-50,g.clientY-this.dragStartY)),this.hostElement.style.left=`${this.posX}px`,this.hostElement.style.top=`${this.posY}px`)},h=()=>{this.isDragging=!1,window.removeEventListener("mousemove",u),window.removeEventListener("mouseup",h),this.savePosition()};window.addEventListener("mousemove",u),window.addEventListener("mouseup",h)});const t=this.shadowRoot.querySelector("#btn-toggle-min");t==null||t.addEventListener("click",()=>{this.isMinimized=!this.isMinimized,this.savePosition(),this.render(),this.attachEvents()});const s=this.shadowRoot.querySelector("#btn-close");s==null||s.addEventListener("click",()=>{this.unmount()});const n=this.shadowRoot.querySelector("#btn-record");n==null||n.addEventListener("click",()=>{this.isRecording?this.callbacks.onStopRecord():this.callbacks.onStartRecord()});const i=this.shadowRoot.querySelector("#btn-checkpoint");i==null||i.addEventListener("click",()=>{if(this.callbacks.onCaptureCheckpoint(),i){const c=i.textContent;i.textContent="✔ Saved!",setTimeout(()=>i.textContent=c,1e3)}});const r=this.shadowRoot.querySelector("#btn-inspect");r==null||r.addEventListener("click",()=>{this.callbacks.onInspectElement()});const o=this.shadowRoot.querySelector("#btn-annotate");o==null||o.addEventListener("click",()=>{const c=prompt("Enter observation, bug note, or hypothesis at this exact moment:");c&&c.trim()&&this.callbacks.onAddAnnotation(c.trim())});const a=this.shadowRoot.querySelector("#btn-dashboard");a==null||a.addEventListener("click",()=>{this.callbacks.onOpenDashboard()})}}(function(){var m;let l=null;const e=new Ot;let t=[],s=null,n=null,i=!1;const r=500,o=[],a=[];window.addEventListener("message",d=>{var f;if(((f=d.data)==null?void 0:f._forensicOrigin)==="PAGE_MAIN"){const{type:w,payload:E}=d.data;if(w==="CONSOLE_ENTRY")o.push(E),o.length>r&&o.shift();else if(w==="NETWORK_ENTRY"){const S=a.findIndex(T=>T.requestId===E.requestId);S>=0?a[S]={...a[S],...E}:(a.push(E),a.length>r&&a.shift())}}});function c(){var d;try{if(typeof chrome<"u"&&((d=chrome.runtime)!=null&&d.getURL)){const f=document.createElement("script");f.src=chrome.runtime.getURL("dist/extension/page-script.js"),f.onload=()=>f.remove(),(document.head||document.documentElement).appendChild(f)}}catch{}}function u(){var f;if(t.length===0||!l)return;const d=[...t];t=[];try{typeof chrome<"u"&&((f=chrome.runtime)!=null&&f.sendMessage)&&chrome.runtime.sendMessage({type:"FORENSIC_EVENTS_CHUNK",sessionId:l.getSessionId(),events:d})}catch{}}function h(d,f,w){var S;if(l)return l.getMetadata();l=new Oe({sessionId:f,sessionName:d||`Recording on ${document.title||window.location.hostname}`}),l.onEvent(T=>{t.push(T),n&&n.incrementEventCount(),t.length>=25&&u()}),l.onCheckpoint(T=>{var x;try{typeof chrome<"u"&&((x=chrome.runtime)!=null&&x.sendMessage)&&chrome.runtime.sendMessage({type:"FORENSIC_CHECKPOINT",sessionId:T.sessionId,checkpoint:T})}catch{}});const E=l.start(document);try{typeof chrome<"u"&&((S=chrome.runtime)!=null&&S.sendMessage)&&chrome.runtime.sendMessage({type:"FORENSIC_SESSION_START",metadata:l.getMetadata(),initialSnapshot:E})}catch{}return s||(s=setInterval(u,1e3)),n&&n.updateState(!0,!1,w||Date.now(),0),l.getMetadata()}function g(){var w;if(!l)return null;u(),s&&(clearInterval(s),s=null);const d=l.stop();try{typeof chrome<"u"&&((w=chrome.runtime)!=null&&w.sendMessage)&&chrome.runtime.sendMessage({type:"FORENSIC_SESSION_STOP",sessionId:d.id,metadata:d})}catch{}const f={...d};return l=null,n&&n.updateState(!1,!1,0,0),f}function p(){if(i){i=!1,document.body.style.cursor="default";return}i=!0,document.body.style.cursor="crosshair";const d=document.createElement("div");d.id="forensic-inspect-highlighter",d.style.position="fixed",d.style.pointerEvents="none",d.style.zIndex="2147483640",d.style.border="2px dashed #38bdf8",d.style.background="rgba(56, 189, 248, 0.15)",d.style.transition="all 0.05s ease",document.body.appendChild(d);const f=E=>{if(!i)return;const S=E.target;if(!S||S.id==="forensic-recorder-floating-host"||S.closest("#forensic-recorder-floating-host")){d.style.display="none";return}const T=S.getBoundingClientRect();d.style.display="block",d.style.left=`${T.left}px`,d.style.top=`${T.top}px`,d.style.width=`${T.width}px`,d.style.height=`${T.height}px`},w=E=>{if(!i)return;const S=E.target;if(!S.closest("#forensic-recorder-floating-host")&&(E.preventDefault(),E.stopPropagation(),i=!1,document.body.style.cursor="default",d.remove(),window.removeEventListener("mousemove",f,!0),window.removeEventListener("click",w,!0),l)){const T=S.id?`#${S.id}`:S.className?`.${S.className.split(" ")[0]}`:S.tagName.toLowerCase();l.addAnnotation("Inspect Element",`Inspected element <${S.tagName.toLowerCase()}> with selector '${T}'`,"USER"),alert(`🎯 Inspected element <${S.tagName.toLowerCase()}> recorded! Checkpoint saved.`)}};window.addEventListener("mousemove",f,!0),window.addEventListener("click",w,!0)}function y(){return n||(n=new Ut({onStartRecord:()=>{h()},onStopRecord:()=>{g()},onTogglePause:()=>{l&&(l.getMetadata().status==="recording"?l.pause():l.resume())},onCaptureCheckpoint:()=>{l&&l.captureCheckpoint("MANUAL",document)},onAddAnnotation:d=>{l&&l.addAnnotation("User Note",d,"USER")},onInspectElement:()=>{p()},onOpenDashboard:()=>{const d=l?l.getSessionId():void 0;chrome.runtime.sendMessage({type:"OPEN_DASHBOARD_TAB",sessionId:d})}})),n}function v(){var d;try{typeof chrome<"u"&&((d=chrome.runtime)!=null&&d.sendMessage)&&chrome.runtime.sendMessage({type:"GET_TAB_RECORDING_STATE"},f=>{chrome.runtime.lastError||!f||f.isRecording&&f.recording&&(y().mount(),h(f.recording.sessionName,f.recording.sessionId,f.recording.startTime))})}catch{}}typeof chrome<"u"&&((m=chrome.runtime)!=null&&m.onMessage)&&chrome.runtime.onMessage.addListener((d,f,w)=>{if(d.type==="HIDE_FORENSIC_OVERLAYS")return n&&n.hide(),document.querySelectorAll('#forensic-recorder-floating-host, #forensic-inspect-highlighter, [id^="forensic-"]').forEach(S=>{const T=S;T.style.setProperty("display","none","important"),T.style.setProperty("visibility","hidden","important"),T.style.setProperty("opacity","0","important")}),w({success:!0}),!0;if(d.type==="RESTORE_FORENSIC_OVERLAYS")return n&&n.show(),document.querySelectorAll('#forensic-recorder-floating-host, #forensic-inspect-highlighter, [id^="forensic-"]').forEach(S=>{const T=S;T.style.removeProperty("display"),T.style.removeProperty("visibility"),T.style.removeProperty("opacity")}),w({success:!0}),!0;if(d.type==="BROWSER_COMMAND_REQUEST"){if(["LIST_TABS","FOCUS_TAB","RELOAD_TAB","LIST_EXTENSIONS","RELOAD_EXTENSION","CLOSE_TAB","OPEN_TAB","RESIZE_VIEWPORT","RESET_VIEWPORT"].includes(d.command))return!1;if(d.command==="GET_TAB_CONSOLE_LOGS"){const{level:E,searchQuery:S,limit:T=100,clearAfterRead:x}=d.payload||{};let N=[...o];if(E&&E!=="all"&&(N=N.filter(D=>D.level===E)),S){const D=String(S).toLowerCase();N=N.filter(M=>{var L,I;return((L=M.text)==null?void 0:L.toLowerCase().includes(D))||((I=M.source)==null?void 0:I.toLowerCase().includes(D))})}return T>0&&(N=N.slice(-T)),x&&(o.length=0),w({id:d.id,command:d.command,success:!0,data:{url:window.location.href,title:document.title,totalCaptured:o.length,returnedCount:N.length,logs:N}}),!0}if(d.command==="GET_TAB_NETWORK_REQUESTS"){const{method:E,searchQuery:S,status:T,onlyErrors:x,limit:N=100,clearAfterRead:D}=d.payload||{};let M=[...a];if(E&&(M=M.filter(L=>{var I;return((I=L.method)==null?void 0:I.toUpperCase())===String(E).toUpperCase()})),T&&(M=M.filter(L=>L.status===Number(T))),x&&(M=M.filter(L=>L.error||L.status&&L.status>=400)),S){const L=String(S).toLowerCase();M=M.filter(I=>{var C;return(C=I.url)==null?void 0:C.toLowerCase().includes(L)})}return N>0&&(M=M.slice(-N)),D&&(a.length=0),w({id:d.id,command:d.command,success:!0,data:{url:window.location.href,title:document.title,totalCaptured:a.length,returnedCount:M.length,requests:M}}),!0}return e.handleCommand(d,document).then(E=>{w(E)}),!0}else if(d.type==="START_RECORDING"){const E=h(d.sessionName);y().mount(),w({success:!0,metadata:E})}else if(d.type==="STOP_RECORDING"){const E=g();w({success:!0,metadata:E})}else if(d.type==="TOGGLE_FLOATING_OVERLAY"){const E=y();document.getElementById("forensic-recorder-floating-host")?(E.unmount(),w({isOpen:!1})):(E.mount(),E.updateState((l==null?void 0:l.getMetadata().status)==="recording",!1,(l==null?void 0:l.getMetadata().startTime)||0,0),w({isOpen:!0}))}else if(d.type==="GET_RECORDER_STATUS")w({isRecording:(l==null?void 0:l.getMetadata().status)==="recording",metadata:(l==null?void 0:l.getMetadata())||null});else if(d.type==="CAPTURE_CHECKPOINT")if(l){const E=l.captureCheckpoint("MANUAL",document);w({success:!0,checkpoint:E})}else w({success:!1,error:"Not currently recording"});return!0}),c(),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",v):v()})()})(); diff --git a/dist/extension/service-worker.js b/dist/extension/service-worker.js index 8a07840c..3df46b93 100644 --- a/dist/extension/service-worker.js +++ b/dist/extension/service-worker.js @@ -1 +1 @@ -var v=Object.defineProperty;var P=(E,l,d)=>l in E?v(E,l,{enumerable:!0,configurable:!0,writable:!0,value:d}):E[l]=d;var b=(E,l,d)=>P(E,typeof l!="symbol"?l+"":l,d);(function(){"use strict";var T,_,p,R;class E{constructor(s="ForensicRecorderDB"){b(this,"dbName");b(this,"dbVersion",1);b(this,"db",null);this.dbName=s}async openDB(){if(this.db)return this.db;if(typeof indexedDB>"u")throw new Error("IndexedDB is not available in current runtime environment");return new Promise((s,e)=>{const r=indexedDB.open(this.dbName,this.dbVersion);r.onupgradeneeded=c=>{const t=c.target.result;if(t.objectStoreNames.contains("sessions")||t.createObjectStore("sessions",{keyPath:"id"}),!t.objectStoreNames.contains("events")){const n=t.createObjectStore("events",{keyPath:"id"});n.createIndex("sessionId","sessionId",{unique:!1}),n.createIndex("sequence","sequence",{unique:!1})}t.objectStoreNames.contains("checkpoints")||t.createObjectStore("checkpoints",{keyPath:"checkpointId"}).createIndex("sessionId","sessionId",{unique:!1}),t.objectStoreNames.contains("snapshots")||t.createObjectStore("snapshots",{keyPath:"sessionId"}),t.objectStoreNames.contains("annotations")||t.createObjectStore("annotations",{keyPath:"id"}).createIndex("sessionId","sessionId",{unique:!1})},r.onsuccess=()=>{this.db=r.result,s(this.db)},r.onerror=()=>e(r.error)})}async saveSession(s){const e=await this.openDB();return new Promise((r,c)=>{const t=e.transaction("sessions","readwrite");t.objectStore("sessions").put(s),t.oncomplete=()=>r(),t.onerror=()=>c(t.error)})}async getSession(s){const e=await this.openDB();return new Promise((r,c)=>{const o=e.transaction("sessions","readonly").objectStore("sessions").get(s);o.onsuccess=()=>r(o.result||null),o.onerror=()=>c(o.error)})}async listSessions(){const s=await this.openDB();return new Promise((e,r)=>{const n=s.transaction("sessions","readonly").objectStore("sessions").getAll();n.onsuccess=()=>{const o=n.result||[];o.sort((a,u)=>u.startTime-a.startTime),e(o)},n.onerror=()=>r(n.error)})}async deleteSession(s){const e=await this.openDB();return new Promise((r,c)=>{const t=e.transaction(["sessions","events","checkpoints","snapshots","annotations"],"readwrite");t.objectStore("sessions").delete(s),t.objectStore("snapshots").delete(s);const a=t.objectStore("events").index("sessionId").openCursor(IDBKeyRange.only(s));a.onsuccess=()=>{const u=a.result;u&&(u.delete(),u.continue())},t.oncomplete=()=>r(!0),t.onerror=()=>c(t.error)})}async appendEvents(s,e){if(e.length===0)return;const r=await this.openDB();return new Promise((c,t)=>{const n=r.transaction("events","readwrite"),o=n.objectStore("events");for(const a of e)o.put(a);n.oncomplete=()=>c(),n.onerror=()=>t(n.error)})}async getEvents(s,e){const r=await this.openDB();return new Promise((c,t)=>{const u=r.transaction("events","readonly").objectStore("events").index("sessionId").getAll(IDBKeyRange.only(s));u.onsuccess=()=>{let m=u.result||[];m.sort((h,f)=>h.sequence-f.sequence),e&&(m=m.filter(h=>!(e.category&&h.category!==e.category||e.type&&h.type!==e.type||typeof e.fromTimestamp=="number"&&h.timestampe.toTimestamp||typeof e.targetNodeId=="number"&&h.targetNodeId!==e.targetNodeId)),typeof e.offset=="number"&&(m=m.slice(e.offset)),typeof e.limit=="number"&&(m=m.slice(0,e.limit))),c(m)},u.onerror=()=>t(u.error)})}async getEventCount(s){const e=await this.openDB();return new Promise((r,c)=>{const a=e.transaction("events","readonly").objectStore("events").index("sessionId").count(IDBKeyRange.only(s));a.onsuccess=()=>r(a.result),a.onerror=()=>c(a.error)})}async saveCheckpoint(s){const e=await this.openDB();return new Promise((r,c)=>{const t=e.transaction("checkpoints","readwrite");t.objectStore("checkpoints").put(s),t.oncomplete=()=>r(),t.onerror=()=>c(t.error)})}async getCheckpoints(s){const e=await this.openDB();return new Promise((r,c)=>{const o=e.transaction("checkpoints","readonly").objectStore("checkpoints").index("sessionId").getAll(IDBKeyRange.only(s));o.onsuccess=()=>{const a=o.result||[];a.sort((u,m)=>u.sequence-m.sequence),r(a)},o.onerror=()=>c(o.error)})}async saveInitialSnapshot(s,e){const r=await this.openDB();return new Promise((c,t)=>{const n=r.transaction("snapshots","readwrite");n.objectStore("snapshots").put({sessionId:s,snapshot:e}),n.oncomplete=()=>c(),n.onerror=()=>t(n.error)})}async getInitialSnapshot(s){const e=await this.openDB();return new Promise((r,c)=>{const n=e.transaction("snapshots","readonly").objectStore("snapshots").get(s);n.onsuccess=()=>r(n.result?n.result.snapshot:null),n.onerror=()=>c(n.error)})}async addAnnotation(s){const e=await this.openDB();return new Promise((r,c)=>{const t=e.transaction("annotations","readwrite");t.objectStore("annotations").put(s),t.oncomplete=()=>r(),t.onerror=()=>c(t.error)})}async getAnnotations(s){const e=await this.openDB();return new Promise((r,c)=>{const o=e.transaction("annotations","readonly").objectStore("annotations").index("sessionId").getAll(IDBKeyRange.only(s));o.onsuccess=()=>r(o.result||[]),o.onerror=()=>c(o.error)})}}const l=new E("ForensicExtensionDB");let d=null,S=null;const w=new Map,g=new Map;async function A(){return new Promise(i=>{try{chrome.tabs.query({active:!0,currentWindow:!0},s=>{if(chrome.runtime.lastError||!s||s.length===0)return i(null);i(s[0].id??null)})}catch{i(null)}})}try{(_=(T=chrome.debugger)==null?void 0:T.onEvent)==null||_.addListener((i,s,e)=>{try{for(const[r,c]of g.entries())if((i==null?void 0:i.tabId)===c||(i==null?void 0:i.targetId)===`tab_${c}`){d==null||d.send(JSON.stringify({type:"CDP_EVENT",sessionId:r,method:s,params:e,timestamp:Date.now()}));return}}catch{}})}catch{}async function O(i,s){if(i==="LIST_TABS")return new Promise((e,r)=>{chrome.tabs.query({},c=>{if(chrome.runtime.lastError)return r(new Error(chrome.runtime.lastError.message));const t=(c||[]).map(n=>({id:n.id,index:n.index,windowId:n.windowId,title:n.title||"Untitled",url:n.url||"",active:!!n.active,status:n.status,pinned:!!n.pinned,favIconUrl:n.favIconUrl,audited:n.id?w.has(n.id):!1,incognito:!!n.incognito,width:n.width,height:n.height}));e({totalTabs:t.length,tabs:t})})});if(i==="FOCUS_TAB"){const e=Number(s==null?void 0:s.tabId);if(!e)throw new Error("tabId is required for focus_tab");return new Promise((r,c)=>{chrome.tabs.update(e,{active:!0},t=>{var n;if(chrome.runtime.lastError||!t)return c(new Error(((n=chrome.runtime.lastError)==null?void 0:n.message)||`Tab ${e} not found`));t.windowId?chrome.windows.update(t.windowId,{focused:!0},()=>{r({focused:!0,tab:{id:t.id,windowId:t.windowId,title:t.title,url:t.url,active:t.active}})}):r({focused:!0,tab:{id:t.id,title:t.title,url:t.url,active:t.active}})})})}if(i==="RELOAD_TAB"){const e=!!(s!=null&&s.bypassCache),r=s!=null&&s.tabId?Number(s.tabId):void 0;return new Promise((c,t)=>{const n=o=>{chrome.tabs.reload(o,{bypassCache:e},()=>{if(chrome.runtime.lastError)return t(new Error(chrome.runtime.lastError.message));chrome.tabs.get(o,a=>{c({reloaded:!0,tabId:o,bypassCache:e,url:a==null?void 0:a.url,title:a==null?void 0:a.title})})})};r?chrome.tabs.get(r,o=>{chrome.runtime.lastError||!o?chrome.tabs.query({active:!0,lastFocusedWindow:!0},a=>{const u=a&&a[0]?a[0]:null;u!=null&&u.id?n(u.id):t(new Error("No active tab found to reload"))}):n(r)}):chrome.tabs.query({active:!0,lastFocusedWindow:!0},o=>{const a=o&&o[0]?o[0]:null;if(!(a!=null&&a.id))return t(new Error("No active tab found to reload"));n(a.id)})})}if(i==="CLOSE_TAB"){const e=s!=null&&s.tabId?Number(s.tabId):void 0,r=s!=null&&s.url?String(s.url).toLowerCase():void 0;return new Promise((c,t)=>{const n=o=>{chrome.tabs.remove(o,()=>{if(chrome.runtime.lastError)return t(new Error(chrome.runtime.lastError.message));c({closed:!0,tabIds:o,count:o.length})})};e?n([e]):r?chrome.tabs.query({},o=>{const u=(o||[]).filter(m=>{var h,f;return((h=m.url)==null?void 0:h.toLowerCase().includes(r))||((f=m.title)==null?void 0:f.toLowerCase().includes(r))}).map(m=>m.id).filter(Boolean);if(u.length===0)return c({closed:!1,message:`No open tab matched '${r}'`});n(u)}):chrome.tabs.query({active:!0,lastFocusedWindow:!0},o=>{const a=o&&o[0]?o[0]:null;if(!(a!=null&&a.id))return t(new Error("No active tab found to close"));n([a.id])})})}if(i==="OPEN_TAB"){const e=s==null?void 0:s.url;if(!e)throw new Error("url is required for open_tab");let r=String(e).trim();!r.startsWith("http://")&&!r.startsWith("https://")&&!r.startsWith("file://")&&!r.startsWith("chrome://")&&!r.startsWith("about:")&&(r.includes("meet.google.com")||r.includes("localhost")||r.includes(".com")||r.includes(".org")||r.includes(".net")||r.includes(".ir")||r.includes(".io")||r.includes(".app"))&&(r="https://"+r);const c=s.active!==!1,t=!!s.pinned;return new Promise((n,o)=>{chrome.tabs.create({url:r,active:c,pinned:t},a=>{if(chrome.runtime.lastError)return o(new Error(chrome.runtime.lastError.message));n({opened:!0,tabId:a.id,windowId:a.windowId,url:a.url||r,title:a.title||"New Tab",active:a.active,status:a.status})})})}if(i==="LIST_EXTENSIONS")return new Promise((e,r)=>{var c;if(!((c=chrome.management)!=null&&c.getAll))return r(new Error("chrome.management API not available"));chrome.management.getAll(t=>{if(chrome.runtime.lastError)return r(new Error(chrome.runtime.lastError.message));const n=(t||[]).map(o=>({id:o.id,name:o.name,version:o.version,description:o.description,enabled:o.enabled,installType:o.installType,isApp:o.isApp,homepageUrl:o.homepageUrl,permissions:o.permissions}));e({totalExtensions:n.length,extensions:n})})});if(i==="SET_EXTENSION_ENABLED"){const e=s==null?void 0:s.extensionId,r=!!(s!=null&&s.enabled);if(!e)throw new Error("extensionId is required for SET_EXTENSION_ENABLED");return new Promise((c,t)=>{var n;if(!((n=chrome.management)!=null&&n.setEnabled))return t(new Error("chrome.management API not available"));chrome.management.setEnabled(e,r,()=>{if(chrome.runtime.lastError)return t(new Error(chrome.runtime.lastError.message||`Failed to set enabled state for ${e}`));c({success:!0,extensionId:e,enabled:r,message:`Extension ${e} successfully ${r?"enabled":"disabled"}.`})})})}if(i==="TOGGLE_EXTENSION"){const e=s==null?void 0:s.extensionId;if(!e)throw new Error("extensionId is required for TOGGLE_EXTENSION");return new Promise((r,c)=>{var t,n;if(!((t=chrome.management)!=null&&t.get)||!((n=chrome.management)!=null&&n.setEnabled))return c(new Error("chrome.management API not available"));chrome.management.get(e,o=>{var u;if(chrome.runtime.lastError||!o)return c(new Error(((u=chrome.runtime.lastError)==null?void 0:u.message)||`Extension ${e} not found`));const a=!o.enabled;chrome.management.setEnabled(e,a,()=>{if(chrome.runtime.lastError)return c(new Error(chrome.runtime.lastError.message||`Failed to toggle ${e}`));r({success:!0,extensionId:e,enabled:a,name:o.name,message:`Extension ${o.name} (${e}) toggled to ${a?"enabled":"disabled"}.`})})})})}if(i==="RESIZE_VIEWPORT"){const e=Math.max(200,Math.min(7680,Number(s==null?void 0:s.width)||1280)),r=Math.max(200,Math.min(4320,Number(s==null?void 0:s.height)||800));return new Promise((c,t)=>{chrome.windows.getCurrent({populate:!1},n=>{var o;if(chrome.runtime.lastError||!n)return t(new Error(((o=chrome.runtime.lastError)==null?void 0:o.message)||"No current window"));chrome.windows.update(n.id??chrome.windows.WINDOW_ID_CURRENT,{width:e,height:r,state:"normal"},a=>{var u;if(chrome.runtime.lastError||!a)return t(new Error(((u=chrome.runtime.lastError)==null?void 0:u.message)||"Window resize failed"));c({success:!0,applied:{width:a.width,height:a.height},previous:{width:n.width,height:n.height},original:{width:n.width,height:n.height},reversible:!0,mode:"browser-window",note:"Reset with reset_viewport — the content script tracks the original size."})})})})}if(i==="RESET_VIEWPORT")return new Promise((e,r)=>{chrome.windows.getCurrent({populate:!1},c=>{var t;if(chrome.runtime.lastError||!c)return r(new Error(((t=chrome.runtime.lastError)==null?void 0:t.message)||"No current window"));chrome.windows.update(c.id??chrome.windows.WINDOW_ID_CURRENT,{state:"maximized"},n=>{var o;if(chrome.runtime.lastError||!n)return r(new Error(((o=chrome.runtime.lastError)==null?void 0:o.message)||"Window restore failed"));e({success:!0,applied:{width:n.width,height:n.height},previous:{width:c.width,height:c.height},original:{width:n.width,height:n.height},reversible:!1,mode:"browser-window",note:"Window restored to maximized state."})})})});if(i==="RELOAD_EXTENSION"){const e=s==null?void 0:s.extensionId,r=chrome.runtime.id;return!e||e===r?(setTimeout(()=>chrome.runtime.reload(),150),{reloaded:!0,extensionId:r,isSelf:!0,message:"Forensic Recorder extension is reloading now."}):new Promise((c,t)=>{var n;if(!((n=chrome.management)!=null&&n.setEnabled))return t(new Error("chrome.management API not available"));chrome.management.setEnabled(e,!1,()=>{if(chrome.runtime.lastError)return t(new Error(chrome.runtime.lastError.message||`Failed to disable ${e}`));setTimeout(()=>{chrome.management.setEnabled(e,!0,()=>{if(chrome.runtime.lastError)return t(new Error(chrome.runtime.lastError.message||`Failed to re-enable ${e}`));c({reloaded:!0,extensionId:e,isSelf:!1,message:`Extension ${e} successfully reloaded.`})})},150)})})}if(i==="CDP_ATTACH"){const e=(s==null?void 0:s.tabId)!==void 0?Number(s.tabId):await A();if(e===null)throw new Error("No target tab available for CDP attach.");return new Promise((r,c)=>{var t;if(!((t=chrome.debugger)!=null&&t.attach))return c(new Error('CDP_UNAVAILABLE: chrome.debugger API not available (check the "debugger" permission).'));chrome.debugger.attach({tabId:e},"1.3",()=>{if(chrome.runtime.lastError)return c(new Error(`CDP_ATTACH failed: ${chrome.runtime.lastError.message}`));s!=null&&s.sessionId&&g.set(String(s.sessionId),e),chrome.debugger.getTargets(n=>{const o=(n||[]).find(a=>a.tabId===e)||{};r({attached:!0,sessionId:s==null?void 0:s.sessionId,tabId:e,targetId:o.id||`tab_${e}`,type:o.type||"page"})})})})}if(i==="CDP_COMMAND"){const{sessionId:e,method:r,params:c}=s||{};if(!r)throw new Error("CDP_COMMAND requires method");return new Promise((t,n)=>{var a;if(!((a=chrome.debugger)!=null&&a.sendCommand))return n(new Error('CDP_UNAVAILABLE: chrome.debugger API not available (check the "debugger" permission).'));const o=g.get(e);if(o===void 0)return n(new Error(`CDP_SESSION_NOT_FOUND: no tab bound to session '${e}' — attach first.`));chrome.debugger.sendCommand({tabId:o},r,c||{},u=>{if(chrome.runtime.lastError){t({__cdpError:!0,code:"CDP_PROTOCOL_ERROR",message:chrome.runtime.lastError.message,method:r});return}t({result:u??{}})})})}if(i==="CDP_DETACH"){const{sessionId:e}=s||{},r=g.get(e);return g.delete(e),r===void 0?{detached:!1,reason:"session not found"}:new Promise((c,t)=>{var n;if(!((n=chrome.debugger)!=null&&n.detach))return c({detached:!1,reason:"chrome.debugger unavailable"});chrome.debugger.detach({tabId:r},()=>{if(chrome.runtime.lastError)return c({detached:!1,reason:chrome.runtime.lastError.message});c({detached:!0,sessionId:e,tabId:r})})})}throw new Error(`Unsupported background command: ${i}`)}function I(){if(!(typeof WebSocket>"u"))try{const i=new WebSocket("ws://127.0.0.1:3847");let s=null;i.onopen=()=>{var e;d=i,console.log("[Forensic Extension] Connected to MCP Bridge on ws://127.0.0.1:3847"),S&&(clearInterval(S),S=null),i.send(JSON.stringify({type:"REGISTER_CLIENT",clientType:"SERVICE_WORKER",url:typeof chrome<"u"&&((e=chrome.runtime)!=null&&e.id)?`chrome-extension://${chrome.runtime.id}`:"service-worker",title:"Forensic Service Worker"})),s&&clearInterval(s),s=setInterval(()=>{if(i&&i.readyState===WebSocket.OPEN)try{i.send(JSON.stringify({type:"HEARTBEAT",timestamp:Date.now()}))}catch(r){console.warn("[TeleDOM SW] non-critical operation failed:",(r==null?void 0:r.message)??r)}},15e3)},i.onclose=()=>{s&&clearInterval(s),d=null,N()},i.onerror=()=>{s&&clearInterval(s),d=null,N()},i.onmessage=async e=>{try{const r=JSON.parse(e.data.toString());if(r.type==="BROWSER_COMMAND_REQUEST"){const{id:c,command:t,payload:n}=r;if(typeof chrome>"u"||!chrome.tabs){i.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!1,error:{code:"NO_CHROME_TABS_API",message:"chrome.tabs API not available in this context"}}));return}if(["LIST_TABS","FOCUS_TAB","RELOAD_TAB","CLOSE_TAB","OPEN_TAB","LIST_EXTENSIONS","RELOAD_EXTENSION","SET_EXTENSION_ENABLED","TOGGLE_EXTENSION","CDP_ATTACH","CDP_COMMAND","CDP_DETACH"].includes(t)){try{const u=await O(t,n);i.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!0,data:u}))}catch(u){i.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!1,error:{code:"COMMAND_ERROR",message:u.message}}))}return}const o=n!=null&&n.tabId?Number(n.tabId):void 0,a=u=>{if(t==="LIVE_PAGE_SCREENSHOT"||t==="LIVE_ELEMENT_SCREENSHOT"){chrome.tabs.sendMessage(u,{type:"HIDE_FORENSIC_OVERLAYS"},()=>{setTimeout(()=>{chrome.tabs.captureVisibleTab({format:"png"},m=>{var h;if(chrome.tabs.sendMessage(u,{type:"RESTORE_FORENSIC_OVERLAYS"}),chrome.runtime.lastError||!m){i.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!1,error:{code:"SCREENSHOT_FAILED",message:((h=chrome.runtime.lastError)==null?void 0:h.message)||"captureVisibleTab failed"}}));return}chrome.tabs.sendMessage(u,{type:"BROWSER_COMMAND_REQUEST",id:c,command:t,payload:{...n,dataUrl:m}},f=>{const C=f||{id:c,command:t,success:!0,data:{dataUrl:m,captureType:t==="LIVE_ELEMENT_SCREENSHOT"?"ELEMENT":"FULL_PAGE"}};i.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",...C}))})})},150)});return}chrome.tabs.sendMessage(u,r,m=>{if(chrome.runtime.lastError){i.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!1,error:{code:"CONTENT_SCRIPT_UNREACHABLE",message:chrome.runtime.lastError.message||`Content script unreachable on tab ${u}`}}));return}i.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",...m||{id:c,command:t,success:!0}}))})};o?a(o):chrome.tabs.query({active:!0,lastFocusedWindow:!0},async u=>{const m=u&&u[0]?u[0]:null,h=m==null?void 0:m.id;if(!h){i.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!1,error:{code:"NO_ACTIVE_TAB",message:"No active browser tab found"}}));return}a(h)})}}catch(r){console.error("[ServiceWorker] Bridge message handling error:",r)}}}catch{d=null,N()}}function N(){S||(S=setInterval(()=>{(!d||d.readyState!==WebSocket.OPEN)&&I()},5e3))}I(),typeof chrome<"u"&&((p=chrome.webNavigation)!=null&&p.onCommitted)&&chrome.webNavigation.onCommitted.addListener(async i=>{var t;if(i.frameId!==0)return;const s=i.tabId,e=w.get(s);if(!e||!e.isRecording)return;let r="NAV_OTHER";i.transitionType==="reload"?r="NAV_RELOAD":(t=i.transitionQualifiers)!=null&&t.includes("forward_back")?r="NAV_FORWARD_BACK":i.transitionType==="link"&&(r="NAV_LINK");const c={id:`nav_${Date.now()}_${Math.random().toString(36).slice(2,6)}`,sessionId:e.sessionId,timestamp:Date.now()-e.startTime,sequence:999999,wallClockTime:Date.now(),type:r,category:"NAVIGATION",source:"USER_INTERACTION",payload:{url:i.url,transitionType:i.transitionType,transitionQualifiers:i.transitionQualifiers,tabId:i.tabId}};try{await l.appendEvents(e.sessionId,[c]),d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify({type:"FORENSIC_EVENTS_CHUNK",sessionId:e.sessionId,events:[c]}))}catch{}}),typeof chrome<"u"&&((R=chrome.runtime)!=null&&R.onMessage)&&chrome.runtime.onMessage.addListener((i,s,e)=>((async()=>{var r,c,t;try{const n=((r=s.tab)==null?void 0:r.id)??i.tabId;if(i.type==="FORENSIC_SESSION_START")n&&w.set(n,{sessionId:i.metadata.id,sessionName:i.metadata.name,startTime:i.metadata.startTime,initialUrl:i.metadata.url,isRecording:!0}),await l.saveSession(i.metadata),i.initialSnapshot&&await l.saveInitialSnapshot(i.metadata.id,i.initialSnapshot),d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify(i)),e({success:!0,sessionId:i.metadata.id});else if(i.type==="GET_TAB_RECORDING_STATE"){const o=n?w.get(n):null;e({isRecording:!!(o!=null&&o.isRecording),recording:o||null})}else if(i.type==="FORENSIC_EVENTS_CHUNK")await l.appendEvents(i.sessionId,i.events),d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify(i)),e({success:!0});else if(i.type==="FORENSIC_CHECKPOINT")await l.saveCheckpoint(i.checkpoint),d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify(i)),e({success:!0});else if(i.type==="FORENSIC_SESSION_STOP"){n&&w.delete(n);const o=await l.getSession(i.sessionId);o&&(o.status="stopped",o.endTime=Date.now(),(c=i.metadata)!=null&&c.durationMs&&(o.durationMs=i.metadata.durationMs),await l.saveSession(o)),d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify(i)),e({success:!0})}else if(i.type==="OPEN_DASHBOARD_TAB"){const o=chrome.runtime.getURL(`dist/src/ui/index.html${i.sessionId?`?session=${i.sessionId}`:""}`);chrome.tabs.create({url:o}),e({success:!0,url:o})}else if(i.type==="CAPTURE_SCREENSHOT"){if((t=chrome.tabs)!=null&&t.captureVisibleTab){chrome.tabs.captureVisibleTab({format:"png"},o=>{e({success:!!o,dataUrl:o})});return}e({success:!1,error:"Screenshot capture unsupported"})}else if(i.type==="ELEMENT_SELECTED")d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify(i)),e({success:!0});else if(i.type==="BROWSER_COMMAND_REQUEST")try{const o=await O(i.command,i.payload);e({id:i.id,command:i.command,success:!0,data:o})}catch(o){e({id:i.id,command:i.command,success:!1,error:{code:"COMMAND_ERROR",message:o.message}})}}catch(n){e({success:!1,error:n.message})}})(),!0)),I()})(); +var v=Object.defineProperty;var P=(E,h,d)=>h in E?v(E,h,{enumerable:!0,configurable:!0,writable:!0,value:d}):E[h]=d;var I=(E,h,d)=>P(E,typeof h!="symbol"?h+"":h,d);(function(){"use strict";var T,_,p,A;class E{constructor(s="ForensicRecorderDB"){I(this,"dbName");I(this,"dbVersion",1);I(this,"db",null);this.dbName=s}async openDB(){if(this.db)return this.db;if(typeof indexedDB>"u")throw new Error("IndexedDB is not available in current runtime environment");return new Promise((s,e)=>{const n=indexedDB.open(this.dbName,this.dbVersion);n.onupgradeneeded=c=>{const t=c.target.result;if(t.objectStoreNames.contains("sessions")||t.createObjectStore("sessions",{keyPath:"id"}),!t.objectStoreNames.contains("events")){const r=t.createObjectStore("events",{keyPath:"id"});r.createIndex("sessionId","sessionId",{unique:!1}),r.createIndex("sequence","sequence",{unique:!1})}t.objectStoreNames.contains("checkpoints")||t.createObjectStore("checkpoints",{keyPath:"checkpointId"}).createIndex("sessionId","sessionId",{unique:!1}),t.objectStoreNames.contains("snapshots")||t.createObjectStore("snapshots",{keyPath:"sessionId"}),t.objectStoreNames.contains("annotations")||t.createObjectStore("annotations",{keyPath:"id"}).createIndex("sessionId","sessionId",{unique:!1})},n.onsuccess=()=>{this.db=n.result,s(this.db)},n.onerror=()=>e(n.error)})}async saveSession(s){const e=await this.openDB();return new Promise((n,c)=>{const t=e.transaction("sessions","readwrite");t.objectStore("sessions").put(s),t.oncomplete=()=>n(),t.onerror=()=>c(t.error)})}async getSession(s){const e=await this.openDB();return new Promise((n,c)=>{const i=e.transaction("sessions","readonly").objectStore("sessions").get(s);i.onsuccess=()=>n(i.result||null),i.onerror=()=>c(i.error)})}async listSessions(){const s=await this.openDB();return new Promise((e,n)=>{const r=s.transaction("sessions","readonly").objectStore("sessions").getAll();r.onsuccess=()=>{const i=r.result||[];i.sort((a,u)=>u.startTime-a.startTime),e(i)},r.onerror=()=>n(r.error)})}async deleteSession(s){const e=await this.openDB();return new Promise((n,c)=>{const t=e.transaction(["sessions","events","checkpoints","snapshots","annotations"],"readwrite");t.objectStore("sessions").delete(s),t.objectStore("snapshots").delete(s);const a=t.objectStore("events").index("sessionId").openCursor(IDBKeyRange.only(s));a.onsuccess=()=>{const u=a.result;u&&(u.delete(),u.continue())},t.oncomplete=()=>n(!0),t.onerror=()=>c(t.error)})}async appendEvents(s,e){if(e.length===0)return;const n=await this.openDB();return new Promise((c,t)=>{const r=n.transaction("events","readwrite"),i=r.objectStore("events");for(const a of e)i.put(a);r.oncomplete=()=>c(),r.onerror=()=>t(r.error)})}async getEvents(s,e){const n=await this.openDB();return new Promise((c,t)=>{const u=n.transaction("events","readonly").objectStore("events").index("sessionId").getAll(IDBKeyRange.only(s));u.onsuccess=()=>{let m=u.result||[];m.sort((l,f)=>l.sequence-f.sequence),e&&(m=m.filter(l=>!(e.category&&l.category!==e.category||e.type&&l.type!==e.type||typeof e.fromTimestamp=="number"&&l.timestampe.toTimestamp||typeof e.targetNodeId=="number"&&l.targetNodeId!==e.targetNodeId)),typeof e.offset=="number"&&(m=m.slice(e.offset)),typeof e.limit=="number"&&(m=m.slice(0,e.limit))),c(m)},u.onerror=()=>t(u.error)})}async getEventCount(s){const e=await this.openDB();return new Promise((n,c)=>{const a=e.transaction("events","readonly").objectStore("events").index("sessionId").count(IDBKeyRange.only(s));a.onsuccess=()=>n(a.result),a.onerror=()=>c(a.error)})}async saveCheckpoint(s){const e=await this.openDB();return new Promise((n,c)=>{const t=e.transaction("checkpoints","readwrite");t.objectStore("checkpoints").put(s),t.oncomplete=()=>n(),t.onerror=()=>c(t.error)})}async getCheckpoints(s){const e=await this.openDB();return new Promise((n,c)=>{const i=e.transaction("checkpoints","readonly").objectStore("checkpoints").index("sessionId").getAll(IDBKeyRange.only(s));i.onsuccess=()=>{const a=i.result||[];a.sort((u,m)=>u.sequence-m.sequence),n(a)},i.onerror=()=>c(i.error)})}async saveInitialSnapshot(s,e){const n=await this.openDB();return new Promise((c,t)=>{const r=n.transaction("snapshots","readwrite");r.objectStore("snapshots").put({sessionId:s,snapshot:e}),r.oncomplete=()=>c(),r.onerror=()=>t(r.error)})}async getInitialSnapshot(s){const e=await this.openDB();return new Promise((n,c)=>{const r=e.transaction("snapshots","readonly").objectStore("snapshots").get(s);r.onsuccess=()=>n(r.result?r.result.snapshot:null),r.onerror=()=>c(r.error)})}async addAnnotation(s){const e=await this.openDB();return new Promise((n,c)=>{const t=e.transaction("annotations","readwrite");t.objectStore("annotations").put(s),t.oncomplete=()=>n(),t.onerror=()=>c(t.error)})}async getAnnotations(s){const e=await this.openDB();return new Promise((n,c)=>{const i=e.transaction("annotations","readonly").objectStore("annotations").index("sessionId").getAll(IDBKeyRange.only(s));i.onsuccess=()=>n(i.result||[]),i.onerror=()=>c(i.error)})}}const h=new E("ForensicExtensionDB");let d=null,S=null;const w=new Map,g=new Map;async function R(){return new Promise(o=>{try{chrome.tabs.query({active:!0,currentWindow:!0},s=>{if(chrome.runtime.lastError||!s||s.length===0)return o(null);o(s[0].id??null)})}catch{o(null)}})}try{(_=(T=chrome.debugger)==null?void 0:T.onEvent)==null||_.addListener((o,s,e)=>{try{for(const[n,c]of g.entries())if((o==null?void 0:o.tabId)===c||(o==null?void 0:o.targetId)===`tab_${c}`){d==null||d.send(JSON.stringify({type:"CDP_EVENT",sessionId:n,method:s,params:e,timestamp:Date.now()}));return}}catch{}})}catch{}async function O(o,s){if(o==="LIST_TABS")return new Promise((e,n)=>{chrome.tabs.query({},c=>{if(chrome.runtime.lastError)return n(new Error(chrome.runtime.lastError.message));const t=(c||[]).map(r=>({id:r.id,index:r.index,windowId:r.windowId,title:r.title||"Untitled",url:r.url||"",active:!!r.active,status:r.status,pinned:!!r.pinned,favIconUrl:r.favIconUrl,audited:r.id?w.has(r.id):!1,incognito:!!r.incognito,width:r.width,height:r.height}));e({totalTabs:t.length,tabs:t})})});if(o==="FOCUS_TAB"){const e=Number(s==null?void 0:s.tabId);if(!e)throw new Error("tabId is required for focus_tab");return new Promise((n,c)=>{chrome.tabs.update(e,{active:!0},t=>{var r;if(chrome.runtime.lastError||!t)return c(new Error(((r=chrome.runtime.lastError)==null?void 0:r.message)||`Tab ${e} not found`));t.windowId?chrome.windows.update(t.windowId,{focused:!0},()=>{n({focused:!0,tab:{id:t.id,windowId:t.windowId,title:t.title,url:t.url,active:t.active}})}):n({focused:!0,tab:{id:t.id,title:t.title,url:t.url,active:t.active}})})})}if(o==="RELOAD_TAB"){const e=!!(s!=null&&s.bypassCache),n=s!=null&&s.tabId?Number(s.tabId):void 0;return new Promise((c,t)=>{const r=i=>{chrome.tabs.reload(i,{bypassCache:e},()=>{if(chrome.runtime.lastError)return t(new Error(chrome.runtime.lastError.message));chrome.tabs.get(i,a=>{c({reloaded:!0,tabId:i,bypassCache:e,url:a==null?void 0:a.url,title:a==null?void 0:a.title})})})};n?chrome.tabs.get(n,i=>{chrome.runtime.lastError||!i?chrome.tabs.query({active:!0,lastFocusedWindow:!0},a=>{const u=a&&a[0]?a[0]:null;u!=null&&u.id?r(u.id):t(new Error("No active tab found to reload"))}):r(n)}):chrome.tabs.query({active:!0,lastFocusedWindow:!0},i=>{const a=i&&i[0]?i[0]:null;if(!(a!=null&&a.id))return t(new Error("No active tab found to reload"));r(a.id)})})}if(o==="CLOSE_TAB"){const e=s!=null&&s.tabId?Number(s.tabId):void 0,n=s!=null&&s.url?String(s.url).toLowerCase():void 0;return new Promise((c,t)=>{const r=i=>{chrome.tabs.remove(i,()=>{if(chrome.runtime.lastError)return t(new Error(chrome.runtime.lastError.message));c({closed:!0,tabIds:i,count:i.length})})};e?r([e]):n?chrome.tabs.query({},i=>{const u=(i||[]).filter(m=>{var l,f;return((l=m.url)==null?void 0:l.toLowerCase().includes(n))||((f=m.title)==null?void 0:f.toLowerCase().includes(n))}).map(m=>m.id).filter(Boolean);if(u.length===0)return c({closed:!1,message:`No open tab matched '${n}'`});r(u)}):chrome.tabs.query({active:!0,lastFocusedWindow:!0},i=>{const a=i&&i[0]?i[0]:null;if(!(a!=null&&a.id))return t(new Error("No active tab found to close"));r([a.id])})})}if(o==="OPEN_TAB"){const e=s==null?void 0:s.url;if(!e)throw new Error("url is required for open_tab");let n=String(e).trim();!n.startsWith("http://")&&!n.startsWith("https://")&&!n.startsWith("file://")&&!n.startsWith("chrome://")&&!n.startsWith("about:")&&(n.includes("meet.google.com")||n.includes("localhost")||n.includes(".com")||n.includes(".org")||n.includes(".net")||n.includes(".ir")||n.includes(".io")||n.includes(".app"))&&(n="https://"+n);const c=s.active!==!1,t=!!s.pinned;return new Promise((r,i)=>{chrome.tabs.create({url:n,active:c,pinned:t},a=>{if(chrome.runtime.lastError)return i(new Error(chrome.runtime.lastError.message));r({opened:!0,tabId:a.id,windowId:a.windowId,url:a.url||n,title:a.title||"New Tab",active:a.active,status:a.status})})})}if(o==="LIST_EXTENSIONS")return new Promise((e,n)=>{var c;if(!((c=chrome.management)!=null&&c.getAll))return n(new Error("chrome.management API not available"));chrome.management.getAll(t=>{if(chrome.runtime.lastError)return n(new Error(chrome.runtime.lastError.message));const r=(t||[]).map(i=>({id:i.id,name:i.name,version:i.version,description:i.description,enabled:i.enabled,installType:i.installType,isApp:i.isApp,homepageUrl:i.homepageUrl,permissions:i.permissions}));e({totalExtensions:r.length,extensions:r})})});if(o==="SET_EXTENSION_ENABLED"){const e=s==null?void 0:s.extensionId,n=!!(s!=null&&s.enabled);if(!e)throw new Error("extensionId is required for SET_EXTENSION_ENABLED");return new Promise((c,t)=>{var r;if(!((r=chrome.management)!=null&&r.setEnabled))return t(new Error("chrome.management API not available"));chrome.management.setEnabled(e,n,()=>{if(chrome.runtime.lastError)return t(new Error(chrome.runtime.lastError.message||`Failed to set enabled state for ${e}`));c({success:!0,extensionId:e,enabled:n,message:`Extension ${e} successfully ${n?"enabled":"disabled"}.`})})})}if(o==="TOGGLE_EXTENSION"){const e=s==null?void 0:s.extensionId;if(!e)throw new Error("extensionId is required for TOGGLE_EXTENSION");return new Promise((n,c)=>{var t,r;if(!((t=chrome.management)!=null&&t.get)||!((r=chrome.management)!=null&&r.setEnabled))return c(new Error("chrome.management API not available"));chrome.management.get(e,i=>{var u;if(chrome.runtime.lastError||!i)return c(new Error(((u=chrome.runtime.lastError)==null?void 0:u.message)||`Extension ${e} not found`));const a=!i.enabled;chrome.management.setEnabled(e,a,()=>{if(chrome.runtime.lastError)return c(new Error(chrome.runtime.lastError.message||`Failed to toggle ${e}`));n({success:!0,extensionId:e,enabled:a,name:i.name,message:`Extension ${i.name} (${e}) toggled to ${a?"enabled":"disabled"}.`})})})})}if(o==="RESIZE_VIEWPORT"){const e=Math.max(200,Math.min(7680,Number(s==null?void 0:s.width)||1280)),n=Math.max(200,Math.min(4320,Number(s==null?void 0:s.height)||800));return new Promise((c,t)=>{chrome.windows.getCurrent({populate:!1},r=>{var i;if(chrome.runtime.lastError||!r)return t(new Error(((i=chrome.runtime.lastError)==null?void 0:i.message)||"No current window"));chrome.windows.update(r.id??chrome.windows.WINDOW_ID_CURRENT,{width:e,height:n,state:"normal"},a=>{var u;if(chrome.runtime.lastError||!a)return t(new Error(((u=chrome.runtime.lastError)==null?void 0:u.message)||"Window resize failed"));c({success:!0,applied:{width:a.width,height:a.height},previous:{width:r.width,height:r.height},original:{width:r.width,height:r.height},reversible:!0,mode:"browser-window",note:"Reset with reset_viewport — the content script tracks the original size."})})})})}if(o==="RESET_VIEWPORT")return new Promise((e,n)=>{chrome.windows.getCurrent({populate:!1},c=>{var t;if(chrome.runtime.lastError||!c)return n(new Error(((t=chrome.runtime.lastError)==null?void 0:t.message)||"No current window"));chrome.windows.update(c.id??chrome.windows.WINDOW_ID_CURRENT,{state:"maximized"},r=>{var i;if(chrome.runtime.lastError||!r)return n(new Error(((i=chrome.runtime.lastError)==null?void 0:i.message)||"Window restore failed"));e({success:!0,applied:{width:r.width,height:r.height},previous:{width:c.width,height:c.height},original:{width:r.width,height:r.height},reversible:!1,mode:"browser-window",note:"Window restored to maximized state."})})})});if(o==="RELOAD_EXTENSION"){const e=s==null?void 0:s.extensionId,n=chrome.runtime.id;return!e||e===n?(setTimeout(()=>chrome.runtime.reload(),150),{reloaded:!0,extensionId:n,isSelf:!0,message:"Forensic Recorder extension is reloading now."}):new Promise((c,t)=>{var r;if(!((r=chrome.management)!=null&&r.setEnabled))return t(new Error("chrome.management API not available"));chrome.management.setEnabled(e,!1,()=>{if(chrome.runtime.lastError)return t(new Error(chrome.runtime.lastError.message||`Failed to disable ${e}`));setTimeout(()=>{chrome.management.setEnabled(e,!0,()=>{if(chrome.runtime.lastError)return t(new Error(chrome.runtime.lastError.message||`Failed to re-enable ${e}`));c({reloaded:!0,extensionId:e,isSelf:!1,message:`Extension ${e} successfully reloaded.`})})},150)})})}if(o==="CDP_ATTACH"){const e=(s==null?void 0:s.tabId)!==void 0?Number(s.tabId):await R();if(e===null)throw new Error("No target tab available for CDP attach.");return new Promise((n,c)=>{var t;if(!((t=chrome.debugger)!=null&&t.attach))return c(new Error('CDP_UNAVAILABLE: chrome.debugger API not available (check the "debugger" permission).'));chrome.debugger.attach({tabId:e},"1.3",()=>{if(chrome.runtime.lastError){const r=chrome.runtime.lastError.message||"";return r.includes("Another debugger is already attached")?c(new Error(`CDP_ATTACH failed: Chrome DevTools (F12) is already open on tab ${e}. Please close the F12 panel on that tab so TeleDOM can attach.`)):c(new Error(`CDP_ATTACH failed: ${r}`))}s!=null&&s.sessionId&&g.set(String(s.sessionId),e),chrome.debugger.getTargets(r=>{const i=(r||[]).find(a=>a.tabId===e)||{};n({attached:!0,sessionId:s==null?void 0:s.sessionId,tabId:e,targetId:i.id||`tab_${e}`,type:i.type||"page"})})})})}if(o==="CDP_COMMAND"){const{sessionId:e,method:n,params:c}=s||{};if(!n)throw new Error("CDP_COMMAND requires method");return new Promise((t,r)=>{var a;if(!((a=chrome.debugger)!=null&&a.sendCommand))return r(new Error('CDP_UNAVAILABLE: chrome.debugger API not available (check the "debugger" permission).'));const i=g.get(e);if(i===void 0)return r(new Error(`CDP_SESSION_NOT_FOUND: no tab bound to session '${e}' — attach first.`));chrome.debugger.sendCommand({tabId:i},n,c||{},u=>{if(chrome.runtime.lastError){t({__cdpError:!0,code:"CDP_PROTOCOL_ERROR",message:chrome.runtime.lastError.message,method:n});return}t({result:u??{}})})})}if(o==="CDP_DETACH"){const{sessionId:e}=s||{},n=g.get(e);return g.delete(e),n===void 0?{detached:!1,reason:"session not found"}:new Promise((c,t)=>{var r;if(!((r=chrome.debugger)!=null&&r.detach))return c({detached:!1,reason:"chrome.debugger unavailable"});chrome.debugger.detach({tabId:n},()=>{if(chrome.runtime.lastError)return c({detached:!1,reason:chrome.runtime.lastError.message});c({detached:!0,sessionId:e,tabId:n})})})}throw new Error(`Unsupported background command: ${o}`)}function b(){if(!(typeof WebSocket>"u"))try{const o=new WebSocket("ws://127.0.0.1:3847");let s=null;o.onopen=()=>{var e;d=o,console.log("[Forensic Extension] Connected to MCP Bridge on ws://127.0.0.1:3847"),S&&(clearInterval(S),S=null),o.send(JSON.stringify({type:"REGISTER_CLIENT",clientType:"SERVICE_WORKER",url:typeof chrome<"u"&&((e=chrome.runtime)!=null&&e.id)?`chrome-extension://${chrome.runtime.id}`:"service-worker",title:"Forensic Service Worker"})),s&&clearInterval(s),s=setInterval(()=>{if(o&&o.readyState===WebSocket.OPEN)try{o.send(JSON.stringify({type:"HEARTBEAT",timestamp:Date.now()}))}catch(n){console.warn("[TeleDOM SW] non-critical operation failed:",(n==null?void 0:n.message)??n)}},15e3)},o.onclose=()=>{s&&clearInterval(s),d=null,N()},o.onerror=()=>{s&&clearInterval(s),d=null,N()},o.onmessage=async e=>{try{const n=JSON.parse(e.data.toString());if(n.type==="BROWSER_COMMAND_REQUEST"){const{id:c,command:t,payload:r}=n;if(typeof chrome>"u"||!chrome.tabs){o.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!1,error:{code:"NO_CHROME_TABS_API",message:"chrome.tabs API not available in this context"}}));return}if(["LIST_TABS","FOCUS_TAB","RELOAD_TAB","CLOSE_TAB","OPEN_TAB","LIST_EXTENSIONS","RELOAD_EXTENSION","SET_EXTENSION_ENABLED","TOGGLE_EXTENSION","CDP_ATTACH","CDP_COMMAND","CDP_DETACH"].includes(t)){try{const u=await O(t,r);o.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!0,data:u}))}catch(u){o.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!1,error:{code:"COMMAND_ERROR",message:u.message}}))}return}const i=r!=null&&r.tabId?Number(r.tabId):void 0,a=u=>{if(t==="LIVE_PAGE_SCREENSHOT"||t==="LIVE_ELEMENT_SCREENSHOT"){chrome.tabs.sendMessage(u,{type:"HIDE_FORENSIC_OVERLAYS"},()=>{setTimeout(()=>{chrome.tabs.captureVisibleTab({format:"png"},m=>{var l;if(chrome.tabs.sendMessage(u,{type:"RESTORE_FORENSIC_OVERLAYS"}),chrome.runtime.lastError||!m){o.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!1,error:{code:"SCREENSHOT_FAILED",message:((l=chrome.runtime.lastError)==null?void 0:l.message)||"captureVisibleTab failed"}}));return}chrome.tabs.sendMessage(u,{type:"BROWSER_COMMAND_REQUEST",id:c,command:t,payload:{...r,dataUrl:m}},f=>{const C=f||{id:c,command:t,success:!0,data:{dataUrl:m,captureType:t==="LIVE_ELEMENT_SCREENSHOT"?"ELEMENT":"FULL_PAGE"}};o.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",...C}))})})},150)});return}chrome.tabs.sendMessage(u,n,m=>{if(chrome.runtime.lastError){o.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!1,error:{code:"CONTENT_SCRIPT_UNREACHABLE",message:chrome.runtime.lastError.message||`Content script unreachable on tab ${u}`}}));return}o.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",...m||{id:c,command:t,success:!0}}))})};i?a(i):chrome.tabs.query({active:!0,lastFocusedWindow:!0},async u=>{const m=u&&u[0]?u[0]:null,l=m==null?void 0:m.id;if(!l){o.send(JSON.stringify({type:"BROWSER_COMMAND_RESPONSE",id:c,command:t,success:!1,error:{code:"NO_ACTIVE_TAB",message:"No active browser tab found"}}));return}a(l)})}}catch(n){console.error("[ServiceWorker] Bridge message handling error:",n)}}}catch{d=null,N()}}function N(){S||(S=setInterval(()=>{(!d||d.readyState!==WebSocket.OPEN)&&b()},5e3))}if(typeof chrome<"u"&&chrome.alarms)try{chrome.alarms.create("teledom_bridge_keepalive",{periodInMinutes:.4}),chrome.alarms.onAlarm.addListener(o=>{if(o.name==="teledom_bridge_keepalive")if(!d||d.readyState!==WebSocket.OPEN)b();else try{d.send(JSON.stringify({type:"HEARTBEAT",timestamp:Date.now()}))}catch{b()}})}catch(o){console.warn("[ServiceWorker] Alarms keepalive setup failed:",o==null?void 0:o.message)}b(),typeof chrome<"u"&&((p=chrome.webNavigation)!=null&&p.onCommitted)&&chrome.webNavigation.onCommitted.addListener(async o=>{var t;if(o.frameId!==0)return;const s=o.tabId,e=w.get(s);if(!e||!e.isRecording)return;let n="NAV_OTHER";o.transitionType==="reload"?n="NAV_RELOAD":(t=o.transitionQualifiers)!=null&&t.includes("forward_back")?n="NAV_FORWARD_BACK":o.transitionType==="link"&&(n="NAV_LINK");const c={id:`nav_${Date.now()}_${Math.random().toString(36).slice(2,6)}`,sessionId:e.sessionId,timestamp:Date.now()-e.startTime,sequence:999999,wallClockTime:Date.now(),type:n,category:"NAVIGATION",source:"USER_INTERACTION",payload:{url:o.url,transitionType:o.transitionType,transitionQualifiers:o.transitionQualifiers,tabId:o.tabId}};try{await h.appendEvents(e.sessionId,[c]),d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify({type:"FORENSIC_EVENTS_CHUNK",sessionId:e.sessionId,events:[c]}))}catch{}}),typeof chrome<"u"&&((A=chrome.runtime)!=null&&A.onMessage)&&chrome.runtime.onMessage.addListener((o,s,e)=>((async()=>{var n,c,t;try{const r=((n=s.tab)==null?void 0:n.id)??o.tabId;if(o.type==="FORENSIC_SESSION_START")r&&w.set(r,{sessionId:o.metadata.id,sessionName:o.metadata.name,startTime:o.metadata.startTime,initialUrl:o.metadata.url,isRecording:!0}),await h.saveSession(o.metadata),o.initialSnapshot&&await h.saveInitialSnapshot(o.metadata.id,o.initialSnapshot),d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify(o)),e({success:!0,sessionId:o.metadata.id});else if(o.type==="GET_TAB_RECORDING_STATE"){const i=r?w.get(r):null;e({isRecording:!!(i!=null&&i.isRecording),recording:i||null})}else if(o.type==="FORENSIC_EVENTS_CHUNK")await h.appendEvents(o.sessionId,o.events),d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify(o)),e({success:!0});else if(o.type==="FORENSIC_CHECKPOINT")await h.saveCheckpoint(o.checkpoint),d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify(o)),e({success:!0});else if(o.type==="FORENSIC_SESSION_STOP"){r&&w.delete(r);const i=await h.getSession(o.sessionId);i&&(i.status="stopped",i.endTime=Date.now(),(c=o.metadata)!=null&&c.durationMs&&(i.durationMs=o.metadata.durationMs),await h.saveSession(i)),d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify(o)),e({success:!0})}else if(o.type==="OPEN_DASHBOARD_TAB"){const i=chrome.runtime.getURL(`dist/src/ui/index.html${o.sessionId?`?session=${o.sessionId}`:""}`);chrome.tabs.create({url:i}),e({success:!0,url:i})}else if(o.type==="CAPTURE_SCREENSHOT"){if((t=chrome.tabs)!=null&&t.captureVisibleTab){chrome.tabs.captureVisibleTab({format:"png"},i=>{e({success:!!i,dataUrl:i})});return}e({success:!1,error:"Screenshot capture unsupported"})}else if(o.type==="ELEMENT_SELECTED")d&&d.readyState===WebSocket.OPEN&&d.send(JSON.stringify(o)),e({success:!0});else if(o.type==="BROWSER_COMMAND_REQUEST")try{const i=await O(o.command,o.payload);e({id:o.id,command:o.command,success:!0,data:i})}catch(i){e({id:o.id,command:o.command,success:!1,error:{code:"COMMAND_ERROR",message:i.message}})}}catch(r){e({success:!1,error:r.message})}})(),!0)),b()})(); diff --git a/dist/server/bridge-server.js b/dist/server/bridge-server.js index a5935064..420602e0 100644 --- a/dist/server/bridge-server.js +++ b/dist/server/bridge-server.js @@ -4,7 +4,6 @@ import * as fs from "fs"; import fs__default from "fs"; import * as path from "path"; import path__default from "path"; -import * as readline from "readline"; import * as zlib from "zlib"; import { gunzipSync, gzipSync } from "zlib"; import { createHash, randomUUID } from "crypto"; @@ -123,41 +122,49 @@ class FileStorageProvider { async saveSession(metadata) { const dir = this.getSessionDir(metadata.id); const metaPath = path.join(dir, "metadata.json"); - fs.writeFileSync(metaPath, JSON.stringify(metadata, null, 2), "utf-8"); + await fs.promises.writeFile(metaPath, JSON.stringify(metadata, null, 2), "utf-8"); } async getSession(sessionId) { const dir = path.join(this.baseDir, sessionId); const metaPath = path.join(dir, "metadata.json"); - if (!fs.existsSync(metaPath)) return null; try { - const data = fs.readFileSync(metaPath, "utf-8"); + const data = await fs.promises.readFile(metaPath, "utf-8"); return JSON.parse(data); - } catch { + } catch (err) { + if (err?.code !== "ENOENT") { + console.warn(`[FileStorage] Warning: Failed to read session ${sessionId}: ${err?.message}`); + } return null; } } async listSessions() { if (!fs.existsSync(this.baseDir)) return []; - const entries = fs.readdirSync(this.baseDir, { withFileTypes: true }); - const sessions = []; - for (const entry of entries) { - if (entry.isDirectory()) { - const metaPath = path.join(this.baseDir, entry.name, "metadata.json"); - if (fs.existsSync(metaPath)) { + try { + const entries = await fs.promises.readdir(this.baseDir, { withFileTypes: true }); + const sessions = []; + for (const entry of entries) { + if (entry.isDirectory()) { + const metaPath = path.join(this.baseDir, entry.name, "metadata.json"); try { - const data = fs.readFileSync(metaPath, "utf-8"); + const data = await fs.promises.readFile(metaPath, "utf-8"); sessions.push(JSON.parse(data)); - } catch { + } catch (err) { + if (err?.code !== "ENOENT") { + console.warn(`[FileStorage] Warning: Corrupt or unreadable session metadata at ${metaPath}: ${err?.message}`); + } } } } + return sessions.sort((a, b) => b.startTime - a.startTime); + } catch (err) { + console.error(`[FileStorage] Failed to list sessions from ${this.baseDir}:`, err?.message); + return []; } - return sessions.sort((a, b) => b.startTime - a.startTime); } async deleteSession(sessionId) { const dir = path.join(this.baseDir, sessionId); if (fs.existsSync(dir)) { - fs.rmSync(dir, { recursive: true, force: true }); + await fs.promises.rm(dir, { recursive: true, force: true, maxRetries: 10, retryDelay: 50 }); return true; } return false; @@ -167,28 +174,26 @@ class FileStorageProvider { const dir = this.getSessionDir(sessionId); const eventsPath = path.join(dir, "events.jsonl"); const lines = events.map((e) => JSON.stringify(e)).join("\n") + "\n"; - fs.appendFileSync(eventsPath, lines, "utf-8"); + await fs.promises.appendFile(eventsPath, lines, "utf-8"); } async getEvents(sessionId, filter) { const dir = path.join(this.baseDir, sessionId); const eventsPath = path.join(dir, "events.jsonl"); if (!fs.existsSync(eventsPath)) return []; - const fileStream = fs.createReadStream(eventsPath, { encoding: "utf-8" }); - const rl = readline.createInterface({ - input: fileStream, - crlfDelay: Infinity - }); + const content = await fs.promises.readFile(eventsPath, "utf-8"); + const lines = content.split(/\r?\n/); const results = []; let matchedCount = 0; const offset = typeof filter?.offset === "number" ? filter.offset : 0; const limit = typeof filter?.limit === "number" ? filter.limit : Infinity; - for await (const line of rl) { + for (const line of lines) { const trimmed = line.trim(); if (!trimmed) continue; let e; try { e = JSON.parse(trimmed); - } catch { + } catch (parseErr) { + console.warn(`[FileStorage] Skipping malformed event line in session ${sessionId}:`, parseErr); continue; } if (filter) { @@ -214,8 +219,6 @@ class FileStorageProvider { } results.push(e); if (results.length >= limit) { - rl.close(); - fileStream.destroy(); break; } } @@ -225,13 +228,9 @@ class FileStorageProvider { const dir = path.join(this.baseDir, sessionId); const eventsPath = path.join(dir, "events.jsonl"); if (!fs.existsSync(eventsPath)) return 0; - const fileStream = fs.createReadStream(eventsPath, { encoding: "utf-8" }); - const rl = readline.createInterface({ - input: fileStream, - crlfDelay: Infinity - }); + const content = await fs.promises.readFile(eventsPath, "utf-8"); let count = 0; - for await (const line of rl) { + for (const line of content.split(/\r?\n/)) { if (line.trim()) count++; } return count; @@ -239,36 +238,46 @@ class FileStorageProvider { async saveCheckpoint(checkpoint) { const dir = this.getSessionDir(checkpoint.sessionId); const chkDir = path.join(dir, "checkpoints"); - if (!fs.existsSync(chkDir)) fs.mkdirSync(chkDir, { recursive: true }); + await fs.promises.mkdir(chkDir, { recursive: true }); const file = path.join(chkDir, `${checkpoint.checkpointId}.json`); - fs.writeFileSync(file, JSON.stringify(checkpoint, null, 2), "utf-8"); + await fs.promises.writeFile(file, JSON.stringify(checkpoint, null, 2), "utf-8"); } async getCheckpoints(sessionId) { const dir = path.join(this.baseDir, sessionId, "checkpoints"); - if (!fs.existsSync(dir)) return []; - const files = fs.readdirSync(dir).filter((f) => f.endsWith(".json")); - const checkpoints = []; - for (const f of files) { - try { - const data = fs.readFileSync(path.join(dir, f), "utf-8"); - checkpoints.push(JSON.parse(data)); - } catch { + try { + const files = (await fs.promises.readdir(dir)).filter((f) => f.endsWith(".json")); + const checkpoints = []; + for (const f of files) { + try { + const data = await fs.promises.readFile(path.join(dir, f), "utf-8"); + checkpoints.push(JSON.parse(data)); + } catch (err) { + console.warn(`[FileStorage] Failed to read/parse checkpoint file ${f} in session ${sessionId}:`, err); + } } + return checkpoints.sort((a, b) => a.sequence - b.sequence); + } catch (err) { + if (err?.code !== "ENOENT") { + console.warn(`[FileStorage] Error accessing checkpoints directory for session ${sessionId}:`, err); + } + return []; } - return checkpoints.sort((a, b) => a.sequence - b.sequence); } async saveInitialSnapshot(sessionId, snapshot) { const dir = this.getSessionDir(sessionId); const file = path.join(dir, "initial_snapshot.json"); - fs.writeFileSync(file, JSON.stringify(snapshot, null, 2), "utf-8"); + await fs.promises.writeFile(file, JSON.stringify(snapshot, null, 2), "utf-8"); } async getInitialSnapshot(sessionId) { const dir = path.join(this.baseDir, sessionId); const file = path.join(dir, "initial_snapshot.json"); - if (!fs.existsSync(file)) return null; try { - return JSON.parse(fs.readFileSync(file, "utf-8")); - } catch { + const content = await fs.promises.readFile(file, "utf-8"); + return JSON.parse(content); + } catch (err) { + if (err?.code !== "ENOENT") { + console.warn(`[FileStorage] Error reading initial snapshot for session ${sessionId}:`, err); + } return null; } } @@ -276,23 +285,28 @@ class FileStorageProvider { const dir = this.getSessionDir(annotation.sessionId); const annPath = path.join(dir, "annotations.json"); let list = []; - if (fs.existsSync(annPath)) { - try { - list = JSON.parse(fs.readFileSync(annPath, "utf-8")); - } catch { - list = []; + try { + const content = await fs.promises.readFile(annPath, "utf-8"); + list = JSON.parse(content); + } catch (err) { + if (err?.code !== "ENOENT") { + console.warn(`[FileStorage] Corrupted annotations file for session ${annotation.sessionId}, starting fresh:`, err); } + list = []; } list.push(annotation); - fs.writeFileSync(annPath, JSON.stringify(list, null, 2), "utf-8"); + await fs.promises.writeFile(annPath, JSON.stringify(list, null, 2), "utf-8"); } async getAnnotations(sessionId) { const dir = path.join(this.baseDir, sessionId); const annPath = path.join(dir, "annotations.json"); - if (!fs.existsSync(annPath)) return []; try { - return JSON.parse(fs.readFileSync(annPath, "utf-8")); - } catch { + const content = await fs.promises.readFile(annPath, "utf-8"); + return JSON.parse(content); + } catch (err) { + if (err?.code !== "ENOENT") { + console.warn(`[FileStorage] Failed to read annotations for session ${sessionId}:`, err); + } return []; } } @@ -8997,7 +9011,18 @@ class LiveToolsHandler { } ] }; - } catch { + } catch (saveErr) { + return { + content: [ + { + type: "text", + text: JSON.stringify({ + ...finalSummary, + fileSaveError: `Failed to write pipeline output to ${args.outputPath}: ${saveErr?.message || saveErr}` + }, null, 2) + } + ] + }; } } return { @@ -9403,7 +9428,8 @@ class ProjectManager { try { const manifest = JSON.parse(fs__default.readFileSync(manifestPath, "utf-8")); out.push({ ...manifest, projectDir: path__default.join(this.baseDir, entry.name), pageCount: manifest.pages?.length || 0 }); - } catch { + } catch (err) { + console.warn(`[ProjectManager] Warning: Skipped corrupt project manifest at ${manifestPath}:`, err); } } return out.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0)); @@ -9664,7 +9690,8 @@ class ProjectManager { if (fs__default.existsSync(p)) { try { out.push(JSON.parse(fs__default.readFileSync(p, "utf-8"))); - } catch { + } catch (err) { + console.warn(`[ProjectManager] Warning: Skipped corrupt region file ${p}:`, err); } } } @@ -10026,7 +10053,8 @@ class CommandRecordingStorage { try { const raw = JSON.parse(fs__default.readFileSync(file, "utf-8")); return raw.recording || raw; - } catch { + } catch (err) { + console.warn(`[RecordingStorage] Warning: Failed to parse recording file ${file}:`, err); return null; } } @@ -10054,7 +10082,8 @@ class CommandRecordingStorage { tags: rec.tags || [], file: path__default.join(this.baseDir, entry.name) }); - } catch { + } catch (err) { + console.warn(`[RecordingStorage] Warning: Skipped corrupt recording file ${entry.name}:`, err); } } return out.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0)); @@ -10471,6 +10500,111 @@ function buildToolCatalog() { } return catalog; } +const TELEDOM_PROFILE_TOOLS = { + // Minimal profile: strictly essential browser actions (~22 tools, ~2.5k tokens) + minimal: [ + "td_browser_navigate", + "td_browser_back", + "td_browser_forward", + "td_browser_refresh", + "td_dom_inspect", + "td_dom_query", + "td_dom_extract", + "td_dom_snapshot", + "td_target_find", + "td_target_check", + "td_action_click", + "td_action_type", + "td_action_select", + "td_action_press", + "td_action_scroll", + "td_wait", + "td_screenshot", + "td_execute_script", + "list_tabs", + "focus_tab", + "close_tab", + "open_tab" + ], + // Core profile: browser primitives + workflow runtime + target memory (~44 tools, ~4.8k tokens) + core: [ + "td_browser_navigate", + "td_browser_back", + "td_browser_forward", + "td_browser_refresh", + "td_dom_inspect", + "td_dom_query", + "td_dom_extract", + "td_dom_snapshot", + "td_target_find", + "td_target_check", + "td_target_describe", + "td_action_click", + "td_action_type", + "td_action_select", + "td_action_hover", + "td_action_press", + "td_action_scroll", + "td_wait", + "td_screenshot", + "td_execute_script", + "td_network_inspect", + "td_console_read", + "td_workflow_save", + "td_workflow_get", + "td_workflow_list", + "td_workflow_update", + "td_workflow_delete", + "td_workflow_validate", + "td_workflow_run", + "td_workflow_runs", + "td_workflow_replay", + "td_target_memory_save", + "td_target_memory_get", + "td_target_memory_list", + "td_target_memory_delete", + "list_tabs", + "focus_tab", + "reload_tab", + "close_tab", + "open_tab", + "inspect_live_page", + "inspect_live_element" + ], + // Forensics profile: historical forensics + diffs + causality + live inspection (~50 tools) + forensics: [ + "list_sessions", + "get_session", + "export_session", + "import_session", + "delete_session", + "get_timeline", + "get_events", + "get_events_around", + "get_dom_state", + "get_dom_node", + "get_dom_subtree", + "diff_dom", + "trace_element", + "find_disappearing_elements", + "why_did_element_disappear", + "get_diagnostics", + "get_network_events", + "get_screenshots", + "td_browser_navigate", + "td_dom_inspect", + "td_dom_query", + "td_dom_extract", + "td_screenshot", + "td_action_click", + "td_action_type", + "td_workflow_run", + "list_tabs", + "focus_tab" + ], + // Full profile: all 350 tools (null means no filtering) + full: null +}; const MCPDOM_V3_TOOLS = [ // ================================================================== // Targeting & forensics @@ -18593,7 +18727,8 @@ class ForensicsToolsHandler { try { const res = await unifiedRuntime.bridgeCommand("LIVE_DOM_SNAPSHOT", { format: "json" }); return { snapshot: res }; - } catch { + } catch (err) { + console.warn(`[ForensicsHandler] Could not capture live snapshot: ${err?.message || err}`); return { snapshot: null }; } } @@ -18602,7 +18737,8 @@ async function runInPageSafe(code, tabId) { try { const { runInPage: runInPage2 } = await Promise.resolve().then(() => interactionCore); return await runInPage2(code, tabId); - } catch { + } catch (err) { + console.warn(`[ForensicsHandler] runInPageSafe failed for tab ${tabId}: ${err?.message || err}`); return null; } } @@ -22506,14 +22642,20 @@ class AgentStore { readJson(file) { try { return JSON.parse(fs.readFileSync(file, "utf-8")); - } catch { + } catch (err) { + if (err?.code !== "ENOENT") { + console.warn(`[WorkflowStore] Warning: Failed to read or parse ${file}:`, err?.message || err); + } return null; } } listJsonNames(dir) { try { return fs.readdirSync(dir).filter((f) => f.endsWith(".json")).sort(); - } catch { + } catch (err) { + if (err?.code !== "ENOENT") { + console.warn(`[WorkflowStore] Warning: Failed to list directory ${dir}:`, err?.message || err); + } return []; } } @@ -25415,12 +25557,14 @@ class MCPBridgeServer { if (targets.length === 0) { for (const [sock, meta] of this.socketMetadata.entries()) { if (meta.clientType === "CONTENT_SCRIPT" && sock.readyState === WebSocket.OPEN) { - targets.push(sock); + targets = [sock]; + break; } } } - if (targets.length === 0) { - targets = Array.from(this.activeSockets); + if (targets.length === 0 && this.activeSockets.size > 0) { + const first = Array.from(this.activeSockets).find((s) => s.readyState === WebSocket.OPEN); + if (first) targets = [first]; } let sentCount = 0; for (const ws of targets) { @@ -25443,17 +25587,53 @@ class MCPBridgeServer { } start() { return new Promise((resolve, reject) => { + const isTrustedOrigin = (origin) => { + if (!origin) return true; + if (origin.startsWith("chrome-extension://")) return true; + if (/^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/.test(origin)) return true; + return false; + }; this.httpServer = http.createServer(async (req, res) => { - res.setHeader("Access-Control-Allow-Origin", "*"); + const origin = req.headers.origin; + if (origin) { + if (isTrustedOrigin(origin)) { + res.setHeader("Access-Control-Allow-Origin", origin); + res.setHeader("Access-Control-Allow-Credentials", "true"); + res.setHeader("Vary", "Origin"); + } else if (req.method === "OPTIONS") { + res.writeHead(403, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ error: "CORS Forbidden: Untrusted cross-origin request rejected" })); + return; + } + } res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); - res.setHeader("Access-Control-Allow-Headers", "Content-Type"); + res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, x-teledom-token"); if (req.method === "OPTIONS") { res.writeHead(204); res.end(); return; } const url = req.url || ""; - if (url === "/health" && req.method === "GET") { + const isAuthValid = () => { + if (!isTrustedOrigin(origin)) return false; + const expectedToken = process.env.TELEDOM_BRIDGE_TOKEN; + if (!expectedToken) return true; + const authHeader = req.headers.authorization; + const tokenHeader = req.headers["x-teledom-token"]; + let queryToken = null; + try { + const parsed = new URL(url, "http://127.0.0.1"); + queryToken = parsed.searchParams.get("token"); + } catch { + } + if (authHeader && authHeader.startsWith("Bearer ")) { + return authHeader.slice(7).trim() === expectedToken; + } + if (tokenHeader && tokenHeader === expectedToken) return true; + if (queryToken && queryToken === expectedToken) return true; + return false; + }; + if (url.startsWith("/health") && req.method === "GET") { res.writeHead(200, { "Content-Type": "application/json" }); res.end( JSON.stringify({ @@ -25465,6 +25645,13 @@ class MCPBridgeServer { ); return; } + if (["/api/mcp/tool", "/api/tabs/close", "/api/sessions/upload"].some((p) => url.startsWith(p))) { + if (!isAuthValid()) { + res.writeHead(403, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ error: "Forbidden: Invalid or missing authorization credentials" })); + return; + } + } const MAX_PAYLOAD_BYTES = 50 * 1024 * 1024; if (url === "/api/sessions/upload" && req.method === "POST") { let body = ""; @@ -25583,7 +25770,13 @@ class MCPBridgeServer { } }, 3e4); this.healthSweepInterval?.unref?.(); - this.wss.on("connection", (ws) => { + this.wss.on("connection", (ws, req) => { + const origin = req?.headers?.origin; + if (origin && !isTrustedOrigin(origin)) { + console.error(`[MCP Bridge] WebSocket connection rejected from untrusted origin: ${origin}`); + ws.close(4403, "Forbidden origin"); + return; + } this.activeSockets.add(ws); console.error(`[MCP Bridge] Client connected. Total active clients: ${this.activeSockets.size}`); ws.on("close", () => { @@ -25711,8 +25904,10 @@ export { FORENSICS_TOOLS as F, MCPDOM_V3_TOOLS as M, MCPBridgeServer, + PNGBuilder as P, TELEDOM_INTELLIGENCE_TOOLS as T, TELEDOM_VERSION as a, FileStorageProvider as b, - MCPToolsHandler as c + MCPToolsHandler as c, + TELEDOM_PROFILE_TOOLS as d }; diff --git a/dist/server/mcp-server.js b/dist/server/mcp-server.js index bf9f2d9e..4f33d5fa 100644 --- a/dist/server/mcp-server.js +++ b/dist/server/mcp-server.js @@ -1,6 +1,7 @@ import * as readline from "readline"; import * as fs from "fs"; -import { M as MCPDOM_V3_TOOLS, D as DEVTOOLS_TOOLS, F as FORENSICS_TOOLS, T as TELEDOM_INTELLIGENCE_TOOLS, a as TELEDOM_VERSION, b as FileStorageProvider, c as MCPToolsHandler, MCPBridgeServer } from "./bridge-server.js"; +import { M as MCPDOM_V3_TOOLS, D as DEVTOOLS_TOOLS, F as FORENSICS_TOOLS, T as TELEDOM_INTELLIGENCE_TOOLS, a as TELEDOM_VERSION, b as FileStorageProvider, c as MCPToolsHandler, MCPBridgeServer, d as TELEDOM_PROFILE_TOOLS } from "./bridge-server.js"; +import { P } from "./bridge-server.js"; import "http"; import "ws"; import "path"; @@ -872,9 +873,15 @@ class ForensicMCPServer { const disableDevTools = process.env.FORENSIC_DISABLE_DEVTOOLS === "true"; const disableForensics = process.env.FORENSIC_DISABLE_FORENSICS === "true"; const disableIntelligence = process.env.FORENSIC_DISABLE_INTELLIGENCE === "true"; - const tools = FORENSIC_MCP_TOOLS.filter( + const profile = (process.env.TELEDOM_PROFILE || "full").toLowerCase(); + const profileAllowed = TELEDOM_PROFILE_TOOLS[profile]; + let tools = FORENSIC_MCP_TOOLS.filter( (t) => !(disableDevTools && t.name.startsWith("dt_")) && !(disableForensics && t.name.startsWith("fx_")) && !(disableIntelligence && t.name.startsWith("td_")) ); + if (profileAllowed && Array.isArray(profileAllowed)) { + const allowedSet = new Set(profileAllowed); + tools = tools.filter((t) => allowedSet.has(t.name)); + } return { jsonrpc: "2.0", id, @@ -1077,5 +1084,7 @@ export { FORENSIC_MCP_TOOLS, FileStorageProvider, ForensicMCPServer, - MCPToolsHandler + MCPToolsHandler, + P as PNGBuilder, + TELEDOM_PROFILE_TOOLS }; diff --git a/dist/src/extension/devtools/devtools.html b/dist/src/extension/devtools/devtools.html index e5ead51c..ec623abe 100644 --- a/dist/src/extension/devtools/devtools.html +++ b/dist/src/extension/devtools/devtools.html @@ -1,10 +1,10 @@ - - - - + + + + - - - - + + + + diff --git a/dist/src/extension/popup/popup.html b/dist/src/extension/popup/popup.html index 9f991f9c..6b4f597e 100644 --- a/dist/src/extension/popup/popup.html +++ b/dist/src/extension/popup/popup.html @@ -1,54 +1,54 @@ - - - - - Forensic Recorder + + + + + Forensic Recorder - - - - - + + + + + diff --git a/dist/src/ui/index.html b/dist/src/ui/index.html index e82ee8a9..0412e036 100644 --- a/dist/src/ui/index.html +++ b/dist/src/ui/index.html @@ -1,243 +1,243 @@ - - - - - - Browser Forensic Recorder & Time-Travel Debugger + + + + + + Browser Forensic Recorder & Time-Travel Debugger - - - -
-
-
-
- Browser Forensic Debugger - v2.0 MCP -
-
- -
-
- - -
-
- -
- - - - - - - -
-
- - -
- -
-
-
- T: 0.0ms | URL: - -
-
-
-
- - -
- - -
- -
-
-
-
Load or record a session to inspect DOM.
-
-
-
Select an element from the DOM tree or replay viewport.
-
-
-
- - -
-
-
- - - - - - -
-
-
-
Select timestamps and click Compare States.
-
-
-
- - -
-
-
-

Disappearing UI Forensic Diagnosis

-
- - -
-
-
-
Enter a CSS selector or node ID to run root-cause diagnosis.
-
-
-
- - -
-
-
No console or error events recorded.
-
-
- - -
-
-
No network events recorded.
-
-
- - -
-
-
- - -
-
-
-
- - -
-
-
-
-
⚡ Agent-Owned Workflows
-
TeleDOM stores and executes; the agent designs and repairs. Teach once · Reuse forever · Prove what happened.
-
- -
-
-
Recent Runs
-
-
-
-
-
-
- - -
-
-
- - - - - -
- -
- 0.0ms - / 0.0ms -
- -
- - -
-
- -
-
-
-
-
DOM Mut
-
-
-
-
User Act
-
-
-
-
Errors
-
-
-
-
Network
-
-
-
-
- - - - - - - - + + + +
+
+
+
+ Browser Forensic Debugger + v2.0 MCP +
+
+ +
+
+ + +
+
+ +
+ + + + + + + +
+
+ + +
+ +
+
+
+ T: 0.0ms | URL: - +
+
+
+
+ + +
+ + +
+ +
+
+
+
Load or record a session to inspect DOM.
+
+
+
Select an element from the DOM tree or replay viewport.
+
+
+
+ + +
+
+
+ + + + + + +
+
+
+
Select timestamps and click Compare States.
+
+
+
+ + +
+
+
+

Disappearing UI Forensic Diagnosis

+
+ + +
+
+
+
Enter a CSS selector or node ID to run root-cause diagnosis.
+
+
+
+ + +
+
+
No console or error events recorded.
+
+
+ + +
+
+
No network events recorded.
+
+
+ + +
+
+
+ + +
+
+
+
+ + +
+
+
+
+
⚡ Agent-Owned Workflows
+
TeleDOM stores and executes; the agent designs and repairs. Teach once · Reuse forever · Prove what happened.
+
+ +
+
+
Recent Runs
+
+
+
+
+
+
+ + +
+
+
+ + + + + +
+ +
+ 0.0ms + / 0.0ms +
+ +
+ + +
+
+ +
+
+
+
+
DOM Mut
+
+
+
+
User Act
+
+
+
+
Errors
+
+
+
+
Network
+
+
+
+
+ + + + + + + + diff --git a/docs/intelligence/BENCHMARKS.md b/docs/intelligence/BENCHMARKS.md index 6ac4f868..94280892 100644 --- a/docs/intelligence/BENCHMARKS.md +++ b/docs/intelligence/BENCHMARKS.md @@ -1,23 +1,23 @@ # TeleDOM v4 — Measured Benchmarks & Suite Metrics -Generated: 2026-09-11T18:05:59.466Z (local deterministic measurements on this machine — not marketing numbers) +Generated: 2026-09-12T07:22:28.467Z (local deterministic measurements on this machine — not marketing numbers) ## Event-scale benchmark matrix | Metric | 10K events | 100K events | 1M events | |---|---|---|---| -| Capture overhead (ms per 10K events) | 248.3 | 213.63 | 88.71 | +| Capture overhead (ms per 10K events) | 211.58 | 180.81 | 135.08 | | Bytes per event (approx) | 352 | 355 | 358 | -| Reconstruction p50 (ms) | 3.62 | 19.1 | 116.78 | -| Reconstruction p95 (ms) | 5.7 | 30.08 | 234.64 | -| Reconstruction p99 (ms) | 5.7 | 78.02 | 259.34 | -| Temporal query p50 (ms) | 0.81 | 4.93 | 25.89 | -| Temporal query p95 (ms) | 8.6 | 7.07 | 33.14 | -| Temporal query p99 (ms) | 8.6 | 9.83 | 57.53 | -| Graph query latency (ms) | 52.21 | 30.6 | 20.2 | -| Investigation latency (ms) | 117.01 | 64.33 | 59.17 | -| Branch simulation latency (ms) | 27.64 | 125.92 | 899.42 | -| Recovery time (serialize+restore, ms) | 112.65 | 457.84 | 4467.36 | +| Reconstruction p50 (ms) | 4.35 | 18.63 | 114.73 | +| Reconstruction p95 (ms) | 25.14 | 43.18 | 226.75 | +| Reconstruction p99 (ms) | 25.14 | 46.93 | 239.83 | +| Temporal query p50 (ms) | 0.92 | 4.69 | 29.54 | +| Temporal query p95 (ms) | 1.72 | 6.87 | 45.49 | +| Temporal query p99 (ms) | 1.72 | 8.24 | 55.39 | +| Graph query latency (ms) | 55.56 | 44.03 | 21.83 | +| Investigation latency (ms) | 582.07 | 120.2 | 66.39 | +| Branch simulation latency (ms) | 28.74 | 120.73 | 882.66 | +| Recovery time (serialize+restore, ms) | 92.57 | 966.19 | 5446.28 | **Timestamp resolution: 0.01 ms — tracked SEPARATELY from reconstruction/query latency (never conflated).** diff --git a/docs/intelligence/COMPATIBILITY.md b/docs/intelligence/COMPATIBILITY.md index 303f8c12..4eb26301 100644 --- a/docs/intelligence/COMPATIBILITY.md +++ b/docs/intelligence/COMPATIBILITY.md @@ -1,6 +1,6 @@ # TeleDOM v4 — Compatibility Matrix (generated) -Generated: 2026-09-11T18:05:32.304Z · TeleDOM version: 4.1.0 +Generated: 2026-09-12T07:22:00.113Z · TeleDOM version: 4.1.0 **Surfaces**: td_=144 · dt_=54 · fx_=31 · base=47 · v3=74 · **total=350** diff --git a/manifest.json b/manifest.json index 63066493..5c230ce8 100644 --- a/manifest.json +++ b/manifest.json @@ -16,7 +16,8 @@ "tabs", "webNavigation", "management", - "debugger" + "debugger", + "alarms" ], "host_permissions": [ "" diff --git a/package.json b/package.json index 0b174041..d8aae37e 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,10 @@ "bench": "vitest run tests/intelligence/suite-reports.test.ts", "golden": "vitest run tests/intelligence/suite-reports.test.ts", "chaos": "vitest run tests/intelligence/suite-reports.test.ts", - "test:sdk": "python sdk/python/test_sdk.py" + "test:sdk": "python sdk/python/test_sdk.py", + "lint:python": "python -m ruff check sdk/python && python -m mypy sdk/python", + "format:python": "python -m isort sdk/python && python -m black sdk/python", + "qa:all": "npm run build && npm run test:unit && npm run test:sdk && npm run lint:python" }, "keywords": [ "browser", diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 00000000..bf842cbb --- /dev/null +++ b/ruff.toml @@ -0,0 +1,15 @@ +line-length = 100 +target-version = "py39" + +[lint] +select = ["E", "F", "W", "I", "RUF022"] +ignore = [ + "EXE001", # shebang executable check + "UP045", # requires Python 3.10+ PEP 604; project supports Python 3.9+ + "BLE001", # blind exception catch during process teardown + "S110", # try-except-pass in process termination + "PYI034", # __enter__ return self + "UP037", # quotes in type annotations + "E402", # module level import not at top of file + "E501", # line length handled by formatter +] diff --git a/scripts/run-operational-suite.js b/scripts/run-operational-suite.js index fcc1961c..a198da2b 100644 --- a/scripts/run-operational-suite.js +++ b/scripts/run-operational-suite.js @@ -4,8 +4,7 @@ import { fileURLToPath } from 'url'; import { spawn } from 'child_process'; import readline from 'readline'; import { JSDOM } from 'jsdom'; -import { FORENSIC_MCP_TOOLS, FileStorageProvider } from '../dist/server/mcp-server.js'; -import { PNGBuilder } from '../src/core/png-builder.ts'; +import { FORENSIC_MCP_TOOLS, FileStorageProvider, PNGBuilder } from '../dist/server/mcp-server.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); diff --git a/sdk/python/examples/extension_smoke_test.py b/sdk/python/examples/extension_smoke_test.py index b24222c6..4640b086 100644 --- a/sdk/python/examples/extension_smoke_test.py +++ b/sdk/python/examples/extension_smoke_test.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 """Extension smoke test — the golden v4.1 use case, as a reusable robot. The scenario the TeleDOM owner asked for: "I develop an extension; I want @@ -24,12 +23,13 @@ HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.join(HERE, "..")) -from teledom import Browser, Workflow, TargetMemory # noqa: E402 +from teledom import Browser, TargetMemory, Workflow FIXTURE = os.path.abspath( os.path.join(HERE, "..", "..", "..", "operational-tests", "_fixtures", "dom-fixture.html") ) + def main() -> int: store = tempfile.mkdtemp(prefix="teledom-sdk-demo-") env = { @@ -54,8 +54,10 @@ def main() -> int: # ── LEARN — persist knowledge (agent-owned; TeleDOM just stores) ── mem = TargetMemory(client=browser.client) mem.save( - "example.test", "primary_action_button", - css="#primary-action-btn", aria="Run Analysis", + "example.test", + "primary_action_button", + css="#primary-action-btn", + aria="Run Analysis", identity={"role": "button", "accessibleName": "Run Analysis"}, confidence=0.95, notes="verify with browser.verify(); repair with find()+describe() when the UI changes", @@ -73,13 +75,28 @@ def main() -> int: wf.input("cta_selector", "Primary CTA selector", default="#primary-action-btn") wf.input("counter_selector", "Counter selector", default="#click-counter") wf.step("inspect", "td_dom_inspect", description="observe the page") - wf.step("verify_cta", "td_target_check", args={"selector": "{{inputs.cta_selector}}"}, - description="cheap target check — no DOM re-analysis") + wf.step( + "verify_cta", + "td_target_check", + args={"selector": "{{inputs.cta_selector}}"}, + description="cheap target check — no DOM re-analysis", + ) wf.step("click_cta", "td_action_click", args={"selector": "{{inputs.cta_selector}}"}) - wf.step("extract_counter", "td_dom_extract", - args={"selector": "{{inputs.counter_selector}}", "fields": {"text": "el.textContent.trim()"}}) - wf.step("assert_state", "td_execute_script", - args={"code": 'return document.querySelector("{{inputs.counter_selector}}").textContent.trim();'}) + wf.step( + "extract_counter", + "td_dom_extract", + args={ + "selector": "{{inputs.counter_selector}}", + "fields": {"text": "el.textContent.trim()"}, + }, + ) + wf.step( + "assert_state", + "td_execute_script", + args={ + "code": 'return document.querySelector("{{inputs.counter_selector}}").textContent.trim();' + }, + ) wf.save(version="1.0.0") print("[LEARN] workflow saved (5 steps, 2 templated inputs, policy caps)") @@ -92,9 +109,13 @@ def main() -> int: metrics = body.get("metrics", {}) print(f" runId : {run.get('runId')}") print(f" status : {body.get('status')}") - print(f" steps : {[(s.get('stepId'), s.get('status')) for s in body.get('steps', [])]}") - print(f" metrics : toolCalls={metrics.get('toolCalls')} domScans={metrics.get('domScans')} " - f"duration={metrics.get('durationMs')}ms") + print( + f" steps : {[(s.get('stepId'), s.get('status')) for s in body.get('steps', [])]}" + ) + print( + f" metrics : toolCalls={metrics.get('toolCalls')} domScans={metrics.get('domScans')} " + f"duration={metrics.get('durationMs')}ms" + ) # ── REPLAY — deterministic re-execution of the recorded run ───── replay = wf.replay(run["runId"]) @@ -108,16 +129,20 @@ def main() -> int: check = browser.verify(css) if not check.get("resolvable", False): failures.append(f"recovery check not resolvable: {check}") - print(f"[RECOVERY] : learned locator '{css}' resolvable={check.get('resolvable')} " - f"confidence={check.get('confidence')}") + print( + f"[RECOVERY] : learned locator '{css}' resolvable={check.get('resolvable')} " + f"confidence={check.get('confidence')}" + ) # ── KPI summary (the v4.1 golden demo) ────────────────────────────── print("\n=== KPIs ===") print("first run : 5 tool calls · 2 DOM scans · 5 MCP round trips") - print(f"reuse run : {metrics.get('toolCalls')} tool calls · {metrics.get('domScans')} DOM scans · 1 MCP round trip") - print(f"MCP round-trip reduction: 80% DOM-scan reduction: 50%") + print( + f"reuse run : {metrics.get('toolCalls')} tool calls · {metrics.get('domScans')} DOM scans · 1 MCP round trip" + ) + print("MCP round-trip reduction: 80% DOM-scan reduction: 50%") print(f"tokensSavedEstimate : {metrics.get('tokensSavedEstimate')}") - print(f"unsafe action bypass : 0 (approval gates BLOCK, never auto-approve)") + print("unsafe action bypass : 0 (approval gates BLOCK, never auto-approve)") if failures: print("\nFAILURES:", failures) diff --git a/sdk/python/pyproject.toml b/sdk/python/pyproject.toml index 3f985556..598a8906 100644 --- a/sdk/python/pyproject.toml +++ b/sdk/python/pyproject.toml @@ -25,3 +25,35 @@ Homepage = "https://github.com/IrMaho/TeleDOM" [tool.setuptools.packages.find] include = ["teledom*"] + +[tool.black] +line-length = 100 +target-version = ["py39", "py310", "py311", "py312"] + +[tool.isort] +profile = "black" +line_length = 100 + +[tool.ruff] +line-length = 100 +target-version = "py39" + +[tool.ruff.lint] +select = ["E", "F", "W", "I", "RUF022"] +ignore = [ + "EXE001", + "UP045", + "BLE001", + "S110", + "PYI034", + "UP037", + "E402", + "E501", +] + +[tool.mypy] +python_version = "3.9" +warn_return_any = true +warn_unused_configs = true +disallow_untyped_defs = false +ignore_missing_imports = true diff --git a/sdk/python/teledom/__init__.py b/sdk/python/teledom/__init__.py index 0461d174..68b7284e 100644 --- a/sdk/python/teledom/__init__.py +++ b/sdk/python/teledom/__init__.py @@ -24,19 +24,19 @@ internal tools, sites with no public API at all. """ -from .client import TeleDOMClient, TeleDOMError from .browser import Browser -from .workflow import Workflow, workflows +from .client import TeleDOMClient, TeleDOMError from .targets import TargetMemory +from .workflow import Workflow, workflows __version__ = "4.1.0" __all__ = [ + "Browser", + "TargetMemory", "TeleDOMClient", "TeleDOMError", - "Browser", "Workflow", - "workflows", - "TargetMemory", "__version__", + "workflows", ] diff --git a/sdk/python/teledom/browser.py b/sdk/python/teledom/browser.py index 28738243..a1be53d9 100644 --- a/sdk/python/teledom/browser.py +++ b/sdk/python/teledom/browser.py @@ -1,13 +1,13 @@ """Semantic Browser programming — the TeleDOM Level-2 primitive surface. - browser = Browser() # spawns + connects TeleDOM - browser.navigate("https://any.site") # any website — API never required - page = browser.inspect() # observe (the agent's eyes) - hits = browser.query("Comments") # find elements without selectors - target = browser.find(selector="#reply-box") - browser.click(target) - browser.type(target, "hello") - browser.verify(selector="#sent") +browser = Browser() # spawns + connects TeleDOM +browser.navigate("https://any.site") # any website — API never required +page = browser.inspect() # observe (the agent's eyes) +hits = browser.query("Comments") # find elements without selectors +target = browser.find(selector="#reply-box") +browser.click(target) +browser.type(target, "hello") +browser.verify(selector="#sent") """ from __future__ import annotations @@ -94,7 +94,12 @@ def snapshot(self, fmt: str = "html") -> Any: # ── targeting ────────────────────────────────────────────────────── - def find(self, selector: Optional[str] = None, xpath: Optional[str] = None, text: Optional[str] = None) -> Any: + def find( + self, + selector: Optional[str] = None, + xpath: Optional[str] = None, + text: Optional[str] = None, + ) -> Any: """Find an element by selector / xpath / text → canonical TARGET with confidence.""" args: dict = {} if selector: @@ -109,7 +114,9 @@ def find(self, selector: Optional[str] = None, xpath: Optional[str] = None, text def verify(self, selector: str, min_confidence: float = 0.0) -> Any: """Cheap target verification — replaces full DOM re-analysis.""" - return self._client.call("td_target_check", {"selector": selector, "minConfidence": min_confidence}) + return self._client.call( + "td_target_check", {"selector": selector, "minConfidence": min_confidence} + ) def describe(self, selector: str) -> Any: return self._client.call("td_target_describe", {"selector": selector}) @@ -155,7 +162,9 @@ def execute_script(self, code: str, timeout_ms: Optional[int] = None) -> Any: return self._client.call("td_execute_script", args) def network(self, url_contains: Optional[str] = None, limit: int = 50) -> Any: - return self._client.call("td_network_inspect", {"urlContains": url_contains, "limit": limit}) + return self._client.call( + "td_network_inspect", {"urlContains": url_contains, "limit": limit} + ) def console(self, level: str = "all") -> Any: return self._client.call("td_console_read", {"level": level}) diff --git a/sdk/python/teledom/client.py b/sdk/python/teledom/client.py index 77916c64..7c1675c9 100644 --- a/sdk/python/teledom/client.py +++ b/sdk/python/teledom/client.py @@ -8,9 +8,9 @@ import json import os +import queue import subprocess import threading -import queue from typing import Any, Optional @@ -32,7 +32,9 @@ def __init__( env: Optional[dict] = None, node_binary: str = "node", ): - self.server_path = server_path or os.environ.get("TELEDOM_SERVER_PATH") or self._default_server_path() + self.server_path = ( + server_path or os.environ.get("TELEDOM_SERVER_PATH") or self._default_server_path() + ) self.cwd = cwd self._proc: Optional[subprocess.Popen] = None self._env = env @@ -95,7 +97,13 @@ def _read_stdout(self) -> None: continue if "id" in msg: self._responses.put(msg) - self._responses.put({"jsonrpc": "2.0", "id": -1, "error": {"message": "server closed the stream"}}) + self._responses.put( + { + "jsonrpc": "2.0", + "id": -1, + "error": {"message": "server closed the stream"}, + } + ) def _next_id(self) -> int: with self._lock: @@ -106,7 +114,12 @@ def _next_id(self) -> int: def request(self, method: str, params: Optional[dict] = None, timeout: float = 60.0) -> dict: rid = self._next_id() - payload = {"jsonrpc": "2.0", "id": rid, "method": method, "params": params or {}} + payload = { + "jsonrpc": "2.0", + "id": rid, + "method": method, + "params": params or {}, + } assert self._proc and self._proc.stdin self._proc.stdin.write((json.dumps(payload) + "\n").encode("utf-8")) self._proc.stdin.flush() diff --git a/sdk/python/teledom/targets.py b/sdk/python/teledom/targets.py index 64daa0b2..7ed9497a 100644 --- a/sdk/python/teledom/targets.py +++ b/sdk/python/teledom/targets.py @@ -73,7 +73,9 @@ def list(self, site: Optional[str] = None, semantic_id: Optional[str] = None) -> return self._client.call("td_target_memory_list", args) def delete(self, site: str, semantic_id: str) -> Any: - return self._client.call("td_target_memory_delete", {"site": site, "semanticId": semantic_id}) + return self._client.call( + "td_target_memory_delete", {"site": site, "semanticId": semantic_id} + ) def close(self) -> None: if self._owns_client: diff --git a/sdk/python/teledom/workflow.py b/sdk/python/teledom/workflow.py index 8fc6894c..a97e1afb 100644 --- a/sdk/python/teledom/workflow.py +++ b/sdk/python/teledom/workflow.py @@ -48,8 +48,18 @@ def __init__( # ── authoring ────────────────────────────────────────────────────── - def input(self, name: str, description: str = "", required: bool = False, default: Any = None) -> "Workflow": - self.inputs[name] = {"description": description, "required": required, "default": default} + def input( + self, + name: str, + description: str = "", + required: bool = False, + default: Any = None, + ) -> "Workflow": + self.inputs[name] = { + "description": description, + "required": required, + "default": default, + } return self def step( @@ -63,7 +73,12 @@ def step( timeout_ms: Optional[int] = None, description: str = "", ) -> "Workflow": - s: dict = {"id": step_id, "tool": tool, "onError": on_error, "description": description} + s: dict = { + "id": step_id, + "tool": tool, + "onError": on_error, + "description": description, + } if args: s["args"] = args if retry_count: @@ -114,7 +129,12 @@ def export(self) -> Any: # ── dumb execution + records ─────────────────────────────────────── - def run(self, inputs: Optional[dict] = None, approved_steps: Optional[list] = None, dry_run: bool = False) -> Any: + def run( + self, + inputs: Optional[dict] = None, + approved_steps: Optional[list] = None, + dry_run: bool = False, + ) -> Any: args: dict = {"name": self.name, "inputs": inputs or {}} if approved_steps: args["approvedSteps"] = approved_steps diff --git a/sdk/python/test_sdk.py b/sdk/python/test_sdk.py index 3667378c..6118bcdf 100644 --- a/sdk/python/test_sdk.py +++ b/sdk/python/test_sdk.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 """Self-test for the TeleDOM Python SDK (no pytest required). Runs the full Level-2 surface against the deterministic DOM fixture: @@ -13,9 +12,11 @@ HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, HERE) -from teledom import Browser, TeleDOMError, Workflow, TargetMemory # noqa: E402 +from teledom import Browser, TargetMemory, Workflow -FIXTURE = os.path.abspath(os.path.join(HERE, "..", "..", "operational-tests", "_fixtures", "dom-fixture.html")) +FIXTURE = os.path.abspath( + os.path.join(HERE, "..", "..", "operational-tests", "_fixtures", "dom-fixture.html") +) passed, failed = 0, 0 @@ -40,8 +41,14 @@ def main() -> int: with Browser(env=env) as browser: print("client:") - check("server handshake reports teledom", browser.server_info.get("name") == "teledom") - check("server version is 4.1.x", browser.server_info.get("version", "").startswith("4.1")) + check( + "server handshake reports teledom", + browser.server_info.get("name") == "teledom", + ) + check( + "server version is 4.1.x", + browser.server_info.get("version", "").startswith("4.1"), + ) tools = browser.client.list_tools() check("350 tools exposed over MCP", len(tools) == 350, f"got {len(tools)}") @@ -60,9 +67,17 @@ def main() -> int: print("target memory:") mem = TargetMemory(client=browser.client) - mem.save("example.test", "primary_action_button", css="#primary-action-btn", confidence=0.95) + mem.save( + "example.test", + "primary_action_button", + css="#primary-action-btn", + confidence=0.95, + ) target = mem.get("example.test", "primary_action_button").get("target", {}) - check("learned target persisted", (target.get("locators") or {}).get("css") == "#primary-action-btn") + check( + "learned target persisted", + (target.get("locators") or {}).get("css") == "#primary-action-btn", + ) listing = mem.list(site="example.test") check("target memory list works", listing.get("count", 0) >= 1) @@ -70,15 +85,26 @@ def main() -> int: wf = Workflow("sdk_self_test", client=browser.client, description="SDK self-test workflow") wf.input("selector", "CTA selector", default="#primary-action-btn") wf.step("verify", "td_target_check", args={"selector": "{{inputs.selector}}"}) - wf.step("assert", "td_execute_script", args={"code": 'return document.querySelector("{{inputs.selector}}") !== null;'}) + wf.step( + "assert", + "td_execute_script", + args={"code": 'return document.querySelector("{{inputs.selector}}") !== null;'}, + ) saved = wf.save(version="1.0.0") check("workflow saved verbatim", saved.get("status") == "PASS") run = wf.run() body = run.get("run", {}) - check("dumb execution SUCCESS", body.get("status") == "SUCCESS", str(body.get("error", ""))) + check( + "dumb execution SUCCESS", + body.get("status") == "SUCCESS", + str(body.get("error", "")), + ) check("deterministic record has metrics", "metrics" in body) - check("steps recorded with status", all("status" in s for s in body.get("steps", []))) + check( + "steps recorded with status", + all("status" in s for s in body.get("steps", [])), + ) replay = wf.replay(run["runId"]) check("verbatim replay works", replay.get("status") == "PASS") diff --git a/src/extension/background/service-worker.ts b/src/extension/background/service-worker.ts index 6b8ef8ae..097d4378 100644 --- a/src/extension/background/service-worker.ts +++ b/src/extension/background/service-worker.ts @@ -335,7 +335,11 @@ async function executeBackgroundCommand(command: string, payload: any): Promise< } (chrome as any).debugger.attach({ tabId }, '1.3', () => { if (chrome.runtime.lastError) { - return reject(new Error(`CDP_ATTACH failed: ${chrome.runtime.lastError.message}`)); + const errMsg = chrome.runtime.lastError.message || ''; + if (errMsg.includes('Another debugger is already attached')) { + return reject(new Error(`CDP_ATTACH failed: Chrome DevTools (F12) is already open on tab ${tabId}. Please close the F12 panel on that tab so TeleDOM can attach.`)); + } + return reject(new Error(`CDP_ATTACH failed: ${errMsg}`)); } // Bind the gateway session to this tab (used by CDP_COMMAND/DETACH). if (payload?.sessionId) cdpTargetsBySession.set(String(payload.sessionId), tabId); @@ -598,6 +602,28 @@ function ensureReconnect() { } } +// Manifest V3 Service Worker Keep-Alive via chrome.alarms (prevents 30s idle termination) +if (typeof chrome !== 'undefined' && chrome.alarms) { + try { + chrome.alarms.create('teledom_bridge_keepalive', { periodInMinutes: 0.4 }); + chrome.alarms.onAlarm.addListener((alarm) => { + if (alarm.name === 'teledom_bridge_keepalive') { + if (!wsBridge || wsBridge.readyState !== WebSocket.OPEN) { + connectBridge(); + } else { + try { + wsBridge.send(JSON.stringify({ type: 'HEARTBEAT', timestamp: Date.now() })); + } catch { + connectBridge(); + } + } + } + }); + } catch (err: any) { + console.warn('[ServiceWorker] Alarms keepalive setup failed:', err?.message); + } +} + // Start bridge connection connectBridge(); diff --git a/src/extension/content/content-script.ts b/src/extension/content/content-script.ts index b0865002..686be22c 100644 --- a/src/extension/content/content-script.ts +++ b/src/extension/content/content-script.ts @@ -415,194 +415,8 @@ import { InPageFloatingController } from './floating-controller'; }); } - // Direct WebSocket connection to MCP Bridge for immediate tab communication - let directWs: WebSocket | null = null; - let directReconnectTimer: any = null; - - function connectDirectBridge() { - if (typeof WebSocket === 'undefined') return; - try { - const ws = new WebSocket('ws://127.0.0.1:3847'); - ws.onopen = () => { - directWs = ws; - console.log('[Forensic ContentScript] Connected directly to MCP Bridge on ws://127.0.0.1:3847'); - if (directReconnectTimer) { - clearInterval(directReconnectTimer); - directReconnectTimer = null; - } - ws.send( - JSON.stringify({ - type: 'REGISTER_CLIENT', - clientType: 'CONTENT_SCRIPT', - url: window.location.href, - title: document.title, - }) - ); - }; - - ws.onclose = () => { - directWs = null; - ensureDirectReconnect(); - }; - - ws.onerror = () => { - directWs = null; - ensureDirectReconnect(); - }; - - ws.onmessage = async (event) => { - try { - const message = JSON.parse(event.data.toString()); - if (message.type === 'BROWSER_COMMAND_REQUEST') { - const { id, command, payload } = message; - - // 1. Background commands & Tab management - if (['LIST_TABS', 'OPEN_TAB', 'LIST_EXTENSIONS', 'RELOAD_EXTENSION', 'CLOSE_TAB', 'FOCUS_TAB', 'RELOAD_TAB', 'RESIZE_VIEWPORT', 'RESET_VIEWPORT'].includes(command)) { - if (typeof chrome !== 'undefined' && chrome.runtime?.sendMessage) { - chrome.runtime.sendMessage(message, (res) => { - if (chrome.runtime.lastError) { - // Local fallback if background unreachable - if (command === 'CLOSE_TAB') { - ws.send(JSON.stringify({ type: 'BROWSER_COMMAND_RESPONSE', id, command, success: true, data: { closed: true, url: window.location.href, title: document.title } })); - setTimeout(() => window.close(), 100); - return; - } - if (command === 'RELOAD_TAB') { - ws.send(JSON.stringify({ type: 'BROWSER_COMMAND_RESPONSE', id, command, success: true, data: { reloaded: true, url: window.location.href, title: document.title } })); - setTimeout(() => window.location.reload(), 100); - return; - } - ws.send( - JSON.stringify({ - type: 'BROWSER_COMMAND_RESPONSE', - id, - command, - success: false, - error: { code: 'FORWARD_ERROR', message: chrome.runtime.lastError.message }, - }) - ); - } else { - ws.send(JSON.stringify({ type: 'BROWSER_COMMAND_RESPONSE', ...(res || { id, command, success: true }) })); - } - }); - return; - } - - if (command === 'CLOSE_TAB') { - ws.send(JSON.stringify({ type: 'BROWSER_COMMAND_RESPONSE', id, command, success: true, data: { closed: true, url: window.location.href, title: document.title } })); - setTimeout(() => window.close(), 100); - return; - } - if (command === 'RELOAD_TAB') { - ws.send(JSON.stringify({ type: 'BROWSER_COMMAND_RESPONSE', id, command, success: true, data: { reloaded: true, url: window.location.href, title: document.title } })); - setTimeout(() => window.location.reload(), 100); - return; - } - } - - // 3. GET_TAB_CONSOLE_LOGS - if (command === 'GET_TAB_CONSOLE_LOGS') { - const { level, searchQuery, limit = 100, clearAfterRead } = payload || {}; - let logs = [...liveConsoleLogs]; - if (level && level !== 'all') { - logs = logs.filter((l) => l.level === level); - } - if (searchQuery) { - const q = String(searchQuery).toLowerCase(); - logs = logs.filter((l) => l.text?.toLowerCase().includes(q) || l.source?.toLowerCase().includes(q)); - } - if (limit > 0) { - logs = logs.slice(-limit); - } - if (clearAfterRead) { - liveConsoleLogs.length = 0; - } - ws.send( - JSON.stringify({ - type: 'BROWSER_COMMAND_RESPONSE', - id, - command, - success: true, - data: { - url: window.location.href, - title: document.title, - totalCaptured: liveConsoleLogs.length, - returnedCount: logs.length, - logs, - }, - }) - ); - return; - } - - // 4. GET_TAB_NETWORK_REQUESTS - if (command === 'GET_TAB_NETWORK_REQUESTS') { - const { method, searchQuery, status, onlyErrors, limit = 100, clearAfterRead } = payload || {}; - let reqs = [...liveNetworkRequests]; - if (method) { - reqs = reqs.filter((r) => r.method?.toUpperCase() === String(method).toUpperCase()); - } - if (status) { - reqs = reqs.filter((r) => r.status === Number(status)); - } - if (onlyErrors) { - reqs = reqs.filter((r) => r.error || (r.status && r.status >= 400)); - } - if (searchQuery) { - const q = String(searchQuery).toLowerCase(); - reqs = reqs.filter((r) => r.url?.toLowerCase().includes(q)); - } - if (limit > 0) { - reqs = reqs.slice(-limit); - } - if (clearAfterRead) { - liveNetworkRequests.length = 0; - } - ws.send( - JSON.stringify({ - type: 'BROWSER_COMMAND_RESPONSE', - id, - command, - success: true, - data: { - url: window.location.href, - title: document.title, - totalCaptured: liveNetworkRequests.length, - returnedCount: reqs.length, - requests: reqs, - }, - }) - ); - return; - } - - // 5. DOM Commands - const res = await liveController.handleCommand(message, document); - ws.send(JSON.stringify(res)); - } - } catch (err: any) { - console.error('[Forensic ContentScript] Bridge message error:', err); - } - }; - } catch { - directWs = null; - ensureDirectReconnect(); - } - } - - function ensureDirectReconnect() { - if (!directReconnectTimer) { - directReconnectTimer = setInterval(() => { - if (!directWs || directWs.readyState !== WebSocket.OPEN) { - connectDirectBridge(); - } - }, 4000); - } - } - - // Initialize + // Initialize injected page script injectPageScript(); - connectDirectBridge(); if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initAutoReconnect); diff --git a/src/forensics/handler.ts b/src/forensics/handler.ts index dc0b7e5f..0d371171 100644 --- a/src/forensics/handler.ts +++ b/src/forensics/handler.ts @@ -445,7 +445,8 @@ export class ForensicsToolsHandler { try { const res = await unifiedRuntime.bridgeCommand('LIVE_DOM_SNAPSHOT', { format: 'json' }); return { snapshot: res }; - } catch { + } catch (err: any) { + console.warn(`[ForensicsHandler] Could not capture live snapshot: ${err?.message || err}`); return { snapshot: null }; } } @@ -455,7 +456,8 @@ async function runInPageSafe(code: string, tabId?: number): Promise(file: string): T | null { try { return JSON.parse(fs.readFileSync(file, 'utf-8')) as T; - } catch { + } catch (err: any) { + if (err?.code !== 'ENOENT') { + console.warn(`[WorkflowStore] Warning: Failed to read or parse ${file}:`, err?.message || err); + } return null; } } @@ -157,7 +160,10 @@ export class AgentStore { private listJsonNames(dir: string): string[] { try { return fs.readdirSync(dir).filter((f) => f.endsWith('.json')).sort(); - } catch { + } catch (err: any) { + if (err?.code !== 'ENOENT') { + console.warn(`[WorkflowStore] Warning: Failed to list directory ${dir}:`, err?.message || err); + } return []; } } diff --git a/src/mcp/bridge-server.ts b/src/mcp/bridge-server.ts index 689336c6..20347ad0 100644 --- a/src/mcp/bridge-server.ts +++ b/src/mcp/bridge-server.ts @@ -104,17 +104,19 @@ export class MCPBridgeServer implements BrowserBridgeClient { } } - // If no service worker connected, fallback to CONTENT_SCRIPT sockets + // If no service worker connected, fallback to a single primary CONTENT_SCRIPT socket (never broadcast commands to all tabs) if (targets.length === 0) { for (const [sock, meta] of this.socketMetadata.entries()) { if (meta.clientType === 'CONTENT_SCRIPT' && sock.readyState === WebSocket.OPEN) { - targets.push(sock); + targets = [sock]; + break; } } } - if (targets.length === 0) { - targets = Array.from(this.activeSockets); + if (targets.length === 0 && this.activeSockets.size > 0) { + const first = Array.from(this.activeSockets).find((s) => s.readyState === WebSocket.OPEN); + if (first) targets = [first]; } let sentCount = 0; @@ -142,11 +144,28 @@ export class MCPBridgeServer implements BrowserBridgeClient { public start(): Promise { return new Promise((resolve, reject) => { + const isTrustedOrigin = (origin?: string): boolean => { + if (!origin) return true; // Direct non-browser callers (Node, curl, stdio MCP) + if (origin.startsWith('chrome-extension://')) return true; + if (/^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/.test(origin)) return true; + return false; + }; + this.httpServer = http.createServer(async (req, res) => { - // Enable CORS - res.setHeader('Access-Control-Allow-Origin', '*'); + const origin = req.headers.origin; + if (origin) { + if (isTrustedOrigin(origin)) { + res.setHeader('Access-Control-Allow-Origin', origin); + res.setHeader('Access-Control-Allow-Credentials', 'true'); + res.setHeader('Vary', 'Origin'); + } else if (req.method === 'OPTIONS') { + res.writeHead(403, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify({ error: 'CORS Forbidden: Untrusted cross-origin request rejected' })); + return; + } + } res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); - res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); + res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, x-teledom-token'); if (req.method === 'OPTIONS') { res.writeHead(204); @@ -156,9 +175,29 @@ export class MCPBridgeServer implements BrowserBridgeClient { const url = req.url || ''; + // Security check for mutating and sensitive endpoints + const isAuthValid = (): boolean => { + if (!isTrustedOrigin(origin)) return false; + const expectedToken = process.env.TELEDOM_BRIDGE_TOKEN; + if (!expectedToken) return true; + const authHeader = req.headers.authorization; + const tokenHeader = req.headers['x-teledom-token']; + let queryToken: string | null = null; + try { + const parsed = new URL(url, 'http://127.0.0.1'); + queryToken = parsed.searchParams.get('token'); + } catch { /* ignored */ } + if (authHeader && authHeader.startsWith('Bearer ')) { + return authHeader.slice(7).trim() === expectedToken; + } + if (tokenHeader && tokenHeader === expectedToken) return true; + if (queryToken && queryToken === expectedToken) return true; + return false; + }; + // 1. Health check (v4.1 fix E-17: version derived from the // authoritative registry — was stale '3.0.0') - if (url === '/health' && req.method === 'GET') { + if (url.startsWith('/health') && req.method === 'GET') { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end( JSON.stringify({ @@ -171,6 +210,15 @@ export class MCPBridgeServer implements BrowserBridgeClient { return; } + // Enforce authorization for sensitive endpoints + if (['/api/mcp/tool', '/api/tabs/close', '/api/sessions/upload'].some(p => url.startsWith(p))) { + if (!isAuthValid()) { + res.writeHead(403, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify({ error: 'Forbidden: Invalid or missing authorization credentials' })); + return; + } + } + const MAX_PAYLOAD_BYTES = 50 * 1024 * 1024; // 50MB limit // 2. Upload Session Bundle @@ -301,7 +349,13 @@ export class MCPBridgeServer implements BrowserBridgeClient { }, 30000); (this.healthSweepInterval as any)?.unref?.(); - this.wss.on('connection', (ws: WebSocket) => { + this.wss.on('connection', (ws: WebSocket, req: http.IncomingMessage) => { + const origin = req?.headers?.origin; + if (origin && !isTrustedOrigin(origin)) { + console.error(`[MCP Bridge] WebSocket connection rejected from untrusted origin: ${origin}`); + ws.close(4403, 'Forbidden origin'); + return; + } this.activeSockets.add(ws); console.error(`[MCP Bridge] Client connected. Total active clients: ${this.activeSockets.size}`); diff --git a/src/mcp/live-tools-handler.ts b/src/mcp/live-tools-handler.ts index 021a0908..0510fcaa 100644 --- a/src/mcp/live-tools-handler.ts +++ b/src/mcp/live-tools-handler.ts @@ -687,8 +687,18 @@ export class LiveToolsHandler { }, ], }; - } catch { - // Fallthrough + } catch (saveErr: any) { + return { + content: [ + { + type: 'text', + text: JSON.stringify({ + ...finalSummary, + fileSaveError: `Failed to write pipeline output to ${args.outputPath}: ${saveErr?.message || saveErr}`, + }, null, 2), + }, + ], + }; } } diff --git a/src/mcp/server.ts b/src/mcp/server.ts index e76ef4f8..892e30bd 100644 --- a/src/mcp/server.ts +++ b/src/mcp/server.ts @@ -11,8 +11,10 @@ import { LiveToolsHandler, BrowserBridgeClient } from './live-tools-handler'; import { MCPBridgeServer } from './bridge-server'; import { BrowserCommandType } from '../types/browser-control'; import { TELEDOM_VERSION } from '../intelligence/version'; +import { TELEDOM_PROFILE_TOOLS } from './tool-groups'; +import { PNGBuilder } from '../core/png-builder'; -export { FORENSIC_MCP_TOOLS, FileStorageProvider, MCPToolsHandler }; +export { FORENSIC_MCP_TOOLS, FileStorageProvider, MCPToolsHandler, TELEDOM_PROFILE_TOOLS, PNGBuilder }; export class ForensicMCPServer { private storage: ForensicStorageProvider; @@ -208,12 +210,21 @@ export class ForensicMCPServer { const disableDevTools = process.env.FORENSIC_DISABLE_DEVTOOLS === 'true'; const disableForensics = process.env.FORENSIC_DISABLE_FORENSICS === 'true'; const disableIntelligence = process.env.FORENSIC_DISABLE_INTELLIGENCE === 'true'; - const tools = FORENSIC_MCP_TOOLS.filter( + const profile = (process.env.TELEDOM_PROFILE || 'full').toLowerCase(); + const profileAllowed = TELEDOM_PROFILE_TOOLS[profile]; + + let tools = FORENSIC_MCP_TOOLS.filter( (t) => !(disableDevTools && t.name.startsWith('dt_')) && !(disableForensics && t.name.startsWith('fx_')) && !(disableIntelligence && t.name.startsWith('td_')), ); + + if (profileAllowed && Array.isArray(profileAllowed)) { + const allowedSet = new Set(profileAllowed); + tools = tools.filter((t) => allowedSet.has(t.name)); + } + return { jsonrpc: '2.0', id, diff --git a/src/mcp/tool-groups.ts b/src/mcp/tool-groups.ts index 68b3179c..27a81d5b 100644 --- a/src/mcp/tool-groups.ts +++ b/src/mcp/tool-groups.ts @@ -225,3 +225,41 @@ export function buildToolCatalog(): ToolDiscoveryInfo[] { export function findGroupOfTool(toolName: string): ToolGroupInfo | undefined { return TOOL_GROUPS.find((g) => g.tools.includes(toolName)); } + +export type TeledomProfileName = 'minimal' | 'core' | 'forensics' | 'full'; + +export const TELEDOM_PROFILE_TOOLS: Record = { + // Minimal profile: strictly essential browser actions (~22 tools, ~2.5k tokens) + minimal: [ + 'td_browser_navigate', 'td_browser_back', 'td_browser_forward', 'td_browser_refresh', + 'td_dom_inspect', 'td_dom_query', 'td_dom_extract', 'td_dom_snapshot', + 'td_target_find', 'td_target_check', + 'td_action_click', 'td_action_type', 'td_action_select', 'td_action_press', 'td_action_scroll', + 'td_wait', 'td_screenshot', 'td_execute_script', + 'list_tabs', 'focus_tab', 'close_tab', 'open_tab', + ], + // Core profile: browser primitives + workflow runtime + target memory (~44 tools, ~4.8k tokens) + core: [ + 'td_browser_navigate', 'td_browser_back', 'td_browser_forward', 'td_browser_refresh', + 'td_dom_inspect', 'td_dom_query', 'td_dom_extract', 'td_dom_snapshot', + 'td_target_find', 'td_target_check', 'td_target_describe', + 'td_action_click', 'td_action_type', 'td_action_select', 'td_action_hover', 'td_action_press', 'td_action_scroll', + 'td_wait', 'td_screenshot', 'td_execute_script', 'td_network_inspect', 'td_console_read', + 'td_workflow_save', 'td_workflow_get', 'td_workflow_list', 'td_workflow_update', 'td_workflow_delete', + 'td_workflow_validate', 'td_workflow_run', 'td_workflow_runs', 'td_workflow_replay', + 'td_target_memory_save', 'td_target_memory_get', 'td_target_memory_list', 'td_target_memory_delete', + 'list_tabs', 'focus_tab', 'reload_tab', 'close_tab', 'open_tab', + 'inspect_live_page', 'inspect_live_element', + ], + // Forensics profile: historical forensics + diffs + causality + live inspection (~50 tools) + forensics: [ + 'list_sessions', 'get_session', 'export_session', 'import_session', 'delete_session', + 'get_timeline', 'get_events', 'get_events_around', 'get_dom_state', 'get_dom_node', 'get_dom_subtree', + 'diff_dom', 'trace_element', 'find_disappearing_elements', 'why_did_element_disappear', + 'get_diagnostics', 'get_network_events', 'get_screenshots', + 'td_browser_navigate', 'td_dom_inspect', 'td_dom_query', 'td_dom_extract', 'td_screenshot', + 'td_action_click', 'td_action_type', 'td_workflow_run', 'list_tabs', 'focus_tab', + ], + // Full profile: all 350 tools (null means no filtering) + full: null, +}; diff --git a/src/projects/project-manager.ts b/src/projects/project-manager.ts index 1c1fe945..0965b1b6 100644 --- a/src/projects/project-manager.ts +++ b/src/projects/project-manager.ts @@ -124,8 +124,8 @@ export class ProjectManager { try { const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8')); out.push({ ...manifest, projectDir: path.join(this.baseDir, entry.name), pageCount: manifest.pages?.length || 0 }); - } catch { - // Corrupt manifest — skip but do not crash the listing + } catch (err) { + console.warn(`[ProjectManager] Warning: Skipped corrupt project manifest at ${manifestPath}:`, err); } } return out.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0)); @@ -443,7 +443,9 @@ export class ProjectManager { if (fs.existsSync(p)) { try { out.push(JSON.parse(fs.readFileSync(p, 'utf-8'))); - } catch { /* skip corrupt */ } + } catch (err) { + console.warn(`[ProjectManager] Warning: Skipped corrupt region file ${p}:`, err); + } } } return out; diff --git a/src/storage/file-storage.ts b/src/storage/file-storage.ts index f119386f..e19033ed 100644 --- a/src/storage/file-storage.ts +++ b/src/storage/file-storage.ts @@ -1,6 +1,5 @@ import * as fs from 'fs'; import * as path from 'path'; -import * as readline from 'readline'; import { Annotation, SessionMetadata } from '../types/session'; import { BaseEvent } from '../types/events'; import { SnapshotCheckpoint } from '../types/checkpoint'; @@ -28,47 +27,54 @@ export class FileStorageProvider implements ForensicStorageProvider { public async saveSession(metadata: SessionMetadata): Promise { const dir = this.getSessionDir(metadata.id); const metaPath = path.join(dir, 'metadata.json'); - fs.writeFileSync(metaPath, JSON.stringify(metadata, null, 2), 'utf-8'); + await fs.promises.writeFile(metaPath, JSON.stringify(metadata, null, 2), 'utf-8'); } public async getSession(sessionId: string): Promise { const dir = path.join(this.baseDir, sessionId); const metaPath = path.join(dir, 'metadata.json'); - if (!fs.existsSync(metaPath)) return null; try { - const data = fs.readFileSync(metaPath, 'utf-8'); + const data = await fs.promises.readFile(metaPath, 'utf-8'); return JSON.parse(data) as SessionMetadata; - } catch { + } catch (err: any) { + if (err?.code !== 'ENOENT') { + console.warn(`[FileStorage] Warning: Failed to read session ${sessionId}: ${err?.message}`); + } return null; } } public async listSessions(): Promise { if (!fs.existsSync(this.baseDir)) return []; - const entries = fs.readdirSync(this.baseDir, { withFileTypes: true }); - const sessions: SessionMetadata[] = []; + try { + const entries = await fs.promises.readdir(this.baseDir, { withFileTypes: true }); + const sessions: SessionMetadata[] = []; - for (const entry of entries) { - if (entry.isDirectory()) { - const metaPath = path.join(this.baseDir, entry.name, 'metadata.json'); - if (fs.existsSync(metaPath)) { + for (const entry of entries) { + if (entry.isDirectory()) { + const metaPath = path.join(this.baseDir, entry.name, 'metadata.json'); try { - const data = fs.readFileSync(metaPath, 'utf-8'); + const data = await fs.promises.readFile(metaPath, 'utf-8'); sessions.push(JSON.parse(data) as SessionMetadata); - } catch { - // Corrupt file skipped + } catch (err: any) { + if (err?.code !== 'ENOENT') { + console.warn(`[FileStorage] Warning: Corrupt or unreadable session metadata at ${metaPath}: ${err?.message}`); + } } } } - } - return sessions.sort((a, b) => b.startTime - a.startTime); + return sessions.sort((a, b) => b.startTime - a.startTime); + } catch (err: any) { + console.error(`[FileStorage] Failed to list sessions from ${this.baseDir}:`, err?.message); + return []; + } } public async deleteSession(sessionId: string): Promise { const dir = path.join(this.baseDir, sessionId); if (fs.existsSync(dir)) { - fs.rmSync(dir, { recursive: true, force: true }); + await fs.promises.rm(dir, { recursive: true, force: true, maxRetries: 10, retryDelay: 50 }); return true; } return false; @@ -79,7 +85,7 @@ export class FileStorageProvider implements ForensicStorageProvider { const dir = this.getSessionDir(sessionId); const eventsPath = path.join(dir, 'events.jsonl'); const lines = events.map((e) => JSON.stringify(e)).join('\n') + '\n'; - fs.appendFileSync(eventsPath, lines, 'utf-8'); + await fs.promises.appendFile(eventsPath, lines, 'utf-8'); } public async getEvents(sessionId: string, filter?: EventFilter): Promise { @@ -87,25 +93,23 @@ export class FileStorageProvider implements ForensicStorageProvider { const eventsPath = path.join(dir, 'events.jsonl'); if (!fs.existsSync(eventsPath)) return []; - const fileStream = fs.createReadStream(eventsPath, { encoding: 'utf-8' }); - const rl = readline.createInterface({ - input: fileStream, - crlfDelay: Infinity, - }); + const content = await fs.promises.readFile(eventsPath, 'utf-8'); + const lines = content.split(/\r?\n/); const results: BaseEvent[] = []; let matchedCount = 0; const offset = typeof filter?.offset === 'number' ? filter.offset : 0; const limit = typeof filter?.limit === 'number' ? filter.limit : Infinity; - for await (const line of rl) { + for (const line of lines) { const trimmed = line.trim(); if (!trimmed) continue; let e: BaseEvent; try { e = JSON.parse(trimmed); - } catch { + } catch (parseErr) { + console.warn(`[FileStorage] Skipping malformed event line in session ${sessionId}:`, parseErr); continue; } @@ -135,8 +139,6 @@ export class FileStorageProvider implements ForensicStorageProvider { results.push(e); if (results.length >= limit) { - rl.close(); - fileStream.destroy(); break; } } @@ -149,14 +151,9 @@ export class FileStorageProvider implements ForensicStorageProvider { const eventsPath = path.join(dir, 'events.jsonl'); if (!fs.existsSync(eventsPath)) return 0; - const fileStream = fs.createReadStream(eventsPath, { encoding: 'utf-8' }); - const rl = readline.createInterface({ - input: fileStream, - crlfDelay: Infinity, - }); - + const content = await fs.promises.readFile(eventsPath, 'utf-8'); let count = 0; - for await (const line of rl) { + for (const line of content.split(/\r?\n/)) { if (line.trim()) count++; } return count; @@ -165,44 +162,52 @@ export class FileStorageProvider implements ForensicStorageProvider { public async saveCheckpoint(checkpoint: SnapshotCheckpoint): Promise { const dir = this.getSessionDir(checkpoint.sessionId); const chkDir = path.join(dir, 'checkpoints'); - if (!fs.existsSync(chkDir)) fs.mkdirSync(chkDir, { recursive: true }); + await fs.promises.mkdir(chkDir, { recursive: true }); const file = path.join(chkDir, `${checkpoint.checkpointId}.json`); - fs.writeFileSync(file, JSON.stringify(checkpoint, null, 2), 'utf-8'); + await fs.promises.writeFile(file, JSON.stringify(checkpoint, null, 2), 'utf-8'); } public async getCheckpoints(sessionId: string): Promise { const dir = path.join(this.baseDir, sessionId, 'checkpoints'); - if (!fs.existsSync(dir)) return []; - - const files = fs.readdirSync(dir).filter((f) => f.endsWith('.json')); - const checkpoints: SnapshotCheckpoint[] = []; + try { + const files = (await fs.promises.readdir(dir)).filter((f) => f.endsWith('.json')); + const checkpoints: SnapshotCheckpoint[] = []; + + for (const f of files) { + try { + const data = await fs.promises.readFile(path.join(dir, f), 'utf-8'); + checkpoints.push(JSON.parse(data)); + } catch (err) { + console.warn(`[FileStorage] Failed to read/parse checkpoint file ${f} in session ${sessionId}:`, err); + } + } - for (const f of files) { - try { - const data = fs.readFileSync(path.join(dir, f), 'utf-8'); - checkpoints.push(JSON.parse(data)); - } catch { - // Ignored + return checkpoints.sort((a, b) => a.sequence - b.sequence); + } catch (err: any) { + if (err?.code !== 'ENOENT') { + console.warn(`[FileStorage] Error accessing checkpoints directory for session ${sessionId}:`, err); } + return []; } - - return checkpoints.sort((a, b) => a.sequence - b.sequence); } public async saveInitialSnapshot(sessionId: string, snapshot: DOMSnapshot): Promise { const dir = this.getSessionDir(sessionId); const file = path.join(dir, 'initial_snapshot.json'); - fs.writeFileSync(file, JSON.stringify(snapshot, null, 2), 'utf-8'); + await fs.promises.writeFile(file, JSON.stringify(snapshot, null, 2), 'utf-8'); } public async getInitialSnapshot(sessionId: string): Promise { const dir = path.join(this.baseDir, sessionId); const file = path.join(dir, 'initial_snapshot.json'); - if (!fs.existsSync(file)) return null; try { - return JSON.parse(fs.readFileSync(file, 'utf-8')) as DOMSnapshot; - } catch { + const content = await fs.promises.readFile(file, 'utf-8'); + return JSON.parse(content) as DOMSnapshot; + } catch (err: any) { + if (err?.code !== 'ENOENT') { + console.warn(`[FileStorage] Error reading initial snapshot for session ${sessionId}:`, err); + } return null; } } @@ -211,24 +216,29 @@ export class FileStorageProvider implements ForensicStorageProvider { const dir = this.getSessionDir(annotation.sessionId); const annPath = path.join(dir, 'annotations.json'); let list: Annotation[] = []; - if (fs.existsSync(annPath)) { - try { - list = JSON.parse(fs.readFileSync(annPath, 'utf-8')); - } catch { - list = []; + try { + const content = await fs.promises.readFile(annPath, 'utf-8'); + list = JSON.parse(content); + } catch (err: any) { + if (err?.code !== 'ENOENT') { + console.warn(`[FileStorage] Corrupted annotations file for session ${annotation.sessionId}, starting fresh:`, err); } + list = []; } list.push(annotation); - fs.writeFileSync(annPath, JSON.stringify(list, null, 2), 'utf-8'); + await fs.promises.writeFile(annPath, JSON.stringify(list, null, 2), 'utf-8'); } public async getAnnotations(sessionId: string): Promise { const dir = path.join(this.baseDir, sessionId); const annPath = path.join(dir, 'annotations.json'); - if (!fs.existsSync(annPath)) return []; try { - return JSON.parse(fs.readFileSync(annPath, 'utf-8')) as Annotation[]; - } catch { + const content = await fs.promises.readFile(annPath, 'utf-8'); + return JSON.parse(content) as Annotation[]; + } catch (err: any) { + if (err?.code !== 'ENOENT') { + console.warn(`[FileStorage] Failed to read annotations for session ${sessionId}:`, err); + } return []; } } diff --git a/src/storage/recording-storage.ts b/src/storage/recording-storage.ts index 80d9fe65..9ee8e94c 100644 --- a/src/storage/recording-storage.ts +++ b/src/storage/recording-storage.ts @@ -33,7 +33,8 @@ export class CommandRecordingStorage { try { const raw = JSON.parse(fs.readFileSync(file, 'utf-8')); return raw.recording || raw; - } catch { + } catch (err) { + console.warn(`[RecordingStorage] Warning: Failed to parse recording file ${file}:`, err); return null; } } @@ -63,8 +64,8 @@ export class CommandRecordingStorage { tags: rec.tags || [], file: path.join(this.baseDir, entry.name), }); - } catch { - // skip corrupt files + } catch (err) { + console.warn(`[RecordingStorage] Warning: Skipped corrupt recording file ${entry.name}:`, err); } } return out.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0)); diff --git a/tests/integration/storage.test.ts b/tests/integration/storage.test.ts index 7cd8e0a1..ffe4c205 100644 --- a/tests/integration/storage.test.ts +++ b/tests/integration/storage.test.ts @@ -174,8 +174,12 @@ describe('Storage Providers (Memory & File)', () => { expect(userPaged.every((e) => e.category === 'USER')).toBe(true); } finally { if (fs.existsSync(testDir)) { - fs.rmSync(testDir, { recursive: true, force: true }); + try { + fs.rmSync(testDir, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }); + } catch { + // Allow transient lock in Windows test runners to drain + } } } - }); + }, 30_000); }); diff --git a/tests/intelligence/workflow.test.ts b/tests/intelligence/workflow.test.ts index 7d4fe5c4..4585128a 100644 --- a/tests/intelligence/workflow.test.ts +++ b/tests/intelligence/workflow.test.ts @@ -31,7 +31,13 @@ beforeEach(() => { afterEach(() => { delete process.env.TELEDOM_AGENT_STORE_DIR; - fs.rmSync(tmpDir, { recursive: true, force: true }); + if (tmpDir && fs.existsSync(tmpDir)) { + try { + fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 10, retryDelay: 50 }); + } catch { + // Allow transient lock in Windows test runners to drain + } + } }); function makeWorkflow(overrides: Partial = {}): AgentWorkflow { diff --git a/vitest.config.ts b/vitest.config.ts index e10ac743..94a6e247 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -5,5 +5,7 @@ export default defineConfig({ environment: 'jsdom', include: ['tests/**/*.test.ts'], exclude: ['dist/**', 'node_modules/**'], + testTimeout: 30000, + hookTimeout: 30000, }, });