From 1689694d6517d5f20167c56db3b44bb16ce8ef4e Mon Sep 17 00:00:00 2001
From: Zachary Roth <100426704+zacharyr0th@users.noreply.github.com>
Date: Thu, 16 Jul 2026 11:31:58 -0700
Subject: [PATCH 1/5] feat: capture local product surface and integrations
---
.github/workflows/benchmark.yml | 41 +-
.github/workflows/ci.yml | 123 ++---
.github/workflows/codeql.yml | 15 +-
.github/workflows/live-typed-packs.yml | 25 +-
.github/workflows/live-web-smoke.yml | 25 +-
.github/workflows/metrics.yml | 38 +-
.github/workflows/publish.yml | 59 ++-
.github/workflows/security.yml | 78 ++-
.gitignore | 16 +-
.python-version | 1 +
AGENTS.md | 14 +
README.md | 8 +
bun.lock | 127 +++++
docs/CHANGELOG.md | 2 +-
docs/acquisition.routes.json | 18 +
docs/alternatives.md | 4 +-
docs/corpus.manifest.json | 29 +
docs/launch-assets/README.md | 16 +
docs/launch-assets/logo-app-icon.svg | 11 +
docs/launch-assets/logo-favicon.svg | 10 +
docs/launch-assets/logo-lockup-dark.svg | 21 +
docs/launch-assets/logo-lockup-light.svg | 21 +
.../logo-mark-monochrome-black.svg | 9 +
.../logo-mark-monochrome-white.svg | 9 +
docs/launch-assets/logo-mark-reversed.svg | 10 +
docs/launch-assets/logo-mark.svg | 10 +
docs/launch-assets/logo-square-dark-1024.png | Bin 10841 -> 8307 bytes
docs/launch-assets/logo-square-light-1024.png | Bin 10803 -> 8366 bytes
docs/launch-assets/logo-square-light-400.png | Bin 0 -> 3685 bytes
.../logo-transparent-dark-1024.png | Bin 9261 -> 7684 bytes
.../logo-transparent-light-1024.png | Bin 9530 -> 7692 bytes
docs/scraping-boundary.md | 2 +-
.../v6-launch/assets/01-context-drift.png | Bin 0 -> 94718 bytes
.../v6-launch/assets/02-lockfile-workflow.png | Bin 0 -> 97866 bytes
docs/social/v6-launch/assets/03-sync-diff.png | Bin 0 -> 109773 bytes
.../v6-launch/assets/04-v3-pack-contract.png | Bin 0 -> 117944 bytes
.../social/v6-launch/assets/05-context-ci.png | Bin 0 -> 93388 bytes
.../assets/06-export-agent-context.png | Bin 0 -> 112781 bytes
.../social/v6-launch/assets/contact-sheet.png | Bin 0 -> 303068 bytes
.../v6-launch/generate_terminal_cards.py | 332 ++++++++++++
docs/social/v6-launch/twitter-thread.md | 212 ++++++++
docs/social/v6.1-benchmark/README.md | 39 ++
.../social/v6.1-benchmark/assets/01-cover.png | Bin 0 -> 73755 bytes
.../v6.1-benchmark/assets/02-core-results.png | Bin 0 -> 67040 bytes
.../v6.1-benchmark/assets/03-boundaries.png | Bin 0 -> 86006 bytes
.../assets/04-pdf-isolation.png | Bin 0 -> 85666 bytes
.../v6.1-benchmark/assets/05-integrity.png | Bin 0 -> 91479 bytes
.../v6.1-benchmark/assets/06-evidence.png | Bin 0 -> 71962 bytes
.../v6.1-benchmark/assets/contact-sheet.png | Bin 0 -> 290890 bytes
docs/social/v6.1-benchmark/generate_cards.py | 359 +++++++++++++
docs/sources.md | 7 +
docs/v6-directory-submission-plan.md | 236 +++++++++
docs/v6-directory-todo.md | 42 ++
docs/v6-directory-tracker.csv | 57 ++
docs/v6-github-list-targets.md | 146 ++++++
docs/v6-github-pr-recipes.json | 163 ++++++
docs/v6-hacker-news-plan.md | 100 ++++
docs/v6-sales-pr-automation.md | 161 ++++++
mcp/package.json | 120 +++--
mise.lock | 276 ++++++++++
mise.toml | 44 ++
package.json | 14 +-
plugin/.codex-plugin/plugin.json | 4 +-
plugin/README.md | 8 +
plugin/assets/logo.svg | 11 +
scripts/github_list_prs.py | 270 ++++++++++
src/docpull/__init__.py | 495 +++++++++---------
src/docpull/basis.py | 32 +-
src/docpull/cache/__init__.py | 42 +-
src/docpull/cache/frontier.py | 82 ++-
src/docpull/cache/manager.py | 7 +-
src/docpull/cli.py | 173 ++++--
src/docpull/context_packs/__init__.py | 96 ++--
src/docpull/conversion/__init__.py | 79 ++-
src/docpull/conversion/extractor.py | 20 +-
src/docpull/discovery/__init__.py | 101 +++-
.../discovery/link_extractors/__init__.py | 42 +-
src/docpull/export_formats.py | 27 +
src/docpull/exports.py | 32 +-
src/docpull/graph.py | 118 +++--
src/docpull/http/__init__.py | 41 +-
src/docpull/http/client.py | 67 ++-
src/docpull/local_workflows.py | 57 +-
src/docpull/mcp/__init__.py | 26 +-
src/docpull/mcp/server.py | 60 ++-
src/docpull/mcp/tools.py | 25 +-
src/docpull/metadata_extractor.py | 2 +-
src/docpull/models/__init__.py | 127 +++--
src/docpull/models/events.py | 2 +-
src/docpull/models/run.py | 21 +-
src/docpull/models/schema.py | 9 +
src/docpull/native_integrations.py | 88 ++++
src/docpull/output_contract.py | 9 +-
src/docpull/pack_reader.py | 106 +++-
src/docpull/pack_tools.py | 298 ++++++++---
src/docpull/pipeline/base.py | 4 +
src/docpull/pipeline/steps/__init__.py | 71 ++-
src/docpull/pipeline/steps/convert.py | 54 +-
src/docpull/pipeline/steps/metadata.py | 4 +-
src/docpull/project.py | 25 +-
src/docpull/security/__init__.py | 38 +-
tests/test_ci_policy.py | 32 +-
tests/test_frontier_resume.py | 55 ++
tests/test_http_efficiency.py | 169 ++++++
tests/test_import_efficiency.py | 107 ++++
tests/test_native_integrations.py | 29 +
tests/test_pack_tools.py | 23 +
tests/test_pipeline.py | 20 +
tests/test_surface_contract.py | 32 +-
web/.gitignore | 3 +
web/app/globals.css | 382 ++++++++++++++
web/app/icon.svg | 10 +
web/app/layout.tsx | 56 ++
web/app/llms.txt/route.ts | 33 ++
web/app/manifest.ts | 26 +
web/app/page.tsx | 53 ++
web/app/pricing/page.tsx | 87 +++
web/app/privacy/page.tsx | 94 ++++
web/app/robots.ts | 14 +
web/app/sitemap.ts | 33 ++
web/app/terms/page.tsx | 88 ++++
web/components/LogoMark.tsx | 25 +
web/components/SiteChrome.tsx | 47 ++
web/next.config.ts | 7 +
web/package.json | 25 +
web/public/apple-touch-icon.png | Bin 0 -> 2337 bytes
web/public/favicon.ico | Bin 0 -> 15086 bytes
web/public/favicon.svg | 10 +
web/public/icon-192.png | Bin 0 -> 2294 bytes
web/public/icon-512.png | Bin 0 -> 7430 bytes
web/public/logo-mark.svg | 10 +
web/public/logo.svg | 11 +
web/tsconfig.json | 26 +
133 files changed, 6395 insertions(+), 935 deletions(-)
create mode 100644 .python-version
create mode 100644 AGENTS.md
create mode 100644 docs/acquisition.routes.json
create mode 100644 docs/corpus.manifest.json
create mode 100644 docs/launch-assets/logo-app-icon.svg
create mode 100644 docs/launch-assets/logo-favicon.svg
create mode 100644 docs/launch-assets/logo-lockup-dark.svg
create mode 100644 docs/launch-assets/logo-lockup-light.svg
create mode 100644 docs/launch-assets/logo-mark-monochrome-black.svg
create mode 100644 docs/launch-assets/logo-mark-monochrome-white.svg
create mode 100644 docs/launch-assets/logo-mark-reversed.svg
create mode 100644 docs/launch-assets/logo-mark.svg
create mode 100644 docs/launch-assets/logo-square-light-400.png
create mode 100644 docs/social/v6-launch/assets/01-context-drift.png
create mode 100644 docs/social/v6-launch/assets/02-lockfile-workflow.png
create mode 100644 docs/social/v6-launch/assets/03-sync-diff.png
create mode 100644 docs/social/v6-launch/assets/04-v3-pack-contract.png
create mode 100644 docs/social/v6-launch/assets/05-context-ci.png
create mode 100644 docs/social/v6-launch/assets/06-export-agent-context.png
create mode 100644 docs/social/v6-launch/assets/contact-sheet.png
create mode 100644 docs/social/v6-launch/generate_terminal_cards.py
create mode 100644 docs/social/v6-launch/twitter-thread.md
create mode 100644 docs/social/v6.1-benchmark/README.md
create mode 100644 docs/social/v6.1-benchmark/assets/01-cover.png
create mode 100644 docs/social/v6.1-benchmark/assets/02-core-results.png
create mode 100644 docs/social/v6.1-benchmark/assets/03-boundaries.png
create mode 100644 docs/social/v6.1-benchmark/assets/04-pdf-isolation.png
create mode 100644 docs/social/v6.1-benchmark/assets/05-integrity.png
create mode 100644 docs/social/v6.1-benchmark/assets/06-evidence.png
create mode 100644 docs/social/v6.1-benchmark/assets/contact-sheet.png
create mode 100644 docs/social/v6.1-benchmark/generate_cards.py
create mode 100644 docs/sources.md
create mode 100644 docs/v6-directory-submission-plan.md
create mode 100644 docs/v6-directory-todo.md
create mode 100644 docs/v6-directory-tracker.csv
create mode 100644 docs/v6-github-list-targets.md
create mode 100644 docs/v6-github-pr-recipes.json
create mode 100644 docs/v6-hacker-news-plan.md
create mode 100644 docs/v6-sales-pr-automation.md
create mode 100644 mise.lock
create mode 100644 mise.toml
create mode 100644 plugin/assets/logo.svg
create mode 100644 scripts/github_list_prs.py
create mode 100644 src/docpull/export_formats.py
create mode 100644 src/docpull/models/schema.py
create mode 100644 src/docpull/native_integrations.py
create mode 100644 tests/test_http_efficiency.py
create mode 100644 tests/test_import_efficiency.py
create mode 100644 tests/test_native_integrations.py
create mode 100644 web/.gitignore
create mode 100644 web/app/globals.css
create mode 100644 web/app/icon.svg
create mode 100644 web/app/layout.tsx
create mode 100644 web/app/llms.txt/route.ts
create mode 100644 web/app/manifest.ts
create mode 100644 web/app/page.tsx
create mode 100644 web/app/pricing/page.tsx
create mode 100644 web/app/privacy/page.tsx
create mode 100644 web/app/robots.ts
create mode 100644 web/app/sitemap.ts
create mode 100644 web/app/terms/page.tsx
create mode 100644 web/components/LogoMark.tsx
create mode 100644 web/components/SiteChrome.tsx
create mode 100644 web/next.config.ts
create mode 100644 web/package.json
create mode 100644 web/public/apple-touch-icon.png
create mode 100644 web/public/favicon.ico
create mode 100644 web/public/favicon.svg
create mode 100644 web/public/icon-192.png
create mode 100644 web/public/icon-512.png
create mode 100644 web/public/logo-mark.svg
create mode 100644 web/public/logo.svg
create mode 100644 web/tsconfig.json
diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml
index bde8701..15082cf 100644
--- a/.github/workflows/benchmark.yml
+++ b/.github/workflows/benchmark.yml
@@ -6,9 +6,6 @@ name: Benchmark
# or if the injected duplicate fraction isn't detected.
on:
- schedule:
- # 04:17 UTC weekly Wednesday — enough signal without daily Actions spend.
- - cron: "17 4 * * 3"
workflow_dispatch:
permissions:
@@ -18,6 +15,10 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
+env:
+ MISE_LOCKED: "1"
+ UV_VERSION: "0.11.6"
+
jobs:
benchmark:
if: github.event_name != 'schedule' || github.event.schedule == '17 4 * * 3'
@@ -29,21 +30,22 @@ jobs:
with:
persist-credentials: false
- - name: Set up Python
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1
+ - uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db
with:
- python-version: "3.11"
+ version: 2026.7.1
+ install: true
+ cache: true
+ - name: Install uv
+ run: python -m pip install "uv==$UV_VERSION"
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- pip install -e ".[dev]"
+ - name: Sync dependencies
+ run: uv sync --locked --dev
- name: Run 10k-page benchmark
env:
DOCPULL_BENCHMARK_10K: "1"
run: |
- PYTHONPATH=src python -m pytest -v -s tests/benchmarks/test_10k_pages.py \
+ uv run --locked python -m pytest -v -s tests/benchmarks/test_10k_pages.py \
| tee benchmark.log
- name: Surface report in summary
@@ -74,19 +76,20 @@ jobs:
with:
persist-credentials: false
- - name: Set up Python
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1
+ - uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db
with:
- python-version: "3.11"
+ version: 2026.7.1
+ install: true
+ cache: true
+ - name: Install uv
+ run: python -m pip install "uv==$UV_VERSION"
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- pip install -e ".[dev]"
+ - name: Sync dependencies
+ run: uv sync --locked --dev
- name: Run public contract smoke tests
run: |
- PYTHONPATH=src python -m pytest -q \
+ uv run --locked python -m pytest -q \
tests/test_surface_contract.py \
tests/test_public_feature_smoke.py \
tests/test_output_contract.py \
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 0d1b0dc..726744b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -2,10 +2,6 @@ name: CI
on:
workflow_dispatch:
- pull_request:
- push:
- branches:
- - main
permissions:
contents: read
@@ -14,61 +10,74 @@ concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
+env:
+ MISE_LOCKED: "1"
+ UV_VERSION: "0.11.6"
+
jobs:
metrics-fresh:
runs-on: ubuntu-24.04
+ timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
persist-credentials: false
+ - uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db
+ with:
+ version: 2026.7.1
+ install: true
+ cache: true
+ - name: Install uv
+ run: python -m pip install "uv==$UV_VERSION"
+
- name: Check metrics freshness
env:
METRICS_MAX_AGE_HOURS: "168"
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
- python .github/scripts/check_metrics_fresh.py || {
+ uv run --locked python .github/scripts/check_metrics_fresh.py || {
echo "::warning::Metrics are stale; run the scheduled Update metrics workflow after merge."
}
else
- python .github/scripts/check_metrics_fresh.py
+ uv run --locked python .github/scripts/check_metrics_fresh.py
fi
test:
runs-on: ubuntu-24.04
+ timeout-minutes: 30
strategy:
fail-fast: false
matrix:
- python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
+ python-version: ["3.10.20", "3.11.15", "3.12.13", "3.13.14", "3.14.6"]
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
persist-credentials: false
- - name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1
+ - uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db
with:
- python-version: ${{ matrix.python-version }}
- cache: pip
- cache-dependency-path: pyproject.toml
+ version: 2026.7.1
+ install: true
+ cache: true
+ - name: Install uv
+ run: python -m pip install "uv==$UV_VERSION"
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- pip install -e ".[all,dev]"
+ - name: Sync dependencies
+ run: uv sync --locked --all-extras --dev
- name: Run tests
- if: matrix.python-version != '3.11'
- run: python -m pytest -q
+ if: matrix.python-version != '3.11.15'
+ run: uv run --locked --all-extras python -m pytest -q
- name: Run tests with coverage
- if: matrix.python-version == '3.11'
- run: python -m pytest --cov=docpull --cov-report=xml --cov-report=term -q
+ if: matrix.python-version == '3.11.15'
+ run: uv run --locked --all-extras python -m pytest --cov=docpull --cov-report=xml --cov-report=term -q
- name: Upload coverage XML
- if: matrix.python-version == '3.11'
+ if: matrix.python-version == '3.11.15'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: coverage-xml
@@ -76,89 +85,85 @@ jobs:
lint:
runs-on: ubuntu-24.04
+ timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
persist-credentials: false
- - name: Set up Python
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1
+ - uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db
with:
- python-version: "3.11"
- cache: pip
- cache-dependency-path: pyproject.toml
+ version: 2026.7.1
+ install: true
+ cache: true
+ - name: Install uv
+ run: python -m pip install "uv==$UV_VERSION"
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- pip install -e ".[all,dev]"
+ - name: Sync dependencies
+ run: uv sync --locked --all-extras --dev
- name: Check generated release metadata
- run: python scripts/sync_release_metadata.py --check
+ run: uv run --locked python scripts/sync_release_metadata.py --check
- name: Run ruff
- run: python -m ruff check .
+ run: uv run --locked python -m ruff check .
- name: Check formatting
- run: python -m ruff format --check .
+ run: uv run --locked python -m ruff format --check .
- name: Run pre-commit
- run: python -m pre_commit run --all-files --show-diff-on-failure
+ run: uv run --locked python -m pre_commit run --all-files --show-diff-on-failure
typecheck:
runs-on: ubuntu-24.04
+ timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
persist-credentials: false
- - name: Set up Python
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1
+ - uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db
with:
- python-version: "3.11"
- cache: pip
- cache-dependency-path: pyproject.toml
+ version: 2026.7.1
+ install: true
+ cache: true
+ - name: Install uv
+ run: python -m pip install "uv==$UV_VERSION"
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- pip install -e ".[all,dev]"
+ - name: Sync dependencies
+ run: uv sync --locked --all-extras --dev
- name: Run mypy
- run: python -m mypy src
+ run: uv run --locked python -m mypy src
package:
runs-on: ubuntu-24.04
+ timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
persist-credentials: false
- - name: Set up Python
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1
+ - uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db
with:
- python-version: "3.11"
- cache: pip
- cache-dependency-path: |
- pyproject.toml
- requirements-release.txt
-
- - name: Install pinned release tooling
- run: python -m pip install -r requirements-release.txt
+ version: 2026.7.1
+ install: true
+ cache: true
+ - name: Install uv
+ run: python -m pip install "uv==$UV_VERSION"
- name: Build wheel and sdist
- run: python scripts/build_release.py --verify-reproducible
+ run: uv run --locked --with-requirements requirements-release.txt python scripts/build_release.py --verify-reproducible
- name: Verify wheel and sdist metadata
- run: python -m twine check dist/*
+ run: uv run --locked --with-requirements requirements-release.txt python -m twine check dist/*
- name: Smoke install built wheel
run: |
- python -m venv .pkg-smoke
- .pkg-smoke/bin/python -m pip install --upgrade pip
- .pkg-smoke/bin/python -m pip install dist/*.whl
+ uv venv .pkg-smoke
+ uv pip install --python .pkg-smoke/bin/python dist/*.whl
.pkg-smoke/bin/docpull --version
.pkg-smoke/bin/python -c "import docpull; print(docpull.__version__)"
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 4d8c191..d6770f0 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -1,13 +1,10 @@
name: CodeQL
+env:
+ MISE_LOCKED: "1"
+
on:
workflow_dispatch:
- pull_request:
- push:
- branches:
- - main
- schedule:
- - cron: "38 6 * * 1"
permissions:
actions: read
@@ -22,6 +19,7 @@ jobs:
analyze:
name: analyze (${{ matrix.language }})
runs-on: ubuntu-24.04
+ timeout-minutes: 30
strategy:
fail-fast: false
matrix:
@@ -36,6 +34,11 @@ jobs:
with:
persist-credentials: false
+ - uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db
+ with:
+ version: 2026.7.1
+ install: true
+ cache: true
- name: Initialize CodeQL
uses: github/codeql-action/init@b22c66273205240d86582638b860f9b25772b4d3
with:
diff --git a/.github/workflows/live-typed-packs.yml b/.github/workflows/live-typed-packs.yml
index 55816a3..7d1ed3f 100644
--- a/.github/workflows/live-typed-packs.yml
+++ b/.github/workflows/live-typed-packs.yml
@@ -2,8 +2,6 @@ name: Live Typed Pack Smoke
on:
workflow_dispatch:
- schedule:
- - cron: "17 11 * * *"
permissions:
contents: read
@@ -12,6 +10,10 @@ concurrency:
group: live-typed-packs
cancel-in-progress: false
+env:
+ MISE_LOCKED: "1"
+ UV_VERSION: "0.11.6"
+
jobs:
live-typed-packs:
runs-on: ubuntu-24.04
@@ -22,17 +24,16 @@ jobs:
with:
persist-credentials: false
- - name: Set up Python
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1
+ - uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db
with:
- python-version: "3.11"
- cache: pip
- cache-dependency-path: pyproject.toml
+ version: 2026.7.1
+ install: true
+ cache: true
+ - name: Install uv
+ run: python -m pip install "uv==$UV_VERSION"
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- pip install -e ".[dev]"
+ - name: Sync dependencies
+ run: uv sync --locked --dev
- name: Run free live typed-pack smokes
env:
@@ -40,7 +41,7 @@ jobs:
run: |
set +e
mkdir -p live-reports
- python -m pytest tests/test_typed_knowledge_packs.py::test_live_typed_pack_smokes -q \
+ uv run --locked python -m pytest tests/test_typed_knowledge_packs.py::test_live_typed_pack_smokes -q \
| tee live-reports/live-typed-packs.log
status=${PIPESTATUS[0]}
python - "$status" <<'PY'
diff --git a/.github/workflows/live-web-smoke.yml b/.github/workflows/live-web-smoke.yml
index 57ac2a3..cb3a6af 100644
--- a/.github/workflows/live-web-smoke.yml
+++ b/.github/workflows/live-web-smoke.yml
@@ -2,8 +2,6 @@ name: Live Web Smoke
on:
workflow_dispatch:
- schedule:
- - cron: "43 10 * * *"
permissions:
contents: read
@@ -12,6 +10,10 @@ concurrency:
group: live-web-smoke
cancel-in-progress: false
+env:
+ MISE_LOCKED: "1"
+ UV_VERSION: "0.11.6"
+
jobs:
live-web-smoke:
runs-on: ubuntu-24.04
@@ -22,17 +24,16 @@ jobs:
with:
persist-credentials: false
- - name: Set up Python
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1
+ - uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db
with:
- python-version: "3.11"
- cache: pip
- cache-dependency-path: pyproject.toml
+ version: 2026.7.1
+ install: true
+ cache: true
+ - name: Install uv
+ run: python -m pip install "uv==$UV_VERSION"
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- pip install -e ".[dev]"
+ - name: Sync dependencies
+ run: uv sync --locked --dev
- name: Run free live web smokes
env:
@@ -40,7 +41,7 @@ jobs:
run: |
set +e
mkdir -p live-reports
- python -m pytest tests/test_live_web_smoke.py -q | tee live-reports/live-web-smoke.log
+ uv run --locked python -m pytest tests/test_live_web_smoke.py -q | tee live-reports/live-web-smoke.log
status=${PIPESTATUS[0]}
python - "$status" <<'PY'
import json
diff --git a/.github/workflows/metrics.yml b/.github/workflows/metrics.yml
index 4e571db..19e9d59 100644
--- a/.github/workflows/metrics.yml
+++ b/.github/workflows/metrics.yml
@@ -1,5 +1,8 @@
name: Update metrics
+env:
+ MISE_LOCKED: "1"
+
# Refreshes METRICS.md and the README downloads chart from PyPI + GitHub APIs.
#
# Signals:
@@ -9,8 +12,8 @@ name: Update metrics
# - GitHub traffic (clones, views, referrers, paths) — last 14 days.
#
# Plugin install proxy: `/plugin marketplace add raintree-technology/docpull`
-# is a git clone under the hood. Weekly clone counts are enough for trend
-# tracking without daily Actions spend.
+# is a git clone under the hood. Manual clone-count refreshes are enough for
+# trend tracking while the external metrics APIs are unreliable.
#
# Why a workflow instead of an external dashboard:
# - Single source of truth committed in-repo (no external service to babysit).
@@ -25,9 +28,6 @@ name: Update metrics
# `METRICS_TOKEN`. The workflow falls back to GITHUB_TOKEN if absent.
on:
- schedule:
- # 09:12 UTC weekly Monday (off-hour to dodge top-of-hour Actions spikes).
- - cron: "12 9 * * 1"
workflow_dispatch:
permissions:
@@ -48,29 +48,41 @@ jobs:
github.event_name == 'schedule' ||
github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
runs-on: ubuntu-24.04
+ timeout-minutes: 30
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
persist-credentials: false
ref: ${{ github.event.repository.default_branch }}
- - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1
+ - uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db
with:
- python-version: "3.11"
-
+ version: 2026.7.1
+ install: true
+ cache: true
- name: Refresh metrics artifacts
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
METRICS_TOKEN: ${{ secrets.METRICS_TOKEN }}
run: |
- if [ -n "${METRICS_TOKEN:-}" ] && GH_TOKEN="$METRICS_TOKEN" gh api "repos/${GITHUB_REPOSITORY}" >/dev/null 2>&1; then
- export GH_TOKEN="$METRICS_TOKEN"
- else
- if [ -n "${METRICS_TOKEN:-}" ]; then
+ metrics_token="${METRICS_TOKEN:-}"
+ use_metrics_token=false
+ if [ -n "$metrics_token" ]; then
+ printf -v GH_TOKEN '%s' "$metrics_token"
+ export GH_TOKEN
+ if gh api "repos/${GITHUB_REPOSITORY}" >/dev/null 2>&1; then
+ use_metrics_token=true
+ fi
+ fi
+
+ if [ "$use_metrics_token" != true ]; then
+ if [ -n "$metrics_token" ]; then
echo "::warning::METRICS_TOKEN is present but failed GitHub API validation; falling back to GITHUB_TOKEN."
fi
- export GH_TOKEN="$GITHUB_TOKEN"
+ printf -v GH_TOKEN '%s' "$GITHUB_TOKEN"
+ export GH_TOKEN
fi
+ unset metrics_token use_metrics_token
python .github/scripts/update_metrics.py
- name: Check generated metrics freshness
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 054f2e3..bffe11d 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -30,9 +30,14 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
+env:
+ MISE_LOCKED: "1"
+ UV_VERSION: "0.11.6"
+
jobs:
build:
runs-on: ubuntu-24.04
+ timeout-minutes: 30
outputs:
version: ${{ steps.meta.outputs.version }}
steps:
@@ -40,9 +45,13 @@ jobs:
with:
persist-credentials: false
- - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1
+ - uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db
with:
- python-version: "3.11"
+ version: 2026.7.1
+ install: true
+ cache: true
+ - name: Install uv
+ run: python -m pip install "uv==$UV_VERSION"
- name: Read pyproject.toml version (and verify tag match on tag push)
id: meta
@@ -74,17 +83,14 @@ jobs:
fi
echo "version=$PROJECT_VERSION" >> "$GITHUB_OUTPUT"
- - name: Install release build dependencies
+ - name: Build distributions
run: |
# Pinned (see requirements-release.txt) so compromised *latest*
# release tooling cannot be auto-pulled into the wheel-building job.
- python -m pip install -r requirements-release.txt
-
- - name: Build distributions
- run: python scripts/build_release.py --verify-reproducible
+ uv run --locked --with-requirements requirements-release.txt python scripts/build_release.py --verify-reproducible
- name: Verify wheel and sdist
- run: python -m twine check dist/*
+ run: uv run --locked --with-requirements requirements-release.txt python -m twine check dist/*
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
@@ -102,18 +108,16 @@ jobs:
with:
persist-credentials: false
- - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1
+ - uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db
with:
- python-version: "3.11"
+ version: 2026.7.1
+ install: true
+ cache: true
+ - name: Install uv
+ run: python -m pip install "uv==$UV_VERSION"
- - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6
- with:
- bun-version: "1.3.11"
-
- - name: Install release gate dependencies
- run: |
- python -m pip install -r requirements-release.txt
- pip install --no-build-isolation -e ".[all,dev]"
+ - name: Sync release gate dependencies
+ run: uv sync --locked --all-extras --dev
- name: Install local render runtime
run: |
@@ -122,14 +126,14 @@ jobs:
agent-browser --version
- name: Check generated release metadata
- run: python scripts/sync_release_metadata.py --check
+ run: uv run --locked python scripts/sync_release_metadata.py --check
- name: Run Bandit
- run: python -m bandit -q -c pyproject.toml -r src scripts
+ run: uv run --locked python -m bandit -q -c pyproject.toml -r src scripts
- name: Run A+ real-feature smoke
run: |
- python scripts/real_feature_smoke.py \
+ uv run --locked python scripts/real_feature_smoke.py \
--json \
--full-mcp \
--strict-ci \
@@ -139,7 +143,7 @@ jobs:
- name: Run A+ release scorecard
run: |
- python scripts/release_a_plus_check.py \
+ uv run --locked python scripts/release_a_plus_check.py \
--strict \
--output-dir "$RUNNER_TEMP/release-readiness" \
--smoke-report "$RUNNER_TEMP/release-readiness/real-feature-smoke/real_feature_smoke.report.json"
@@ -151,9 +155,8 @@ jobs:
- name: Smoke install built wheel
run: |
- python -m venv .release-smoke
- .release-smoke/bin/python -m pip install --upgrade pip
- .release-smoke/bin/python -m pip install dist/*.whl
+ uv venv .release-smoke
+ uv pip install --python .release-smoke/bin/python dist/*.whl
.release-smoke/bin/docpull --version
.release-smoke/bin/python -c "import docpull; print(docpull.__version__)"
@@ -168,6 +171,7 @@ jobs:
publish:
needs: [build, release-gates]
runs-on: ubuntu-24.04
+ timeout-minutes: 30
environment:
name: pypi
url: https://pypi.org/project/docpull/
@@ -190,6 +194,11 @@ jobs:
persist-credentials: false
if: github.event_name == 'push' && github.ref_type == 'tag'
+ - uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db
+ with:
+ version: 2026.7.1
+ install: true
+ cache: true
- name: Create GitHub release
if: github.event_name == 'push' && github.ref_type == 'tag'
env:
diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml
index 1f1191e..e976d47 100644
--- a/.github/workflows/security.yml
+++ b/.github/workflows/security.yml
@@ -2,10 +2,6 @@ name: Security
on:
workflow_dispatch:
- pull_request:
- push:
- branches:
- - main
permissions:
contents: read
@@ -14,9 +10,14 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
+env:
+ MISE_LOCKED: "1"
+ UV_VERSION: "0.11.6"
+
jobs:
secret-scan:
runs-on: ubuntu-24.04
+ timeout-minutes: 30
steps:
- name: Checkout full history
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
@@ -24,6 +25,11 @@ jobs:
persist-credentials: false
fetch-depth: 0
+ - uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db
+ with:
+ version: 2026.7.1
+ install: true
+ cache: true
- name: Run Gitleaks
# Use the MIT-licensed gitleaks CLI rather than gitleaks-action@v2,
# which requires a paid GITLEAKS_LICENSE secret for organization repos.
@@ -35,33 +41,36 @@ jobs:
python-security:
runs-on: ubuntu-24.04
+ timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
persist-credentials: false
- - name: Set up Python
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1
+ - uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db
with:
- python-version: "3.11"
+ version: 2026.7.1
+ install: true
+ cache: true
+ - name: Install uv
+ run: python -m pip install "uv==$UV_VERSION"
- - name: Install Python dependencies
- run: |
- python -m pip install --upgrade pip setuptools==83.0.0
- pip install -e ".[dev]"
+ - name: Sync Python dependencies
+ run: uv sync --locked --dev
- name: Audit Python dependencies
- run: python -m pip_audit
+ run: uv run --locked python -m pip_audit
- name: Run Bandit
- run: python -m bandit -q -c pyproject.toml -r src scripts
+ run: uv run --locked python -m bandit -q -c pyproject.toml -r src scripts
- name: Run Python security regression tests
- run: PYTHONPATH=src python -m pytest -q tests/test_security_hardening.py tests/test_discovery.py tests/test_integration.py
+ run: uv run --locked python -m pytest -q tests/test_security_hardening.py tests/test_discovery.py tests/test_integration.py
mcp-security:
runs-on: ubuntu-24.04
+ timeout-minutes: 30
defaults:
run:
working-directory: mcp
@@ -71,13 +80,13 @@ jobs:
with:
persist-credentials: false
- - name: Set up Bun
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6
+ - uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db
with:
- bun-version: "1.3.11"
-
+ version: 2026.7.1
+ install: true
+ cache: true
- name: Install MCP dependencies
- run: bun install --frozen-lockfile
+ run: mise run setup
- name: Audit MCP dependencies
run: bun audit
@@ -86,4 +95,33 @@ jobs:
run: bun test
- name: Typecheck MCP
- run: bun run typecheck
+ run: mise run typecheck
+
+ web-security:
+ runs-on: ubuntu-24.04
+ timeout-minutes: 30
+ defaults:
+ run:
+ working-directory: web
+ steps:
+ - name: Checkout
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
+ with:
+ persist-credentials: false
+
+ - uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db
+ with:
+ version: 2026.7.1
+ install: true
+ cache: true
+ - name: Install web dependencies
+ run: mise run setup
+
+ - name: Audit web dependencies
+ run: bun audit
+
+ - name: Typecheck web app
+ run: mise run typecheck
+
+ - name: Build web app
+ run: mise x -- bun run build
diff --git a/.gitignore b/.gitignore
index a40bf3f..0156e0e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -83,9 +83,6 @@ target/
profile_default/
ipython_config.py
-# pyenv
-.python-version
-
# pipenv
Pipfile.lock
@@ -195,9 +192,9 @@ QUALITY_IMPROVEMENTS.md
test_fetch.py
test_error_handling.py
-# Playwright
-.playwright/
-playwright/.auth/
+# Browser automation artifacts
+.browser/
+agent-browser/.auth/
trace.zip
screenshots/
@@ -216,3 +213,10 @@ screenshots/
.agents/
competitors/
docs/internal/
+
+# mise local overrides
+mise.local.toml
+mise.*.local.toml
+mise.local.lock
+mise.*.local.lock
+.mise/
diff --git a/.python-version b/.python-version
new file mode 100644
index 0000000..28d9a01
--- /dev/null
+++ b/.python-version
@@ -0,0 +1 @@
+3.12.13
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..142dcf5
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,14 @@
+# DocPull Agent Instructions
+
+DocPull is the open-source context dependency manager for AI agents. Its core
+contract is local-first, browser-free by default, reproducible, cited, and
+budget guarded.
+
+- Preserve CLI, Python SDK, MCP, and artifact-contract compatibility.
+- Do not silently enable browser or paid/cloud rendering. Those paths require
+ explicit user configuration and budgets.
+- Respect robots, source rights, provenance, and existing cache/lock semantics.
+- Never store credentials or fetched private content in fixtures or reports.
+- Use uv for Python work and Bun 1.3.11/Node 24 for the web and MCP packages.
+- Run the focused pytest suite while iterating and `bun run validate:full` from
+ the root for repository-wide changes.
diff --git a/README.md b/README.md
index 5e96060..d980a3b 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,11 @@
+
+
+
+
# docpull
**Context dependencies for AI agents. Browser-free by default.**
diff --git a/bun.lock b/bun.lock
index 39021d5..4a0ed15 100644
--- a/bun.lock
+++ b/bun.lock
@@ -23,25 +23,118 @@
"typescript": "^6.0.3",
},
},
+ "web": {
+ "name": "docpull-web",
+ "version": "1.0.0",
+ "dependencies": {
+ "next": "^16.2.9",
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0",
+ },
+ "devDependencies": {
+ "@types/node": "^25.9.1",
+ "@types/react": "^19",
+ "@types/react-dom": "^19",
+ "typescript": "^6.0.3",
+ },
+ },
},
"overrides": {
"postcss": "^8.5.10",
},
"packages": {
+ "@emnapi/runtime": ["@emnapi/runtime@1.11.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA=="],
+
"@hono/node-server": ["@hono/node-server@1.19.14", "", { "peerDependencies": { "hono": "^4" } }, "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw=="],
+ "@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="],
+
+ "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="],
+
+ "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.4" }, "os": "darwin", "cpu": "x64" }, "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw=="],
+
+ "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g=="],
+
+ "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg=="],
+
+ "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.4", "", { "os": "linux", "cpu": "arm" }, "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A=="],
+
+ "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw=="],
+
+ "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA=="],
+
+ "@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.2.4", "", { "os": "linux", "cpu": "none" }, "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA=="],
+
+ "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ=="],
+
+ "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw=="],
+
+ "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw=="],
+
+ "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg=="],
+
+ "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.4" }, "os": "linux", "cpu": "arm" }, "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw=="],
+
+ "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg=="],
+
+ "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.4" }, "os": "linux", "cpu": "ppc64" }, "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA=="],
+
+ "@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.2.4" }, "os": "linux", "cpu": "none" }, "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw=="],
+
+ "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.4" }, "os": "linux", "cpu": "s390x" }, "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg=="],
+
+ "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ=="],
+
+ "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg=="],
+
+ "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q=="],
+
+ "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.5", "", { "dependencies": { "@emnapi/runtime": "^1.7.0" }, "cpu": "none" }, "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw=="],
+
+ "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g=="],
+
+ "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg=="],
+
+ "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="],
+
"@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.29.0", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ=="],
+ "@next/env": ["@next/env@16.2.10", "", {}, "sha512-zLPxg9M0MEHmygpj5OuxjQ+vHMiy/K7cSp74G8ecYolmgUWw0RwN02tF56npup/+qaI8JB97hQgS/r2Hb6QwVA=="],
+
+ "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.2.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-v9IdJCa0H0mbo+8z5zwUpOk1Vj7RjkcI5uNYf5Ws1y6szf/p3Mzl9hLaST8SCt6L9h8NGnruZcd2+o0NTNwDhA=="],
+
+ "@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.2.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-17IS0jJRViROGmA9uGdNR8VPJpfbnaVG7E9qhso5jDLkmyd0lSDORWxbcKINzcFqzZqGwGtMSnrFRxBpuUYjLQ=="],
+
+ "@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@16.2.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-GRQRsRtuciNJvB54AvvuQTiq0oZtFwa1owQqtZD8wwnGpM2L39MV22kpI72YSXLKIyY40LC66EiLFv4PiicXxg=="],
+
+ "@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@16.2.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-zkN9MQYS7UQBro+FnISUq1itaQjXI9xqISzuQ+2bc921NcJ1x4yPCqrn77tVN6/dOOXaaWVX3k6/bR07pPwK+A=="],
+
+ "@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@16.2.10", "", { "os": "linux", "cpu": "x64" }, "sha512-iCVJnwvrPYECvA6WM/7+oo+OiTvedIKLxtCLAZP4xZR3nXa1zmzZyLPbYCmWvpd4CvMYF1EMTafd0ii3DygLvA=="],
+
+ "@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@16.2.10", "", { "os": "linux", "cpu": "x64" }, "sha512-ov2g4H0dHY9bPoOU83m91hWT7Iq5qy13bUnyyshLU3HGR1Ownn0X9QpmDPc5iIUaahTp7f7LeGAhV4DSFtackw=="],
+
+ "@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@16.2.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-DwAnhLX76HQiFFQNgWlcK+JzlnD1rZ+UK/WY0ZMI/deXpvgnesjNYrqcfo1JzBuz4Kf7o3brIBL0glI1junatA=="],
+
+ "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.2.10", "", { "os": "win32", "cpu": "x64" }, "sha512-0JXq3b85Jk9Jg4ntLUbXSPvoDw3gpZou7twuKdoFG2jOw635v7+IiXfTaa0TxVMyx78pUjnrVYwLgjKfX4e6/A=="],
+
+ "@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="],
+
"@types/node": ["@types/node@25.9.4", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-dszCsrKb5U7ZsVZBWiHFklTloVl0mSEnWH/iZXfZUlI4rzCUnsvGmgqfuVRHL54ugE7/wRuxEIXRa2iMZ+BG6g=="],
"@types/pg": ["@types/pg@8.20.0", "", { "dependencies": { "@types/node": "*", "pg-protocol": "*", "pg-types": "^2.2.0" } }, "sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow=="],
+ "@types/react": ["@types/react@19.2.17", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw=="],
+
+ "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
+
"accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
"ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="],
"ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="],
+ "baseline-browser-mapping": ["baseline-browser-mapping@2.10.41", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-WwS7MHhqGHHlaVsqRZnhvCEMS0owDX+SxRlve7JkuH7My1Ara3ZriTmCQupPfYjxMZ8I/tgxtJYr2t7taHaH4A=="],
+
"body-parser": ["body-parser@2.3.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^2.0.0", "debug": "^4.4.3", "http-errors": "^2.0.1", "iconv-lite": "^0.7.2", "on-finished": "^2.4.1", "qs": "^6.15.2", "raw-body": "^3.0.2", "type-is": "^2.1.0" } }, "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw=="],
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
@@ -50,6 +143,10 @@
"call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
+ "caniuse-lite": ["caniuse-lite@1.0.30001800", "", {}, "sha512-MMHtuAz9Ys840zAY5F4k6fV5GaivZ9sPk+nz0mY+GYVzRBnYkN0mpqkSR92oWRQ19yQWo4HvBV/FnC16AJX8MA=="],
+
+ "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="],
+
"content-disposition": ["content-disposition@1.1.0", "", {}, "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g=="],
"content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
@@ -62,12 +159,18 @@
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
+ "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
+
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
"depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
+ "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
+
"docpull-mcp-lab": ["docpull-mcp-lab@workspace:mcp"],
+ "docpull-web": ["docpull-web@workspace:web"],
+
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
@@ -148,8 +251,12 @@
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
+ "nanoid": ["nanoid@3.3.15", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA=="],
+
"negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
+ "next": ["next@16.2.10", "", { "dependencies": { "@next/env": "16.2.10", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.2.10", "@next/swc-darwin-x64": "16.2.10", "@next/swc-linux-arm64-gnu": "16.2.10", "@next/swc-linux-arm64-musl": "16.2.10", "@next/swc-linux-x64-gnu": "16.2.10", "@next/swc-linux-x64-musl": "16.2.10", "@next/swc-win32-arm64-msvc": "16.2.10", "@next/swc-win32-x64-msvc": "16.2.10", "sharp": "^0.34.5" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-2som5AVXb3kE6Yjine3/mNbBayYF58eguBWIVVUdr1y/L426xyVEgYxgBG+1QC34P2x5E+tcDup6XkuOAX3dCA=="],
+
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
@@ -182,8 +289,12 @@
"pgpass": ["pgpass@1.0.5", "", { "dependencies": { "split2": "^4.1.0" } }, "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug=="],
+ "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
+
"pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="],
+ "postcss": ["postcss@8.5.16", "", { "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg=="],
+
"postgres-array": ["postgres-array@2.0.0", "", {}, "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="],
"postgres-bytea": ["postgres-bytea@1.0.1", "", {}, "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ=="],
@@ -200,18 +311,28 @@
"raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="],
+ "react": ["react@19.2.7", "", {}, "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ=="],
+
+ "react-dom": ["react-dom@19.2.7", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.7" } }, "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ=="],
+
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
+ "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
+
+ "semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
+
"send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="],
"serve-static": ["serve-static@2.2.1", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw=="],
"setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
+ "sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="],
+
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
@@ -224,12 +345,18 @@
"side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
+ "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
+
"split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="],
"statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
+ "styled-jsx": ["styled-jsx@5.1.6", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" } }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="],
+
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
+ "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
+
"type-is": ["type-is@2.1.0", "", { "dependencies": { "content-type": "^2.0.0", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA=="],
"typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="],
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index 9f8a2c5..ea6f742 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -127,7 +127,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
`CIThresholds` through the root Python SDK contract.
- Remove provider and observability extras from the public package extras;
internal experiments that need those SDKs should install them directly.
-- Remove the unreleased Playwright renderer runtime and keep `agent-browser` as
+- Remove the unreleased browser renderer runtime and keep `agent-browser` as
the sole local browser-rendering contract for local, Vercel, and E2B paths.
- Make the `sec-filing` profile use the extractor ensemble so base installs
fall back to the built-in extractor when optional Trafilatura is unavailable.
diff --git a/docs/acquisition.routes.json b/docs/acquisition.routes.json
new file mode 100644
index 0000000..68e8441
--- /dev/null
+++ b/docs/acquisition.routes.json
@@ -0,0 +1,18 @@
+{
+ "schema_version": 3,
+ "generated_at": "2026-07-15T04:21:53.366286+00:00",
+ "output_contract_version": 3,
+ "routes": [
+ {
+ "route": "local-fetch",
+ "output_format": "markdown",
+ "fetched_count": 0,
+ "record_count": 0,
+ "domain_count": 0,
+ "skip_counts": {
+ "robots_disallowed": 0
+ }
+ }
+ ],
+ "domains": {}
+}
diff --git a/docs/alternatives.md b/docs/alternatives.md
index 2d52915..f57d3d3 100644
--- a/docs/alternatives.md
+++ b/docs/alternatives.md
@@ -18,7 +18,7 @@ tool.
| Crawl static/server-rendered websites at modest to large scale | DocPull | Async HTTP, framework-aware extraction, manifests, cache support |
| Parse one messy article page in Python | trafilatura | Excellent text extraction library; DocPull can also use it as an optional extractor |
| Build a custom crawling pipeline with queues, middleware, and spiders | Scrapy | Mature scraping framework for custom pipelines and broad crawler control |
-| Automate a real browser or interact with JavaScript-heavy pages | Playwright, Puppeteer, Selenium | Required when useful content only exists after client-side rendering or interaction |
+| Automate a real browser or interact with JavaScript-heavy pages | agent-browser, Puppeteer, Selenium | Required when useful content only exists after client-side rendering or interaction |
| Build browser-backed crawlers in the JavaScript ecosystem | Crawlee | Strong fit for JavaScript/TypeScript crawling stacks |
| Use a hosted web-to-LLM extraction service | Firecrawl, Jina Reader, hosted extraction APIs | Useful when you want an API service to manage crawling/extraction infrastructure |
| Search the live web before building a pack | Dedicated search/extract providers, then DocPull source ingestion | Search providers find candidate sources; DocPull's public release contract starts when selected sources are fetched, parsed, packed, and validated locally |
@@ -55,7 +55,7 @@ tool.
| DocPull | Yes | Yes | Yes | Yes | Yes | No |
| trafilatura | Yes | Yes | Yes | No | Partial | No |
| Scrapy | Yes | Yes by default | Yes | No | No | No |
-| Playwright/Puppeteer/Selenium | Yes | No | Mixed | No | No | No |
+| agent-browser/Puppeteer/Selenium | Yes | No | Mixed | Yes | No | No |
| Crawlee | Yes | Mixed | No | No | No | No |
| Firecrawl/Jina Reader/hosted extraction APIs | No | Hidden/varies | API-first | Partial | Partial | Yes |
diff --git a/docs/corpus.manifest.json b/docs/corpus.manifest.json
new file mode 100644
index 0000000..cb4d6fd
--- /dev/null
+++ b/docs/corpus.manifest.json
@@ -0,0 +1,29 @@
+{
+ "schema_version": 3,
+ "output_contract_version": 3,
+ "generated_at": "2026-07-15T04:29:31.283115+00:00",
+ "output_format": "markdown",
+ "run": {
+ "schema_version": 1,
+ "profile": "rag",
+ "start_url": "pack --help",
+ "max_pages": null,
+ "max_depth": 5,
+ "include_paths": [],
+ "exclude_paths": [],
+ "output_format": "markdown",
+ "naming_strategy": "full",
+ "rich_metadata": true,
+ "extractor": "default",
+ "enable_special_cases": true,
+ "strict_js_required": false,
+ "max_tokens_per_file": null,
+ "emit_chunks": false,
+ "tokenizer": "cl100k_base",
+ "auth_type": "none"
+ },
+ "document_count": 0,
+ "record_count": 0,
+ "chunk_count": 0,
+ "records": []
+}
diff --git a/docs/launch-assets/README.md b/docs/launch-assets/README.md
index 7d80a46..7afaf93 100644
--- a/docs/launch-assets/README.md
+++ b/docs/launch-assets/README.md
@@ -9,6 +9,22 @@ submissions.
- `logo-square-dark-1024.png` - light mark on dark square background.
- `logo-transparent-dark-1024.png` - dark mark on transparent background.
- `logo-transparent-light-1024.png` - light mark on transparent background.
+- `logo-square-light-400.png` - 400x400 directory and marketplace icon.
+
+## Logo SVGs
+
+- `logo-mark.svg` - primary two-color mark on a transparent background.
+- `logo-mark-reversed.svg` - warm-white and green mark for dark backgrounds.
+- `logo-mark-monochrome-black.svg` - solid black mark.
+- `logo-mark-monochrome-white.svg` - solid white mark.
+- `logo-lockup-dark.svg` - mark and wordmark for light backgrounds.
+- `logo-lockup-light.svg` - reversed mark and wordmark for dark backgrounds.
+- `logo-app-icon.svg` - rounded-square app and social icon.
+- `logo-favicon.svg` - simplified small-size icon.
+
+The mark uses near-black `#101213`, verification green `#0F6B5D`, and warm
+white `#F5F4EF`. Preserve the geometric D silhouette, chamfered outer and inner
+right shoulders, and inset module; do not close the counter at small sizes.
## Screenshots
diff --git a/docs/launch-assets/logo-app-icon.svg b/docs/launch-assets/logo-app-icon.svg
new file mode 100644
index 0000000..0d3331a
--- /dev/null
+++ b/docs/launch-assets/logo-app-icon.svg
@@ -0,0 +1,11 @@
+
diff --git a/docs/launch-assets/logo-favicon.svg b/docs/launch-assets/logo-favicon.svg
new file mode 100644
index 0000000..7970925
--- /dev/null
+++ b/docs/launch-assets/logo-favicon.svg
@@ -0,0 +1,10 @@
+
diff --git a/docs/launch-assets/logo-lockup-dark.svg b/docs/launch-assets/logo-lockup-dark.svg
new file mode 100644
index 0000000..56e447d
--- /dev/null
+++ b/docs/launch-assets/logo-lockup-dark.svg
@@ -0,0 +1,21 @@
+
diff --git a/docs/launch-assets/logo-lockup-light.svg b/docs/launch-assets/logo-lockup-light.svg
new file mode 100644
index 0000000..bc28737
--- /dev/null
+++ b/docs/launch-assets/logo-lockup-light.svg
@@ -0,0 +1,21 @@
+
diff --git a/docs/launch-assets/logo-mark-monochrome-black.svg b/docs/launch-assets/logo-mark-monochrome-black.svg
new file mode 100644
index 0000000..939dfd0
--- /dev/null
+++ b/docs/launch-assets/logo-mark-monochrome-black.svg
@@ -0,0 +1,9 @@
+
diff --git a/docs/launch-assets/logo-mark-monochrome-white.svg b/docs/launch-assets/logo-mark-monochrome-white.svg
new file mode 100644
index 0000000..e9446b8
--- /dev/null
+++ b/docs/launch-assets/logo-mark-monochrome-white.svg
@@ -0,0 +1,9 @@
+
diff --git a/docs/launch-assets/logo-mark-reversed.svg b/docs/launch-assets/logo-mark-reversed.svg
new file mode 100644
index 0000000..839f280
--- /dev/null
+++ b/docs/launch-assets/logo-mark-reversed.svg
@@ -0,0 +1,10 @@
+
diff --git a/docs/launch-assets/logo-mark.svg b/docs/launch-assets/logo-mark.svg
new file mode 100644
index 0000000..5ade7c6
--- /dev/null
+++ b/docs/launch-assets/logo-mark.svg
@@ -0,0 +1,10 @@
+
diff --git a/docs/launch-assets/logo-square-dark-1024.png b/docs/launch-assets/logo-square-dark-1024.png
index 4401996a624601ba94d9788b3389df6dd6536d63..43cc966c38e50af18808d33a9971cf0f553b1290 100644
GIT binary patch
literal 8307
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
literal 10803
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