diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index 80c0d49..8753d05 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -26,7 +26,7 @@ jobs: bench: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - uses: actions/setup-node@v7 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 64ded2d..abee3f5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - run: cargo test --workspace --locked @@ -32,7 +32,7 @@ jobs: name: manifests, smoke, docs runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - uses: oven-sh/setup-bun@v2 with: bun-version: '1.4.0' @@ -41,8 +41,12 @@ jobs: components: clippy, rustfmt - uses: Swatinem/rust-cache@v2 - run: bun install --frozen-lockfile - - name: Manifests agree on one version - run: bun scripts/check-version.ts + - name: Manifests agree on one version and one tagline + env: + GH_TOKEN: ${{ github.token }} + run: | + bun scripts/check-version.ts + bun scripts/check-tagline.ts "$(gh api "repos/$GITHUB_REPOSITORY" --jq .description)" - name: Format and lints run: cargo fmt --all --check && cargo clippy --workspace --locked -- -D warnings - name: Build release binary diff --git a/.github/workflows/demo.yml b/.github/workflows/demo.yml index 62921cc..8390dcb 100644 --- a/.github/workflows/demo.yml +++ b/.github/workflows/demo.yml @@ -15,7 +15,7 @@ jobs: record: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - uses: actions/setup-node@v7 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 70ad553..fcd2a7a 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -23,7 +23,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - uses: oven-sh/setup-bun@v2 with: bun-version: '1.4.0' @@ -41,4 +41,4 @@ jobs: url: ${{ steps.deployment.outputs.page_url }} steps: - id: deployment - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@v5 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7551e0d..8993f3c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,7 +25,7 @@ jobs: version: ${{ steps.v.outputs.version }} publish: ${{ steps.v.outputs.publish }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - id: v env: GH_TOKEN: ${{ github.token }} @@ -53,7 +53,7 @@ jobs: - { key: linux-arm64-gnu, os: ubuntu-latest, target: aarch64-unknown-linux-gnu, zig: '2.17', bin: lockdocs } - { key: win32-x64-msvc, os: windows-latest, target: x86_64-pc-windows-msvc, bin: lockdocs.exe } steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} @@ -98,7 +98,7 @@ jobs: env: V: ${{ needs.check.outputs.version }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - uses: actions/setup-node@v7 with: node-version: '22' @@ -107,7 +107,7 @@ jobs: with: bun-version: '1.4.0' - run: bun scripts/check-version.ts - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: path: artifacts - name: Stage natives @@ -120,16 +120,18 @@ jobs: chmod +x packages/npm/$key/* done cp README.md LICENSE packages/lockdocs/ - - name: Publish to npm - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + # npm trusted publishing (OIDC, id-token: write above): no long-lived + # token. Each package trusts SylphxAI/lockdocs .github/workflows/release.yml. + - name: npm with trusted publishing support + run: npm install -g npm@^11.15.0 && npm --version + - name: Publish to npm (OIDC, with provenance) run: | set -euo pipefail pub() { local dir=$1 name name=$(node -p "require('./$dir/package.json').name") if npm view "$name@$V" version >/dev/null 2>&1; then echo "= $name@$V already live"; return; fi - (cd "$dir" && npm publish --access public) + (cd "$dir" && npm publish --access public --provenance) echo "+ $name@$V published" } for key in darwin-arm64 darwin-x64 linux-x64-gnu linux-arm64-gnu win32-x64-msvc; do pub packages/npm/$key; done diff --git a/Cargo.lock b/Cargo.lock index 10558d7..09a80fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,11 +52,11 @@ checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" [[package]] name = "block-buffer" -version = "0.10.4" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" dependencies = [ - "generic-array", + "hybrid-array", ] [[package]] @@ -96,11 +96,17 @@ dependencies = [ "thiserror", ] +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "cpufeatures" -version = "0.2.17" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" dependencies = [ "libc", ] @@ -147,29 +153,29 @@ checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" [[package]] name = "crypto-common" -version = "0.1.7" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" dependencies = [ - "generic-array", - "typenum", + "hybrid-array", ] [[package]] name = "digest" -version = "0.10.7" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ "block-buffer", + "const-oid", "crypto-common", ] [[package]] name = "dirs" -version = "6.0.0" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +checksum = "8d57d423b3c82e89b9a24ca3091fee61f456a26edbd28d26c65906f4bc1dcd8f" dependencies = [ "dirs-sys", ] @@ -268,16 +274,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - [[package]] name = "getrandom" version = "0.2.17" @@ -357,6 +353,15 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +[[package]] +name = "hybrid-array" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" +dependencies = [ + "typenum", +] + [[package]] name = "indexmap" version = "2.14.2" @@ -713,9 +718,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.9" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" dependencies = [ "cfg-if", "cpufeatures", @@ -825,19 +830,10 @@ dependencies = [ "indexmap", "serde_core", "serde_spanned", - "toml_datetime 1.1.1+spec-1.1.0", + "toml_datetime", "toml_parser", "toml_writer", - "winnow 1.0.4", -] - -[[package]] -name = "toml_datetime" -version = "0.7.5+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" -dependencies = [ - "serde_core", + "winnow", ] [[package]] @@ -851,15 +847,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.23.10+spec-1.0.0" +version = "0.25.15+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +checksum = "1340ea94a5856333492c9064b02c778b191dd2c853778d9609debdcdfea3a614" dependencies = [ "indexmap", - "toml_datetime 0.7.5+spec-1.1.0", + "toml_datetime", "toml_parser", "toml_writer", - "winnow 0.7.15", + "winnow", ] [[package]] @@ -868,7 +864,7 @@ version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" dependencies = [ - "winnow 1.0.4", + "winnow", ] [[package]] @@ -995,12 +991,6 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e" -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -1106,19 +1096,13 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.7.15" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" dependencies = [ "memchr", ] -[[package]] -name = "winnow" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" - [[package]] name = "xattr" version = "1.6.1" diff --git a/PROJECT.md b/PROJECT.md index 3860518..bd29682 100644 --- a/PROJECT.md +++ b/PROJECT.md @@ -28,3 +28,7 @@ Bump with `bun scripts/set-version.ts X.Y.Z && cargo update -w`, add a the npm version is new: 5 native targets on GitHub-hosted runners, the natives and `@sylphx/lockdocs`, an `npx` smoke on a real project, the GitHub release, and the MCP Registry entry. + +npm publishing uses trusted publishing (OIDC): every package +(`@sylphx/lockdocs` and the five `@sylphx/lockdocs-*` natives) trusts +`SylphxAI/lockdocs` `.github/workflows/release.yml`; there is no npm token. diff --git a/README.md b/README.md index b100155..dd70574 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ # lockdocs -**Context7 without rate limits: exact-version library docs for AI agents, straight from your lockfile, offline.** +**Exact-version library docs from your lockfile — local, offline, no rate limits.** Reads your lockfile. Answers from the docs and type declarations of the exact version you installed.
-npm · PyPI · crates.io · Go. One Rust binary. No account, no API key, no rate limit. MIT. +npm · PyPI · crates.io · Go. MCP server + CLI in one Rust binary. No account, no API key. MIT. [![npm](https://img.shields.io/npm/v/@sylphx/lockdocs?color=7c9cff&label=npm)](https://www.npmjs.com/package/@sylphx/lockdocs) [![CI](https://github.com/SylphxAI/lockdocs/actions/workflows/ci.yml/badge.svg)](https://github.com/SylphxAI/lockdocs/actions/workflows/ci.yml) @@ -68,7 +68,7 @@ lockdocs takes the version question off the table: - **Exact version, zero config.** It reads `package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`, `bun.lock`, `Cargo.lock`, `uv.lock`, `poetry.lock`, `Pipfile.lock`, `requirements*.txt` and `go.mod`. No library IDs, no "use v14" in the prompt. - **Docs that ship with the code.** READMEs, changelogs and `docs/` folders, plus the API reference in the package itself: `.d.ts` declarations with JSDoc, Python docstrings and stubs, rustdoc comments, Go doc comments. If it is installed, it is documented, including your private and internal packages. -- **Offline and unlimited.** Everything is read from `node_modules`, your virtualenv, `~/.cargo/registry` and the Go module cache. No network, no account, no rate limit, and nothing about your dependencies leaves your machine. +- **Offline and unlimited.** Everything is read from `node_modules`, your virtualenv, `~/.cargo/registry` and the Go module cache. Offline after a one-time model download (129 MB, kept as 32 MB); keyword-only mode (`LOCKDOCS_EMBED=0`) needs no network at all. No account, no rate limit, and nothing about your dependencies leaves your machine. - **Upstream docs at the exact tag, when you want them.** Packages like Next.js, Django and FastAPI ship no docs. `lockdocs fetch` pulls their docs folders from GitHub at the git tag of your pinned version, once, then stays offline. - **Meaning, not just words.** Hybrid retrieval: BM25 fused with a small local embedding model (downloaded once, 32 MB on disk), plus API redirects from deprecation notes ("use `model_validate` instead"). - **Small, cited answers.** Packed into a token budget (1,200 by default), every section cited as `package@version path:line`. @@ -119,16 +119,18 @@ Out of the box lockdocs reads only your disk (plus the one-time embedding model ## Benchmarks -70 questions whose correct answer depends on the version, over 14 libraries (zod, Next.js, React Router, pydantic, axum, tokio, Tailwind CSS, ESLint, Prisma, React, Vite, Express, SQLAlchemy, Django, FastAPI), each asked in a real project with that version installed. An answer passes when it contains the version-correct API and none of the other version's. Same questions and grader against Context7's anonymous API, on a GitHub-hosted runner ([run](https://github.com/SylphxAI/lockdocs/actions/runs/36125903106)): + +70 questions whose correct answer depends on the version, over 15 libraries (zod, Next.js, React Router, pydantic, axum, tokio, Tailwind CSS, ESLint, Prisma, React, Vite, Express, SQLAlchemy, Django, FastAPI), each asked in a real project with that version installed. An answer passes when it contains the version-correct API and none of the other version's. Same questions and grader against Context7's anonymous API, on a GitHub-hosted runner ([run](https://github.com/SylphxAI/lockdocs/actions/runs/36125903106)): | | correct | older majors | newer majors | tokio | median tokens | median latency | |---|---|---|---|---|---|---| -| **lockdocs + `lockdocs fetch`** | **55/70** | **24/33** | 29/34 | 2/3 | **875** | **87 ms** | +| lockdocs + `lockdocs fetch` | 55/70 | 24/33 | 29/34 | 2/3 | 875 | 87 ms | | lockdocs, package files only | 46/70 | 22/33 | 22/34 | 2/3 | 915 | 49 ms | -| Context7 (anonymous) | 49/70 | 12/33 | **34/34** | **3/3** | 908 | 2,011 ms | +| Context7 (anonymous) | 49/70 | 12/33 | 34/34 | 3/3 | 908 | 2,011 ms | + - **Where versions matter most, lockdocs wins by 2x.** On older majors Context7 often answers with the newest API (all five pydantic 1 questions got pydantic 2 answers). -- **Context7 still leads on the newest majors and on tokio.** Its index covers docs websites that no package or tag ships (Prisma's docs now describe a later major), and lockdocs has a few ranking misses. The benchmark page lists every question and answer. +- **Context7 is ahead on the newest majors (34/34 vs 29/34) and on tokio (3/3 vs 2/3)**, and we are working to close that. Its index covers docs websites that no package or tag ships (Prisma's docs now describe a later major), and lockdocs has a few ranking misses. The benchmark page lists every question and answer. - **~23x faster, no quota.** lockdocs latency is a fresh CLI process per question; `lockdocs fetch` is a one-time 0.6-5 s per project (median 2.4 s). Method, questions, per-question results and scripts: [benchmark page](https://sylphxai.github.io/lockdocs/benchmarks) and [`bench/`](bench/). @@ -185,8 +187,7 @@ lockdocs reads files on your machine and answers over stdio. Network use: the em - [**repomap**](https://github.com/SylphxAI/repomap): a map of your codebase for AI agents: code graph, search, call paths and change impact, with an interactive graph UI. - [**anymd**](https://github.com/SylphxAI/anymd): any file to clean Markdown for your AI agent: PDF, Word, PowerPoint, Excel, EPUB, HTML, images, audio and video. - -All three run locally, need no API key, and are MIT licensed. +- [**readme-mark**](https://github.com/SylphxAI/readme-mark): beautiful README images from one URL. ## Star history diff --git a/bench/render.py b/bench/render.py index e7171b3..f648ea0 100755 --- a/bench/render.py +++ b/bench/render.py @@ -19,3 +19,43 @@ doc = re.sub(r".*?(?=\n## Reading the results)", "\n\n" + body + "\n", doc, flags=re.S) open(p, "w").write(doc) print(body.split("\n\n")[1] if "\n\n" in body else body) + + +# README: the headline table and counts, between and . +NAMES = {"next": "Next.js", "react-router": "React Router", "tailwindcss": "Tailwind CSS", "eslint": "ESLint", "sqlalchemy": "SQLAlchemy", + "fastapi": "FastAPI", "django": "Django", "express": "Express", "vite": "Vite", "react": "React", "prisma": "Prisma", "@prisma/client": "Prisma"} +rows = res["rows"] +libs = [] +for r in rows: + n = NAMES.get(r["package"], r["package"]) + if n not in libs: + libs.append(n) +single = sorted({NAMES.get(r["package"], r["package"]) for r in rows if r.get("line") == "single"}) + + +def sub(key, line): + rs = [r for r in rows if r.get("line") == line] + got = sum(1 for r in rs if (r.get("context7", {}) if key == "context7" else r["variants"].get(key, {})).get("pass")) + return f"{got}/{len(rs)}" + + +def fmt_ms(v): + return f"{v:,.0f} ms" + + +table = [ + f"{len(rows)} questions whose correct answer depends on the version, over {len(libs)} libraries ({', '.join(libs)}), each asked in a real project with that version installed. " + "An answer passes when it contains the version-correct API and none of the other version's. Same questions and grader against Context7's anonymous API, " + f"on a GitHub-hosted runner" + (f" ([run]({url}))" if url else "") + ":", + "", + f"| | correct | older majors | newer majors | {', '.join(single) or 'single version'} | median tokens | median latency |", + "|---|---|---|---|---|---|---|", +] +for key, label in [("fetched", "lockdocs + `lockdocs fetch`"), ("hybrid", "lockdocs, package files only"), ("context7", "Context7 (anonymous)")]: + a = res["summary"].get(key) + if a: + table.append(f"| {label} | {a['passed']}/{a['total']} | {sub(key, 'older')} | {sub(key, 'newer')} | {sub(key, 'single')} | {a['median_tokens']:,} | {fmt_ms(a['median_ms'])} |") +rp = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "README.md") +readme = open(rp).read() +readme = re.sub(r".*?", "\n" + "\n".join(table) + "\n", readme, flags=re.S) +open(rp, "w").write(readme) diff --git a/bench/results.json b/bench/results.json deleted file mode 100644 index 35fbf65..0000000 --- a/bench/results.json +++ /dev/null @@ -1,2482 +0,0 @@ -{ - "tokenizer": "tiktoken o200k_base", - "index": { - "axum07": { - "ms": 201, - "report": { - "missing": [ - { - "error": "@vue/compiler-dom@3.5.43 is pinned in /home/runner/work/lockdocs/lockdocs/bun.lock but its files are not on this machine: run your package manager's install, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "@vue/compiler-dom@3.5.43" - }, - { - "error": "@vue/server-renderer@3.5.43 is pinned in /home/runner/work/lockdocs/lockdocs/bun.lock but its files are not on this machine: run your package manager's install, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "@vue/server-renderer@3.5.43" - }, - { - "error": "vitepress@1.6.4 is pinned in /home/runner/work/lockdocs/lockdocs/bun.lock but its files are not on this machine: run your package manager's install, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "vitepress@1.6.4" - }, - { - "error": "vue@3.5.43 is pinned in /home/runner/work/lockdocs/lockdocs/bun.lock but its files are not on this machine: run your package manager's install, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "vue@3.5.43" - } - ], - "ms": 193, - "packages": [ - { - "build_ms": 140, - "ecosystem": "cargo", - "package": "axum@0.7.9", - "sections": 262, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/axum-0.7.9", - "symbols": 236 - }, - { - "build_ms": 187, - "ecosystem": "cargo", - "package": "tokio@1.41.1", - "sections": 551, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.41.1", - "symbols": 1311 - } - ] - } - }, - "axum08": { - "ms": 205, - "report": { - "missing": [ - { - "error": "@vue/compiler-dom@3.5.43 is pinned in /home/runner/work/lockdocs/lockdocs/bun.lock but its files are not on this machine: run your package manager's install, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "@vue/compiler-dom@3.5.43" - }, - { - "error": "@vue/server-renderer@3.5.43 is pinned in /home/runner/work/lockdocs/lockdocs/bun.lock but its files are not on this machine: run your package manager's install, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "@vue/server-renderer@3.5.43" - }, - { - "error": "vitepress@1.6.4 is pinned in /home/runner/work/lockdocs/lockdocs/bun.lock but its files are not on this machine: run your package manager's install, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "vitepress@1.6.4" - }, - { - "error": "vue@3.5.43 is pinned in /home/runner/work/lockdocs/lockdocs/bun.lock but its files are not on this machine: run your package manager's install, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "vue@3.5.43" - } - ], - "ms": 199, - "packages": [ - { - "build_ms": 146, - "ecosystem": "cargo", - "package": "axum@0.8.1", - "sections": 272, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/axum-0.8.1", - "symbols": 264 - }, - { - "build_ms": 194, - "ecosystem": "cargo", - "package": "tokio@1.43.0", - "sections": 561, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.43.0", - "symbols": 1332 - } - ] - } - }, - "next14": { - "ms": 403, - "report": { - "missing": [ - { - "error": "tempfile@3.27.0 is pinned in /home/runner/work/lockdocs/lockdocs/Cargo.lock but its files are not on this machine: run `cargo fetch`, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "tempfile@3.27.0" - } - ], - "ms": 388, - "packages": [ - { - "build_ms": 199, - "ecosystem": "npm", - "package": "next@14.2.15", - "sections": 9, - "source": "node_modules/next", - "symbols": 4890 - }, - { - "build_ms": 20, - "ecosystem": "npm", - "package": "react@18.3.1", - "sections": 4, - "source": "node_modules/react", - "symbols": 0 - }, - { - "build_ms": 180, - "ecosystem": "npm", - "package": "react-dom@18.3.1", - "sections": 7, - "source": "node_modules/react-dom", - "symbols": 0 - }, - { - "build_ms": 159, - "ecosystem": "cargo", - "package": "anyhow@1.0.104", - "sections": 14, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/anyhow-1.0.104", - "symbols": 55 - }, - { - "build_ms": 4, - "ecosystem": "cargo", - "package": "dirs@6.0.0", - "sections": 18, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/dirs-6.0.0", - "symbols": 95 - }, - { - "build_ms": 43, - "ecosystem": "cargo", - "package": "flate2@1.1.10", - "sections": 23, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/flate2-1.1.10", - "symbols": 333 - }, - { - "build_ms": 29, - "ecosystem": "cargo", - "package": "postcard@1.1.3", - "sections": 22, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/postcard-1.1.3", - "symbols": 93 - }, - { - "build_ms": 134, - "ecosystem": "cargo", - "package": "rayon@1.12.0", - "sections": 134, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rayon-1.12.0", - "symbols": 315 - }, - { - "build_ms": 85, - "ecosystem": "cargo", - "package": "serde@1.0.229", - "sections": 23, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde-1.0.229", - "symbols": 216 - }, - { - "build_ms": 83, - "ecosystem": "cargo", - "package": "serde_json@1.0.151", - "sections": 50, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde_json-1.0.151", - "symbols": 271 - }, - { - "build_ms": 28, - "ecosystem": "cargo", - "package": "tar@0.4.46", - "sections": 7, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tar-0.4.46", - "symbols": 223 - }, - { - "build_ms": 45, - "ecosystem": "cargo", - "package": "toml@1.1.6+spec-1.1.0", - "sections": 15, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/toml-1.1.6+spec-1.1.0", - "symbols": 132 - }, - { - "build_ms": 49, - "ecosystem": "cargo", - "package": "toml_edit@0.23.10+spec-1.0.0", - "sections": 15, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/toml_edit-0.23.10+spec-1.0.0", - "symbols": 389 - }, - { - "build_ms": 1, - "ecosystem": "cargo", - "package": "tree-sitter@0.27.0", - "sections": 12, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-0.27.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-go@0.25.0", - "sections": 1, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-go-0.25.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-python@0.25.0", - "sections": 2, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-python-0.25.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-rust@0.24.2", - "sections": 3, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-rust-0.24.2", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-typescript@0.23.2", - "sections": 1, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-typescript-0.23.2", - "symbols": 0 - }, - { - "build_ms": 85, - "ecosystem": "cargo", - "package": "ureq@3.4.2", - "sections": 150, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ureq-3.4.2", - "symbols": 348 - }, - { - "build_ms": 28, - "ecosystem": "cargo", - "package": "yaml-rust2@0.13.0", - "sections": 46, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/yaml-rust2-0.13.0", - "symbols": 66 - }, - { - "build_ms": 173, - "ecosystem": "cargo", - "package": "zip@8.6.0", - "sections": 214, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/zip-8.6.0", - "symbols": 346 - } - ] - } - }, - "next15": { - "ms": 391, - "report": { - "missing": [ - { - "error": "tempfile@3.27.0 is pinned in /home/runner/work/lockdocs/lockdocs/Cargo.lock but its files are not on this machine: run `cargo fetch`, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "tempfile@3.27.0" - } - ], - "ms": 377, - "packages": [ - { - "build_ms": 229, - "ecosystem": "npm", - "package": "next@15.1.0", - "sections": 9, - "source": "node_modules/next", - "symbols": 5585 - }, - { - "build_ms": 35, - "ecosystem": "npm", - "package": "react@19.0.0", - "sections": 4, - "source": "node_modules/react", - "symbols": 0 - }, - { - "build_ms": 369, - "ecosystem": "npm", - "package": "react-dom@19.0.0", - "sections": 7, - "source": "node_modules/react-dom", - "symbols": 0 - }, - { - "build_ms": 159, - "ecosystem": "cargo", - "package": "anyhow@1.0.104", - "sections": 14, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/anyhow-1.0.104", - "symbols": 55 - }, - { - "build_ms": 4, - "ecosystem": "cargo", - "package": "dirs@6.0.0", - "sections": 18, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/dirs-6.0.0", - "symbols": 95 - }, - { - "build_ms": 43, - "ecosystem": "cargo", - "package": "flate2@1.1.10", - "sections": 23, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/flate2-1.1.10", - "symbols": 333 - }, - { - "build_ms": 29, - "ecosystem": "cargo", - "package": "postcard@1.1.3", - "sections": 22, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/postcard-1.1.3", - "symbols": 93 - }, - { - "build_ms": 134, - "ecosystem": "cargo", - "package": "rayon@1.12.0", - "sections": 134, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rayon-1.12.0", - "symbols": 315 - }, - { - "build_ms": 85, - "ecosystem": "cargo", - "package": "serde@1.0.229", - "sections": 23, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde-1.0.229", - "symbols": 216 - }, - { - "build_ms": 83, - "ecosystem": "cargo", - "package": "serde_json@1.0.151", - "sections": 50, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde_json-1.0.151", - "symbols": 271 - }, - { - "build_ms": 28, - "ecosystem": "cargo", - "package": "tar@0.4.46", - "sections": 7, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tar-0.4.46", - "symbols": 223 - }, - { - "build_ms": 45, - "ecosystem": "cargo", - "package": "toml@1.1.6+spec-1.1.0", - "sections": 15, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/toml-1.1.6+spec-1.1.0", - "symbols": 132 - }, - { - "build_ms": 49, - "ecosystem": "cargo", - "package": "toml_edit@0.23.10+spec-1.0.0", - "sections": 15, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/toml_edit-0.23.10+spec-1.0.0", - "symbols": 389 - }, - { - "build_ms": 1, - "ecosystem": "cargo", - "package": "tree-sitter@0.27.0", - "sections": 12, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-0.27.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-go@0.25.0", - "sections": 1, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-go-0.25.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-python@0.25.0", - "sections": 2, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-python-0.25.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-rust@0.24.2", - "sections": 3, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-rust-0.24.2", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-typescript@0.23.2", - "sections": 1, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-typescript-0.23.2", - "symbols": 0 - }, - { - "build_ms": 85, - "ecosystem": "cargo", - "package": "ureq@3.4.2", - "sections": 150, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ureq-3.4.2", - "symbols": 348 - }, - { - "build_ms": 28, - "ecosystem": "cargo", - "package": "yaml-rust2@0.13.0", - "sections": 46, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/yaml-rust2-0.13.0", - "symbols": 66 - }, - { - "build_ms": 173, - "ecosystem": "cargo", - "package": "zip@8.6.0", - "sections": 214, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/zip-8.6.0", - "symbols": 346 - } - ] - } - }, - "pydantic1": { - "ms": 51, - "report": { - "missing": [ - { - "error": "@vue/compiler-dom@3.5.43 is pinned in /home/runner/work/lockdocs/lockdocs/bun.lock but its files are not on this machine: run your package manager's install, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "@vue/compiler-dom@3.5.43" - }, - { - "error": "@vue/server-renderer@3.5.43 is pinned in /home/runner/work/lockdocs/lockdocs/bun.lock but its files are not on this machine: run your package manager's install, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "@vue/server-renderer@3.5.43" - }, - { - "error": "vitepress@1.6.4 is pinned in /home/runner/work/lockdocs/lockdocs/bun.lock but its files are not on this machine: run your package manager's install, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "vitepress@1.6.4" - }, - { - "error": "vue@3.5.43 is pinned in /home/runner/work/lockdocs/lockdocs/bun.lock but its files are not on this machine: run your package manager's install, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "vue@3.5.43" - }, - { - "error": "tempfile@3.27.0 is pinned in /home/runner/work/lockdocs/lockdocs/Cargo.lock but its files are not on this machine: run `cargo fetch`, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "tempfile@3.27.0" - } - ], - "ms": 45, - "packages": [ - { - "build_ms": 31, - "ecosystem": "pypi", - "package": "pydantic@1.10.18", - "sections": 135, - "source": ".venv/lib/python3.12/site-packages", - "symbols": 573 - }, - { - "build_ms": 159, - "ecosystem": "cargo", - "package": "anyhow@1.0.104", - "sections": 14, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/anyhow-1.0.104", - "symbols": 55 - }, - { - "build_ms": 4, - "ecosystem": "cargo", - "package": "dirs@6.0.0", - "sections": 18, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/dirs-6.0.0", - "symbols": 95 - }, - { - "build_ms": 43, - "ecosystem": "cargo", - "package": "flate2@1.1.10", - "sections": 23, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/flate2-1.1.10", - "symbols": 333 - }, - { - "build_ms": 29, - "ecosystem": "cargo", - "package": "postcard@1.1.3", - "sections": 22, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/postcard-1.1.3", - "symbols": 93 - }, - { - "build_ms": 134, - "ecosystem": "cargo", - "package": "rayon@1.12.0", - "sections": 134, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rayon-1.12.0", - "symbols": 315 - }, - { - "build_ms": 85, - "ecosystem": "cargo", - "package": "serde@1.0.229", - "sections": 23, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde-1.0.229", - "symbols": 216 - }, - { - "build_ms": 83, - "ecosystem": "cargo", - "package": "serde_json@1.0.151", - "sections": 50, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde_json-1.0.151", - "symbols": 271 - }, - { - "build_ms": 28, - "ecosystem": "cargo", - "package": "tar@0.4.46", - "sections": 7, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tar-0.4.46", - "symbols": 223 - }, - { - "build_ms": 45, - "ecosystem": "cargo", - "package": "toml@1.1.6+spec-1.1.0", - "sections": 15, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/toml-1.1.6+spec-1.1.0", - "symbols": 132 - }, - { - "build_ms": 49, - "ecosystem": "cargo", - "package": "toml_edit@0.23.10+spec-1.0.0", - "sections": 15, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/toml_edit-0.23.10+spec-1.0.0", - "symbols": 389 - }, - { - "build_ms": 1, - "ecosystem": "cargo", - "package": "tree-sitter@0.27.0", - "sections": 12, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-0.27.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-go@0.25.0", - "sections": 1, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-go-0.25.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-python@0.25.0", - "sections": 2, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-python-0.25.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-rust@0.24.2", - "sections": 3, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-rust-0.24.2", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-typescript@0.23.2", - "sections": 1, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-typescript-0.23.2", - "symbols": 0 - }, - { - "build_ms": 85, - "ecosystem": "cargo", - "package": "ureq@3.4.2", - "sections": 150, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ureq-3.4.2", - "symbols": 348 - }, - { - "build_ms": 28, - "ecosystem": "cargo", - "package": "yaml-rust2@0.13.0", - "sections": 46, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/yaml-rust2-0.13.0", - "symbols": 66 - }, - { - "build_ms": 173, - "ecosystem": "cargo", - "package": "zip@8.6.0", - "sections": 214, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/zip-8.6.0", - "symbols": 346 - } - ] - } - }, - "pydantic2": { - "ms": 98, - "report": { - "missing": [ - { - "error": "@vue/compiler-dom@3.5.43 is pinned in /home/runner/work/lockdocs/lockdocs/bun.lock but its files are not on this machine: run your package manager's install, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "@vue/compiler-dom@3.5.43" - }, - { - "error": "@vue/server-renderer@3.5.43 is pinned in /home/runner/work/lockdocs/lockdocs/bun.lock but its files are not on this machine: run your package manager's install, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "@vue/server-renderer@3.5.43" - }, - { - "error": "vitepress@1.6.4 is pinned in /home/runner/work/lockdocs/lockdocs/bun.lock but its files are not on this machine: run your package manager's install, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "vitepress@1.6.4" - }, - { - "error": "vue@3.5.43 is pinned in /home/runner/work/lockdocs/lockdocs/bun.lock but its files are not on this machine: run your package manager's install, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "vue@3.5.43" - }, - { - "error": "tempfile@3.27.0 is pinned in /home/runner/work/lockdocs/lockdocs/Cargo.lock but its files are not on this machine: run `cargo fetch`, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "tempfile@3.27.0" - } - ], - "ms": 90, - "packages": [ - { - "build_ms": 77, - "ecosystem": "pypi", - "package": "pydantic@2.9.2", - "sections": 191, - "source": ".venv/lib/python3.12/site-packages", - "symbols": 1255 - }, - { - "build_ms": 159, - "ecosystem": "cargo", - "package": "anyhow@1.0.104", - "sections": 14, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/anyhow-1.0.104", - "symbols": 55 - }, - { - "build_ms": 4, - "ecosystem": "cargo", - "package": "dirs@6.0.0", - "sections": 18, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/dirs-6.0.0", - "symbols": 95 - }, - { - "build_ms": 43, - "ecosystem": "cargo", - "package": "flate2@1.1.10", - "sections": 23, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/flate2-1.1.10", - "symbols": 333 - }, - { - "build_ms": 29, - "ecosystem": "cargo", - "package": "postcard@1.1.3", - "sections": 22, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/postcard-1.1.3", - "symbols": 93 - }, - { - "build_ms": 134, - "ecosystem": "cargo", - "package": "rayon@1.12.0", - "sections": 134, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rayon-1.12.0", - "symbols": 315 - }, - { - "build_ms": 85, - "ecosystem": "cargo", - "package": "serde@1.0.229", - "sections": 23, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde-1.0.229", - "symbols": 216 - }, - { - "build_ms": 83, - "ecosystem": "cargo", - "package": "serde_json@1.0.151", - "sections": 50, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde_json-1.0.151", - "symbols": 271 - }, - { - "build_ms": 28, - "ecosystem": "cargo", - "package": "tar@0.4.46", - "sections": 7, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tar-0.4.46", - "symbols": 223 - }, - { - "build_ms": 45, - "ecosystem": "cargo", - "package": "toml@1.1.6+spec-1.1.0", - "sections": 15, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/toml-1.1.6+spec-1.1.0", - "symbols": 132 - }, - { - "build_ms": 49, - "ecosystem": "cargo", - "package": "toml_edit@0.23.10+spec-1.0.0", - "sections": 15, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/toml_edit-0.23.10+spec-1.0.0", - "symbols": 389 - }, - { - "build_ms": 1, - "ecosystem": "cargo", - "package": "tree-sitter@0.27.0", - "sections": 12, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-0.27.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-go@0.25.0", - "sections": 1, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-go-0.25.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-python@0.25.0", - "sections": 2, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-python-0.25.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-rust@0.24.2", - "sections": 3, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-rust-0.24.2", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-typescript@0.23.2", - "sections": 1, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-typescript-0.23.2", - "symbols": 0 - }, - { - "build_ms": 85, - "ecosystem": "cargo", - "package": "ureq@3.4.2", - "sections": 150, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ureq-3.4.2", - "symbols": 348 - }, - { - "build_ms": 28, - "ecosystem": "cargo", - "package": "yaml-rust2@0.13.0", - "sections": 46, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/yaml-rust2-0.13.0", - "symbols": 66 - }, - { - "build_ms": 173, - "ecosystem": "cargo", - "package": "zip@8.6.0", - "sections": 214, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/zip-8.6.0", - "symbols": 346 - } - ] - } - }, - "rr6": { - "ms": 175, - "report": { - "missing": [ - { - "error": "tempfile@3.27.0 is pinned in /home/runner/work/lockdocs/lockdocs/Cargo.lock but its files are not on this machine: run `cargo fetch`, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "tempfile@3.27.0" - } - ], - "ms": 161, - "packages": [ - { - "build_ms": 160, - "ecosystem": "npm", - "package": "react@18.3.1", - "sections": 4, - "source": "node_modules/react", - "symbols": 0 - }, - { - "build_ms": 150, - "ecosystem": "npm", - "package": "react-dom@18.3.1", - "sections": 7, - "source": "node_modules/react-dom", - "symbols": 0 - }, - { - "build_ms": 7, - "ecosystem": "npm", - "package": "react-router@6.26.2", - "sections": 74, - "source": "node_modules/react-router", - "symbols": 207 - }, - { - "build_ms": 7, - "ecosystem": "npm", - "package": "react-router-dom@6.26.2", - "sections": 80, - "source": "node_modules/react-router-dom", - "symbols": 145 - }, - { - "build_ms": 159, - "ecosystem": "cargo", - "package": "anyhow@1.0.104", - "sections": 14, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/anyhow-1.0.104", - "symbols": 55 - }, - { - "build_ms": 4, - "ecosystem": "cargo", - "package": "dirs@6.0.0", - "sections": 18, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/dirs-6.0.0", - "symbols": 95 - }, - { - "build_ms": 43, - "ecosystem": "cargo", - "package": "flate2@1.1.10", - "sections": 23, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/flate2-1.1.10", - "symbols": 333 - }, - { - "build_ms": 29, - "ecosystem": "cargo", - "package": "postcard@1.1.3", - "sections": 22, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/postcard-1.1.3", - "symbols": 93 - }, - { - "build_ms": 134, - "ecosystem": "cargo", - "package": "rayon@1.12.0", - "sections": 134, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rayon-1.12.0", - "symbols": 315 - }, - { - "build_ms": 85, - "ecosystem": "cargo", - "package": "serde@1.0.229", - "sections": 23, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde-1.0.229", - "symbols": 216 - }, - { - "build_ms": 83, - "ecosystem": "cargo", - "package": "serde_json@1.0.151", - "sections": 50, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde_json-1.0.151", - "symbols": 271 - }, - { - "build_ms": 28, - "ecosystem": "cargo", - "package": "tar@0.4.46", - "sections": 7, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tar-0.4.46", - "symbols": 223 - }, - { - "build_ms": 45, - "ecosystem": "cargo", - "package": "toml@1.1.6+spec-1.1.0", - "sections": 15, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/toml-1.1.6+spec-1.1.0", - "symbols": 132 - }, - { - "build_ms": 49, - "ecosystem": "cargo", - "package": "toml_edit@0.23.10+spec-1.0.0", - "sections": 15, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/toml_edit-0.23.10+spec-1.0.0", - "symbols": 389 - }, - { - "build_ms": 1, - "ecosystem": "cargo", - "package": "tree-sitter@0.27.0", - "sections": 12, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-0.27.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-go@0.25.0", - "sections": 1, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-go-0.25.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-python@0.25.0", - "sections": 2, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-python-0.25.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-rust@0.24.2", - "sections": 3, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-rust-0.24.2", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-typescript@0.23.2", - "sections": 1, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-typescript-0.23.2", - "symbols": 0 - }, - { - "build_ms": 85, - "ecosystem": "cargo", - "package": "ureq@3.4.2", - "sections": 150, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ureq-3.4.2", - "symbols": 348 - }, - { - "build_ms": 28, - "ecosystem": "cargo", - "package": "yaml-rust2@0.13.0", - "sections": 46, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/yaml-rust2-0.13.0", - "symbols": 66 - }, - { - "build_ms": 173, - "ecosystem": "cargo", - "package": "zip@8.6.0", - "sections": 214, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/zip-8.6.0", - "symbols": 346 - } - ] - } - }, - "rr7": { - "ms": 372, - "report": { - "missing": [ - { - "error": "tempfile@3.27.0 is pinned in /home/runner/work/lockdocs/lockdocs/Cargo.lock but its files are not on this machine: run `cargo fetch`, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "tempfile@3.27.0" - } - ], - "ms": 362, - "packages": [ - { - "build_ms": 33, - "ecosystem": "npm", - "package": "react@19.0.0", - "sections": 4, - "source": "node_modules/react", - "symbols": 0 - }, - { - "build_ms": 329, - "ecosystem": "npm", - "package": "react-dom@19.0.0", - "sections": 7, - "source": "node_modules/react-dom", - "symbols": 0 - }, - { - "build_ms": 354, - "ecosystem": "npm", - "package": "react-router@7.1.1", - "sections": 92, - "source": "node_modules/react-router", - "symbols": 1160 - }, - { - "build_ms": 159, - "ecosystem": "cargo", - "package": "anyhow@1.0.104", - "sections": 14, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/anyhow-1.0.104", - "symbols": 55 - }, - { - "build_ms": 4, - "ecosystem": "cargo", - "package": "dirs@6.0.0", - "sections": 18, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/dirs-6.0.0", - "symbols": 95 - }, - { - "build_ms": 43, - "ecosystem": "cargo", - "package": "flate2@1.1.10", - "sections": 23, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/flate2-1.1.10", - "symbols": 333 - }, - { - "build_ms": 29, - "ecosystem": "cargo", - "package": "postcard@1.1.3", - "sections": 22, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/postcard-1.1.3", - "symbols": 93 - }, - { - "build_ms": 134, - "ecosystem": "cargo", - "package": "rayon@1.12.0", - "sections": 134, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rayon-1.12.0", - "symbols": 315 - }, - { - "build_ms": 85, - "ecosystem": "cargo", - "package": "serde@1.0.229", - "sections": 23, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde-1.0.229", - "symbols": 216 - }, - { - "build_ms": 83, - "ecosystem": "cargo", - "package": "serde_json@1.0.151", - "sections": 50, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde_json-1.0.151", - "symbols": 271 - }, - { - "build_ms": 28, - "ecosystem": "cargo", - "package": "tar@0.4.46", - "sections": 7, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tar-0.4.46", - "symbols": 223 - }, - { - "build_ms": 45, - "ecosystem": "cargo", - "package": "toml@1.1.6+spec-1.1.0", - "sections": 15, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/toml-1.1.6+spec-1.1.0", - "symbols": 132 - }, - { - "build_ms": 49, - "ecosystem": "cargo", - "package": "toml_edit@0.23.10+spec-1.0.0", - "sections": 15, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/toml_edit-0.23.10+spec-1.0.0", - "symbols": 389 - }, - { - "build_ms": 1, - "ecosystem": "cargo", - "package": "tree-sitter@0.27.0", - "sections": 12, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-0.27.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-go@0.25.0", - "sections": 1, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-go-0.25.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-python@0.25.0", - "sections": 2, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-python-0.25.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-rust@0.24.2", - "sections": 3, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-rust-0.24.2", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-typescript@0.23.2", - "sections": 1, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-typescript-0.23.2", - "symbols": 0 - }, - { - "build_ms": 85, - "ecosystem": "cargo", - "package": "ureq@3.4.2", - "sections": 150, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ureq-3.4.2", - "symbols": 348 - }, - { - "build_ms": 28, - "ecosystem": "cargo", - "package": "yaml-rust2@0.13.0", - "sections": 46, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/yaml-rust2-0.13.0", - "symbols": 66 - }, - { - "build_ms": 173, - "ecosystem": "cargo", - "package": "zip@8.6.0", - "sections": 214, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/zip-8.6.0", - "symbols": 346 - } - ] - } - }, - "zod3": { - "ms": 30, - "report": { - "missing": [ - { - "error": "tempfile@3.27.0 is pinned in /home/runner/work/lockdocs/lockdocs/Cargo.lock but its files are not on this machine: run `cargo fetch`, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "tempfile@3.27.0" - } - ], - "ms": 24, - "packages": [ - { - "build_ms": 23, - "ecosystem": "npm", - "package": "zod@3.23.8", - "sections": 121, - "source": "node_modules/zod", - "symbols": 713 - }, - { - "build_ms": 159, - "ecosystem": "cargo", - "package": "anyhow@1.0.104", - "sections": 14, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/anyhow-1.0.104", - "symbols": 55 - }, - { - "build_ms": 4, - "ecosystem": "cargo", - "package": "dirs@6.0.0", - "sections": 18, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/dirs-6.0.0", - "symbols": 95 - }, - { - "build_ms": 43, - "ecosystem": "cargo", - "package": "flate2@1.1.10", - "sections": 23, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/flate2-1.1.10", - "symbols": 333 - }, - { - "build_ms": 29, - "ecosystem": "cargo", - "package": "postcard@1.1.3", - "sections": 22, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/postcard-1.1.3", - "symbols": 93 - }, - { - "build_ms": 134, - "ecosystem": "cargo", - "package": "rayon@1.12.0", - "sections": 134, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rayon-1.12.0", - "symbols": 315 - }, - { - "build_ms": 85, - "ecosystem": "cargo", - "package": "serde@1.0.229", - "sections": 23, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde-1.0.229", - "symbols": 216 - }, - { - "build_ms": 83, - "ecosystem": "cargo", - "package": "serde_json@1.0.151", - "sections": 50, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde_json-1.0.151", - "symbols": 271 - }, - { - "build_ms": 28, - "ecosystem": "cargo", - "package": "tar@0.4.46", - "sections": 7, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tar-0.4.46", - "symbols": 223 - }, - { - "build_ms": 45, - "ecosystem": "cargo", - "package": "toml@1.1.6+spec-1.1.0", - "sections": 15, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/toml-1.1.6+spec-1.1.0", - "symbols": 132 - }, - { - "build_ms": 49, - "ecosystem": "cargo", - "package": "toml_edit@0.23.10+spec-1.0.0", - "sections": 15, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/toml_edit-0.23.10+spec-1.0.0", - "symbols": 389 - }, - { - "build_ms": 1, - "ecosystem": "cargo", - "package": "tree-sitter@0.27.0", - "sections": 12, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-0.27.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-go@0.25.0", - "sections": 1, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-go-0.25.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-python@0.25.0", - "sections": 2, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-python-0.25.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-rust@0.24.2", - "sections": 3, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-rust-0.24.2", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-typescript@0.23.2", - "sections": 1, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-typescript-0.23.2", - "symbols": 0 - }, - { - "build_ms": 85, - "ecosystem": "cargo", - "package": "ureq@3.4.2", - "sections": 150, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ureq-3.4.2", - "symbols": 348 - }, - { - "build_ms": 28, - "ecosystem": "cargo", - "package": "yaml-rust2@0.13.0", - "sections": 46, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/yaml-rust2-0.13.0", - "symbols": 66 - }, - { - "build_ms": 173, - "ecosystem": "cargo", - "package": "zip@8.6.0", - "sections": 214, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/zip-8.6.0", - "symbols": 346 - } - ] - } - }, - "zod4": { - "ms": 51, - "report": { - "missing": [ - { - "error": "tempfile@3.27.0 is pinned in /home/runner/work/lockdocs/lockdocs/Cargo.lock but its files are not on this machine: run `cargo fetch`, or enable fetching (--fetch or LOCKDOCS_FETCH=1) to download exactly this version.", - "package": "tempfile@3.27.0" - } - ], - "ms": 44, - "packages": [ - { - "build_ms": 42, - "ecosystem": "npm", - "package": "zod@4.1.5", - "sections": 8, - "source": "node_modules/zod", - "symbols": 3164 - }, - { - "build_ms": 159, - "ecosystem": "cargo", - "package": "anyhow@1.0.104", - "sections": 14, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/anyhow-1.0.104", - "symbols": 55 - }, - { - "build_ms": 4, - "ecosystem": "cargo", - "package": "dirs@6.0.0", - "sections": 18, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/dirs-6.0.0", - "symbols": 95 - }, - { - "build_ms": 43, - "ecosystem": "cargo", - "package": "flate2@1.1.10", - "sections": 23, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/flate2-1.1.10", - "symbols": 333 - }, - { - "build_ms": 29, - "ecosystem": "cargo", - "package": "postcard@1.1.3", - "sections": 22, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/postcard-1.1.3", - "symbols": 93 - }, - { - "build_ms": 134, - "ecosystem": "cargo", - "package": "rayon@1.12.0", - "sections": 134, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rayon-1.12.0", - "symbols": 315 - }, - { - "build_ms": 85, - "ecosystem": "cargo", - "package": "serde@1.0.229", - "sections": 23, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde-1.0.229", - "symbols": 216 - }, - { - "build_ms": 83, - "ecosystem": "cargo", - "package": "serde_json@1.0.151", - "sections": 50, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde_json-1.0.151", - "symbols": 271 - }, - { - "build_ms": 28, - "ecosystem": "cargo", - "package": "tar@0.4.46", - "sections": 7, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tar-0.4.46", - "symbols": 223 - }, - { - "build_ms": 45, - "ecosystem": "cargo", - "package": "toml@1.1.6+spec-1.1.0", - "sections": 15, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/toml-1.1.6+spec-1.1.0", - "symbols": 132 - }, - { - "build_ms": 49, - "ecosystem": "cargo", - "package": "toml_edit@0.23.10+spec-1.0.0", - "sections": 15, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/toml_edit-0.23.10+spec-1.0.0", - "symbols": 389 - }, - { - "build_ms": 1, - "ecosystem": "cargo", - "package": "tree-sitter@0.27.0", - "sections": 12, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-0.27.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-go@0.25.0", - "sections": 1, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-go-0.25.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-python@0.25.0", - "sections": 2, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-python-0.25.0", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-rust@0.24.2", - "sections": 3, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-rust-0.24.2", - "symbols": 0 - }, - { - "build_ms": 0, - "ecosystem": "cargo", - "package": "tree-sitter-typescript@0.23.2", - "sections": 1, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tree-sitter-typescript-0.23.2", - "symbols": 0 - }, - { - "build_ms": 85, - "ecosystem": "cargo", - "package": "ureq@3.4.2", - "sections": 150, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ureq-3.4.2", - "symbols": 348 - }, - { - "build_ms": 28, - "ecosystem": "cargo", - "package": "yaml-rust2@0.13.0", - "sections": 46, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/yaml-rust2-0.13.0", - "symbols": 66 - }, - { - "build_ms": 173, - "ecosystem": "cargo", - "package": "zip@8.6.0", - "sections": 214, - "source": "~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/zip-8.6.0", - "symbols": 346 - } - ] - } - } - }, - "rows": [ - { - "id": "zod3-strict", - "project": "zod3", - "package": "zod", - "version": "3.23.8", - "question": "How do I reject unknown keys in an object schema?", - "why": "v3: .strict() on ZodObject", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1719, - "ms": 5.0 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 685, - "ms": 2552, - "library": "/colinhacks/zod/v3.24.2", - "version_match": "same major" - } - }, - { - "id": "zod4-strict", - "project": "zod4", - "package": "zod", - "version": "4.1.5", - "question": "How do I reject unknown keys in an object schema?", - "why": "v4: z.strictObject() (.strict() is legacy)", - "lockdocs": { - "pass": false, - "missing": [ - [ - "strictObject" - ] - ], - "rejected": [], - "tokens": 1829, - "ms": 9.5 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 688, - "ms": 2620, - "library": "/colinhacks/zod/v4.0.1", - "version_match": "same major" - } - }, - { - "id": "zod3-email", - "project": "zod3", - "package": "zod", - "version": "3.23.8", - "question": "How do I validate that a string is an email address?", - "why": "v3: z.string().email(); top-level z.email() does not exist", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1701, - "ms": 5.5 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1576, - "ms": 1324, - "library": "/colinhacks/zod/v3.24.2", - "version_match": "same major" - } - }, - { - "id": "zod4-email", - "project": "zod4", - "package": "zod", - "version": "4.1.5", - "question": "How do I validate that a string is an email address?", - "why": "v4: top-level z.email()", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 2030, - "ms": 9.7 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1328, - "ms": 1591, - "library": "/colinhacks/zod/v4.0.1", - "version_match": "same major" - } - }, - { - "id": "zod3-error", - "project": "zod3", - "package": "zod", - "version": "3.23.8", - "question": "How do I customize the error message when validation fails?", - "why": "v3: message / required_error / errorMap params", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1602, - "ms": 5.3 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 893, - "ms": 1723, - "library": "/colinhacks/zod/v3.24.2", - "version_match": "same major" - } - }, - { - "id": "zod4-error", - "project": "zod4", - "package": "zod", - "version": "4.1.5", - "question": "How do I customize the error message when validation fails?", - "why": "v4: unified `error` param; required_error removed", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1842, - "ms": 9.4 - }, - "context7": { - "pass": false, - "missing": [], - "rejected": [ - "required_error" - ], - "tokens": 846, - "ms": 1459, - "library": "/colinhacks/zod/v4.0.1", - "version_match": "same major" - } - }, - { - "id": "zod4-record", - "project": "zod4", - "package": "zod", - "version": "4.1.5", - "question": "How do I define a record schema with string keys and number values?", - "why": "v4: z.record(keySchema, valueSchema)", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1771, - "ms": 9.5 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 811, - "ms": 1656, - "library": "/colinhacks/zod/v4.0.1", - "version_match": "same major" - } - }, - { - "id": "next14-cookies", - "project": "next14", - "package": "next", - "version": "14.2.15", - "question": "Is cookies() from next/headers synchronous or does it return a Promise?", - "why": "14: cookies() returns ReadonlyRequestCookies synchronously", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1480, - "ms": 15.6 - }, - "context7": { - "pass": false, - "missing": [ - [ - "ReadonlyRequestCookies" - ] - ], - "rejected": [], - "tokens": 987, - "ms": 2974, - "library": "/vercel/next.js/v14.3.0-canary.87", - "version_match": "same major" - } - }, - { - "id": "next15-cookies", - "project": "next15", - "package": "next", - "version": "15.1.0", - "question": "Is cookies() from next/headers synchronous or does it return a Promise?", - "why": "15: cookies() is async", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1351, - "ms": 18.4 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 980, - "ms": 2950, - "library": "/vercel/next.js/v15.1.11", - "version_match": "same major" - } - }, - { - "id": "next14-headers", - "project": "next14", - "package": "next", - "version": "14.2.15", - "question": "How do I read the incoming request headers in a server component?", - "why": "14: headers() is sync", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1405, - "ms": 15.3 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1119, - "ms": 1703, - "library": "/vercel/next.js/v14.3.0-canary.87", - "version_match": "same major" - } - }, - { - "id": "next15-headers", - "project": "next15", - "package": "next", - "version": "15.1.0", - "question": "How do I read the incoming request headers in a server component?", - "why": "15: headers() is async", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1400, - "ms": 19.7 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 918, - "ms": 2366, - "library": "/vercel/next.js/v15.1.11", - "version_match": "same major" - } - }, - { - "id": "next14-nostore", - "project": "next14", - "package": "next", - "version": "14.2.15", - "question": "How do I opt a server component out of caching so it renders dynamically?", - "why": "14: unstable_noStore()", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1468, - "ms": 15.4 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 979, - "ms": 1678, - "library": "/vercel/next.js/v14.3.0-canary.87", - "version_match": "same major" - } - }, - { - "id": "next15-connection", - "project": "next15", - "package": "next", - "version": "15.1.0", - "question": "How do I opt a server component out of caching so it renders dynamically?", - "why": "15: connection() (unstable_noStore deprecated)", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1464, - "ms": 18.1 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1198, - "ms": 1489, - "library": "/vercel/next.js/v15.1.11", - "version_match": "same major" - } - }, - { - "id": "next15-after", - "project": "next15", - "package": "next", - "version": "15.1.0", - "question": "How do I run code after the response has finished streaming?", - "why": "15.1: after() from next/server (unstable_after in 15.0)", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1446, - "ms": 18.3 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1951, - "ms": 1665, - "library": "/vercel/next.js/v15.1.11", - "version_match": "same major" - } - }, - { - "id": "rr6-json", - "project": "rr6", - "package": "react-router", - "version": "6.26.2", - "question": "How do I return data with a custom HTTP status code from a loader?", - "why": "v6: json() helper", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1481, - "ms": 3.8 - }, - "context7": { - "pass": false, - "missing": [ - [ - "json(" - ] - ], - "rejected": [], - "tokens": 606, - "ms": 2420, - "library": "/websites/reactrouter", - "version_match": "unversioned" - } - }, - { - "id": "rr7-data", - "project": "rr7", - "package": "react-router", - "version": "7.1.1", - "question": "How do I return data with a custom HTTP status code from a loader?", - "why": "v7: data() helper (json() deprecated)", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1586, - "ms": 7.2 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 572, - "ms": 2711, - "library": "/websites/reactrouter", - "version_match": "unversioned" - } - }, - { - "id": "rr6-defer", - "project": "rr6", - "package": "react-router", - "version": "6.26.2", - "question": "How do I stream slow data from a loader with deferred values?", - "why": "v6: defer() + ", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1508, - "ms": 3.7 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 975, - "ms": 1515, - "library": "/websites/reactrouter", - "version_match": "unversioned" - } - }, - { - "id": "rr6-future", - "project": "rr6", - "package": "react-router", - "version": "6.26.2", - "question": "Which future flag enables React.startTransition for state updates?", - "why": "v6.26: future.v7_startTransition", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1559, - "ms": 3.8 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 420, - "ms": 1415, - "library": "/websites/reactrouter", - "version_match": "unversioned" - } - }, - { - "id": "rr7-router", - "project": "rr7", - "package": "react-router", - "version": "7.1.1", - "question": "How do I create a browser router with data loaders?", - "why": "v7: createBrowserRouter from react-router", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1490, - "ms": 7.1 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1220, - "ms": 1985, - "library": "/websites/reactrouter", - "version_match": "unversioned" - } - }, - { - "id": "pyd1-dict", - "project": "pydantic1", - "package": "pydantic", - "version": "1.10.18", - "question": "How do I convert a model instance to a dict?", - "why": "v1: .dict()", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1532, - "ms": 17.0 - }, - "context7": { - "pass": false, - "missing": [ - [ - ".dict(", - "def dict(" - ] - ], - "rejected": [ - "model_dump" - ], - "tokens": 908, - "ms": 2975, - "library": "/pydantic/pydantic", - "version_match": "unversioned" - } - }, - { - "id": "pyd2-dict", - "project": "pydantic2", - "package": "pydantic", - "version": "2.9.2", - "question": "How do I convert a model instance to a dict?", - "why": "v2: .model_dump()", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1437, - "ms": 20.3 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 839, - "ms": 3001, - "library": "/pydantic/pydantic", - "version_match": "unversioned" - } - }, - { - "id": "pyd1-parse", - "project": "pydantic1", - "package": "pydantic", - "version": "1.10.18", - "question": "How do I create a model from a dict and validate it?", - "why": "v1: Model.parse_obj()", - "lockdocs": { - "pass": false, - "missing": [ - [ - "parse_obj" - ] - ], - "rejected": [], - "tokens": 1620, - "ms": 17.1 - }, - "context7": { - "pass": false, - "missing": [ - [ - "parse_obj" - ] - ], - "rejected": [ - "model_validate" - ], - "tokens": 2146, - "ms": 3102, - "library": "/pydantic/pydantic", - "version_match": "unversioned" - } - }, - { - "id": "pyd2-parse", - "project": "pydantic2", - "package": "pydantic", - "version": "2.9.2", - "question": "How do I create a model from a dict and validate it?", - "why": "v2: Model.model_validate()", - "lockdocs": { - "pass": false, - "missing": [ - [ - "model_validate" - ] - ], - "rejected": [], - "tokens": 1543, - "ms": 20.4 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 2146, - "ms": 1350, - "library": "/pydantic/pydantic", - "version_match": "unversioned" - } - }, - { - "id": "pyd1-validator", - "project": "pydantic1", - "package": "pydantic", - "version": "1.10.18", - "question": "How do I add a custom validator for a field?", - "why": "v1: @validator", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1577, - "ms": 17.0 - }, - "context7": { - "pass": false, - "missing": [ - [ - "@validator", - "def validator(" - ] - ], - "rejected": [ - "field_validator" - ], - "tokens": 1201, - "ms": 2932, - "library": "/pydantic/pydantic", - "version_match": "unversioned" - } - }, - { - "id": "pyd2-validator", - "project": "pydantic2", - "package": "pydantic", - "version": "2.9.2", - "question": "How do I add a custom validator for a field?", - "why": "v2: @field_validator", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1386, - "ms": 20.3 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1207, - "ms": 1608, - "library": "/pydantic/pydantic", - "version_match": "unversioned" - } - }, - { - "id": "pyd1-schema", - "project": "pydantic1", - "package": "pydantic", - "version": "1.10.18", - "question": "How do I get the JSON schema of a model?", - "why": "v1: Model.schema() / schema_json()", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1525, - "ms": 17.1 - }, - "context7": { - "pass": false, - "missing": [ - [ - "schema_json", - "def schema(", - ".schema(" - ] - ], - "rejected": [ - "model_json_schema" - ], - "tokens": 1742, - "ms": 2395, - "library": "/pydantic/pydantic", - "version_match": "unversioned" - } - }, - { - "id": "pyd2-schema", - "project": "pydantic2", - "package": "pydantic", - "version": "2.9.2", - "question": "How do I get the JSON schema of a model?", - "why": "v2: Model.model_json_schema()", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1449, - "ms": 20.1 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1618, - "ms": 1458, - "library": "/pydantic/pydantic", - "version_match": "unversioned" - } - }, - { - "id": "pyd1-config", - "project": "pydantic1", - "package": "pydantic", - "version": "1.10.18", - "question": "How do I allow extra fields on a model?", - "why": "v1: class Config: extra = Extra.allow", - "lockdocs": { - "pass": false, - "missing": [ - [ - "Extra.allow", - "class Config" - ] - ], - "rejected": [], - "tokens": 1540, - "ms": 16.8 - }, - "context7": { - "pass": false, - "missing": [], - "rejected": [ - "ConfigDict" - ], - "tokens": 819, - "ms": 1512, - "library": "/pydantic/pydantic", - "version_match": "unversioned" - } - }, - { - "id": "pyd2-config", - "project": "pydantic2", - "package": "pydantic", - "version": "2.9.2", - "question": "How do I allow extra fields on a model?", - "why": "v2: model_config = ConfigDict(extra='allow')", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1527, - "ms": 20.1 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 683, - "ms": 1768, - "library": "/pydantic/pydantic", - "version_match": "unversioned" - } - }, - { - "id": "axum07-path", - "project": "axum07", - "package": "axum", - "version": "0.7.9", - "question": "How do I declare a route with a path parameter?", - "why": "0.7: /users/:id", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1581, - "ms": 6.5 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1674, - "ms": 2514, - "library": "/tokio-rs/axum", - "version_match": "unversioned" - } - }, - { - "id": "axum08-path", - "project": "axum08", - "package": "axum", - "version": "0.8.1", - "question": "How do I declare a route with a path parameter?", - "why": "0.8: /users/{id}", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1573, - "ms": 6.8 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1465, - "ms": 2160, - "library": "/tokio-rs/axum", - "version_match": "unversioned" - } - }, - { - "id": "axum07-extractor", - "project": "axum07", - "package": "axum", - "version": "0.7.9", - "question": "How do I implement a custom extractor with FromRequestParts?", - "why": "0.7: #[async_trait] on the impl", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1512, - "ms": 6.5 - }, - "context7": { - "pass": false, - "missing": [ - [ - "async_trait" - ] - ], - "rejected": [], - "tokens": 1652, - "ms": 1666, - "library": "/tokio-rs/axum", - "version_match": "unversioned" - } - }, - { - "id": "axum08-optional", - "project": "axum08", - "package": "axum", - "version": "0.8.1", - "question": "How do I make an extractor optional with Option?", - "why": "0.8: OptionalFromRequestParts", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1479, - "ms": 6.6 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 469, - "ms": 1569, - "library": "/tokio-rs/axum", - "version_match": "unversioned" - } - }, - { - "id": "tokio-blocking", - "project": "axum08", - "package": "tokio", - "version": "1.43.0", - "question": "How do I run blocking code without blocking the async runtime?", - "why": "tokio::task::spawn_blocking", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1435, - "ms": 17.7 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 789, - "ms": 2347, - "library": "/websites/rs_tokio_tokio", - "version_match": "unversioned" - } - }, - { - "id": "tokio-select", - "project": "axum08", - "package": "tokio", - "version": "1.43.0", - "question": "How do I wait on several futures and take whichever finishes first?", - "why": "tokio::select!", - "lockdocs": { - "pass": false, - "missing": [ - [ - "select!" - ] - ], - "rejected": [], - "tokens": 1574, - "ms": 17.9 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 498, - "ms": 1405, - "library": "/websites/rs_tokio_tokio", - "version_match": "unversioned" - } - }, - { - "id": "tokio-timeout", - "project": "axum08", - "package": "tokio", - "version": "1.43.0", - "question": "How do I put a timeout on a future?", - "why": "tokio::time::timeout", - "lockdocs": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 1531, - "ms": 17.5 - }, - "context7": { - "pass": true, - "missing": [], - "rejected": [], - "tokens": 921, - "ms": 1295, - "library": "/websites/rs_tokio_tokio", - "version_match": "unversioned" - } - } - ], - "summary": { - "lockdocs": { - "answered": 36, - "passed": 31, - "total": 36, - "median_tokens": 1531, - "median_ms": 15.6, - "p95_ms": 20.3 - }, - "context7": { - "answered": 36, - "passed": 27, - "total": 36, - "median_tokens": 979, - "median_ms": 1723, - "p95_ms": 3001 - } - }, - "context7_calls": { - "calls": 47, - "rate_limited": 0, - "errors": 0, - "stopped": false, - "limit": "200", - "remaining": "147" - }, - "runner": { - "os": "Linux", - "machine": "x86_64" - } -} \ No newline at end of file diff --git a/crates/lockdocs-core/Cargo.toml b/crates/lockdocs-core/Cargo.toml index 22986e1..67302a5 100644 --- a/crates/lockdocs-core/Cargo.toml +++ b/crates/lockdocs-core/Cargo.toml @@ -13,7 +13,7 @@ rayon = "1" serde = { version = "1", features = ["derive"] } serde_json = "1" postcard = { version = "1", features = ["use-std"] } -dirs = "6" +dirs = "7" toml = "1" yaml-rust2 = "0.13" tree-sitter = "0.27" @@ -24,7 +24,7 @@ tree-sitter-rust = "0.24" ureq = "3" flate2 = "1" tar = "0.4" -sha2 = "0.10" +sha2 = "0.11" zip = { version = "8", default-features = false, features = ["deflate-flate2-zlib-rs"] } [dev-dependencies] diff --git a/crates/lockdocs-core/src/embed.rs b/crates/lockdocs-core/src/embed.rs index f5da2ae..610bcfa 100644 --- a/crates/lockdocs-core/src/embed.rs +++ b/crates/lockdocs-core/src/embed.rs @@ -127,7 +127,7 @@ pub fn ensure() -> Result<()> { total += n as u64; } drop(file); - let got = format!("{:x}", hasher.finalize()); + let got: String = hasher.finalize().iter().map(|b| format!("{b:02x}")).collect(); if got != WEIGHTS_SHA256 || total != WEIGHTS_BYTES { let _ = std::fs::remove_file(&tmp); bail!("model download failed verification (sha256 {got}, {total} bytes)"); diff --git a/crates/lockdocs/Cargo.toml b/crates/lockdocs/Cargo.toml index d61af47..e663ac7 100644 --- a/crates/lockdocs/Cargo.toml +++ b/crates/lockdocs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lockdocs" -description = "Exact-version library docs for AI agents, straight from your lockfile, offline. MCP server + CLI." +description = "Exact-version library docs from your lockfile — local, offline, no rate limits." version.workspace = true edition.workspace = true license.workspace = true @@ -15,5 +15,5 @@ path = "src/main.rs" anyhow = "1" lockdocs-core = { path = "../lockdocs-core" } serde_json = "1" -toml_edit = "0.23" -dirs = "6" +toml_edit = "0.25" +dirs = "7" diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 2817da9..7829bb1 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -1,7 +1,7 @@ import { defineConfig } from 'vitepress' const url = 'https://sylphxai.github.io/lockdocs/' -const desc = 'Context7 without rate limits: exact-version library docs for AI agents, straight from your lockfile, offline. MCP server + CLI for npm, PyPI, crates.io and Go. MIT.' +const desc = 'Exact-version library docs from your lockfile — local, offline, no rate limits.' const icon = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect x='6' y='14' width='20' height='14' rx='3' fill='%237c9cff'/%3E%3Cpath d='M10 14V10a6 6 0 0 1 12 0v4' fill='none' stroke='%2342d6a4' stroke-width='3'/%3E%3Crect x='11' y='18' width='10' height='2' rx='1' fill='%2306080c'/%3E%3Crect x='11' y='22' width='7' height='2' rx='1' fill='%2306080c'/%3E%3C/svg%3E" export default defineConfig({ @@ -16,7 +16,7 @@ export default defineConfig({ ['meta', { name: 'theme-color', content: '#06080c' }], ['link', { rel: 'canonical', href: url }], ['meta', { property: 'og:type', content: 'website' }], - ['meta', { property: 'og:title', content: 'lockdocs: exact-version library docs for AI agents' }], + ['meta', { property: 'og:title', content: 'lockdocs' }], ['meta', { property: 'og:description', content: desc }], ['meta', { property: 'og:url', content: url }], ['meta', { property: 'og:image', content: `${url}img/demo.gif` }], diff --git a/docs/index.md b/docs/index.md index 75f199c..60c7185 100644 --- a/docs/index.md +++ b/docs/index.md @@ -3,7 +3,7 @@ layout: home hero: name: lockdocs text: The docs for the version you actually installed. - tagline: Context7 without rate limits. lockdocs reads your lockfile and answers your AI agent from the installed packages' own docs and type declarations. npm, PyPI, crates.io, Go. Offline. No API key. MIT. + tagline: Exact-version library docs from your lockfile — local, offline, no rate limits. actions: - theme: brand text: npx -y @sylphx/lockdocs setup @@ -23,7 +23,7 @@ features: details: READMEs, changelogs and docs folders, plus API reference from .d.ts + JSDoc, Python docstrings, rustdoc and Go doc comments. Private packages included. - icon: ✈️ title: Offline and unlimited - details: Everything comes from node_modules, your virtualenv, the Cargo registry and the Go module cache. No network, no account, no rate limit. + details: Everything comes from node_modules, your virtualenv, the Cargo registry and the Go module cache. Offline after a one-time model download; keyword-only needs no network. No account, no rate limit. - icon: 🎯 title: Small, cited answers details: Hybrid search (BM25 + a small local embedding model) over symbols and sections, packed into a 1,200-token budget by default, every section cited as package@version path:line. diff --git a/packages/lockdocs/package.json b/packages/lockdocs/package.json index 77d4cbd..ae068e5 100644 --- a/packages/lockdocs/package.json +++ b/packages/lockdocs/package.json @@ -2,7 +2,7 @@ "name": "@sylphx/lockdocs", "version": "0.2.0", "mcpName": "io.github.SylphxAI/lockdocs", - "description": "Context7 without rate limits: exact-version library docs for AI agents, straight from your lockfile, offline. MCP server + CLI (Rust). npm, PyPI, crates.io, Go.", + "description": "Exact-version library docs from your lockfile — local, offline, no rate limits.", "bin": { "lockdocs": "bin/lockdocs.js" }, diff --git a/scripts/check-tagline.ts b/scripts/check-tagline.ts new file mode 100644 index 0000000..8425442 --- /dev/null +++ b/scripts/check-tagline.ts @@ -0,0 +1,20 @@ +// One tagline everywhere. Source: packages/lockdocs/package.json "description". +// Checks the README lead, the docs hero and meta description, server.json and +// the crate description; CI also compares the GitHub repository description. +import { readFileSync } from "node:fs"; + +const t: string = JSON.parse(readFileSync("packages/lockdocs/package.json", "utf8")).description; +const bad: string[] = []; +const has = (file: string, needle: string) => readFileSync(file, "utf8").includes(needle) || bad.push(`${file} lacks: ${needle}`); +has("README.md", `**${t}**`); +has("docs/index.md", `tagline: ${t}`); +has("docs/.vitepress/config.ts", `const desc = '${t}'`); +has("crates/lockdocs/Cargo.toml", `description = "${t}"`); +if (JSON.parse(readFileSync("server.json", "utf8")).description !== t) bad.push("server.json description differs"); +const gh = process.argv[2]; +if (gh !== undefined && gh.trim() !== t) bad.push(`GitHub description differs: ${gh.trim()}`); +if (bad.length) { + console.error(`tagline mismatch (want "${t}"):\n ${bad.join("\n ")}`); + process.exit(1); +} +console.log(`tagline consistent: ${t}`); diff --git a/server.json b/server.json index 2153e4d..0a09e44 100644 --- a/server.json +++ b/server.json @@ -2,7 +2,7 @@ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json", "name": "io.github.SylphxAI/lockdocs", "title": "lockdocs", - "description": "Exact-version library docs from your lockfile, offline. No rate limits, private packages work.", + "description": "Exact-version library docs from your lockfile — local, offline, no rate limits.", "repository": { "url": "https://github.com/SylphxAI/lockdocs", "source": "github"