diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..d50f1055 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,68 @@ +# Dependencies +**/node_modules/ +npm-debug.log* +pnpm-debug.log* + +# Build outputs (will be built in Docker) +**/dist/ + +# Environment files +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# IDE files +.vscode/ +.idea/ +*.swp +*.swo + +# OS files +.DS_Store +Thumbs.db + +# Git +.git/ +.gitignore +.gitattributes + +# Documentation (except README) +*.md +!README.md + +# Test files +test/ +**/test/ +*.test.* +*.spec.* + +# Coverage +coverage/ +**/coverage/ + +# Logs +logs/ +*.log + +# Docker +Dockerfile* +.dockerignore +docker-compose*.yml + +# CI/CD +.github/ + +# Agent and plan files +.dotagent/ + +# Extension package (not needed for server) +packages/extension/ + +# CLI source (only package.json needed for workspace) +packages/cli/src/ +packages/cli/dist/ + +# Scripts +scripts/ diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml new file mode 100644 index 00000000..0698e521 --- /dev/null +++ b/.github/workflows/build-and-test.yml @@ -0,0 +1,331 @@ +name: Build & Test + +on: + push: + branches: [main, develop] + pull_request: + branches: [main, develop] + +permissions: + contents: read + pull-requests: read + +jobs: + detect-changes: + runs-on: ubuntu-latest + outputs: + core: ${{ steps.filter.outputs.core }} + cli: ${{ steps.filter.outputs.cli }} + server: ${{ steps.filter.outputs.server }} + extension: ${{ steps.filter.outputs.extension }} + workflows: ${{ steps.filter.outputs.workflows }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Detect file changes + uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + core: + - 'packages/core/**' + cli: + - 'packages/cli/**' + server: + - 'packages/server/**' + extension: + - 'packages/extension/**' + workflows: + - '.github/workflows/**' + + setup: + runs-on: ubuntu-latest + needs: [detect-changes] + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Setup pnpm + uses: pnpm/action-setup@v2 + with: + version: 9 + + - name: Get pnpm store directory + shell: bash + run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - name: Cache pnpm store + uses: actions/cache@v4 + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + # Install is fast (pnpm store is cached) but needed to create workspace symlinks + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build core package + run: pnpm --filter spark-core build + + - name: Cache core build + uses: actions/cache@v4 + with: + path: packages/core/dist + key: ${{ runner.os }}-core-dist-${{ github.sha }} + + - name: Check formatting + run: pnpm format:check + + core: + runs-on: ubuntu-latest + needs: [detect-changes, setup] + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Setup pnpm + uses: pnpm/action-setup@v2 + with: + version: 9 + + - name: Get pnpm store directory + shell: bash + run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - name: Cache pnpm store + uses: actions/cache@v4 + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + # Install is fast (pnpm store is cached) but needed to create workspace symlinks + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Cache core build + uses: actions/cache@v4 + with: + path: packages/core/dist + key: ${{ runner.os }}-core-dist-${{ github.sha }} + + - name: Typecheck core + run: pnpm --filter spark-core run typecheck + + - name: Test core + if: needs.detect-changes.outputs.core == 'true' || needs.detect-changes.outputs.workflows == 'true' + run: pnpm --filter spark-core run test + + cli: + runs-on: ubuntu-latest + needs: [detect-changes, setup] + if: needs.detect-changes.outputs.cli == 'true' || needs.detect-changes.outputs.core == 'true' || needs.detect-changes.outputs.workflows == 'true' + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Setup pnpm + uses: pnpm/action-setup@v2 + with: + version: 9 + + - name: Get pnpm store directory + shell: bash + run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - name: Cache pnpm store + uses: actions/cache@v4 + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + # Install is fast (pnpm store is cached) but needed to create workspace symlinks + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Cache core build + uses: actions/cache@v4 + with: + path: packages/core/dist + key: ${{ runner.os }}-core-dist-${{ github.sha }} + + - name: Typecheck CLI + run: pnpm --filter spark-cli run typecheck + + - name: Test CLI + run: pnpm --filter spark-cli run test + + - name: Build CLI + run: pnpm --filter spark-cli run build + + server: + runs-on: ubuntu-latest + needs: [detect-changes, setup] + if: needs.detect-changes.outputs.server == 'true' || needs.detect-changes.outputs.core == 'true' || needs.detect-changes.outputs.workflows == 'true' + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Setup pnpm + uses: pnpm/action-setup@v2 + with: + version: 9 + + - name: Get pnpm store directory + shell: bash + run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - name: Cache pnpm store + uses: actions/cache@v4 + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + # Install is fast (pnpm store is cached) but needed to create workspace symlinks + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Cache core build + uses: actions/cache@v4 + with: + path: packages/core/dist + key: ${{ runner.os }}-core-dist-${{ github.sha }} + + - name: Typecheck server + run: pnpm --filter @spark/server run typecheck + + - name: Test server + run: pnpm --filter @spark/server run test + + - name: Build server + run: pnpm --filter @spark/server run build + + extension: + runs-on: ubuntu-latest + needs: [detect-changes, setup] + if: needs.detect-changes.outputs.extension == 'true' || needs.detect-changes.outputs.core == 'true' || needs.detect-changes.outputs.workflows == 'true' + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Setup pnpm + uses: pnpm/action-setup@v2 + with: + version: 9 + + - name: Get pnpm store directory + shell: bash + run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - name: Cache pnpm store + uses: actions/cache@v4 + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + # Install is fast (pnpm store is cached) but needed to create workspace symlinks + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Cache core build + uses: actions/cache@v4 + with: + path: packages/core/dist + key: ${{ runner.os }}-core-dist-${{ github.sha }} + + - name: Typecheck extension + run: pnpm --filter spark-extension run typecheck + + - name: Test extension + run: pnpm --filter spark-extension run test + + - name: Build extension for Firefox + run: pnpm --filter spark-extension run build:firefox + + - name: Build extension for Chrome + run: pnpm --filter spark-extension run build:chrome + + - name: Get Playwright version + id: playwright-version + run: | + set -euo pipefail + if [ ! -f packages/extension/package.json ]; then + echo "Error: packages/extension/package.json not found" >&2 + exit 1 + fi + version=$(jq -re '.devDependencies["@playwright/test"] // empty' packages/extension/package.json) + if [ -z "$version" ]; then + echo "Error: @playwright/test devDependency not found in packages/extension/package.json" >&2 + exit 1 + fi + echo "version=$version" >> "$GITHUB_OUTPUT" + + - name: Cache Playwright browsers + uses: actions/cache@v4 + id: playwright-cache + with: + path: ~/.cache/ms-playwright + key: ${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.version }} + + - name: Install Playwright browsers + if: steps.playwright-cache.outputs.cache-hit != 'true' + run: pnpm --filter spark-extension exec playwright install --with-deps chromium + + - name: Install Playwright system dependencies + if: steps.playwright-cache.outputs.cache-hit == 'true' + run: pnpm --filter spark-extension exec playwright install-deps chromium + + - name: Run extension e2e tests + run: pnpm --filter spark-extension run test:e2e:headless:chrome + + - name: Upload Playwright report + uses: actions/upload-artifact@v4 + if: ${{ !cancelled() }} + with: + name: playwright-report + path: packages/extension/playwright-report/ + retention-days: 30 + + - name: Upload Playwright test results + uses: actions/upload-artifact@v4 + if: ${{ !cancelled() }} + with: + name: playwright-test-results + path: packages/extension/test-results/ + retention-days: 30 + if-no-files-found: ignore diff --git a/.github/workflows/ci.yml b/.github/workflows/deps_check.yml similarity index 78% rename from .github/workflows/ci.yml rename to .github/workflows/deps_check.yml index 575fc458..05a504a1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/deps_check.yml @@ -1,4 +1,4 @@ -name: CI +name: Dependency Version Check on: push: @@ -7,7 +7,7 @@ on: branches: [main, develop] jobs: - ci: + check-deps: runs-on: ubuntu-latest steps: @@ -40,14 +40,5 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile - - name: Check formatting - run: pnpm run format:check - - - name: Run type check - run: pnpm run typecheck - - - name: Run tests - run: pnpm test - - - name: Build project - run: pnpm run build + - name: Check dependency versions + run: node scripts/check-deps.js diff --git a/.github/workflows/extension_ci.yml b/.github/workflows/extension_ci.yml deleted file mode 100644 index 2538e52a..00000000 --- a/.github/workflows/extension_ci.yml +++ /dev/null @@ -1,131 +0,0 @@ -name: Extension CI - -on: - push: - branches: [main, develop] - paths: - - "extension/**" - - "src/**" - - "package.json" - - "pnpm-lock.yaml" - - ".github/workflows/extension_ci.yml" - pull_request: - branches: [main, develop] - paths: - - "extension/**" - - "src/**" - - "package.json" - - "pnpm-lock.yaml" - - ".github/workflows/extension_ci.yml" - -jobs: - extension-ci: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: "22" - - # For some reason, `pnpm run format:check` blows up in CI if we let - # the version here match the one that we are running (pnpm 9.0.0 as of this writing), - # and if we leave it at 8, things are ok. - # XXX once we upgrade to pnpm 10, we should try making this match - - name: Setup pnpm - uses: pnpm/action-setup@v2 - with: - version: 9 - - - name: Get pnpm store directory - shell: bash - run: | - echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - - name: Setup pnpm cache - uses: actions/cache@v3 - with: - path: ${{ env.STORE_PATH }} - key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store- - - - name: Install all dependencies - run: pnpm install --frozen-lockfile - - - name: Build core package - run: pnpm run clean && pnpm run build - - # Re-run install to resolve package exports now that dist/ exists. - # pnpm resolves exports during install, but dist/ is only created - # (and not resolved) by the build step above. - - name: Re-link workspace dependencies - run: pnpm install - - - name: Check extension formatting - run: pnpm --filter spark-extension run format:check - - - name: Run extension type check - run: pnpm --filter spark-extension run typecheck - - - name: Run extension tests - run: pnpm --filter spark-extension test - - - name: Build extension for Firefox - run: pnpm --filter spark-extension run build:firefox - - - name: Build extension for Chrome - run: pnpm --filter spark-extension run build:chrome - - - name: Get Playwright version - id: playwright-version - run: | - set -euo pipefail - if [ ! -f extension/package.json ]; then - echo "Error: extension/package.json not found" >&2 - exit 1 - fi - version=$(jq -re '.devDependencies["@playwright/test"] // empty' extension/package.json) - if [ -z "$version" ]; then - echo "Error: @playwright/test devDependency not found in extension/package.json" >&2 - exit 1 - fi - echo "version=$version" >> "$GITHUB_OUTPUT" - - - name: Cache Playwright browsers - uses: actions/cache@v4 - id: playwright-cache - with: - path: ~/.cache/ms-playwright - key: ${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.version }} - - - name: Install Playwright browsers - if: steps.playwright-cache.outputs.cache-hit != 'true' - run: pnpm --filter spark-extension exec playwright install --with-deps chromium - - - name: Install Playwright system dependencies - if: steps.playwright-cache.outputs.cache-hit == 'true' - run: pnpm --filter spark-extension exec playwright install-deps chromium - - - name: Run extension e2e tests - run: pnpm --filter spark-extension run test:e2e:headless:chrome - - - name: Upload Playwright report - uses: actions/upload-artifact@v4 - if: ${{ !cancelled() }} - with: - name: playwright-report - path: extension/playwright-report/ - retention-days: 30 - - - name: Upload Playwright test results - uses: actions/upload-artifact@v4 - if: ${{ !cancelled() }} - with: - name: playwright-test-results - path: extension/test-results/ - retention-days: 30 - if-no-files-found: ignore diff --git a/.github/workflows/gar_image_push.yml b/.github/workflows/gar_image_push.yml index dd6f0541..615f1922 100644 --- a/.github/workflows/gar_image_push.yml +++ b/.github/workflows/gar_image_push.yml @@ -44,7 +44,7 @@ jobs: project_id: moz-fx-tabs-prod should_tag_latest: true image_build_context: . - dockerfile_path: "./server/Dockerfile" + dockerfile_path: "./packages/server/Dockerfile" - name: Push the Docker image to GAR uses: mozilla-it/deploy-actions/docker-push@v4.3.2 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 394afab1..9fae3623 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -42,10 +42,10 @@ jobs: run: pnpm install --frozen-lockfile - name: Run tests - run: pnpm test + run: pnpm -r run test - name: Build project - run: pnpm run build + run: pnpm --filter spark-core build - name: Create package tarball run: npm pack @@ -53,8 +53,8 @@ jobs: - name: Get package info id: package run: | - echo "name=$(node -p "require('./package.json').name")" >> $GITHUB_OUTPUT - echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT + echo "name=$(node -p "require('./packages/core/package.json').name")" >> $GITHUB_OUTPUT + echo "version=$(node -p "require('./packages/core/package.json').version")" >> $GITHUB_OUTPUT - name: Create Release run: | diff --git a/.github/workflows/server_ci.yml b/.github/workflows/server_ci.yml deleted file mode 100644 index e6ec0588..00000000 --- a/.github/workflows/server_ci.yml +++ /dev/null @@ -1,75 +0,0 @@ -name: Server CI - -on: - push: - branches: [main, develop] - paths: - - "server/**" - - "src/**" - - "package.json" - - "pnpm-lock.yaml" - - ".github/workflows/server_ci.yml" - pull_request: - branches: [main, develop] - paths: - - "server/**" - - "src/**" - - "package.json" - - "pnpm-lock.yaml" - - ".github/workflows/server_ci.yml" - -jobs: - server-ci: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: "22" - - - name: Setup pnpm - uses: pnpm/action-setup@v2 - with: - version: 9 - - - name: Get pnpm store directory - shell: bash - run: | - echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - - name: Setup pnpm cache - uses: actions/cache@v3 - with: - path: ${{ env.STORE_PATH }} - key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store- - - - name: Install root dependencies and build main package - run: | - pnpm install --frozen-lockfile - pnpm run build - - - name: Install server dependencies - working-directory: ./server - run: pnpm install --frozen-lockfile - - - name: Check server formatting - working-directory: ./server - run: pnpm run format:check - - - name: Run server type check - working-directory: ./server - run: pnpm run typecheck - - - name: Run server tests - working-directory: ./server - run: pnpm test - - - name: Build server - working-directory: ./server - run: pnpm run build diff --git a/.gitignore b/.gitignore index 7e2871d1..151ef69a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ dist scripts/docker-build.sh debug coverage + +# Auto-generated aria tree bundle +packages/core/src/browser/ariaTree/bundle.ts diff --git a/.prettierignore b/.prettierignore index ac0195dc..7bcc72b4 100644 --- a/.prettierignore +++ b/.prettierignore @@ -6,13 +6,11 @@ yarn.lock # Build outputs dist/ build/ +.output/ +.wxt/ # Generated bundles src/browser/ariaTree/bundle.ts # Dependencies -node_modules/ - -# Subprojects -extension/ -server/ \ No newline at end of file +node_modules/ \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index 6e65abe3..d405a420 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,12 +2,12 @@ ## Project Overview -Spark is an AI-powered web automation library and CLI tool that lets you control browsers using natural language. The project consists of: +Spark is an AI-powered web automation library and CLI tool that lets you control browsers using natural language. The project is organized as a pnpm monorepo with the following packages: -- **Core library** (`src/`) - Main automation engine -- **CLI** (`src/cli/`) - Command-line interface -- **Extension** (`extension/`) - Browser extension -- **Server** (`server/`) - Server component +- **Core library** (`packages/core/`) - Main automation engine (spark-core) +- **CLI** (`packages/cli/`) - Command-line interface (@tabstack/spark) +- **Extension** (`packages/extension/`) - Browser extension (spark-extension) +- **Server** (`packages/server/`) - Server component (@spark/server) ## Common Commands @@ -33,7 +33,8 @@ pnpm check # Run format + typecheck + test (full validation) ```bash pnpm spark # Run spark CLI locally (uses tsx) pnpm spark run "task" # Run an automation task -pnpm spark config # Configure AI provider settings +pnpm spark config init # Create config file +pnpm spark config show # View current settings ``` ### Installation & Setup @@ -46,16 +47,32 @@ pnpm install-cli # Build and install CLI globally ## Project Structure -- `src/` - Core library source code - - `browser/` - Browser automation implementations - - `cli/` - CLI commands and configuration - - `tools/` - AI agent tools - - `utils/` - Utility functions -- `test/` - Test files (mirrors src structure) -- `extension/` - Browser extension code -- `server/` - Server component -- `docs/` - Documentation -- `scripts/` - Build and deployment scripts +``` +spark/ +├── package.json # Workspace root (format scripts only) +├── pnpm-workspace.yaml +├── packages/ +│ ├── core/ # Main library (spark-core) +│ │ ├── package.json +│ │ ├── tsconfig.json +│ │ ├── src/ # Core library source code +│ │ │ ├── browser/ # Browser automation implementations +│ │ │ ├── config/ # Configuration system (modular) +│ │ │ ├── tools/ # AI agent tools +│ │ │ └── utils/ # Utility functions +│ │ └── test/ # Test files (mirrors src structure) +│ ├── cli/ # CLI tool (@tabstack/spark) +│ │ ├── package.json +│ │ └── src/ +│ ├── server/ # Server component (@spark/server) +│ │ ├── package.json +│ │ └── src/ +│ └── extension/ # Browser extension (spark-extension) +│ ├── package.json +│ └── src/ +├── docs/ # Documentation +└── scripts/ # Build and deployment scripts +``` ## Development Workflow @@ -66,6 +83,35 @@ pnpm install-cli # Build and install CLI globally - Run `pnpm test` to verify tests pass 3. **Full validation**: Run `pnpm check` (does all three) +### Working in the Monorepo + +**From root:** + +- `pnpm format` - Format all code +- `pnpm format:check` - Check formatting +- `pnpm spark ` - Run CLI locally +- `pnpm -r run test` - Run all tests +- `pnpm -r run typecheck` - Typecheck all packages +- `pnpm -F spark-core run test` - Run tests for specific package + +**From a package directory (e.g., `cd packages/core`):** + +- `pnpm test` - Run tests +- `pnpm test:watch` - Run tests in watch mode +- `pnpm typecheck` - Run type checking +- `pnpm build` - Build the package + +### Package Dependencies + +- CLI, server, and extension depend on `spark-core` via workspace protocol +- Use `"spark-core": "workspace:*"` in package.json + +### Import Style + +- All imports use `.js` extensions (NodeNext module resolution) +- No barrel imports (no index.ts re-export files) +- Import directly from specific files: `import { foo } from "spark-core/utils/foo.js"` + ## Testing - Tests use Vitest @@ -82,7 +128,32 @@ Spark supports multiple AI providers: - Ollama - Vertex AI -Configure with: `pnpm spark config --init` +### Configuration System + +The configuration system has been refactored into a modular architecture in `packages/core/src/config/`: + +- **defaults.ts**: Type definitions, field definitions, and default values (browser-compatible) +- **configManager.ts**: Singleton config manager with build-mode-aware resolution +- **globalConfig.ts**: File I/O operations with XDG-compliant paths (`~/.config/spark/`) +- **envParser.ts**: Environment variable parsing and normalization +- **helpers.ts**: CLI option generation utilities +- **index.ts**: Public exports + +### Config Commands + +Configuration is now managed via subcommands: + +```bash +pnpm spark config init # Create empty config file +pnpm spark config show # Display current config +pnpm spark config set = # Set a value +pnpm spark config get # Get a value +pnpm spark config reset # Reset to defaults +``` + +**Config file location**: `~/.config/spark/config.json` (XDG-compliant on Linux/macOS) + +In production mode (when installed via npm), the CLI requires a config file to exist. Run `spark config init` to create one. ## Security - Secret Scanning diff --git a/README.md b/README.md index cc47dbdc..c59315d4 100644 --- a/README.md +++ b/README.md @@ -18,52 +18,47 @@ Spark is part of [Tabstack](https://tabstack.ai), Mozilla's browsing infrastruct ## Requirements - **[Node.js 22+](https://nodejs.org/)** - JavaScript runtime -- **[pnpm](https://pnpm.io/installation)** - Package manager (npm and yarn also work but pnpm is recommended) - **AI Provider (one of):** - [OpenAI API key](https://platform.openai.com/api-keys) (cloud) - [OpenRouter API key](https://openrouter.ai/keys) (cloud) - [Ollama](https://ollama.ai) running locally (local) - [LM Studio](https://lmstudio.ai) server (local) - Google Cloud project with Vertex AI enabled -- **Browsers:** Automatically installed by Playwright (Firefox, Chrome, Safari, Edge) +- **Browsers:** Automatically installed when you first run Spark (Firefox, Chrome, Safari, Edge) ## Quick Start ### Installation ```bash -# Clone the repository -git clone https://github.com/Mozilla-Ocho/spark.git -cd spark - -# Install dependencies -pnpm install +# Install globally +npm install -g @tabstack/spark -# Install browsers for automation -pnpm playwright install +# Or use npx (no installation required) +npx @tabstack/spark -# Setup AI provider -pnpm spark config --init +# Initialize configuration +spark config init # Run your first task -pnpm spark run "what's the weather in Tokyo?" +spark run "what's the weather in Tokyo?" ``` ### Basic Usage ```bash # Simple web queries -pnpm spark run "find the latest news on Reuters" -pnpm spark run "what's the current price of AAPL stock?" +spark run "find the latest news on Reuters" +spark run "what's the current price of AAPL stock?" # With specific starting URL -pnpm spark run "find flight deals to Paris" --url https://booking.com/ +spark run "find flight deals to Paris" --url https://booking.com/ # With structured data -pnpm spark run "book a flight" --url https://booking.com/ --data '{"from":"NYC","to":"LAX","date":"2024-12-25"}' +spark run "book a flight" --url https://booking.com/ --data '{"from":"NYC","to":"LAX","date":"2024-12-25"}' # With safety constraints -pnpm spark run "search hotels in Tokyo" --guardrails "browse only, don't book anything" +spark run "search hotels in Tokyo" --guardrails "browse only, don't book anything" ``` ## Features @@ -80,7 +75,15 @@ pnpm spark run "search hotels in Tokyo" --guardrails "browse only, don't book an ### CLI Installation -See [Quick Start](#quick-start) above for CLI installation instructions. +```bash +# Install globally +npm install -g @tabstack/spark + +# Or use npx (no installation required) +npx @tabstack/spark +``` + +See [Quick Start](#quick-start) above for complete setup instructions. ### Browser Extension @@ -113,7 +116,7 @@ For detailed extension development instructions, see [extension/README.md](exten **Basic syntax:** ```bash -pnpm spark run "" [options] +spark run "" [options] ``` See [Configuration Reference](#configuration-reference) for all available options. @@ -121,15 +124,17 @@ See [Configuration Reference](#configuration-reference) for all available option **Configuration:** ```bash -pnpm spark config --init # Setup wizard -pnpm spark config --show # View current settings -pnpm spark config --reset # Clear all settings +spark config init # Create config file +spark config show # View current settings +spark config set = # Set a value +spark config get # Get a value +spark config reset # Clear all settings ``` ### Programmatic Usage ```javascript -import { WebAgent, PlaywrightBrowser } from "spark"; +import { WebAgent, PlaywrightBrowser } from "@tabstack/spark"; import { openai } from "@ai-sdk/openai"; const browser = new PlaywrightBrowser({ headless: false }); @@ -156,23 +161,23 @@ try { ### Simple Tasks ```bash -pnpm spark run "is it raining in London?" -pnpm spark run "what's trending on Hacker News?" -pnpm spark run "find the contact email for example.com" +spark run "is it raining in London?" +spark run "what's trending on Hacker News?" +spark run "find the contact email for example.com" ``` ### With URLs ```bash -pnpm spark run "find flight deals" --url https://kayak.com -pnpm spark run "check if items are in stock" --url https://store.com +spark run "find flight deals" --url https://kayak.com +spark run "check if items are in stock" --url https://store.com ``` ### With Structured Data ```bash # Hotel search -pnpm spark run "find hotels" --url https://booking.com --data '{ +spark run "find hotels" --url https://booking.com --data '{ "location": "Paris", "checkIn": "2024-12-20", "checkOut": "2024-12-22", @@ -180,7 +185,7 @@ pnpm spark run "find hotels" --url https://booking.com --data '{ }' # Form filling -pnpm spark run "submit contact form" --url https://company.com/contact --data '{ +spark run "submit contact form" --url https://company.com/contact --data '{ "name": "John Doe", "email": "john@example.com", "message": "Hello world" @@ -191,41 +196,41 @@ pnpm spark run "submit contact form" --url https://company.com/contact --data '{ ```bash # Browse-only mode -pnpm spark run "research product prices" --guardrails "only browse, don't buy anything" +spark run "research product prices" --guardrails "only browse, don't buy anything" # Domain restrictions -pnpm spark run "find company info" --url https://company.com --guardrails "stay on current domain only" +spark run "find company info" --url https://company.com --guardrails "stay on current domain only" # Form restrictions -pnpm spark run "check shipping costs" --guardrails "don't submit any payment forms" +spark run "check shipping costs" --guardrails "don't submit any payment forms" ``` ### Advanced Options ```bash # Run a vanilla Firefox with WebDriver BiDi as protocol -pnpm spark run "test checkout flow" --channel moz-firefox +spark run "test checkout flow" --channel moz-firefox # Use a specific browser executable -pnpm spark run "test with custom Firefox" --executable-path /usr/bin/firefox +spark run "test with custom Firefox" --executable-path /usr/bin/firefox # Chrome browser testing -pnpm spark run "test checkout flow" --browser chrome --headless +spark run "test checkout flow" --browser chrome --headless # Headless automation -pnpm spark run "get daily stock prices" --headless --browser firefox +spark run "get daily stock prices" --headless --browser firefox # Debug mode -pnpm spark run "complex automation task" --debug +spark run "complex automation task" --debug # Vision mode for complex visual layouts -pnpm spark run "fill out complex form" --vision +spark run "fill out complex form" --vision # Enhanced reasoning for complex tasks -pnpm spark run "research and compare insurance plans" --reasoning-effort high +spark run "research and compare insurance plans" --reasoning-effort high # Combined options -pnpm spark run "test signup flow" \ +spark run "test signup flow" \ --url https://app.com \ --browser safari \ --headless \ @@ -237,52 +242,55 @@ pnpm spark run "test signup flow" \ ```bash # Using an HTTP proxy -pnpm spark run "search for products" --proxy http://proxy.company.com:8080 +spark run "search for products" --proxy http://proxy.company.com:8080 # Using authenticated proxy -pnpm spark run "access internal site" \ +spark run "access internal site" \ --proxy http://proxy.company.com:8080 \ --proxy-username myuser \ --proxy-password mypass # Using SOCKS5 proxy -pnpm spark run "secure browsing" --proxy socks5://127.0.0.1:1080 +spark run "secure browsing" --proxy socks5://127.0.0.1:1080 ``` ## Configuration -Spark supports multiple AI providers and stores configuration globally: +Spark supports multiple AI providers and stores configuration in `~/.config/spark/config.json`: ```bash -# Setup wizard (recommended for first use) -pnpm spark config --init +# Create config file (recommended for first use) +spark config init # Manual configuration -pnpm spark config --set provider=openai -pnpm spark config --set openai_api_key=sk-your-key +spark config set provider=openai +spark config set openai_api_key=sk-your-key # Or use OpenRouter -pnpm spark config --set provider=openrouter -pnpm spark config --set openrouter_api_key=sk-or-your-key +spark config set provider=openrouter +spark config set openrouter_api_key=sk-or-your-key # Or use local AI providers -pnpm spark config --set provider=ollama -pnpm spark config --set model=llama3.2 +spark config set provider=ollama +spark config set model=llama3.2 -pnpm spark config --set provider=lmstudio -pnpm spark config --set model=your-loaded-model +spark config set provider=lmstudio +spark config set model=your-loaded-model # Set defaults -pnpm spark config --set browser=chrome -pnpm spark config --set headless=true -pnpm spark config --set vision=true -pnpm spark config --set reasoning_effort=medium +spark config set browser=chrome +spark config set headless=true +spark config set vision=true +spark config set reasoning_effort=medium # View settings -pnpm spark config --show +spark config show + +# Get specific value +spark config get provider # Reset everything -pnpm spark config --reset +spark config reset ``` **Available AI Providers:** @@ -300,7 +308,7 @@ See [Configuration Priority](#configuration-priority) for how settings are resol ### WebAgent ```javascript -import { WebAgent, PlaywrightBrowser } from "spark"; +import { WebAgent, PlaywrightBrowser } from "@tabstack/spark"; import { openai } from "@ai-sdk/openai"; const browser = new PlaywrightBrowser({ headless: false }); @@ -350,10 +358,20 @@ new PlaywrightBrowser({ Built with TypeScript, Playwright, and the Vercel AI SDK. -### Running the CLI in Development +### Setup for Contributors ```bash -# Run without building +# Clone the repository +git clone https://github.com/Mozilla-Ocho/spark.git +cd spark + +# Install dependencies (requires pnpm for monorepo) +pnpm install + +# Install Playwright browsers +pnpm playwright install + +# Run CLI locally in development mode pnpm spark run "your task here" ``` @@ -544,14 +562,13 @@ Configuration values are resolved in the following order (highest to lowest prio 1. **Command-line options** - Directly passed to the command 2. **Environment variables** - Set in your shell or `.env` file -3. **Local `.env` file** - In your project directory -4. **Global config file** - Set via `pnpm spark config --set` +3. **Global config file** - Stored at `~/.config/spark/config.json` ### Examples ```bash # Using CLI options -pnpm spark run "search for flights" \ +spark run "search for flights" \ --url https://airline.com \ --browser chrome \ --headless \ @@ -563,17 +580,17 @@ export SPARK_PROVIDER=openrouter export SPARK_MODEL=claude-3.5-sonnet export SPARK_BROWSER=firefox export SPARK_HEADLESS=true -pnpm spark run "book a hotel" +spark run "book a hotel" # Mixed usage (CLI options override environment variables) export SPARK_BROWSER=firefox -pnpm spark run "search products" --browser chrome # Will use chrome +spark run "search products" --browser chrome # Will use chrome # Setting defaults via config -pnpm spark config --set browser=chrome -pnpm spark config --set headless=true -pnpm spark config --set vision=true -pnpm spark run "test task" # Uses configured defaults +spark config set browser=chrome +spark config set headless=true +spark config set vision=true +spark run "test task" # Uses configured defaults ``` ## Sharp Edges & Limitations diff --git a/extension/pnpm-workspace.yaml b/extension/pnpm-workspace.yaml deleted file mode 100644 index b9cc1a7c..00000000 --- a/extension/pnpm-workspace.yaml +++ /dev/null @@ -1,4 +0,0 @@ -onlyBuiltDependencies: - - "@tailwindcss/oxide" - - esbuild - - spawn-sync diff --git a/package.json b/package.json index 1e9b80a4..cff8893c 100644 --- a/package.json +++ b/package.json @@ -1,50 +1,24 @@ { - "name": "spark", + "name": "spark-workspace", + "description": "Spark monorepo workspace", + "private": true, "version": "0.12.1", - "description": "AI-powered web automation library and CLI tool", - "main": "dist/index.js", - "types": "dist/index.d.ts", "type": "module", "engines": { "node": "^22.0.0" }, - "bin": { - "spark": "./dist/cli.js" - }, - "exports": { - ".": { - "types": "./dist/index.d.ts", - "import": "./dist/index.js" - }, - "./core": { - "types": "./dist/core.d.ts", - "import": "./dist/core.js" - }, - "./ariaTree": { - "types": "./dist/browser/ariaTree/index.d.ts", - "import": "./dist/browser/ariaTree/index.js" - } - }, - "files": [ - "dist/**/*", - "README.md", - "LICENSE" - ], "scripts": { - "clean": "rm -rf dist", - "bundle:aria": "tsx scripts/bundle-aria-tree.ts", - "build": "pnpm run bundle:aria && tsc", - "typecheck": "tsc --project tsconfig.check.json", - "prepare": "npm run build", - "prepublishOnly": "npm run build", - "spark": "NODE_NO_WARNINGS=1 tsx src/cli.ts", - "test": "vitest run", - "test:watch": "vitest", - "install-cli": "npm run build && chmod +x dist/cli.js && npm install -g .", + "clean": "pnpm -r run clean", + "build": "pnpm -r run build", + "typecheck": "pnpm -r run typecheck", + "spark": "pnpm --filter @tabstack/spark run spark", + "test": "pnpm -r run test", + "test:watch": "pnpm -r run test:watch", + "install-cli": "pnpm --filter @tabstack/spark run build && pnpm install -g ./packages/cli", "format": "prettier --write . --list-different", "format:check": "prettier --check .", "release": "./scripts/release.sh", - "check": "pnpm run format && pnpm run typecheck && pnpm test" + "check": "pnpm run format && pnpm run typecheck && pnpm run test" }, "keywords": [ "ai", @@ -57,37 +31,7 @@ "author": "", "license": "MIT", "devDependencies": { - "@types/jsdom": "^27.0.0", - "@types/node": "^25.2.0", - "@types/turndown": "^5.0.6", - "@vitest/coverage-v8": "^4.0.18", - "esbuild": "^0.27.3", - "jsdom": "^28.0.0", - "nodemon": "^3.1.11", - "prettier": "^3.8.1", - "tsx": "^4.21.0", - "typescript": "^5.9.3", - "vitest": "^4.0.18" - }, - "dependencies": { - "@ai-sdk/google": "^3.0.20", - "@ai-sdk/google-vertex": "^4.0.41", - "@ai-sdk/openai": "^3.0.25", - "@ai-sdk/openai-compatible": "^2.0.26", - "@ghostery/adblocker-playwright": "^2.13.4", - "@openrouter/ai-sdk-provider": "^2.1.1", - "ai": "^6.0.69", - "chalk": "^5.6.2", - "commander": "^14.0.3", - "cross-fetch": "^4.1.0", - "dotenv": "^17.2.3", - "eventemitter3": "^5.0.4", - "liquidjs": "^10.24.0", - "nanoid": "^5.1.6", - "ollama-ai-provider-v2": "^3.0.3", - "playwright": "1.58.1", - "turndown": "^7.2.2", - "zod": "^4.3.6" + "prettier": "^3.8.1" }, "packageManager": "pnpm@9.0.0" } diff --git a/packages/cli/package.json b/packages/cli/package.json new file mode 100644 index 00000000..1d286350 --- /dev/null +++ b/packages/cli/package.json @@ -0,0 +1,36 @@ +{ + "name": "@spark/cli", + "version": "0.12.0", + "description": "Spark CLI - AI-powered web automation tool", + "type": "module", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "bin": { + "spark": "./dist/cli.js" + }, + "engines": { + "node": "^22.0.0" + }, + "scripts": { + "build": "tsup", + "prebuild": "pnpm --filter spark-core build", + "clean": "rm -rf dist", + "typecheck": "tsc --noEmit", + "dev": "tsx src/cli.ts", + "test": "vitest run", + "test:watch": "vitest" + }, + "dependencies": { + "chalk": "^5.6.2", + "commander": "^14.0.3", + "spark-core": "workspace:*" + }, + "devDependencies": { + "@types/node": "^25.2.0", + "tsup": "^8.3.5", + "tsx": "^4.21.0", + "typescript": "^5.9.3", + "vitest": "^4.0.18" + }, + "packageManager": "pnpm@9.0.0" +} diff --git a/src/cli.ts b/packages/cli/src/cli.ts similarity index 77% rename from src/cli.ts rename to packages/cli/src/cli.ts index d75aa9b4..52925ba7 100644 --- a/src/cli.ts +++ b/packages/cli/src/cli.ts @@ -1,10 +1,10 @@ #!/usr/bin/env node import { Command } from "commander"; -import { createRunCommand } from "./cli/commands/run.js"; -import { createConfigCommand } from "./cli/commands/config.js"; -import { createExamplesCommand } from "./cli/commands/examples.js"; -import { getPackageInfo } from "./cli/utils.js"; +import { createRunCommand } from "./commands/run.js"; +import { createConfigCommand } from "./commands/config.js"; +import { createExamplesCommand } from "./commands/examples.js"; +import { getPackageInfo } from "./utils.js"; /** * Spark CLI - AI-powered web automation tool diff --git a/src/cli/commands/config.ts b/packages/cli/src/commands/config.ts similarity index 98% rename from src/cli/commands/config.ts rename to packages/cli/src/commands/config.ts index dc5dc3d0..9266b8d3 100644 --- a/src/cli/commands/config.ts +++ b/packages/cli/src/commands/config.ts @@ -1,8 +1,8 @@ import chalk from "chalk"; import { Command } from "commander"; import { existsSync, unlinkSync } from "fs"; -import { config } from "../../config.js"; -import { getAIProviderInfo } from "../provider.js"; +import { config } from "spark-core/config.js"; +import { getAIProviderInfo } from "spark-core/provider.js"; import { getPackageInfo, parseConfigKeyValue, parseConfigValue } from "../utils.js"; /** diff --git a/src/cli/commands/examples.ts b/packages/cli/src/commands/examples.ts similarity index 100% rename from src/cli/commands/examples.ts rename to packages/cli/src/commands/examples.ts diff --git a/src/cli/commands/run.ts b/packages/cli/src/commands/run.ts similarity index 91% rename from src/cli/commands/run.ts rename to packages/cli/src/commands/run.ts index a16e26b1..10abc20c 100644 --- a/src/cli/commands/run.ts +++ b/packages/cli/src/commands/run.ts @@ -1,18 +1,18 @@ import chalk from "chalk"; import { Command } from "commander"; -import { WebAgent } from "../../webAgent.js"; -import { PlaywrightBrowser } from "../../browser/playwrightBrowser.js"; -import { config, addConfigOptions } from "../../config.js"; +import { WebAgent } from "spark-core/webAgent.js"; +import { PlaywrightBrowser } from "spark-core/browser/playwrightBrowser.js"; +import { config, addConfigOptions } from "spark-core/config.js"; import { validateBrowser, getValidBrowsers, parseJsonData, parseResourcesList } from "../utils.js"; -import { createAIProvider } from "../provider.js"; -import { ChalkConsoleLogger } from "../../loggers/chalkConsole.js"; -import { JSONConsoleLogger } from "../../loggers/json.js"; -import { WebAgentEventType, WebAgentEventEmitter } from "../../events.js"; +import { createAIProvider } from "spark-core/provider.js"; +import { ChalkConsoleLogger } from "spark-core/loggers/chalkConsole.js"; +import { JSONConsoleLogger } from "spark-core/loggers/json.js"; +import { WebAgentEventType, WebAgentEventEmitter } from "spark-core/events.js"; import * as fs from "fs"; import * as path from "path"; -import { MetricsCollector } from "../../loggers/metricsCollector.js"; -import { Logger } from "../../loggers/types.js"; -import { SecretsRedactor } from "../../loggers/secretsRedactor.js"; +import { MetricsCollector } from "spark-core/loggers/metricsCollector.js"; +import { Logger } from "spark-core/loggers/types.js"; +import { SecretsRedactor } from "spark-core/loggers/secretsRedactor.js"; /** * Creates the 'run' command for executing web automation tasks. diff --git a/packages/cli/src/provider.ts b/packages/cli/src/provider.ts new file mode 100644 index 00000000..98ea42df --- /dev/null +++ b/packages/cli/src/provider.ts @@ -0,0 +1,2 @@ +// Re-export shared provider system +export { createAIProvider, getAIProviderInfo } from "spark/provider.js"; diff --git a/src/cli/utils.ts b/packages/cli/src/utils.ts similarity index 98% rename from src/cli/utils.ts rename to packages/cli/src/utils.ts index 08f0d207..29146523 100644 --- a/src/cli/utils.ts +++ b/packages/cli/src/utils.ts @@ -11,7 +11,7 @@ import { fileURLToPath } from "url"; */ export function getPackageInfo(): { version: string; name: string; description: string } { const __dirname = dirname(fileURLToPath(import.meta.url)); - const packageJson = JSON.parse(readFileSync(join(__dirname, "../../package.json"), "utf-8")); + const packageJson = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8")); return { version: packageJson.version, diff --git a/test/cli/commands/run.test.ts b/packages/cli/test/commands/run.test.ts similarity index 93% rename from test/cli/commands/run.test.ts rename to packages/cli/test/commands/run.test.ts index efc58918..71947ef1 100644 --- a/test/cli/commands/run.test.ts +++ b/packages/cli/test/commands/run.test.ts @@ -1,13 +1,13 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import { Command } from "commander"; -import { createRunCommand } from "../../../src/cli/commands/run.js"; -import { getConfigDefaults } from "../../../src/config.js"; +import { createRunCommand } from "../../src/commands/run.js"; +import { getConfigDefaults } from "spark-core/config.js"; // Get defaults from schema (used for mocking config.getConfig) const schemaDefaults = getConfigDefaults(); // Mock all the dependencies -vi.mock("../../../src/webAgent.js", () => ({ +vi.mock("spark-core/webAgent.js", () => ({ WebAgent: vi.fn().mockImplementation(function () { return { execute: vi.fn().mockResolvedValue({ @@ -19,15 +19,15 @@ vi.mock("../../../src/webAgent.js", () => ({ }), })); -vi.mock("../../../src/browser/playwrightBrowser.js", () => ({ +vi.mock("spark-core/browser/playwrightBrowser.js", () => ({ PlaywrightBrowser: vi.fn().mockImplementation(function () { return {}; }), })); // Mock the config module to avoid fs dependencies -vi.mock("../../../src/config.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("spark-core/config.js", async (importOriginal) => { + const actual = await importOriginal(); // Return DEFAULTS from getConfig so run command gets proper default values return { ...actual, @@ -38,23 +38,23 @@ vi.mock("../../../src/config.js", async (importOriginal) => { }; }); -vi.mock("../../../src/provider.js", () => ({ +vi.mock("spark-core/provider.js", () => ({ createAIProvider: vi.fn(() => ({})), })); -vi.mock("../../../src/loggers/chalkConsole.js", () => ({ +vi.mock("spark-core/loggers/chalkConsole.js", () => ({ ChalkConsoleLogger: vi.fn().mockImplementation(function () { return {}; }), })); -vi.mock("../../../src/loggers/json.js", () => ({ +vi.mock("spark-core/loggers/json.js", () => ({ JSONConsoleLogger: vi.fn().mockImplementation(function () { return {}; }), })); -vi.mock("../../../src/cli/utils.js", () => ({ +vi.mock("../../src/utils.js", () => ({ validateBrowser: vi.fn(() => true), getValidBrowsers: vi.fn(() => ["firefox", "chrome", "chromium"]), parseJsonData: vi.fn((data) => JSON.parse(data)), @@ -76,7 +76,7 @@ vi.mock("fs", async (importOriginal) => { }); // Mock WebAgentEventEmitter -vi.mock("../../../src/events.js", () => ({ +vi.mock("spark-core/events.js", () => ({ WebAgentEventType: { AI_GENERATION: "ai:generation", }, @@ -88,13 +88,13 @@ vi.mock("../../../src/events.js", () => ({ }), })); -import { WebAgent } from "../../../src/webAgent.js"; -import { PlaywrightBrowser } from "../../../src/browser/playwrightBrowser.js"; -import { config } from "../../../src/config.js"; -import { createAIProvider } from "../../../src/provider.js"; -import { ChalkConsoleLogger } from "../../../src/loggers/chalkConsole.js"; -import { JSONConsoleLogger } from "../../../src/loggers/json.js"; -import { WebAgentEventEmitter } from "../../../src/events.js"; +import { WebAgent } from "spark-core/webAgent.js"; +import { PlaywrightBrowser } from "spark-core/browser/playwrightBrowser.js"; +import { config } from "spark-core/config.js"; +import { createAIProvider } from "spark-core/provider.js"; +import { ChalkConsoleLogger } from "spark-core/loggers/chalkConsole.js"; +import { JSONConsoleLogger } from "spark-core/loggers/json.js"; +import { WebAgentEventEmitter } from "spark-core/events.js"; import * as fs from "fs"; const mockWebAgent = vi.mocked(WebAgent); @@ -521,7 +521,7 @@ describe("CLI Run Command", () => { describe("Error Handling", () => { it("should handle invalid JSON data", async () => { // Mock parseJsonData to throw an error - const { parseJsonData } = await import("../../../src/cli/utils.js"); + const { parseJsonData } = await import("../../src/utils.js"); vi.mocked(parseJsonData).mockImplementation(() => { throw new Error("Invalid JSON"); }); @@ -543,7 +543,7 @@ describe("CLI Run Command", () => { it("should handle WebAgent execution errors", async () => { // Reset validateBrowser to return true so we get past browser validation - const { validateBrowser } = await import("../../../src/cli/utils.js"); + const { validateBrowser } = await import("../../src/utils.js"); vi.mocked(validateBrowser).mockReturnValue(true); const mockWebAgentInstance = { diff --git a/test/cli/config.test.ts b/packages/cli/test/config.test.ts similarity index 97% rename from test/cli/config.test.ts rename to packages/cli/test/config.test.ts index cd68a779..838eba60 100644 --- a/test/cli/config.test.ts +++ b/packages/cli/test/config.test.ts @@ -1,12 +1,12 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; -import { type SparkConfigResolved, getConfigDefaults } from "../../src/cli/config.js"; +import { type SparkConfigResolved, getConfigDefaults } from "spark-core/config.js"; // Get defaults for creating complete mock configs const defaults = getConfigDefaults(); // Mock the entire config module to test the interface -vi.mock("../../src/cli/config.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("spark-core/config.js", async (importOriginal) => { + const actual = await importOriginal(); const mockConfig = { getConfig: vi.fn(), getGlobalConfig: vi.fn(), @@ -25,7 +25,7 @@ vi.mock("../../src/cli/config.js", async (importOriginal) => { }; }); -import { config } from "../../src/cli/config.js"; +import { config } from "spark-core/config.js"; const mockConfig = vi.mocked(config); diff --git a/test/cli/utils.test.ts b/packages/cli/test/utils.test.ts similarity index 99% rename from test/cli/utils.test.ts rename to packages/cli/test/utils.test.ts index b2a28093..78288f9c 100644 --- a/test/cli/utils.test.ts +++ b/packages/cli/test/utils.test.ts @@ -7,7 +7,7 @@ import { parseConfigKeyValue, parseConfigValue, getPackageInfo, -} from "../../src/cli/utils.js"; +} from "../src/utils.js"; describe("CLI Utils", () => { describe("validateBrowser", () => { diff --git a/tsconfig.json b/packages/cli/tsconfig.json similarity index 87% rename from tsconfig.json rename to packages/cli/tsconfig.json index 924efacc..4d47548b 100644 --- a/tsconfig.json +++ b/packages/cli/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { // Language and environment "target": "ES2022", - "lib": ["ES2022", "DOM", "DOM.Iterable"], + "lib": ["ES2022"], // Module system "module": "NodeNext", @@ -29,5 +29,5 @@ "resolveJsonModule": true }, "include": ["src/**/*"], - "exclude": ["node_modules", "dist", "**/*.test.ts"] + "exclude": ["node_modules", "dist"] } diff --git a/packages/cli/tsup.config.ts b/packages/cli/tsup.config.ts new file mode 100644 index 00000000..708187a6 --- /dev/null +++ b/packages/cli/tsup.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/cli.ts"], + format: ["esm"], + dts: true, + outDir: "dist", + target: "node22", + clean: true, + sourcemap: true, + splitting: false, + treeshake: true, + // Shebang is preserved from the source file +}); diff --git a/packages/core/.prettierignore b/packages/core/.prettierignore new file mode 100644 index 00000000..1067a72c --- /dev/null +++ b/packages/core/.prettierignore @@ -0,0 +1,5 @@ +# Build outputs +dist/ + +# Dependencies +node_modules/ diff --git a/packages/core/package.json b/packages/core/package.json new file mode 100644 index 00000000..c165a89d --- /dev/null +++ b/packages/core/package.json @@ -0,0 +1,79 @@ +{ + "name": "spark-core", + "version": "0.12.0", + "description": "AI-powered web automation library", + "type": "module", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "engines": { + "node": "^22.0.0" + }, + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + }, + "./core": { + "types": "./dist/core.d.ts", + "import": "./dist/core.js" + }, + "./*": { + "types": "./dist/*", + "import": "./dist/*" + } + }, + "files": [ + "dist/**/*", + "README.md", + "LICENSE" + ], + "scripts": { + "bundle:aria": "tsx scripts/bundle-aria-tree.ts", + "build": "pnpm run bundle:aria && tsc", + "clean": "rm -rf dist", + "typecheck": "pnpm run bundle:aria && tsc --project tsconfig.check.json", + "test": "pnpm run bundle:aria && vitest run", + "test:watch": "pnpm run bundle:aria && vitest" + }, + "keywords": [ + "ai", + "automation", + "web-scraping", + "playwright", + "browser-automation" + ], + "author": "", + "license": "MIT", + "dependencies": { + "@ai-sdk/google": "^3.0.20", + "@ai-sdk/google-vertex": "^4.0.41", + "@ai-sdk/openai": "^3.0.25", + "@ai-sdk/openai-compatible": "^2.0.26", + "@ghostery/adblocker-playwright": "^2.13.4", + "@openrouter/ai-sdk-provider": "^2.1.1", + "ai": "^6.0.69", + "chalk": "^5.6.2", + "commander": "^14.0.3", + "cross-fetch": "^4.1.0", + "dotenv": "^17.2.3", + "eventemitter3": "^5.0.4", + "liquidjs": "^10.24.0", + "nanoid": "^5.1.6", + "ollama-ai-provider-v2": "^3.0.3", + "playwright": "1.58.1", + "turndown": "^7.2.2", + "zod": "^4.3.6" + }, + "devDependencies": { + "@types/jsdom": "^27.0.0", + "@types/node": "^25.2.0", + "@types/turndown": "^5.0.6", + "@vitest/coverage-v8": "^4.0.18", + "esbuild": "^0.27.3", + "jsdom": "^28.0.0", + "tsx": "^4.21.0", + "typescript": "^5.9.3", + "vitest": "^4.0.18" + }, + "packageManager": "pnpm@9.0.0" +} diff --git a/scripts/bundle-aria-tree.ts b/packages/core/scripts/bundle-aria-tree.ts similarity index 89% rename from scripts/bundle-aria-tree.ts rename to packages/core/scripts/bundle-aria-tree.ts index 612237a5..89ea7919 100644 --- a/scripts/bundle-aria-tree.ts +++ b/packages/core/scripts/bundle-aria-tree.ts @@ -12,12 +12,12 @@ import { join, dirname } from "path"; import { fileURLToPath } from "url"; const __dirname = dirname(fileURLToPath(import.meta.url)); -const projectRoot = join(__dirname, ".."); +const packageRoot = join(__dirname, ".."); async function main() { // Bundle the ariaTree entry point into a single IIFE const result = await build({ - entryPoints: [join(projectRoot, "src/browser/ariaTree/ariaSnapshot.ts")], + entryPoints: [join(packageRoot, "src/browser/ariaTree/ariaSnapshot.ts")], bundle: true, format: "iife", globalName: "__sparkAriaTree", @@ -40,7 +40,7 @@ async function main() { export const ARIA_TREE_SCRIPT = ${JSON.stringify(bundledCode)}; `; - const outPath = join(projectRoot, "src/browser/ariaTree/bundle.ts"); + const outPath = join(packageRoot, "src/browser/ariaTree/bundle.ts"); writeFileSync(outPath, output); console.log(`Wrote ${outPath} (${bundledCode.length} bytes)`); } diff --git a/src/browser/ariaBrowser.ts b/packages/core/src/browser/ariaBrowser.ts similarity index 100% rename from src/browser/ariaBrowser.ts rename to packages/core/src/browser/ariaBrowser.ts diff --git a/src/browser/ariaTree/ariaSnapshot.ts b/packages/core/src/browser/ariaTree/ariaSnapshot.ts similarity index 100% rename from src/browser/ariaTree/ariaSnapshot.ts rename to packages/core/src/browser/ariaTree/ariaSnapshot.ts diff --git a/src/browser/ariaTree/cssTokenizer.ts b/packages/core/src/browser/ariaTree/cssTokenizer.ts similarity index 100% rename from src/browser/ariaTree/cssTokenizer.ts rename to packages/core/src/browser/ariaTree/cssTokenizer.ts diff --git a/src/browser/ariaTree/domUtils.ts b/packages/core/src/browser/ariaTree/domUtils.ts similarity index 100% rename from src/browser/ariaTree/domUtils.ts rename to packages/core/src/browser/ariaTree/domUtils.ts diff --git a/src/browser/ariaTree/roleUtils.ts b/packages/core/src/browser/ariaTree/roleUtils.ts similarity index 100% rename from src/browser/ariaTree/roleUtils.ts rename to packages/core/src/browser/ariaTree/roleUtils.ts diff --git a/src/browser/ariaTree/stringUtils.ts b/packages/core/src/browser/ariaTree/stringUtils.ts similarity index 100% rename from src/browser/ariaTree/stringUtils.ts rename to packages/core/src/browser/ariaTree/stringUtils.ts diff --git a/src/browser/ariaTree/types.ts b/packages/core/src/browser/ariaTree/types.ts similarity index 100% rename from src/browser/ariaTree/types.ts rename to packages/core/src/browser/ariaTree/types.ts diff --git a/src/browser/ariaTree/yamlUtils.ts b/packages/core/src/browser/ariaTree/yamlUtils.ts similarity index 100% rename from src/browser/ariaTree/yamlUtils.ts rename to packages/core/src/browser/ariaTree/yamlUtils.ts diff --git a/src/browser/navigationRetry.ts b/packages/core/src/browser/navigationRetry.ts similarity index 100% rename from src/browser/navigationRetry.ts rename to packages/core/src/browser/navigationRetry.ts diff --git a/src/browser/playwrightBrowser.ts b/packages/core/src/browser/playwrightBrowser.ts similarity index 100% rename from src/browser/playwrightBrowser.ts rename to packages/core/src/browser/playwrightBrowser.ts diff --git a/src/config.ts b/packages/core/src/config.ts similarity index 100% rename from src/config.ts rename to packages/core/src/config.ts diff --git a/src/configDefaults.ts b/packages/core/src/configDefaults.ts similarity index 100% rename from src/configDefaults.ts rename to packages/core/src/configDefaults.ts diff --git a/src/constants.ts b/packages/core/src/constants.ts similarity index 100% rename from src/constants.ts rename to packages/core/src/constants.ts diff --git a/src/core.ts b/packages/core/src/core.ts similarity index 96% rename from src/core.ts rename to packages/core/src/core.ts index 1ca291ae..dc9d5c3e 100644 --- a/src/core.ts +++ b/packages/core/src/core.ts @@ -84,6 +84,13 @@ export const DEFAULT_REASONING_EFFORT = _defaults.reasoning_effort; export const DEFAULT_LOGGER = _defaults.logger; export const DEFAULT_METRICS_INCREMENTAL = _defaults.metrics_incremental; +// Aria tree utilities +export { + generateAndRenderAriaTree, + applySetOfMarks, + removeSetOfMarks, +} from "./browser/ariaTree/ariaSnapshot.js"; + // Note: createProvider not exported in core to avoid Node.js dependencies in browser // Use provider libraries directly in browser environments export * from "./schemas.js"; diff --git a/src/errors.ts b/packages/core/src/errors.ts similarity index 100% rename from src/errors.ts rename to packages/core/src/errors.ts diff --git a/src/events.ts b/packages/core/src/events.ts similarity index 100% rename from src/events.ts rename to packages/core/src/events.ts diff --git a/src/index.ts b/packages/core/src/index.ts similarity index 100% rename from src/index.ts rename to packages/core/src/index.ts diff --git a/src/loggers/chalkConsole.ts b/packages/core/src/loggers/chalkConsole.ts similarity index 100% rename from src/loggers/chalkConsole.ts rename to packages/core/src/loggers/chalkConsole.ts diff --git a/src/loggers/console.ts b/packages/core/src/loggers/console.ts similarity index 100% rename from src/loggers/console.ts rename to packages/core/src/loggers/console.ts diff --git a/src/loggers/filter.ts b/packages/core/src/loggers/filter.ts similarity index 100% rename from src/loggers/filter.ts rename to packages/core/src/loggers/filter.ts diff --git a/src/loggers/generic.ts b/packages/core/src/loggers/generic.ts similarity index 100% rename from src/loggers/generic.ts rename to packages/core/src/loggers/generic.ts diff --git a/src/loggers/json.ts b/packages/core/src/loggers/json.ts similarity index 100% rename from src/loggers/json.ts rename to packages/core/src/loggers/json.ts diff --git a/src/loggers/metricsCollector.ts b/packages/core/src/loggers/metricsCollector.ts similarity index 100% rename from src/loggers/metricsCollector.ts rename to packages/core/src/loggers/metricsCollector.ts diff --git a/src/loggers/secretsRedactor.ts b/packages/core/src/loggers/secretsRedactor.ts similarity index 100% rename from src/loggers/secretsRedactor.ts rename to packages/core/src/loggers/secretsRedactor.ts diff --git a/src/loggers/types.ts b/packages/core/src/loggers/types.ts similarity index 100% rename from src/loggers/types.ts rename to packages/core/src/loggers/types.ts diff --git a/src/loggers/wrapper.ts b/packages/core/src/loggers/wrapper.ts similarity index 100% rename from src/loggers/wrapper.ts rename to packages/core/src/loggers/wrapper.ts diff --git a/src/prompts.ts b/packages/core/src/prompts.ts similarity index 100% rename from src/prompts.ts rename to packages/core/src/prompts.ts diff --git a/src/provider.ts b/packages/core/src/provider.ts similarity index 100% rename from src/provider.ts rename to packages/core/src/provider.ts diff --git a/src/schemas.ts b/packages/core/src/schemas.ts similarity index 100% rename from src/schemas.ts rename to packages/core/src/schemas.ts diff --git a/src/search/providers/bingSearch.ts b/packages/core/src/search/providers/bingSearch.ts similarity index 100% rename from src/search/providers/bingSearch.ts rename to packages/core/src/search/providers/bingSearch.ts diff --git a/src/search/providers/browserSearch.ts b/packages/core/src/search/providers/browserSearch.ts similarity index 100% rename from src/search/providers/browserSearch.ts rename to packages/core/src/search/providers/browserSearch.ts diff --git a/src/search/providers/duckduckgoSearch.ts b/packages/core/src/search/providers/duckduckgoSearch.ts similarity index 100% rename from src/search/providers/duckduckgoSearch.ts rename to packages/core/src/search/providers/duckduckgoSearch.ts diff --git a/src/search/providers/googleSearch.ts b/packages/core/src/search/providers/googleSearch.ts similarity index 100% rename from src/search/providers/googleSearch.ts rename to packages/core/src/search/providers/googleSearch.ts diff --git a/src/search/providers/parallelSearch.ts b/packages/core/src/search/providers/parallelSearch.ts similarity index 100% rename from src/search/providers/parallelSearch.ts rename to packages/core/src/search/providers/parallelSearch.ts diff --git a/src/search/searchProvider.ts b/packages/core/src/search/searchProvider.ts similarity index 100% rename from src/search/searchProvider.ts rename to packages/core/src/search/searchProvider.ts diff --git a/src/search/searchService.ts b/packages/core/src/search/searchService.ts similarity index 100% rename from src/search/searchService.ts rename to packages/core/src/search/searchService.ts diff --git a/src/snapshotCompressor.ts b/packages/core/src/snapshotCompressor.ts similarity index 100% rename from src/snapshotCompressor.ts rename to packages/core/src/snapshotCompressor.ts diff --git a/src/tools/planningTools.ts b/packages/core/src/tools/planningTools.ts similarity index 100% rename from src/tools/planningTools.ts rename to packages/core/src/tools/planningTools.ts diff --git a/src/tools/searchTools.ts b/packages/core/src/tools/searchTools.ts similarity index 100% rename from src/tools/searchTools.ts rename to packages/core/src/tools/searchTools.ts diff --git a/src/tools/validationTools.ts b/packages/core/src/tools/validationTools.ts similarity index 100% rename from src/tools/validationTools.ts rename to packages/core/src/tools/validationTools.ts diff --git a/src/tools/webActionTools.ts b/packages/core/src/tools/webActionTools.ts similarity index 100% rename from src/tools/webActionTools.ts rename to packages/core/src/tools/webActionTools.ts diff --git a/src/utils/configMerge.ts b/packages/core/src/utils/configMerge.ts similarity index 100% rename from src/utils/configMerge.ts rename to packages/core/src/utils/configMerge.ts diff --git a/src/utils/env.ts b/packages/core/src/utils/env.ts similarity index 100% rename from src/utils/env.ts rename to packages/core/src/utils/env.ts diff --git a/src/utils/jsonParser.ts b/packages/core/src/utils/jsonParser.ts similarity index 100% rename from src/utils/jsonParser.ts rename to packages/core/src/utils/jsonParser.ts diff --git a/src/utils/promptSecurity.ts b/packages/core/src/utils/promptSecurity.ts similarity index 100% rename from src/utils/promptSecurity.ts rename to packages/core/src/utils/promptSecurity.ts diff --git a/src/utils/retry.ts b/packages/core/src/utils/retry.ts similarity index 100% rename from src/utils/retry.ts rename to packages/core/src/utils/retry.ts diff --git a/src/utils/template.ts b/packages/core/src/utils/template.ts similarity index 100% rename from src/utils/template.ts rename to packages/core/src/utils/template.ts diff --git a/src/utils/types.ts b/packages/core/src/utils/types.ts similarity index 100% rename from src/utils/types.ts rename to packages/core/src/utils/types.ts diff --git a/src/webAgent.ts b/packages/core/src/webAgent.ts similarity index 100% rename from src/webAgent.ts rename to packages/core/src/webAgent.ts diff --git a/test/ariaBrowser.test.ts b/packages/core/test/ariaBrowser.test.ts similarity index 100% rename from test/ariaBrowser.test.ts rename to packages/core/test/ariaBrowser.test.ts diff --git a/test/browser/ariaTree/ariaSnapshot.test.ts b/packages/core/test/browser/ariaTree/ariaSnapshot.test.ts similarity index 100% rename from test/browser/ariaTree/ariaSnapshot.test.ts rename to packages/core/test/browser/ariaTree/ariaSnapshot.test.ts diff --git a/test/config.test.ts b/packages/core/test/config.test.ts similarity index 100% rename from test/config.test.ts rename to packages/core/test/config.test.ts diff --git a/test/errors.test.ts b/packages/core/test/errors.test.ts similarity index 100% rename from test/errors.test.ts rename to packages/core/test/errors.test.ts diff --git a/test/events.test.ts b/packages/core/test/events.test.ts similarity index 100% rename from test/events.test.ts rename to packages/core/test/events.test.ts diff --git a/test/index.test.ts b/packages/core/test/index.test.ts similarity index 100% rename from test/index.test.ts rename to packages/core/test/index.test.ts diff --git a/test/loggers.test.ts b/packages/core/test/loggers.test.ts similarity index 100% rename from test/loggers.test.ts rename to packages/core/test/loggers.test.ts diff --git a/test/metricsCollector.test.ts b/packages/core/test/metricsCollector.test.ts similarity index 100% rename from test/metricsCollector.test.ts rename to packages/core/test/metricsCollector.test.ts diff --git a/test/navigationRetry.test.ts b/packages/core/test/navigationRetry.test.ts similarity index 100% rename from test/navigationRetry.test.ts rename to packages/core/test/navigationRetry.test.ts diff --git a/test/playwrightBrowser.test.ts b/packages/core/test/playwrightBrowser.test.ts similarity index 100% rename from test/playwrightBrowser.test.ts rename to packages/core/test/playwrightBrowser.test.ts diff --git a/test/prompts.test.ts b/packages/core/test/prompts.test.ts similarity index 100% rename from test/prompts.test.ts rename to packages/core/test/prompts.test.ts diff --git a/test/cli/provider.test.ts b/packages/core/test/provider.test.ts similarity index 99% rename from test/cli/provider.test.ts rename to packages/core/test/provider.test.ts index 5b103230..88605fcb 100644 --- a/test/cli/provider.test.ts +++ b/packages/core/test/provider.test.ts @@ -1,8 +1,8 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; -import { createAIProvider, getAIProviderInfo } from "../../src/provider.js"; +import { createAIProvider, getAIProviderInfo } from "../src/provider.js"; // Mock the config module -vi.mock("../../src/config.js", () => ({ +vi.mock("../src/config.js", () => ({ config: { getConfig: vi.fn(), }, @@ -85,7 +85,7 @@ vi.mock("@ai-sdk/openai-compatible", () => ({ })), })); -import { config, getConfigDefaults } from "../../src/config.js"; +import { config, getConfigDefaults } from "../src/config.js"; import { openai, createOpenAI } from "@ai-sdk/openai"; import { createOpenRouter } from "@openrouter/ai-sdk-provider"; import { createGoogleGenerativeAI } from "@ai-sdk/google"; diff --git a/test/schemas.test.ts b/packages/core/test/schemas.test.ts similarity index 100% rename from test/schemas.test.ts rename to packages/core/test/schemas.test.ts diff --git a/test/search/searchProvider.test.ts b/packages/core/test/search/searchProvider.test.ts similarity index 100% rename from test/search/searchProvider.test.ts rename to packages/core/test/search/searchProvider.test.ts diff --git a/test/search/searchService.test.ts b/packages/core/test/search/searchService.test.ts similarity index 100% rename from test/search/searchService.test.ts rename to packages/core/test/search/searchService.test.ts diff --git a/test/secretsRedactor.test.ts b/packages/core/test/secretsRedactor.test.ts similarity index 100% rename from test/secretsRedactor.test.ts rename to packages/core/test/secretsRedactor.test.ts diff --git a/test/snapshotCompressor.test.ts b/packages/core/test/snapshotCompressor.test.ts similarity index 100% rename from test/snapshotCompressor.test.ts rename to packages/core/test/snapshotCompressor.test.ts diff --git a/test/tools/planningTools.test.ts b/packages/core/test/tools/planningTools.test.ts similarity index 100% rename from test/tools/planningTools.test.ts rename to packages/core/test/tools/planningTools.test.ts diff --git a/test/tools/searchTools.test.ts b/packages/core/test/tools/searchTools.test.ts similarity index 100% rename from test/tools/searchTools.test.ts rename to packages/core/test/tools/searchTools.test.ts diff --git a/test/tools/validationTools.test.ts b/packages/core/test/tools/validationTools.test.ts similarity index 100% rename from test/tools/validationTools.test.ts rename to packages/core/test/tools/validationTools.test.ts diff --git a/test/tools/webActionTools.test.ts b/packages/core/test/tools/webActionTools.test.ts similarity index 100% rename from test/tools/webActionTools.test.ts rename to packages/core/test/tools/webActionTools.test.ts diff --git a/test/utils/configMerge.test.ts b/packages/core/test/utils/configMerge.test.ts similarity index 100% rename from test/utils/configMerge.test.ts rename to packages/core/test/utils/configMerge.test.ts diff --git a/test/utils/env.test.ts b/packages/core/test/utils/env.test.ts similarity index 100% rename from test/utils/env.test.ts rename to packages/core/test/utils/env.test.ts diff --git a/test/utils/jsonParser.test.ts b/packages/core/test/utils/jsonParser.test.ts similarity index 100% rename from test/utils/jsonParser.test.ts rename to packages/core/test/utils/jsonParser.test.ts diff --git a/test/utils/promptSecurity.test.ts b/packages/core/test/utils/promptSecurity.test.ts similarity index 100% rename from test/utils/promptSecurity.test.ts rename to packages/core/test/utils/promptSecurity.test.ts diff --git a/test/utils/retry.test.ts b/packages/core/test/utils/retry.test.ts similarity index 100% rename from test/utils/retry.test.ts rename to packages/core/test/utils/retry.test.ts diff --git a/test/utils/template.test.ts b/packages/core/test/utils/template.test.ts similarity index 100% rename from test/utils/template.test.ts rename to packages/core/test/utils/template.test.ts diff --git a/test/webAgent.test.ts b/packages/core/test/webAgent.test.ts similarity index 100% rename from test/webAgent.test.ts rename to packages/core/test/webAgent.test.ts diff --git a/tsconfig.check.json b/packages/core/tsconfig.check.json similarity index 100% rename from tsconfig.check.json rename to packages/core/tsconfig.check.json diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json new file mode 100644 index 00000000..17746269 --- /dev/null +++ b/packages/core/tsconfig.json @@ -0,0 +1,40 @@ +{ + "compilerOptions": { + // Language and environment + "target": "ES2022", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + + // Module system + "module": "NodeNext", + "moduleResolution": "NodeNext", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + + // Output + "outDir": "./dist", + "rootDir": "./src", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + + // Type checking + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + + // Interop and compatibility + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "isolatedModules": true, + "resolveJsonModule": true, + + // Path aliases + "baseUrl": ".", + "paths": { + "@cli/*": ["packages/cli/src/*"], + "@core/*": ["src/*"] + } + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "**/*.test.ts"] +} diff --git a/vitest.config.ts b/packages/core/vitest.config.ts similarity index 100% rename from vitest.config.ts rename to packages/core/vitest.config.ts diff --git a/extension/.gitignore b/packages/extension/.gitignore similarity index 100% rename from extension/.gitignore rename to packages/extension/.gitignore diff --git a/extension/.prettierrc b/packages/extension/.prettierrc similarity index 100% rename from extension/.prettierrc rename to packages/extension/.prettierrc diff --git a/extension/README.md b/packages/extension/README.md similarity index 100% rename from extension/README.md rename to packages/extension/README.md diff --git a/extension/assets/react.svg b/packages/extension/assets/react.svg similarity index 100% rename from extension/assets/react.svg rename to packages/extension/assets/react.svg diff --git a/extension/docs/architecture.md b/packages/extension/docs/architecture.md similarity index 100% rename from extension/docs/architecture.md rename to packages/extension/docs/architecture.md diff --git a/extension/docs/prose-typography-customization-plan.md b/packages/extension/docs/prose-typography-customization-plan.md similarity index 100% rename from extension/docs/prose-typography-customization-plan.md rename to packages/extension/docs/prose-typography-customization-plan.md diff --git a/extension/docs/task-execution-flow.md b/packages/extension/docs/task-execution-flow.md similarity index 100% rename from extension/docs/task-execution-flow.md rename to packages/extension/docs/task-execution-flow.md diff --git a/extension/e2e/fixtures/extension.ts b/packages/extension/e2e/fixtures/extension.ts similarity index 100% rename from extension/e2e/fixtures/extension.ts rename to packages/extension/e2e/fixtures/extension.ts diff --git a/extension/e2e/sidepanel.spec.ts b/packages/extension/e2e/sidepanel.spec.ts similarity index 98% rename from extension/e2e/sidepanel.spec.ts rename to packages/extension/e2e/sidepanel.spec.ts index 42f579fc..2df5b31f 100644 --- a/extension/e2e/sidepanel.spec.ts +++ b/packages/extension/e2e/sidepanel.spec.ts @@ -1,4 +1,4 @@ -import { test, expect } from "./fixtures/extension"; +import { test, expect } from "./fixtures/extension.js"; test.describe("Sidepanel", () => { test("should display settings page when no API key is configured", async ({ diff --git a/extension/entrypoints/background.ts b/packages/extension/entrypoints/background.ts similarity index 99% rename from extension/entrypoints/background.ts rename to packages/extension/entrypoints/background.ts index 82106993..97437758 100644 --- a/extension/entrypoints/background.ts +++ b/packages/extension/entrypoints/background.ts @@ -1,13 +1,13 @@ import browser from "webextension-polyfill"; -import { AgentManager, EventStoreLogger } from "../src/AgentManager"; -import { useConversationStore } from "../src/stores/conversationStore"; +import { AgentManager, EventStoreLogger } from "../src/AgentManager.js"; +import { useConversationStore } from "../src/stores/conversationStore.js"; import { showIndicator, hideIndicator, isIndicatorActive, setupNavigationListener, cleanupStaleRegistrations, -} from "../src/background/indicatorControl"; +} from "../src/background/indicatorControl.js"; import type { ChromeBrowser, ExtensionMessage, @@ -15,7 +15,7 @@ import type { ExecuteTaskResponse, CancelTaskMessage, CancelTaskResponse, -} from "../src/types/browser"; +} from "../src/types/browser.js"; interface StorageSettings { apiKey?: string; diff --git a/extension/entrypoints/content.ts b/packages/extension/entrypoints/content.ts similarity index 98% rename from extension/entrypoints/content.ts rename to packages/extension/entrypoints/content.ts index e176c0ef..d6d23246 100644 --- a/extension/entrypoints/content.ts +++ b/packages/extension/entrypoints/content.ts @@ -1,6 +1,6 @@ // Import ariaTree functionality from shared module import browser from "webextension-polyfill"; -import { generateAndRenderAriaTree, applySetOfMarks, removeSetOfMarks } from "spark/ariaTree"; +import { generateAndRenderAriaTree, applySetOfMarks, removeSetOfMarks } from "spark-core/core.js"; import type { ExtensionMessage, GetPageInfoResponse, diff --git a/extension/entrypoints/sidepanel.html b/packages/extension/entrypoints/sidepanel.html similarity index 100% rename from extension/entrypoints/sidepanel.html rename to packages/extension/entrypoints/sidepanel.html diff --git a/extension/package.json b/packages/extension/package.json similarity index 81% rename from extension/package.json rename to packages/extension/package.json index 55ec0edf..f9e245a6 100644 --- a/extension/package.json +++ b/packages/extension/package.json @@ -8,22 +8,21 @@ "node": "^22.0.0" }, "scripts": { + "build": "wxt build -b chrome", + "prebuild": "pnpm --filter spark-core build", + "build:chrome": "wxt build -b chrome", + "prebuild:chrome": "pnpm --filter spark-core build", + "build:firefox": "wxt build -b firefox", + "prebuild:firefox": "pnpm --filter spark-core build", + "clean": "rm -rf .output", "dev:chrome": "node scripts/mkdirp.js .wxt/chrome-data && WEB_EXT_CHROMIUM_PROFILE=.wxt/chrome-data WEB_EXT_KEEP_PROFILE_CHANGES=true wxt -b chrome", "dev:chrome:tmp-profile": "wxt -b chrome", "dev:firefox": "node scripts/mkdirp.js .wxt/firefox-data && WEB_EXT_FIREFOX_PROFILE=.wxt/firefox-data WEB_EXT_KEEP_PROFILE_CHANGES=true wxt -b firefox", "dev:firefox:tmp-profile": "wxt -b firefox", - "prebuild:chrome": "cd .. && pnpm build", - "build:chrome": "wxt build -b chrome", - "prebuild:firefox": "cd .. && pnpm build", - "build:firefox": "wxt build -b firefox", "zip:chrome": "wxt zip -b chrome", "zip:firefox": "wxt zip -b firefox", - "compile": "tsc --noEmit", "postinstall": "wxt prepare", - "format": "prettier --write . --list-different", - "format:check": "prettier --check .", "typecheck": "tsc --noEmit", - "check": "pnpm run format && pnpm run typecheck && pnpm run test", "test": "vitest run", "test:watch": "vitest", "test:ui": "vitest --ui", @@ -32,16 +31,21 @@ "test:e2e:ui:chrome": "playwright test --ui" }, "dependencies": { + "@ai-sdk/google": "^3.0.20", + "@ai-sdk/openai": "^3.0.25", "@fontsource-variable/inter": "^5.2.8", + "@openrouter/ai-sdk-provider": "^2.1.1", "@tailwindcss/vite": "^4.1.18", "@types/webextension-polyfill": "^0.12.4", "@wxt-dev/webextension-polyfill": "^1.0.0", "clsx": "^2.1.1", "marked-react": "^3.0.2", + "ollama-ai-provider-v2": "^3.0.3", "react": "^19.2.4", "react-dom": "^19.2.4", - "spark": "file:..", + "spark-core": "workspace:*", "tailwindcss": "^4.1.18", + "turndown": "^7.2.2", "webextension-polyfill": "^0.12.0", "yaml": "^2.8.2", "zustand": "^5.0.11" @@ -54,6 +58,7 @@ "@testing-library/user-event": "^14.6.1", "@types/react": "^19.2.10", "@types/react-dom": "^19.2.3", + "@types/turndown": "^5.0.6", "@wxt-dev/module-react": "^1.1.5", "happy-dom": "^20.4.0", "prettier": "^3.8.1", diff --git a/extension/playwright.config.ts b/packages/extension/playwright.config.ts similarity index 100% rename from extension/playwright.config.ts rename to packages/extension/playwright.config.ts diff --git a/extension/public/icon/128.png b/packages/extension/public/icon/128.png similarity index 100% rename from extension/public/icon/128.png rename to packages/extension/public/icon/128.png diff --git a/extension/public/icon/16.png b/packages/extension/public/icon/16.png similarity index 100% rename from extension/public/icon/16.png rename to packages/extension/public/icon/16.png diff --git a/extension/public/icon/24.png b/packages/extension/public/icon/24.png similarity index 100% rename from extension/public/icon/24.png rename to packages/extension/public/icon/24.png diff --git a/extension/public/icon/32.png b/packages/extension/public/icon/32.png similarity index 100% rename from extension/public/icon/32.png rename to packages/extension/public/icon/32.png diff --git a/extension/public/icon/48.png b/packages/extension/public/icon/48.png similarity index 100% rename from extension/public/icon/48.png rename to packages/extension/public/icon/48.png diff --git a/extension/public/icon/96.png b/packages/extension/public/icon/96.png similarity index 100% rename from extension/public/icon/96.png rename to packages/extension/public/icon/96.png diff --git a/extension/public/icon/sidebar.svg b/packages/extension/public/icon/sidebar.svg similarity index 100% rename from extension/public/icon/sidebar.svg rename to packages/extension/public/icon/sidebar.svg diff --git a/extension/public/indicator.css b/packages/extension/public/indicator.css similarity index 100% rename from extension/public/indicator.css rename to packages/extension/public/indicator.css diff --git a/extension/public/wxt.svg b/packages/extension/public/wxt.svg similarity index 100% rename from extension/public/wxt.svg rename to packages/extension/public/wxt.svg diff --git a/extension/scripts/mkdirp.js b/packages/extension/scripts/mkdirp.js similarity index 100% rename from extension/scripts/mkdirp.js rename to packages/extension/scripts/mkdirp.js diff --git a/extension/src/AgentManager.ts b/packages/extension/src/AgentManager.ts similarity index 96% rename from extension/src/AgentManager.ts rename to packages/extension/src/AgentManager.ts index b6019a06..d2435d68 100644 --- a/extension/src/AgentManager.ts +++ b/packages/extension/src/AgentManager.ts @@ -1,8 +1,8 @@ -import { ExtensionBrowser } from "./ExtensionBrowser"; -import { EventStoreLogger } from "./EventStoreLogger"; +import { ExtensionBrowser } from "./ExtensionBrowser.js"; +import { EventStoreLogger } from "./EventStoreLogger.js"; // Import shared code - browser-safe imports only -import { WebAgent, Logger } from "spark/core"; +import { WebAgent, Logger } from "spark-core/core.js"; import { createOpenAI } from "@ai-sdk/openai"; import { createOpenRouter } from "@openrouter/ai-sdk-provider"; import { createGoogleGenerativeAI } from "@ai-sdk/google"; diff --git a/extension/src/ChatMessage.tsx b/packages/extension/src/ChatMessage.tsx similarity index 97% rename from extension/src/ChatMessage.tsx rename to packages/extension/src/ChatMessage.tsx index 1f8e8b05..ff2a96aa 100644 --- a/extension/src/ChatMessage.tsx +++ b/packages/extension/src/ChatMessage.tsx @@ -2,9 +2,9 @@ import type { ReactElement } from "react"; import clsx from "clsx"; -import type { Theme } from "./theme"; +import type { Theme } from "./theme.js"; -import type { ChatMessage } from "./hooks/useConversation"; +import type { ChatMessage } from "./hooks/useConversation.js"; interface ChatMessageProps { type: ChatMessage["type"]; diff --git a/extension/src/EventLogger.ts b/packages/extension/src/EventLogger.ts similarity index 94% rename from extension/src/EventLogger.ts rename to packages/extension/src/EventLogger.ts index 46956938..73fb6cc4 100644 --- a/extension/src/EventLogger.ts +++ b/packages/extension/src/EventLogger.ts @@ -1,4 +1,4 @@ -import type { WebAgentEventType } from "spark/core"; +import type { WebAgentEventType } from "spark-core/core.js"; export interface LogEvent { id: string; diff --git a/extension/src/EventStoreLogger.ts b/packages/extension/src/EventStoreLogger.ts similarity index 95% rename from extension/src/EventStoreLogger.ts rename to packages/extension/src/EventStoreLogger.ts index f2a87cf9..08246c38 100644 --- a/extension/src/EventStoreLogger.ts +++ b/packages/extension/src/EventStoreLogger.ts @@ -1,8 +1,8 @@ import browser from "webextension-polyfill"; -import { GenericLogger } from "spark/core"; -import { createLogger } from "./utils/logger"; -import { isValidRealtimeEvent } from "./utils/typeGuards"; -import type { RealtimeEventMessage } from "./types/browser"; +import { GenericLogger } from "spark-core/core.js"; +import { createLogger } from "./utils/logger.js"; +import { isValidRealtimeEvent } from "./utils/typeGuards.js"; +import type { RealtimeEventMessage } from "./types/browser.js"; interface EventData { type: string; diff --git a/extension/src/ExtensionBrowser.ts b/packages/extension/src/ExtensionBrowser.ts similarity index 99% rename from extension/src/ExtensionBrowser.ts rename to packages/extension/src/ExtensionBrowser.ts index 0a5870cc..a78df362 100644 --- a/extension/src/ExtensionBrowser.ts +++ b/packages/extension/src/ExtensionBrowser.ts @@ -1,8 +1,8 @@ import browser from "webextension-polyfill"; -import type { AriaBrowser } from "spark/core"; -import { PageAction, LoadState } from "spark/core"; +import type { AriaBrowser } from "spark-core/core.js"; +import { PageAction, LoadState } from "spark-core/core.js"; import type { Tabs } from "webextension-polyfill"; -import { createLogger } from "./utils/logger"; +import { createLogger } from "./utils/logger.js"; import TurndownService from "turndown"; interface ActionResult { diff --git a/extension/src/background/indicatorControl.ts b/packages/extension/src/background/indicatorControl.ts similarity index 100% rename from extension/src/background/indicatorControl.ts rename to packages/extension/src/background/indicatorControl.ts diff --git a/extension/src/components/icons/SettingsGearIcon.tsx b/packages/extension/src/components/icons/SettingsGearIcon.tsx similarity index 100% rename from extension/src/components/icons/SettingsGearIcon.tsx rename to packages/extension/src/components/icons/SettingsGearIcon.tsx diff --git a/extension/src/components/icons/SparkLogo.tsx b/packages/extension/src/components/icons/SparkLogo.tsx similarity index 100% rename from extension/src/components/icons/SparkLogo.tsx rename to packages/extension/src/components/icons/SparkLogo.tsx diff --git a/extension/src/components/sidepanel/ChatView.tsx b/packages/extension/src/components/sidepanel/ChatView.tsx similarity index 97% rename from extension/src/components/sidepanel/ChatView.tsx rename to packages/extension/src/components/sidepanel/ChatView.tsx index 97156fe3..bfd42f0f 100644 --- a/extension/src/components/sidepanel/ChatView.tsx +++ b/packages/extension/src/components/sidepanel/ChatView.tsx @@ -2,14 +2,14 @@ import { useState, useEffect, type ReactElement } from "react"; import browser from "webextension-polyfill"; import Markdown from "marked-react"; import clsx from "clsx"; -import { ChatMessage } from "../../ChatMessage"; -import { useChat } from "../../useChat"; -import type { ChatMessage as ChatMessageType } from "../../hooks/useConversation"; -import { useEvents } from "../../stores/eventStore"; -import { useSettings } from "../../stores/settingsStore"; -import { useConversationStore } from "../../stores/conversationStore"; -import { useSystemTheme } from "../../useSystemTheme"; -import type { Theme } from "../../theme"; +import { ChatMessage } from "../../ChatMessage.js"; +import { useChat } from "../../useChat.js"; +import type { ChatMessage as ChatMessageType } from "../../hooks/useConversation.js"; +import { useEvents } from "../../stores/eventStore.js"; +import { useSettings } from "../../stores/settingsStore.js"; +import { useConversationStore } from "../../stores/conversationStore.js"; +import { useSystemTheme } from "../../useSystemTheme.js"; +import type { Theme } from "../../theme.js"; import type { ExecuteTaskMessage, ExecuteTaskResponse, @@ -17,7 +17,7 @@ import type { CancelTaskResponse, RealtimeEventMessage, RealtimeEvent, -} from "../../types/browser"; +} from "../../types/browser.js"; import { isTaskStartedData, isAgentReasonedData, @@ -27,10 +27,10 @@ import { isBrowserActionCompletedData, isBrowserActionStartedData, isAgentActionData, -} from "../../utils/typeGuards"; -import type { BrowserActionStartedEventData } from "../../types/browser"; -import { SettingsGearIcon } from "../icons/SettingsGearIcon"; -import { SparkLogo } from "../icons/SparkLogo"; +} from "../../utils/typeGuards.js"; +import type { BrowserActionStartedEventData } from "../../types/browser.js"; +import { SettingsGearIcon } from "../icons/SettingsGearIcon.js"; +import { SparkLogo } from "../icons/SparkLogo.js"; // Interface for events in ExecuteTaskResponse interface EventData { diff --git a/extension/src/components/sidepanel/SettingsView.tsx b/packages/extension/src/components/sidepanel/SettingsView.tsx similarity index 98% rename from extension/src/components/sidepanel/SettingsView.tsx rename to packages/extension/src/components/sidepanel/SettingsView.tsx index 1c7d3a3c..ed522fa1 100644 --- a/extension/src/components/sidepanel/SettingsView.tsx +++ b/packages/extension/src/components/sidepanel/SettingsView.tsx @@ -1,6 +1,6 @@ import { type ReactElement } from "react"; -import { useSettings } from "../../stores/settingsStore"; -import { useSystemTheme } from "../../useSystemTheme"; +import { useSettings } from "../../stores/settingsStore.js"; +import { useSystemTheme } from "../../useSystemTheme.js"; interface SettingsViewProps { onBack: () => void; diff --git a/extension/src/components/sidepanel/SidePanel.css b/packages/extension/src/components/sidepanel/SidePanel.css similarity index 100% rename from extension/src/components/sidepanel/SidePanel.css rename to packages/extension/src/components/sidepanel/SidePanel.css diff --git a/extension/src/components/sidepanel/SidePanel.tsx b/packages/extension/src/components/sidepanel/SidePanel.tsx similarity index 96% rename from extension/src/components/sidepanel/SidePanel.tsx rename to packages/extension/src/components/sidepanel/SidePanel.tsx index 656f71dd..3d9b9777 100644 --- a/extension/src/components/sidepanel/SidePanel.tsx +++ b/packages/extension/src/components/sidepanel/SidePanel.tsx @@ -1,10 +1,10 @@ import { useState, useEffect, type ReactElement } from "react"; import browser from "webextension-polyfill"; import "./SidePanel.css"; -import ChatView from "./ChatView"; -import SettingsView from "./SettingsView"; -import { useSettings } from "../../stores/settingsStore"; -import { useConversationStore } from "../../stores/conversationStore"; +import ChatView from "./ChatView.js"; +import SettingsView from "./SettingsView.js"; +import { useSettings } from "../../stores/settingsStore.js"; +import { useConversationStore } from "../../stores/conversationStore.js"; type View = "chat" | "settings"; diff --git a/extension/src/components/sidepanel/main.tsx b/packages/extension/src/components/sidepanel/main.tsx similarity index 87% rename from extension/src/components/sidepanel/main.tsx rename to packages/extension/src/components/sidepanel/main.tsx index 8d995b45..07ccc8cb 100644 --- a/extension/src/components/sidepanel/main.tsx +++ b/packages/extension/src/components/sidepanel/main.tsx @@ -1,7 +1,7 @@ import React from "react"; import { createRoot } from "react-dom/client"; import "@fontsource-variable/inter"; -import SidePanel from "./SidePanel"; +import SidePanel from "./SidePanel.js"; import "./SidePanel.css"; const root = createRoot(document.getElementById("root")!); diff --git a/extension/src/hooks/useAutoScroll.ts b/packages/extension/src/hooks/useAutoScroll.ts similarity index 97% rename from extension/src/hooks/useAutoScroll.ts rename to packages/extension/src/hooks/useAutoScroll.ts index 30ddc3e2..fcda8b24 100644 --- a/extension/src/hooks/useAutoScroll.ts +++ b/packages/extension/src/hooks/useAutoScroll.ts @@ -1,6 +1,6 @@ import { useEffect, useRef, useCallback } from "react"; -import { useConversationStore } from "../stores/conversationStore"; -import type { ChatMessage } from "./useConversation"; +import { useConversationStore } from "../stores/conversationStore.js"; +import type { ChatMessage } from "./useConversation.js"; /** * Hook for managing auto-scroll behavior in chat interfaces diff --git a/extension/src/hooks/useConversation.ts b/packages/extension/src/hooks/useConversation.ts similarity index 99% rename from extension/src/hooks/useConversation.ts rename to packages/extension/src/hooks/useConversation.ts index b43c1e59..08436afa 100644 --- a/extension/src/hooks/useConversation.ts +++ b/packages/extension/src/hooks/useConversation.ts @@ -1,5 +1,5 @@ import { useCallback } from "react"; -import { useConversationStore, useTabConversation } from "../stores/conversationStore"; +import { useConversationStore, useTabConversation } from "../stores/conversationStore.js"; export interface ChatMessage { id: string; diff --git a/extension/src/stores/conversationStore.ts b/packages/extension/src/stores/conversationStore.ts similarity index 98% rename from extension/src/stores/conversationStore.ts rename to packages/extension/src/stores/conversationStore.ts index 8ac9f98f..1fe445bc 100644 --- a/extension/src/stores/conversationStore.ts +++ b/packages/extension/src/stores/conversationStore.ts @@ -1,8 +1,8 @@ import { create } from "zustand"; import { persist, createJSONStorage } from "zustand/middleware"; import browser from "webextension-polyfill"; -import type { ChatMessage } from "../useChat"; -import { reviver } from "../utils/storage"; +import type { ChatMessage } from "../useChat.js"; +import { reviver } from "../utils/storage.js"; export interface Conversation { id: string; diff --git a/extension/src/stores/eventStore.ts b/packages/extension/src/stores/eventStore.ts similarity index 97% rename from extension/src/stores/eventStore.ts rename to packages/extension/src/stores/eventStore.ts index d0d6b5ae..bc96b8b3 100644 --- a/extension/src/stores/eventStore.ts +++ b/packages/extension/src/stores/eventStore.ts @@ -1,8 +1,8 @@ import { create } from "zustand"; import { persist, createJSONStorage } from "zustand/middleware"; import browser from "webextension-polyfill"; -import type { WebAgentEventType } from "spark/core"; -import { reviver } from "../utils/storage"; +import type { WebAgentEventType } from "spark-core/core.js"; +import { reviver } from "../utils/storage.js"; export interface EventData { id: string; diff --git a/extension/src/stores/settingsStore.ts b/packages/extension/src/stores/settingsStore.ts similarity index 98% rename from extension/src/stores/settingsStore.ts rename to packages/extension/src/stores/settingsStore.ts index 689180cc..4a396018 100644 --- a/extension/src/stores/settingsStore.ts +++ b/packages/extension/src/stores/settingsStore.ts @@ -1,7 +1,7 @@ import { create } from "zustand"; import { persist, createJSONStorage } from "zustand/middleware"; import browser from "webextension-polyfill"; -import { reviver } from "../utils/storage"; +import { reviver } from "../utils/storage.js"; export interface Settings { apiKey: string; diff --git a/extension/src/theme.ts b/packages/extension/src/theme.ts similarity index 100% rename from extension/src/theme.ts rename to packages/extension/src/theme.ts diff --git a/extension/src/types/browser.ts b/packages/extension/src/types/browser.ts similarity index 100% rename from extension/src/types/browser.ts rename to packages/extension/src/types/browser.ts diff --git a/extension/src/useChat.ts b/packages/extension/src/useChat.ts similarity index 91% rename from extension/src/useChat.ts rename to packages/extension/src/useChat.ts index f2adccc6..e778b22d 100644 --- a/extension/src/useChat.ts +++ b/packages/extension/src/useChat.ts @@ -1,7 +1,7 @@ import { useCallback } from "react"; -import { useConversation } from "./hooks/useConversation"; -import { useAutoScroll } from "./hooks/useAutoScroll"; -import type { ChatMessage } from "./hooks/useConversation"; +import { useConversation } from "./hooks/useConversation.js"; +import { useAutoScroll } from "./hooks/useAutoScroll.js"; +import type { ChatMessage } from "./hooks/useConversation.js"; // Re-export ChatMessage type for backwards compatibility export type { ChatMessage }; diff --git a/extension/src/useEventLogger.ts b/packages/extension/src/useEventLogger.ts similarity index 89% rename from extension/src/useEventLogger.ts rename to packages/extension/src/useEventLogger.ts index bb8c9a1c..618c3d09 100644 --- a/extension/src/useEventLogger.ts +++ b/packages/extension/src/useEventLogger.ts @@ -1,5 +1,5 @@ import { useState, useEffect, useRef } from "react"; -import { EventLogger, type LogEvent } from "./EventLogger"; +import { EventLogger, type LogEvent } from "./EventLogger.js"; export function useEventLogger(): { events: LogEvent[]; diff --git a/extension/src/useEventStore.ts b/packages/extension/src/useEventStore.ts similarity index 93% rename from extension/src/useEventStore.ts rename to packages/extension/src/useEventStore.ts index e5da8126..0610e661 100644 --- a/extension/src/useEventStore.ts +++ b/packages/extension/src/useEventStore.ts @@ -1,5 +1,5 @@ import { useState, useEffect, useRef } from "react"; -import { EventStoreLogger } from "./EventStoreLogger"; +import { EventStoreLogger } from "./EventStoreLogger.js"; type AgentEvent = { type: string; data: any; timestamp: number }; diff --git a/extension/src/useSystemTheme.ts b/packages/extension/src/useSystemTheme.ts similarity index 93% rename from extension/src/useSystemTheme.ts rename to packages/extension/src/useSystemTheme.ts index 41690f89..3c3ae9e7 100644 --- a/extension/src/useSystemTheme.ts +++ b/packages/extension/src/useSystemTheme.ts @@ -1,5 +1,5 @@ import { useState, useEffect } from "react"; -import { theme, type ThemeMode } from "./theme"; +import { theme, type ThemeMode } from "./theme.js"; export function useSystemTheme() { const [themeMode, setThemeMode] = useState(() => { diff --git a/extension/src/utils/logger.ts b/packages/extension/src/utils/logger.ts similarity index 100% rename from extension/src/utils/logger.ts rename to packages/extension/src/utils/logger.ts diff --git a/extension/src/utils/storage.ts b/packages/extension/src/utils/storage.ts similarity index 100% rename from extension/src/utils/storage.ts rename to packages/extension/src/utils/storage.ts diff --git a/extension/src/utils/typeGuards.ts b/packages/extension/src/utils/typeGuards.ts similarity index 99% rename from extension/src/utils/typeGuards.ts rename to packages/extension/src/utils/typeGuards.ts index 1793b996..169a9aab 100644 --- a/extension/src/utils/typeGuards.ts +++ b/packages/extension/src/utils/typeGuards.ts @@ -11,7 +11,7 @@ import type { BrowserActionCompletedEventData, BrowserActionStartedEventData, RealtimeEvent, -} from "../types/browser"; +} from "../types/browser.js"; /** * Check if an object has an optional string property diff --git a/extension/test/AgentManager.test.ts b/packages/extension/test/AgentManager.test.ts similarity index 95% rename from extension/test/AgentManager.test.ts rename to packages/extension/test/AgentManager.test.ts index 82444a01..d662c8e5 100644 --- a/extension/test/AgentManager.test.ts +++ b/packages/extension/test/AgentManager.test.ts @@ -1,15 +1,15 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; -import { AgentManager } from "../src/AgentManager"; +import { AgentManager } from "../src/AgentManager.js"; vi.mock("@ai-sdk/openai"); vi.mock("@openrouter/ai-sdk-provider"); -vi.mock("spark/core"); -vi.mock("../src/ExtensionBrowser"); +vi.mock("spark-core/core.js"); +vi.mock("../src/ExtensionBrowser.js"); import { createOpenAI, type OpenAIProvider } from "@ai-sdk/openai"; import { createOpenRouter, type OpenRouterProvider } from "@openrouter/ai-sdk-provider"; -import { WebAgent } from "spark/core"; -import { ExtensionBrowser } from "../src/ExtensionBrowser"; +import { WebAgent } from "spark-core/core.js"; +import { ExtensionBrowser } from "../src/ExtensionBrowser.js"; describe("AgentManager", () => { let mockOpenAI: OpenAIProvider; diff --git a/extension/test/ChatMessage.test.tsx b/packages/extension/test/ChatMessage.test.tsx similarity index 95% rename from extension/test/ChatMessage.test.tsx rename to packages/extension/test/ChatMessage.test.tsx index 4356b466..7f3d4b49 100644 --- a/extension/test/ChatMessage.test.tsx +++ b/packages/extension/test/ChatMessage.test.tsx @@ -1,7 +1,7 @@ import { describe, it, expect } from "vitest"; import { render, screen } from "@testing-library/react"; -import { ChatMessage } from "../src/ChatMessage"; -import { theme } from "../src/theme"; +import { ChatMessage } from "../src/ChatMessage.js"; +import { theme } from "../src/theme.js"; describe("ChatMessage", () => { const defaultProps = { diff --git a/extension/test/EventStoreLogger.test.ts b/packages/extension/test/EventStoreLogger.test.ts similarity index 99% rename from extension/test/EventStoreLogger.test.ts rename to packages/extension/test/EventStoreLogger.test.ts index b934121b..dac8b447 100644 --- a/extension/test/EventStoreLogger.test.ts +++ b/packages/extension/test/EventStoreLogger.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; -import { EventStoreLogger } from "../src/EventStoreLogger"; +import { EventStoreLogger } from "../src/EventStoreLogger.js"; import browser from "webextension-polyfill"; // Mock the webextension-polyfill module diff --git a/extension/test/ExtensionBrowser.test.ts b/packages/extension/test/ExtensionBrowser.test.ts similarity index 97% rename from extension/test/ExtensionBrowser.test.ts rename to packages/extension/test/ExtensionBrowser.test.ts index 3e7bebb4..b0407d58 100644 --- a/extension/test/ExtensionBrowser.test.ts +++ b/packages/extension/test/ExtensionBrowser.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, beforeEach, vi } from "vitest"; -import { ExtensionBrowser } from "../src/ExtensionBrowser"; +import { ExtensionBrowser } from "../src/ExtensionBrowser.js"; import browser from "webextension-polyfill"; vi.mock("webextension-polyfill", () => ({ diff --git a/extension/test/background.test.ts b/packages/extension/test/background.test.ts similarity index 99% rename from extension/test/background.test.ts rename to packages/extension/test/background.test.ts index 93fd8aaa..214b03ba 100644 --- a/extension/test/background.test.ts +++ b/packages/extension/test/background.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import browser from "webextension-polyfill"; -import { EventStoreLogger } from "../src/EventStoreLogger"; +import { EventStoreLogger } from "../src/EventStoreLogger.js"; // Mock the webextension-polyfill module vi.mock("webextension-polyfill", () => ({ diff --git a/extension/test/background/indicatorControl.test.ts b/packages/extension/test/background/indicatorControl.test.ts similarity index 99% rename from extension/test/background/indicatorControl.test.ts rename to packages/extension/test/background/indicatorControl.test.ts index 3059665a..791c9f00 100644 --- a/extension/test/background/indicatorControl.test.ts +++ b/packages/extension/test/background/indicatorControl.test.ts @@ -8,7 +8,7 @@ import { resetIndicatorState, ensureIndicatorCSSRegistered, cleanupStaleRegistrations, -} from "../../src/background/indicatorControl"; +} from "../../src/background/indicatorControl.js"; import browser from "webextension-polyfill"; // Type definitions for test mocks diff --git a/extension/test/components/SettingsView.test.tsx b/packages/extension/test/components/SettingsView.test.tsx similarity index 99% rename from extension/test/components/SettingsView.test.tsx rename to packages/extension/test/components/SettingsView.test.tsx index 97825bba..6663ed87 100644 --- a/extension/test/components/SettingsView.test.tsx +++ b/packages/extension/test/components/SettingsView.test.tsx @@ -1,6 +1,6 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { render, screen } from "@testing-library/react"; -import SettingsView from "../../src/components/sidepanel/SettingsView"; +import SettingsView from "../../src/components/sidepanel/SettingsView.js"; // Mock the hooks const mockUpdateSettings = vi.fn(); diff --git a/extension/test/components/icons/SparkLogo.test.tsx b/packages/extension/test/components/icons/SparkLogo.test.tsx similarity index 99% rename from extension/test/components/icons/SparkLogo.test.tsx rename to packages/extension/test/components/icons/SparkLogo.test.tsx index 91e405d9..98d63ac5 100644 --- a/extension/test/components/icons/SparkLogo.test.tsx +++ b/packages/extension/test/components/icons/SparkLogo.test.tsx @@ -1,6 +1,6 @@ import { describe, it, expect } from "vitest"; import { render } from "@testing-library/react"; -import { SparkLogo } from "../../../src/components/icons/SparkLogo"; +import { SparkLogo } from "../../../src/components/icons/SparkLogo.js"; describe("SparkLogo", () => { it("renders an SVG element", () => { diff --git a/extension/test/components/sidepanel/ChatView.test.tsx b/packages/extension/test/components/sidepanel/ChatView.test.tsx similarity index 99% rename from extension/test/components/sidepanel/ChatView.test.tsx rename to packages/extension/test/components/sidepanel/ChatView.test.tsx index b68a92f7..4651a51e 100644 --- a/extension/test/components/sidepanel/ChatView.test.tsx +++ b/packages/extension/test/components/sidepanel/ChatView.test.tsx @@ -3,10 +3,10 @@ import { render, screen } from "@testing-library/react"; import ChatView, { shouldDisplayError, formatBrowserAction, -} from "../../../src/components/sidepanel/ChatView"; -import { theme } from "../../../src/theme"; +} from "../../../src/components/sidepanel/ChatView.js"; +import { theme } from "../../../src/theme.js"; import browser from "webextension-polyfill"; -import type { RealtimeEventMessage } from "../../../src/types/browser"; +import type { RealtimeEventMessage } from "../../../src/types/browser.js"; type MessageListenerCallback = (message: RealtimeEventMessage) => void; diff --git a/extension/test/content/indicatorStyles.test.ts b/packages/extension/test/content/indicatorStyles.test.ts similarity index 99% rename from extension/test/content/indicatorStyles.test.ts rename to packages/extension/test/content/indicatorStyles.test.ts index 3d19f562..c5e4a08a 100644 --- a/extension/test/content/indicatorStyles.test.ts +++ b/packages/extension/test/content/indicatorStyles.test.ts @@ -1,7 +1,7 @@ import { describe, it, expect } from "vitest"; import fs from "fs"; import path from "path"; -import { INDICATOR_CSS } from "../../src/background/indicatorControl"; +import { INDICATOR_CSS } from "../../src/background/indicatorControl.js"; describe("indicator CSS file for dynamic registration", () => { const cssPath = path.join(__dirname, "../../public/indicator.css"); diff --git a/extension/test/setup.ts b/packages/extension/test/setup.ts similarity index 100% rename from extension/test/setup.ts rename to packages/extension/test/setup.ts diff --git a/extension/test/stores/settingsStore.test.ts b/packages/extension/test/stores/settingsStore.test.ts similarity index 98% rename from extension/test/stores/settingsStore.test.ts rename to packages/extension/test/stores/settingsStore.test.ts index 3db4f76e..23945927 100644 --- a/extension/test/stores/settingsStore.test.ts +++ b/packages/extension/test/stores/settingsStore.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; -import type { Settings } from "../../src/stores/settingsStore"; -import { useSettingsStore } from "../../src/stores/settingsStore"; +import type { Settings } from "../../src/stores/settingsStore.js"; +import { useSettingsStore } from "../../src/stores/settingsStore.js"; import browser from "webextension-polyfill"; // Mock webextension-polyfill diff --git a/extension/test/utils/storage.test.ts b/packages/extension/test/utils/storage.test.ts similarity index 94% rename from extension/test/utils/storage.test.ts rename to packages/extension/test/utils/storage.test.ts index cf0f9e5a..a49188ff 100644 --- a/extension/test/utils/storage.test.ts +++ b/packages/extension/test/utils/storage.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from "vitest"; -import { reviver } from "../../src/utils/storage"; +import { reviver } from "../../src/utils/storage.js"; describe("reviver", () => { it("should convert ISO date string to Date object when key is timestamp", () => { diff --git a/extension/test/utils/typeGuards.test.ts b/packages/extension/test/utils/typeGuards.test.ts similarity index 99% rename from extension/test/utils/typeGuards.test.ts rename to packages/extension/test/utils/typeGuards.test.ts index 18f649ac..05429468 100644 --- a/extension/test/utils/typeGuards.test.ts +++ b/packages/extension/test/utils/typeGuards.test.ts @@ -14,7 +14,7 @@ import { isBrowserActionStartedData, isValidRealtimeEvent, isAgentActionData, -} from "../../src/utils/typeGuards"; +} from "../../src/utils/typeGuards.js"; import type { TaskStartedEventData, AgentReasonedEventData, @@ -23,7 +23,7 @@ import type { TaskValidationErrorEventData, BrowserActionCompletedEventData, BrowserActionStartedEventData, -} from "../../src/types/browser"; +} from "../../src/types/browser.js"; describe("Type Guard Helpers", () => { describe("hasOptionalStringProp", () => { diff --git a/extension/tsconfig.json b/packages/extension/tsconfig.json similarity index 100% rename from extension/tsconfig.json rename to packages/extension/tsconfig.json diff --git a/extension/vitest.config.ts b/packages/extension/vitest.config.ts similarity index 100% rename from extension/vitest.config.ts rename to packages/extension/vitest.config.ts diff --git a/extension/wxt.config.ts b/packages/extension/wxt.config.ts similarity index 91% rename from extension/wxt.config.ts rename to packages/extension/wxt.config.ts index 1f2b670c..8a8e266e 100644 --- a/extension/wxt.config.ts +++ b/packages/extension/wxt.config.ts @@ -57,6 +57,22 @@ let config = { }, vite: () => ({ plugins: [tailwindcss()] as any, + resolve: { + alias: { + "spark/core": resolve(__dirname, "../core/src/core.ts"), + }, + }, + build: { + commonjsOptions: { + include: [/node_modules/], + }, + rollupOptions: { + external: ["wxt/browser", "@wxt-dev/webextension-polyfill/browser"], + }, + }, + optimizeDeps: { + exclude: ["@wxt-dev/webextension-polyfill"], + }, server: { fs: { // Allow serving files from parent node_modules (for @fontsource-variable/inter) diff --git a/server/.env.example b/packages/server/.env.example similarity index 100% rename from server/.env.example rename to packages/server/.env.example diff --git a/server/.gitignore b/packages/server/.gitignore similarity index 100% rename from server/.gitignore rename to packages/server/.gitignore diff --git a/server/.prettierignore b/packages/server/.prettierignore similarity index 100% rename from server/.prettierignore rename to packages/server/.prettierignore diff --git a/server/.prettierrc b/packages/server/.prettierrc similarity index 100% rename from server/.prettierrc rename to packages/server/.prettierrc diff --git a/server/DOCKER.md b/packages/server/DOCKER.md similarity index 100% rename from server/DOCKER.md rename to packages/server/DOCKER.md diff --git a/server/Dockerfile b/packages/server/Dockerfile similarity index 56% rename from server/Dockerfile rename to packages/server/Dockerfile index 5b1a7423..cb0eb8e2 100644 --- a/server/Dockerfile +++ b/packages/server/Dockerfile @@ -10,29 +10,36 @@ ARG INSTALL_PLAYWRIGHT_BROWSERS=false # Set working directory WORKDIR /app -# Copy root package files and build main spark package +# Copy workspace configuration +COPY pnpm-workspace.yaml ./ + +# Copy root package files for core spark library COPY package.json pnpm-lock.yaml ./ COPY src ./src COPY scripts ./scripts COPY tsconfig.json ./ -RUN pnpm install + +# Copy CLI package files (needed for bin reference in root package.json) +COPY packages/cli/package.json packages/cli/tsconfig.json ./packages/cli/ + +# Copy server package files +COPY packages/server/package.json packages/server/tsconfig.json packages/server/tsup.config.ts ./packages/server/ +COPY packages/server/src ./packages/server/src + +# Install all workspace dependencies (skip prepare scripts to avoid build errors) +RUN pnpm install --ignore-scripts # Install Playwright system dependencies as root (requires apt) RUN if [ "$INSTALL_PLAYWRIGHT_BROWSERS" = "true" ]; then \ npx playwright install-deps firefox chromium; \ fi -RUN pnpm run build - -# Now work on the server -WORKDIR /app/server -COPY server/package.json server/pnpm-lock.yaml ./ -RUN pnpm install +# Build core spark package first (required by server) +# Build just the TypeScript in the root (core library) +RUN pnpm tsc -# Copy server source and build -COPY server/src ./src -COPY server/tsconfig.json ./ -RUN pnpm run build +# Build server package +RUN pnpm --filter @spark/server run build # Expose the port EXPOSE 3000 @@ -53,5 +60,8 @@ RUN if [ "$INSTALL_PLAYWRIGHT_BROWSERS" = "true" ]; then \ npx playwright install firefox chromium; \ fi +# Set working directory to server package +WORKDIR /app/packages/server + # Start the server CMD ["pnpm", "start"] \ No newline at end of file diff --git a/server/README.md b/packages/server/README.md similarity index 100% rename from server/README.md rename to packages/server/README.md diff --git a/server/docker-compose-chromium.yml b/packages/server/docker-compose-chromium.yml similarity index 91% rename from server/docker-compose-chromium.yml rename to packages/server/docker-compose-chromium.yml index 387638e4..ff823373 100644 --- a/server/docker-compose-chromium.yml +++ b/packages/server/docker-compose-chromium.yml @@ -1,8 +1,8 @@ services: spark: build: - context: .. - dockerfile: server/Dockerfile + context: ../.. + dockerfile: packages/server/Dockerfile container_name: spark-server ports: - "3000:3000" diff --git a/server/docker-compose-firefox.yml b/packages/server/docker-compose-firefox.yml similarity index 91% rename from server/docker-compose-firefox.yml rename to packages/server/docker-compose-firefox.yml index dbd03594..806d9eba 100644 --- a/server/docker-compose-firefox.yml +++ b/packages/server/docker-compose-firefox.yml @@ -1,8 +1,8 @@ services: spark: build: - context: .. - dockerfile: server/Dockerfile + context: ../.. + dockerfile: packages/server/Dockerfile container_name: spark-server ports: - "3000:3000" diff --git a/server/docker-compose.dev.yml b/packages/server/docker-compose.dev.yml similarity index 69% rename from server/docker-compose.dev.yml rename to packages/server/docker-compose.dev.yml index 71584304..2cde714a 100644 --- a/server/docker-compose.dev.yml +++ b/packages/server/docker-compose.dev.yml @@ -1,8 +1,8 @@ services: spark-server: build: - context: .. - dockerfile: server/Dockerfile + context: ../.. + dockerfile: packages/server/Dockerfile args: INSTALL_PLAYWRIGHT_BROWSERS: "true" ports: @@ -14,6 +14,8 @@ services: - SPARK_REASONING_EFFORT=low volumes: # Mount server source code for hot reloading - - ./src:/app/server/src + - ./src:/app/packages/server/src + # Mount core library for hot reloading + - ../../src:/app/src command: ["pnpm", "run", "dev"] restart: unless-stopped diff --git a/server/package.json b/packages/server/package.json similarity index 96% rename from server/package.json rename to packages/server/package.json index c0e0d651..c5f76f66 100644 --- a/server/package.json +++ b/packages/server/package.json @@ -37,7 +37,7 @@ "@hono/sentry": "^1.2.2", "dotenv": "^17.2.3", "hono": "^4.11.7", - "spark": "file:.." + "spark-core": "workspace:*" }, "packageManager": "pnpm@9.0.0" } diff --git a/server/src/StreamLogger.test.ts b/packages/server/src/StreamLogger.test.ts similarity index 100% rename from server/src/StreamLogger.test.ts rename to packages/server/src/StreamLogger.test.ts diff --git a/server/src/StreamLogger.ts b/packages/server/src/StreamLogger.ts similarity index 92% rename from server/src/StreamLogger.ts rename to packages/server/src/StreamLogger.ts index 4fc3d12c..1e64b116 100644 --- a/server/src/StreamLogger.ts +++ b/packages/server/src/StreamLogger.ts @@ -1,4 +1,5 @@ -import { GenericLogger, WebAgentEventType } from "spark"; +import { GenericLogger } from "spark-core/loggers/generic.js"; +import { WebAgentEventType } from "spark-core/events.js"; type EventSender = (event: string, data: any) => Promise; diff --git a/server/src/index.test.ts b/packages/server/src/index.test.ts similarity index 100% rename from server/src/index.test.ts rename to packages/server/src/index.test.ts diff --git a/server/src/index.ts b/packages/server/src/index.ts similarity index 100% rename from server/src/index.ts rename to packages/server/src/index.ts diff --git a/server/src/routes/spark.test.ts b/packages/server/src/routes/spark.test.ts similarity index 81% rename from server/src/routes/spark.test.ts rename to packages/server/src/routes/spark.test.ts index 1f250e9d..55c0dc6b 100644 --- a/server/src/routes/spark.test.ts +++ b/packages/server/src/routes/spark.test.ts @@ -2,26 +2,32 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import { Hono } from "hono"; import sparkRoutes from "./spark.js"; -// Mock the spark library -vi.mock("spark", () => ({ - WebAgent: vi.fn().mockImplementation(() => ({ - execute: vi.fn().mockResolvedValue({ - success: true, - finalAnswer: "Task completed successfully", - plan: "Test plan", - taskExplanation: "Test explanation", - iterations: 1, - validationAttempts: 1, - }), - close: vi.fn().mockResolvedValue(undefined), - })), - PlaywrightBrowser: vi.fn().mockImplementation(() => ({})), - config: { - getConfig: vi.fn(() => ({ - provider: "openai", - openai_api_key: "sk-test123", - })), - }, +// Mock spark-core/webAgent.js +vi.mock("spark-core/webAgent.js", () => ({ + WebAgent: vi.fn().mockImplementation(function () { + return { + execute: vi.fn().mockResolvedValue({ + success: true, + finalAnswer: "Task completed successfully", + plan: "Test plan", + taskExplanation: "Test explanation", + iterations: 1, + validationAttempts: 1, + }), + close: vi.fn().mockResolvedValue(undefined), + }; + }), +})); + +// Mock spark-core/browser/playwrightBrowser.js +vi.mock("spark-core/browser/playwrightBrowser.js", () => ({ + PlaywrightBrowser: vi.fn().mockImplementation(function () { + return {}; + }), +})); + +// Mock spark-core/provider.js +vi.mock("spark-core/provider.js", () => ({ createAIProvider: vi.fn(() => ({})), getAIProviderInfo: vi.fn(() => ({ provider: "openai", @@ -29,7 +35,10 @@ vi.mock("spark", () => ({ hasApiKey: true, keySource: "env", })), - // Config merge utilities +})); + +// Mock spark-core/utils/configMerge.js +vi.mock("spark-core/utils/configMerge.js", () => ({ createNavigationRetryConfig: vi.fn((overrides) => ({ baseTimeoutMs: overrides?.baseTimeoutMs ?? 30000, maxTimeoutMs: overrides?.maxTimeoutMs ?? 120000, @@ -37,14 +46,21 @@ vi.mock("spark", () => ({ timeoutMultiplier: overrides?.timeoutMultiplier ?? 2, ...(overrides?.onRetry && { onRetry: overrides.onRetry }), })), - // Default constants - DEFAULT_BROWSER: "firefox", - DEFAULT_HEADLESS: false, - DEFAULT_BLOCK_ADS: true, - DEFAULT_DEBUG: false, - DEFAULT_VISION: false, - DEFAULT_MAX_ITERATIONS: 50, - DEFAULT_MAX_VALIDATION_ATTEMPTS: 3, +})); + +// Mock spark-core/configDefaults.js +vi.mock("spark-core/configDefaults.js", () => ({ + SEARCH_PROVIDERS: ["none", "duckduckgo", "google", "bing", "parallel-api"], +})); + +// Mock spark-core/config.js +vi.mock("spark-core/config.js", () => ({ + config: { + getConfig: vi.fn(() => ({ + provider: "openai", + openai_api_key: "sk-test123", + })), + }, })); // Mock the AI SDK @@ -54,7 +70,9 @@ vi.mock("@ai-sdk/openai", () => ({ // Mock the StreamLogger vi.mock("../StreamLogger.js", () => ({ - StreamLogger: vi.fn().mockImplementation(() => ({})), + StreamLogger: vi.fn().mockImplementation(function () { + return {}; + }), })); describe("Spark Routes", () => { @@ -73,7 +91,7 @@ describe("Spark Routes", () => { process.env.OPENAI_API_KEY = "test-key"; // Reset the getAIProviderInfo mock to its default success state - const { getAIProviderInfo } = await import("spark"); + const { getAIProviderInfo } = await import("spark-core/provider.js"); vi.mocked(getAIProviderInfo).mockReturnValue({ provider: "openai", model: "gpt-4.1", @@ -103,7 +121,7 @@ describe("Spark Routes", () => { it("should reject requests without OpenAI API key", async () => { // Mock getAIProviderInfo to throw an error for missing API key - const { getAIProviderInfo } = await import("spark"); + const { getAIProviderInfo } = await import("spark-core/provider.js"); vi.mocked(getAIProviderInfo).mockImplementation(() => { throw new Error( "No OpenAI API key found. Please set OPENAI_API_KEY environment variable or configure globally.", diff --git a/server/src/routes/spark.ts b/packages/server/src/routes/spark.ts similarity index 95% rename from server/src/routes/spark.ts rename to packages/server/src/routes/spark.ts index 560e8b7d..02277486 100644 --- a/server/src/routes/spark.ts +++ b/packages/server/src/routes/spark.ts @@ -1,16 +1,13 @@ import { Hono } from "hono"; import { streamSSE } from "hono/streaming"; -import { - WebAgent, - PlaywrightBrowser, - createAIProvider, - getAIProviderInfo, - createNavigationRetryConfig, - SEARCH_PROVIDERS, -} from "spark"; -import type { TaskExecutionResult } from "spark"; +import { WebAgent } from "spark-core/webAgent.js"; +import { PlaywrightBrowser } from "spark-core/browser/playwrightBrowser.js"; +import { createAIProvider, getAIProviderInfo } from "spark-core/provider.js"; +import { createNavigationRetryConfig } from "spark-core/utils/configMerge.js"; +import { SEARCH_PROVIDERS } from "spark-core/configDefaults.js"; +import type { TaskExecutionResult } from "spark-core/webAgent.js"; +import { config } from "spark-core/config.js"; import { StreamLogger } from "../StreamLogger.js"; -import { config } from "../config.js"; interface ErrorResponse { success: false; diff --git a/server/tsconfig.json b/packages/server/tsconfig.json similarity index 100% rename from server/tsconfig.json rename to packages/server/tsconfig.json diff --git a/packages/server/tsup.config.ts b/packages/server/tsup.config.ts new file mode 100644 index 00000000..20fc8749 --- /dev/null +++ b/packages/server/tsup.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm"], + dts: true, + outDir: "dist", + target: "node22", + clean: true, + sourcemap: true, + splitting: false, + treeshake: true, +}); diff --git a/server/vitest.config.ts b/packages/server/vitest.config.ts similarity index 100% rename from server/vitest.config.ts rename to packages/server/vitest.config.ts diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f4af526c..da040d5f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,28 +7,62 @@ settings: importers: .: + devDependencies: + prettier: + specifier: ^3.8.1 + version: 3.8.1 + + packages/cli: + dependencies: + chalk: + specifier: ^5.6.2 + version: 5.6.2 + commander: + specifier: ^14.0.3 + version: 14.0.3 + spark-core: + specifier: workspace:* + version: link:../core + devDependencies: + '@types/node': + specifier: ^25.2.0 + version: 25.2.3 + tsup: + specifier: ^8.3.5 + version: 8.5.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) + tsx: + specifier: ^4.21.0 + version: 4.21.0 + typescript: + specifier: ^5.9.3 + version: 5.9.3 + vitest: + specifier: ^4.0.18 + version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.2.3)(happy-dom@20.6.1)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) + + packages/core: dependencies: '@ai-sdk/google': specifier: ^3.0.20 - version: 3.0.20(zod@4.3.6) + version: 3.0.29(zod@4.3.6) '@ai-sdk/google-vertex': specifier: ^4.0.41 - version: 4.0.41(zod@4.3.6) + version: 4.0.58(zod@4.3.6) '@ai-sdk/openai': specifier: ^3.0.25 - version: 3.0.25(zod@4.3.6) + version: 3.0.29(zod@4.3.6) '@ai-sdk/openai-compatible': specifier: ^2.0.26 - version: 2.0.26(zod@4.3.6) + version: 2.0.30(zod@4.3.6) '@ghostery/adblocker-playwright': specifier: ^2.13.4 - version: 2.13.4(playwright@1.58.1) + version: 2.14.1(playwright@1.58.1) '@openrouter/ai-sdk-provider': specifier: ^2.1.1 - version: 2.1.1(ai@6.0.69(zod@4.3.6))(zod@4.3.6) + version: 2.2.3(ai@6.0.87(zod@4.3.6))(zod@4.3.6) ai: specifier: ^6.0.69 - version: 6.0.69(zod@4.3.6) + version: 6.0.87(zod@4.3.6) chalk: specifier: ^5.6.2 version: 5.6.2 @@ -40,7 +74,7 @@ importers: version: 4.1.0 dotenv: specifier: ^17.2.3 - version: 17.2.3 + version: 17.3.1 eventemitter3: specifier: ^5.0.4 version: 5.0.4 @@ -52,7 +86,7 @@ importers: version: 5.1.6 ollama-ai-provider-v2: specifier: ^3.0.3 - version: 3.0.3(ai@6.0.69(zod@4.3.6))(zod@4.3.6) + version: 3.3.1(ai@6.0.87(zod@4.3.6))(zod@4.3.6) playwright: specifier: 1.58.1 version: 1.58.1 @@ -68,25 +102,19 @@ importers: version: 27.0.0 '@types/node': specifier: ^25.2.0 - version: 25.2.0 + version: 25.2.3 '@types/turndown': specifier: ^5.0.6 version: 5.0.6 '@vitest/coverage-v8': specifier: ^4.0.18 - version: 4.0.18(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.2.0)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@28.0.0)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.18(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.2.3)(happy-dom@20.6.1)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)) esbuild: specifier: ^0.27.3 version: 0.27.3 jsdom: specifier: ^28.0.0 - version: 28.0.0 - nodemon: - specifier: ^3.1.11 - version: 3.1.11 - prettier: - specifier: ^3.8.1 - version: 3.8.1 + version: 28.1.0 tsx: specifier: ^4.21.0 version: 4.21.0 @@ -95,13 +123,22 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.18 - version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.2.0)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@28.0.0)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) + version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.2.3)(happy-dom@20.6.1)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) - extension: + packages/extension: dependencies: + '@ai-sdk/google': + specifier: ^3.0.20 + version: 3.0.29(zod@4.3.6) + '@ai-sdk/openai': + specifier: ^3.0.25 + version: 3.0.29(zod@4.3.6) '@fontsource-variable/inter': specifier: ^5.2.8 version: 5.2.8 + '@openrouter/ai-sdk-provider': + specifier: ^2.1.1 + version: 2.2.3(ai@6.0.87(zod@4.3.6))(zod@4.3.6) '@tailwindcss/vite': specifier: ^4.1.18 version: 4.1.18(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)) @@ -117,18 +154,24 @@ importers: marked-react: specifier: ^3.0.2 version: 3.0.2(react@19.2.4) + ollama-ai-provider-v2: + specifier: ^3.0.3 + version: 3.3.1(ai@6.0.87(zod@4.3.6))(zod@4.3.6) react: specifier: ^19.2.4 version: 19.2.4 react-dom: specifier: ^19.2.4 version: 19.2.4(react@19.2.4) - spark: - specifier: file:.. - version: 'file:' + spark-core: + specifier: workspace:* + version: link:../core tailwindcss: specifier: ^4.1.18 version: 4.1.18 + turndown: + specifier: ^7.2.2 + version: 7.2.2 webextension-polyfill: specifier: ^0.12.0 version: 0.12.0 @@ -137,11 +180,11 @@ importers: version: 2.8.2 zustand: specifier: ^5.0.11 - version: 5.0.11(@types/react@19.2.10)(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4)) + version: 5.0.11(@types/react@19.2.14)(react@19.2.4) devDependencies: '@playwright/test': specifier: ^1.58.1 - version: 1.58.1 + version: 1.58.2 '@tailwindcss/typography': specifier: ^0.5.19 version: 0.5.19(tailwindcss@4.1.18) @@ -150,22 +193,25 @@ importers: version: 6.9.1 '@testing-library/react': specifier: ^16.3.2 - version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@testing-library/user-event': specifier: ^14.6.1 version: 14.6.1(@testing-library/dom@10.4.1) '@types/react': specifier: ^19.2.10 - version: 19.2.10 + version: 19.2.14 '@types/react-dom': specifier: ^19.2.3 - version: 19.2.3(@types/react@19.2.10) + version: 19.2.3(@types/react@19.2.14) + '@types/turndown': + specifier: ^5.0.6 + version: 5.0.6 '@wxt-dev/module-react': specifier: ^1.1.5 version: 1.1.5(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))(wxt@0.20.13(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.57.1)(tsx@4.21.0)(yaml@2.8.2)) happy-dom: specifier: ^20.4.0 - version: 20.4.0 + version: 20.6.1 prettier: specifier: ^3.8.1 version: 3.8.1 @@ -174,28 +220,28 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.18 - version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.2.3)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@28.0.0)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) + version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.2.3)(happy-dom@20.6.1)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) wxt: specifier: 0.20.13 version: 0.20.13(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.57.1)(tsx@4.21.0)(yaml@2.8.2) - server: + packages/server: dependencies: '@hono/node-server': specifier: ^1.19.9 - version: 1.19.9(hono@4.11.7) + version: 1.19.9(hono@4.11.9) '@hono/sentry': specifier: ^1.2.2 - version: 1.2.2(hono@4.11.7) + version: 1.2.2(hono@4.11.9) dotenv: specifier: ^17.2.3 - version: 17.2.3 + version: 17.3.1 hono: specifier: ^4.11.7 - version: 4.11.7 - spark: - specifier: file:.. - version: 'file:' + version: 4.11.9 + spark-core: + specifier: workspace:* + version: link:../core devDependencies: '@types/node': specifier: ^25.2.0 @@ -211,7 +257,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.18 - version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.2.3)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@28.0.0)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) + version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.2.3)(happy-dom@20.6.1)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) packages: @@ -224,94 +270,48 @@ packages: '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} - '@ai-sdk/anthropic@3.0.35': - resolution: {integrity: sha512-Y3g/5uVj621XSB9lGF7WrD7qR+orhV5xpaYkRF8kfj2j4W7e7BBGIvxcdsCf85FjJbc6tKQdNTZ84ZEqT3Y5TQ==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/anthropic@3.0.44': resolution: {integrity: sha512-ke1NldgohWJ7sWLqm9Um9TVIOrtg8Y8AecWeB6PgaLt+paTPisAsyNfe8FNOVusuv58ugLBqY/78AkhUmbjXHA==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/gateway@3.0.32': - resolution: {integrity: sha512-7clZRr07P9rpur39t1RrbIe7x8jmwnwUWI8tZs+BvAfX3NFgdSVGGIaT7bTz2pb08jmLXzTSDbrOTqAQ7uBkBQ==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/gateway@3.0.47': resolution: {integrity: sha512-gGsUF42TKjnnKpyHNpk/J6Hw1HCg0XqfRS9QSeZ2nn+ccy+CUXIbnuIpeBMrGCHUOAiZCy5Ei/H9BW9VgV+vKg==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/google-vertex@4.0.41': - resolution: {integrity: sha512-lAr8qb+sZ97TUwT9lnkZH+1nvzav/xTEnlXKB22x7wqPbc4WPJU/UDCgzSiwEEzkT9jBU70V+/pqhnjjJ5ez6Q==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/google-vertex@4.0.58': resolution: {integrity: sha512-i19ovUxTopZt4Z8ICbSzrww1ESiNJjMxbkxFia0pncfteZMA2FOAgFazGOIOIGZexRuHrpZ7cWID3DdEtubxBQ==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/google@3.0.20': - resolution: {integrity: sha512-bVGsulEr6JiipAFlclo9bjL5WaUV0iCSiiekLt+PY6pwmtJeuU2GaD9DoE3OqR8LN2W779mU13IhVEzlTupf8g==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/google@3.0.29': resolution: {integrity: sha512-x0hcU10AA+i1ZUQHloGD5qXWsB+Y8qnxlmFUef6Ly4rB53MGVbQExkI9nOKiCO3mu2TGiiNoQMeKWSeQVLfRUA==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/openai-compatible@2.0.26': - resolution: {integrity: sha512-l6jdFjI1C2eDAEm7oo+dnRn0oG1EkcyqfbEZ7ozT0TnYrah6amX2JkftYMP1GRzNtAeCB3WNN8XspXdmi6ZNlQ==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/openai-compatible@2.0.30': resolution: {integrity: sha512-iTjumHf1/u4NhjXYFn/aONM2GId3/o7J1Lp5ql8FCbgIMyRwrmanR5xy1S3aaVkfTscuDvLTzWiy1mAbGzK3nQ==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/openai@3.0.25': - resolution: {integrity: sha512-DsaN46R98+D1W3lU3fKuPU3ofacboLaHlkAwxJPgJ8eup1AJHmPK1N1y10eJJbJcF6iby8Tf/vanoZxc9JPUfw==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/openai@3.0.29': resolution: {integrity: sha512-ugVTIVpuSLKTjzSPe1F1DWiblJT/lwrrHx0OZEKjpMk/EYP6j6VD/F7SJqM1dsqOJryeBCJWFbUzLNqc99PrMA==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/provider-utils@4.0.13': - resolution: {integrity: sha512-HHG72BN4d+OWTcq2NwTxOm/2qvk1duYsnhCDtsbYwn/h/4zeqURu1S0+Cn0nY2Ysq9a9HGKvrYuMn9bgFhR2Og==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/provider-utils@4.0.15': resolution: {integrity: sha512-8XiKWbemmCbvNN0CLR9u3PQiet4gtEVIrX4zzLxnCj06AwsEDJwJVBbKrEI4t6qE8XRSIvU2irka0dcpziKW6w==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/provider@3.0.7': - resolution: {integrity: sha512-VkPLrutM6VdA924/mG8OS+5frbVTcu6e046D2bgDo00tehBANR1QBJ/mPcZ9tXMFOsVcm6SQArOregxePzTFPw==} - engines: {node: '>=18'} - '@ai-sdk/provider@3.0.8': resolution: {integrity: sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ==} engines: {node: '>=18'} @@ -335,24 +335,20 @@ packages: '@asamuzakjp/nwsapi@2.3.9': resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} - '@babel/code-frame@7.28.6': - resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==} - engines: {node: '>=6.9.0'} - '@babel/code-frame@7.29.0': resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.6': - resolution: {integrity: sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==} + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} engines: {node: '>=6.9.0'} - '@babel/core@7.28.6': - resolution: {integrity: sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==} + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.28.6': - resolution: {integrity: sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==} + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} engines: {node: '>=6.9.0'} '@babel/helper-compilation-targets@7.28.6': @@ -393,11 +389,6 @@ packages: resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.6': - resolution: {integrity: sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==} - engines: {node: '>=6.0.0'} - hasBin: true - '@babel/parser@7.29.0': resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} engines: {node: '>=6.0.0'} @@ -427,12 +418,8 @@ packages: resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.28.6': - resolution: {integrity: sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.28.6': - resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==} + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} engines: {node: '>=6.9.0'} '@babel/types@7.29.0': @@ -443,6 +430,10 @@ packages: resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} + '@bramus/specificity@2.4.2': + resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} + hasBin: true + '@csstools/color-helpers@6.0.1': resolution: {integrity: sha512-NmXRccUJMk2AWA5A7e5a//3bCIMyOu2hAtdRYrhPPHjDxINuCwX1w6rnIZ4xjLcp0ayv6h8Pc3X0eJUGiAAXHQ==} engines: {node: '>=20.19.0'} @@ -655,19 +646,19 @@ packages: '@fontsource-variable/inter@5.2.8': resolution: {integrity: sha512-kOfP2D+ykbcX/P3IFnokOhVRNoTozo5/JxhAIVYLpea/UBmCQ/YWPBfWIDuBImXX/15KH+eKh4xpEUyS2sQQGQ==} - '@ghostery/adblocker-content@2.13.4': - resolution: {integrity: sha512-VPa4dyHqTyMWxut/wCYYlHdVRsQ2ZXXezTv31WiRhUC86LFKz8rL/Jnj1baHXlRrO5Ndhpll1/e/J/Tzwu6mqg==} + '@ghostery/adblocker-content@2.14.1': + resolution: {integrity: sha512-hDE6RAL9xgQonJQiK1knOHy527PEwlAuvKaha4snE0XO6Vmtk0HThce1M2JFVRxGayWR3nTxoWbvEfGWXU7O/A==} - '@ghostery/adblocker-extended-selectors@2.13.4': - resolution: {integrity: sha512-nDNK72R9Ly+AOBsd3f0SAxtF3FELx7ogOPCDD2MVJtv3qYZG76fHUmUoCGRmN2oHlPPNUQJ+vI4Rm/LRM1B5XQ==} + '@ghostery/adblocker-extended-selectors@2.14.1': + resolution: {integrity: sha512-3RARO2ukDrfwDqVEMD+HKZIwsM9QjjII+U1zqxhLXZ0dZRHjbtUHlZCsokqfjZ1JAa3ZVKcZrF0nZv5SA2LgyA==} - '@ghostery/adblocker-playwright@2.13.4': - resolution: {integrity: sha512-quUqzA1HpuXtGDkW2lmzDYuVDwbxyG73mBIdkA2cvbCRz08Jc9NHssejBzGcRGytBzfOznMCtWwqUqYhZTJ9sA==} + '@ghostery/adblocker-playwright@2.14.1': + resolution: {integrity: sha512-ODNTIVuhBslpehelujprYv4X2Iu0yXKTGk5TEy1aii5m4M0D884KU2htrcOg5GexQ0xoSf4guldsM899f1uEJA==} peerDependencies: playwright: ^1.x - '@ghostery/adblocker@2.13.4': - resolution: {integrity: sha512-rI7MbS+F2ckIr/2brV+QHMyl55W7F1vazAFiJYHcOBi6i4ClI47Ep95HakwB2qM95gv9igQDTE1zFisV2YKgGg==} + '@ghostery/adblocker@2.14.1': + resolution: {integrity: sha512-/cQTMJRd4/7zpgFHWqe+9wqiRPGTy+BhqfkxplvejPgq8d6spBjC6bSJV61rVHJZw5F4KOO5ReKOvuguaKG28A==} '@ghostery/url-parser@1.3.1': resolution: {integrity: sha512-QKqGi+7aDQ4RcyHyCwgEk6B9vWnsBP4Q7htaN0zPJV3ATqTKEQDtSTb9c/AN586oJUDs24YXKcwFYwNweY/YjQ==} @@ -683,18 +674,14 @@ packages: peerDependencies: hono: '>=3.*' - '@isaacs/balanced-match@4.0.1': - resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} - engines: {node: 20 || >=22} - - '@isaacs/brace-expansion@5.0.0': - resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} - engines: {node: 20 || >=22} - '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@isaacs/cliui@9.0.0': + resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==} + engines: {node: '>=18'} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -726,13 +713,6 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@openrouter/ai-sdk-provider@2.1.1': - resolution: {integrity: sha512-UypPbVnSExxmG/4Zg0usRiit3auvQVrjUXSyEhm0sZ9GQnW/d8p/bKgCk2neh1W5YyRSo7PNQvCrAEBHZnqQkQ==} - engines: {node: '>=18'} - peerDependencies: - ai: ^6.0.0 - zod: ^3.25.0 || ^4.0.0 - '@openrouter/ai-sdk-provider@2.2.3': resolution: {integrity: sha512-NovC+BaCfEeJwhToDrs8JeDYXXlJdEyz7lcxkjtyePSE4eoAKik872SyDK0MzXKcz8MRkv7XlNhPI6zz4TQp0g==} engines: {node: '>=18'} @@ -748,8 +728,8 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@playwright/test@1.58.1': - resolution: {integrity: sha512-6LdVIUERWxQMmUSSQi0I53GgCBYgM2RpGngCPY7hSeju+VrKjq3lvs7HpJoPbDiY5QM5EYRtRX5fvrinnMAz3w==} + '@playwright/test@1.58.2': + resolution: {integrity: sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==} engines: {node: '>=18'} hasBin: true @@ -783,8 +763,8 @@ packages: '@remusao/trie@2.1.0': resolution: {integrity: sha512-Er3Q8q0/2OcCJPQYJOPLmCuqO0wu7cav3SPtpjlxSbjFi1x+A1pZkkLD6c9q2rGEkGW/tkrRzfrhNMt8VQjzXg==} - '@rolldown/pluginutils@1.0.0-beta.53': - resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} + '@rolldown/pluginutils@1.0.0-rc.3': + resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} '@rollup/rollup-android-arm-eabi@4.57.1': resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==} @@ -1089,9 +1069,6 @@ packages: '@types/minimatch@3.0.5': resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==} - '@types/node@25.2.0': - resolution: {integrity: sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==} - '@types/node@25.2.3': resolution: {integrity: sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==} @@ -1100,8 +1077,8 @@ packages: peerDependencies: '@types/react': ^19.2.0 - '@types/react@19.2.10': - resolution: {integrity: sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw==} + '@types/react@19.2.14': + resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} @@ -1122,8 +1099,8 @@ packages: resolution: {integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==} engines: {node: '>= 20'} - '@vitejs/plugin-react@5.1.2': - resolution: {integrity: sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==} + '@vitejs/plugin-react@5.1.4': + resolution: {integrity: sha512-VIcFLdRi/VYRU8OL/puL7QXMYafHmqOnwTZY50U1JPlCNj30PxCMx65c494b1K9be9hX83KVt0+gTEwTWLqToA==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 @@ -1175,16 +1152,16 @@ packages: '@webext-core/match-patterns@1.0.3': resolution: {integrity: sha512-NY39ACqCxdKBmHgw361M9pfJma8e4AZo20w9AY+5ZjIj1W2dvXC8J31G5fjfOGbulW9w4WKpT8fPooi0mLkn9A==} - '@wxt-dev/browser@0.1.32': - resolution: {integrity: sha512-jvfSppeLzlH4sOkIvMBJoA1pKoI+U5gTkjDwMKdkTWh0P/fj+KDyze3lzo3S6372viCm8tXUKNez+VKyVz2ZDw==} + '@wxt-dev/browser@0.1.36': + resolution: {integrity: sha512-48Wn8pItPNg7rCdy10c73z6Alto0z5xkBZohPApKK4/uC8C70j9tJRlaxXdHF/u8+SMZGdrvYtz16oLrOxBu6g==} '@wxt-dev/module-react@1.1.5': resolution: {integrity: sha512-KgsUrsgH5rBT8MwiipnDEOHBXmLvTIdFICrI7KjngqSf9DpVRn92HsKmToxY0AYpkP19hHWta2oNYFTzmmm++g==} peerDependencies: wxt: '>=0.19.16' - '@wxt-dev/storage@1.2.6': - resolution: {integrity: sha512-f6AknnpJvhNHW4s0WqwSGCuZAj0fjP3EVNPBO5kB30pY+3Zt/nqZGqJN6FgBLCSkYjPJ8VL1hNX5LMVmvxQoDw==} + '@wxt-dev/storage@1.2.7': + resolution: {integrity: sha512-+rfRmfF2Wd6knXSFfgjLHelKEVnlryI/UG2/gNbO9U/KZJtSvo8QkGSJ1iJQ7jLYCYD+oYCzMZdL7D4BJLCUkw==} '@wxt-dev/webextension-polyfill@1.0.0': resolution: {integrity: sha512-F83YdA5Dmy8u9QjRMY2r5h2GlzcYi/Ur+pvM1jTqPDj32qZlG53vqBLxRzptSrqahweahECBnJMe9GFegArgkQ==} @@ -1205,12 +1182,6 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} - ai@6.0.69: - resolution: {integrity: sha512-zIURMSnNroaVvu47Bm3XhC2y3LRsm8jmkwBgupxF+N7q/s6MpIiv04w1ltlnWqC8+T2PT2rN+f0sUhF+vArkwg==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - ai@6.0.87: resolution: {integrity: sha512-EHq2y9s1OGgN705mPJIII8qaL43Ko7rMUjMHiCWIpG8esnjBNvymlrcFLnwzPRnMD6OAC6PrRZyiD5nZwX3qFw==} engines: {node: '>=18'} @@ -1220,8 +1191,8 @@ packages: ansi-align@3.0.1: resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} - ansi-escapes@7.2.0: - resolution: {integrity: sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==} + ansi-escapes@7.3.0: + resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} engines: {node: '>=18'} ansi-regex@5.0.1: @@ -1244,9 +1215,8 @@ packages: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} aria-query@5.3.0: resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} @@ -1280,17 +1250,21 @@ packages: resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} engines: {node: '>=8.0.0'} - atomically@2.1.0: - resolution: {integrity: sha512-+gDffFXRW6sl/HCwbta7zK4uNqbPjv4YJEAdz7Vu+FLQHe77eZ4bvbJGi4hE0QPeJlMYMA3piXEr1UL3dAwx7Q==} + atomically@2.1.1: + resolution: {integrity: sha512-P4w9o2dqARji6P7MHprklbfiArZAWvo07yW7qs3pdljb3BWr12FIB7W+p0zJiuiVsUpRO0iZn1kFFcpPegg0tQ==} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@4.0.2: + resolution: {integrity: sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg==} + engines: {node: 20 || >=22} + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.9.15: - resolution: {integrity: sha512-kX8h7K2srmDyYnXRIppo4AH/wYgzWVCs+eKr3RusRSQ5PvRYoEFmR/I0PbdTjKFAoKqp5+kbxnNTFO9jOfSVJg==} + baseline-browser-mapping@2.9.19: + resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==} hasBin: true bidi-js@1.0.3: @@ -1299,10 +1273,6 @@ packages: bignumber.js@9.3.1: resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - bluebird@3.7.2: resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} @@ -1319,6 +1289,10 @@ packages: brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@5.0.2: + resolution: {integrity: sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==} + engines: {node: 20 || >=22} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -1338,6 +1312,12 @@ packages: resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} engines: {node: '>=18'} + bundle-require@5.1.0: + resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.18' + c12@3.3.3: resolution: {integrity: sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q==} peerDependencies: @@ -1354,8 +1334,8 @@ packages: resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} engines: {node: '>=16'} - caniuse-lite@1.0.30001764: - resolution: {integrity: sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==} + caniuse-lite@1.0.30001770: + resolution: {integrity: sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw==} chai@6.2.2: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} @@ -1365,10 +1345,6 @@ packages: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} - chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} @@ -1382,13 +1358,16 @@ packages: engines: {node: '>=12.13.0'} hasBin: true - ci-info@4.3.1: - resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} engines: {node: '>=8'} citty@0.1.6: resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + citty@0.2.1: + resolution: {integrity: sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg==} + cli-boxes@3.0.0: resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} engines: {node: '>=10'} @@ -1435,6 +1414,10 @@ packages: resolution: {integrity: sha512-bmkUukX8wAOjHdN26xj5c4ctEV22TQ7dQYhSmuckKhToXrkUn0iIaolHdIxYYqD55nhpSPA9zPQ1yP57GdXP2A==} engines: {node: '>= 0.6.x'} + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + commander@9.5.0: resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} engines: {node: ^12.20.0 || >=14} @@ -1449,8 +1432,8 @@ packages: confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} - confbox@0.2.2: - resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} config-chain@1.1.13: resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} @@ -1498,8 +1481,8 @@ packages: cssom@0.5.0: resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==} - cssstyle@5.3.7: - resolution: {integrity: sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==} + cssstyle@6.0.1: + resolution: {integrity: sha512-IoJs7La+oFp/AB033wBStxNOJt4+9hHMxsXUPANcoXL2b3W4DZKghlJ2cI/eyeRZIQ9ysvYEorVhjrcYctWbog==} engines: {node: '>=20'} csstype@3.2.3: @@ -1545,8 +1528,8 @@ packages: resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} engines: {node: '>=18'} - default-browser@5.4.0: - resolution: {integrity: sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg==} + default-browser@5.5.0: + resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} engines: {node: '>=18'} define-lazy-prop@2.0.0: @@ -1602,8 +1585,8 @@ packages: resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} - dotenv@17.2.3: - resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==} + dotenv@17.3.1: + resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==} engines: {node: '>=12'} eastasianwidth@0.2.0: @@ -1612,8 +1595,8 @@ packages: ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} - electron-to-chromium@1.5.267: - resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} + electron-to-chromium@1.5.286: + resolution: {integrity: sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==} emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} @@ -1624,8 +1607,8 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - enhanced-resolve@5.18.4: - resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} + enhanced-resolve@5.19.0: + resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==} engines: {node: '>=10.13.0'} entities@4.5.0: @@ -1636,6 +1619,10 @@ packages: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + environment@1.1.0: resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} engines: {node: '>=18'} @@ -1646,6 +1633,9 @@ packages: es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-module-lexer@2.0.0: + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + es6-error@4.1.1: resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} @@ -1727,6 +1717,9 @@ packages: engines: {node: '>=18'} hasBin: true + fix-dts-default-cjs-exports@1.0.1: + resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} + foreground-child@3.3.1: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} @@ -1784,8 +1777,8 @@ packages: get-port-please@3.2.0: resolution: {integrity: sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==} - get-tsconfig@4.13.0: - resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + get-tsconfig@4.13.6: + resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} giget@2.0.0: resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} @@ -1831,20 +1824,16 @@ packages: resolution: {integrity: sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==} engines: {node: '>=18'} - happy-dom@20.4.0: - resolution: {integrity: sha512-RDeQm3dT9n0A5f/TszjUmNCLEuPnMGv3Tv4BmNINebz/h17PA6LMBcxJ5FrcqltNBMh9jA/8ufgDdBYUdBt+eg==} + happy-dom@20.6.1: + resolution: {integrity: sha512-+0vhESXXhFwkdjZnJ5DlmJIfUYGgIEEjzIjB+aKJbFuqlvvKyOi+XkI1fYbgYR9QCxG5T08koxsQ6HrQfa5gCQ==} engines: {node: '>=20.0.0'} - has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - hono@4.11.7: - resolution: {integrity: sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw==} + hono@4.11.9: + resolution: {integrity: sha512-Eaw2YTGM6WOxA6CXbckaEvslr2Ne4NFsKrvc0v97JD5awbmeBLO5w9Ho9L9kmKonrwF9RJlW6BxT1PVv/agBHQ==} engines: {node: '>=16.9.0'} hookable@5.5.3: @@ -1860,8 +1849,8 @@ packages: html-escaper@3.0.3: resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} - htmlparser2@10.0.0: - resolution: {integrity: sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==} + htmlparser2@10.1.0: + resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} http-proxy-agent@7.0.2: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} @@ -1871,9 +1860,6 @@ packages: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} - ignore-by-default@1.0.1: - resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==} - immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} @@ -1905,10 +1891,6 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} @@ -1996,8 +1978,8 @@ packages: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} - is-wsl@3.1.0: - resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} engines: {node: '>=16'} isarray@1.0.0: @@ -2028,10 +2010,18 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jackspeak@4.2.3: + resolution: {integrity: sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==} + engines: {node: 20 || >=22} + jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + js-tokens@10.0.0: resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} @@ -2041,8 +2031,8 @@ packages: js-tokens@9.0.1: resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} - jsdom@28.0.0: - resolution: {integrity: sha512-KDYJgZ6T2TKdU8yBfYueq5EPG/EylMsBvCaenWMJb2OXmjgczzwveRCoJ+Hgj1lXPDyasvrgneSn4GBuR1hYyA==} + jsdom@28.1.0: + resolution: {integrity: sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: canvas: ^3.0.0 @@ -2086,8 +2076,8 @@ packages: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} - ky@1.14.2: - resolution: {integrity: sha512-q3RBbsO5A5zrPhB6CaCS8ZUv+NWCXv6JJT4Em0i264G9W0fdPB8YRfnnEi7Dm7X7omAkBIPojzYJ2D1oHTHqug==} + ky@1.14.3: + resolution: {integrity: sha512-9zy9lkjac+TR1c2tG+mkNSVlyOpInnWdSMiue4F+kq8TwJSgv6o8jhLRg8Ho6SnZ9wOYUq/yozts9qQCfk7bIw==} engines: {node: '>=18'} latest-version@9.0.0: @@ -2170,6 +2160,13 @@ packages: resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} engines: {node: '>= 12.0.0'} + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + lines-and-columns@2.0.4: resolution: {integrity: sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -2192,6 +2189,10 @@ packages: resolution: {integrity: sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==} engines: {node: '>=18.0.0'} + load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + local-pkg@1.1.2: resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==} engines: {node: '>=14'} @@ -2272,8 +2273,8 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} - minimatch@10.1.1: - resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} + minimatch@10.2.1: + resolution: {integrity: sha512-MClCe8IL5nRRmawL6ib/eT4oLyeKMGCghibcDWK+J0hh0Q8kqSdia6BvbRMVk6mPa6WqUa5uR2oxt6C5jd533A==} engines: {node: 20 || >=22} minimatch@3.1.2: @@ -2300,6 +2301,9 @@ packages: resolution: {integrity: sha512-I7tSVxHGPlmPN/enE3mS1aOSo6bWBfls+3HmuEeCUBCE7gWnm3cBXCBkpurzFjVRwC6Kld8lLaZ1Iv5vOcjvcQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nano-spawn@1.0.3: resolution: {integrity: sha512-jtpsQDetTnvS2Ts1fiRdci5rx0VYws5jGyC+4IYOTnIQ/wwdf6JdomlHBwqC3bJYOvaKu0C2GSZ1A60anrYpaA==} engines: {node: '>=20.17'} @@ -2345,11 +2349,6 @@ packages: node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} - nodemon@3.1.11: - resolution: {integrity: sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g==} - engines: {node: '>=10'} - hasBin: true - normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -2357,11 +2356,15 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - nypm@0.6.2: - resolution: {integrity: sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==} - engines: {node: ^14.16.0 || >=16.10.0} + nypm@0.6.5: + resolution: {integrity: sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ==} + engines: {node: '>=18'} hasBin: true + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} @@ -2371,13 +2374,6 @@ packages: ohash@2.0.11: resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} - ollama-ai-provider-v2@3.0.3: - resolution: {integrity: sha512-fdSYb81sU80Op/O4tH0eBUMfmc9wCRJBIBRdFZzIYUpEkI6+Qq/k+CWVSaMN/j02UnUTjJf8UIOlASRA3teRcw==} - engines: {node: '>=18'} - peerDependencies: - ai: ^5.0.0 || ^6.0.0 - zod: ^4.0.16 - ollama-ai-provider-v2@3.3.1: resolution: {integrity: sha512-j4BBqqQnvf/uDz+aPYcgU4/MQZERw087Fn1DMGtViA/PgahBq36jHKHVoZfx8mxj+w8cxsKd3eYaDgyZPhE6YA==} engines: {node: '>=18'} @@ -2440,8 +2436,8 @@ packages: pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - perfect-debounce@2.0.0: - resolution: {integrity: sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==} + perfect-debounce@2.1.0: + resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -2464,6 +2460,10 @@ packages: resolution: {integrity: sha512-vnMCM6xZTb1WDmLvtG2lE/2p+t9hDEIvTWJsu6FejkE62vB7gDhvzrpFR4Cw2to+9JNQxVnkAKVPA1KPB98vWg==} hasBin: true + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} @@ -2475,11 +2475,39 @@ packages: engines: {node: '>=18'} hasBin: true + playwright-core@1.58.2: + resolution: {integrity: sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==} + engines: {node: '>=18'} + hasBin: true + playwright@1.58.1: resolution: {integrity: sha512-+2uTZHxSCcxjvGc5C891LrS1/NlxglGxzrC4seZiVjcYVQfUa87wBL6rTDqzGjuoWNjnBzRqKmF6zRYGMvQUaQ==} engines: {node: '>=18'} hasBin: true + playwright@1.58.2: + resolution: {integrity: sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==} + engines: {node: '>=18'} + hasBin: true + + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + postcss-selector-parser@6.0.10: resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} engines: {node: '>=4'} @@ -2514,9 +2542,6 @@ packages: proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} - pstree.remy@1.1.8: - resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} - publish-browser-extension@3.0.3: resolution: {integrity: sha512-cBINZCkLo7YQaGoUvEHthZ0sDzgJQht28IS+SFMT2omSNhGsPiVNRkWir3qLiTrhGhW9Ci2KVHpA1QAMoBdL2g==} hasBin: true @@ -2564,10 +2589,6 @@ packages: readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} - readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} @@ -2600,6 +2621,10 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} @@ -2658,8 +2683,8 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.7.3: - resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} engines: {node: '>=10'} hasBin: true @@ -2691,10 +2716,6 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - simple-update-notifier@2.0.0: - resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} - engines: {node: '>=10'} - sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} @@ -2706,8 +2727,8 @@ packages: resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} engines: {node: '>=18'} - sonic-boom@4.2.0: - resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} + sonic-boom@4.2.1: + resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} @@ -2724,11 +2745,6 @@ packages: resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} engines: {node: '>= 12'} - 'spark@file:': - resolution: {directory: '', type: directory} - engines: {node: ^22.0.0} - hasBin: true - spawn-sync@1.0.15: resolution: {integrity: sha512-9DWBgrgYZzNghseho0JOuh+5fg9u6QWhAWa51QC7+U5rCheZ/j1DrEZnyE0RBBRqZ9uEXGPgSSM0nky6burpVw==} @@ -2797,9 +2813,10 @@ packages: stubborn-utils@1.0.2: resolution: {integrity: sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg==} - supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} @@ -2815,6 +2832,13 @@ packages: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + thread-stream@3.1.0: resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} @@ -2824,6 +2848,9 @@ packages: tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyexec@1.0.2: resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} engines: {node: '>=18'} @@ -2836,14 +2863,11 @@ packages: resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} engines: {node: '>=14.0.0'} - tldts-core@7.0.19: - resolution: {integrity: sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==} - tldts-core@7.0.23: resolution: {integrity: sha512-0g9vrtDQLrNIiCj22HSe9d4mLVG3g5ph5DZ8zCKBr4OtrspmNB6ss7hVyzArAeE88ceZocIEGkyW1Ime7fxPtQ==} - tldts-experimental@7.0.19: - resolution: {integrity: sha512-Pu+urmGB5Ja0SQxzF0j1mG40Swnq0xrC6lcQwpPbpD0VlRtqym2Y1bfZen/+mKZ022/FxBIbtQzOU1KRrO1RSg==} + tldts-experimental@7.0.23: + resolution: {integrity: sha512-jsBnhWMTWVodIrvNEM0vFUf/rNr8fwt9AwsbaObiEQxR0q958ZkVOmvyR+0iaIYBq00FkGGqfnbfIG5Y7GU9MA==} tldts@7.0.23: resolution: {integrity: sha512-ASdhgQIBSay0R/eXggAkQ53G4nTJqTXqC2kbaBbdDwM7SkjyZyO0OaaN1/FH7U/yCeqOHDwFO5j8+Os/IS1dXw==} @@ -2860,10 +2884,6 @@ packages: toucan-js@4.1.1: resolution: {integrity: sha512-GTPwEaCRN8IbYe5/VeGiwxYvMO0dKaC16fTeLbF+QGswjkLZ9JUqAfDhLMyH2SWukYhmetH+uxWa1Bhluv/evQ==} - touch@3.1.1: - resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==} - hasBin: true - tough-cookie@6.0.0: resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} engines: {node: '>=16'} @@ -2875,9 +2895,35 @@ packages: resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} engines: {node: '>=20'} + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsup@8.5.1: + resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.5.0' + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + tsx@4.21.0: resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} engines: {node: '>=18.0.0'} @@ -2908,9 +2954,6 @@ packages: uhyphen@0.2.0: resolution: {integrity: sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==} - undefsafe@2.0.5: - resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} - undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} @@ -2944,11 +2987,6 @@ packages: resolution: {integrity: sha512-+dwUY4L35XFYEzE+OAL3sarJdUioVovq+8f7lcIJ7wnmnYQV5UD1Y/lcwaMSyaQ6Bj3JMj1XSTjZbNLHn/19yA==} engines: {node: '>=18'} - use-sync-external-store@1.6.0: - resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -2956,8 +2994,8 @@ packages: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true - vite-node@5.2.0: - resolution: {integrity: sha512-7UT39YxUukIA97zWPXUGb0SGSiLexEGlavMwU3HDE6+d/HJhKLjLqu4eX2qv6SQiocdhKLRcusroDwXHQ6CnRQ==} + vite-node@5.3.0: + resolution: {integrity: sha512-8f20COPYJujc3OKPX6OuyBy3ZIv2det4eRRU4GY1y2MjbeGSUmPjedxg1b72KnTagCofwvZ65ThzjxDW2AtQFQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -3212,25 +3250,12 @@ snapshots: '@adobe/css-tools@4.4.4': {} - '@ai-sdk/anthropic@3.0.35(zod@4.3.6)': - dependencies: - '@ai-sdk/provider': 3.0.7 - '@ai-sdk/provider-utils': 4.0.13(zod@4.3.6) - zod: 4.3.6 - '@ai-sdk/anthropic@3.0.44(zod@4.3.6)': dependencies: '@ai-sdk/provider': 3.0.8 '@ai-sdk/provider-utils': 4.0.15(zod@4.3.6) zod: 4.3.6 - '@ai-sdk/gateway@3.0.32(zod@4.3.6)': - dependencies: - '@ai-sdk/provider': 3.0.7 - '@ai-sdk/provider-utils': 4.0.13(zod@4.3.6) - '@vercel/oidc': 3.1.0 - zod: 4.3.6 - '@ai-sdk/gateway@3.0.47(zod@4.3.6)': dependencies: '@ai-sdk/provider': 3.0.8 @@ -3238,17 +3263,6 @@ snapshots: '@vercel/oidc': 3.1.0 zod: 4.3.6 - '@ai-sdk/google-vertex@4.0.41(zod@4.3.6)': - dependencies: - '@ai-sdk/anthropic': 3.0.35(zod@4.3.6) - '@ai-sdk/google': 3.0.20(zod@4.3.6) - '@ai-sdk/provider': 3.0.7 - '@ai-sdk/provider-utils': 4.0.13(zod@4.3.6) - google-auth-library: 10.5.0 - zod: 4.3.6 - transitivePeerDependencies: - - supports-color - '@ai-sdk/google-vertex@4.0.58(zod@4.3.6)': dependencies: '@ai-sdk/anthropic': 3.0.44(zod@4.3.6) @@ -3260,49 +3274,24 @@ snapshots: transitivePeerDependencies: - supports-color - '@ai-sdk/google@3.0.20(zod@4.3.6)': - dependencies: - '@ai-sdk/provider': 3.0.7 - '@ai-sdk/provider-utils': 4.0.13(zod@4.3.6) - zod: 4.3.6 - '@ai-sdk/google@3.0.29(zod@4.3.6)': dependencies: '@ai-sdk/provider': 3.0.8 '@ai-sdk/provider-utils': 4.0.15(zod@4.3.6) zod: 4.3.6 - '@ai-sdk/openai-compatible@2.0.26(zod@4.3.6)': - dependencies: - '@ai-sdk/provider': 3.0.7 - '@ai-sdk/provider-utils': 4.0.13(zod@4.3.6) - zod: 4.3.6 - '@ai-sdk/openai-compatible@2.0.30(zod@4.3.6)': dependencies: '@ai-sdk/provider': 3.0.8 '@ai-sdk/provider-utils': 4.0.15(zod@4.3.6) zod: 4.3.6 - '@ai-sdk/openai@3.0.25(zod@4.3.6)': - dependencies: - '@ai-sdk/provider': 3.0.7 - '@ai-sdk/provider-utils': 4.0.13(zod@4.3.6) - zod: 4.3.6 - '@ai-sdk/openai@3.0.29(zod@4.3.6)': dependencies: '@ai-sdk/provider': 3.0.8 '@ai-sdk/provider-utils': 4.0.15(zod@4.3.6) zod: 4.3.6 - '@ai-sdk/provider-utils@4.0.13(zod@4.3.6)': - dependencies: - '@ai-sdk/provider': 3.0.7 - '@standard-schema/spec': 1.1.0 - eventsource-parser: 3.0.6 - zod: 4.3.6 - '@ai-sdk/provider-utils@4.0.15(zod@4.3.6)': dependencies: '@ai-sdk/provider': 3.0.8 @@ -3310,10 +3299,6 @@ snapshots: eventsource-parser: 3.0.6 zod: 4.3.6 - '@ai-sdk/provider@3.0.7': - dependencies: - json-schema: 0.4.0 - '@ai-sdk/provider@3.0.8': dependencies: json-schema: 0.4.0 @@ -3345,51 +3330,45 @@ snapshots: '@asamuzakjp/nwsapi@2.3.9': {} - '@babel/code-frame@7.28.6': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - '@babel/code-frame@7.29.0': dependencies: '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.28.6': {} + '@babel/compat-data@7.29.0': {} - '@babel/core@7.28.6': + '@babel/core@7.29.0': dependencies: - '@babel/code-frame': 7.28.6 - '@babel/generator': 7.28.6 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.28.6) + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) '@babel/helpers': 7.28.6 - '@babel/parser': 7.28.6 + '@babel/parser': 7.29.0 '@babel/template': 7.28.6 - '@babel/traverse': 7.28.6 - '@babel/types': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/generator@7.28.6': + '@babel/generator@7.29.1': dependencies: - '@babel/parser': 7.28.6 - '@babel/types': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 '@babel/helper-compilation-targets@7.28.6': dependencies: - '@babel/compat-data': 7.28.6 + '@babel/compat-data': 7.29.0 '@babel/helper-validator-option': 7.27.1 browserslist: 4.28.1 lru-cache: 5.1.1 @@ -3399,17 +3378,17 @@ snapshots: '@babel/helper-module-imports@7.28.6': dependencies: - '@babel/traverse': 7.28.6 - '@babel/types': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.6(@babel/core@7.28.6)': + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-module-imports': 7.28.6 '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.6 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color @@ -3424,24 +3403,20 @@ snapshots: '@babel/helpers@7.28.6': dependencies: '@babel/template': 7.28.6 - '@babel/types': 7.28.6 - - '@babel/parser@7.28.6': - dependencies: - '@babel/types': 7.28.6 + '@babel/types': 7.29.0 '@babel/parser@7.29.0': dependencies: '@babel/types': 7.29.0 - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.6)': + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.6)': + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 '@babel/runtime@7.28.2': {} @@ -3450,27 +3425,22 @@ snapshots: '@babel/template@7.28.6': dependencies: - '@babel/code-frame': 7.28.6 - '@babel/parser': 7.28.6 - '@babel/types': 7.28.6 + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 - '@babel/traverse@7.28.6': + '@babel/traverse@7.29.0': dependencies: - '@babel/code-frame': 7.28.6 - '@babel/generator': 7.28.6 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.6 + '@babel/parser': 7.29.0 '@babel/template': 7.28.6 - '@babel/types': 7.28.6 - debug: 4.4.3(supports-color@5.5.0) + '@babel/types': 7.29.0 + debug: 4.4.3 transitivePeerDependencies: - supports-color - '@babel/types@7.28.6': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/types@7.29.0': dependencies: '@babel/helper-string-parser': 7.27.1 @@ -3478,6 +3448,10 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} + '@bramus/specificity@2.4.2': + dependencies: + css-tree: 3.1.0 + '@csstools/color-helpers@6.0.1': {} '@csstools/css-calc@3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': @@ -3598,48 +3572,42 @@ snapshots: '@fontsource-variable/inter@5.2.8': {} - '@ghostery/adblocker-content@2.13.4': + '@ghostery/adblocker-content@2.14.1': dependencies: - '@ghostery/adblocker-extended-selectors': 2.13.4 + '@ghostery/adblocker-extended-selectors': 2.14.1 - '@ghostery/adblocker-extended-selectors@2.13.4': {} + '@ghostery/adblocker-extended-selectors@2.14.1': {} - '@ghostery/adblocker-playwright@2.13.4(playwright@1.58.1)': + '@ghostery/adblocker-playwright@2.14.1(playwright@1.58.1)': dependencies: - '@ghostery/adblocker': 2.13.4 - '@ghostery/adblocker-content': 2.13.4 + '@ghostery/adblocker': 2.14.1 + '@ghostery/adblocker-content': 2.14.1 playwright: 1.58.1 - tldts-experimental: 7.0.19 + tldts-experimental: 7.0.23 - '@ghostery/adblocker@2.13.4': + '@ghostery/adblocker@2.14.1': dependencies: - '@ghostery/adblocker-content': 2.13.4 - '@ghostery/adblocker-extended-selectors': 2.13.4 + '@ghostery/adblocker-content': 2.14.1 + '@ghostery/adblocker-extended-selectors': 2.14.1 '@ghostery/url-parser': 1.3.1 '@remusao/guess-url-type': 2.1.0 '@remusao/small': 2.1.0 '@remusao/smaz': 2.2.0 - tldts-experimental: 7.0.19 + tldts-experimental: 7.0.23 '@ghostery/url-parser@1.3.1': dependencies: - tldts-experimental: 7.0.19 + tldts-experimental: 7.0.23 - '@hono/node-server@1.19.9(hono@4.11.7)': + '@hono/node-server@1.19.9(hono@4.11.9)': dependencies: - hono: 4.11.7 + hono: 4.11.9 - '@hono/sentry@1.2.2(hono@4.11.7)': + '@hono/sentry@1.2.2(hono@4.11.9)': dependencies: - hono: 4.11.7 + hono: 4.11.9 toucan-js: 4.1.1 - '@isaacs/balanced-match@4.0.1': {} - - '@isaacs/brace-expansion@5.0.0': - dependencies: - '@isaacs/balanced-match': 4.0.1 - '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -3649,6 +3617,8 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@isaacs/cliui@9.0.0': {} + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -3682,11 +3652,6 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 - '@openrouter/ai-sdk-provider@2.1.1(ai@6.0.69(zod@4.3.6))(zod@4.3.6)': - dependencies: - ai: 6.0.69(zod@4.3.6) - zod: 4.3.6 - '@openrouter/ai-sdk-provider@2.2.3(ai@6.0.87(zod@4.3.6))(zod@4.3.6)': dependencies: ai: 6.0.87(zod@4.3.6) @@ -3697,9 +3662,9 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@playwright/test@1.58.1': + '@playwright/test@1.58.2': dependencies: - playwright: 1.58.1 + playwright: 1.58.2 '@pnpm/config.env-replace@1.1.0': {} @@ -3730,7 +3695,7 @@ snapshots: '@remusao/trie@2.1.0': {} - '@rolldown/pluginutils@1.0.0-beta.53': {} + '@rolldown/pluginutils@1.0.0-rc.3': {} '@rollup/rollup-android-arm-eabi@4.57.1': optional: true @@ -3823,7 +3788,7 @@ snapshots: '@tailwindcss/node@4.1.18': dependencies: '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.18.4 + enhanced-resolve: 5.19.0 jiti: 2.6.1 lightningcss: 1.30.2 magic-string: 0.30.21 @@ -3913,15 +3878,15 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@babel/runtime': 7.28.6 '@testing-library/dom': 10.4.1 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) optionalDependencies: - '@types/react': 19.2.10 - '@types/react-dom': 19.2.3(@types/react@19.2.10) + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1)': dependencies: @@ -3931,24 +3896,24 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.28.6 - '@babel/types': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.28.0 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.28.6 + '@babel/types': 7.29.0 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.28.6 - '@babel/types': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.28.6 + '@babel/types': 7.29.0 '@types/chai@5.2.3': dependencies: @@ -3975,19 +3940,15 @@ snapshots: '@types/minimatch@3.0.5': {} - '@types/node@25.2.0': - dependencies: - undici-types: 7.16.0 - '@types/node@25.2.3': dependencies: undici-types: 7.16.0 - '@types/react-dom@19.2.3(@types/react@19.2.10)': + '@types/react-dom@19.2.3(@types/react@19.2.14)': dependencies: - '@types/react': 19.2.10 + '@types/react': 19.2.14 - '@types/react@19.2.10': + '@types/react@19.2.14': dependencies: csstype: 3.2.3 @@ -4005,19 +3966,19 @@ snapshots: '@vercel/oidc@3.1.0': {} - '@vitejs/plugin-react@5.1.2(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))': + '@vitejs/plugin-react@5.1.4(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))': dependencies: - '@babel/core': 7.28.6 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.6) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.6) - '@rolldown/pluginutils': 1.0.0-beta.53 + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@rolldown/pluginutils': 1.0.0-rc.3 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 vite: 7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@4.0.18(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.2.0)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@28.0.0)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/coverage-v8@4.0.18(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.2.3)(happy-dom@20.6.1)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@bcoe/v8-coverage': 1.0.2 '@vitest/utils': 4.0.18 @@ -4029,7 +3990,7 @@ snapshots: obug: 2.1.1 std-env: 3.10.0 tinyrainbow: 3.0.3 - vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.2.0)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@28.0.0)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) + vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.2.3)(happy-dom@20.6.1)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) '@vitest/expect@4.0.18': dependencies: @@ -4040,14 +4001,6 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@25.2.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))': - dependencies: - '@vitest/spy': 4.0.18 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 7.3.1(@types/node@25.2.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.0.18 @@ -4088,22 +4041,22 @@ snapshots: '@webext-core/match-patterns@1.0.3': {} - '@wxt-dev/browser@0.1.32': + '@wxt-dev/browser@0.1.36': dependencies: '@types/filesystem': 0.0.36 '@types/har-format': 1.2.16 '@wxt-dev/module-react@1.1.5(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))(wxt@0.20.13(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.57.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: - '@vitejs/plugin-react': 5.1.2(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)) + '@vitejs/plugin-react': 5.1.4(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)) wxt: 0.20.13(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.57.1)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - supports-color - vite - '@wxt-dev/storage@1.2.6': + '@wxt-dev/storage@1.2.7': dependencies: - '@wxt-dev/browser': 0.1.32 + '@wxt-dev/browser': 0.1.36 async-mutex: 0.5.0 dequal: 2.0.3 @@ -4118,14 +4071,6 @@ snapshots: agent-base@7.1.4: {} - ai@6.0.69(zod@4.3.6): - dependencies: - '@ai-sdk/gateway': 3.0.32(zod@4.3.6) - '@ai-sdk/provider': 3.0.7 - '@ai-sdk/provider-utils': 4.0.13(zod@4.3.6) - '@opentelemetry/api': 1.9.0 - zod: 4.3.6 - ai@6.0.87(zod@4.3.6): dependencies: '@ai-sdk/gateway': 3.0.47(zod@4.3.6) @@ -4138,7 +4083,7 @@ snapshots: dependencies: string-width: 4.2.3 - ansi-escapes@7.2.0: + ansi-escapes@7.3.0: dependencies: environment: 1.1.0 @@ -4154,10 +4099,7 @@ snapshots: ansi-styles@6.2.3: {} - anymatch@3.1.3: - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 + any-promise@1.3.0: {} aria-query@5.3.0: dependencies: @@ -4185,16 +4127,20 @@ snapshots: atomic-sleep@1.0.0: {} - atomically@2.1.0: + atomically@2.1.1: dependencies: stubborn-fs: 2.0.0 when-exit: 2.1.5 balanced-match@1.0.2: {} + balanced-match@4.0.2: + dependencies: + jackspeak: 4.2.3 + base64-js@1.5.1: {} - baseline-browser-mapping@2.9.15: {} + baseline-browser-mapping@2.9.19: {} bidi-js@1.0.3: dependencies: @@ -4202,8 +4148,6 @@ snapshots: bignumber.js@9.3.1: {} - binary-extensions@2.3.0: {} - bluebird@3.7.2: {} boolbase@1.0.0: {} @@ -4228,15 +4172,19 @@ snapshots: dependencies: balanced-match: 1.0.2 + brace-expansion@5.0.2: + dependencies: + balanced-match: 4.0.2 + braces@3.0.3: dependencies: fill-range: 7.1.1 browserslist@4.28.1: dependencies: - baseline-browser-mapping: 2.9.15 - caniuse-lite: 1.0.30001764 - electron-to-chromium: 1.5.267 + baseline-browser-mapping: 2.9.19 + caniuse-lite: 1.0.30001770 + electron-to-chromium: 1.5.286 node-releases: 2.0.27 update-browserslist-db: 1.2.3(browserslist@4.28.1) @@ -4248,18 +4196,23 @@ snapshots: dependencies: run-applescript: 7.1.0 + bundle-require@5.1.0(esbuild@0.27.3): + dependencies: + esbuild: 0.27.3 + load-tsconfig: 0.2.5 + c12@3.3.3(magicast@0.3.5): dependencies: chokidar: 5.0.0 - confbox: 0.2.2 + confbox: 0.2.4 defu: 6.1.4 - dotenv: 17.2.3 + dotenv: 17.3.1 exsolve: 1.0.8 giget: 2.0.0 jiti: 2.6.1 ohash: 2.0.11 pathe: 2.0.3 - perfect-debounce: 2.0.0 + perfect-debounce: 2.1.0 pkg-types: 2.3.0 rc9: 2.1.2 optionalDependencies: @@ -4269,24 +4222,12 @@ snapshots: camelcase@8.0.0: {} - caniuse-lite@1.0.30001764: {} + caniuse-lite@1.0.30001770: {} chai@6.2.2: {} chalk@5.6.2: {} - chokidar@3.6.0: - dependencies: - anymatch: 3.1.3 - braces: 3.0.3 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - chokidar@4.0.3: dependencies: readdirp: 4.1.2 @@ -4304,12 +4245,14 @@ snapshots: transitivePeerDependencies: - supports-color - ci-info@4.3.1: {} + ci-info@4.4.0: {} citty@0.1.6: dependencies: consola: 3.4.2 + citty@0.2.1: {} + cli-boxes@3.0.0: {} cli-cursor@5.0.0: @@ -4347,6 +4290,8 @@ snapshots: dependencies: graceful-readlink: 1.0.1 + commander@4.1.1: {} + commander@9.5.0: {} concat-map@0.0.1: {} @@ -4360,7 +4305,7 @@ snapshots: confbox@0.1.8: {} - confbox@0.2.2: {} + confbox@0.2.4: {} config-chain@1.1.13: dependencies: @@ -4369,7 +4314,7 @@ snapshots: configstore@7.1.0: dependencies: - atomically: 2.1.0 + atomically: 2.1.1 dot-prop: 9.0.0 graceful-fs: 4.2.11 xdg-basedir: 5.1.0 @@ -4413,7 +4358,7 @@ snapshots: cssom@0.5.0: {} - cssstyle@5.3.7: + cssstyle@6.0.1: dependencies: '@asamuzakjp/css-color': 4.1.2 '@csstools/css-syntax-patches-for-csstree': 1.0.27 @@ -4437,11 +4382,9 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.4.3(supports-color@5.5.0): + debug@4.4.3: dependencies: ms: 2.1.3 - optionalDependencies: - supports-color: 5.5.0 decimal.js@10.6.0: {} @@ -4449,7 +4392,7 @@ snapshots: default-browser-id@5.0.1: {} - default-browser@5.4.0: + default-browser@5.5.0: dependencies: bundle-name: 4.1.0 default-browser-id: 5.0.1 @@ -4498,7 +4441,7 @@ snapshots: dotenv@16.6.1: {} - dotenv@17.2.3: {} + dotenv@17.3.1: {} eastasianwidth@0.2.0: {} @@ -4506,7 +4449,7 @@ snapshots: dependencies: safe-buffer: 5.2.1 - electron-to-chromium@1.5.267: {} + electron-to-chromium@1.5.286: {} emoji-regex@10.6.0: {} @@ -4514,7 +4457,7 @@ snapshots: emoji-regex@9.2.2: {} - enhanced-resolve@5.18.4: + enhanced-resolve@5.19.0: dependencies: graceful-fs: 4.2.11 tapable: 2.3.0 @@ -4523,6 +4466,8 @@ snapshots: entities@6.0.1: {} + entities@7.0.1: {} + environment@1.1.0: {} error-ex@1.3.4: @@ -4531,6 +4476,8 @@ snapshots: es-module-lexer@1.7.0: {} + es-module-lexer@2.0.0: {} + es6-error@4.1.1: {} esbuild@0.27.3: @@ -4621,6 +4568,12 @@ snapshots: minimist: 1.2.8 xml2js: 0.6.2 + fix-dts-default-cjs-exports@1.0.1: + dependencies: + magic-string: 0.30.21 + mlly: 1.8.0 + rollup: 4.57.1 + foreground-child@3.3.1: dependencies: cross-spawn: 7.0.6 @@ -4680,7 +4633,7 @@ snapshots: get-port-please@3.2.0: {} - get-tsconfig@4.13.0: + get-tsconfig@4.13.6: dependencies: resolve-pkg-maps: 1.0.0 @@ -4690,7 +4643,7 @@ snapshots: consola: 3.4.2 defu: 6.1.4 node-fetch-native: 1.6.7 - nypm: 0.6.2 + nypm: 0.6.5 pathe: 2.0.3 glob-parent@5.1.2: @@ -4741,23 +4694,21 @@ snapshots: transitivePeerDependencies: - supports-color - happy-dom@20.4.0: + happy-dom@20.6.1: dependencies: '@types/node': 25.2.3 '@types/whatwg-mimetype': 3.0.2 '@types/ws': 8.18.1 - entities: 4.5.0 + entities: 6.0.1 whatwg-mimetype: 3.0.0 ws: 8.19.0 transitivePeerDependencies: - bufferutil - utf-8-validate - has-flag@3.0.0: {} - has-flag@4.0.0: {} - hono@4.11.7: {} + hono@4.11.9: {} hookable@5.5.3: {} @@ -4771,29 +4722,27 @@ snapshots: html-escaper@3.0.3: {} - htmlparser2@10.0.0: + htmlparser2@10.1.0: dependencies: domelementtype: 2.3.0 domhandler: 5.0.3 domutils: 3.2.2 - entities: 6.0.1 + entities: 7.0.1 http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 transitivePeerDependencies: - supports-color https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 transitivePeerDependencies: - supports-color - ignore-by-default@1.0.1: {} - immediate@3.0.6: {} import-meta-resolve@4.2.0: {} @@ -4814,10 +4763,6 @@ snapshots: is-arrayish@0.2.1: {} - is-binary-path@2.1.0: - dependencies: - binary-extensions: 2.3.0 - is-docker@2.2.1: {} is-docker@3.0.0: {} @@ -4873,7 +4818,7 @@ snapshots: dependencies: is-docker: 2.2.1 - is-wsl@3.1.0: + is-wsl@3.1.1: dependencies: is-inside-container: 1.0.0 @@ -4904,20 +4849,27 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + jackspeak@4.2.3: + dependencies: + '@isaacs/cliui': 9.0.0 + jiti@2.6.1: {} + joycon@3.1.1: {} + js-tokens@10.0.0: {} js-tokens@4.0.0: {} js-tokens@9.0.1: {} - jsdom@28.0.0: + jsdom@28.1.0: dependencies: '@acemir/cssom': 0.9.31 '@asamuzakjp/dom-selector': 6.8.1 + '@bramus/specificity': 2.4.2 '@exodus/bytes': 1.14.1 - cssstyle: 5.3.7 + cssstyle: 6.0.1 data-urls: 7.0.0 decimal.js: 10.6.0 html-encoding-sniffer: 6.0.0 @@ -4976,7 +4928,7 @@ snapshots: kleur@3.0.3: {} - ky@1.14.2: {} + ky@1.14.3: {} latest-version@9.0.0: dependencies: @@ -4988,7 +4940,7 @@ snapshots: lighthouse-logger@2.0.2: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3 marky: 1.3.0 transitivePeerDependencies: - supports-color @@ -5042,6 +4994,10 @@ snapshots: lightningcss-win32-arm64-msvc: 1.30.2 lightningcss-win32-x64-msvc: 1.30.2 + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + lines-and-columns@2.0.4: {} linkedom@0.18.12: @@ -5049,7 +5005,7 @@ snapshots: css-select: 5.2.2 cssom: 0.5.0 html-escaper: 3.0.3 - htmlparser2: 10.0.0 + htmlparser2: 10.1.0 uhyphen: 0.2.0 liquidjs@10.24.0: @@ -5065,6 +5021,8 @@ snapshots: rfdc: 1.4.1 wrap-ansi: 9.0.2 + load-tsconfig@0.2.5: {} + local-pkg@1.1.2: dependencies: mlly: 1.8.0 @@ -5080,7 +5038,7 @@ snapshots: log-update@6.1.0: dependencies: - ansi-escapes: 7.2.0 + ansi-escapes: 7.3.0 cli-cursor: 5.0.0 slice-ansi: 7.1.2 strip-ansi: 7.1.2 @@ -5102,8 +5060,8 @@ snapshots: magicast@0.3.5: dependencies: - '@babel/parser': 7.28.6 - '@babel/types': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 source-map-js: 1.2.1 magicast@0.5.2: @@ -5114,7 +5072,7 @@ snapshots: make-dir@4.0.0: dependencies: - semver: 7.7.3 + semver: 7.7.4 make-error@1.3.6: {} @@ -5142,9 +5100,9 @@ snapshots: min-indent@1.0.1: {} - minimatch@10.1.1: + minimatch@10.2.1: dependencies: - '@isaacs/brace-expansion': 5.0.0 + brace-expansion: 5.0.2 minimatch@3.1.2: dependencies: @@ -5174,6 +5132,12 @@ snapshots: array-union: 3.0.1 minimatch: 3.1.2 + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + nano-spawn@1.0.3: {} nanoid@3.3.11: {} @@ -5200,40 +5164,27 @@ snapshots: dependencies: growly: 1.3.0 is-wsl: 2.2.0 - semver: 7.7.3 + semver: 7.7.4 shellwords: 0.1.1 uuid: 8.3.2 which: 2.0.2 node-releases@2.0.27: {} - nodemon@3.1.11: - dependencies: - chokidar: 3.6.0 - debug: 4.4.3(supports-color@5.5.0) - ignore-by-default: 1.0.1 - minimatch: 3.1.2 - pstree.remy: 1.1.8 - semver: 7.7.3 - simple-update-notifier: 2.0.0 - supports-color: 5.5.0 - touch: 3.1.1 - undefsafe: 2.0.5 - normalize-path@3.0.0: {} nth-check@2.1.1: dependencies: boolbase: 1.0.0 - nypm@0.6.2: + nypm@0.6.5: dependencies: - citty: 0.1.6 - consola: 3.4.2 + citty: 0.2.1 pathe: 2.0.3 - pkg-types: 2.3.0 tinyexec: 1.0.2 + object-assign@4.1.1: {} + obug@2.1.1: {} ofetch@1.5.1: @@ -5244,13 +5195,6 @@ snapshots: ohash@2.0.11: {} - ollama-ai-provider-v2@3.0.3(ai@6.0.69(zod@4.3.6))(zod@4.3.6): - dependencies: - '@ai-sdk/provider': 3.0.8 - '@ai-sdk/provider-utils': 4.0.15(zod@4.3.6) - ai: 6.0.69(zod@4.3.6) - zod: 4.3.6 - ollama-ai-provider-v2@3.3.1(ai@6.0.87(zod@4.3.6))(zod@4.3.6): dependencies: '@ai-sdk/provider': 3.0.8 @@ -5266,7 +5210,7 @@ snapshots: open@10.2.0: dependencies: - default-browser: 5.4.0 + default-browser: 5.5.0 define-lazy-prop: 3.0.0 is-inside-container: 1.0.0 wsl-utils: 0.1.0 @@ -5295,16 +5239,16 @@ snapshots: package-json@10.0.1: dependencies: - ky: 1.14.2 + ky: 1.14.3 registry-auth-token: 5.1.1 registry-url: 6.0.1 - semver: 7.7.3 + semver: 7.7.4 pako@1.0.11: {} parse-json@7.1.1: dependencies: - '@babel/code-frame': 7.28.6 + '@babel/code-frame': 7.29.0 error-ex: 1.3.4 json-parse-even-better-errors: 3.0.2 lines-and-columns: 2.0.4 @@ -5327,7 +5271,7 @@ snapshots: pathe@2.0.3: {} - perfect-debounce@2.0.0: {} + perfect-debounce@2.1.0: {} picocolors@1.1.1: {} @@ -5352,9 +5296,11 @@ snapshots: quick-format-unescaped: 4.0.4 real-require: 0.2.0 safe-stable-stringify: 2.5.0 - sonic-boom: 4.2.0 + sonic-boom: 4.2.1 thread-stream: 3.1.0 + pirates@4.0.7: {} + pkg-types@1.3.1: dependencies: confbox: 0.1.8 @@ -5363,18 +5309,35 @@ snapshots: pkg-types@2.3.0: dependencies: - confbox: 0.2.2 + confbox: 0.2.4 exsolve: 1.0.8 pathe: 2.0.3 playwright-core@1.58.1: {} + playwright-core@1.58.2: {} + playwright@1.58.1: dependencies: playwright-core: 1.58.1 optionalDependencies: fsevents: 2.3.2 + playwright@1.58.2: + dependencies: + playwright-core: 1.58.2 + optionalDependencies: + fsevents: 2.3.2 + + postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + jiti: 2.6.1 + postcss: 8.5.6 + tsx: 4.21.0 + yaml: 2.8.2 + postcss-selector-parser@6.0.10: dependencies: cssesc: 3.0.0 @@ -5409,13 +5372,11 @@ snapshots: proto-list@1.2.4: {} - pstree.remy@1.1.8: {} - publish-browser-extension@3.0.3: dependencies: cac: 6.7.14 consola: 3.4.2 - dotenv: 17.2.3 + dotenv: 17.3.1 form-data-encoder: 4.1.0 formdata-node: 6.0.3 listr2: 8.3.3 @@ -5467,10 +5428,6 @@ snapshots: string_decoder: 1.1.1 util-deprecate: 1.0.2 - readdirp@3.6.0: - dependencies: - picomatch: 2.3.1 - readdirp@4.1.2: {} readdirp@5.0.0: {} @@ -5494,6 +5451,8 @@ snapshots: require-from-string@2.0.2: {} + resolve-from@5.0.0: {} + resolve-pkg-maps@1.0.0: {} restore-cursor@5.1.0: @@ -5564,7 +5523,7 @@ snapshots: semver@6.3.1: {} - semver@7.7.3: {} + semver@7.7.4: {} set-value@4.1.0: dependencies: @@ -5587,10 +5546,6 @@ snapshots: signal-exit@4.1.0: {} - simple-update-notifier@2.0.0: - dependencies: - semver: 7.7.3 - sisteransi@1.0.5: {} slice-ansi@5.0.0: @@ -5603,7 +5558,7 @@ snapshots: ansi-styles: 6.2.3 is-fullwidth-code-point: 5.1.0 - sonic-boom@4.2.0: + sonic-boom@4.2.1: dependencies: atomic-sleep: 1.0.0 @@ -5618,30 +5573,6 @@ snapshots: source-map@0.7.6: {} - 'spark@file:': - dependencies: - '@ai-sdk/google': 3.0.29(zod@4.3.6) - '@ai-sdk/google-vertex': 4.0.58(zod@4.3.6) - '@ai-sdk/openai': 3.0.29(zod@4.3.6) - '@ai-sdk/openai-compatible': 2.0.30(zod@4.3.6) - '@ghostery/adblocker-playwright': 2.13.4(playwright@1.58.1) - '@openrouter/ai-sdk-provider': 2.2.3(ai@6.0.87(zod@4.3.6))(zod@4.3.6) - ai: 6.0.87(zod@4.3.6) - chalk: 5.6.2 - commander: 14.0.3 - cross-fetch: 4.1.0 - dotenv: 17.2.3 - eventemitter3: 5.0.4 - liquidjs: 10.24.0 - nanoid: 5.1.6 - ollama-ai-provider-v2: 3.3.1(ai@6.0.87(zod@4.3.6))(zod@4.3.6) - playwright: 1.58.1 - turndown: 7.2.2 - zod: 4.3.6 - transitivePeerDependencies: - - encoding - - supports-color - spawn-sync@1.0.15: dependencies: concat-stream: 1.6.2 @@ -5709,9 +5640,15 @@ snapshots: stubborn-utils@1.0.2: {} - supports-color@5.5.0: + sucrase@3.35.1: dependencies: - has-flag: 3.0.0 + '@jridgewell/gen-mapping': 0.3.13 + commander: 4.1.1 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + tinyglobby: 0.2.15 + ts-interface-checker: 0.1.13 supports-color@7.2.0: dependencies: @@ -5723,6 +5660,14 @@ snapshots: tapable@2.3.0: {} + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + thread-stream@3.1.0: dependencies: real-require: 0.2.0 @@ -5731,6 +5676,8 @@ snapshots: tinybench@2.9.0: {} + tinyexec@0.3.2: {} + tinyexec@1.0.2: {} tinyglobby@0.2.15: @@ -5740,13 +5687,11 @@ snapshots: tinyrainbow@3.0.3: {} - tldts-core@7.0.19: {} - tldts-core@7.0.23: {} - tldts-experimental@7.0.19: + tldts-experimental@7.0.23: dependencies: - tldts-core: 7.0.19 + tldts-core: 7.0.23 tldts@7.0.23: dependencies: @@ -5764,8 +5709,6 @@ snapshots: '@sentry/types': 8.9.2 '@sentry/utils': 8.9.2 - touch@3.1.1: {} - tough-cookie@6.0.0: dependencies: tldts: 7.0.23 @@ -5776,12 +5719,44 @@ snapshots: dependencies: punycode: 2.3.1 + tree-kill@1.2.2: {} + + ts-interface-checker@0.1.13: {} + tslib@2.8.1: {} + tsup@8.5.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2): + dependencies: + bundle-require: 5.1.0(esbuild@0.27.3) + cac: 6.7.14 + chokidar: 4.0.3 + consola: 3.4.2 + debug: 4.4.3 + esbuild: 0.27.3 + fix-dts-default-cjs-exports: 1.0.1 + joycon: 3.1.1 + picocolors: 1.1.1 + postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2) + resolve-from: 5.0.0 + rollup: 4.57.1 + source-map: 0.7.6 + sucrase: 3.35.1 + tinyexec: 0.3.2 + tinyglobby: 0.2.15 + tree-kill: 1.2.2 + optionalDependencies: + postcss: 8.5.6 + typescript: 5.9.3 + transitivePeerDependencies: + - jiti + - supports-color + - tsx + - yaml + tsx@4.21.0: dependencies: esbuild: 0.27.3 - get-tsconfig: 4.13.0 + get-tsconfig: 4.13.6 optionalDependencies: fsevents: 2.3.3 @@ -5801,8 +5776,6 @@ snapshots: uhyphen@0.2.0: {} - undefsafe@2.0.5: {} - undici-types@7.16.0: {} undici@7.22.0: {} @@ -5854,22 +5827,17 @@ snapshots: is-npm: 6.1.0 latest-version: 9.0.0 pupa: 3.3.0 - semver: 7.7.3 + semver: 7.7.4 xdg-basedir: 5.1.0 - use-sync-external-store@1.6.0(react@19.2.4): - dependencies: - react: 19.2.4 - optional: true - util-deprecate@1.0.2: {} uuid@8.3.2: {} - vite-node@5.2.0(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2): + vite-node@5.3.0(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2): dependencies: cac: 6.7.14 - es-module-lexer: 1.7.0 + es-module-lexer: 2.0.0 obug: 2.1.1 pathe: 2.0.3 vite: 7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) @@ -5886,22 +5854,6 @@ snapshots: - tsx - yaml - vite@7.3.1(@types/node@25.2.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2): - dependencies: - esbuild: 0.27.3 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.57.1 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 25.2.0 - fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.30.2 - tsx: 4.21.0 - yaml: 2.8.2 - vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2): dependencies: esbuild: 0.27.3 @@ -5918,47 +5870,7 @@ snapshots: tsx: 4.21.0 yaml: 2.8.2 - vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.2.0)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@28.0.0)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2): - dependencies: - '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@25.2.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)) - '@vitest/pretty-format': 4.0.18 - '@vitest/runner': 4.0.18 - '@vitest/snapshot': 4.0.18 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - es-module-lexer: 1.7.0 - expect-type: 1.3.0 - magic-string: 0.30.21 - obug: 2.1.1 - pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 - tinybench: 2.9.0 - tinyexec: 1.0.2 - tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@25.2.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) - why-is-node-running: 2.3.0 - optionalDependencies: - '@opentelemetry/api': 1.9.0 - '@types/node': 25.2.0 - happy-dom: 20.4.0 - jsdom: 28.0.0 - transitivePeerDependencies: - - jiti - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml - - vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.2.3)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@28.0.0)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2): + vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.2.3)(happy-dom@20.6.1)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2): dependencies: '@vitest/expect': 4.0.18 '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)) @@ -5983,8 +5895,8 @@ snapshots: optionalDependencies: '@opentelemetry/api': 1.9.0 '@types/node': 25.2.3 - happy-dom: 20.4.0 - jsdom: 28.0.0 + happy-dom: 20.6.1 + jsdom: 28.1.0 transitivePeerDependencies: - jiti - less @@ -6105,7 +6017,7 @@ snapshots: wsl-utils@0.1.0: dependencies: - is-wsl: 3.1.0 + is-wsl: 3.1.1 wxt@0.20.13(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.57.1)(tsx@4.21.0)(yaml@2.8.2): dependencies: @@ -6114,16 +6026,16 @@ snapshots: '@webext-core/fake-browser': 1.3.4 '@webext-core/isolated-element': 1.1.3 '@webext-core/match-patterns': 1.0.3 - '@wxt-dev/browser': 0.1.32 - '@wxt-dev/storage': 1.2.6 + '@wxt-dev/browser': 0.1.36 + '@wxt-dev/storage': 1.2.7 async-mutex: 0.5.0 c12: 3.3.3(magicast@0.3.5) cac: 6.7.14 chokidar: 4.0.3 - ci-info: 4.3.1 + ci-info: 4.4.0 consola: 3.4.2 defu: 6.1.4 - dotenv: 17.2.3 + dotenv: 17.3.1 dotenv-expand: 12.0.3 esbuild: 0.27.3 fast-glob: 3.3.3 @@ -6133,26 +6045,26 @@ snapshots: giget: 2.0.0 hookable: 5.5.3 import-meta-resolve: 4.2.0 - is-wsl: 3.1.0 + is-wsl: 3.1.1 json5: 2.2.3 jszip: 3.10.1 linkedom: 0.18.12 magicast: 0.3.5 - minimatch: 10.1.1 + minimatch: 10.2.1 nano-spawn: 1.0.3 normalize-path: 3.0.0 - nypm: 0.6.2 + nypm: 0.6.5 ohash: 2.0.11 open: 10.2.0 ora: 8.2.0 - perfect-debounce: 2.0.0 + perfect-debounce: 2.1.0 picocolors: 1.1.1 prompts: 2.4.2 publish-browser-extension: 3.0.3 scule: 1.3.0 unimport: 5.6.0 vite: 7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) - vite-node: 5.2.0(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) + vite-node: 5.3.0(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) web-ext-run: 0.2.4 transitivePeerDependencies: - '@types/node' @@ -6208,8 +6120,7 @@ snapshots: zod@4.3.6: {} - zustand@5.0.11(@types/react@19.2.10)(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4)): + zustand@5.0.11(@types/react@19.2.14)(react@19.2.4): optionalDependencies: - '@types/react': 19.2.10 + '@types/react': 19.2.14 react: 19.2.4 - use-sync-external-store: 1.6.0(react@19.2.4) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 55f73a5a..dee51e92 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,4 +1,2 @@ packages: - - "." - - "extension" - - "server" + - "packages/*" diff --git a/scripts/check-deps.js b/scripts/check-deps.js new file mode 100755 index 00000000..573a521e --- /dev/null +++ b/scripts/check-deps.js @@ -0,0 +1,135 @@ +#!/usr/bin/env node + +/** + * Check for dependency version mismatches across all package.json files in the monorepo. + * + * This script scans all package.json files and ensures that if the same dependency + * appears in multiple packages, they all use the same version. + */ + +import { readFileSync, readdirSync, statSync } from "fs"; +import { join, relative } from "path"; + +const RED = "\x1b[31m"; +const GREEN = "\x1b[32m"; +const YELLOW = "\x1b[33m"; +const RESET = "\x1b[0m"; + +/** + * Recursively find all package.json files in a directory + */ +function findPackageJsonFiles(dir, files = []) { + const entries = readdirSync(dir); + + for (const entry of entries) { + const fullPath = join(dir, entry); + + // Skip node_modules and dist directories + if (entry === "node_modules" || entry === "dist" || entry === ".git") { + continue; + } + + try { + const stat = statSync(fullPath); + + if (stat.isDirectory()) { + findPackageJsonFiles(fullPath, files); + } else if (entry === "package.json") { + files.push(fullPath); + } + } catch (error) { + // Skip files we can't read + continue; + } + } + + return files; +} + +function main() { + const rootDir = process.cwd(); + + // Find all package.json files + const packageJsonFiles = findPackageJsonFiles(rootDir); + + console.log(`Found ${packageJsonFiles.length} package.json files`); + + // Map to store: dependency -> { version -> [files] } + const dependencyVersions = new Map(); + + // Read all package.json files and collect dependency versions + for (const file of packageJsonFiles) { + try { + const content = JSON.parse(readFileSync(file, "utf-8")); + const relativePath = relative(rootDir, file); + + // Process both dependencies and devDependencies + const allDeps = { + ...content.dependencies, + ...content.devDependencies, + }; + + for (const [depName, version] of Object.entries(allDeps)) { + // Skip workspace protocol dependencies (e.g., "workspace:*") + if (version.startsWith("workspace:")) { + continue; + } + + if (!dependencyVersions.has(depName)) { + dependencyVersions.set(depName, new Map()); + } + + const versionMap = dependencyVersions.get(depName); + if (!versionMap.has(version)) { + versionMap.set(version, []); + } + + versionMap.get(version).push(relativePath); + } + } catch (error) { + console.error(`${RED}Error reading ${file}: ${error.message}${RESET}`); + process.exit(1); + } + } + + // Check for mismatches + const mismatches = []; + + for (const [depName, versionMap] of dependencyVersions.entries()) { + if (versionMap.size > 1) { + mismatches.push({ + name: depName, + versions: Array.from(versionMap.entries()).map(([version, files]) => ({ + version, + files, + })), + }); + } + } + + // Report results + if (mismatches.length > 0) { + console.error(`\n${RED}❌ Dependency version mismatches found:${RESET}\n`); + + for (const mismatch of mismatches) { + console.error(`${YELLOW}${mismatch.name}:${RESET}`); + for (const { version, files } of mismatch.versions) { + console.error(` - ${version}`); + for (const file of files) { + console.error(` ${file}`); + } + } + console.error(""); + } + + console.error( + `${RED}Please ensure all packages use the same version for shared dependencies.${RESET}\n`, + ); + process.exit(1); + } + + console.log(`\n${GREEN}✅ All dependency versions are consistent across packages.${RESET}\n`); + process.exit(0); +} + +main(); diff --git a/server/.dockerignore b/server/.dockerignore deleted file mode 100644 index ffbd6b3d..00000000 --- a/server/.dockerignore +++ /dev/null @@ -1,48 +0,0 @@ -# Dependencies -node_modules/ -npm-debug.log* -pnpm-debug.log* - -# Build outputs -dist/ - -# Environment files -.env -.env.local -.env.development.local -.env.test.local -.env.production.local - -# IDE files -.vscode/ -.idea/ -*.swp -*.swo - -# OS files -.DS_Store -Thumbs.db - -# Git -.git/ -.gitignore - -# Documentation -*.md -!README.md - -# Test files -test/ -*.test.* -*.spec.* - -# Coverage -coverage/ - -# Logs -logs/ -*.log - -# Docker -Dockerfile -.dockerignore \ No newline at end of file diff --git a/server/pnpm-lock.yaml b/server/pnpm-lock.yaml deleted file mode 100644 index 11b6cbfc..00000000 --- a/server/pnpm-lock.yaml +++ /dev/null @@ -1,2047 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - '@hono/node-server': - specifier: ^1.16.0 - version: 1.16.0(hono@4.9.6) - '@hono/sentry': - specifier: ^1.2.2 - version: 1.2.2(hono@4.9.6) - dotenv: - specifier: ^16.6.1 - version: 16.6.1 - hono: - specifier: ^4.9.6 - version: 4.9.6 - spark: - specifier: file:.. - version: file:.. - devDependencies: - '@types/node': - specifier: ^22.17.2 - version: 22.17.2 - prettier: - specifier: ^3.6.2 - version: 3.6.2 - tsx: - specifier: ^4.20.4 - version: 4.20.4 - typescript: - specifier: ^5.9.2 - version: 5.9.2 - vitest: - specifier: ^1.6.1 - version: 1.6.1(@types/node@22.17.2) - -packages: - - '@ai-sdk/anthropic@2.0.4': - resolution: {integrity: sha512-ii2bZEUPwBitUiK1dpX+HsOarcDGY71G9TVdSJqbfXSVqa+speJNZ8PA/bjuNMml0NyX8VxNsaMg3SwBUCZspA==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4 - - '@ai-sdk/gateway@1.0.7': - resolution: {integrity: sha512-Athrq7OARuNc0iHZJP6InhSQ53tImCc990vMWyR1UHaZgPZJbXjKhIMiOj54F0I0Nlemx48V4fHYUTfLkJotnQ==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4 - - '@ai-sdk/google-vertex@3.0.9': - resolution: {integrity: sha512-ivUU0evqIukf4LVWv2MRahpvS7XebWtKFk81oOmcFQ3Uy4CVPS2Up0ozzUEfp65zQAOQVIjbALmHPKMWQkEd4g==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4 - - '@ai-sdk/google@2.0.6': - resolution: {integrity: sha512-8acuseWJI+RRH99JDWM/n7IJRuuGNa4YzLXB/leqE/ZByHyIiVWGADjJi/vfnJnmdM5fQnezJ6SRTF6feI5rSQ==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4 - - '@ai-sdk/openai-compatible@1.0.11': - resolution: {integrity: sha512-eRD6dZviy31KYz4YvxAR/c6UEYx3p4pCiWZeDdYdAHj0rn8xZlGVxtQRs1qynhz6IYGOo4aLBf9zVW5w0tI/Uw==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4 - - '@ai-sdk/openai@2.0.15': - resolution: {integrity: sha512-/IUyQ9ck4uUTtGojvQamcUWpNWkwpL/P1F6LYRxpQGj07H00oJEBH/VUizrIq0ZvW/vkuK6c6X4UJS9PrdYyxA==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4 - - '@ai-sdk/provider-utils@3.0.1': - resolution: {integrity: sha512-/iP1sKc6UdJgGH98OCly7sWJKv+J9G47PnTjIj40IJMUQKwDrUMyf7zOOfRtPwSuNifYhSoJQ4s1WltI65gJ/g==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4 - - '@ai-sdk/provider-utils@3.0.3': - resolution: {integrity: sha512-kAxIw1nYmFW1g5TvE54ZB3eNtgZna0RnLjPUp1ltz1+t9xkXJIuDT4atrwfau9IbS0BOef38wqrI8CjFfQrxhw==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4 - - '@ai-sdk/provider-utils@3.0.5': - resolution: {integrity: sha512-HliwB/yzufw3iwczbFVE2Fiwf1XqROB/I6ng8EKUsPM5+2wnIa8f4VbljZcDx+grhFrPV+PnRZH7zBqi8WZM7Q==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4 - - '@ai-sdk/provider@2.0.0': - resolution: {integrity: sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==} - engines: {node: '>=18'} - - '@esbuild/aix-ppc64@0.21.5': - resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [aix] - - '@esbuild/aix-ppc64@0.25.6': - resolution: {integrity: sha512-ShbM/3XxwuxjFiuVBHA+d3j5dyac0aEVVq1oluIDf71hUw0aRF59dV/efUsIwFnR6m8JNM2FjZOzmaZ8yG61kw==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.21.5': - resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm64@0.25.6': - resolution: {integrity: sha512-hd5zdUarsK6strW+3Wxi5qWws+rJhCCbMiC9QZyzoxfk5uHRIE8T287giQxzVpEvCwuJ9Qjg6bEjcRJcgfLqoA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.21.5': - resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - - '@esbuild/android-arm@0.25.6': - resolution: {integrity: sha512-S8ToEOVfg++AU/bHwdksHNnyLyVM+eMVAOf6yRKFitnwnbwwPNqKr3srzFRe7nzV69RQKb5DgchIX5pt3L53xg==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.21.5': - resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - - '@esbuild/android-x64@0.25.6': - resolution: {integrity: sha512-0Z7KpHSr3VBIO9A/1wcT3NTy7EB4oNC4upJ5ye3R7taCc2GUdeynSLArnon5G8scPwaU866d3H4BCrE5xLW25A==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.21.5': - resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-arm64@0.25.6': - resolution: {integrity: sha512-FFCssz3XBavjxcFxKsGy2DYK5VSvJqa6y5HXljKzhRZ87LvEi13brPrf/wdyl/BbpbMKJNOr1Sd0jtW4Ge1pAA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.21.5': - resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - - '@esbuild/darwin-x64@0.25.6': - resolution: {integrity: sha512-GfXs5kry/TkGM2vKqK2oyiLFygJRqKVhawu3+DOCk7OxLy/6jYkWXhlHwOoTb0WqGnWGAS7sooxbZowy+pK9Yg==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.21.5': - resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-arm64@0.25.6': - resolution: {integrity: sha512-aoLF2c3OvDn2XDTRvn8hN6DRzVVpDlj2B/F66clWd/FHLiHaG3aVZjxQX2DYphA5y/evbdGvC6Us13tvyt4pWg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.21.5': - resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.25.6': - resolution: {integrity: sha512-2SkqTjTSo2dYi/jzFbU9Plt1vk0+nNg8YC8rOXXea+iA3hfNJWebKYPs3xnOUf9+ZWhKAaxnQNUf2X9LOpeiMQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.21.5': - resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm64@0.25.6': - resolution: {integrity: sha512-b967hU0gqKd9Drsh/UuAm21Khpoh6mPBSgz8mKRq4P5mVK8bpA+hQzmm/ZwGVULSNBzKdZPQBRT3+WuVavcWsQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.21.5': - resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-arm@0.25.6': - resolution: {integrity: sha512-SZHQlzvqv4Du5PrKE2faN0qlbsaW/3QQfUUc6yO2EjFcA83xnwm91UbEEVx4ApZ9Z5oG8Bxz4qPE+HFwtVcfyw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.21.5': - resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-ia32@0.25.6': - resolution: {integrity: sha512-aHWdQ2AAltRkLPOsKdi3xv0mZ8fUGPdlKEjIEhxCPm5yKEThcUjHpWB1idN74lfXGnZ5SULQSgtr5Qos5B0bPw==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.21.5': - resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-loong64@0.25.6': - resolution: {integrity: sha512-VgKCsHdXRSQ7E1+QXGdRPlQ/e08bN6WMQb27/TMfV+vPjjTImuT9PmLXupRlC90S1JeNNW5lzkAEO/McKeJ2yg==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.21.5': - resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-mips64el@0.25.6': - resolution: {integrity: sha512-WViNlpivRKT9/py3kCmkHnn44GkGXVdXfdc4drNmRl15zVQ2+D2uFwdlGh6IuK5AAnGTo2qPB1Djppj+t78rzw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.21.5': - resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-ppc64@0.25.6': - resolution: {integrity: sha512-wyYKZ9NTdmAMb5730I38lBqVu6cKl4ZfYXIs31Baf8aoOtB4xSGi3THmDYt4BTFHk7/EcVixkOV2uZfwU3Q2Jw==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.21.5': - resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-riscv64@0.25.6': - resolution: {integrity: sha512-KZh7bAGGcrinEj4qzilJ4hqTY3Dg2U82c8bv+e1xqNqZCrCyc+TL9AUEn5WGKDzm3CfC5RODE/qc96OcbIe33w==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.21.5': - resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-s390x@0.25.6': - resolution: {integrity: sha512-9N1LsTwAuE9oj6lHMyyAM+ucxGiVnEqUdp4v7IaMmrwb06ZTEVCIs3oPPplVsnjPfyjmxwHxHMF8b6vzUVAUGw==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.21.5': - resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - - '@esbuild/linux-x64@0.25.6': - resolution: {integrity: sha512-A6bJB41b4lKFWRKNrWoP2LHsjVzNiaurf7wyj/XtFNTsnPuxwEBWHLty+ZE0dWBKuSK1fvKgrKaNjBS7qbFKig==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.25.6': - resolution: {integrity: sha512-IjA+DcwoVpjEvyxZddDqBY+uJ2Snc6duLpjmkXm/v4xuS3H+3FkLZlDm9ZsAbF9rsfP3zeA0/ArNDORZgrxR/Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.21.5': - resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.25.6': - resolution: {integrity: sha512-dUXuZr5WenIDlMHdMkvDc1FAu4xdWixTCRgP7RQLBOkkGgwuuzaGSYcOpW4jFxzpzL1ejb8yF620UxAqnBrR9g==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.25.6': - resolution: {integrity: sha512-l8ZCvXP0tbTJ3iaqdNf3pjaOSd5ex/e6/omLIQCVBLmHTlfXW3zAxQ4fnDmPLOB1x9xrcSi/xtCWFwCZRIaEwg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.21.5': - resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.25.6': - resolution: {integrity: sha512-hKrmDa0aOFOr71KQ/19JC7az1P0GWtCN1t2ahYAf4O007DHZt/dW8ym5+CUdJhQ/qkZmI1HAF8KkJbEFtCL7gw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.25.6': - resolution: {integrity: sha512-+SqBcAWoB1fYKmpWoQP4pGtx+pUUC//RNYhFdbcSA16617cchuryuhOCRpPsjCblKukAckWsV+aQ3UKT/RMPcA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.21.5': - resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - - '@esbuild/sunos-x64@0.25.6': - resolution: {integrity: sha512-dyCGxv1/Br7MiSC42qinGL8KkG4kX0pEsdb0+TKhmJZgCUDBGmyo1/ArCjNGiOLiIAgdbWgmWgib4HoCi5t7kA==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.21.5': - resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-arm64@0.25.6': - resolution: {integrity: sha512-42QOgcZeZOvXfsCBJF5Afw73t4veOId//XD3i+/9gSkhSV6Gk3VPlWncctI+JcOyERv85FUo7RxuxGy+z8A43Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.21.5': - resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-ia32@0.25.6': - resolution: {integrity: sha512-4AWhgXmDuYN7rJI6ORB+uU9DHLq/erBbuMoAuB4VWJTu5KtCgcKYPynF0YI1VkBNuEfjNlLrFr9KZPJzrtLkrQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.21.5': - resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - - '@esbuild/win32-x64@0.25.6': - resolution: {integrity: sha512-NgJPHHbEpLQgDH2MjQu90pzW/5vvXIZ7KOnPyNBm92A6WgZ/7b6fJyUBjoumLqeOQQGqY2QjQxRo97ah4Sj0cA==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@ghostery/adblocker-content@2.11.3': - resolution: {integrity: sha512-Es3Mm86JStRdyl0o2/YXZot8C41dWChgY7Et3pu8Bll3+MTp+fjnXwD/a8ic1TD6UYHXPqpUU7b9f6OWa0Twnw==} - - '@ghostery/adblocker-extended-selectors@2.11.3': - resolution: {integrity: sha512-+d/AZ1oIXy+WP+ogd9behZ3c136pSdt7QmwODNODeXPgEJJggersuLiKRDsBlG+nqy03gaTt5Vo7qk3rYa7cyA==} - - '@ghostery/adblocker-playwright@2.11.3': - resolution: {integrity: sha512-PAFw8+Zaf7MwGmAcnaFdwQxEwYNvJ5rwARciM96tLQ0Ep7M1FJkZM8NUq7Et+VYAngm1xE4xF8Zym99umJp7Dw==} - peerDependencies: - playwright: ^1.x - - '@ghostery/adblocker@2.11.3': - resolution: {integrity: sha512-uNblOHFagpi7yz1nOmhPvmK1QWWzOV7K9sTNy7SDM+i1FZkfSJYCPyFBlioV15GNVm/cRfMWW7LyZKWCnQ2+sQ==} - - '@ghostery/url-parser@1.3.0': - resolution: {integrity: sha512-FEzdSeiva0Mt3bR4xePFzthhjT4IzvA5QTvS1xXkNyLpMGeq40mb3V2fSs0ZItRaP9IybZthDfHUSbQ1HLdx4Q==} - - '@hono/node-server@1.16.0': - resolution: {integrity: sha512-9LwRb5XOrTFapOABiQjGC50wRVlzUvWZsDHINCnkBniP+Q+LQf4waN0nzk9t+2kqcTsnGnieSmqpHsr6kH2bdw==} - engines: {node: '>=18.14.1'} - peerDependencies: - hono: ^4 - - '@hono/sentry@1.2.2': - resolution: {integrity: sha512-027grZBrRGDPor8mRd+QOBcSpUlF07YrTp/WFDXZhbvWZ+1LrZdERUqcdg1gBGDUTanHhd9ucblpNNN6+V1bxg==} - peerDependencies: - hono: '>=3.*' - - '@jest/schemas@29.6.3': - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jridgewell/sourcemap-codec@1.5.4': - resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==} - - '@mixmark-io/domino@2.2.0': - resolution: {integrity: sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==} - - '@openrouter/ai-sdk-provider@1.1.2': - resolution: {integrity: sha512-cfiKVpNygGFaJojBHFvtTf7UiF458Xh9yPcTg4FXF7bGYN5V33Rxx9dXNE12fjv6lHeC5C7jwQHDrzUIFol1iQ==} - engines: {node: '>=18'} - peerDependencies: - ai: ^5.0.0 - zod: ^3.24.1 || ^v4 - - '@opentelemetry/api@1.9.0': - resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} - engines: {node: '>=8.0.0'} - - '@remusao/guess-url-type@2.1.0': - resolution: {integrity: sha512-zI3dlTUxpjvx2GCxp9nLOSK5yEIqDCpxlAVGwb2Y49RKkS72oeNaxxo+VWS5+XQ5+Mf8Zfp9ZXIlk+G5eoEN8A==} - - '@remusao/small@2.1.0': - resolution: {integrity: sha512-Y1kyjZp7JU7dXdyOdxHVNfoTr1XLZJTyQP36/esZUU/WRWq9XY0PV2HsE3CsIHuaTf4pvgWv2pvzvnZ//UHIJQ==} - - '@remusao/smaz-compress@2.2.0': - resolution: {integrity: sha512-TXpTPgILRUYOt2rEe0+9PC12xULPvBqeMpmipzB9A7oM4fa9Ztvy9lLYzPTd7tiQEeoNa1pmxihpKfJtsxnM/w==} - - '@remusao/smaz-decompress@2.2.0': - resolution: {integrity: sha512-ERAPwxPaA0/yg4hkNU7T2S+lnp9jj1sApcQMtOyROvOQyo+Zuh6Hn/oRcXr8mmjlYzyRaC7E6r3mT1nrdHR6pg==} - - '@remusao/smaz@2.2.0': - resolution: {integrity: sha512-eSd3Qs0ELP/e7tU1SI5RWXcCn9KjDgvBY+KtWbL4i2QvvHhJOfdIt4v0AA3S5BbLWAr5dCEC7C4LUfogDm6q/Q==} - - '@remusao/trie@2.1.0': - resolution: {integrity: sha512-Er3Q8q0/2OcCJPQYJOPLmCuqO0wu7cav3SPtpjlxSbjFi1x+A1pZkkLD6c9q2rGEkGW/tkrRzfrhNMt8VQjzXg==} - - '@rollup/rollup-android-arm-eabi@4.45.1': - resolution: {integrity: sha512-NEySIFvMY0ZQO+utJkgoMiCAjMrGvnbDLHvcmlA33UXJpYBCvlBEbMMtV837uCkS+plG2umfhn0T5mMAxGrlRA==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.45.1': - resolution: {integrity: sha512-ujQ+sMXJkg4LRJaYreaVx7Z/VMgBBd89wGS4qMrdtfUFZ+TSY5Rs9asgjitLwzeIbhwdEhyj29zhst3L1lKsRQ==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.45.1': - resolution: {integrity: sha512-FSncqHvqTm3lC6Y13xncsdOYfxGSLnP+73k815EfNmpewPs+EyM49haPS105Rh4aF5mJKywk9X0ogzLXZzN9lA==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.45.1': - resolution: {integrity: sha512-2/vVn/husP5XI7Fsf/RlhDaQJ7x9zjvC81anIVbr4b/f0xtSmXQTFcGIQ/B1cXIYM6h2nAhJkdMHTnD7OtQ9Og==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.45.1': - resolution: {integrity: sha512-4g1kaDxQItZsrkVTdYQ0bxu4ZIQ32cotoQbmsAnW1jAE4XCMbcBPDirX5fyUzdhVCKgPcrwWuucI8yrVRBw2+g==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.45.1': - resolution: {integrity: sha512-L/6JsfiL74i3uK1Ti2ZFSNsp5NMiM4/kbbGEcOCps99aZx3g8SJMO1/9Y0n/qKlWZfn6sScf98lEOUe2mBvW9A==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.45.1': - resolution: {integrity: sha512-RkdOTu2jK7brlu+ZwjMIZfdV2sSYHK2qR08FUWcIoqJC2eywHbXr0L8T/pONFwkGukQqERDheaGTeedG+rra6Q==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.45.1': - resolution: {integrity: sha512-3kJ8pgfBt6CIIr1o+HQA7OZ9mp/zDk3ctekGl9qn/pRBgrRgfwiffaUmqioUGN9hv0OHv2gxmvdKOkARCtRb8Q==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.45.1': - resolution: {integrity: sha512-k3dOKCfIVixWjG7OXTCOmDfJj3vbdhN0QYEqB+OuGArOChek22hn7Uy5A/gTDNAcCy5v2YcXRJ/Qcnm4/ma1xw==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.45.1': - resolution: {integrity: sha512-PmI1vxQetnM58ZmDFl9/Uk2lpBBby6B6rF4muJc65uZbxCs0EA7hhKCk2PKlmZKuyVSHAyIw3+/SiuMLxKxWog==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-loongarch64-gnu@4.45.1': - resolution: {integrity: sha512-9UmI0VzGmNJ28ibHW2GpE2nF0PBQqsyiS4kcJ5vK+wuwGnV5RlqdczVocDSUfGX/Na7/XINRVoUgJyFIgipoRg==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-powerpc64le-gnu@4.45.1': - resolution: {integrity: sha512-7nR2KY8oEOUTD3pBAxIBBbZr0U7U+R9HDTPNy+5nVVHDXI4ikYniH1oxQz9VoB5PbBU1CZuDGHkLJkd3zLMWsg==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.45.1': - resolution: {integrity: sha512-nlcl3jgUultKROfZijKjRQLUu9Ma0PeNv/VFHkZiKbXTBQXhpytS8CIj5/NfBeECZtY2FJQubm6ltIxm/ftxpw==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-riscv64-musl@4.45.1': - resolution: {integrity: sha512-HJV65KLS51rW0VY6rvZkiieiBnurSzpzore1bMKAhunQiECPuxsROvyeaot/tcK3A3aGnI+qTHqisrpSgQrpgA==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.45.1': - resolution: {integrity: sha512-NITBOCv3Qqc6hhwFt7jLV78VEO/il4YcBzoMGGNxznLgRQf43VQDae0aAzKiBeEPIxnDrACiMgbqjuihx08OOw==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.45.1': - resolution: {integrity: sha512-+E/lYl6qu1zqgPEnTrs4WysQtvc/Sh4fC2nByfFExqgYrqkKWp1tWIbe+ELhixnenSpBbLXNi6vbEEJ8M7fiHw==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.45.1': - resolution: {integrity: sha512-a6WIAp89p3kpNoYStITT9RbTbTnqarU7D8N8F2CV+4Cl9fwCOZraLVuVFvlpsW0SbIiYtEnhCZBPLoNdRkjQFw==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-win32-arm64-msvc@4.45.1': - resolution: {integrity: sha512-T5Bi/NS3fQiJeYdGvRpTAP5P02kqSOpqiopwhj0uaXB6nzs5JVi2XMJb18JUSKhCOX8+UE1UKQufyD6Or48dJg==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.45.1': - resolution: {integrity: sha512-lxV2Pako3ujjuUe9jiU3/s7KSrDfH6IgTSQOnDWr9aJ92YsFd7EurmClK0ly/t8dzMkDtd04g60WX6yl0sGfdw==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.45.1': - resolution: {integrity: sha512-M/fKi4sasCdM8i0aWJjCSFm2qEnYRR8AMLG2kxp6wD13+tMGA4Z1tVAuHkNRjud5SW2EM3naLuK35w9twvf6aA==} - cpu: [x64] - os: [win32] - - '@sentry/core@8.9.2': - resolution: {integrity: sha512-ixm8NISFlPlEo3FjSaqmq4nnd13BRHoafwJ5MG+okCz6BKGZ1SexEggP42/QpGvDprUUHnfncG6WUMgcarr1zA==} - engines: {node: '>=14.18'} - - '@sentry/types@8.9.2': - resolution: {integrity: sha512-+LFOyQGl+zk5SZRGZD2MEURf7i5RHgP/mt3s85Rza+vz8M211WJ0YsjkIGUJFSY842nged5QLx4JysLaBlLymg==} - engines: {node: '>=14.18'} - - '@sentry/utils@8.9.2': - resolution: {integrity: sha512-A4srR9mEBFdVXwSEKjQ94msUbVkMr8JeFiEj9ouOFORw/Y/ux/WV2bWVD/ZI9wq0TcTNK8L1wBgU8UMS5lIq3A==} - engines: {node: '>=14.18'} - - '@sinclair/typebox@0.27.8': - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - - '@standard-schema/spec@1.0.0': - resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} - - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - - '@types/node@22.17.2': - resolution: {integrity: sha512-gL6z5N9Jm9mhY+U2KXZpteb+09zyffliRkZyZOHODGATyC5B1Jt/7TzuuiLkFsSUMLbS1OLmlj/E+/3KF4Q/4w==} - - '@types/turndown@5.0.5': - resolution: {integrity: sha512-TL2IgGgc7B5j78rIccBtlYAnkuv8nUQqhQc+DSYV5j9Be9XOcm/SKOVRuA47xAVI3680Tk9B1d8flK2GWT2+4w==} - - '@vitest/expect@1.6.1': - resolution: {integrity: sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==} - - '@vitest/runner@1.6.1': - resolution: {integrity: sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==} - - '@vitest/snapshot@1.6.1': - resolution: {integrity: sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ==} - - '@vitest/spy@1.6.1': - resolution: {integrity: sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw==} - - '@vitest/utils@1.6.1': - resolution: {integrity: sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==} - - acorn-walk@8.3.4: - resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} - engines: {node: '>=0.4.0'} - - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} - engines: {node: '>=0.4.0'} - hasBin: true - - agent-base@7.1.4: - resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} - engines: {node: '>= 14'} - - ai@5.0.15: - resolution: {integrity: sha512-EX5hF+NVFm6R11mvdZRbg6eJEjyMlniI4/xOnyTh4VtDQ457lhIgi3kDGrHW3/qw9ELon9m2e7AK3g5z5sLwsQ==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4 - - ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - - assertion-error@1.1.0: - resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} - - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - - bignumber.js@9.3.1: - resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} - - buffer-equal-constant-time@1.0.1: - resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} - - cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} - - chai@4.5.0: - resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} - engines: {node: '>=4'} - - chalk@5.5.0: - resolution: {integrity: sha512-1tm8DTaJhPBG3bIkVeZt1iZM9GfSX2lzOeDVZH9R9ffRHpmHvxZ/QhgQH/aDTkswQVt+YHdXAdS/In/30OjCbg==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - - check-error@1.0.3: - resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} - - commander@10.0.1: - resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} - engines: {node: '>=14'} - - commander@14.0.0: - resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==} - engines: {node: '>=20'} - - confbox@0.1.8: - resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} - - cross-fetch@4.1.0: - resolution: {integrity: sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - debug@4.4.1: - resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - deep-eql@4.1.4: - resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} - engines: {node: '>=6'} - - diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - dotenv@16.6.1: - resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} - engines: {node: '>=12'} - - ecdsa-sig-formatter@1.0.11: - resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} - - esbuild@0.21.5: - resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} - engines: {node: '>=12'} - hasBin: true - - esbuild@0.25.6: - resolution: {integrity: sha512-GVuzuUwtdsghE3ocJ9Bs8PNoF13HNQ5TXbEi2AhvVb8xU1Iwt9Fos9FEamfoee+u/TOsn7GUWc04lz46n2bbTg==} - engines: {node: '>=18'} - hasBin: true - - estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - - eventemitter3@5.0.1: - resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} - - eventsource-parser@3.0.3: - resolution: {integrity: sha512-nVpZkTMM9rF6AQ9gPJpFsNAMt48wIzB5TQgiTLdHiuO8XEDhUgZEhqKlZWXbIzo9VmJ/HvysHqEaVeD5v9TPvA==} - engines: {node: '>=20.0.0'} - - execa@8.0.1: - resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} - engines: {node: '>=16.17'} - - extend@3.0.2: - resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - - fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - gaxios@6.7.1: - resolution: {integrity: sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==} - engines: {node: '>=14'} - - gcp-metadata@6.1.1: - resolution: {integrity: sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==} - engines: {node: '>=14'} - - get-func-name@2.0.2: - resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} - - get-stream@8.0.1: - resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} - engines: {node: '>=16'} - - get-tsconfig@4.10.1: - resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} - - google-auth-library@9.15.1: - resolution: {integrity: sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==} - engines: {node: '>=14'} - - google-logging-utils@0.0.2: - resolution: {integrity: sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==} - engines: {node: '>=14'} - - gtoken@7.1.0: - resolution: {integrity: sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==} - engines: {node: '>=14.0.0'} - - hono@4.9.6: - resolution: {integrity: sha512-doVjXhSFvYZ7y0dNokjwwSahcrAfdz+/BCLvAMa/vHLzjj8+CFyV5xteThGUsKdkaasgN+gF2mUxao+SGLpUeA==} - engines: {node: '>=16.9.0'} - - https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} - - human-signals@5.0.0: - resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} - engines: {node: '>=16.17.0'} - - is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - - is-stream@3.0.0: - resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - js-tokens@9.0.1: - resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} - - json-bigint@1.0.0: - resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} - - json-schema@0.4.0: - resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} - - jwa@2.0.1: - resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} - - jws@4.0.0: - resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==} - - liquidjs@10.21.1: - resolution: {integrity: sha512-NZXmCwv3RG5nire3fmIn9HsOyJX3vo+ptp0yaXUHAMzSNBhx74Hm+dAGJvscUA6lNqbLuYfXgNavRQ9UbUJhQQ==} - engines: {node: '>=14'} - hasBin: true - - local-pkg@0.5.1: - resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==} - engines: {node: '>=14'} - - loupe@2.3.7: - resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} - - magic-string@0.30.17: - resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} - - merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - - mimic-fn@4.0.0: - resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} - engines: {node: '>=12'} - - mlly@1.7.4: - resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - nanoid@5.1.5: - resolution: {integrity: sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==} - engines: {node: ^18 || >=20} - hasBin: true - - node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - - npm-run-path@5.3.0: - resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - ollama-ai-provider-v2@1.1.2: - resolution: {integrity: sha512-M7mI9OGGarFYGuL5r2pvJiOyN84EvEYAbHqk/YeOmaXX8Enb+E+5QIqPGWsgA1CJFulofsdEGEkJFDMEut8QyQ==} - engines: {node: '>=18'} - peerDependencies: - zod: ^4.0.16 - - onetime@6.0.0: - resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} - engines: {node: '>=12'} - - p-limit@5.0.0: - resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} - engines: {node: '>=18'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-key@4.0.0: - resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} - engines: {node: '>=12'} - - pathe@1.1.2: - resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} - - pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - - pathval@1.1.1: - resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - pkg-types@1.3.1: - resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - - playwright-core@1.53.0: - resolution: {integrity: sha512-mGLg8m0pm4+mmtB7M89Xw/GSqoNC+twivl8ITteqvAndachozYe2ZA7srU6uleV1vEdAHYqjq+SV8SNxRRFYBw==} - engines: {node: '>=18'} - hasBin: true - - playwright@1.53.0: - resolution: {integrity: sha512-ghGNnIEYZC4E+YtclRn4/p6oYbdPiASELBIYkBXfaTVKreQUYbMUYQDwS12a8F0/HtIjr/CkGjtwABeFPGcS4Q==} - engines: {node: '>=18'} - hasBin: true - - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} - engines: {node: ^10 || ^12 || >=14} - - prettier@3.6.2: - resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} - engines: {node: '>=14'} - hasBin: true - - pretty-format@29.7.0: - resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - react-is@18.3.1: - resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - - resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - - rollup@4.45.1: - resolution: {integrity: sha512-4iya7Jb76fVpQyLoiVpzUrsjQ12r3dM7fIVz+4NwoYvZOShknRmiv+iu9CClZml5ZLGb0XMcYLutK6w9tgxHDw==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - spark@file:..: - resolution: {directory: .., type: directory} - hasBin: true - - stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - - std-env@3.9.0: - resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} - - strip-final-newline@3.0.0: - resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} - engines: {node: '>=12'} - - strip-literal@2.1.1: - resolution: {integrity: sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==} - - tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - - tinypool@0.8.4: - resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==} - engines: {node: '>=14.0.0'} - - tinyspy@2.2.1: - resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==} - engines: {node: '>=14.0.0'} - - tldts-core@7.0.10: - resolution: {integrity: sha512-z7PilFbUHwd+IlQ72D0aHDpqykUUpe9yvwa5k/rFvFLmpvNmWqHEIHoSYwE5sA5LZU4bTTIjhDZEjURHc8f2ag==} - - tldts-experimental@7.0.10: - resolution: {integrity: sha512-5qrQCSbJwrSlO4Rg/KFLnyMhkv5ngTeFh0pRYxEr5q+8eh0gguXqCO+RvzOEMEKqasR9XPYkSPTaoPUx0UBv8w==} - - toucan-js@4.1.1: - resolution: {integrity: sha512-GTPwEaCRN8IbYe5/VeGiwxYvMO0dKaC16fTeLbF+QGswjkLZ9JUqAfDhLMyH2SWukYhmetH+uxWa1Bhluv/evQ==} - - tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - - tsx@4.20.4: - resolution: {integrity: sha512-yyxBKfORQ7LuRt/BQKBXrpcq59ZvSW0XxwfjAt3w2/8PmdxaFzijtMhTawprSHhpzeM5BgU2hXHG3lklIERZXg==} - engines: {node: '>=18.0.0'} - hasBin: true - - turndown@7.2.1: - resolution: {integrity: sha512-7YiPJw6rLClQL3oUKN3KgMaXeJJ2lAyZItclgKDurqnH61so4k4IH/qwmMva0zpuJc/FhRExBBnk7EbeFANlgQ==} - - type-detect@4.1.0: - resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} - engines: {node: '>=4'} - - typescript@5.9.2: - resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} - engines: {node: '>=14.17'} - hasBin: true - - ufo@1.6.1: - resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} - - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - - uuid@9.0.1: - resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} - hasBin: true - - vite-node@1.6.1: - resolution: {integrity: sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - - vite@5.4.19: - resolution: {integrity: sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || >=20.0.0 - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - - vitest@1.6.1: - resolution: {integrity: sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 1.6.1 - '@vitest/ui': 1.6.1 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@types/node': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - - webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - - whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} - hasBin: true - - yocto-queue@1.2.1: - resolution: {integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==} - engines: {node: '>=12.20'} - - zod-to-json-schema@3.24.6: - resolution: {integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==} - peerDependencies: - zod: ^3.24.1 - - zod@4.0.17: - resolution: {integrity: sha512-1PHjlYRevNxxdy2JZ8JcNAw7rX8V9P1AKkP+x/xZfxB0K5FYfuV+Ug6P/6NVSR2jHQ+FzDDoDHS04nYUsOIyLQ==} - -snapshots: - - '@ai-sdk/anthropic@2.0.4(zod@4.0.17)': - dependencies: - '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.3(zod@4.0.17) - zod: 4.0.17 - - '@ai-sdk/gateway@1.0.7(zod@4.0.17)': - dependencies: - '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.3(zod@4.0.17) - zod: 4.0.17 - - '@ai-sdk/google-vertex@3.0.9(zod@4.0.17)': - dependencies: - '@ai-sdk/anthropic': 2.0.4(zod@4.0.17) - '@ai-sdk/google': 2.0.6(zod@4.0.17) - '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.3(zod@4.0.17) - google-auth-library: 9.15.1 - zod: 4.0.17 - transitivePeerDependencies: - - encoding - - supports-color - - '@ai-sdk/google@2.0.6(zod@4.0.17)': - dependencies: - '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.3(zod@4.0.17) - zod: 4.0.17 - - '@ai-sdk/openai-compatible@1.0.11(zod@4.0.17)': - dependencies: - '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.5(zod@4.0.17) - zod: 4.0.17 - - '@ai-sdk/openai@2.0.15(zod@4.0.17)': - dependencies: - '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.3(zod@4.0.17) - zod: 4.0.17 - - '@ai-sdk/provider-utils@3.0.1(zod@4.0.17)': - dependencies: - '@ai-sdk/provider': 2.0.0 - '@standard-schema/spec': 1.0.0 - eventsource-parser: 3.0.3 - zod: 4.0.17 - zod-to-json-schema: 3.24.6(zod@4.0.17) - - '@ai-sdk/provider-utils@3.0.3(zod@4.0.17)': - dependencies: - '@ai-sdk/provider': 2.0.0 - '@standard-schema/spec': 1.0.0 - eventsource-parser: 3.0.3 - zod: 4.0.17 - zod-to-json-schema: 3.24.6(zod@4.0.17) - - '@ai-sdk/provider-utils@3.0.5(zod@4.0.17)': - dependencies: - '@ai-sdk/provider': 2.0.0 - '@standard-schema/spec': 1.0.0 - eventsource-parser: 3.0.3 - zod: 4.0.17 - zod-to-json-schema: 3.24.6(zod@4.0.17) - - '@ai-sdk/provider@2.0.0': - dependencies: - json-schema: 0.4.0 - - '@esbuild/aix-ppc64@0.21.5': - optional: true - - '@esbuild/aix-ppc64@0.25.6': - optional: true - - '@esbuild/android-arm64@0.21.5': - optional: true - - '@esbuild/android-arm64@0.25.6': - optional: true - - '@esbuild/android-arm@0.21.5': - optional: true - - '@esbuild/android-arm@0.25.6': - optional: true - - '@esbuild/android-x64@0.21.5': - optional: true - - '@esbuild/android-x64@0.25.6': - optional: true - - '@esbuild/darwin-arm64@0.21.5': - optional: true - - '@esbuild/darwin-arm64@0.25.6': - optional: true - - '@esbuild/darwin-x64@0.21.5': - optional: true - - '@esbuild/darwin-x64@0.25.6': - optional: true - - '@esbuild/freebsd-arm64@0.21.5': - optional: true - - '@esbuild/freebsd-arm64@0.25.6': - optional: true - - '@esbuild/freebsd-x64@0.21.5': - optional: true - - '@esbuild/freebsd-x64@0.25.6': - optional: true - - '@esbuild/linux-arm64@0.21.5': - optional: true - - '@esbuild/linux-arm64@0.25.6': - optional: true - - '@esbuild/linux-arm@0.21.5': - optional: true - - '@esbuild/linux-arm@0.25.6': - optional: true - - '@esbuild/linux-ia32@0.21.5': - optional: true - - '@esbuild/linux-ia32@0.25.6': - optional: true - - '@esbuild/linux-loong64@0.21.5': - optional: true - - '@esbuild/linux-loong64@0.25.6': - optional: true - - '@esbuild/linux-mips64el@0.21.5': - optional: true - - '@esbuild/linux-mips64el@0.25.6': - optional: true - - '@esbuild/linux-ppc64@0.21.5': - optional: true - - '@esbuild/linux-ppc64@0.25.6': - optional: true - - '@esbuild/linux-riscv64@0.21.5': - optional: true - - '@esbuild/linux-riscv64@0.25.6': - optional: true - - '@esbuild/linux-s390x@0.21.5': - optional: true - - '@esbuild/linux-s390x@0.25.6': - optional: true - - '@esbuild/linux-x64@0.21.5': - optional: true - - '@esbuild/linux-x64@0.25.6': - optional: true - - '@esbuild/netbsd-arm64@0.25.6': - optional: true - - '@esbuild/netbsd-x64@0.21.5': - optional: true - - '@esbuild/netbsd-x64@0.25.6': - optional: true - - '@esbuild/openbsd-arm64@0.25.6': - optional: true - - '@esbuild/openbsd-x64@0.21.5': - optional: true - - '@esbuild/openbsd-x64@0.25.6': - optional: true - - '@esbuild/openharmony-arm64@0.25.6': - optional: true - - '@esbuild/sunos-x64@0.21.5': - optional: true - - '@esbuild/sunos-x64@0.25.6': - optional: true - - '@esbuild/win32-arm64@0.21.5': - optional: true - - '@esbuild/win32-arm64@0.25.6': - optional: true - - '@esbuild/win32-ia32@0.21.5': - optional: true - - '@esbuild/win32-ia32@0.25.6': - optional: true - - '@esbuild/win32-x64@0.21.5': - optional: true - - '@esbuild/win32-x64@0.25.6': - optional: true - - '@ghostery/adblocker-content@2.11.3': - dependencies: - '@ghostery/adblocker-extended-selectors': 2.11.3 - - '@ghostery/adblocker-extended-selectors@2.11.3': {} - - '@ghostery/adblocker-playwright@2.11.3(playwright@1.53.0)': - dependencies: - '@ghostery/adblocker': 2.11.3 - '@ghostery/adblocker-content': 2.11.3 - playwright: 1.53.0 - tldts-experimental: 7.0.10 - - '@ghostery/adblocker@2.11.3': - dependencies: - '@ghostery/adblocker-content': 2.11.3 - '@ghostery/adblocker-extended-selectors': 2.11.3 - '@ghostery/url-parser': 1.3.0 - '@remusao/guess-url-type': 2.1.0 - '@remusao/small': 2.1.0 - '@remusao/smaz': 2.2.0 - tldts-experimental: 7.0.10 - - '@ghostery/url-parser@1.3.0': - dependencies: - tldts-experimental: 7.0.10 - - '@hono/node-server@1.16.0(hono@4.9.6)': - dependencies: - hono: 4.9.6 - - '@hono/sentry@1.2.2(hono@4.9.6)': - dependencies: - hono: 4.9.6 - toucan-js: 4.1.1 - - '@jest/schemas@29.6.3': - dependencies: - '@sinclair/typebox': 0.27.8 - - '@jridgewell/sourcemap-codec@1.5.4': {} - - '@mixmark-io/domino@2.2.0': {} - - '@openrouter/ai-sdk-provider@1.1.2(ai@5.0.15(zod@4.0.17))(zod@4.0.17)': - dependencies: - ai: 5.0.15(zod@4.0.17) - zod: 4.0.17 - - '@opentelemetry/api@1.9.0': {} - - '@remusao/guess-url-type@2.1.0': {} - - '@remusao/small@2.1.0': {} - - '@remusao/smaz-compress@2.2.0': - dependencies: - '@remusao/trie': 2.1.0 - - '@remusao/smaz-decompress@2.2.0': {} - - '@remusao/smaz@2.2.0': - dependencies: - '@remusao/smaz-compress': 2.2.0 - '@remusao/smaz-decompress': 2.2.0 - - '@remusao/trie@2.1.0': {} - - '@rollup/rollup-android-arm-eabi@4.45.1': - optional: true - - '@rollup/rollup-android-arm64@4.45.1': - optional: true - - '@rollup/rollup-darwin-arm64@4.45.1': - optional: true - - '@rollup/rollup-darwin-x64@4.45.1': - optional: true - - '@rollup/rollup-freebsd-arm64@4.45.1': - optional: true - - '@rollup/rollup-freebsd-x64@4.45.1': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.45.1': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.45.1': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.45.1': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.45.1': - optional: true - - '@rollup/rollup-linux-loongarch64-gnu@4.45.1': - optional: true - - '@rollup/rollup-linux-powerpc64le-gnu@4.45.1': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.45.1': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.45.1': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.45.1': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.45.1': - optional: true - - '@rollup/rollup-linux-x64-musl@4.45.1': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.45.1': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.45.1': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.45.1': - optional: true - - '@sentry/core@8.9.2': - dependencies: - '@sentry/types': 8.9.2 - '@sentry/utils': 8.9.2 - - '@sentry/types@8.9.2': {} - - '@sentry/utils@8.9.2': - dependencies: - '@sentry/types': 8.9.2 - - '@sinclair/typebox@0.27.8': {} - - '@standard-schema/spec@1.0.0': {} - - '@types/estree@1.0.8': {} - - '@types/node@22.17.2': - dependencies: - undici-types: 6.21.0 - - '@types/turndown@5.0.5': {} - - '@vitest/expect@1.6.1': - dependencies: - '@vitest/spy': 1.6.1 - '@vitest/utils': 1.6.1 - chai: 4.5.0 - - '@vitest/runner@1.6.1': - dependencies: - '@vitest/utils': 1.6.1 - p-limit: 5.0.0 - pathe: 1.1.2 - - '@vitest/snapshot@1.6.1': - dependencies: - magic-string: 0.30.17 - pathe: 1.1.2 - pretty-format: 29.7.0 - - '@vitest/spy@1.6.1': - dependencies: - tinyspy: 2.2.1 - - '@vitest/utils@1.6.1': - dependencies: - diff-sequences: 29.6.3 - estree-walker: 3.0.3 - loupe: 2.3.7 - pretty-format: 29.7.0 - - acorn-walk@8.3.4: - dependencies: - acorn: 8.15.0 - - acorn@8.15.0: {} - - agent-base@7.1.4: {} - - ai@5.0.15(zod@4.0.17): - dependencies: - '@ai-sdk/gateway': 1.0.7(zod@4.0.17) - '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.3(zod@4.0.17) - '@opentelemetry/api': 1.9.0 - zod: 4.0.17 - - ansi-styles@5.2.0: {} - - assertion-error@1.1.0: {} - - base64-js@1.5.1: {} - - bignumber.js@9.3.1: {} - - buffer-equal-constant-time@1.0.1: {} - - cac@6.7.14: {} - - chai@4.5.0: - dependencies: - assertion-error: 1.1.0 - check-error: 1.0.3 - deep-eql: 4.1.4 - get-func-name: 2.0.2 - loupe: 2.3.7 - pathval: 1.1.1 - type-detect: 4.1.0 - - chalk@5.5.0: {} - - check-error@1.0.3: - dependencies: - get-func-name: 2.0.2 - - commander@10.0.1: {} - - commander@14.0.0: {} - - confbox@0.1.8: {} - - cross-fetch@4.1.0: - dependencies: - node-fetch: 2.7.0 - transitivePeerDependencies: - - encoding - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - debug@4.4.1: - dependencies: - ms: 2.1.3 - - deep-eql@4.1.4: - dependencies: - type-detect: 4.1.0 - - diff-sequences@29.6.3: {} - - dotenv@16.6.1: {} - - ecdsa-sig-formatter@1.0.11: - dependencies: - safe-buffer: 5.2.1 - - esbuild@0.21.5: - optionalDependencies: - '@esbuild/aix-ppc64': 0.21.5 - '@esbuild/android-arm': 0.21.5 - '@esbuild/android-arm64': 0.21.5 - '@esbuild/android-x64': 0.21.5 - '@esbuild/darwin-arm64': 0.21.5 - '@esbuild/darwin-x64': 0.21.5 - '@esbuild/freebsd-arm64': 0.21.5 - '@esbuild/freebsd-x64': 0.21.5 - '@esbuild/linux-arm': 0.21.5 - '@esbuild/linux-arm64': 0.21.5 - '@esbuild/linux-ia32': 0.21.5 - '@esbuild/linux-loong64': 0.21.5 - '@esbuild/linux-mips64el': 0.21.5 - '@esbuild/linux-ppc64': 0.21.5 - '@esbuild/linux-riscv64': 0.21.5 - '@esbuild/linux-s390x': 0.21.5 - '@esbuild/linux-x64': 0.21.5 - '@esbuild/netbsd-x64': 0.21.5 - '@esbuild/openbsd-x64': 0.21.5 - '@esbuild/sunos-x64': 0.21.5 - '@esbuild/win32-arm64': 0.21.5 - '@esbuild/win32-ia32': 0.21.5 - '@esbuild/win32-x64': 0.21.5 - - esbuild@0.25.6: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.6 - '@esbuild/android-arm': 0.25.6 - '@esbuild/android-arm64': 0.25.6 - '@esbuild/android-x64': 0.25.6 - '@esbuild/darwin-arm64': 0.25.6 - '@esbuild/darwin-x64': 0.25.6 - '@esbuild/freebsd-arm64': 0.25.6 - '@esbuild/freebsd-x64': 0.25.6 - '@esbuild/linux-arm': 0.25.6 - '@esbuild/linux-arm64': 0.25.6 - '@esbuild/linux-ia32': 0.25.6 - '@esbuild/linux-loong64': 0.25.6 - '@esbuild/linux-mips64el': 0.25.6 - '@esbuild/linux-ppc64': 0.25.6 - '@esbuild/linux-riscv64': 0.25.6 - '@esbuild/linux-s390x': 0.25.6 - '@esbuild/linux-x64': 0.25.6 - '@esbuild/netbsd-arm64': 0.25.6 - '@esbuild/netbsd-x64': 0.25.6 - '@esbuild/openbsd-arm64': 0.25.6 - '@esbuild/openbsd-x64': 0.25.6 - '@esbuild/openharmony-arm64': 0.25.6 - '@esbuild/sunos-x64': 0.25.6 - '@esbuild/win32-arm64': 0.25.6 - '@esbuild/win32-ia32': 0.25.6 - '@esbuild/win32-x64': 0.25.6 - - estree-walker@3.0.3: - dependencies: - '@types/estree': 1.0.8 - - eventemitter3@5.0.1: {} - - eventsource-parser@3.0.3: {} - - execa@8.0.1: - dependencies: - cross-spawn: 7.0.6 - get-stream: 8.0.1 - human-signals: 5.0.0 - is-stream: 3.0.0 - merge-stream: 2.0.0 - npm-run-path: 5.3.0 - onetime: 6.0.0 - signal-exit: 4.1.0 - strip-final-newline: 3.0.0 - - extend@3.0.2: {} - - fsevents@2.3.2: - optional: true - - fsevents@2.3.3: - optional: true - - gaxios@6.7.1: - dependencies: - extend: 3.0.2 - https-proxy-agent: 7.0.6 - is-stream: 2.0.1 - node-fetch: 2.7.0 - uuid: 9.0.1 - transitivePeerDependencies: - - encoding - - supports-color - - gcp-metadata@6.1.1: - dependencies: - gaxios: 6.7.1 - google-logging-utils: 0.0.2 - json-bigint: 1.0.0 - transitivePeerDependencies: - - encoding - - supports-color - - get-func-name@2.0.2: {} - - get-stream@8.0.1: {} - - get-tsconfig@4.10.1: - dependencies: - resolve-pkg-maps: 1.0.0 - - google-auth-library@9.15.1: - dependencies: - base64-js: 1.5.1 - ecdsa-sig-formatter: 1.0.11 - gaxios: 6.7.1 - gcp-metadata: 6.1.1 - gtoken: 7.1.0 - jws: 4.0.0 - transitivePeerDependencies: - - encoding - - supports-color - - google-logging-utils@0.0.2: {} - - gtoken@7.1.0: - dependencies: - gaxios: 6.7.1 - jws: 4.0.0 - transitivePeerDependencies: - - encoding - - supports-color - - hono@4.9.6: {} - - https-proxy-agent@7.0.6: - dependencies: - agent-base: 7.1.4 - debug: 4.4.1 - transitivePeerDependencies: - - supports-color - - human-signals@5.0.0: {} - - is-stream@2.0.1: {} - - is-stream@3.0.0: {} - - isexe@2.0.0: {} - - js-tokens@9.0.1: {} - - json-bigint@1.0.0: - dependencies: - bignumber.js: 9.3.1 - - json-schema@0.4.0: {} - - jwa@2.0.1: - dependencies: - buffer-equal-constant-time: 1.0.1 - ecdsa-sig-formatter: 1.0.11 - safe-buffer: 5.2.1 - - jws@4.0.0: - dependencies: - jwa: 2.0.1 - safe-buffer: 5.2.1 - - liquidjs@10.21.1: - dependencies: - commander: 10.0.1 - - local-pkg@0.5.1: - dependencies: - mlly: 1.7.4 - pkg-types: 1.3.1 - - loupe@2.3.7: - dependencies: - get-func-name: 2.0.2 - - magic-string@0.30.17: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.4 - - merge-stream@2.0.0: {} - - mimic-fn@4.0.0: {} - - mlly@1.7.4: - dependencies: - acorn: 8.15.0 - pathe: 2.0.3 - pkg-types: 1.3.1 - ufo: 1.6.1 - - ms@2.1.3: {} - - nanoid@3.3.11: {} - - nanoid@5.1.5: {} - - node-fetch@2.7.0: - dependencies: - whatwg-url: 5.0.0 - - npm-run-path@5.3.0: - dependencies: - path-key: 4.0.0 - - ollama-ai-provider-v2@1.1.2(zod@4.0.17): - dependencies: - '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.1(zod@4.0.17) - zod: 4.0.17 - - onetime@6.0.0: - dependencies: - mimic-fn: 4.0.0 - - p-limit@5.0.0: - dependencies: - yocto-queue: 1.2.1 - - path-key@3.1.1: {} - - path-key@4.0.0: {} - - pathe@1.1.2: {} - - pathe@2.0.3: {} - - pathval@1.1.1: {} - - picocolors@1.1.1: {} - - pkg-types@1.3.1: - dependencies: - confbox: 0.1.8 - mlly: 1.7.4 - pathe: 2.0.3 - - playwright-core@1.53.0: {} - - playwright@1.53.0: - dependencies: - playwright-core: 1.53.0 - optionalDependencies: - fsevents: 2.3.2 - - postcss@8.5.6: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - prettier@3.6.2: {} - - pretty-format@29.7.0: - dependencies: - '@jest/schemas': 29.6.3 - ansi-styles: 5.2.0 - react-is: 18.3.1 - - react-is@18.3.1: {} - - resolve-pkg-maps@1.0.0: {} - - rollup@4.45.1: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.45.1 - '@rollup/rollup-android-arm64': 4.45.1 - '@rollup/rollup-darwin-arm64': 4.45.1 - '@rollup/rollup-darwin-x64': 4.45.1 - '@rollup/rollup-freebsd-arm64': 4.45.1 - '@rollup/rollup-freebsd-x64': 4.45.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.45.1 - '@rollup/rollup-linux-arm-musleabihf': 4.45.1 - '@rollup/rollup-linux-arm64-gnu': 4.45.1 - '@rollup/rollup-linux-arm64-musl': 4.45.1 - '@rollup/rollup-linux-loongarch64-gnu': 4.45.1 - '@rollup/rollup-linux-powerpc64le-gnu': 4.45.1 - '@rollup/rollup-linux-riscv64-gnu': 4.45.1 - '@rollup/rollup-linux-riscv64-musl': 4.45.1 - '@rollup/rollup-linux-s390x-gnu': 4.45.1 - '@rollup/rollup-linux-x64-gnu': 4.45.1 - '@rollup/rollup-linux-x64-musl': 4.45.1 - '@rollup/rollup-win32-arm64-msvc': 4.45.1 - '@rollup/rollup-win32-ia32-msvc': 4.45.1 - '@rollup/rollup-win32-x64-msvc': 4.45.1 - fsevents: 2.3.3 - - safe-buffer@5.2.1: {} - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - siginfo@2.0.0: {} - - signal-exit@4.1.0: {} - - source-map-js@1.2.1: {} - - spark@file:..: - dependencies: - '@ai-sdk/google-vertex': 3.0.9(zod@4.0.17) - '@ai-sdk/openai': 2.0.15(zod@4.0.17) - '@ai-sdk/openai-compatible': 1.0.11(zod@4.0.17) - '@ghostery/adblocker-playwright': 2.11.3(playwright@1.53.0) - '@openrouter/ai-sdk-provider': 1.1.2(ai@5.0.15(zod@4.0.17))(zod@4.0.17) - '@types/turndown': 5.0.5 - ai: 5.0.15(zod@4.0.17) - chalk: 5.5.0 - commander: 14.0.0 - cross-fetch: 4.1.0 - dotenv: 16.6.1 - eventemitter3: 5.0.1 - liquidjs: 10.21.1 - nanoid: 5.1.5 - ollama-ai-provider-v2: 1.1.2(zod@4.0.17) - playwright: 1.53.0 - turndown: 7.2.1 - zod: 4.0.17 - transitivePeerDependencies: - - encoding - - supports-color - - stackback@0.0.2: {} - - std-env@3.9.0: {} - - strip-final-newline@3.0.0: {} - - strip-literal@2.1.1: - dependencies: - js-tokens: 9.0.1 - - tinybench@2.9.0: {} - - tinypool@0.8.4: {} - - tinyspy@2.2.1: {} - - tldts-core@7.0.10: {} - - tldts-experimental@7.0.10: - dependencies: - tldts-core: 7.0.10 - - toucan-js@4.1.1: - dependencies: - '@sentry/core': 8.9.2 - '@sentry/types': 8.9.2 - '@sentry/utils': 8.9.2 - - tr46@0.0.3: {} - - tsx@4.20.4: - dependencies: - esbuild: 0.25.6 - get-tsconfig: 4.10.1 - optionalDependencies: - fsevents: 2.3.3 - - turndown@7.2.1: - dependencies: - '@mixmark-io/domino': 2.2.0 - - type-detect@4.1.0: {} - - typescript@5.9.2: {} - - ufo@1.6.1: {} - - undici-types@6.21.0: {} - - uuid@9.0.1: {} - - vite-node@1.6.1(@types/node@22.17.2): - dependencies: - cac: 6.7.14 - debug: 4.4.1 - pathe: 1.1.2 - picocolors: 1.1.1 - vite: 5.4.19(@types/node@22.17.2) - transitivePeerDependencies: - - '@types/node' - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - vite@5.4.19(@types/node@22.17.2): - dependencies: - esbuild: 0.21.5 - postcss: 8.5.6 - rollup: 4.45.1 - optionalDependencies: - '@types/node': 22.17.2 - fsevents: 2.3.3 - - vitest@1.6.1(@types/node@22.17.2): - dependencies: - '@vitest/expect': 1.6.1 - '@vitest/runner': 1.6.1 - '@vitest/snapshot': 1.6.1 - '@vitest/spy': 1.6.1 - '@vitest/utils': 1.6.1 - acorn-walk: 8.3.4 - chai: 4.5.0 - debug: 4.4.1 - execa: 8.0.1 - local-pkg: 0.5.1 - magic-string: 0.30.17 - pathe: 1.1.2 - picocolors: 1.1.1 - std-env: 3.9.0 - strip-literal: 2.1.1 - tinybench: 2.9.0 - tinypool: 0.8.4 - vite: 5.4.19(@types/node@22.17.2) - vite-node: 1.6.1(@types/node@22.17.2) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 22.17.2 - transitivePeerDependencies: - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - webidl-conversions@3.0.1: {} - - whatwg-url@5.0.0: - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - why-is-node-running@2.3.0: - dependencies: - siginfo: 2.0.0 - stackback: 0.0.2 - - yocto-queue@1.2.1: {} - - zod-to-json-schema@3.24.6(zod@4.0.17): - dependencies: - zod: 4.0.17 - - zod@4.0.17: {} diff --git a/server/src/config.ts b/server/src/config.ts deleted file mode 100644 index fec4b9ae..00000000 --- a/server/src/config.ts +++ /dev/null @@ -1,2 +0,0 @@ -// Re-export shared config system for server -export { config, ConfigManager, type SparkConfig } from "spark"; diff --git a/src/browser/ariaTree/bundle.ts b/src/browser/ariaTree/bundle.ts deleted file mode 100644 index 98525d9b..00000000 --- a/src/browser/ariaTree/bundle.ts +++ /dev/null @@ -1,4 +0,0 @@ -// AUTO-GENERATED by scripts/bundle-aria-tree.ts — do not edit -// Regenerate with: pnpm run bundle:aria -export const ARIA_TREE_SCRIPT = - '"use strict";\nvar __sparkAriaTree = (() => {\n var __defProp = Object.defineProperty;\n var __getOwnPropDesc = Object.getOwnPropertyDescriptor;\n var __getOwnPropNames = Object.getOwnPropertyNames;\n var __hasOwnProp = Object.prototype.hasOwnProperty;\n var __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n };\n var __copyProps = (to, from, except, desc) => {\n if (from && typeof from === "object" || typeof from === "function") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n };\n var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);\n\n // src/browser/ariaTree/ariaSnapshot.ts\n var ariaSnapshot_exports = {};\n __export(ariaSnapshot_exports, {\n applySetOfMarks: () => applySetOfMarks,\n generateAndRenderAriaTree: () => generateAndRenderAriaTree,\n isInteractiveElement: () => isInteractiveElement,\n removeSetOfMarks: () => removeSetOfMarks\n });\n\n // src/browser/ariaTree/stringUtils.ts\n function normalizeWhiteSpace(text) {\n if (!text) return "";\n return text.replace(/[\\u200b\\u00ad]/g, "").trim().replace(/\\s+/g, " ");\n }\n\n // src/browser/ariaTree/domUtils.ts\n function parentElementOrShadowHost(element) {\n if (element.parentElement) return element.parentElement;\n if (!element.parentNode) return;\n if (element.parentNode.nodeType === 11 && element.parentNode.host)\n return element.parentNode.host;\n }\n function enclosingShadowRootOrDocument(element) {\n let node = element;\n while (node.parentNode) node = node.parentNode;\n if (node.nodeType === 11 || node.nodeType === 9)\n return node;\n }\n function enclosingShadowHost(element) {\n while (element.parentElement) element = element.parentElement;\n return parentElementOrShadowHost(element);\n }\n function closestCrossShadow(element, css, scope) {\n while (element) {\n const closest = element.closest(css);\n if (scope && closest !== scope && closest?.contains(scope)) return;\n if (closest) return closest;\n element = enclosingShadowHost(element);\n }\n }\n function getElementComputedStyle(element, pseudo) {\n return element.ownerDocument && element.ownerDocument.defaultView ? element.ownerDocument.defaultView.getComputedStyle(element, pseudo) : void 0;\n }\n function isElementStyleVisibilityVisible(element, style) {\n style = style ?? getElementComputedStyle(element);\n if (!style) return true;\n if (Element.prototype.checkVisibility) {\n if (!element.checkVisibility()) return false;\n } else {\n const detailsOrSummary = element.closest("details,summary");\n if (detailsOrSummary !== element && detailsOrSummary?.nodeName === "DETAILS" && !detailsOrSummary.open)\n return false;\n }\n if (style.visibility !== "visible") return false;\n return true;\n }\n function box(element) {\n const style = getElementComputedStyle(element);\n if (!style) return { visible: true };\n if (style.display === "contents") {\n for (let child = element.firstChild; child; child = child.nextSibling) {\n if (child.nodeType === 1 && isElementVisible(child))\n return { visible: true, style };\n if (child.nodeType === 3 && isVisibleTextNode(child))\n return { visible: true, style };\n }\n return { visible: false, style };\n }\n if (!isElementStyleVisibilityVisible(element, style)) return { style, visible: false };\n const rect = element.getBoundingClientRect();\n return { rect, style, visible: rect.width > 0 && rect.height > 0 };\n }\n function isElementVisible(element) {\n return box(element).visible;\n }\n function isVisibleTextNode(node) {\n const range = node.ownerDocument.createRange();\n range.selectNode(node);\n const rect = range.getBoundingClientRect();\n return rect.width > 0 && rect.height > 0;\n }\n function elementSafeTagName(element) {\n if (element instanceof HTMLFormElement) return "FORM";\n return element.tagName.toUpperCase();\n }\n\n // src/browser/ariaTree/cssTokenizer.ts\n var between = function(num, first, last) {\n return num >= first && num <= last;\n };\n function digit(code) {\n return between(code, 48, 57);\n }\n function hexdigit(code) {\n return digit(code) || between(code, 65, 70) || between(code, 97, 102);\n }\n function uppercaseletter(code) {\n return between(code, 65, 90);\n }\n function lowercaseletter(code) {\n return between(code, 97, 122);\n }\n function letter(code) {\n return uppercaseletter(code) || lowercaseletter(code);\n }\n function nonascii(code) {\n return code >= 128;\n }\n function namestartchar(code) {\n return letter(code) || nonascii(code) || code === 95;\n }\n function namechar(code) {\n return namestartchar(code) || digit(code) || code === 45;\n }\n function nonprintable(code) {\n return between(code, 0, 8) || code === 11 || between(code, 14, 31) || code === 127;\n }\n function newline(code) {\n return code === 10;\n }\n function whitespace(code) {\n return newline(code) || code === 9 || code === 32;\n }\n var maximumallowedcodepoint = 1114111;\n function preprocess(str) {\n const codepoints = [];\n for (let i = 0; i < str.length; i++) {\n let code = str.charCodeAt(i);\n if (code === 13 && str.charCodeAt(i + 1) === 10) {\n code = 10;\n i++;\n }\n if (code === 13 || code === 12) code = 10;\n if (code === 0) code = 65533;\n if (between(code, 55296, 56319) && between(str.charCodeAt(i + 1), 56320, 57343)) {\n const lead = code - 55296;\n const trail = str.charCodeAt(i + 1) - 56320;\n code = Math.pow(2, 16) + lead * Math.pow(2, 10) + trail;\n i++;\n }\n codepoints.push(code);\n }\n return codepoints;\n }\n function stringFromCode(code) {\n if (code <= 65535) return String.fromCharCode(code);\n code -= Math.pow(2, 16);\n const lead = Math.floor(code / Math.pow(2, 10)) + 55296;\n const trail = code % Math.pow(2, 10) + 56320;\n return String.fromCharCode(lead) + String.fromCharCode(trail);\n }\n function tokenize(str1) {\n const str = preprocess(str1);\n let i = -1;\n const tokens = [];\n let code;\n let line = 0;\n let column = 0;\n let lastLineLength = 0;\n const incrLineno = function() {\n line += 1;\n lastLineLength = column;\n column = 0;\n };\n const codepoint = function(i2) {\n if (i2 >= str.length) return -1;\n return str[i2];\n };\n const next = function(num) {\n if (num === void 0) num = 1;\n if (num > 3) throw "Spec Error: no more than three codepoints of lookahead.";\n return codepoint(i + num);\n };\n const consume = function(num) {\n if (num === void 0) num = 1;\n i += num;\n code = codepoint(i);\n if (newline(code)) incrLineno();\n else column += num;\n return true;\n };\n const reconsume = function() {\n i -= 1;\n if (newline(code)) {\n line -= 1;\n column = lastLineLength;\n } else {\n column -= 1;\n }\n return true;\n };\n const eof = function(codepoint2) {\n if (codepoint2 === void 0) codepoint2 = code;\n return codepoint2 === -1;\n };\n const donothing = function() {\n };\n const parseerror = function() {\n };\n const consumeAToken = function() {\n consumeComments();\n consume();\n if (whitespace(code)) {\n while (whitespace(next())) consume();\n return new WhitespaceToken();\n } else if (code === 34) {\n return consumeAStringToken();\n } else if (code === 35) {\n if (namechar(next()) || areAValidEscape(next(1), next(2))) {\n const token = new HashToken("");\n if (wouldStartAnIdentifier(next(1), next(2), next(3))) token.type = "id";\n token.value = consumeAName();\n return token;\n } else {\n return new DelimToken(code);\n }\n } else if (code === 39) {\n return consumeAStringToken();\n } else if (code === 40) {\n return new OpenParenToken();\n } else if (code === 41) {\n return new CloseParenToken();\n } else if (code === 43) {\n if (startsWithANumber()) {\n reconsume();\n return consumeANumericToken();\n } else {\n return new DelimToken(code);\n }\n } else if (code === 44) {\n return new CommaToken();\n } else if (code === 45) {\n if (startsWithANumber()) {\n reconsume();\n return consumeANumericToken();\n } else if (startsWithAnIdentifier()) {\n reconsume();\n return consumeAnIdentlikeToken();\n } else {\n return new DelimToken(code);\n }\n } else if (code === 46) {\n if (startsWithANumber()) {\n reconsume();\n return consumeANumericToken();\n } else {\n return new DelimToken(code);\n }\n } else if (code === 58) {\n return new ColonToken();\n } else if (code === 59) {\n return new SemicolonToken();\n } else if (code === 64) {\n if (wouldStartAnIdentifier(next(1), next(2), next(3)))\n return new AtKeywordToken(consumeAName());\n else return new DelimToken(code);\n } else if (code === 91) {\n return new OpenSquareToken();\n } else if (code === 92) {\n if (startsWithAValidEscape()) {\n reconsume();\n return consumeAnIdentlikeToken();\n } else {\n parseerror();\n return new DelimToken(code);\n }\n } else if (code === 93) {\n return new CloseSquareToken();\n } else if (code === 123) {\n return new OpenCurlyToken();\n } else if (code === 125) {\n return new CloseCurlyToken();\n } else if (digit(code)) {\n reconsume();\n return consumeANumericToken();\n } else if (namestartchar(code)) {\n reconsume();\n return consumeAnIdentlikeToken();\n } else if (eof()) {\n return new EOFToken();\n } else {\n return new DelimToken(code);\n }\n };\n const consumeComments = function() {\n while (next(1) === 47 && next(2) === 42) {\n consume(2);\n while (true) {\n consume();\n if (code === 42 && next() === 47) {\n consume();\n break;\n } else if (eof()) {\n parseerror();\n return;\n }\n }\n }\n };\n const consumeANumericToken = function() {\n const num = consumeANumber();\n if (wouldStartAnIdentifier(next(1), next(2), next(3))) {\n const token = new DimensionToken();\n token.value = num.value;\n token.repr = num.repr;\n token.type = num.type;\n token.unit = consumeAName();\n return token;\n } else if (next() === 37) {\n consume();\n const token = new PercentageToken();\n token.value = num.value;\n token.repr = num.repr;\n return token;\n } else {\n const token = new NumberToken();\n token.value = num.value;\n token.repr = num.repr;\n token.type = num.type;\n return token;\n }\n };\n const consumeAnIdentlikeToken = function() {\n const str2 = consumeAName();\n if (str2.toLowerCase() === "url" && next() === 40) {\n consume();\n while (whitespace(next(1)) && whitespace(next(2))) consume();\n if (next() === 34 || next() === 39) return new FunctionToken(str2);\n else if (whitespace(next()) && (next(2) === 34 || next(2) === 39))\n return new FunctionToken(str2);\n else return consumeAURLToken();\n } else if (next() === 40) {\n consume();\n return new FunctionToken(str2);\n } else {\n return new IdentToken(str2);\n }\n };\n const consumeAStringToken = function(endingCodePoint) {\n if (endingCodePoint === void 0) endingCodePoint = code;\n let string = "";\n while (consume()) {\n if (code === endingCodePoint || eof()) {\n return new StringToken(string);\n } else if (newline(code)) {\n parseerror();\n reconsume();\n return new BadStringToken();\n } else if (code === 92) {\n if (eof(next())) donothing();\n else if (newline(next())) consume();\n else string += stringFromCode(consumeEscape());\n } else {\n string += stringFromCode(code);\n }\n }\n throw new Error("Internal error");\n };\n const consumeAURLToken = function() {\n const token = new URLToken("");\n while (whitespace(next())) consume();\n if (eof(next())) return token;\n while (consume()) {\n if (code === 41 || eof()) {\n return token;\n } else if (whitespace(code)) {\n while (whitespace(next())) consume();\n if (next() === 41 || eof(next())) {\n consume();\n return token;\n } else {\n consumeTheRemnantsOfABadURL();\n return new BadURLToken();\n }\n } else if (code === 34 || code === 39 || code === 40 || nonprintable(code)) {\n parseerror();\n consumeTheRemnantsOfABadURL();\n return new BadURLToken();\n } else if (code === 92) {\n if (startsWithAValidEscape()) {\n token.value += stringFromCode(consumeEscape());\n } else {\n parseerror();\n consumeTheRemnantsOfABadURL();\n return new BadURLToken();\n }\n } else {\n token.value += stringFromCode(code);\n }\n }\n throw new Error("Internal error");\n };\n const consumeEscape = function() {\n consume();\n if (hexdigit(code)) {\n const digits = [code];\n for (let total = 0; total < 5; total++) {\n if (hexdigit(next())) {\n consume();\n digits.push(code);\n } else {\n break;\n }\n }\n if (whitespace(next())) consume();\n let value = parseInt(\n digits.map(function(x) {\n return String.fromCharCode(x);\n }).join(""),\n 16\n );\n if (value > maximumallowedcodepoint) value = 65533;\n return value;\n } else if (eof()) {\n return 65533;\n } else {\n return code;\n }\n };\n const areAValidEscape = function(c1, c2) {\n if (c1 !== 92) return false;\n if (newline(c2)) return false;\n return true;\n };\n const startsWithAValidEscape = function() {\n return areAValidEscape(code, next());\n };\n const wouldStartAnIdentifier = function(c1, c2, c3) {\n if (c1 === 45) return namestartchar(c2) || c2 === 45 || areAValidEscape(c2, c3);\n else if (namestartchar(c1)) return true;\n else if (c1 === 92) return areAValidEscape(c1, c2);\n else return false;\n };\n const startsWithAnIdentifier = function() {\n return wouldStartAnIdentifier(code, next(1), next(2));\n };\n const wouldStartANumber = function(c1, c2, c3) {\n if (c1 === 43 || c1 === 45) {\n if (digit(c2)) return true;\n if (c2 === 46 && digit(c3)) return true;\n return false;\n } else if (c1 === 46) {\n if (digit(c2)) return true;\n return false;\n } else if (digit(c1)) {\n return true;\n } else {\n return false;\n }\n };\n const startsWithANumber = function() {\n return wouldStartANumber(code, next(1), next(2));\n };\n const consumeAName = function() {\n let result = "";\n while (consume()) {\n if (namechar(code)) {\n result += stringFromCode(code);\n } else if (startsWithAValidEscape()) {\n result += stringFromCode(consumeEscape());\n } else {\n reconsume();\n return result;\n }\n }\n throw new Error("Internal parse error");\n };\n const consumeANumber = function() {\n let repr = "";\n let type = "integer";\n if (next() === 43 || next() === 45) {\n consume();\n repr += stringFromCode(code);\n }\n while (digit(next())) {\n consume();\n repr += stringFromCode(code);\n }\n if (next(1) === 46 && digit(next(2))) {\n consume();\n repr += stringFromCode(code);\n consume();\n repr += stringFromCode(code);\n type = "number";\n while (digit(next())) {\n consume();\n repr += stringFromCode(code);\n }\n }\n const c1 = next(1), c2 = next(2), c3 = next(3);\n if ((c1 === 69 || c1 === 101) && digit(c2)) {\n consume();\n repr += stringFromCode(code);\n consume();\n repr += stringFromCode(code);\n type = "number";\n while (digit(next())) {\n consume();\n repr += stringFromCode(code);\n }\n } else if ((c1 === 69 || c1 === 101) && (c2 === 43 || c2 === 45) && digit(c3)) {\n consume();\n repr += stringFromCode(code);\n consume();\n repr += stringFromCode(code);\n consume();\n repr += stringFromCode(code);\n type = "number";\n while (digit(next())) {\n consume();\n repr += stringFromCode(code);\n }\n }\n const value = +repr;\n return { type, value, repr };\n };\n const consumeTheRemnantsOfABadURL = function() {\n while (consume()) {\n if (code === 41 || eof()) {\n return;\n } else if (startsWithAValidEscape()) {\n consumeEscape();\n donothing();\n } else {\n donothing();\n }\n }\n };\n let iterationCount = 0;\n while (!eof(next())) {\n tokens.push(consumeAToken());\n iterationCount++;\n if (iterationCount > str.length * 2) throw new Error("I\'m infinite-looping!");\n }\n return tokens;\n }\n var CSSParserToken = class {\n tokenType = "";\n value;\n toJSON() {\n return { token: this.tokenType };\n }\n toString() {\n return this.tokenType;\n }\n toSource() {\n return "" + this;\n }\n };\n var BadStringToken = class extends CSSParserToken {\n tokenType = "BADSTRING";\n };\n var BadURLToken = class extends CSSParserToken {\n tokenType = "BADURL";\n };\n var WhitespaceToken = class extends CSSParserToken {\n tokenType = "WHITESPACE";\n toString() {\n return "WS";\n }\n toSource() {\n return " ";\n }\n };\n var ColonToken = class extends CSSParserToken {\n tokenType = ":";\n };\n var SemicolonToken = class extends CSSParserToken {\n tokenType = ";";\n };\n var CommaToken = class extends CSSParserToken {\n tokenType = ",";\n };\n var GroupingToken = class extends CSSParserToken {\n value = "";\n mirror = "";\n };\n var OpenCurlyToken = class extends GroupingToken {\n tokenType = "{";\n constructor() {\n super();\n this.value = "{";\n this.mirror = "}";\n }\n };\n var CloseCurlyToken = class extends GroupingToken {\n tokenType = "}";\n constructor() {\n super();\n this.value = "}";\n this.mirror = "{";\n }\n };\n var OpenSquareToken = class extends GroupingToken {\n tokenType = "[";\n constructor() {\n super();\n this.value = "[";\n this.mirror = "]";\n }\n };\n var CloseSquareToken = class extends GroupingToken {\n tokenType = "]";\n constructor() {\n super();\n this.value = "]";\n this.mirror = "[";\n }\n };\n var OpenParenToken = class extends GroupingToken {\n tokenType = "(";\n constructor() {\n super();\n this.value = "(";\n this.mirror = ")";\n }\n };\n var CloseParenToken = class extends GroupingToken {\n tokenType = ")";\n constructor() {\n super();\n this.value = ")";\n this.mirror = "(";\n }\n };\n var EOFToken = class extends CSSParserToken {\n tokenType = "EOF";\n toSource() {\n return "";\n }\n };\n var DelimToken = class extends CSSParserToken {\n tokenType = "DELIM";\n value = "";\n constructor(code) {\n super();\n this.value = stringFromCode(code);\n }\n toString() {\n return "DELIM(" + this.value + ")";\n }\n toSource() {\n if (this.value === "\\\\") return "\\\\\\n";\n else return this.value;\n }\n };\n var StringValuedToken = class extends CSSParserToken {\n value = "";\n };\n var IdentToken = class extends StringValuedToken {\n constructor(val) {\n super();\n this.value = val;\n }\n tokenType = "IDENT";\n };\n var FunctionToken = class extends StringValuedToken {\n tokenType = "FUNCTION";\n mirror;\n constructor(val) {\n super();\n this.value = val;\n this.mirror = ")";\n }\n };\n var AtKeywordToken = class extends StringValuedToken {\n tokenType = "AT-KEYWORD";\n constructor(val) {\n super();\n this.value = val;\n }\n };\n var HashToken = class extends StringValuedToken {\n tokenType = "HASH";\n type;\n constructor(val) {\n super();\n this.value = val;\n this.type = "unrestricted";\n }\n };\n var StringToken = class extends StringValuedToken {\n tokenType = "STRING";\n constructor(val) {\n super();\n this.value = val;\n }\n };\n var URLToken = class extends StringValuedToken {\n tokenType = "URL";\n constructor(val) {\n super();\n this.value = val;\n }\n };\n var NumberToken = class extends CSSParserToken {\n tokenType = "NUMBER";\n type;\n repr;\n constructor() {\n super();\n this.type = "integer";\n this.repr = "";\n }\n };\n var PercentageToken = class extends CSSParserToken {\n tokenType = "PERCENTAGE";\n repr;\n constructor() {\n super();\n this.repr = "";\n }\n };\n var DimensionToken = class extends CSSParserToken {\n tokenType = "DIMENSION";\n type;\n repr;\n unit;\n constructor() {\n super();\n this.type = "integer";\n this.repr = "";\n this.unit = "";\n }\n };\n\n // src/browser/ariaTree/roleUtils.ts\n function hasExplicitAccessibleName(e) {\n return e.hasAttribute("aria-label") || e.hasAttribute("aria-labelledby");\n }\n var kAncestorPreventingLandmark = "article:not([role]), aside:not([role]), main:not([role]), nav:not([role]), section:not([role]), [role=article], [role=complementary], [role=main], [role=navigation], [role=region]";\n var kGlobalAriaAttributes = [\n ["aria-atomic", void 0],\n ["aria-busy", void 0],\n ["aria-controls", void 0],\n ["aria-current", void 0],\n ["aria-describedby", void 0],\n ["aria-details", void 0],\n ["aria-dropeffect", void 0],\n ["aria-flowto", void 0],\n ["aria-grabbed", void 0],\n ["aria-hidden", void 0],\n ["aria-keyshortcuts", void 0],\n [\n "aria-label",\n [\n "caption",\n "code",\n "deletion",\n "emphasis",\n "generic",\n "insertion",\n "paragraph",\n "presentation",\n "strong",\n "subscript",\n "superscript"\n ]\n ],\n [\n "aria-labelledby",\n [\n "caption",\n "code",\n "deletion",\n "emphasis",\n "generic",\n "insertion",\n "paragraph",\n "presentation",\n "strong",\n "subscript",\n "superscript"\n ]\n ],\n ["aria-live", void 0],\n ["aria-owns", void 0],\n ["aria-relevant", void 0],\n ["aria-roledescription", ["generic"]]\n ];\n function hasGlobalAriaAttribute(element, forRole) {\n return kGlobalAriaAttributes.some(([attr, prohibited]) => {\n return !prohibited?.includes(forRole || "") && element.hasAttribute(attr);\n });\n }\n function hasTabIndex(element) {\n return !Number.isNaN(Number(String(element.getAttribute("tabindex"))));\n }\n function isFocusable(element) {\n return !isNativelyDisabled(element) && (isNativelyFocusable(element) || hasTabIndex(element));\n }\n function isNativelyFocusable(element) {\n const tagName = elementSafeTagName(element);\n if (["BUTTON", "DETAILS", "SELECT", "TEXTAREA"].includes(tagName)) return true;\n if (tagName === "A" || tagName === "AREA") return element.hasAttribute("href");\n if (tagName === "INPUT") return !element.hidden;\n return false;\n }\n var kImplicitRoleByTagName = {\n A: (e) => e.hasAttribute("href") ? "link" : null,\n AREA: (e) => e.hasAttribute("href") ? "link" : null,\n ARTICLE: () => "article",\n ASIDE: () => "complementary",\n BLOCKQUOTE: () => "blockquote",\n BUTTON: () => "button",\n CAPTION: () => "caption",\n CODE: () => "code",\n DATALIST: () => "listbox",\n DD: () => "definition",\n DEL: () => "deletion",\n DETAILS: () => "group",\n DFN: () => "term",\n DIALOG: () => "dialog",\n DT: () => "term",\n EM: () => "emphasis",\n FIELDSET: () => "group",\n FIGURE: () => "figure",\n FOOTER: (e) => closestCrossShadow(e, kAncestorPreventingLandmark) ? null : "contentinfo",\n FORM: (e) => hasExplicitAccessibleName(e) ? "form" : null,\n H1: () => "heading",\n H2: () => "heading",\n H3: () => "heading",\n H4: () => "heading",\n H5: () => "heading",\n H6: () => "heading",\n HEADER: (e) => closestCrossShadow(e, kAncestorPreventingLandmark) ? null : "banner",\n HR: () => "separator",\n HTML: () => "document",\n IMG: (e) => e.getAttribute("alt") === "" && !e.getAttribute("title") && !hasGlobalAriaAttribute(e) && !hasTabIndex(e) ? "presentation" : "img",\n INPUT: (e) => {\n const type = e.type.toLowerCase();\n if (type === "search") return e.hasAttribute("list") ? "combobox" : "searchbox";\n if (["email", "tel", "text", "url", ""].includes(type)) {\n const list = getIdRefs(e, e.getAttribute("list"))[0];\n return list && elementSafeTagName(list) === "DATALIST" ? "combobox" : "textbox";\n }\n if (type === "hidden") return null;\n if (type === "file") return "button";\n return inputTypeToRole[type] || "textbox";\n },\n INS: () => "insertion",\n LI: () => "listitem",\n MAIN: () => "main",\n MARK: () => "mark",\n MATH: () => "math",\n MENU: () => "list",\n METER: () => "meter",\n NAV: () => "navigation",\n OL: () => "list",\n OPTGROUP: () => "group",\n OPTION: () => "option",\n OUTPUT: () => "status",\n P: () => "paragraph",\n PROGRESS: () => "progressbar",\n SECTION: (e) => hasExplicitAccessibleName(e) ? "region" : null,\n SELECT: (e) => e.hasAttribute("multiple") || e.size > 1 ? "listbox" : "combobox",\n STRONG: () => "strong",\n SUB: () => "subscript",\n SUP: () => "superscript",\n SVG: () => "img",\n TABLE: () => "table",\n TBODY: () => "rowgroup",\n TD: (e) => {\n const table = closestCrossShadow(e, "table");\n const role = table ? getExplicitAriaRole(table) : "";\n return role === "grid" || role === "treegrid" ? "gridcell" : "cell";\n },\n TEXTAREA: () => "textbox",\n TFOOT: () => "rowgroup",\n TH: (e) => {\n if (e.getAttribute("scope") === "col") return "columnheader";\n if (e.getAttribute("scope") === "row") return "rowheader";\n const table = closestCrossShadow(e, "table");\n const role = table ? getExplicitAriaRole(table) : "";\n return role === "grid" || role === "treegrid" ? "gridcell" : "cell";\n },\n THEAD: () => "rowgroup",\n TIME: () => "time",\n TR: () => "row",\n UL: () => "list"\n };\n var kPresentationInheritanceParents = {\n DD: ["DL", "DIV"],\n DIV: ["DL"],\n DT: ["DL", "DIV"],\n LI: ["OL", "UL"],\n TBODY: ["TABLE"],\n TD: ["TR"],\n TFOOT: ["TABLE"],\n TH: ["TR"],\n THEAD: ["TABLE"],\n TR: ["THEAD", "TBODY", "TFOOT", "TABLE"]\n };\n function getImplicitAriaRole(element) {\n const implicitRole = kImplicitRoleByTagName[elementSafeTagName(element)]?.(element) || "";\n if (!implicitRole) return null;\n let ancestor = element;\n while (ancestor) {\n const parent = parentElementOrShadowHost(ancestor);\n const parents = kPresentationInheritanceParents[elementSafeTagName(ancestor)];\n if (!parents || !parent || !parents.includes(elementSafeTagName(parent))) break;\n const parentExplicitRole = getExplicitAriaRole(parent);\n if ((parentExplicitRole === "none" || parentExplicitRole === "presentation") && !hasPresentationConflictResolution(parent, parentExplicitRole))\n return parentExplicitRole;\n ancestor = parent;\n }\n return implicitRole;\n }\n var validRoles = [\n "alert",\n "alertdialog",\n "application",\n "article",\n "banner",\n "blockquote",\n "button",\n "caption",\n "cell",\n "checkbox",\n "code",\n "columnheader",\n "combobox",\n "complementary",\n "contentinfo",\n "definition",\n "deletion",\n "dialog",\n "directory",\n "document",\n "emphasis",\n "feed",\n "figure",\n "form",\n "generic",\n "grid",\n "gridcell",\n "group",\n "heading",\n "img",\n "insertion",\n "link",\n "list",\n "listbox",\n "listitem",\n "log",\n "main",\n "mark",\n "marquee",\n "math",\n "meter",\n "menu",\n "menubar",\n "menuitem",\n "menuitemcheckbox",\n "menuitemradio",\n "navigation",\n "none",\n "note",\n "option",\n "paragraph",\n "presentation",\n "progressbar",\n "radio",\n "radiogroup",\n "region",\n "row",\n "rowgroup",\n "rowheader",\n "scrollbar",\n "search",\n "searchbox",\n "separator",\n "slider",\n "spinbutton",\n "status",\n "strong",\n "subscript",\n "superscript",\n "switch",\n "tab",\n "table",\n "tablist",\n "tabpanel",\n "term",\n "textbox",\n "time",\n "timer",\n "toolbar",\n "tooltip",\n "tree",\n "treegrid",\n "treeitem"\n ];\n function getExplicitAriaRole(element) {\n const roles = (element.getAttribute("role") || "").split(" ").map((role) => role.trim());\n return roles.find((role) => validRoles.includes(role)) || null;\n }\n function hasPresentationConflictResolution(element, role) {\n return hasGlobalAriaAttribute(element, role) || isFocusable(element);\n }\n function getAriaRole(element) {\n const explicitRole = getExplicitAriaRole(element);\n if (!explicitRole) return getImplicitAriaRole(element);\n if (explicitRole === "none" || explicitRole === "presentation") {\n const implicitRole = getImplicitAriaRole(element);\n if (hasPresentationConflictResolution(element, implicitRole)) return implicitRole;\n }\n return explicitRole;\n }\n function getAriaBoolean(attr) {\n return attr === null ? void 0 : attr.toLowerCase() === "true";\n }\n function isElementIgnoredForAria(element) {\n return ["STYLE", "SCRIPT", "NOSCRIPT", "TEMPLATE"].includes(elementSafeTagName(element));\n }\n function isElementHiddenForAria(element) {\n if (isElementIgnoredForAria(element)) return true;\n const style = getElementComputedStyle(element);\n const isSlot = element.nodeName === "SLOT";\n if (style?.display === "contents" && !isSlot) {\n for (let child = element.firstChild; child; child = child.nextSibling) {\n if (child.nodeType === 1 && !isElementHiddenForAria(child))\n return false;\n if (child.nodeType === 3 && isVisibleTextNode(child))\n return false;\n }\n return true;\n }\n const isOptionInsideSelect = element.nodeName === "OPTION" && !!element.closest("select");\n if (!isOptionInsideSelect && !isSlot && !isElementStyleVisibilityVisible(element, style))\n return true;\n return belongsToDisplayNoneOrAriaHiddenOrNonSlotted(element);\n }\n function belongsToDisplayNoneOrAriaHiddenOrNonSlotted(element) {\n let hidden = cacheIsHidden?.get(element);\n if (hidden === void 0) {\n hidden = false;\n if (element.parentElement && element.parentElement.shadowRoot && !element.assignedSlot)\n hidden = true;\n if (!hidden) {\n const style = getElementComputedStyle(element);\n hidden = !style || style.display === "none" || getAriaBoolean(element.getAttribute("aria-hidden")) === true;\n }\n if (!hidden) {\n const parent = parentElementOrShadowHost(element);\n if (parent) hidden = belongsToDisplayNoneOrAriaHiddenOrNonSlotted(parent);\n }\n cacheIsHidden?.set(element, hidden);\n }\n return hidden;\n }\n function getIdRefs(element, ref) {\n if (!ref) return [];\n const root = enclosingShadowRootOrDocument(element);\n if (!root) return [];\n try {\n const ids = ref.split(" ").filter((id) => !!id);\n const result = [];\n for (const id of ids) {\n const firstElement = root.querySelector("#" + CSS.escape(id));\n if (firstElement && !result.includes(firstElement)) result.push(firstElement);\n }\n return result;\n } catch {\n return [];\n }\n }\n function trimFlatString(s) {\n return s.trim();\n }\n function asFlatString(s) {\n return s.split("\\xA0").map(\n (chunk) => chunk.replace(/\\r\\n/g, "\\n").replace(/[\\u200b\\u00ad]/g, "").replace(/\\s\\s*/g, " ")\n ).join("\\xA0").trim();\n }\n function queryInAriaOwned(element, selector) {\n const result = [...element.querySelectorAll(selector)];\n for (const owned of getIdRefs(element, element.getAttribute("aria-owns"))) {\n if (owned.matches(selector)) result.push(owned);\n result.push(...owned.querySelectorAll(selector));\n }\n return result;\n }\n function getCSSContent(element, pseudo) {\n const cache = pseudo === "::before" ? cachePseudoContentBefore : pseudo === "::after" ? cachePseudoContentAfter : cachePseudoContent;\n if (cache?.has(element)) return cache?.get(element);\n const style = getElementComputedStyle(element, pseudo);\n let content;\n if (style && style.display !== "none" && style.visibility !== "hidden") {\n content = parseCSSContentPropertyAsString(element, style.content, !!pseudo);\n }\n if (pseudo && content !== void 0) {\n const display = style?.display || "inline";\n if (display !== "inline") content = " " + content + " ";\n }\n if (cache) cache.set(element, content);\n return content;\n }\n function parseCSSContentPropertyAsString(element, content, isPseudo) {\n if (!content || content === "none" || content === "normal") {\n return;\n }\n try {\n let tokens = tokenize(content).filter((token) => !(token instanceof WhitespaceToken));\n const delimIndex = tokens.findIndex(\n (token) => token instanceof DelimToken && token.value === "/"\n );\n if (delimIndex !== -1) {\n tokens = tokens.slice(delimIndex + 1);\n } else if (!isPseudo) {\n return;\n }\n const accumulated = [];\n let index = 0;\n while (index < tokens.length) {\n if (tokens[index] instanceof StringToken) {\n accumulated.push(tokens[index].value);\n index++;\n } else if (index + 2 < tokens.length && tokens[index] instanceof FunctionToken && tokens[index].value === "attr" && tokens[index + 1] instanceof IdentToken && tokens[index + 2] instanceof CloseParenToken) {\n const attrName = tokens[index + 1].value;\n accumulated.push(element.getAttribute(attrName) || "");\n index += 3;\n } else {\n return;\n }\n }\n return accumulated.join("");\n } catch {\n }\n }\n function getAriaLabelledByElements(element) {\n const ref = element.getAttribute("aria-labelledby");\n if (ref === null) return null;\n const refs = getIdRefs(element, ref);\n return refs.length ? refs : null;\n }\n function allowsNameFromContent(role, targetDescendant) {\n const alwaysAllowsNameFromContent = [\n "button",\n "cell",\n "checkbox",\n "columnheader",\n "gridcell",\n "heading",\n "link",\n "menuitem",\n "menuitemcheckbox",\n "menuitemradio",\n "option",\n "radio",\n "row",\n "rowheader",\n "switch",\n "tab",\n "tooltip",\n "treeitem"\n ].includes(role);\n const descendantAllowsNameFromContent = targetDescendant && [\n "",\n "caption",\n "code",\n "contentinfo",\n "definition",\n "deletion",\n "emphasis",\n "insertion",\n "list",\n "listitem",\n "mark",\n "none",\n "paragraph",\n "presentation",\n "region",\n "row",\n "rowgroup",\n "section",\n "strong",\n "subscript",\n "superscript",\n "table",\n "term",\n "time"\n ].includes(role);\n return alwaysAllowsNameFromContent || descendantAllowsNameFromContent;\n }\n function getElementAccessibleName(element, includeHidden) {\n const cache = includeHidden ? cacheAccessibleNameHidden : cacheAccessibleName;\n let accessibleName = cache?.get(element);\n if (accessibleName === void 0) {\n accessibleName = "";\n const elementProhibitsNaming = [\n "caption",\n "code",\n "definition",\n "deletion",\n "emphasis",\n "generic",\n "insertion",\n "mark",\n "paragraph",\n "presentation",\n "strong",\n "subscript",\n "suggestion",\n "superscript",\n "term",\n "time"\n ].includes(getAriaRole(element) || "");\n if (!elementProhibitsNaming) {\n accessibleName = asFlatString(\n getTextAlternativeInternal(element, {\n includeHidden,\n visitedElements: /* @__PURE__ */ new Set(),\n embeddedInTargetElement: "self"\n })\n );\n }\n cache?.set(element, accessibleName);\n }\n return accessibleName;\n }\n function getTextAlternativeInternal(element, options) {\n if (options.visitedElements.has(element)) return "";\n const childOptions = {\n ...options,\n embeddedInTargetElement: options.embeddedInTargetElement === "self" ? "descendant" : options.embeddedInTargetElement\n };\n if (!options.includeHidden) {\n const isEmbeddedInHiddenReferenceTraversal = !!options.embeddedInLabelledBy?.hidden || !!options.embeddedInDescribedBy?.hidden || !!options.embeddedInNativeTextAlternative?.hidden || !!options.embeddedInLabel?.hidden;\n if (isElementIgnoredForAria(element) || !isEmbeddedInHiddenReferenceTraversal && isElementHiddenForAria(element)) {\n options.visitedElements.add(element);\n return "";\n }\n }\n const labelledBy = getAriaLabelledByElements(element);\n if (!options.embeddedInLabelledBy) {\n const accessibleName = (labelledBy || []).map(\n (ref) => getTextAlternativeInternal(ref, {\n ...options,\n embeddedInLabelledBy: { element: ref, hidden: isElementHiddenForAria(ref) },\n embeddedInDescribedBy: void 0,\n embeddedInTargetElement: void 0,\n embeddedInLabel: void 0,\n embeddedInNativeTextAlternative: void 0\n })\n ).join(" ");\n if (accessibleName) return accessibleName;\n }\n const role = getAriaRole(element) || "";\n const tagName = elementSafeTagName(element);\n if (!!options.embeddedInLabel || !!options.embeddedInLabelledBy || options.embeddedInTargetElement === "descendant") {\n const isOwnLabel = [\n ...element.labels || []\n ].includes(element);\n const isOwnLabelledBy = (labelledBy || []).includes(element);\n if (!isOwnLabel && !isOwnLabelledBy) {\n if (role === "textbox") {\n options.visitedElements.add(element);\n if (tagName === "INPUT" || tagName === "TEXTAREA")\n return element.value;\n return element.textContent || "";\n }\n if (["combobox", "listbox"].includes(role)) {\n options.visitedElements.add(element);\n let selectedOptions;\n if (tagName === "SELECT") {\n selectedOptions = [...element.selectedOptions];\n if (!selectedOptions.length && element.options.length)\n selectedOptions.push(element.options[0]);\n } else {\n const listbox = role === "combobox" ? queryInAriaOwned(element, "*").find((e) => getAriaRole(e) === "listbox") : element;\n selectedOptions = listbox ? queryInAriaOwned(listbox, \'[aria-selected="true"]\').filter(\n (e) => getAriaRole(e) === "option"\n ) : [];\n }\n if (!selectedOptions.length && tagName === "INPUT") {\n return element.value;\n }\n return selectedOptions.map((option) => getTextAlternativeInternal(option, childOptions)).join(" ");\n }\n if (["progressbar", "scrollbar", "slider", "spinbutton", "meter"].includes(role)) {\n options.visitedElements.add(element);\n if (element.hasAttribute("aria-valuetext"))\n return element.getAttribute("aria-valuetext") || "";\n if (element.hasAttribute("aria-valuenow"))\n return element.getAttribute("aria-valuenow") || "";\n return element.getAttribute("value") || "";\n }\n if (["menu"].includes(role)) {\n options.visitedElements.add(element);\n return "";\n }\n }\n }\n const ariaLabel = element.getAttribute("aria-label") || "";\n if (trimFlatString(ariaLabel)) {\n options.visitedElements.add(element);\n return ariaLabel;\n }\n if (!["presentation", "none"].includes(role)) {\n if (tagName === "INPUT" && ["button", "submit", "reset"].includes(element.type)) {\n options.visitedElements.add(element);\n const value = element.value || "";\n if (trimFlatString(value)) return value;\n if (element.type === "submit") return "Submit";\n if (element.type === "reset") return "Reset";\n const title = element.getAttribute("title") || "";\n return title;\n }\n if (tagName === "INPUT" && element.type === "file") {\n options.visitedElements.add(element);\n const labels = element.labels || [];\n if (labels.length && !options.embeddedInLabelledBy)\n return getAccessibleNameFromAssociatedLabels(labels, options);\n return "Choose File";\n }\n if (tagName === "INPUT" && element.type === "image") {\n options.visitedElements.add(element);\n const labels = element.labels || [];\n if (labels.length && !options.embeddedInLabelledBy)\n return getAccessibleNameFromAssociatedLabels(labels, options);\n const alt = element.getAttribute("alt") || "";\n if (trimFlatString(alt)) return alt;\n const title = element.getAttribute("title") || "";\n if (trimFlatString(title)) return title;\n return "Submit";\n }\n if (!labelledBy && tagName === "BUTTON") {\n options.visitedElements.add(element);\n const labels = element.labels || [];\n if (labels.length) return getAccessibleNameFromAssociatedLabels(labels, options);\n }\n if (!labelledBy && tagName === "OUTPUT") {\n options.visitedElements.add(element);\n const labels = element.labels || [];\n if (labels.length) return getAccessibleNameFromAssociatedLabels(labels, options);\n return element.getAttribute("title") || "";\n }\n if (!labelledBy && (tagName === "TEXTAREA" || tagName === "SELECT" || tagName === "INPUT")) {\n options.visitedElements.add(element);\n const labels = element.labels || [];\n if (labels.length) return getAccessibleNameFromAssociatedLabels(labels, options);\n const usePlaceholder = tagName === "INPUT" && ["text", "password", "search", "tel", "email", "url"].includes(\n element.type\n ) || tagName === "TEXTAREA";\n const placeholder = element.getAttribute("placeholder") || "";\n const title = element.getAttribute("title") || "";\n if (!usePlaceholder || title) return title;\n return placeholder;\n }\n if (!labelledBy && tagName === "FIELDSET") {\n options.visitedElements.add(element);\n for (let child = element.firstElementChild; child; child = child.nextElementSibling) {\n if (elementSafeTagName(child) === "LEGEND") {\n return getTextAlternativeInternal(child, {\n ...childOptions,\n embeddedInNativeTextAlternative: {\n element: child,\n hidden: isElementHiddenForAria(child)\n }\n });\n }\n }\n const title = element.getAttribute("title") || "";\n return title;\n }\n if (!labelledBy && tagName === "FIGURE") {\n options.visitedElements.add(element);\n for (let child = element.firstElementChild; child; child = child.nextElementSibling) {\n if (elementSafeTagName(child) === "FIGCAPTION") {\n return getTextAlternativeInternal(child, {\n ...childOptions,\n embeddedInNativeTextAlternative: {\n element: child,\n hidden: isElementHiddenForAria(child)\n }\n });\n }\n }\n const title = element.getAttribute("title") || "";\n return title;\n }\n if (tagName === "IMG") {\n options.visitedElements.add(element);\n const alt = element.getAttribute("alt") || "";\n if (trimFlatString(alt)) return alt;\n const title = element.getAttribute("title") || "";\n return title;\n }\n if (tagName === "TABLE") {\n options.visitedElements.add(element);\n for (let child = element.firstElementChild; child; child = child.nextElementSibling) {\n if (elementSafeTagName(child) === "CAPTION") {\n return getTextAlternativeInternal(child, {\n ...childOptions,\n embeddedInNativeTextAlternative: {\n element: child,\n hidden: isElementHiddenForAria(child)\n }\n });\n }\n }\n const summary = element.getAttribute("summary") || "";\n if (summary) return summary;\n }\n if (tagName === "AREA") {\n options.visitedElements.add(element);\n const alt = element.getAttribute("alt") || "";\n if (trimFlatString(alt)) return alt;\n const title = element.getAttribute("title") || "";\n return title;\n }\n if (tagName === "SVG" || element.ownerSVGElement) {\n options.visitedElements.add(element);\n for (let child = element.firstElementChild; child; child = child.nextElementSibling) {\n if (elementSafeTagName(child) === "TITLE" && child.ownerSVGElement) {\n return getTextAlternativeInternal(child, {\n ...childOptions,\n embeddedInLabelledBy: { element: child, hidden: isElementHiddenForAria(child) }\n });\n }\n }\n }\n if (element.ownerSVGElement && tagName === "A") {\n const title = element.getAttribute("xlink:title") || "";\n if (trimFlatString(title)) {\n options.visitedElements.add(element);\n return title;\n }\n }\n }\n const shouldNameFromContentForSummary = tagName === "SUMMARY" && !["presentation", "none"].includes(role);\n if (allowsNameFromContent(role, options.embeddedInTargetElement === "descendant") || shouldNameFromContentForSummary || !!options.embeddedInLabelledBy || !!options.embeddedInDescribedBy || !!options.embeddedInLabel || !!options.embeddedInNativeTextAlternative) {\n options.visitedElements.add(element);\n const accessibleName = innerAccumulatedElementText(element, childOptions);\n const maybeTrimmedAccessibleName = options.embeddedInTargetElement === "self" ? trimFlatString(accessibleName) : accessibleName;\n if (maybeTrimmedAccessibleName) return accessibleName;\n }\n if (!["presentation", "none"].includes(role) || tagName === "IFRAME") {\n options.visitedElements.add(element);\n const title = element.getAttribute("title") || "";\n if (trimFlatString(title)) return title;\n }\n options.visitedElements.add(element);\n return "";\n }\n function innerAccumulatedElementText(element, options) {\n const tokens = [];\n const visit = (node, skipSlotted) => {\n if (skipSlotted && node.assignedSlot) return;\n if (node.nodeType === 1) {\n const display = getElementComputedStyle(node)?.display || "inline";\n let token = getTextAlternativeInternal(node, options);\n if (display !== "inline" || node.nodeName === "BR") token = " " + token + " ";\n tokens.push(token);\n } else if (node.nodeType === 3) {\n tokens.push(node.textContent || "");\n }\n };\n tokens.push(getCSSContent(element, "::before") || "");\n const content = getCSSContent(element);\n if (content !== void 0) {\n tokens.push(content);\n } else {\n const assignedNodes = element.nodeName === "SLOT" ? element.assignedNodes() : [];\n if (assignedNodes.length) {\n for (const child of assignedNodes) visit(child, false);\n } else {\n for (let child = element.firstChild; child; child = child.nextSibling) visit(child, true);\n if (element.shadowRoot) {\n for (let child = element.shadowRoot.firstChild; child; child = child.nextSibling)\n visit(child, true);\n }\n for (const owned of getIdRefs(element, element.getAttribute("aria-owns"))) visit(owned, true);\n }\n }\n tokens.push(getCSSContent(element, "::after") || "");\n return tokens.join("");\n }\n var kAriaSelectedRoles = [\n "gridcell",\n "option",\n "row",\n "tab",\n "rowheader",\n "columnheader",\n "treeitem"\n ];\n function getAriaSelected(element) {\n if (elementSafeTagName(element) === "OPTION") return element.selected;\n if (kAriaSelectedRoles.includes(getAriaRole(element) || ""))\n return getAriaBoolean(element.getAttribute("aria-selected")) === true;\n return false;\n }\n var kAriaCheckedRoles = [\n "checkbox",\n "menuitemcheckbox",\n "option",\n "radio",\n "switch",\n "menuitemradio",\n "treeitem"\n ];\n function getAriaChecked(element) {\n const result = getChecked(element, true);\n return result === "error" ? false : result;\n }\n function getChecked(element, allowMixed) {\n const tagName = elementSafeTagName(element);\n if (allowMixed && tagName === "INPUT" && element.indeterminate)\n return "mixed";\n if (tagName === "INPUT" && ["checkbox", "radio"].includes(element.type))\n return element.checked;\n if (kAriaCheckedRoles.includes(getAriaRole(element) || "")) {\n const checked = element.getAttribute("aria-checked");\n if (checked === "true") return true;\n if (allowMixed && checked === "mixed") return "mixed";\n return false;\n }\n return "error";\n }\n var kAriaPressedRoles = ["button"];\n function getAriaPressed(element) {\n if (kAriaPressedRoles.includes(getAriaRole(element) || "")) {\n const pressed = element.getAttribute("aria-pressed");\n if (pressed === "true") return true;\n if (pressed === "mixed") return "mixed";\n }\n return false;\n }\n var kAriaExpandedRoles = [\n "application",\n "button",\n "checkbox",\n "combobox",\n "gridcell",\n "link",\n "listbox",\n "menuitem",\n "row",\n "rowheader",\n "tab",\n "treeitem",\n "columnheader",\n "menuitemcheckbox",\n "menuitemradio",\n "rowheader",\n "switch"\n ];\n function getAriaExpanded(element) {\n if (elementSafeTagName(element) === "DETAILS") return element.open;\n if (kAriaExpandedRoles.includes(getAriaRole(element) || "")) {\n const expanded = element.getAttribute("aria-expanded");\n if (expanded === null) return void 0;\n if (expanded === "true") return true;\n return false;\n }\n return void 0;\n }\n var kAriaLevelRoles = ["heading", "listitem", "row", "treeitem"];\n function getAriaLevel(element) {\n const native = { H1: 1, H2: 2, H3: 3, H4: 4, H5: 5, H6: 6 }[elementSafeTagName(element)];\n if (native) return native;\n if (kAriaLevelRoles.includes(getAriaRole(element) || "")) {\n const attr = element.getAttribute("aria-level");\n const value = attr === null ? Number.NaN : Number(attr);\n if (Number.isInteger(value) && value >= 1) return value;\n }\n return 0;\n }\n var kAriaDisabledRoles = [\n "application",\n "button",\n "composite",\n "gridcell",\n "group",\n "input",\n "link",\n "menuitem",\n "scrollbar",\n "separator",\n "tab",\n "checkbox",\n "columnheader",\n "combobox",\n "grid",\n "listbox",\n "menu",\n "menubar",\n "menuitemcheckbox",\n "menuitemradio",\n "option",\n "radio",\n "radiogroup",\n "row",\n "rowheader",\n "searchbox",\n "select",\n "slider",\n "spinbutton",\n "switch",\n "tablist",\n "textbox",\n "toolbar",\n "tree",\n "treegrid",\n "treeitem"\n ];\n function getAriaDisabled(element) {\n return isNativelyDisabled(element) || hasExplicitAriaDisabled(element);\n }\n function isNativelyDisabled(element) {\n const isNativeFormControl = [\n "BUTTON",\n "INPUT",\n "SELECT",\n "TEXTAREA",\n "OPTION",\n "OPTGROUP"\n ].includes(element.tagName);\n return isNativeFormControl && (element.hasAttribute("disabled") || belongsToDisabledFieldSet(element));\n }\n function belongsToDisabledFieldSet(element) {\n const fieldSetElement = element?.closest("FIELDSET[DISABLED]");\n if (!fieldSetElement) return false;\n const legendElement = fieldSetElement.querySelector(":scope > LEGEND");\n return !legendElement || !legendElement.contains(element);\n }\n function hasExplicitAriaDisabled(element, isAncestor = false) {\n if (!element) return false;\n if (isAncestor || kAriaDisabledRoles.includes(getAriaRole(element) || "")) {\n const attribute = (element.getAttribute("aria-disabled") || "").toLowerCase();\n if (attribute === "true") return true;\n if (attribute === "false") return false;\n return hasExplicitAriaDisabled(parentElementOrShadowHost(element), true);\n }\n return false;\n }\n function getAccessibleNameFromAssociatedLabels(labels, options) {\n return [...labels].map(\n (label) => getTextAlternativeInternal(label, {\n ...options,\n embeddedInLabel: { element: label, hidden: isElementHiddenForAria(label) },\n embeddedInNativeTextAlternative: void 0,\n embeddedInLabelledBy: void 0,\n embeddedInDescribedBy: void 0,\n embeddedInTargetElement: void 0\n })\n ).filter((accessibleName) => !!accessibleName).join(" ");\n }\n function receivesPointerEvents(element) {\n const cache = cachePointerEvents;\n let e = element;\n let result;\n const parents = [];\n for (; e; e = parentElementOrShadowHost(e)) {\n const cached = cache.get(e);\n if (cached !== void 0) {\n result = cached;\n break;\n }\n parents.push(e);\n const style = getElementComputedStyle(e);\n if (!style) {\n result = true;\n break;\n }\n const value = style.pointerEvents;\n if (value) {\n result = value !== "none";\n break;\n }\n }\n if (result === void 0) result = true;\n for (const parent of parents) cache.set(parent, result);\n return result;\n }\n var cacheAccessibleName;\n var cacheAccessibleNameHidden;\n var cacheIsHidden;\n var cachePseudoContent;\n var cachePseudoContentBefore;\n var cachePseudoContentAfter;\n var cachePointerEvents;\n var cachesCounter = 0;\n function beginAriaCaches() {\n ++cachesCounter;\n cacheAccessibleName ??= /* @__PURE__ */ new Map();\n cacheAccessibleNameHidden ??= /* @__PURE__ */ new Map();\n cacheIsHidden ??= /* @__PURE__ */ new Map();\n cachePseudoContent ??= /* @__PURE__ */ new Map();\n cachePseudoContentBefore ??= /* @__PURE__ */ new Map();\n cachePseudoContentAfter ??= /* @__PURE__ */ new Map();\n cachePointerEvents ??= /* @__PURE__ */ new Map();\n }\n function endAriaCaches() {\n if (!--cachesCounter) {\n cacheAccessibleName = void 0;\n cacheAccessibleNameHidden = void 0;\n cacheIsHidden = void 0;\n cachePseudoContent = void 0;\n cachePseudoContentBefore = void 0;\n cachePseudoContentAfter = void 0;\n cachePointerEvents = void 0;\n }\n }\n var inputTypeToRole = {\n button: "button",\n checkbox: "checkbox",\n image: "button",\n number: "spinbutton",\n radio: "radio",\n range: "slider",\n reset: "button",\n submit: "button"\n };\n\n // src/browser/ariaTree/yamlUtils.ts\n function yamlEscapeKeyIfNeeded(str) {\n if (!yamlStringNeedsQuotes(str)) return str;\n return `\'` + str.replace(/\'/g, `\'\'`) + `\'`;\n }\n function yamlEscapeValueIfNeeded(str) {\n if (!yamlStringNeedsQuotes(str)) return str;\n return \'"\' + str.replace(/[\\\\"\\x00-\\x1f\\x7f-\\x9f]/g, (c) => {\n switch (c) {\n case "\\\\":\n return "\\\\\\\\";\n case \'"\':\n return \'\\\\"\';\n case "\\b":\n return "\\\\b";\n case "\\f":\n return "\\\\f";\n case "\\n":\n return "\\\\n";\n case "\\r":\n return "\\\\r";\n case "\t":\n return "\\\\t";\n default:\n const code = c.charCodeAt(0);\n return "\\\\x" + code.toString(16).padStart(2, "0");\n }\n }) + \'"\';\n }\n function yamlStringNeedsQuotes(str) {\n if (str.length === 0) return true;\n if (/^\\s|\\s$/.test(str)) return true;\n if (/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f-\\x9f]/.test(str)) return true;\n if (/^-/.test(str)) return true;\n if (/[\\n:](\\s|$)/.test(str)) return true;\n if (/\\s#/.test(str)) return true;\n if (/[\\n\\r]/.test(str)) return true;\n if (/^[&*\\],?!>|@"\'#%]/.test(str)) return true;\n if (/[{}`]/.test(str)) return true;\n if (/^\\[/.test(str)) return true;\n if (!isNaN(Number(str)) || ["y", "n", "yes", "no", "true", "false", "on", "off", "null"].includes(str.toLowerCase()))\n return true;\n return false;\n }\n\n // src/browser/ariaTree/ariaSnapshot.ts\n function generateAndRenderAriaTree(root, counter) {\n const refCounter = counter || { value: 0 };\n root.querySelectorAll("[data-spark-ref]").forEach((el) => {\n el.removeAttribute("data-spark-ref");\n el.removeAttribute("data-spark-role");\n });\n const ariaTree = generateAriaTree(root);\n return renderAriaTree(ariaTree, refCounter);\n }\n var MAX_IFRAME_DEPTH = 5;\n function generateAriaTree(rootElement, iframeDepth = 0) {\n const visited = /* @__PURE__ */ new Set();\n const root = {\n role: "fragment",\n name: "",\n children: [],\n element: rootElement,\n props: {},\n box: box(rootElement),\n receivesPointerEvents: true\n };\n const visit = (ariaNode, node) => {\n if (visited.has(node)) return;\n visited.add(node);\n if (node.nodeType === Node.TEXT_NODE && node.nodeValue) {\n const text = node.nodeValue;\n if (ariaNode.role !== "textbox" && text) ariaNode.children.push(node.nodeValue || "");\n return;\n }\n if (node.nodeType !== Node.ELEMENT_NODE) return;\n const element = node;\n let isVisible = !isElementHiddenForAria(element);\n isVisible = isVisible || isElementVisible(element);\n if (!isVisible) return;\n const ariaChildren = [];\n if (element.hasAttribute("aria-owns")) {\n const ids = element.getAttribute("aria-owns").split(/\\s+/);\n for (const id of ids) {\n const ownedElement = rootElement.ownerDocument.getElementById(id);\n if (ownedElement) ariaChildren.push(ownedElement);\n }\n }\n if (element.nodeName === "IFRAME") {\n if (iframeDepth >= MAX_IFRAME_DEPTH) return;\n const iframe = element;\n try {\n const iframeDoc = iframe.contentDocument;\n if (iframeDoc && iframeDoc.body) {\n iframeDoc.body.querySelectorAll("[data-spark-ref]").forEach((el) => el.removeAttribute("data-spark-ref"));\n const iframeTree = generateAriaTree(iframeDoc.body, iframeDepth + 1);\n for (const child of iframeTree.children) {\n ariaNode.children.push(child);\n }\n return;\n }\n } catch {\n }\n const iframeNode = {\n role: "iframe",\n name: "",\n children: [],\n props: {},\n element,\n box: box(element),\n receivesPointerEvents: true\n };\n ariaNode.children.push(iframeNode);\n return;\n }\n const childAriaNode = toAriaNode(element);\n if (childAriaNode) {\n ariaNode.children.push(childAriaNode);\n }\n processElement(childAriaNode || ariaNode, element, ariaChildren);\n };\n function processElement(ariaNode, element, ariaChildren = []) {\n const display = getElementComputedStyle(element)?.display || "inline";\n const treatAsBlock = display !== "inline" || element.nodeName === "BR" ? " " : "";\n if (treatAsBlock) ariaNode.children.push(treatAsBlock);\n ariaNode.children.push(getCSSContent(element, "::before") || "");\n const assignedNodes = element.nodeName === "SLOT" ? element.assignedNodes() : [];\n if (assignedNodes.length) {\n for (const child of assignedNodes) visit(ariaNode, child);\n } else {\n for (let child = element.firstChild; child; child = child.nextSibling) {\n if (!child.assignedSlot) visit(ariaNode, child);\n }\n if (element.shadowRoot) {\n for (let child = element.shadowRoot.firstChild; child; child = child.nextSibling)\n visit(ariaNode, child);\n }\n }\n for (const child of ariaChildren) visit(ariaNode, child);\n ariaNode.children.push(getCSSContent(element, "::after") || "");\n if (treatAsBlock) ariaNode.children.push(treatAsBlock);\n if (ariaNode.children.length === 1 && ariaNode.name === ariaNode.children[0])\n ariaNode.children = [];\n if (ariaNode.role === "link" && element.hasAttribute("href")) {\n const href = element.getAttribute("href");\n ariaNode.props["url"] = href;\n }\n }\n beginAriaCaches();\n try {\n visit(root, rootElement);\n } finally {\n endAriaCaches();\n }\n normalizeStringChildren(root);\n normalizeGenericRoles(root);\n return root;\n }\n function toAriaNode(element) {\n const role = getAriaRole(element) ?? "generic";\n if (role === "presentation" || role === "none") return null;\n const name = normalizeWhiteSpace(getElementAccessibleName(element, false) || "");\n const pointerEvents = receivesPointerEvents(element);\n const result = {\n role,\n name,\n children: [],\n props: {},\n element,\n box: box(element),\n receivesPointerEvents: pointerEvents\n };\n if (kAriaCheckedRoles.includes(role))\n result.checked = getAriaChecked(element);\n if (kAriaDisabledRoles.includes(role))\n result.disabled = getAriaDisabled(element);\n if (kAriaExpandedRoles.includes(role))\n result.expanded = getAriaExpanded(element);\n if (kAriaLevelRoles.includes(role)) result.level = getAriaLevel(element);\n if (kAriaPressedRoles.includes(role))\n result.pressed = getAriaPressed(element);\n if (kAriaSelectedRoles.includes(role))\n result.selected = getAriaSelected(element);\n if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {\n const nonTextTypes = ["password", "checkbox", "radio", "file"];\n const sensitiveAutocomplete = [\n "cc-number",\n "cc-name",\n "cc-csc",\n "cc-exp",\n "cc-exp-month",\n "cc-exp-year",\n "cc-type",\n "new-password",\n "current-password",\n "one-time-code"\n ];\n const autocomplete = element.getAttribute("autocomplete") || "";\n if (!nonTextTypes.includes(element.type) && !sensitiveAutocomplete.includes(autocomplete)) {\n result.children = [element.value];\n }\n }\n return result;\n }\n function normalizeGenericRoles(node) {\n const normalizeChildren = (node2) => {\n const result = [];\n for (const child of node2.children || []) {\n if (typeof child === "string") {\n result.push(child);\n continue;\n }\n const normalized = normalizeChildren(child);\n result.push(...normalized);\n }\n const removeSelf = node2.role === "generic" && result.length <= 1 && result.every((c) => typeof c !== "string" && nodeReceivesPointerEvents(c));\n if (removeSelf) return result;\n node2.children = result;\n return [node2];\n };\n normalizeChildren(node);\n }\n function normalizeStringChildren(rootA11yNode) {\n const flushChildren = (buffer, normalizedChildren) => {\n if (!buffer.length) return;\n const text = normalizeWhiteSpace(buffer.join(""));\n if (text) normalizedChildren.push(text);\n buffer.length = 0;\n };\n const visit = (ariaNode) => {\n const normalizedChildren = [];\n const buffer = [];\n for (const child of ariaNode.children || []) {\n if (typeof child === "string") {\n buffer.push(child);\n } else {\n flushChildren(buffer, normalizedChildren);\n visit(child);\n normalizedChildren.push(child);\n }\n }\n flushChildren(buffer, normalizedChildren);\n ariaNode.children = normalizedChildren.length ? normalizedChildren : [];\n if (ariaNode.children.length === 1 && ariaNode.children[0] === ariaNode.name)\n ariaNode.children = [];\n };\n visit(rootA11yNode);\n }\n var SOM_CONTAINER_ID = "__spark-som-container";\n var SOM_COLORS = [\n "#e6194b",\n // red\n "#3cb44b",\n // green\n "#4363d8",\n // blue\n "#f58231",\n // orange\n "#911eb4",\n // purple\n "#42d4f4"\n // cyan\n ];\n var SOM_INTERACTIVE_TAGS = /* @__PURE__ */ new Set(["A", "BUTTON", "INPUT", "SELECT", "TEXTAREA", "SUMMARY"]);\n var SOM_INTERACTIVE_ROLES = /* @__PURE__ */ new Set([\n "button",\n "link",\n "textbox",\n "combobox",\n "checkbox",\n "radio",\n "switch",\n "slider",\n "spinbutton",\n "searchbox",\n "option",\n "menuitem",\n "menuitemcheckbox",\n "menuitemradio",\n "tab",\n "treeitem",\n "gridcell",\n "columnheader",\n "rowheader"\n ]);\n function isInteractiveElement(el) {\n if (SOM_INTERACTIVE_TAGS.has(el.tagName)) return true;\n const ce = el.getAttribute("contenteditable");\n if (ce === "true" || ce === "") return true;\n const computedRole = el.getAttribute("data-spark-role");\n if (computedRole && SOM_INTERACTIVE_ROLES.has(computedRole)) return true;\n const rawRole = el.getAttribute("role");\n if (rawRole) {\n const roles = rawRole.split(/\\s+/);\n if (roles.some((r) => SOM_INTERACTIVE_ROLES.has(r))) return true;\n }\n const tabindex = el.getAttribute("tabindex");\n if (tabindex !== null) {\n const tabValue = parseInt(tabindex, 10);\n if (!isNaN(tabValue) && tabValue >= 0 && (!computedRole || computedRole === "generic")) {\n return true;\n }\n }\n return false;\n }\n function applySetOfMarks() {\n removeSetOfMarks();\n if (!document.body) return;\n const container = document.createElement("div");\n container.id = SOM_CONTAINER_ID;\n container.style.cssText = "position:fixed;top:0;left:0;width:0;height:0;pointer-events:none;z-index:2147483647;";\n const elements = document.querySelectorAll("[data-spark-ref]");\n let colorIndex = 0;\n elements.forEach((el) => {\n const ref = el.getAttribute("data-spark-ref");\n if (!ref) return;\n if (!isInteractiveElement(el)) return;\n const rect = el.getBoundingClientRect();\n if (rect.width === 0 && rect.height === 0) return;\n const color = SOM_COLORS[colorIndex % SOM_COLORS.length];\n const absTop = rect.top + window.scrollY;\n const absLeft = rect.left + window.scrollX;\n const outline = document.createElement("div");\n outline.style.cssText = `position:absolute;top:${absTop}px;left:${absLeft}px;width:${rect.width}px;height:${rect.height}px;border:2px solid ${color};box-sizing:border-box;border-radius:2px;`;\n container.appendChild(outline);\n const badge = document.createElement("div");\n badge.textContent = ref;\n badge.style.cssText = `position:absolute;top:${absTop}px;left:${absLeft}px;background:${color};color:#fff;font:bold 11px monospace;padding:1px 3px;border-radius:2px;line-height:1.2;white-space:nowrap;`;\n container.appendChild(badge);\n colorIndex++;\n });\n document.body.appendChild(container);\n }\n function removeSetOfMarks() {\n const existing = document.getElementById(SOM_CONTAINER_ID);\n if (existing) existing.remove();\n }\n function nodeReceivesPointerEvents(ariaNode) {\n return ariaNode.box.visible && ariaNode.receivesPointerEvents;\n }\n function hasPointerCursor(ariaNode) {\n return ariaNode.box.style?.cursor === "pointer";\n }\n function renderAriaTree(root, counter) {\n const lines = [];\n const visit = (ariaNode, _parentAriaNode, indent) => {\n if (typeof ariaNode === "string") {\n const text = yamlEscapeValueIfNeeded(ariaNode);\n if (text) lines.push(indent + "- text: " + text);\n return;\n }\n let key = ariaNode.role;\n if (ariaNode.name) {\n const displayName = ariaNode.name.length > 900 ? ariaNode.name.slice(0, 900) + "..." : ariaNode.name;\n const stringifiedName = JSON.stringify(displayName);\n key += " " + stringifiedName;\n }\n if (ariaNode.checked === "mixed") key += ` [checked=mixed]`;\n if (ariaNode.checked === true) key += ` [checked]`;\n if (ariaNode.disabled) key += ` [disabled]`;\n if (ariaNode.expanded) key += ` [expanded]`;\n if (ariaNode.level) key += ` [level=${ariaNode.level}]`;\n if (ariaNode.pressed === "mixed") key += ` [pressed=mixed]`;\n if (ariaNode.pressed === true) key += ` [pressed]`;\n if (ariaNode.selected === true) key += ` [selected]`;\n if (nodeReceivesPointerEvents(ariaNode)) {\n const ref = "E" + ++counter.value;\n const cursor = hasPointerCursor(ariaNode) ? " [cursor=pointer]" : "";\n key += ` [ref=${ref}]${cursor}`;\n ariaNode.element?.setAttribute("data-spark-ref", ref);\n ariaNode.element?.setAttribute("data-spark-role", ariaNode.role);\n }\n const escapedKey = indent + "- " + yamlEscapeKeyIfNeeded(key);\n const hasProps = !!Object.keys(ariaNode.props).length;\n if (!ariaNode.children.length && !hasProps) {\n lines.push(escapedKey);\n } else if (ariaNode.children.length === 1 && typeof ariaNode.children[0] === "string" && !hasProps) {\n const text = ariaNode.children[0];\n if (text) lines.push(escapedKey + ": " + yamlEscapeValueIfNeeded(text));\n else lines.push(escapedKey);\n } else {\n lines.push(escapedKey + ":");\n for (const [name, value] of Object.entries(ariaNode.props))\n lines.push(indent + " - /" + name + ": " + yamlEscapeValueIfNeeded(value));\n for (const child of ariaNode.children || []) visit(child, ariaNode, indent + " ");\n }\n };\n if (root.role === "fragment") {\n for (const child of root.children || []) visit(child, root, "");\n } else {\n visit(root, null, "");\n }\n return lines.join("\\n");\n }\n return __toCommonJS(ariaSnapshot_exports);\n})();\n\nglobalThis.__sparkAriaTree = __sparkAriaTree;\n'; diff --git a/src/browser/ariaTree/index.ts b/src/browser/ariaTree/index.ts deleted file mode 100644 index 3527cc5f..00000000 --- a/src/browser/ariaTree/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Spark Aria Tree Module - * - * Shared accessibility tree generation for both CLI (Playwright) and Extension consumers. - * Extracted from Playwright's aria snapshot code, stripped to AI-mode only. - * - * Both consumers inject this code into the browser page context: - * - CLI: via page.evaluate() with a bundled script - * - Extension: via content script imports - */ - -export { generateAndRenderAriaTree, applySetOfMarks, removeSetOfMarks } from "./ariaSnapshot.js"; -export type { AriaNode, AriaRole, AriaProps, Box, RefCounter } from "./types.js"; diff --git a/src/cli/config.ts b/src/cli/config.ts deleted file mode 100644 index 3fddcc02..00000000 --- a/src/cli/config.ts +++ /dev/null @@ -1,8 +0,0 @@ -// Re-export shared config system -export { - config, - ConfigManager, - getConfigDefaults, - type SparkConfig, - type SparkConfigResolved, -} from "../config.js"; diff --git a/src/cli/provider.ts b/src/cli/provider.ts deleted file mode 100644 index b9115924..00000000 --- a/src/cli/provider.ts +++ /dev/null @@ -1,2 +0,0 @@ -// Re-export shared provider system -export { createAIProvider, getAIProviderInfo } from "../provider.js"; diff --git a/src/search/index.ts b/src/search/index.ts deleted file mode 100644 index 046edb71..00000000 --- a/src/search/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Search Module - * - * Re-exports the public API for search functionality. - */ - -export { createSearchProvider, type SearchProvider } from "./searchProvider.js"; -export { SearchService } from "./searchService.js"; diff --git a/src/utils/index.ts b/src/utils/index.ts deleted file mode 100644 index 3b9924d1..00000000 --- a/src/utils/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Utils Module - * - * Common utilities and helper functions used throughout the application. - */ - -// Environment utilities -export { getEnv } from "./env.js"; - -// Template utilities -export { buildPromptTemplate } from "./template.js"; - -// TypeScript utility types -export type { AwaitedProperties } from "./types.js";