diff --git a/.gitignore b/.gitignore index 688d41c..52c1776 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,8 @@ # Generated artifacts -codeindex.json +blastradius.json symbolindex.json repo_graph.json -symbolindex.json -.codeindex/ +.blastradius/ benchmark/results.json # Claude Code diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..f69eb73 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,36 @@ +# AGENTS.md + +## Developer Commands & Verification + +- **Run tests**: `uv run pytest` (set `$env:PYTHONPATH="."` if running outside an installed venv). +- **Run single test**: `uv run pytest tests/test_phase1.py` or `uv run pytest -k `. +- **Run CLI in dev**: `uv run python -m blastradius.cli ` or `uv run blastradius `. +- **Environment note**: Avoid system `pip` or system `python` if broken; prefer `uv run` or `.venv\Scripts\` execution. + +## Core Architecture & Package Structure + +- **Package name**: `blastradius` (source in `blastradius/`). Entry point: `blastradius.cli:main`. +- **Index artifacts**: Default dependency graph is written to `blastradius.json`; SQLite store is populated at `/.blastradius/index.db`. +- **Layering rule**: `blastradius.store`, `blastradius.temporal`, and core modules must **never** import from `blastradius.semantic` or `blastradius.analyzers`. +- **Backward compatibility**: The `blastradius.json` file export schema is frozen. SQLite DB synchronization is an additive side-effect of `index.build()`. + +## Storage & Database Gotchas (`blastradius/store/db.py`) + +- **FTS5 table**: Must remain a standalone table without the `content=` option. Using `content='symbols'` triggers `database disk image is malformed` errors during deletes in WAL mode. +- **Soft deletes**: `sync()` must set `last_seen_commit` on soft-delete for temporal `--as-of` queries to filter correctly. +- **SQLite transactions**: `executescript()` auto-commits pending transactions in Python `sqlite3`. Keep regular DDL and FTS DDL in separate `executescript()` calls. +- **`sqlite-vec` optional dependency**: Never import `sqlite_vec` at module top-level. Wrap imports in `try...except` for runtime feature detection and graceful fallback to FTS5 + graph search. + +## Temporal Layer (`blastradius/temporal/history.py`) + +- **Git history reading**: `backfill()` streams commit history using `git ls-tree` and `git cat-file --batch`. Do not replace this with `git checkout` or individual `git show` calls. + +## Coding Conventions + +- **Module header**: Every Python file starts with: + ```python + # Copyright 2026 David Scheiderman + # Licensed under the Apache License, Version 2.0 + from __future__ import annotations + ``` +- **Python version**: Targets Python 3.9+. Modern union (`X | Y`) and generic types (`list[str]`) are enabled via `from __future__ import annotations`. diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e1cc6e..2f5c422 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ All notable changes to this project will be documented in this file. ### Added -- **`codeindex symbol-blast `** — per-export blast radius for a file. Lists every +- **`blastradius symbol-blast `** — per-export blast radius for a file. Lists every exported symbol with a count and list of which importer files reference it by name. Answers "which routes use each export from lib/db/schema.ts" without manual grep. Supports `--json` for programmatic use. @@ -46,10 +46,10 @@ All notable changes to this project will be documented in this file. ### Fixed -- **`lookup` reads SQLite DB** — `codeindex lookup` and the `lookup_symbol` MCP tool - previously read `symbolindex.json`, which is only written by `codeindex symbols`. +- **`lookup` reads SQLite DB** — `blastradius lookup` and the `lookup_symbol` MCP tool + previously read `symbolindex.json`, which is only written by `blastradius symbols`. Both now query `Store.lookup_by_name()` from the SQLite DB (the same source as - `codeindex search`), falling back to `symbolindex.json` only when no DB is present. + `blastradius search`), falling back to `symbolindex.json` only when no DB is present. Symbols found via search — including those extracted from destructured re-exports — are now consistently reachable via lookup. - **`lookup` output shows symbol name** — plain-mode output was `auth.ts:8 (const)`; @@ -69,9 +69,9 @@ All notable changes to this project will be documented in this file. genuine API surfaces with broad real coupling. - **`changed-since` edge origin annotation** — added edges now carry `first_seen_commit`; when N edges share the `last_indexed_commit` value, the CLI prints a count. The message - branches on whether `codeindex history` has been run: - - History not run: `"run codeindex history to date them accurately"` - - History run: `"bootstrap-gap artifacts: existed before the first codeindex analyze + branches on whether `blastradius history` has been run: + - History not run: `"run blastradius history to date them accurately"` + - History run: `"bootstrap-gap artifacts: existed before the first blastradius analyze and cannot be dated further"` — correctly reflects the inherent limitation rather than implying a fixable error. MCP response gains `bootstrap_gap` boolean. @@ -113,11 +113,11 @@ All notable changes to this project will be documented in this file. when FTS (or semantic KNN) already returns ≥ k results, preventing structurally adjacent but semantically unrelated symbols from diluting high-quality keyword hits. -- **Search file aggregation** — `codeindex search` and the `semantic_search` +- **Search file aggregation** — `blastradius search` and the `semantic_search` MCP tool now include a `Files` section aggregating results by file (sorted by symbol hit count). The entry-point file appears even when no single symbol from it ranks at the top. -- **`db status` FTS row count** — `codeindex db status` now shows +- **`db status` FTS row count** — `blastradius db status` now shows `fts_symbols` (rows in `symbols_fts`) making it easy to diagnose whether the FTS index is populated. @@ -125,22 +125,22 @@ All notable changes to this project will be documented in this file. ### Fixed -- **Multi-word FTS search OR fallback** — `codeindex search "auth token"` previously +- **Multi-word FTS search OR fallback** — `blastradius search "auth token"` previously returned nothing when AND semantics found no single symbol containing all words. `fts_search()` now retries with `word1 OR word2 OR ...` automatically when the AND query returns zero results. -- **`changed-since` backfill warning** — when `codeindex history` has never been run, +- **`changed-since` backfill warning** — when `blastradius history` has never been run, all files share exactly one `first_seen_commit`, making `changed-since` results inaccurate against any older ref. The command now detects this via `COUNT(DISTINCT first_seen_commit) <= 1` and prints a clear warning on stderr (CLI) / includes a `"warning"` key in the response (JSON + MCP tool) directing - the user to run `codeindex history` first. + the user to run `blastradius history` first. ## [0.3.0] - 2026-06-07 ### Summary -codeindex evolves from a stateless point-in-time dependency analyzer into a +blastradius evolves from a stateless point-in-time dependency analyzer into a **temporal code knowledge graph** — persistent, incremental, and semantically queryable. Three new properties: persistence + incrementality, time, and meaning (semantic retrieval). All existing CLI commands, JSON schemas, and MCP @@ -149,36 +149,36 @@ tools are unchanged. ### Added #### Persistent SQLite store (Phase 1) -- `.codeindex/index.db` — SQLite graph store created automatically on - `codeindex analyze`; survives across runs, never touches `codeindex.json` +- `.blastradius/index.db` — SQLite graph store created automatically on + `blastradius analyze`; survives across runs, never touches `blastradius.json` - Incremental indexing: detects changed files via `git diff --name-status` between index runs; logs changed file count to stderr -- `codeindex db status` — schema version, last indexed commit, file/edge/symbol counts -- `codeindex db migrate` — applies pending schema migrations (runs automatically on open) -- `codeindex symbols` now syncs symbols to DB with FTS5 full-text index +- `blastradius db status` — schema version, last indexed commit, file/edge/symbol counts +- `blastradius db migrate` — applies pending schema migrations (runs automatically on open) +- `blastradius symbols` now syncs symbols to DB with FTS5 full-text index #### Temporal layer (Phase 2) - Every file, edge, and symbol carries `first_seen_commit` / `last_seen_commit` — facts are never hard-deleted, only soft-deleted with temporal stamps -- `codeindex history [--since REF] [--max-commits N]` — backfills temporal +- `blastradius history [--since REF] [--max-commits N]` — backfills temporal data from git history without any working-tree checkouts (uses `git ls-tree` + `git cat-file --batch`) -- `codeindex changed-since ` — files and edges added or removed since a +- `blastradius changed-since ` — files and edges added or removed since a commit, branch, or tag -- `codeindex impact --as-of ` — blast radius at a historical point +- `blastradius impact --as-of ` — blast radius at a historical point in time, not just HEAD #### Semantic layer (Phase 3) -- `codeindex search "" [--k N] [--as-of REF] [--json]` — hybrid +- `blastradius search "" [--k N] [--as-of REF] [--json]` — hybrid semantic + FTS5 keyword + graph expansion search, fused with Reciprocal Rank Fusion (RRF) -- `codeindex/semantic/provider.py` — `EmbeddingProvider` ABC + +- `blastradius/semantic/provider.py` — `EmbeddingProvider` ABC + `OpenAIEmbeddingProvider` HTTP client (stdlib `urllib` only, no new runtime deps) - `sqlite-vec` optional extension for KNN vector search; absent = graceful fallback to FTS + graph with a clear notice (no crash, no config required) -- Embeddings generated automatically during `codeindex analyze` when - `CODEINDEX_EMBEDDING_ENDPOINT` / `_MODEL` / `_DIMS` env vars are set -- `codeindex[semantic]` extra: `pip install 'codeindex[semantic]'` +- Embeddings generated automatically during `blastradius analyze` when + `BLASTRADIUS_EMBEDDING_ENDPOINT` / `_MODEL` / `_DIMS` env vars are set +- `blastradius[semantic]` extra: `pip install 'blastradius[semantic]'` #### MCP surface (Phase 4) — 4 new tools, existing 6 unchanged - `semantic_search` — hybrid search from an MCP client; degrades gracefully @@ -190,18 +190,18 @@ tools are unchanged. - `schema_version` bumped to `"2"` with forward migration from `"1"` - FTS5 `symbols_fts` rowid now equals `symbols.id` (enables direct FTS → symbol row mapping without a secondary lookup) -- `codeindex db status` output extended with `embedding_model`, `embedding_dims`, +- `blastradius db status` output extended with `embedding_model`, `embedding_dims`, `vec_symbols` fields - README rewritten to document all new commands, the SQLite store, semantic setup, and the full 10-tool MCP surface ### Internal -- `codeindex/store/db.py`: `Store` class — `init_vectors()`, `upsert_embeddings()`, +- `blastradius/store/db.py`: `Store` class — `init_vectors()`, `upsert_embeddings()`, `semantic_search()`, `fts_search()`, `graph_expand()`, `neighborhood()`, `symbol_visible_at()`, `get_symbol()`, `symbols_needing_embeddings()` -- `codeindex/temporal/history.py`: `backfill()` — BFS over git log via plumbing +- `blastradius/temporal/history.py`: `backfill()` — BFS over git log via plumbing commands; no checkout side-effects -- `codeindex/semantic/search.py`: `hybrid_search()` with RRF fusion +- `blastradius/semantic/search.py`: `hybrid_search()` with RRF fusion - Dependency direction enforced: `store/` and `temporal/` never import from `semantic/` or `graph/` - 7 new Phase 3 tests; 6 Phase 2 tests; 5 Phase 1 tests (18 total, all green) @@ -209,9 +209,9 @@ tools are unchanged. ## [0.2.0] - 2026-05-24 ### Added -- `codeindex lookup ` — find where a symbol is defined (file + line) -- `codeindex dependencies ` — show imports and imported-by for a file -- `codeindex high-blast` — list files above a blast score threshold +- `blastradius lookup ` — find where a symbol is defined (file + line) +- `blastradius dependencies ` — show imports and imported-by for a file +- `blastradius high-blast` — list files above a blast score threshold - All three new commands support `--json` for machine-readable output - `lookup_symbol` and `build_symbol_index` tools in MCP server - CLI integration test suite (`benchmark/test_cli.py`) — 37 assertions covering happy path, `--json` output, error cases, and sort-order invariants @@ -231,12 +231,12 @@ tools are unchanged. ### Added - Multi-language dependency analysis: Python, JavaScript/TypeScript, Go, Ruby, Rust, Java/Kotlin, PHP, CSS - Blast-radius impact scoring — every file gets a score based on direct and transitive dependents -- `codeindex analyze ` — analyze a repo and write `codeindex.json` -- `codeindex impact ` — show blast-radius impact report for a file -- `codeindex symbols ` — build `symbolindex.json` with functions, classes, and exports; supports `--inline` and `--claude-md` modes -- `codeindex serve --mcp` — MCP stdio server exposing `analyze_repo`, `get_impact`, `get_dependencies`, `get_high_blast_files`, `build_symbol_index`, `lookup_symbol` -- `codeindex serve --viz` — visualization UI server -- `codeindex install-hook` — pre-commit hook for blast-radius warnings +- `blastradius analyze ` — analyze a repo and write `blastradius.json` +- `blastradius impact ` — show blast-radius impact report for a file +- `blastradius symbols ` — build `symbolindex.json` with functions, classes, and exports; supports `--inline` and `--claude-md` modes +- `blastradius serve --mcp` — MCP stdio server exposing `analyze_repo`, `get_impact`, `get_dependencies`, `get_high_blast_files`, `build_symbol_index`, `lookup_symbol` +- `blastradius serve --viz` — visualization UI server +- `blastradius install-hook` — pre-commit hook for blast-radius warnings - Phase 4: Docker, CI/CD, and schema analyzers - Phase 5: monorepo and cross-language intelligence - Apache 2.0 license diff --git a/HANDOFF.md b/HANDOFF.md index 51b30d5..7452ac7 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -1,6 +1,6 @@ -# Engineering Handoff — codeindex Temporal Knowledge Graph +# Engineering Handoff — blastradius Temporal Knowledge Graph -**Repo:** `scheidydudes-github-repos/codeindex` +**Repo:** `scheidydudes-github-repos/blastradius` **Branch:** `main` (4 commits ahead of origin) **Last commit:** `e863853` — Phase 2 temporal layer **Test status:** 11/11 passing (`uv run pytest` or `.venv/bin/pytest`) @@ -9,7 +9,7 @@ ## 1. Mission -We're evolving `codeindex` from a stateless point-in-time dependency analyzer into a **self-hosted temporal code knowledge graph** — persistent, incremental, and semantically queryable. The design document is `docs/codeindex-temporal-knowledge-graph.md` (CKG-DESIGN-001). Phases 0–2 are complete and committed. Next up is Phase 3 (semantic retrieval via embeddings) then Phase 4 (MCP surface + README). +We're evolving `blastradius` from a stateless point-in-time dependency analyzer into a **self-hosted temporal code knowledge graph** — persistent, incremental, and semantically queryable. The design document is `docs/blastradius-temporal-knowledge-graph.md` (CKG-DESIGN-001). Phases 0–2 are complete and committed. Next up is Phase 3 (semantic retrieval via embeddings) then Phase 4 (MCP surface + README). --- @@ -19,30 +19,30 @@ We're evolving `codeindex` from a stateless point-in-time dependency analyzer in - **Phase 0** (`555c38d`): `docs/CKG-INTERNALS.md` — full internal map of the pre-change codebase. No behavior changes. -- **Phase 1** (`9b167d6`): SQLite store at `/.codeindex/index.db`. - - `Store` class in `codeindex/store/db.py` — schema v1, WAL mode, upsert/soft-delete for files/edges/symbols, FTS5 symbol index. +- **Phase 1** (`9b167d6`): SQLite store at `/.blastradius/index.db`. + - `Store` class in `blastradius/store/db.py` — schema v1, WAL mode, upsert/soft-delete for files/edges/symbols, FTS5 symbol index. - `index.build()` now syncs to DB as a side effect after every `analyze` run. JSON export unchanged. - - `codeindex db status` / `codeindex db migrate` CLI commands. + - `blastradius db status` / `blastradius db migrate` CLI commands. - Incremental detection: logs `N file(s) changed since ` based on `git diff --name-status`. - 5 tests: golden idempotency, DB population, incremental detection, status counts, soft-delete. - **Phase 2** (`e863853`): Temporal layer. - - `codeindex/temporal/history.py`: `backfill()` walks git log via `git ls-tree` + `git cat-file --batch`; never touches working tree; sets `first_seen_commit`/`last_seen_commit` on files and edges. + - `blastradius/temporal/history.py`: `backfill()` walks git log via `git ls-tree` + `git cat-file --batch`; never touches working tree; sets `first_seen_commit`/`last_seen_commit` on files and edges. - `Store.as_of_impact(file, reachable_set)`: blast radius at a historical point using SQLite temp table for commit ancestry. - `Store.changed_since(reachable_set)`: files/edges added or removed since a ref. - - `codeindex history [--since REF] [--max-commits N]` - - `codeindex changed-since ` - - `codeindex impact FILE --as-of ` + - `blastradius history [--since REF] [--max-commits N]` + - `blastradius changed-since ` + - `blastradius impact FILE --as-of ` - 6 tests: as-of differs from HEAD, changed_since edges, backfill populates commits table, first_seen_commit set, no working-tree modification, changed-since added file. ### What's NOT yet built -- **Phase 3** (semantic layer): `codeindex/semantic/` package, embedding provider, `vec_symbols` table, `codeindex search` command, hybrid RRF query engine. +- **Phase 3** (semantic layer): `blastradius/semantic/` package, embedding provider, `vec_symbols` table, `blastradius search` command, hybrid RRF query engine. - **Phase 4** (surface): 4 new MCP tools (`semantic_search`, `temporal_impact`, `graph_query`, `changed_since`), README update. ### Exact next action -Start Phase 3. The design doc (`docs/codeindex-temporal-knowledge-graph.md` §6.4, §6.5, §8 Phase 3) is the authoritative spec. Read it before writing code. +Start Phase 3. The design doc (`docs/blastradius-temporal-knowledge-graph.md` §6.4, §6.5, §8 Phase 3) is the authoritative spec. Read it before writing code. --- @@ -57,7 +57,7 @@ Start Phase 3. The design doc (`docs/codeindex-temporal-knowledge-graph.md` §6. **Decision:** JSON write path is fully unchanged; DB is an additive side-effect **Alternatives considered:** Replace JSON with DB-only export; migrate callers to read from DB -**Reason:** Backward compatibility — every existing CLI command, MCP tool, and viz server reads `codeindex.json`. Phase 4 will eventually add DB-backed read paths, but for now JSON stays as the source of truth for queries. +**Reason:** Backward compatibility — every existing CLI command, MCP tool, and viz server reads `blastradius.json`. Phase 4 will eventually add DB-backed read paths, but for now JSON stays as the source of truth for queries. **Reversibility:** Load-bearing for Phases 1–3; Phase 4 is the right time to revisit. --- @@ -86,7 +86,7 @@ Start Phase 3. The design doc (`docs/codeindex-temporal-knowledge-graph.md` §6. **Decision:** uv venv at `.venv/` with Python 3.11 **Alternatives considered:** System pip (broken on this machine due to packaging metadata corruption) **Reason:** System pip had a corrupted `packaging` package. uv created a clean 3.11 venv. -**Reversibility:** Easy. Run `.venv/bin/pytest` or `.venv/bin/codeindex` for everything. +**Reversibility:** Easy. Run `.venv/bin/pytest` or `.venv/bin/blastradius` for everything. --- @@ -96,10 +96,10 @@ Start Phase 3. The design doc (`docs/codeindex-temporal-knowledge-graph.md` §6. | File | Purpose | |---|---| -| `codeindex/store/__init__.py` | Re-exports `Store` | -| `codeindex/store/db.py` | `Store` class: schema, upsert/soft-delete, temporal queries, FTS, status | -| `codeindex/temporal/__init__.py` | Re-exports `backfill` | -| `codeindex/temporal/history.py` | `backfill()`, git plumbing helpers, lightweight import extractor | +| `blastradius/store/__init__.py` | Re-exports `Store` | +| `blastradius/store/db.py` | `Store` class: schema, upsert/soft-delete, temporal queries, FTS, status | +| `blastradius/temporal/__init__.py` | Re-exports `backfill` | +| `blastradius/temporal/history.py` | `backfill()`, git plumbing helpers, lightweight import extractor | | `tests/test_phase1.py` | 5 Phase 1 acceptance tests | | `tests/test_phase2.py` | 6 Phase 2 acceptance tests | | `tests/fixtures/simple_python/` | 3-file Python fixture repo (main, utils, models) | @@ -109,29 +109,29 @@ Start Phase 3. The design doc (`docs/codeindex-temporal-knowledge-graph.md` §6. | File | What changed | |---|---| -| `codeindex/index.py` | Added `git_reachable()`, `git_resolve()`, `db_path_for()`, `find_db()`. `build()` now syncs to Store after enrichment. Content hashes computed pre-sync, stripped before JSON write. | -| `codeindex/cli.py` | Added `_cmd_db`, `_cmd_history`, `_cmd_changed_since`. Updated `_cmd_impact` to handle `--as-of`. Added `history`, `changed-since`, `db` subparsers. Added `--as-of` arg to `impact`. | +| `blastradius/index.py` | Added `git_reachable()`, `git_resolve()`, `db_path_for()`, `find_db()`. `build()` now syncs to Store after enrichment. Content hashes computed pre-sync, stripped before JSON write. | +| `blastradius/cli.py` | Added `_cmd_db`, `_cmd_history`, `_cmd_changed_since`. Updated `_cmd_impact` to handle `--as-of`. Added `history`, `changed-since`, `db` subparsers. Added `--as-of` arg to `impact`. | | `pyproject.toml` | Added `dev = ["pytest>=7"]`, `semantic = ["sqlite-vec"]` extras. Added `[tool.pytest.ini_options]`. | ### Should NOT be touched | File | Why | |---|---| -| `codeindex/analyze.py` | Full repo analysis dispatcher — untouched by design. Per-file incremental parsing is a future optimization. | -| `codeindex/analyzers/*.py` | All existing analyzers — Phase 1–3 don't modify them. | -| `codeindex/mcp_server.py` | Existing 6 MCP tools — Phase 4 adds new ones alongside, never modifies existing. | -| `codeindex/impact.py` | `compute_blast_radius()` is called directly by `Store.as_of_impact()`. Don't change its signature. | -| `docs/codeindex-temporal-knowledge-graph.md` | The spec. Don't edit it; read it. | +| `blastradius/analyze.py` | Full repo analysis dispatcher — untouched by design. Per-file incremental parsing is a future optimization. | +| `blastradius/analyzers/*.py` | All existing analyzers — Phase 1–3 don't modify them. | +| `blastradius/mcp_server.py` | Existing 6 MCP tools — Phase 4 adds new ones alongside, never modifies existing. | +| `blastradius/impact.py` | `compute_blast_radius()` is called directly by `Store.as_of_impact()`. Don't change its signature. | +| `docs/blastradius-temporal-knowledge-graph.md` | The spec. Don't edit it; read it. | ### Phase 3 will create ``` -codeindex/semantic/__init__.py -codeindex/semantic/provider.py # EmbeddingProvider ABC + OpenAI-compat HTTP impl -codeindex/semantic/search.py # Hybrid query engine (semantic + FTS + graph, RRF) +blastradius/semantic/__init__.py +blastradius/semantic/provider.py # EmbeddingProvider ABC + OpenAI-compat HTTP impl +blastradius/semantic/search.py # Hybrid query engine (semantic + FTS + graph, RRF) ``` -And add to `Store` in `codeindex/store/db.py`: +And add to `Store` in `blastradius/store/db.py`: - `vec_symbols` virtual table (gated behind `sqlite-vec` import) - `upsert_embeddings(symbol_ids_and_vecs)` method - `semantic_search(query_vec, k, reachable)` method @@ -153,13 +153,13 @@ Python's `sqlite3.executescript()` commits any pending transaction before runnin The format is: ` blob \n\n` for each object. The parser in `history.py:_git_cat_file_batch()` reads byte-by-byte with `pos` tracking. Don't replace this with individual `git show` calls — it's deliberately batch for performance. **System pip is broken on this machine** -Don't use `pip3` or `python3` directly. Always use `.venv/bin/pytest`, `.venv/bin/codeindex`, `.venv/bin/python3`. The miniforge Python 3.9 has a corrupted `packaging` package that causes `pip install` to fail. +Don't use `pip3` or `python3` directly. Always use `.venv/bin/pytest`, `.venv/bin/blastradius`, `.venv/bin/python3`. The miniforge Python 3.9 has a corrupted `packaging` package that causes `pip install` to fail. **`sqlite-vec` for Phase 3 must be feature-detected at runtime** -The design doc requires graceful degradation: if `sqlite-vec` can't load (not installed, wrong platform), `codeindex search` falls back to FTS + graph with a clear log message. Never `import sqlite_vec` at module level — always try/except around the extension load, same pattern as the FTS DDL in `_apply_schema()`. +The design doc requires graceful degradation: if `sqlite-vec` can't load (not installed, wrong platform), `blastradius search` falls back to FTS + graph with a clear log message. Never `import sqlite_vec` at module level — always try/except around the extension load, same pattern as the FTS DDL in `_apply_schema()`. **Dependency direction is a hard constraint** -`codeindex/core/`, `store/`, and `temporal/` must NEVER import from `codeindex/graph/` or `codeindex/semantic/`. The import arrow points downward only. The current `store/db.py` has a local import of `compute_blast_radius` inside `as_of_impact()` — this is a `codeindex.impact` import (core layer), which is fine. +`blastradius/core/`, `store/`, and `temporal/` must NEVER import from `blastradius/graph/` or `blastradius/semantic/`. The import arrow points downward only. The current `store/db.py` has a local import of `compute_blast_radius` inside `as_of_impact()` — this is a `blastradius.impact` import (core layer), which is fine. --- @@ -188,7 +188,7 @@ except ImportError: **No comments on obvious code.** Comments only for non-obvious constraints or workarounds (e.g., the FTS content= issue). No docstrings on trivial methods. -**JSON schema is frozen.** `codeindex.json` and `symbolindex.json` schemas don't change. Any new data lives in the DB only, exposed via new CLI/MCP commands. +**JSON schema is frozen.** `blastradius.json` and `symbolindex.json` schemas don't change. Any new data lives in the DB only, exposed via new CLI/MCP commands. --- @@ -206,15 +206,15 @@ except ImportError: ## 8. Do Not Touch -- **`codeindex/mcp_server.py`** — existing 6 tools work and are not under change until Phase 4. Phase 4 adds new tools alongside; it doesn't modify existing ones. -- **`codeindex/analyze.py` and `codeindex/analyzers/`** — the parsing pipeline is deliberately untouched. Any incremental per-file parsing is a future optimization, not Phase 3. -- **The `codeindex.json` / `symbolindex.json` schema** — frozen per constraint #3. +- **`blastradius/mcp_server.py`** — existing 6 tools work and are not under change until Phase 4. Phase 4 adds new tools alongside; it doesn't modify existing ones. +- **`blastradius/analyze.py` and `blastradius/analyzers/`** — the parsing pipeline is deliberately untouched. Any incremental per-file parsing is a future optimization, not Phase 3. +- **The `blastradius.json` / `symbolindex.json` schema** — frozen per constraint #3. - **`.venv/`** — don't recreate or upgrade. Python 3.11, packages installed via `uv pip install -e ".[dev,yaml]"`. -- **`docs/codeindex-temporal-knowledge-graph.md`** — the spec document. Read-only. +- **`docs/blastradius-temporal-knowledge-graph.md`** — the spec document. Read-only. - **`SCHEMA_VERSION = "1"` in `store/db.py`** — don't bump until Phase 3 actually adds the `vec_symbols` table, and then also add a migration path. --- ## 9. Resume Command -> Read `HANDOFF.md` and `docs/codeindex-temporal-knowledge-graph.md` (§6.4, §6.5, §8 Phase 3, §9 Constraints). Then implement Phase 3: create `codeindex/semantic/` with an embedding provider interface and OpenAI-compatible HTTP client (stdlib urllib only, no new runtime deps for the client), add `vec_symbols` to the Store gated behind `sqlite-vec`, implement `codeindex search` with hybrid RRF retrieval (semantic + FTS + graph), and add degradation tests. Use `.venv/bin/pytest` to run tests. Do not modify existing analyzers, the JSON export schema, or any existing MCP tools. Run all 11 existing tests before committing — they must stay green. +> Read `HANDOFF.md` and `docs/blastradius-temporal-knowledge-graph.md` (§6.4, §6.5, §8 Phase 3, §9 Constraints). Then implement Phase 3: create `blastradius/semantic/` with an embedding provider interface and OpenAI-compatible HTTP client (stdlib urllib only, no new runtime deps for the client), add `vec_symbols` to the Store gated behind `sqlite-vec`, implement `blastradius search` with hybrid RRF retrieval (semantic + FTS + graph), and add degradation tests. Use `.venv/bin/pytest` to run tests. Do not modify existing analyzers, the JSON export schema, or any existing MCP tools. Run all 11 existing tests before committing — they must stay green. diff --git a/README.md b/README.md index 04f1915..e22889a 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -# codeindex +# blastradius **Temporal code knowledge graph** with blast-radius impact scoring, semantic symbol search, and git-history-aware dependency analysis — for AI-assisted development. Point it at any project — Python, JavaScript/TypeScript, Go, Ruby, Rust, Java, PHP, and more — and get: -- A persistent **SQLite graph store** at `/.codeindex/index.db` — incremental, queryable, temporal -- A `codeindex.json` dependency index written directly into your repo (preserved for backward compatibility) +- A persistent **SQLite graph store** at `/.blastradius/index.db` — incremental, queryable, temporal +- A `blastradius.json` dependency index written directly into your repo (preserved for backward compatibility) - Per-file blast-radius scores (how many files break if this one changes), including **historical as-of queries** - A `symbolindex.json` symbol map so AI can find any function/class without scanning every file - **Hybrid semantic search** over symbols: natural-language queries fused with keyword + graph expansion @@ -20,14 +20,14 @@ No build step. No npm. Zero required runtime dependencies — SQLite is stdlib. ## Install ```bash -pip install codeindex +pip install blastradius ``` Or from source: ```bash -git clone https://github.com/scheidydude/codeindex -cd codeindex +git clone https://github.com/scheidydude/blastradius +cd blastradius pip install -e . ``` @@ -36,23 +36,23 @@ pip install -e . ## Quickstart ```bash -# Build the dependency index (also writes to .codeindex/index.db) -codeindex analyze ./myapp +# Build the dependency index (also writes to .blastradius/index.db) +blastradius analyze ./myapp # Build the symbol index (where every function and class lives) -codeindex symbols ./myapp +blastradius symbols ./myapp # See blast radius for a file before touching it -codeindex impact src/auth.py +blastradius impact src/auth.py # Search symbols with natural language (no embedding endpoint needed — FTS fallback) -codeindex search "validate auth token" +blastradius search "validate auth token" # See what changed since a release tag -codeindex changed-since v1.2.0 +blastradius changed-since v1.2.0 # Launch the visualization UI -codeindex serve --viz --repo ./myapp +blastradius serve --viz --repo ./myapp open http://localhost:8080 ``` @@ -60,26 +60,26 @@ open http://localhost:8080 ## Commands -### `codeindex analyze` +### `blastradius analyze` ```bash -codeindex analyze [REPO_PATH] [--output PATH] [--watch] +blastradius analyze [REPO_PATH] [--output PATH] [--watch] ``` -Analyzes the repo and writes `codeindex.json` to the repo root. Detects 12+ languages automatically. +Analyzes the repo and writes `blastradius.json` to the repo root. Detects 12+ languages automatically. | Flag | Default | Description | |------|---------|-------------| | `REPO_PATH` | `.` | Path to repo root | -| `--output` | `/codeindex.json` | Override output path | +| `--output` | `/blastradius.json` | Override output path | | `--watch` | off | Re-index on file changes (requires `watchdog`) | --- -### `codeindex symbols` +### `blastradius symbols` ```bash -codeindex symbols [REPO_PATH] [--output PATH] [--inline] [--index PATH] +blastradius symbols [REPO_PATH] [--output PATH] [--inline] [--index PATH] [--claude-md] [--claude-md-path PATH] [--all-symbols] ``` @@ -90,7 +90,7 @@ Builds a symbol index — a map of every function, class, struct, and type to it | Flag | Description | |------|-------------| | _(none)_ | Write a standalone `symbolindex.json` | -| `--inline` | Embed symbols into each node in `codeindex.json` instead | +| `--inline` | Embed symbols into each node in `blastradius.json` instead | | `--claude-md` | Append a compressed symbol summary to `CLAUDE.md` | Both `--inline` and `--claude-md` can be combined in a single run. @@ -101,7 +101,7 @@ Both `--inline` and `--claude-md` can be combined in a single run. |------|---------|-------------| | `REPO_PATH` | `.` | Path to repo root | | `--output` | `/symbolindex.json` | Output path (standalone mode) | -| `--index` | auto-discovered | Path to `codeindex.json` (for `--inline`) | +| `--index` | auto-discovered | Path to `blastradius.json` (for `--inline`) | | `--claude-md-path` | `/CLAUDE.md` | Override CLAUDE.md path | | `--all-symbols` | off | Include non-exported symbols in CLAUDE.md (default: exported only) | @@ -109,19 +109,19 @@ Both `--inline` and `--claude-md` can be combined in a single run. ```bash # Standalone symbol index -codeindex symbols ./myapp +blastradius symbols ./myapp -# Embed into codeindex.json (one file for blast radius + symbols) -codeindex symbols ./myapp --inline +# Embed into blastradius.json (one file for blast radius + symbols) +blastradius symbols ./myapp --inline # Write CLAUDE.md summary so Claude Code loads symbols automatically -codeindex symbols ./myapp --claude-md +blastradius symbols ./myapp --claude-md # All three at once -codeindex symbols ./myapp --inline --claude-md +blastradius symbols ./myapp --inline --claude-md # Re-generate when code changes -codeindex symbols ./myapp --inline --claude-md +blastradius symbols ./myapp --inline --claude-md ``` **Why it matters:** Claude Code and other AI tools normally scan every file to find a function definition. With a symbol index, Claude can load one file, do an O(1) lookup, and open only the relevant file — cutting token usage 60–90% on symbol-location tasks. @@ -130,10 +130,10 @@ codeindex symbols ./myapp --inline --claude-md --- -### `codeindex impact` +### `blastradius impact` ```bash -codeindex impact FILE [--index PATH] [--out FILE] [--json] [--as-of REF] +blastradius impact FILE [--index PATH] [--out FILE] [--json] [--as-of REF] ``` Shows the blast-radius impact for a specific file: direct dependents, transitive dependents, blast score, and risk level. @@ -158,23 +158,23 @@ Risk: HIGH — affects 7/42 files (16.7% of codebase) | Flag | Description | |------|-------------| -| `--index PATH` | Path to `codeindex.json` (auto-discovered if omitted) | +| `--index PATH` | Path to `blastradius.json` (auto-discovered if omitted) | | `--out FILE` | Write a markdown report to this file | | `--json` | Output raw JSON | | `--as-of REF` | Compute blast radius at a historical commit/ref instead of HEAD | --- -### `codeindex search` +### `blastradius search` ```bash -codeindex search QUERY [--k N] [--as-of REF] [--db PATH] [--json] +blastradius search QUERY [--k N] [--as-of REF] [--db PATH] [--json] ``` Hybrid semantic + keyword + graph symbol search. Finds relevant functions and classes without knowing their exact names. **Retrieval signals fused with Reciprocal Rank Fusion (RRF):** -1. **Semantic KNN** — embedding similarity (requires `codeindex[semantic]` + a configured endpoint) +1. **Semantic KNN** — embedding similarity (requires `blastradius[semantic]` + a configured endpoint) 2. **FTS5 keyword** — full-text search over symbol names, signatures, and docstrings 3. **Graph expansion** — structurally adjacent symbols from dependent/dependency files @@ -182,16 +182,16 @@ Degrades gracefully: if no embedding endpoint is configured, falls back to FTS + ```bash # Keyword + graph search (no embedding setup required) -codeindex search "validate auth token" +blastradius search "validate auth token" -# Full semantic search (requires CODEINDEX_EMBEDDING_* env vars) -CODEINDEX_EMBEDDING_ENDPOINT=http://localhost:11434 \ -CODEINDEX_EMBEDDING_MODEL=nomic-embed-text \ -CODEINDEX_EMBEDDING_DIMS=768 \ -codeindex search "validate auth token" +# Full semantic search (requires BLASTRADIUS_EMBEDDING_* env vars) +BLASTRADIUS_EMBEDDING_ENDPOINT=http://localhost:11434 \ +BLASTRADIUS_EMBEDDING_MODEL=nomic-embed-text \ +BLASTRADIUS_EMBEDDING_DIMS=768 \ +blastradius search "validate auth token" # Historical search — symbols visible at a release tag -codeindex search "token validation" --as-of v1.2.0 +blastradius search "token validation" --as-of v1.2.0 ``` | Flag | Default | Description | @@ -199,15 +199,15 @@ codeindex search "token validation" --as-of v1.2.0 | `QUERY` | — | Natural-language or keyword query | | `--k N` | `10` | Number of results to return | | `--as-of REF` | HEAD | Restrict to symbols visible at this commit/ref | -| `--db PATH` | auto-discovered | Path to `.codeindex/index.db` | +| `--db PATH` | auto-discovered | Path to `.blastradius/index.db` | | `--json` | off | Output raw JSON | --- -### `codeindex history` +### `blastradius history` ```bash -codeindex history [REPO_PATH] [--since REF] [--max-commits N] [--json] +blastradius history [REPO_PATH] [--since REF] [--max-commits N] [--json] ``` Backfills temporal graph data from git history — without any working-tree checkouts. Reads blobs via `git cat-file --batch` and stamps `first_seen_commit` / `last_seen_commit` on every file, edge, and symbol. @@ -216,10 +216,10 @@ Run this once after initial setup to enable `--as-of` queries across the full hi ```bash # Backfill up to 1000 commits (default) -codeindex history . +blastradius history . # Backfill only recent history -codeindex history . --since v1.0.0 --max-commits 200 +blastradius history . --since v1.0.0 --max-commits 200 ``` | Flag | Default | Description | @@ -231,16 +231,16 @@ codeindex history . --since v1.0.0 --max-commits 200 --- -### `codeindex changed-since` +### `blastradius changed-since` ```bash -codeindex changed-since REF [--repo PATH] [--db PATH] [--json] +blastradius changed-since REF [--repo PATH] [--db PATH] [--json] ``` Lists files and dependency edges added or removed since a commit, branch, or tag. ``` -$ codeindex changed-since v1.2.0 +$ blastradius changed-since v1.2.0 Changes since v1.2.0: Added files (2): @@ -255,22 +255,22 @@ Changes since v1.2.0: |------|---------|-------------| | `REF` | — | Commit hash, branch, or tag to compare against | | `--repo PATH` | `.` | Repo root (for git operations) | -| `--db PATH` | auto-discovered | Path to `.codeindex/index.db` | +| `--db PATH` | auto-discovered | Path to `.blastradius/index.db` | | `--json` | off | Output raw JSON | --- -### `codeindex db` +### `blastradius db` ```bash -codeindex db status [--db PATH] [--json] -codeindex db migrate [--db PATH] +blastradius db status [--db PATH] [--json] +blastradius db migrate [--db PATH] ``` -Manages the SQLite store at `/.codeindex/index.db`. +Manages the SQLite store at `/.blastradius/index.db`. ``` -$ codeindex db status +$ blastradius db status schema_version : 2 repo_root : /Users/alice/myapp last_indexed_commit : a3f2e1c8 @@ -282,20 +282,20 @@ embedding_dims : 768 vec_symbols : enabled ``` -`db migrate` applies any pending schema migrations automatically (also runs on every `codeindex analyze`). +`db migrate` applies any pending schema migrations automatically (also runs on every `blastradius analyze`). --- -### `codeindex serve` +### `blastradius serve` ```bash -codeindex serve --viz [--repo PATH] [--port PORT] [--watch] -codeindex serve --mcp +blastradius serve --viz [--repo PATH] [--port PORT] [--watch] +blastradius serve --mcp ``` `--viz` launches an interactive visualization UI in your browser (5 modes: 2D force graph, 3D network, dependency matrix, treemap, infrastructure graph). -`--mcp` starts a stdio MCP server that exposes codeindex tools directly to Claude and other MCP clients. +`--mcp` starts a stdio MCP server that exposes blastradius tools directly to Claude and other MCP clients. **MCP tools:** @@ -317,8 +317,8 @@ codeindex serve --mcp ```json { "mcpServers": { - "codeindex": { - "command": "codeindex", + "blastradius": { + "command": "blastradius", "args": ["serve", "--mcp"] } } @@ -327,23 +327,23 @@ codeindex serve --mcp --- -### `codeindex lookup` +### `blastradius lookup` ```bash -codeindex lookup SYMBOL [--index PATH] [--json] +blastradius lookup SYMBOL [--index PATH] [--json] ``` Finds where a function, class, struct, or other symbol is defined. Queries the SQLite DB (same source as `search`), falling back to `symbolindex.json` if no DB is present. Prints 5 lines of source context around the definition. ``` -$ codeindex lookup compute_blast_radius -codeindex/impact.py:6 compute_blast_radius (function) +$ blastradius lookup compute_blast_radius +blastradius/impact.py:6 compute_blast_radius (function) > 6 | def compute_blast_radius(nodes: list[dict], links: list[dict]) -> dict[str, dict]: 7 | """...""" 8 | ... -$ codeindex lookup AuthService +$ blastradius lookup AuthService src/auth.py:44 AuthService (class) methods: login, logout, refresh > 44 | class AuthService: @@ -359,16 +359,16 @@ If a symbol isn't found, it's likely a third-party import — only symbols defin --- -### `codeindex dependencies` +### `blastradius dependencies` ```bash -codeindex dependencies FILE [--index PATH] [--json] +blastradius dependencies FILE [--index PATH] [--json] ``` Shows what a file imports and what imports it, plus its blast score. ``` -$ codeindex dependencies src/auth.py +$ blastradius dependencies src/auth.py File: src/auth.py (blast score: 8.5) Imports (3): @@ -383,21 +383,21 @@ Imported by (2): | Flag | Description | |------|-------------| -| `--index PATH` | Path to `codeindex.json` (auto-discovered if omitted) | +| `--index PATH` | Path to `blastradius.json` (auto-discovered if omitted) | | `--json` | Output raw JSON | --- -### `codeindex high-blast` +### `blastradius high-blast` ```bash -codeindex high-blast [--threshold N] [--index PATH] [--json] +blastradius high-blast [--threshold N] [--index PATH] [--json] ``` Lists all files whose blast score exceeds the threshold, sorted by score descending. Useful for identifying the riskiest files before a refactor. ``` -$ codeindex high-blast --threshold 5 +$ blastradius high-blast --threshold 5 Files with blast score ≥ 5.0 (3 found) 13.0 src/db.py (12d / 2t) @@ -410,21 +410,21 @@ Files with blast score ≥ 5.0 (3 found) | Flag | Default | Description | |------|---------|-------------| | `--threshold N` | `5` | Minimum blast score to include | -| `--index PATH` | auto-discovered | Path to `codeindex.json` | +| `--index PATH` | auto-discovered | Path to `blastradius.json` | | `--json` | off | Output raw JSON | --- -### `codeindex symbol-blast` +### `blastradius symbol-blast` ```bash -codeindex symbol-blast FILE [--json] +blastradius symbol-blast FILE [--json] ``` Per-export blast radius for a file. Lists every exported symbol with the count and exact file paths of importers that reference it by name. Useful when a file exports many symbols and you only need to touch one — lets you confirm the others are safe. ``` -$ codeindex symbol-blast lib/db/schema.ts +$ blastradius symbol-blast lib/db/schema.ts Symbol-level blast radius: lib/db/schema.ts @@ -449,10 +449,10 @@ Symbol-level blast radius: lib/db/schema.ts --- -### `codeindex install-hook` +### `blastradius install-hook` ```bash -codeindex install-hook [--repo PATH] [--threshold N] [--strict] [--remove] +blastradius install-hook [--repo PATH] [--threshold N] [--strict] [--remove] ``` Installs a git pre-commit hook that warns when staged files exceed the blast score threshold. @@ -465,7 +465,7 @@ Installs a git pre-commit hook that warns when staged files exceed the blast sco --- -## Using codeindex in another repo with Claude +## Using blastradius in another repo with Claude Three workflows, ordered by automation level. @@ -476,25 +476,25 @@ Claude gets symbol lookup, dependency, and impact tools it calls automatically. **One-time setup:** ```bash cd /your/other/repo -codeindex analyze . -codeindex symbols . +blastradius analyze . +blastradius symbols . ``` Register the MCP server with Claude Code using `claude mcp add`. Use `--scope project` to limit it to this repo, or `--scope global` to use it everywhere: ```bash # Project-scoped (recommended — stored in .claude/settings.json) -claude mcp add --scope project codeindex -- /path/to/codeindex serve --mcp +claude mcp add --scope project blastradius -- /path/to/blastradius serve --mcp # Global (available in all repos) -claude mcp add --scope global codeindex -- /path/to/codeindex serve --mcp +claude mcp add --scope global blastradius -- /path/to/blastradius serve --mcp ``` -Find the full path to your codeindex binary with `which codeindex`, then substitute it above. +Find the full path to your blastradius binary with `which blastradius`, then substitute it above. ```bash # Example with conda install -claude mcp add --scope project codeindex -- /opt/homebrew/Caskroom/miniforge/base/bin/codeindex serve --mcp +claude mcp add --scope project blastradius -- /opt/homebrew/Caskroom/miniforge/base/bin/blastradius serve --mcp ``` Verify it registered: @@ -502,14 +502,14 @@ Verify it registered: claude mcp list ``` -> **Note:** Do not use `"command": "codeindex"` with a bare name — Claude Code does not inherit your shell PATH, so the binary won't be found unless you use the absolute path. +> **Note:** Do not use `"command": "blastradius"` with a bare name — Claude Code does not inherit your shell PATH, so the binary won't be found unless you use the absolute path. Claude now has all 10 MCP tools available in every session. When it needs to find `processPayment`, it calls `lookup_symbol("processPayment")` and gets `src/billing.py:142` back in one shot — no file scanning. When it needs to find code that validates auth tokens without knowing the exact name, it calls `semantic_search("validate auth token")`. **Keep the index fresh:** ```bash # Auto-rebuild on file changes (leave running in a terminal) -codeindex symbols . --watch +blastradius symbols . --watch ``` --- @@ -520,7 +520,7 @@ Symbol table is embedded in `CLAUDE.md` so it loads into every session automatic ```bash cd /your/other/repo -codeindex symbols . --claude-md +blastradius symbols . --claude-md ``` This upserts a `symbolindex` code fence into `CLAUDE.md`. Every Claude Code session in that repo loads it at startup. Claude can answer "where is `X` defined?" from context alone with zero tool calls. @@ -530,7 +530,7 @@ This upserts a `symbolindex` code fence into `CLAUDE.md`. Every Claude Code sess **Keep it fresh:** ```bash # Re-run after significant refactors -codeindex analyze . && codeindex symbols . --claude-md +blastradius analyze . && blastradius symbols . --claude-md ``` --- @@ -540,15 +540,15 @@ codeindex analyze . && codeindex symbols . --claude-md For large repos where the `--claude-md` section would be too large, use the MCP server for lookups and add a short hint to `CLAUDE.md` so Claude reaches for the tool first: ```bash -codeindex analyze . -codeindex symbols . +blastradius analyze . +blastradius symbols . ``` Then add to `CLAUDE.md`: ```markdown -## Codeindex +## Blastradius Symbol index: `symbolindex.json` — use the `lookup_symbol` MCP tool before grepping for any function or class. -Dependency index: `codeindex.json` — use `get_impact` before modifying high-blast files. +Dependency index: `blastradius.json` — use `get_impact` before modifying high-blast files. ``` This costs almost no tokens but primes Claude to use the index rather than defaulting to grep. @@ -561,20 +561,20 @@ The same data available via MCP is also accessible directly from the terminal: ```bash # Find where a symbol is defined (shows code snippet) -codeindex lookup MyClassName -codeindex lookup process_payment --json +blastradius lookup MyClassName +blastradius lookup process_payment --json # Show what a file imports and what depends on it -codeindex dependencies src/auth.py +blastradius dependencies src/auth.py # List the riskiest files to change -codeindex high-blast --threshold 5 +blastradius high-blast --threshold 5 # Blast-radius report before touching a file -codeindex impact src/auth.py +blastradius impact src/auth.py # Per-export blast radius — which importers use each exported symbol -codeindex symbol-blast lib/db/schema.ts +blastradius symbol-blast lib/db/schema.ts ``` --- @@ -586,7 +586,7 @@ codeindex symbol-blast lib/db/schema.ts | Daily driver repo, active feature work | MCP server | | Medium repo, frequent symbol lookups | CLAUDE.md injection | | Large repo (1000+ files) | MCP server + short CLAUDE.md hint | -| Quick one-off in an unfamiliar repo | `codeindex symbols . --claude-md`, delete after | +| Quick one-off in an unfamiliar repo | `blastradius symbols . --claude-md`, delete after | | Terminal / scripting use | CLI commands (`lookup`, `dependencies`, `high-blast`) | --- @@ -612,7 +612,7 @@ codeindex symbol-blast lib/db/schema.ts ## Output schemas -### `codeindex.json` +### `blastradius.json` ```json { @@ -647,7 +647,7 @@ codeindex symbol-blast lib/db/schema.ts } ``` -The `symbols` field is only present when `codeindex symbols --inline` has been run. +The `symbols` field is only present when `blastradius symbols --inline` has been run. --- @@ -694,7 +694,7 @@ The `symbols` field is only present when `codeindex symbols --inline` has been r - *"Where is `verify_token` defined?"* → `symbols["verify_token"][0].file` + `.line` — O(1) - *"What symbols live in `src/auth.py`?"* → `file_symbols["src/auth.py"]` — O(1) -- *"What's the blast radius of changing `verify_token`?"* → cross-reference `codeindex.json` via the file +- *"What's the blast radius of changing `verify_token`?"* → cross-reference `blastradius.json` via the file --- @@ -703,15 +703,15 @@ The `symbols` field is only present when `codeindex symbols --inline` has been r When `--claude-md` is used, a compact section is upserted into `CLAUDE.md` bounded by HTML comment markers so re-runs update in place: ``` - + ## Symbol Index -_Generated by codeindex. Update: `codeindex symbols --claude-md`_ +_Generated by blastradius. Update: `blastradius symbols --claude-md`_ ```symbolindex src/auth.py: verify_token:fn:18 AuthService:cls:44[login,logout,refresh] src/db.py: connect:fn:12 query:fn:28 close:fn:55 ``` - + ``` Format per symbol: `name:kind_abbr:line[methods...]` @@ -721,10 +721,10 @@ Kind abbreviations: `fn` function · `cls` class · `st` struct · `en` enum · ## AI workflow comparison -| Task | Without codeindex | With symbolindex.json | +| Task | Without blastradius | With symbolindex.json | |------|-------------------|----------------------| | Find where `process_payment` is defined | Grep / scan ~200 files | Load 1 file, O(1) lookup | -| Understand blast radius of a change | Manual tracing | `codeindex impact ` | +| Understand blast radius of a change | Manual tracing | `blastradius impact ` | | Load only relevant context | Full repo scan | File + line from symbol map | | Estimated token savings | baseline | **60–90% on symbol tasks** | @@ -734,31 +734,31 @@ Kind abbreviations: `fn` function · `cls` class · `st` struct · `en` enum · | Package | Purpose | Install | |---------|---------|---------| -| `sqlite-vec` | Semantic vector search in `codeindex search` and `semantic_search` MCP tool | `pip install 'codeindex[semantic]'` | -| `watchdog` | `--watch` file change detection | `pip install 'codeindex[watch]'` | -| `PyYAML` | Better Docker Compose / CI YAML parsing | `pip install 'codeindex[yaml]'` | -| `tomli` | Rust `Cargo.toml` on Python < 3.11 | `pip install 'codeindex[toml]'` | +| `sqlite-vec` | Semantic vector search in `blastradius search` and `semantic_search` MCP tool | `pip install 'blastradius[semantic]'` | +| `watchdog` | `--watch` file change detection | `pip install 'blastradius[watch]'` | +| `PyYAML` | Better Docker Compose / CI YAML parsing | `pip install 'blastradius[yaml]'` | +| `tomli` | Rust `Cargo.toml` on Python < 3.11 | `pip install 'blastradius[toml]'` | ### Semantic search configuration Semantic search requires a self-hosted embedding endpoint (Ollama, LM Studio, llama.cpp server, or any OpenAI-compatible `/v1/embeddings` API) and the `sqlite-vec` extension. ```bash -pip install 'codeindex[semantic]' +pip install 'blastradius[semantic]' # Set env vars (add to your shell profile or .env) -export CODEINDEX_EMBEDDING_ENDPOINT=http://localhost:11434 -export CODEINDEX_EMBEDDING_MODEL=nomic-embed-text -export CODEINDEX_EMBEDDING_DIMS=768 +export BLASTRADIUS_EMBEDDING_ENDPOINT=http://localhost:11434 +export BLASTRADIUS_EMBEDDING_MODEL=nomic-embed-text +export BLASTRADIUS_EMBEDDING_DIMS=768 # Re-index to generate embeddings -codeindex analyze ./myapp +blastradius analyze ./myapp # Search -codeindex search "validate JWT token" +blastradius search "validate JWT token" ``` -Without these env vars, `codeindex search` and the `semantic_search` MCP tool fall back to FTS5 keyword + graph search — no crash, no config required. +Without these env vars, `blastradius search` and the `semantic_search` MCP tool fall back to FTS5 keyword + graph search — no crash, no config required. --- diff --git a/benchmark/test_cli.py b/benchmark/test_cli.py index 333b8f6..f113936 100644 --- a/benchmark/test_cli.py +++ b/benchmark/test_cli.py @@ -3,9 +3,9 @@ CLI integration tests for: lookup, dependencies, high-blast. Usage: - python benchmark/test_cli.py [--repo PATH] [--codeindex PATH] + python benchmark/test_cli.py [--repo PATH] [--blastradius PATH] -Reads codeindex.json and symbolindex.json from --repo to build fixtures, +Reads blastradius.json and symbolindex.json from --repo to build fixtures, then invokes the CLI as a subprocess and validates stdout/exit codes. """ from __future__ import annotations @@ -170,27 +170,39 @@ def test_high_blast(exe: str, repo: str, r: Results, index_path: str) -> None: # Entry point # --------------------------------------------------------------------------- def main() -> None: + if hasattr(sys.stdout, "reconfigure"): + sys.stdout.reconfigure(encoding="utf-8", errors="replace") + if hasattr(sys.stderr, "reconfigure"): + sys.stderr.reconfigure(encoding="utf-8", errors="replace") + import argparse parser = argparse.ArgumentParser(description="CLI integration tests: lookup, dependencies, high-blast") parser.add_argument("--repo", default=".", help="Repo path (default: .)") - parser.add_argument("--codeindex", default="codeindex", help="Path to codeindex executable (default: codeindex)") + parser.add_argument("--blastradius", default="blastradius", help="Path to blastradius executable (default: blastradius)") args = parser.parse_args() repo = str(Path(args.repo).resolve()) - exe = args.codeindex + exe = args.blastradius print(f"Repo : {repo}") print(f"Command : {exe}") - index_path = str(Path(repo) / "codeindex.json") + index_path = str(Path(repo) / "blastradius.json") sym_path = str(Path(repo) / "symbolindex.json") if not Path(index_path).exists(): - print(f"ERROR: {index_path} not found. Run: codeindex analyze {repo}", file=sys.stderr) - sys.exit(1) + print(f"Building index: {exe} analyze {repo}") + rc, out, err = run([exe, "analyze", repo], repo) + if rc != 0 or not Path(index_path).exists(): + print(f"ERROR: Failed to build {index_path}.\n{err}", file=sys.stderr) + sys.exit(1) + if not Path(sym_path).exists(): - print(f"ERROR: {sym_path} not found. Run: codeindex symbols {repo}", file=sys.stderr) - sys.exit(1) + print(f"Building symbol index: {exe} symbols {repo}") + rc, out, err = run([exe, "symbols", repo], repo) + if rc != 0 or not Path(sym_path).exists(): + print(f"ERROR: Failed to build {sym_path}.\n{err}", file=sys.stderr) + sys.exit(1) # Pick probe fixtures from actual index data index_data = json.loads(Path(index_path).read_text()) @@ -206,7 +218,7 @@ def main() -> None: # Probe symbol: first symbol in index symbols = sym_data.get("symbols", {}) if not symbols: - print("ERROR: symbolindex.json has no symbols. Run: codeindex symbols {repo}", file=sys.stderr) + print("ERROR: symbolindex.json has no symbols. Run: blastradius symbols {repo}", file=sys.stderr) sys.exit(1) sym_name, sym_matches = next(iter(symbols.items())) expected_file = Path(sym_matches[0]["file"]).name diff --git a/benchmark/test_mcp.py b/benchmark/test_mcp.py index 73b3fa0..db7866a 100644 --- a/benchmark/test_mcp.py +++ b/benchmark/test_mcp.py @@ -1,12 +1,12 @@ #!/usr/bin/env python3 """ -MCP server integration test — exercises all 6 tools via real JSON-RPC stdio. +MCP server integration test — exercises all tools via real JSON-RPC stdio. Usage: - python benchmark/test_mcp.py [--repo PATH] [--codeindex PATH] + python benchmark/test_mcp.py [--repo PATH] [--blastradius PATH] Starts the MCP server as a subprocess, sends JSON-RPC messages, validates responses. -All 6 tools tested: analyze_repo, get_impact, get_dependencies, +All tools tested: analyze_repo, get_impact, get_dependencies, get_high_blast_files, build_symbol_index, lookup_symbol. """ from __future__ import annotations @@ -252,18 +252,23 @@ def test_unknown_tool(client: MCPClient, r: Results) -> None: # Entry point # --------------------------------------------------------------------------- def main() -> None: + if hasattr(sys.stdout, "reconfigure"): + sys.stdout.reconfigure(encoding="utf-8", errors="replace") + if hasattr(sys.stderr, "reconfigure"): + sys.stderr.reconfigure(encoding="utf-8", errors="replace") + import argparse parser = argparse.ArgumentParser(description="MCP server integration tests") parser.add_argument("--repo", default=".", help="Repo path (default: .)") parser.add_argument( - "--codeindex", - default="codeindex", - help="Path to codeindex executable (default: codeindex)", + "--blastradius", + default="blastradius", + help="Path to blastradius executable (default: blastradius)", ) args = parser.parse_args() repo = str(Path(args.repo).resolve()) - command = [args.codeindex, "serve", "--mcp"] + command = [args.blastradius, "serve", "--mcp"] print(f"Repo : {repo}") print(f"Command : {' '.join(command)}") @@ -273,7 +278,7 @@ def main() -> None: time.sleep(0.3) # let server start # Discover test fixtures from the repo's own indexes - index_file = Path(repo) / "codeindex.json" + index_file = Path(repo) / "blastradius.json" sym_file = Path(repo) / "symbolindex.json" probe_file = "." diff --git a/blastradius/__init__.py b/blastradius/__init__.py new file mode 100644 index 0000000..70440c1 --- /dev/null +++ b/blastradius/__init__.py @@ -0,0 +1,2 @@ +"""blastradius — repo dependency analyzer with blast-radius impact scoring.""" +__version__ = "0.1.0" diff --git a/codeindex/analyze.py b/blastradius/analyze.py similarity index 96% rename from codeindex/analyze.py rename to blastradius/analyze.py index efcced5..e81ff46 100644 --- a/codeindex/analyze.py +++ b/blastradius/analyze.py @@ -3,13 +3,13 @@ import sys from pathlib import Path -from codeindex.analyzers import ( +from blastradius.analyzers import ( python_analyzer, js_analyzer, css_analyzer, go_analyzer, ruby_analyzer, rust_analyzer, java_analyzer, php_analyzer, docker_analyzer, ci_analyzer, schema_analyzer, terraform_analyzer, ) -from codeindex.analyzers.cross_lang_analyzer import find_api_boundaries -from codeindex.analyzers.monorepo_analyzer import detect_workspaces, assign_packages +from blastradius.analyzers.cross_lang_analyzer import find_api_boundaries +from blastradius.analyzers.monorepo_analyzer import detect_workspaces, assign_packages _SKIP = { "__pycache__", ".venv", "venv", "env", ".git", diff --git a/codeindex/analyzers/__init__.py b/blastradius/analyzers/__init__.py similarity index 100% rename from codeindex/analyzers/__init__.py rename to blastradius/analyzers/__init__.py diff --git a/codeindex/analyzers/base.py b/blastradius/analyzers/base.py similarity index 100% rename from codeindex/analyzers/base.py rename to blastradius/analyzers/base.py diff --git a/codeindex/analyzers/ci_analyzer.py b/blastradius/analyzers/ci_analyzer.py similarity index 100% rename from codeindex/analyzers/ci_analyzer.py rename to blastradius/analyzers/ci_analyzer.py diff --git a/codeindex/analyzers/cross_lang_analyzer.py b/blastradius/analyzers/cross_lang_analyzer.py similarity index 100% rename from codeindex/analyzers/cross_lang_analyzer.py rename to blastradius/analyzers/cross_lang_analyzer.py diff --git a/codeindex/analyzers/css_analyzer.py b/blastradius/analyzers/css_analyzer.py similarity index 100% rename from codeindex/analyzers/css_analyzer.py rename to blastradius/analyzers/css_analyzer.py diff --git a/codeindex/analyzers/docker_analyzer.py b/blastradius/analyzers/docker_analyzer.py similarity index 100% rename from codeindex/analyzers/docker_analyzer.py rename to blastradius/analyzers/docker_analyzer.py diff --git a/codeindex/analyzers/go_analyzer.py b/blastradius/analyzers/go_analyzer.py similarity index 100% rename from codeindex/analyzers/go_analyzer.py rename to blastradius/analyzers/go_analyzer.py diff --git a/codeindex/analyzers/java_analyzer.py b/blastradius/analyzers/java_analyzer.py similarity index 100% rename from codeindex/analyzers/java_analyzer.py rename to blastradius/analyzers/java_analyzer.py diff --git a/codeindex/analyzers/js_analyzer.py b/blastradius/analyzers/js_analyzer.py similarity index 100% rename from codeindex/analyzers/js_analyzer.py rename to blastradius/analyzers/js_analyzer.py diff --git a/codeindex/analyzers/monorepo_analyzer.py b/blastradius/analyzers/monorepo_analyzer.py similarity index 100% rename from codeindex/analyzers/monorepo_analyzer.py rename to blastradius/analyzers/monorepo_analyzer.py diff --git a/codeindex/analyzers/php_analyzer.py b/blastradius/analyzers/php_analyzer.py similarity index 100% rename from codeindex/analyzers/php_analyzer.py rename to blastradius/analyzers/php_analyzer.py diff --git a/codeindex/analyzers/python_analyzer.py b/blastradius/analyzers/python_analyzer.py similarity index 100% rename from codeindex/analyzers/python_analyzer.py rename to blastradius/analyzers/python_analyzer.py diff --git a/codeindex/analyzers/ruby_analyzer.py b/blastradius/analyzers/ruby_analyzer.py similarity index 100% rename from codeindex/analyzers/ruby_analyzer.py rename to blastradius/analyzers/ruby_analyzer.py diff --git a/codeindex/analyzers/rust_analyzer.py b/blastradius/analyzers/rust_analyzer.py similarity index 100% rename from codeindex/analyzers/rust_analyzer.py rename to blastradius/analyzers/rust_analyzer.py diff --git a/codeindex/analyzers/schema_analyzer.py b/blastradius/analyzers/schema_analyzer.py similarity index 100% rename from codeindex/analyzers/schema_analyzer.py rename to blastradius/analyzers/schema_analyzer.py diff --git a/codeindex/analyzers/terraform_analyzer.py b/blastradius/analyzers/terraform_analyzer.py similarity index 100% rename from codeindex/analyzers/terraform_analyzer.py rename to blastradius/analyzers/terraform_analyzer.py diff --git a/codeindex/cli.py b/blastradius/cli.py similarity index 88% rename from codeindex/cli.py rename to blastradius/cli.py index fcd59d6..3f3c6dd 100644 --- a/codeindex/cli.py +++ b/blastradius/cli.py @@ -1,4 +1,4 @@ -"""codeindex CLI entry point.""" +"""blastradius CLI entry point.""" from __future__ import annotations import argparse import json @@ -7,7 +7,7 @@ def _cmd_analyze(args: argparse.Namespace) -> None: - from codeindex.index import build + from blastradius.index import build repo = args.repo output = Path(args.output) if args.output else None @@ -16,7 +16,7 @@ def _cmd_analyze(args: argparse.Namespace) -> None: from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler except ImportError: - print("watchdog not installed — run: pip install 'codeindex[watch]'", file=sys.stderr) + print("watchdog not installed — run: pip install 'blastradius[watch]'", file=sys.stderr) sys.exit(1) import threading @@ -26,7 +26,7 @@ def _cmd_analyze(args: argparse.Namespace) -> None: ".rb", ".go", ".rs", ".java", ".kt", ".php", ".yml", ".yaml", ".sql", ".prisma", } - dest = output or (Path(repo).resolve() / "codeindex.json") + dest = output or (Path(repo).resolve() / "blastradius.json") class _Watcher(FileSystemEventHandler): def __init__(self): @@ -62,16 +62,16 @@ def on_modified(self, event): def _cmd_impact(args: argparse.Namespace) -> None: - from codeindex.index import load, find_index, find_db, db_path_for, INDEX_FILENAME - from codeindex.index import git_reachable, git_resolve - from codeindex.impact import compute_blast_radius - from codeindex.reporter import format_stdout, format_markdown + from blastradius.index import load, find_index, find_db, db_path_for, INDEX_FILENAME + from blastradius.index import git_reachable, git_resolve + from blastradius.impact import compute_blast_radius + from blastradius.reporter import format_stdout, format_markdown as_of = getattr(args, "as_of", None) if as_of: # ── temporal path: query DB for historical blast radius ──────────────── - from codeindex.store import Store + from blastradius.store import Store repo = Path(args.file).resolve().parent db_path = find_db(repo) or find_db(Path.cwd()) @@ -79,7 +79,7 @@ def _cmd_impact(args: argparse.Namespace) -> None: # Try discovering from cwd upward db_path = find_db(Path.cwd()) if not db_path or not db_path.exists(): - print("No .codeindex/index.db found — run: codeindex analyze ", file=sys.stderr) + print("No .blastradius/index.db found — run: blastradius analyze ", file=sys.stderr) sys.exit(1) # Resolve repo root from DB meta @@ -122,7 +122,7 @@ def _cmd_impact(args: argparse.Namespace) -> None: if blast is None: print( f"No temporal data for {file_id} at {as_of}. " - "Run `codeindex history` to backfill, or `codeindex analyze` at each commit.", + "Run `blastradius history` to backfill, or `blastradius analyze` at each commit.", file=sys.stderr, ) sys.exit(1) @@ -152,7 +152,7 @@ def _cmd_impact(args: argparse.Namespace) -> None: index_path = find_index(Path.cwd()) if not index_path: print( - f"No {INDEX_FILENAME} found. Run: codeindex analyze ", + f"No {INDEX_FILENAME} found. Run: blastradius analyze ", file=sys.stderr, ) sys.exit(1) @@ -201,10 +201,10 @@ def _cmd_impact(args: argparse.Namespace) -> None: def _cmd_serve(args: argparse.Namespace) -> None: if args.mcp: - from codeindex.mcp_server import serve + from blastradius.mcp_server import serve serve() else: - from codeindex.viz_server import serve + from blastradius.viz_server import serve output = Path(args.output) if getattr(args, "output", None) else None serve( repo_path=args.repo, @@ -215,11 +215,11 @@ def _cmd_serve(args: argparse.Namespace) -> None: def _cmd_symbols(args: argparse.Namespace) -> None: - from codeindex.symbols import ( + from blastradius.symbols import ( build_symbol_index, write_standalone, write_inline, write_claude_md, SYMBOL_INDEX_FILENAME, ) - from codeindex.index import find_index, INDEX_FILENAME + from blastradius.index import find_index, INDEX_FILENAME repo = Path(args.repo).resolve() symbol_data = build_symbol_index(str(repo)) @@ -231,7 +231,7 @@ def _cmd_symbols(args: argparse.Namespace) -> None: index_path = find_index(repo) if not index_path: print( - f"No {INDEX_FILENAME} found — run: codeindex analyze first, " + f"No {INDEX_FILENAME} found — run: blastradius analyze first, " "or pass --index ", file=sys.stderr, ) @@ -247,8 +247,8 @@ def _cmd_symbols(args: argparse.Namespace) -> None: def _cmd_lookup(args: argparse.Namespace) -> None: - from codeindex.index import db_path_for, find_index, INDEX_FILENAME - from codeindex.store import Store + from blastradius.index import db_path_for, find_index, INDEX_FILENAME + from blastradius.store import Store name = args.name matches = [] @@ -274,13 +274,13 @@ def _cmd_lookup(args: argparse.Namespace) -> None: # Fall back to symbolindex.json when DB not available if not matches and not args.index: try: - from codeindex.mcp_server import _resolve_symbol_index + from blastradius.mcp_server import _resolve_symbol_index sym_data = _resolve_symbol_index(None) matches = sym_data.get("symbols", {}).get(name, []) except FileNotFoundError: pass elif not matches and args.index: - from codeindex.mcp_server import _resolve_symbol_index + from blastradius.mcp_server import _resolve_symbol_index sym_data = _resolve_symbol_index(args.index) matches = sym_data.get("symbols", {}).get(name, []) @@ -309,13 +309,13 @@ def _cmd_lookup(args: argparse.Namespace) -> None: def _cmd_dependencies(args: argparse.Namespace) -> None: - from codeindex.index import load, find_index, INDEX_FILENAME + from blastradius.index import load, find_index, INDEX_FILENAME if args.index: index_path = Path(args.index) else: index_path = find_index(Path(args.file).parent) or find_index(Path.cwd()) if not index_path: - print(f"No {INDEX_FILENAME} found. Run: codeindex analyze ", file=sys.stderr) + print(f"No {INDEX_FILENAME} found. Run: blastradius analyze ", file=sys.stderr) sys.exit(1) data = load(index_path) fp = args.file @@ -347,13 +347,13 @@ def _cmd_dependencies(args: argparse.Namespace) -> None: def _cmd_high_blast(args: argparse.Namespace) -> None: - from codeindex.index import load, find_index, INDEX_FILENAME + from blastradius.index import load, find_index, INDEX_FILENAME if args.index: index_path = Path(args.index) else: index_path = find_index(Path.cwd()) if not index_path: - print(f"No {INDEX_FILENAME} found. Run: codeindex analyze ", file=sys.stderr) + print(f"No {INDEX_FILENAME} found. Run: blastradius analyze ", file=sys.stderr) sys.exit(1) data = load(index_path) threshold = args.threshold @@ -371,7 +371,7 @@ def _cmd_high_blast(args: argparse.Namespace) -> None: for n in results ]}, indent=2)) else: - print(f"Files with blast score ≥ {threshold} ({len(results)} found)\n") + print(f"Files with blast score >= {threshold} ({len(results)} found)\n") for n in results: loc = n.get("loc", 0) loc_str = f" {loc} loc" if loc else "" @@ -381,15 +381,15 @@ def _cmd_high_blast(args: argparse.Namespace) -> None: def _cmd_symbol_blast(args: argparse.Namespace) -> None: """Per-export blast radius: which importers reference each exported symbol.""" - from codeindex.index import find_db + from blastradius.index import find_db import re as _re db_path = find_db(Path.cwd()) if not db_path or not db_path.exists(): - print("No .codeindex/index.db found — run: codeindex analyze ", file=sys.stderr) + print("No .blastradius/index.db found — run: blastradius analyze ", file=sys.stderr) sys.exit(1) - from codeindex.store import Store + from blastradius.store import Store store = Store(db_path) file_path = args.file @@ -444,12 +444,12 @@ def _cmd_symbol_blast(args: argparse.Namespace) -> None: def _cmd_db(args: argparse.Namespace) -> None: - from codeindex.index import find_db - from codeindex.store import Store + from blastradius.index import find_db + from blastradius.store import Store db_path = Path(args.db) if getattr(args, "db", None) else find_db(Path.cwd()) if not db_path or not db_path.exists(): - print("No .codeindex/index.db found — run: codeindex analyze ", file=sys.stderr) + print("No .blastradius/index.db found — run: blastradius analyze ", file=sys.stderr) sys.exit(1) if args.db_command == "status": @@ -477,9 +477,9 @@ def _cmd_db(args: argparse.Namespace) -> None: def _cmd_history(args: argparse.Namespace) -> None: - from codeindex.index import find_db, db_path_for - from codeindex.store import Store - from codeindex.temporal import backfill + from blastradius.index import find_db, db_path_for + from blastradius.store import Store + from blastradius.temporal import backfill repo = Path(args.repo).resolve() db_path = find_db(repo) or db_path_for(repo) @@ -503,12 +503,12 @@ def _cmd_history(args: argparse.Namespace) -> None: def _cmd_changed_since(args: argparse.Namespace) -> None: - from codeindex.index import find_db, git_reachable, git_resolve, git_modified - from codeindex.store import Store + from blastradius.index import find_db, git_reachable, git_resolve, git_modified + from blastradius.store import Store db_path = Path(args.db) if getattr(args, "db", None) else find_db(Path.cwd()) if not db_path or not db_path.exists(): - print("No .codeindex/index.db found — run: codeindex analyze ", file=sys.stderr) + print("No .blastradius/index.db found — run: blastradius analyze ", file=sys.stderr) sys.exit(1) repo = Path(args.repo).resolve() if getattr(args, "repo", None) else Path.cwd() @@ -592,36 +592,36 @@ def _cmd_changed_since(args: argparse.Namespace) -> None: if result.get("warning"): # history has never been run — backfill will resolve these print(f"\n ({analyze_origin_count} of {len(ae)} added edge(s) first seen at last-analyzed HEAD" - f" — run `codeindex history` to date them accurately)") + f" — run `blastradius history` to date them accurately)") else: # history has been run; these edges predate the first analyze print(f"\n ({analyze_origin_count} of {len(ae)} added edge(s) are bootstrap-gap artifacts:" - f" they existed before the first `codeindex analyze` and cannot be dated further)") + f" they existed before the first `blastradius analyze` and cannot be dated further)") if not any([mf, af, rf, ae, re_]): print(" (no changes detected)") def _cmd_search(args: argparse.Namespace) -> None: - from codeindex.index import find_db, git_reachable, git_resolve - from codeindex.store import Store - from codeindex.semantic.search import hybrid_search + from blastradius.index import find_db, git_reachable, git_resolve + from blastradius.store import Store + from blastradius.semantic.search import hybrid_search db_path = Path(args.db) if getattr(args, "db", None) else find_db(Path.cwd()) if not db_path or not db_path.exists(): - print("No .codeindex/index.db found — run: codeindex analyze ", file=sys.stderr) + print("No .blastradius/index.db found — run: blastradius analyze ", file=sys.stderr) sys.exit(1) store = Store(db_path) provider = None import os - endpoint = os.environ.get("CODEINDEX_EMBEDDING_ENDPOINT", "") - model = os.environ.get("CODEINDEX_EMBEDDING_MODEL", "") - dims_str = os.environ.get("CODEINDEX_EMBEDDING_DIMS", "") + endpoint = os.environ.get("BLASTRADIUS_EMBEDDING_ENDPOINT", "") + model = os.environ.get("BLASTRADIUS_EMBEDDING_MODEL", "") + dims_str = os.environ.get("BLASTRADIUS_EMBEDDING_DIMS", "") if endpoint and model and dims_str: try: dims = int(dims_str) - from codeindex.semantic.provider import OpenAIEmbeddingProvider + from blastradius.semantic.provider import OpenAIEmbeddingProvider provider = OpenAIEmbeddingProvider(endpoint=endpoint, model=model, dims=dims) except Exception: pass @@ -673,7 +673,7 @@ def _cmd_search(args: argparse.Namespace) -> None: def _cmd_install_hook(args: argparse.Namespace) -> None: - from codeindex.hook import install + from blastradius.hook import install install( repo_path=args.repo, threshold=args.threshold, @@ -684,21 +684,21 @@ def _cmd_install_hook(args: argparse.Namespace) -> None: def _build_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( - prog="codeindex", + prog="blastradius", description="Repo dependency analyzer with blast-radius impact scoring.", ) sub = parser.add_subparsers(dest="command", required=True) # ── analyze ──────────────────────────────────────────────────────────── - p_analyze = sub.add_parser("analyze", help="Analyze a repo and write codeindex.json") + p_analyze = sub.add_parser("analyze", help="Analyze a repo and write blastradius.json") p_analyze.add_argument("repo", nargs="?", default=".", help="Path to repo root (default: .)") - p_analyze.add_argument("--output", help="Output path (default: /codeindex.json)") + p_analyze.add_argument("--output", help="Output path (default: /blastradius.json)") p_analyze.add_argument("--watch", action="store_true", help="Re-index on file changes") # ── impact ───────────────────────────────────────────────────────────── p_impact = sub.add_parser("impact", help="Show blast-radius impact for a file") p_impact.add_argument("file", help="File path to assess") - p_impact.add_argument("--index", help="Path to codeindex.json (auto-discovered if omitted)") + p_impact.add_argument("--index", help="Path to blastradius.json (auto-discovered if omitted)") p_impact.add_argument("--out", help="Write markdown report to this file") p_impact.add_argument("--json", action="store_true", help="Output raw JSON") p_impact.add_argument("--as-of", dest="as_of", metavar="REF", @@ -712,7 +712,7 @@ def _build_parser() -> argparse.ArgumentParser: p_serve.add_argument("--repo", default=".", help="Repo to analyze (viz mode)") p_serve.add_argument("--port", type=int, default=8080, help="Port for viz server") p_serve.add_argument("--watch", action="store_true", help="Watch for file changes (viz mode)") - p_serve.add_argument("--output", help="codeindex.json path override (viz mode)") + p_serve.add_argument("--output", help="blastradius.json path override (viz mode)") # ── symbols ──────────────────────────────────────────────────────────────── p_sym = sub.add_parser("symbols", help="Build a symbol index (functions, classes, exports)") @@ -722,11 +722,11 @@ def _build_parser() -> argparse.ArgumentParser: ) p_sym.add_argument( "--inline", action="store_true", - help="Embed symbols into codeindex.json nodes instead of a separate file", + help="Embed symbols into blastradius.json nodes instead of a separate file", ) p_sym.add_argument( "--index", - help="Path to codeindex.json for --inline mode (auto-discovered if omitted)", + help="Path to blastradius.json for --inline mode (auto-discovered if omitted)", ) p_sym.add_argument( "--claude-md", dest="claude_md", action="store_true", @@ -750,13 +750,13 @@ def _build_parser() -> argparse.ArgumentParser: # ── dependencies ─────────────────────────────────────────────────────── p_deps = sub.add_parser("dependencies", help="Show imports and imported-by for a file") p_deps.add_argument("file", help="File path to inspect") - p_deps.add_argument("--index", help="Path to codeindex.json (auto-discovered if omitted)") + p_deps.add_argument("--index", help="Path to blastradius.json (auto-discovered if omitted)") p_deps.add_argument("--json", action="store_true", help="Output raw JSON") # ── high-blast ───────────────────────────────────────────────────────── p_hb = sub.add_parser("high-blast", help="List files above a blast score threshold") p_hb.add_argument("--threshold", type=float, default=5.0, help="Minimum blast score (default: 5)") - p_hb.add_argument("--index", help="Path to codeindex.json (auto-discovered if omitted)") + p_hb.add_argument("--index", help="Path to blastradius.json (auto-discovered if omitted)") p_hb.add_argument("--json", action="store_true", help="Output raw JSON") # ── symbol-blast ────────────────────────────────────────────────────────── @@ -768,7 +768,7 @@ def _build_parser() -> argparse.ArgumentParser: p_sb.add_argument("--json", action="store_true", help="Output raw JSON") # ── db ───────────────────────────────────────────────────────────────────── - p_db = sub.add_parser("db", help="Manage the SQLite store (.codeindex/index.db)") + p_db = sub.add_parser("db", help="Manage the SQLite store (.blastradius/index.db)") p_db.add_argument("--db", help="Path to index.db (auto-discovered if omitted)") p_db.add_argument("--json", action="store_true", help="Output raw JSON (status only)") db_sub = p_db.add_subparsers(dest="db_command", required=True) @@ -824,6 +824,11 @@ def _build_parser() -> argparse.ArgumentParser: def main() -> None: + if hasattr(sys.stdout, "reconfigure"): + sys.stdout.reconfigure(encoding="utf-8", errors="replace") + if hasattr(sys.stderr, "reconfigure"): + sys.stderr.reconfigure(encoding="utf-8", errors="replace") + parser = _build_parser() args = parser.parse_args() diff --git a/codeindex/hook.py b/blastradius/hook.py similarity index 73% rename from codeindex/hook.py rename to blastradius/hook.py index d171b6f..62b685c 100644 --- a/codeindex/hook.py +++ b/blastradius/hook.py @@ -5,21 +5,21 @@ import sys from pathlib import Path -HOOK_MARKER = "# codeindex-hook" +HOOK_MARKER = "# blastradius-hook" HOOK_TEMPLATE = """\ #!/usr/bin/env bash {marker} -# Installed by codeindex. Remove this file or run `codeindex install-hook --remove` to disable. +# Installed by blastradius. Remove this file or run `blastradius install-hook --remove` to disable. THRESHOLD={threshold} STRICT={strict} -# Find codeindex.json by walking up from repo root -INDEX=$(git rev-parse --show-toplevel)/codeindex.json +# Find blastradius.json by walking up from repo root +INDEX=$(git rev-parse --show-toplevel)/blastradius.json if [ ! -f "$INDEX" ]; then - echo "[codeindex] No codeindex.json found — skipping impact check. Run: codeindex analyze ." + echo "[blastradius] No blastradius.json found — skipping impact check. Run: blastradius analyze ." exit 0 fi @@ -33,14 +33,14 @@ WARNED=0 while IFS= read -r FILE; do if [ -z "$FILE" ]; then continue; fi - OUTPUT=$(codeindex impact "$FILE" --index "$INDEX" 2>/dev/null) + OUTPUT=$(blastradius impact "$FILE" --index "$INDEX" 2>/dev/null) if [ $? -ne 0 ]; then continue; fi SCORE=$(echo "$OUTPUT" | grep -oP 'Blast Score: \\K[0-9.]+') if [ -z "$SCORE" ]; then continue; fi SCORE_INT=$(echo "$SCORE" | cut -d. -f1) if [ "$SCORE_INT" -ge "$THRESHOLD" ] 2>/dev/null; then echo "" - echo "[codeindex] HIGH BLAST RADIUS: $FILE (score: $SCORE)" + echo "[blastradius] HIGH BLAST RADIUS: $FILE (score: $SCORE)" echo "$OUTPUT" echo "" WARNED=1 @@ -48,7 +48,7 @@ done <<< "$STAGED" if [ "$WARNED" -eq 1 ] && [ "$STRICT" = "1" ]; then - echo "[codeindex] Commit blocked (--strict mode). Review impact above." + echo "[blastradius] Commit blocked (--strict mode). Review impact above." exit 1 fi @@ -70,9 +70,9 @@ def install(repo_path: str, threshold: int = 10, strict: bool = False, remove: b content = hook_path.read_text() if HOOK_MARKER in content: hook_path.unlink() - print(f"Removed codeindex pre-commit hook from {hook_path}") + print(f"Removed blastradius pre-commit hook from {hook_path}") else: - print("Pre-commit hook exists but was not installed by codeindex — not removing.") + print("Pre-commit hook exists but was not installed by blastradius — not removing.") else: print("No pre-commit hook found.") return @@ -81,7 +81,7 @@ def install(repo_path: str, threshold: int = 10, strict: bool = False, remove: b content = hook_path.read_text() if HOOK_MARKER not in content: print( - f"A pre-commit hook already exists at {hook_path} and was not installed by codeindex.\n" + f"A pre-commit hook already exists at {hook_path} and was not installed by blastradius.\n" "Add the following manually or use a hook manager (husky, pre-commit, lefthook).", file=sys.stderr, ) @@ -99,7 +99,7 @@ def install(repo_path: str, threshold: int = 10, strict: bool = False, remove: b mode = "strict (blocks commit)" if strict else "warn-only" print( - f"Installed codeindex pre-commit hook → {hook_path}\n" + f"Installed blastradius pre-commit hook → {hook_path}\n" f" threshold: {threshold} mode: {mode}\n" - "Run `codeindex install-hook --remove` to uninstall." + "Run `blastradius install-hook --remove` to uninstall." ) diff --git a/codeindex/impact.py b/blastradius/impact.py similarity index 100% rename from codeindex/impact.py rename to blastradius/impact.py diff --git a/codeindex/index.py b/blastradius/index.py similarity index 88% rename from codeindex/index.py rename to blastradius/index.py index 5519977..be006f1 100644 --- a/codeindex/index.py +++ b/blastradius/index.py @@ -1,9 +1,9 @@ # Copyright 2026 David Scheiderman # Licensed under the Apache License, Version 2.0 -"""Build and persist codeindex.json in the target repo root. +"""Build and persist blastradius.json in the target repo root. Phase-1 change: build() now also syncs graph data to a SQLite store at -/.codeindex/index.db. The JSON write path is unchanged so existing +/.blastradius/index.db. The JSON write path is unchanged so existing consumers keep working without modification. """ from __future__ import annotations @@ -14,12 +14,12 @@ import sys from pathlib import Path -from codeindex.analyze import analyze -from codeindex.impact import compute_blast_radius, enrich_nodes, enrich_links -from codeindex.store import Store +from blastradius.analyze import analyze +from blastradius.impact import compute_blast_radius, enrich_nodes, enrich_links +from blastradius.store import Store -INDEX_FILENAME = "codeindex.json" -_DB_DIR = ".codeindex" +INDEX_FILENAME = "blastradius.json" +_DB_DIR = ".blastradius" _DB_NAME = "index.db" @@ -109,13 +109,13 @@ def _content_hash(root: Path, rel_path: str) -> str | None: def _embed_new_symbols(store) -> None: """Embed symbols that lack a vector entry, if an embedding endpoint is configured. - Reads CODEINDEX_EMBEDDING_ENDPOINT / _MODEL / _DIMS from env. + Reads BLASTRADIUS_EMBEDDING_ENDPOINT / _MODEL / _DIMS from env. Silently skips if any required env var is missing or if the call fails. """ import os - endpoint = os.environ.get("CODEINDEX_EMBEDDING_ENDPOINT", "") - model = os.environ.get("CODEINDEX_EMBEDDING_MODEL", "") - dims_str = os.environ.get("CODEINDEX_EMBEDDING_DIMS", "") + endpoint = os.environ.get("BLASTRADIUS_EMBEDDING_ENDPOINT", "") + model = os.environ.get("BLASTRADIUS_EMBEDDING_MODEL", "") + dims_str = os.environ.get("BLASTRADIUS_EMBEDDING_DIMS", "") if not (endpoint and model and dims_str): return try: @@ -131,7 +131,7 @@ def _embed_new_symbols(store) -> None: return try: - from codeindex.semantic.provider import OpenAIEmbeddingProvider + from blastradius.semantic.provider import OpenAIEmbeddingProvider provider = OpenAIEmbeddingProvider(endpoint=endpoint, model=model, dims=dims) ids = [p[0] for p in pairs] texts = [p[1] for p in pairs] @@ -184,7 +184,7 @@ def build(repo_path: str, output: Path | None = None) -> dict: # Build and sync symbol index try: - from codeindex.symbols import build_symbol_index + from blastradius.symbols import build_symbol_index symbol_data = build_symbol_index(str(root)) store.sync_symbols(symbol_data, commit=head_commit) except Exception as exc: @@ -216,13 +216,13 @@ def build(repo_path: str, output: Path | None = None) -> dict: def load(index_path: Path) -> dict: if not index_path.exists(): raise FileNotFoundError( - f"{index_path} not found — run: codeindex analyze " + f"{index_path} not found — run: blastradius analyze " ) return json.loads(index_path.read_text()) def find_index(start: Path) -> Path | None: - """Walk up from start looking for codeindex.json.""" + """Walk up from start looking for blastradius.json.""" current = start.resolve() for _ in range(10): candidate = current / INDEX_FILENAME @@ -236,7 +236,7 @@ def find_index(start: Path) -> Path | None: def find_db(start: Path) -> Path | None: - """Walk up from start looking for .codeindex/index.db.""" + """Walk up from start looking for .blastradius/index.db.""" current = start.resolve() for _ in range(10): candidate = current / _DB_DIR / _DB_NAME diff --git a/codeindex/mcp_server.py b/blastradius/mcp_server.py similarity index 90% rename from codeindex/mcp_server.py rename to blastradius/mcp_server.py index 19a9882..fc7de0b 100644 --- a/codeindex/mcp_server.py +++ b/blastradius/mcp_server.py @@ -1,21 +1,21 @@ # Copyright 2026 David Scheiderman # Licensed under the Apache License, Version 2.0 -"""Stdio MCP server — exposes codeindex tools to Claude and other MCP clients.""" +"""Stdio MCP server — exposes blastradius tools to Claude and other MCP clients.""" from __future__ import annotations import json import sys from pathlib import Path -from codeindex.index import build, load, find_index, find_db, INDEX_FILENAME -from codeindex.index import git_reachable, git_resolve, git_modified -from codeindex.impact import compute_blast_radius -from codeindex.reporter import format_markdown -from codeindex.symbols import SYMBOL_INDEX_FILENAME +from blastradius.index import build, load, find_index, find_db, INDEX_FILENAME +from blastradius.index import git_reachable, git_resolve, git_modified +from blastradius.impact import compute_blast_radius +from blastradius.reporter import format_markdown +from blastradius.symbols import SYMBOL_INDEX_FILENAME TOOLS = [ { "name": "analyze_repo", - "description": "Analyze a repository and build/refresh its codeindex.json dependency index.", + "description": "Analyze a repository and build/refresh its blastradius.json dependency index.", "inputSchema": { "type": "object", "properties": { @@ -43,7 +43,7 @@ }, "index_path": { "type": "string", - "description": "Path to codeindex.json. Auto-discovered if omitted.", + "description": "Path to blastradius.json. Auto-discovered if omitted.", }, }, "required": ["file_path"], @@ -61,7 +61,7 @@ }, "index_path": { "type": "string", - "description": "Path to codeindex.json. Auto-discovered if omitted.", + "description": "Path to blastradius.json. Auto-discovered if omitted.", }, }, "required": ["file_path"], @@ -79,7 +79,7 @@ }, "index_path": { "type": "string", - "description": "Path to codeindex.json. Auto-discovered if omitted.", + "description": "Path to blastradius.json. Auto-discovered if omitted.", }, }, }, @@ -150,7 +150,7 @@ }, "db_path": { "type": "string", - "description": "Path to .codeindex/index.db. Auto-discovered from cwd if omitted.", + "description": "Path to .blastradius/index.db. Auto-discovered from cwd if omitted.", }, }, "required": ["query"], @@ -161,8 +161,8 @@ "description": ( "Compute blast-radius impact for a file at a historical commit/ref. " "Shows which files depended on it at that point in time, not just at HEAD. " - "Requires codeindex analyze to have been run at (or near) the target commit, " - "or codeindex history to have backfilled temporal data." + "Requires blastradius analyze to have been run at (or near) the target commit, " + "or blastradius history to have backfilled temporal data." ), "inputSchema": { "type": "object", @@ -177,7 +177,7 @@ }, "db_path": { "type": "string", - "description": "Path to .codeindex/index.db. Auto-discovered from cwd if omitted.", + "description": "Path to .blastradius/index.db. Auto-discovered from cwd if omitted.", }, }, "required": ["file"], @@ -208,7 +208,7 @@ }, "db_path": { "type": "string", - "description": "Path to .codeindex/index.db. Auto-discovered from cwd if omitted.", + "description": "Path to .blastradius/index.db. Auto-discovered from cwd if omitted.", }, }, "required": ["file"], @@ -230,7 +230,7 @@ }, "db_path": { "type": "string", - "description": "Path to .codeindex/index.db. Auto-discovered from cwd if omitted.", + "description": "Path to .blastradius/index.db. Auto-discovered from cwd if omitted.", }, }, "required": ["ref"], @@ -245,7 +245,7 @@ def _resolve_index(index_path: str | None) -> dict: discovered = find_index(Path.cwd()) if not discovered: raise FileNotFoundError( - f"No {INDEX_FILENAME} found. Run: codeindex analyze " + f"No {INDEX_FILENAME} found. Run: blastradius analyze " ) return load(discovered) @@ -342,13 +342,13 @@ def _resolve_symbol_index(symbol_index_path: str | None) -> dict: p = _find_symbol_index(Path.cwd()) if not p or not p.exists(): raise FileNotFoundError( - f"No {SYMBOL_INDEX_FILENAME} found. Run: codeindex symbols " + f"No {SYMBOL_INDEX_FILENAME} found. Run: blastradius symbols " ) return json.loads(p.read_text()) def _call_lookup_symbol(params: dict) -> dict: - from codeindex.store import Store + from blastradius.store import Store name = params["name"] matches = [] @@ -394,7 +394,7 @@ def _call_lookup_symbol(params: dict) -> dict: def _call_build_symbol_index(params: dict) -> dict: - from codeindex.symbols import build_symbol_index as _build, write_standalone # noqa: PLC0415 + from blastradius.symbols import build_symbol_index as _build, write_standalone # noqa: PLC0415 repo_path = params["repo_path"] symbol_data = _build(repo_path) out = Path(repo_path) / SYMBOL_INDEX_FILENAME @@ -409,7 +409,7 @@ def _call_build_symbol_index(params: dict) -> dict: def _resolve_db(params: dict): """Return an open Store for the db_path in params or auto-discovered from cwd.""" - from codeindex.store import Store + from blastradius.store import Store db_path_str = params.get("db_path") if db_path_str: db_path = Path(db_path_str) @@ -417,24 +417,24 @@ def _resolve_db(params: dict): db_path = find_db(Path.cwd()) if not db_path or not db_path.exists(): raise FileNotFoundError( - "No .codeindex/index.db found — run: codeindex analyze " + "No .blastradius/index.db found — run: blastradius analyze " ) return Store(db_path) def _call_semantic_search(params: dict) -> dict: - from codeindex.semantic.search import hybrid_search + from blastradius.semantic.search import hybrid_search import os store = _resolve_db(params) provider = None - endpoint = os.environ.get("CODEINDEX_EMBEDDING_ENDPOINT", "") - model = os.environ.get("CODEINDEX_EMBEDDING_MODEL", "") - dims_str = os.environ.get("CODEINDEX_EMBEDDING_DIMS", "") + endpoint = os.environ.get("BLASTRADIUS_EMBEDDING_ENDPOINT", "") + model = os.environ.get("BLASTRADIUS_EMBEDDING_MODEL", "") + dims_str = os.environ.get("BLASTRADIUS_EMBEDDING_DIMS", "") if endpoint and model and dims_str: try: - from codeindex.semantic.provider import OpenAIEmbeddingProvider + from blastradius.semantic.provider import OpenAIEmbeddingProvider provider = OpenAIEmbeddingProvider( endpoint=endpoint, model=model, dims=int(dims_str) ) @@ -504,7 +504,7 @@ def _call_temporal_impact(params: dict) -> dict: return { "error": ( f"No temporal data for {file_id} at {as_of}. " - "Run `codeindex history` to backfill or `codeindex analyze` at each commit." + "Run `blastradius history` to backfill or `blastradius analyze` at each commit." ) } return { @@ -657,7 +657,7 @@ def err(code, message): return ok({ "protocolVersion": "2024-11-05", "capabilities": {"tools": {}}, - "serverInfo": {"name": "codeindex", "version": "0.1.0"}, + "serverInfo": {"name": "blastradius", "version": "0.1.0"}, }) if method == "notifications/initialized": @@ -690,7 +690,7 @@ def err(code, message): def serve() -> None: - print("[codeindex MCP] ready on stdio", file=sys.stderr) + print("[blastradius MCP] ready on stdio", file=sys.stderr) for line in sys.stdin: line = line.strip() if not line: diff --git a/codeindex/reporter.py b/blastradius/reporter.py similarity index 97% rename from codeindex/reporter.py rename to blastradius/reporter.py index 58f6381..50492b6 100644 --- a/codeindex/reporter.py +++ b/blastradius/reporter.py @@ -105,7 +105,7 @@ def format_markdown( ) lines.append("") lines.append( - "_Generated by [codeindex](https://github.com/scheidydudes/codeindex)_" + "_Generated by [blastradius](https://github.com/scheidydudes/blastradius)_" ) return "\n".join(lines) diff --git a/codeindex/semantic/__init__.py b/blastradius/semantic/__init__.py similarity index 58% rename from codeindex/semantic/__init__.py rename to blastradius/semantic/__init__.py index 0b56cb7..9e68cf6 100644 --- a/codeindex/semantic/__init__.py +++ b/blastradius/semantic/__init__.py @@ -2,7 +2,7 @@ # Licensed under the Apache License, Version 2.0 from __future__ import annotations -from codeindex.semantic.provider import EmbeddingProvider, OpenAIEmbeddingProvider -from codeindex.semantic.search import hybrid_search +from blastradius.semantic.provider import EmbeddingProvider, OpenAIEmbeddingProvider +from blastradius.semantic.search import hybrid_search __all__ = ["EmbeddingProvider", "OpenAIEmbeddingProvider", "hybrid_search"] diff --git a/codeindex/semantic/provider.py b/blastradius/semantic/provider.py similarity index 93% rename from codeindex/semantic/provider.py rename to blastradius/semantic/provider.py index cde1bd0..e981e93 100644 --- a/codeindex/semantic/provider.py +++ b/blastradius/semantic/provider.py @@ -2,8 +2,8 @@ # Licensed under the Apache License, Version 2.0 """Embedding provider interface and OpenAI-compatible HTTP client. -Dependency rule: this module must not import from codeindex.store, codeindex.graph, -or any other codeindex layer. It is a pure provider abstraction. +Dependency rule: this module must not import from blastradius.store, blastradius.graph, +or any other blastradius layer. It is a pure provider abstraction. """ from __future__ import annotations diff --git a/codeindex/semantic/search.py b/blastradius/semantic/search.py similarity index 92% rename from codeindex/semantic/search.py rename to blastradius/semantic/search.py index c438253..c201b38 100644 --- a/codeindex/semantic/search.py +++ b/blastradius/semantic/search.py @@ -7,8 +7,8 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from codeindex.store.db import Store - from codeindex.semantic.provider import EmbeddingProvider + from blastradius.store.db import Store + from blastradius.semantic.provider import EmbeddingProvider _RRF_K = 60 # standard RRF constant @@ -67,10 +67,10 @@ def _note(sid: int, signal: str) -> None: if sem_ids: ranked_lists.append(sem_ids) except Exception as exc: - print(f"[codeindex] semantic search skipped: {exc}", file=sys.stderr) + print(f"[blastradius] semantic search skipped: {exc}", file=sys.stderr) elif provider is not None and not store._has_vec: print( - "[codeindex] sqlite-vec not available — falling back to FTS + graph search.", + "[blastradius] sqlite-vec not available — falling back to FTS + graph search.", file=sys.stderr, ) @@ -82,7 +82,7 @@ def _note(sid: int, signal: str) -> None: if fts_ids: ranked_lists.append(fts_ids) except Exception as exc: - print(f"[codeindex] FTS search skipped: {exc}", file=sys.stderr) + print(f"[blastradius] FTS search skipped: {exc}", file=sys.stderr) # 3. Graph expansion: supplement when primary signals are sparse. # Skip if FTS (or semantic) already returned enough results — graph neighbours diff --git a/codeindex/store/__init__.py b/blastradius/store/__init__.py similarity index 74% rename from codeindex/store/__init__.py rename to blastradius/store/__init__.py index 7107058..87fd348 100644 --- a/codeindex/store/__init__.py +++ b/blastradius/store/__init__.py @@ -2,6 +2,6 @@ # Licensed under the Apache License, Version 2.0 from __future__ import annotations -from codeindex.store.db import Store, SCHEMA_VERSION +from blastradius.store.db import Store, SCHEMA_VERSION __all__ = ["Store", "SCHEMA_VERSION"] diff --git a/codeindex/store/db.py b/blastradius/store/db.py similarity index 98% rename from codeindex/store/db.py rename to blastradius/store/db.py index cb2ffb3..9a2c758 100644 --- a/codeindex/store/db.py +++ b/blastradius/store/db.py @@ -1,9 +1,9 @@ # Copyright 2026 David Scheiderman # Licensed under the Apache License, Version 2.0 -"""SQLite-backed persistent store for codeindex graph data. +"""SQLite-backed persistent store for blastradius graph data. -Dependency rule: this module must not import from codeindex.graph or -codeindex.semantic. The dependency arrow points only upward into this layer. +Dependency rule: this module must not import from blastradius.graph or +blastradius.semantic. The dependency arrow points only upward into this layer. """ from __future__ import annotations @@ -185,7 +185,7 @@ def _maybe_load_vec(self) -> None: self._vec_dims = int(dims_str) self._has_vec = True except Exception as exc: - print(f"[codeindex] sqlite-vec load failed: {exc}", file=sys.stderr) + print(f"[blastradius] sqlite-vec load failed: {exc}", file=sys.stderr) self._has_vec = False # ── meta ────────────────────────────────────────────────────────────────── @@ -551,7 +551,7 @@ def as_of_impact(self, file_path: str, reachable: set) -> dict | None: obtained via `git log --format=%H `. Returns None if no temporal data is available. """ - from codeindex.impact import compute_blast_radius # avoid circular at module level + from blastradius.impact import compute_blast_radius # avoid circular at module level self._populate_reachable_temp(reachable) @@ -607,7 +607,7 @@ def _backfill_warning(self) -> str | None: if row and row[0] <= 1: return ( "Git history has not been backfilled — all files share the same " - "first_seen_commit. Run `codeindex history` first for accurate " + "first_seen_commit. Run `blastradius history` first for accurate " "changed_since results." ) return None @@ -690,8 +690,8 @@ def init_vectors(self, dims: int) -> bool: """ if not _HAS_SQLITE_VEC: print( - "[codeindex] sqlite-vec not installed — semantic search unavailable. " - "Install with: pip install 'codeindex[semantic]'", + "[blastradius] sqlite-vec not installed — semantic search unavailable. " + "Install with: pip install 'blastradius[semantic]'", file=sys.stderr, ) return False @@ -711,7 +711,7 @@ def init_vectors(self, dims: int) -> bool: self._conn.commit() return True except Exception as exc: - print(f"[codeindex] sqlite-vec init failed: {exc}", file=sys.stderr) + print(f"[blastradius] sqlite-vec init failed: {exc}", file=sys.stderr) self._has_vec = False return False @@ -1014,7 +1014,7 @@ def neighborhood(self, file_path: str, direction: str, depth: int) -> dict: # ── status ──────────────────────────────────────────────────────────────── def status(self) -> dict: - """Return a snapshot of store state for `codeindex db status`.""" + """Return a snapshot of store state for `blastradius db status`.""" try: fts_rows = self._conn.execute( "SELECT COUNT(*) FROM symbols_fts" diff --git a/codeindex/symbol_extractor.py b/blastradius/symbol_extractor.py similarity index 99% rename from codeindex/symbol_extractor.py rename to blastradius/symbol_extractor.py index 8e16ceb..f484280 100644 --- a/codeindex/symbol_extractor.py +++ b/blastradius/symbol_extractor.py @@ -1,4 +1,4 @@ -"""Per-language symbol extraction for the codeindex symbol index.""" +"""Per-language symbol extraction for the blastradius symbol index.""" from __future__ import annotations import ast import re diff --git a/codeindex/symbols.py b/blastradius/symbols.py similarity index 92% rename from codeindex/symbols.py rename to blastradius/symbols.py index dd277a8..9ce1299 100644 --- a/codeindex/symbols.py +++ b/blastradius/symbols.py @@ -5,13 +5,13 @@ from datetime import date from pathlib import Path -from codeindex.analyzers.base import load_gitignore_patterns, is_ignored, is_skip_dir -from codeindex.symbol_extractor import EXTRACTORS, extract_symbols +from blastradius.analyzers.base import load_gitignore_patterns, is_ignored, is_skip_dir +from blastradius.symbol_extractor import EXTRACTORS, extract_symbols SYMBOL_INDEX_FILENAME = "symbolindex.json" -_CLAUDE_START = "" -_CLAUDE_END = "" +_CLAUDE_START = "" +_CLAUDE_END = "" _SUPPORTED_EXTS = frozenset(EXTRACTORS.keys()) @@ -91,7 +91,7 @@ def write_standalone(symbol_data: dict, output: Path) -> None: def write_inline(symbol_data: dict, index_path: Path) -> None: - """Embed symbols into each node in an existing codeindex.json.""" + """Embed symbols into each node in an existing blastradius.json.""" data = json.loads(index_path.read_text()) by_file = symbol_data["file_symbols"] enriched = 0 @@ -136,7 +136,7 @@ def _build_claude_section(symbol_data: dict, exported_only: bool = True) -> str: lines = [ _CLAUDE_START, "## Symbol Index", - "_Generated by codeindex. Update: `codeindex symbols --claude-md`_", + "_Generated by blastradius. Update: `blastradius symbols --claude-md`_", "", "```symbolindex", ] diff --git a/codeindex/temporal/__init__.py b/blastradius/temporal/__init__.py similarity index 74% rename from codeindex/temporal/__init__.py rename to blastradius/temporal/__init__.py index 8d0e19f..ed3460c 100644 --- a/codeindex/temporal/__init__.py +++ b/blastradius/temporal/__init__.py @@ -2,6 +2,6 @@ # Licensed under the Apache License, Version 2.0 from __future__ import annotations -from codeindex.temporal.history import backfill +from blastradius.temporal.history import backfill __all__ = ["backfill"] diff --git a/codeindex/temporal/history.py b/blastradius/temporal/history.py similarity index 98% rename from codeindex/temporal/history.py rename to blastradius/temporal/history.py index 9fb3544..1dae791 100644 --- a/codeindex/temporal/history.py +++ b/blastradius/temporal/history.py @@ -2,7 +2,7 @@ # Licensed under the Apache License, Version 2.0 """Git history backfill via plumbing — never touches the working tree. -Dependency rule: must not import from codeindex.graph or codeindex.semantic. +Dependency rule: must not import from blastradius.graph or blastradius.semantic. """ from __future__ import annotations @@ -221,7 +221,7 @@ def _is_parseable(rel_path: str) -> bool: def backfill( root: Path, - store: object, # codeindex.store.Store — avoid circular import + store: object, # blastradius.store.Store — avoid circular import since: str | None = None, max_commits: int | None = 1000, ) -> tuple[int, int]: diff --git a/codeindex/viz_server.py b/blastradius/viz_server.py similarity index 91% rename from codeindex/viz_server.py rename to blastradius/viz_server.py index bc6d49c..5f9a9c4 100644 --- a/codeindex/viz_server.py +++ b/blastradius/viz_server.py @@ -1,4 +1,4 @@ -"""Minimal HTTP server for the codeindex visualization UI.""" +"""Minimal HTTP server for the blastradius visualization UI.""" from __future__ import annotations import json import os @@ -12,11 +12,11 @@ VIZ_HTML = HERE.parent / "viz" / "explorer.html" REPO_PATH = "." -INDEX_FILE: Path = Path("codeindex.json") +INDEX_FILE: Path = Path("blastradius.json") def _run_analysis(repo_path: str, output: Path) -> bool: - from codeindex.index import build + from blastradius.index import build try: build(repo_path, output) return True @@ -60,7 +60,7 @@ def do_GET(self): if INDEX_FILE.exists(): self._send_file(INDEX_FILE, "application/json") else: - self._send_json({"error": "codeindex.json not found — run: codeindex analyze "}, 404) + self._send_json({"error": "blastradius.json not found — run: blastradius analyze "}, 404) elif path == "/refresh": ok = _run_analysis(REPO_PATH, INDEX_FILE) @@ -111,7 +111,7 @@ def on_modified(self, event): def serve(repo_path: str, port: int = 8080, watch: bool = False, output: Path | None = None) -> None: global REPO_PATH, INDEX_FILE REPO_PATH = repo_path - INDEX_FILE = output or (Path(repo_path).resolve() / "codeindex.json") + INDEX_FILE = output or (Path(repo_path).resolve() / "blastradius.json") print(f"Analyzing {repo_path} …", file=sys.stderr) _run_analysis(repo_path, INDEX_FILE) diff --git a/codeindex/__init__.py b/codeindex/__init__.py deleted file mode 100644 index 3830db6..0000000 --- a/codeindex/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -"""codeindex — repo dependency analyzer with blast-radius impact scoring.""" -__version__ = "0.1.0" diff --git a/docs/CKG-INTERNALS.md b/docs/CKG-INTERNALS.md index d865450..74e90ce 100644 --- a/docs/CKG-INTERNALS.md +++ b/docs/CKG-INTERNALS.md @@ -1,4 +1,4 @@ -# CKG-INTERNALS: codeindex Internal Architecture +# CKG-INTERNALS: blastradius Internal Architecture | | | |---|---| @@ -14,7 +14,7 @@ Produced per Phase 0 of CKG-DESIGN-001. Documents current module structure, data ## 1. Module Map ``` -codeindex/ +blastradius/ __init__.py — package metadata; version "0.1.0" cli.py — argparse CLI; 8 commands; dispatch table at line 353 index.py — build() orchestrator; load() reader; find_index() discovery @@ -115,10 +115,10 @@ def build(repo_path, output): enrich_links(data["nodes"], data["links"]) # impact.py:81–99 — adds imports/imported_by data["meta"]["indexed"] = True dest = output or (root / INDEX_FILENAME) - dest.write_text(json.dumps(data, indent=2)) # writes codeindex.json + dest.write_text(json.dumps(data, indent=2)) # writes blastradius.json ``` -`INDEX_FILENAME = "codeindex.json"` (index.py top). +`INDEX_FILENAME = "blastradius.json"` (index.py top). --- @@ -148,7 +148,7 @@ Result keyed by node ID: ## 5. JSON Output -### 5.1 `codeindex.json` — written by `index.py:25` +### 5.1 `blastradius.json` — written by `index.py:25` ```json { @@ -186,7 +186,7 @@ Result keyed by node ID: ```json { - "meta": {"generated": "2026-06-07", "repo": "codeindex/", "total_symbols": 156}, + "meta": {"generated": "2026-06-07", "repo": "blastradius/", "total_symbols": 156}, "symbols": { "MyClass": [{"file": "src/main.py", "line": 42, "kind": "class", "exported": true, "methods": ["run"]}] }, @@ -201,7 +201,7 @@ Result keyed by node ID: | Function | Location | Purpose | |---|---|---| | `write_standalone()` | `symbols.py:77–85` | Writes `symbolindex.json` | -| `write_inline()` | `symbols.py:88–114` | Merges symbol data into `codeindex.json` nodes | +| `write_inline()` | `symbols.py:88–114` | Merges symbol data into `blastradius.json` nodes | | `write_claude_md()` | `symbols.py:146–171` | Upserts a symbol section into `CLAUDE.md` | --- @@ -261,7 +261,7 @@ Protocol: JSON-RPC 2.0 over stdio. Entry: `serve()` at line 331. | `build_symbol_index` | `_call_build_symbol_index` | `symbols.build_symbol_index()` | **Key helpers**: -- `_resolve_index()` (line 127) — loads `codeindex.json`; auto-discovers by walking up from cwd +- `_resolve_index()` (line 127) — loads `blastradius.json`; auto-discovers by walking up from cwd - `_resolve_file_id()` (line 138) — fuzzy-matches a path to a node ID by suffix - `_handle()` (line 284) — routes JSON-RPC method → handler @@ -274,7 +274,7 @@ HTTP server using stdlib `http.server`. Routes: | Route | Handler | Response | |---|---|---| | `/`, `/index.html` | `do_GET` (line 53) | Serves `viz/explorer.html` | -| `/graph` | `do_GET` (line 60) | Serves `codeindex.json` as JSON | +| `/graph` | `do_GET` (line 60) | Serves `blastradius.json` as JSON | | `/refresh` | `do_GET` (line 65) | Calls `_run_analysis()` → `index.build()` | Watch mode (`viz_server.py:73–109`): watchdog observer + 1 s debounce timer triggers `_run_analysis()` on file changes. @@ -344,7 +344,7 @@ cli.py main() ├─ enrich_nodes() ← mutate nodes with blast fields ├─ enrich_links() ← add imports/imported_by to nodes │ ← SEAM A: upsert to SQLite here - └─ write codeindex.json + └─ write blastradius.json cli.py / mcp_server.py (query commands) └─ index.load(path) ← SEAM B: replace with DB read diff --git a/docs/codeindex-temporal-knowledge-graph.md b/docs/blastradius-temporal-knowledge-graph.md similarity index 78% rename from docs/codeindex-temporal-knowledge-graph.md rename to docs/blastradius-temporal-knowledge-graph.md index 368604f..796cd25 100644 --- a/docs/codeindex-temporal-knowledge-graph.md +++ b/docs/blastradius-temporal-knowledge-graph.md @@ -1,10 +1,10 @@ -# codeindex → Temporal Code Knowledge Graph +# blastradius → Temporal Code Knowledge Graph | | | |---|---| | **Doc ID** | CKG-DESIGN-001 | | **Status** | Draft — ready for implementation | -| **Target repo** | `scheidydude/codeindex` | +| **Target repo** | `scheidydude/blastradius` | | **Audience** | Claude Code (implementing agent) + maintainer | | **License constraint** | Apache 2.0 (preserve existing headers) | @@ -15,7 +15,7 @@ ## 1. Problem statement -`codeindex` today is a **stateless, point-in-time, exact-match** dependency and symbol analyzer. It parses a repo, computes a dependency graph with blast-radius scores plus a symbol map, and writes `codeindex.json` / `symbolindex.json`. That design is excellent for a one-shot snapshot but blocks three capabilities needed to serve as a durable knowledge graph for AI agents: +`blastradius` today is a **stateless, point-in-time, exact-match** dependency and symbol analyzer. It parses a repo, computes a dependency graph with blast-radius scores plus a symbol map, and writes `blastradius.json` / `symbolindex.json`. That design is excellent for a one-shot snapshot but blocks three capabilities needed to serve as a durable knowledge graph for AI agents: 1. **Stateless.** Every run recomputes the entire index from scratch. There is no persistent store, no incremental update, and no cheap repeated querying. This does not scale to an always-on agent asking many questions, or to large repos. 2. **Atemporal.** The graph only ever represents *now*. It cannot answer how structure evolved — when a dependency was introduced, what the blast radius of a file was at a past release, or which files churn most — which is core to real impact analysis and code archaeology. @@ -23,7 +23,7 @@ ## 2. Goal -Evolve `codeindex` into a **self-hosted, local-first temporal code knowledge graph with hybrid retrieval** — conceptually "Graphiti applied to code instead of conversations" — while preserving everything that makes the current tool good: deterministic AST extraction, near-zero-friction install, and the existing CLI / JSON / MCP / viz surfaces. +Evolve `blastradius` into a **self-hosted, local-first temporal code knowledge graph with hybrid retrieval** — conceptually "Graphiti applied to code instead of conversations" — while preserving everything that makes the current tool good: deterministic AST extraction, near-zero-friction install, and the existing CLI / JSON / MCP / viz surfaces. The end state adds three properties to the existing graph: **persistence + incrementality**, **time**, and **meaning (semantic retrieval)**. @@ -31,10 +31,10 @@ The end state adds three properties to the existing graph: **persistence + incre These are out of scope. Do not implement them, and do not refactor toward them. -- **Not conversational / agent memory.** This project does not store user preferences, chat history, or "who the user is." That is a separate concern that belongs in a downstream memory layer. `codeindex` is a *code-context provider*, not a personal-memory store. Keep the two truth models separate (deterministic code facts vs. probabilistic conversational facts). +- **Not conversational / agent memory.** This project does not store user preferences, chat history, or "who the user is." That is a separate concern that belongs in a downstream memory layer. `blastradius` is a *code-context provider*, not a personal-memory store. Keep the two truth models separate (deterministic code facts vs. probabilistic conversational facts). - **Not LLM-based extraction.** Do not replace deterministic AST/regex extraction with an LLM. The deterministic model is a reliability advantage and must remain the source of graph structure. LLMs/embeddings are used *only* for the semantic retrieval layer, never to infer edges or symbols. - **Not a server-based graph database.** No Neo4j, FalkorDB, or any external graph service. The store stays embedded. -- **No breaking changes to the public contract.** The `codeindex.json` / `symbolindex.json` schemas and existing CLI commands must keep working unchanged. +- **No breaking changes to the public contract.** The `blastradius.json` / `symbolindex.json` schemas and existing CLI commands must keep working unchanged. - **No cloud dependency.** Embeddings must be obtainable from a local/self-hosted endpoint. Nothing leaves the machine by default. ## 4. Architecture overview @@ -69,10 +69,10 @@ The migration is deliberately layered so each layer is shippable on its own: ### 4.1 Package layout & extraction boundary -This work ships as a **feature release on the existing `codeindex` repo**, *not* a fork and *not* (yet) a separate project. But it is laid out so the heavy layer can be extracted into its own package later with a clean lift, if it grows an independent identity. To keep that door open, the codebase is partitioned into a **lean core** and **optional layers**, and the dependency direction is strictly one-way. +This work ships as a **feature release on the existing `blastradius` repo**, *not* a fork and *not* (yet) a separate project. But it is laid out so the heavy layer can be extracted into its own package later with a clean lift, if it grows an independent identity. To keep that door open, the codebase is partitioned into a **lean core** and **optional layers**, and the dependency direction is strictly one-way. ``` -codeindex/ +blastradius/ core/ # deterministic parsers, blast scoring — the lean primitive store/ # SQLite store + incremental indexing (core dependency-free) temporal/ # commit stamping + git-history ingestion (core dependency-free) @@ -83,19 +83,19 @@ codeindex/ **Hard partitioning rules:** - `core/`, `store/`, and `temporal/` **must not import** from `graph/` or `semantic/`. The dependency arrow points only *up*, from the heavy layers down into the core — never the reverse. This is what makes a future extraction a move, not a rewrite. -- `graph/` and `semantic/` are gated behind optional extras (`codeindex[graph]`, `codeindex[semantic]`). The default `pip install codeindex` installs only the lean core + store + temporal and pulls in **no** new runtime dependencies. -- The heavy layers consume the core through its public store/graph API only — never by reaching into core internals — so that when `graph/`+`semantic/` are lifted into a standalone package, the only change is declaring `codeindex` as a dependency. +- `graph/` and `semantic/` are gated behind optional extras (`blastradius[graph]`, `blastradius[semantic]`). The default `pip install blastradius` installs only the lean core + store + temporal and pulls in **no** new runtime dependencies. +- The heavy layers consume the core through its public store/graph API only — never by reaching into core internals — so that when `graph/`+`semantic/` are lifted into a standalone package, the only change is declaring `blastradius` as a dependency. ## 5. Data model -The canonical store becomes a single SQLite database (default: `/.codeindex/index.db`). `codeindex.json` / `symbolindex.json` become **exports** (a view rendered from the DB), preserving the current public schema exactly. +The canonical store becomes a single SQLite database (default: `/.blastradius/index.db`). `blastradius.json` / `symbolindex.json` become **exports** (a view rendered from the DB), preserving the current public schema exactly. ### 5.1 Temporal model Bi-temporal, kept simple: - **Commit time** — where a fact lives in git history. Every node/edge/symbol carries `first_seen_commit` and `last_seen_commit` (nullable; `NULL` last-seen = still present at HEAD). -- **Index time** — when `codeindex` observed the fact (`first_seen_at`, `last_seen_at`, ISO-8601). +- **Index time** — when `blastradius` observed the fact (`first_seen_at`, `last_seen_at`, ISO-8601). Facts are **never hard-deleted**. When a file/edge/symbol disappears, set its `last_seen_commit` and `last_seen_at` and flag it inactive. This is what enables "as-of" queries and churn analysis. @@ -190,8 +190,8 @@ Bump `schema_version` and ship a forward migration whenever this changes. ## 6. Component design -### 6.1 Storage layer (`codeindex/store/`) -A thin module wrapping the SQLite connection: schema creation, versioned migrations, upsert/close helpers for files/edges/symbols, and JSON export that reproduces the current `codeindex.json` / `symbolindex.json` byte-for-byte (golden-tested). The store is the new source of truth; everything else reads/writes through it. +### 6.1 Storage layer (`blastradius/store/`) +A thin module wrapping the SQLite connection: schema creation, versioned migrations, upsert/close helpers for files/edges/symbols, and JSON export that reproduces the current `blastradius.json` / `symbolindex.json` byte-for-byte (golden-tested). The store is the new source of truth; everything else reads/writes through it. ### 6.2 Incremental indexer Replaces full recompute. Algorithm: @@ -206,7 +206,7 @@ Replaces full recompute. Algorithm: 6. Refresh FTS rows for changed symbols. (Embeddings handled in Phase 3.) 7. Update `index_meta.last_indexed_commit` and export JSON. -### 6.3 Temporal ingestion (`codeindex history`) +### 6.3 Temporal ingestion (`blastradius history`) Backfills the temporal graph from git history **without checkouts**, to keep it safe and fast: - Walk `git log` oldest→newest within bounds (`--since`, `--max-commits`). @@ -218,8 +218,8 @@ This is the most performance-sensitive component — see Risks. Default to **bou ### 6.4 Semantic layer (Phase 3) - **What gets embedded:** per symbol, the concatenation of `name + signature + doc` (skip empties). -- **Embedding provider interface** (`codeindex/semantic/`): a small abstraction with one shipped implementation — an **OpenAI-compatible `/v1/embeddings` HTTP client** built on stdlib `urllib` (no new dependency for the client itself). Endpoint URL, model name, and dimensions come from config/env. This targets a self-hosted local inference server out of the box. -- **Vector store:** `sqlite-vec` `vec0` virtual table. This is the single new optional dependency, gated behind the `codeindex[semantic]` extra. If the extension can't load, semantic features degrade gracefully (log a clear message, fall back to FTS + exact) — they never hard-fail the tool. +- **Embedding provider interface** (`blastradius/semantic/`): a small abstraction with one shipped implementation — an **OpenAI-compatible `/v1/embeddings` HTTP client** built on stdlib `urllib` (no new dependency for the client itself). Endpoint URL, model name, and dimensions come from config/env. This targets a self-hosted local inference server out of the box. +- **Vector store:** `sqlite-vec` `vec0` virtual table. This is the single new optional dependency, gated behind the `blastradius[semantic]` extra. If the extension can't load, semantic features degrade gracefully (log a clear message, fall back to FTS + exact) — they never hard-fail the tool. - Embeddings are (re)generated only for new/changed symbols during indexing, batched. ### 6.5 Hybrid query engine @@ -237,12 +237,12 @@ Combine the ranked lists with **Reciprocal Rank Fusion** (`score = Σ 1/(60 + ra ### 7.1 CLI (additions; existing commands unchanged) | Command | Purpose | |---|---| -| `codeindex analyze` | Existing — now incremental, writes to SQLite, still exports `codeindex.json` | -| `codeindex history [--since REF] [--max-commits N]` | Backfill the temporal graph from git history | -| `codeindex search "" [--k N] [--as-of REF] [--json]` | Hybrid semantic + keyword + graph search | -| `codeindex impact FILE [--as-of REF]` | Existing — gains optional point-in-time blast radius | -| `codeindex db status` | Show schema version, last indexed commit, counts, embedding config | -| `codeindex db migrate` | Apply pending schema migrations | +| `blastradius analyze` | Existing — now incremental, writes to SQLite, still exports `blastradius.json` | +| `blastradius history [--since REF] [--max-commits N]` | Backfill the temporal graph from git history | +| `blastradius search "" [--k N] [--as-of REF] [--json]` | Hybrid semantic + keyword + graph search | +| `blastradius impact FILE [--as-of REF]` | Existing — gains optional point-in-time blast radius | +| `blastradius db status` | Show schema version, last indexed commit, counts, embedding config | +| `blastradius db migrate` | Apply pending schema migrations | ### 7.2 MCP tools (additions; existing four unchanged) | Tool | Description | @@ -253,29 +253,29 @@ Combine the ranked lists with **Reciprocal Rank Fusion** (`score = Σ 1/(60 + ra | `changed_since` | `ref` → files/edges/symbols added or removed since a ref | ### 7.3 Configuration -Read from `[tool.codeindex]` in `pyproject.toml` and/or `.codeindex.toml`, env vars override. Keys: `db_path`, `embedding_endpoint`, `embedding_model`, `embedding_dims`, `history_max_commits`. All have safe defaults; semantic config is optional. +Read from `[tool.blastradius]` in `pyproject.toml` and/or `.blastradius.toml`, env vars override. Keys: `db_path`, `embedding_endpoint`, `embedding_model`, `embedding_dims`, `history_max_commits`. All have safe defaults; semantic config is optional. ## 8. Implementation phases > Each phase ends with: all existing tests green, new tests added, acceptance checks passing, a commit. Keep the core dependency-free; every new dependency is an optional extra. ### Phase 0 — Orient (no behavior change) -- Read the existing package layout under `codeindex/` and `viz/`. Produce `docs/CKG-INTERNALS.md`: current module map, where parsing happens, where JSON is written, how the MCP server and CLI dispatch are wired. +- Read the existing package layout under `blastradius/` and `viz/`. Produce `docs/CKG-INTERNALS.md`: current module map, where parsing happens, where JSON is written, how the MCP server and CLI dispatch are wired. - Identify the integration seams for the new store without changing behavior. - **Acceptance:** internals doc committed; no source changes; existing tests still pass. ### Phase 1 — SQLite store + incremental indexing (no new deps) -- Implement `codeindex/store/` (schema, migrations, upsert/close, JSON export). -- Wire `analyze` to populate the DB and export `codeindex.json` / `symbolindex.json` from it. +- Implement `blastradius/store/` (schema, migrations, upsert/close, JSON export). +- Wire `analyze` to populate the DB and export `blastradius.json` / `symbolindex.json` from it. - Implement incremental change detection (git diff + content-hash fallback) and affected-subgraph blast recompute. - Populate `symbols_fts`. - **Acceptance:** - Exported JSON is byte-identical to pre-change output on a fixture repo (golden test). - Re-running `analyze` after editing one file re-parses only that file's change set (assert via instrumentation/log). - - `codeindex db status` reports correct counts. + - `blastradius db status` reports correct counts. ### Phase 2 — Temporal layer (no new deps) -- Implement `codeindex history` via `git ls-tree` + `git cat-file --batch` (no checkouts), bounded by `--since` / `--max-commits`. +- Implement `blastradius history` via `git ls-tree` + `git cat-file --batch` (no checkouts), bounded by `--since` / `--max-commits`. - Maintain `first_seen_commit` / `last_seen_commit` on nodes/edges/symbols; populate `commits`. - Add `--as-of` to `impact`; implement `changed_since`. - **Acceptance:** @@ -286,7 +286,7 @@ Read from `[tool.codeindex]` in `pyproject.toml` and/or `.codeindex.toml`, env v ### Phase 3 — Semantic layer (optional dep: `sqlite-vec`) - Implement the embedding-provider interface + stdlib OpenAI-compatible client. - Add `vec_symbols`; embed `name+signature+doc` for new/changed symbols, batched. -- Implement the hybrid query engine (semantic + FTS + graph, RRF fusion, optional temporal filter) behind `codeindex search`. +- Implement the hybrid query engine (semantic + FTS + graph, RRF fusion, optional temporal filter) behind `blastradius search`. - Graceful degradation when the extension or endpoint is unavailable. - **Acceptance:** - With a local endpoint configured, `search "validate auth token"` surfaces the auth-validation symbol without its name in the query. @@ -300,7 +300,7 @@ Read from `[tool.codeindex]` in `pyproject.toml` and/or `.codeindex.toml`, env v ## 9. Constraints for the implementing agent (hard rules) -1. **Preserve the zero-dependency core.** Phases 0–2 add **no** runtime dependencies. `sqlite-vec` (Phase 3) is the only new dependency and must be an optional extra (`codeindex[semantic]`); the tool must run fully without it. +1. **Preserve the zero-dependency core.** Phases 0–2 add **no** runtime dependencies. `sqlite-vec` (Phase 3) is the only new dependency and must be an optional extra (`blastradius[semantic]`); the tool must run fully without it. 2. **Respect the partitioning and dependency direction (§4.1).** `core/`, `store/`, and `temporal/` must never import from `graph/` or `semantic/`. The heavy layers depend on the core, never the reverse, and consume it only through its public store/graph API. This keeps a future extraction into a standalone package a clean lift. Any change that creates a core→heavy import is a hard failure. 3. **Do not change the public JSON schema or existing CLI commands.** JSON output stays byte-compatible (golden-tested). 4. **Deterministic extraction is sacred.** No LLM or heuristic inference of edges/symbols. Embeddings serve retrieval only. @@ -325,7 +325,7 @@ Read from `[tool.codeindex]` in `pyproject.toml` and/or `.codeindex.toml`, env v | `sqlite-vec` extension load fails on a platform | Feature-detect at startup; fall back; document install per OS | | Schema evolution breaks existing DBs | Versioned migrations + `schema_version` in `index_meta`; `db migrate` command | | Incremental diff misses a change | Content-hash fallback validates against git diff; provide `analyze --full` escape hatch to force a rebuild | -| Scope creep into conversational memory | Section 3 forbids it; `codeindex` stays a code-context provider only | +| Scope creep into conversational memory | Section 3 forbids it; `blastradius` stays a code-context provider only | ## 12. Definition of done The project is complete when: `analyze` is incremental and SQLite-backed with byte-identical JSON export; `history` builds a queryable temporal graph; `impact --as-of` and `changed_since` work; `search` performs hybrid retrieval with graceful degradation; all four new MCP tools are registered; the README documents everything; and the full test suite (golden + temporal + retrieval + degradation) passes with the core remaining dependency-free. diff --git a/docs/evaluation-prompt.md b/docs/evaluation-prompt.md index 66af280..582549f 100644 --- a/docs/evaluation-prompt.md +++ b/docs/evaluation-prompt.md @@ -1,22 +1,22 @@ -# codeindex Evaluation Prompt +# blastradius Evaluation Prompt Copy and paste the following prompt into Claude Code from inside the repo you want to evaluate. -Requires codeindex v0.3.6+ installed and `codeindex analyze` already run. +Requires blastradius v0.3.6+ installed and `blastradius analyze` already run. --- ``` -You are evaluating codeindex against this repo. Your job is to run 5 realistic tasks two ways each — once with standard shell tools (grep, git, find, cat) and once with codeindex — then produce a structured comparison report. Make no changes to this repo or the codeindex repo. +You are evaluating blastradius against this repo. Your job is to run 5 realistic tasks two ways each — once with standard shell tools (grep, git, find, cat) and once with blastradius — then produce a structured comparison report. Make no changes to this repo or the blastradius repo. ## Setup check -First, verify codeindex is available and the DB exists: +First, verify blastradius is available and the DB exists: ```bash -codeindex db status +blastradius db status ``` -If the DB is missing, run `codeindex analyze .` first, then continue. +If the DB is missing, run `blastradius analyze .` first, then continue. ## The 5 tasks @@ -28,16 +28,16 @@ Run each task both ways. Time both approaches (use `time`). Record what you actu Pick the most important user-facing concept in this codebase (auth, payment, scheduling, API handler, etc. — infer it from the file structure). Answer: "Where does this process begin? What function is the entry point?" -**Without codeindex:** +**Without blastradius:** ```bash grep -r "" --include="*.py" --include="*.ts" --include="*.go" -l | grep -v test | grep -v __pycache__ | head -20 # then open the most likely file and read it ``` -**With codeindex:** +**With blastradius:** ```bash -codeindex search "" -codeindex lookup +blastradius search "" +blastradius lookup ``` Note: `lookup` prints the definition line plus 4 lines of source context. If a symbol isn't found, it's likely a third-party import (only repo-defined symbols are indexed). @@ -48,15 +48,15 @@ Note: `lookup` prints the definition line plus 4 lines of source context. If a s Pick the file that looks most central (lots of imports, core module name, etc.). Answer: "How many files would be affected if this changed? Is it safe to touch?" -**Without codeindex:** +**Without blastradius:** ```bash grep -r "from \|import " --include="*.py" --include="*.ts" --include="*.go" -l | grep -v test | grep -v __pycache__ # count the results and note: this is only direct importers ``` -**With codeindex:** +**With blastradius:** ```bash -codeindex impact +blastradius impact ``` --- @@ -65,15 +65,15 @@ codeindex impact Pick a mid-level module (not the God object, not a leaf utility). Answer: "What does this depend on, and what depends on it?" -**Without codeindex:** +**Without blastradius:** ```bash grep -n "^import\|^from" | head -20 # what it imports grep -r "from.*\|import.*" --include="*.py" -l | grep -v test # who imports it ``` -**With codeindex:** +**With blastradius:** ```bash -codeindex dependencies +blastradius dependencies ``` --- @@ -82,12 +82,12 @@ codeindex dependencies Answer: "If I had 30 minutes to read code before a major refactor, which files must I understand first?" -**Without codeindex:** +**Without blastradius:** No direct equivalent. Describe what you would do manually (read entry points, follow imports, build a mental model). -**With codeindex:** +**With blastradius:** ```bash -codeindex high-blast --threshold +blastradius high-blast --threshold ``` --- @@ -97,19 +97,19 @@ codeindex high-blast --threshold Pick a commit from 1–3 weeks ago (or a release tag if one exists). Answer: "What new dependencies were introduced? What was removed?" -**Without codeindex:** +**Without blastradius:** ```bash git log --oneline -10 # pick a ref git diff --name-only ..HEAD ``` -**With codeindex:** +**With blastradius:** ```bash git log --oneline -10 # same ref -codeindex changed-since +blastradius changed-since ``` -Note: if you see "Warning: Git history has not been backfilled", run `codeindex history .` first, then repeat the command. +Note: if you see "Warning: Git history has not been backfilled", run `blastradius history .` first, then repeat the command. --- @@ -117,16 +117,16 @@ Note: if you see "Warning: Git history has not been backfilled", run `codeindex Pick a high-blast file that exports multiple symbols (a schema, a utility module, a shared config). Answer: "Which specific exports are actually used, and by which files? Is it safe to change just one of them?" -**Without codeindex:** +**Without blastradius:** ```bash # For each exported name, grep importers separately: grep -r "ExportedName" --include="*.ts" --include="*.py" -l # repeat for each export — tedious for files with 5+ exports ``` -**With codeindex:** +**With blastradius:** ```bash -codeindex symbol-blast +blastradius symbol-blast ``` This lists every exported symbol with a count and the exact importer files that reference it by name — so you can see that changing `userSchema` affects 8 routes while `legacySchema` affects only 1. @@ -147,9 +147,9 @@ After running all 6 tasks, fill in this table: | 6. Per-export blast | | | | | | Then answer: -- Which codeindex result surprised you most? (Something you wouldn't have found with grep alone?) -- Did any codeindex command return wrong or misleading results? -- What query or task did you try that codeindex couldn't answer? +- Which blastradius result surprised you most? (Something you wouldn't have found with grep alone?) +- Did any blastradius command return wrong or misleading results? +- What query or task did you try that blastradius couldn't answer? ## Report format @@ -164,5 +164,5 @@ Write the final report as: **Rough edges found:** -**Verdict:** one sentence — would you add codeindex to your workflow for this repo? +**Verdict:** one sentence — would you add blastradius to your workflow for this repo? ``` diff --git a/pyproject.toml b/pyproject.toml index 8b219c1..d995078 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ requires = ["setuptools>=68"] build-backend = "setuptools.build_meta" [project] -name = "codeindex" +name = "blastradius" version = "0.3.6" description = "Repo dependency analyzer with blast-radius impact scoring for AI-assisted development" readme = "README.md" @@ -11,7 +11,7 @@ license = { text = "Apache-2.0" } requires-python = ">=3.9" [project.scripts] -codeindex = "codeindex.cli:main" +blastradius = "blastradius.cli:main" [project.optional-dependencies] watch = ["watchdog"] @@ -25,7 +25,7 @@ testpaths = ["tests"] [tool.setuptools.packages.find] where = ["."] -include = ["codeindex*"] +include = ["blastradius*"] [tool.setuptools.package-data] -"codeindex" = ["py.typed"] +"blastradius" = ["py.typed"] diff --git a/tests/test_phase1.py b/tests/test_phase1.py index d51325d..4f88bfb 100644 --- a/tests/test_phase1.py +++ b/tests/test_phase1.py @@ -7,7 +7,7 @@ repo (golden test). 2. Re-running analyze after editing one file logs only that file's change set (incremental detection test). - 3. `codeindex db status` reports correct counts. + 3. `blastradius db status` reports correct counts. """ from __future__ import annotations @@ -41,10 +41,10 @@ def _init_git(repo: Path) -> str: def _run_analyze(repo: Path) -> dict: - """Run codeindex.index.build() and return the parsed JSON output.""" + """Run blastradius.index.build() and return the parsed JSON output.""" # Import here so we get the Phase-1 version, not a cached import import importlib - import codeindex.index as idx_mod + import blastradius.index as idx_mod importlib.reload(idx_mod) data = idx_mod.build(str(repo)) @@ -87,8 +87,8 @@ def test_golden_idempotent(tmp_path: Path) -> None: def test_db_populated(tmp_path: Path) -> None: """After analyze(), the SQLite store contains the expected file rows.""" - from codeindex.store import Store - from codeindex.index import db_path_for + from blastradius.store import Store + from blastradius.index import db_path_for repo = tmp_path / "repo" shutil.copytree(FIXTURE_SRC, repo) @@ -97,7 +97,7 @@ def test_db_populated(tmp_path: Path) -> None: data = _run_analyze(repo) db_path = db_path_for(repo) - assert db_path.exists(), ".codeindex/index.db not created" + assert db_path.exists(), ".blastradius/index.db not created" store = Store(db_path) status = store.status() @@ -147,8 +147,8 @@ def test_incremental_detection(tmp_path: Path, capsys: pytest.CaptureFixture) -> def test_db_status_counts(tmp_path: Path) -> None: """store.status() counts match the number of nodes analyze() produced.""" - from codeindex.store import Store - from codeindex.index import db_path_for + from blastradius.store import Store + from blastradius.index import db_path_for repo = tmp_path / "repo" shutil.copytree(FIXTURE_SRC, repo) @@ -172,8 +172,8 @@ def test_db_status_counts(tmp_path: Path) -> None: def test_soft_delete_on_removal(tmp_path: Path) -> None: """Removing a file marks its DB row inactive, not deleted.""" - from codeindex.store import Store - from codeindex.index import db_path_for + from blastradius.store import Store + from blastradius.index import db_path_for repo = tmp_path / "repo" shutil.copytree(FIXTURE_SRC, repo) diff --git a/tests/test_phase2.py b/tests/test_phase2.py index 212cb51..e6157ba 100644 --- a/tests/test_phase2.py +++ b/tests/test_phase2.py @@ -46,7 +46,7 @@ def _commit_all(repo: Path, message: str) -> str: def _run_analyze(repo: Path) -> None: import importlib - import codeindex.index as idx_mod + import blastradius.index as idx_mod importlib.reload(idx_mod) idx_mod.build(str(repo)) @@ -86,8 +86,8 @@ def _make_temporal_repo(tmp_path: Path) -> tuple[Path, str, str, str]: def test_as_of_impact_differs_from_head(tmp_path: Path) -> None: """impact B --as-of C2 shows A as dependent; impact B at HEAD does not.""" - from codeindex.store import Store - from codeindex.index import db_path_for, git_reachable, git_resolve + from blastradius.store import Store + from blastradius.index import db_path_for, git_reachable, git_resolve repo, c1, c2, c3 = _make_temporal_repo(tmp_path) db_path = db_path_for(repo) @@ -119,8 +119,8 @@ def test_as_of_impact_differs_from_head(tmp_path: Path) -> None: def test_changed_since_edges(tmp_path: Path) -> None: """changed_since(reachable_C1) shows added edge at C2 and its removal.""" - from codeindex.store import Store - from codeindex.index import db_path_for, git_reachable + from blastradius.store import Store + from blastradius.index import db_path_for, git_reachable repo, c1, c2, c3 = _make_temporal_repo(tmp_path) db_path = db_path_for(repo) @@ -141,10 +141,10 @@ def test_changed_since_edges(tmp_path: Path) -> None: # ── Test 3: history backfill populates commits table ───────────────────────── def test_history_backfill_commits(tmp_path: Path) -> None: - """codeindex history populates the commits table.""" - from codeindex.store import Store - from codeindex.index import db_path_for - from codeindex.temporal import backfill + """blastradius history populates the commits table.""" + from blastradius.store import Store + from blastradius.index import db_path_for + from blastradius.temporal import backfill repo = tmp_path / "hist_repo" shutil.copytree(FIXTURE_SRC, repo) @@ -175,9 +175,9 @@ def test_history_backfill_commits(tmp_path: Path) -> None: def test_history_backfill_first_seen(tmp_path: Path) -> None: """After backfill, files have first_seen_commit set.""" - from codeindex.store import Store - from codeindex.index import db_path_for - from codeindex.temporal import backfill + from blastradius.store import Store + from blastradius.index import db_path_for + from blastradius.temporal import backfill repo = tmp_path / "seen_repo" shutil.copytree(FIXTURE_SRC, repo) @@ -206,9 +206,9 @@ def test_history_backfill_first_seen(tmp_path: Path) -> None: def test_history_no_working_tree_change(tmp_path: Path) -> None: """git status is clean before and after backfill (no checkout side-effects).""" - from codeindex.store import Store - from codeindex.index import db_path_for - from codeindex.temporal import backfill + from blastradius.store import Store + from blastradius.index import db_path_for + from blastradius.temporal import backfill repo = tmp_path / "clean_repo" shutil.copytree(FIXTURE_SRC, repo) @@ -231,7 +231,7 @@ def test_history_no_working_tree_change(tmp_path: Path) -> None: f"Backfill modified working-tree file: {f}" ) - # Git status should show clean (only .codeindex/ and generated files differ) + # Git status should show clean (only .blastradius/ and generated files differ) status = subprocess.run( ["git", "status", "--porcelain", "--", "*.py"], cwd=repo, capture_output=True, text=True, @@ -243,8 +243,8 @@ def test_history_no_working_tree_change(tmp_path: Path) -> None: def test_changed_since_added_file(tmp_path: Path) -> None: """changed_since(C1) shows a file added at C2.""" - from codeindex.store import Store - from codeindex.index import db_path_for, git_reachable + from blastradius.store import Store + from blastradius.index import db_path_for, git_reachable repo = tmp_path / "addfile_repo" shutil.copytree(FIXTURE_SRC, repo) diff --git a/tests/test_phase3.py b/tests/test_phase3.py index 72eced7..c55f4f3 100644 --- a/tests/test_phase3.py +++ b/tests/test_phase3.py @@ -65,7 +65,7 @@ def _commit_all(repo: Path, message: str) -> str: def _run_analyze(repo: Path) -> None: - import codeindex.index as idx_mod + import blastradius.index as idx_mod importlib.reload(idx_mod) idx_mod.build(str(repo)) @@ -92,8 +92,8 @@ def _make_repo_with_symbols(tmp_path: Path) -> Path: def test_fts_search_returns_results(tmp_path: Path) -> None: """fts_search finds symbols by name keyword without any embedding.""" - from codeindex.index import db_path_for - from codeindex.store import Store + from blastradius.index import db_path_for + from blastradius.store import Store repo = _make_repo_with_symbols(tmp_path) store = Store(db_path_for(repo)) @@ -123,9 +123,9 @@ def test_fts_search_returns_results(tmp_path: Path) -> None: def test_hybrid_search_stub_provider(tmp_path: Path) -> None: """hybrid_search returns results using stub embeddings + FTS, no live endpoint.""" - from codeindex.index import db_path_for - from codeindex.store import Store - from codeindex.semantic.search import hybrid_search + from blastradius.index import db_path_for + from blastradius.store import Store + from blastradius.semantic.search import hybrid_search repo = _make_repo_with_symbols(tmp_path) store = Store(db_path_for(repo)) @@ -169,9 +169,9 @@ def test_hybrid_search_stub_provider(tmp_path: Path) -> None: def test_search_degrades_without_sqlite_vec(tmp_path: Path, capsys) -> None: """hybrid_search falls back to FTS+graph and emits notice when vec unavailable.""" - from codeindex.index import db_path_for - from codeindex.store import Store - from codeindex.semantic.search import hybrid_search + from blastradius.index import db_path_for + from blastradius.store import Store + from blastradius.semantic.search import hybrid_search repo = _make_repo_with_symbols(tmp_path) store = Store(db_path_for(repo)) @@ -200,10 +200,10 @@ def test_search_degrades_without_sqlite_vec(tmp_path: Path, capsys) -> None: def test_search_degrades_endpoint_unreachable(tmp_path: Path) -> None: """hybrid_search falls back to FTS+graph when embedding endpoint errors.""" - from codeindex.index import db_path_for - from codeindex.store import Store - from codeindex.semantic.search import hybrid_search - from codeindex.semantic.provider import OpenAIEmbeddingProvider + from blastradius.index import db_path_for + from blastradius.store import Store + from blastradius.semantic.search import hybrid_search + from blastradius.semantic.provider import OpenAIEmbeddingProvider repo = _make_repo_with_symbols(tmp_path) store = Store(db_path_for(repo)) @@ -233,8 +233,8 @@ def test_search_degrades_endpoint_unreachable(tmp_path: Path) -> None: def test_graph_expand(tmp_path: Path) -> None: """graph_expand returns symbols from files that import or are imported by given symbols.""" - from codeindex.index import db_path_for - from codeindex.store import Store + from blastradius.index import db_path_for + from blastradius.store import Store repo = _make_repo_with_symbols(tmp_path) store = Store(db_path_for(repo)) @@ -260,8 +260,8 @@ def test_graph_expand(tmp_path: Path) -> None: def test_get_symbol_metadata(tmp_path: Path) -> None: """get_symbol returns name, file, kind, and other expected fields.""" - from codeindex.index import db_path_for - from codeindex.store import Store + from blastradius.index import db_path_for + from blastradius.store import Store repo = _make_repo_with_symbols(tmp_path) store = Store(db_path_for(repo)) @@ -285,9 +285,9 @@ def test_get_symbol_metadata(tmp_path: Path) -> None: def test_schema_version_is_current(tmp_path: Path) -> None: """Opening a fresh store sets schema_version to the current version.""" - from codeindex.store import Store, SCHEMA_VERSION + from blastradius.store import Store, SCHEMA_VERSION - db_path = tmp_path / ".codeindex" / "index.db" + db_path = tmp_path / ".blastradius" / "index.db" store = Store(db_path) version = store.get_meta("schema_version") store.close() diff --git a/uv.lock b/uv.lock index a845016..100f434 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 1 +revision = 3 requires-python = ">=3.9" resolution-markers = [ "python_full_version >= '3.10'", @@ -7,8 +7,8 @@ resolution-markers = [ ] [[package]] -name = "codeindex" -version = "0.3.5" +name = "blastradius" +version = "0.3.6" source = { editable = "." } [package.optional-dependencies] @@ -43,9 +43,9 @@ provides-extras = ["watch", "yaml", "toml", "dev", "semantic"] name = "colorama" version = "0.4.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] [[package]] @@ -53,11 +53,11 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371 } +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740 }, + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, ] [[package]] @@ -67,9 +67,9 @@ source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version < '3.10'", ] -sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793 } +sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050 }, + { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, ] [[package]] @@ -79,36 +79,36 @@ source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.10'", ] -sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503 } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484 }, + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, ] [[package]] name = "packaging" version = "26.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134 } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195 }, + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, ] [[package]] name = "pluggy" version = "1.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412 } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538 }, + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, ] [[package]] name = "pygments" version = "2.20.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991 } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151 }, + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, ] [[package]] @@ -119,17 +119,17 @@ resolution-markers = [ "python_full_version < '3.10'", ] dependencies = [ - { name = "colorama", marker = "python_full_version < '3.10' and sys_platform == 'win32'" }, - { name = "exceptiongroup", marker = "python_full_version < '3.10'" }, - { name = "iniconfig", version = "2.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "packaging", marker = "python_full_version < '3.10'" }, - { name = "pluggy", marker = "python_full_version < '3.10'" }, - { name = "pygments", marker = "python_full_version < '3.10'" }, - { name = "tomli", marker = "python_full_version < '3.10'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup" }, + { name = "iniconfig", version = "2.1.0", source = { registry = "https://pypi.org/simple" } }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, + { name = "tomli" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618 } +sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750 }, + { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, ] [[package]] @@ -140,90 +140,90 @@ resolution-markers = [ "python_full_version >= '3.10'", ] dependencies = [ - { name = "colorama", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" }, - { name = "exceptiongroup", marker = "python_full_version == '3.10.*'" }, - { name = "iniconfig", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "packaging", marker = "python_full_version >= '3.10'" }, - { name = "pluggy", marker = "python_full_version >= '3.10'" }, - { name = "pygments", marker = "python_full_version >= '3.10'" }, - { name = "tomli", marker = "python_full_version == '3.10.*'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "iniconfig", version = "2.3.0", source = { registry = "https://pypi.org/simple" } }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165 } +sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249 }, + { url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" }, ] [[package]] name = "pyyaml" version = "6.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960 } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227 }, - { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019 }, - { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646 }, - { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793 }, - { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293 }, - { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872 }, - { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828 }, - { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415 }, - { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561 }, - { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826 }, - { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577 }, - { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556 }, - { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114 }, - { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638 }, - { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463 }, - { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986 }, - { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543 }, - { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763 }, - { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063 }, - { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973 }, - { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116 }, - { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011 }, - { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870 }, - { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089 }, - { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181 }, - { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658 }, - { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003 }, - { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344 }, - { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669 }, - { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252 }, - { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081 }, - { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159 }, - { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626 }, - { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613 }, - { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115 }, - { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427 }, - { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090 }, - { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246 }, - { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814 }, - { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809 }, - { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454 }, - { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355 }, - { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175 }, - { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228 }, - { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194 }, - { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429 }, - { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912 }, - { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108 }, - { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641 }, - { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901 }, - { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132 }, - { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261 }, - { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272 }, - { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923 }, - { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062 }, - { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341 }, - { url = "https://files.pythonhosted.org/packages/9f/62/67fc8e68a75f738c9200422bf65693fb79a4cd0dc5b23310e5202e978090/pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da", size = 184450 }, - { url = "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917", size = 174319 }, - { url = "https://files.pythonhosted.org/packages/d0/cd/f0cfc8c74f8a030017a2b9c771b7f47e5dd702c3e28e5b2071374bda2948/pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9", size = 737631 }, - { url = "https://files.pythonhosted.org/packages/ef/b2/18f2bd28cd2055a79a46c9b0895c0b3d987ce40ee471cecf58a1a0199805/pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5", size = 836795 }, - { url = "https://files.pythonhosted.org/packages/73/b9/793686b2d54b531203c160ef12bec60228a0109c79bae6c1277961026770/pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a", size = 750767 }, - { url = "https://files.pythonhosted.org/packages/a9/86/a137b39a611def2ed78b0e66ce2fe13ee701a07c07aebe55c340ed2a050e/pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926", size = 727982 }, - { url = "https://files.pythonhosted.org/packages/dd/62/71c27c94f457cf4418ef8ccc71735324c549f7e3ea9d34aba50874563561/pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7", size = 755677 }, - { url = "https://files.pythonhosted.org/packages/29/3d/6f5e0d58bd924fb0d06c3a6bad00effbdae2de5adb5cda5648006ffbd8d3/pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0", size = 142592 }, - { url = "https://files.pythonhosted.org/packages/f0/0c/25113e0b5e103d7f1490c0e947e303fe4a696c10b501dea7a9f49d4e876c/pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007", size = 158777 }, + { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, + { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, + { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, + { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, + { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, + { url = "https://files.pythonhosted.org/packages/9f/62/67fc8e68a75f738c9200422bf65693fb79a4cd0dc5b23310e5202e978090/pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da", size = 184450, upload-time = "2025-09-25T21:33:00.618Z" }, + { url = "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917", size = 174319, upload-time = "2025-09-25T21:33:02.086Z" }, + { url = "https://files.pythonhosted.org/packages/d0/cd/f0cfc8c74f8a030017a2b9c771b7f47e5dd702c3e28e5b2071374bda2948/pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9", size = 737631, upload-time = "2025-09-25T21:33:03.25Z" }, + { url = "https://files.pythonhosted.org/packages/ef/b2/18f2bd28cd2055a79a46c9b0895c0b3d987ce40ee471cecf58a1a0199805/pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5", size = 836795, upload-time = "2025-09-25T21:33:05.014Z" }, + { url = "https://files.pythonhosted.org/packages/73/b9/793686b2d54b531203c160ef12bec60228a0109c79bae6c1277961026770/pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a", size = 750767, upload-time = "2025-09-25T21:33:06.398Z" }, + { url = "https://files.pythonhosted.org/packages/a9/86/a137b39a611def2ed78b0e66ce2fe13ee701a07c07aebe55c340ed2a050e/pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926", size = 727982, upload-time = "2025-09-25T21:33:08.708Z" }, + { url = "https://files.pythonhosted.org/packages/dd/62/71c27c94f457cf4418ef8ccc71735324c549f7e3ea9d34aba50874563561/pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7", size = 755677, upload-time = "2025-09-25T21:33:09.876Z" }, + { url = "https://files.pythonhosted.org/packages/29/3d/6f5e0d58bd924fb0d06c3a6bad00effbdae2de5adb5cda5648006ffbd8d3/pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0", size = 142592, upload-time = "2025-09-25T21:33:10.983Z" }, + { url = "https://files.pythonhosted.org/packages/f0/0c/25113e0b5e103d7f1490c0e947e303fe4a696c10b501dea7a9f49d4e876c/pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007", size = 158777, upload-time = "2025-09-25T21:33:15.55Z" }, ] [[package]] @@ -231,109 +231,109 @@ name = "sqlite-vec" version = "0.1.9" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/68/85/9fad0045d8e7c8df3e0fa5a56c630e8e15ad6e5ca2e6106fceb666aa6638/sqlite_vec-0.1.9-py3-none-macosx_10_6_x86_64.whl", hash = "sha256:1b62a7f0a060d9475575d4e599bbf94a13d85af896bc1ce86ee80d1b5b48e5fb", size = 131171 }, - { url = "https://files.pythonhosted.org/packages/a4/3d/3677e0cd2f92e5ebc43cd29fbf565b75582bff1ccfa0b8327c7508e1084f/sqlite_vec-0.1.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1d52e30513bae4cc9778ddbf6145610434081be4c3afe57cd877893bad9f6b6c", size = 165434 }, - { url = "https://files.pythonhosted.org/packages/00/d4/f2b936d3bdc38eadcbd2a87875815db36430fab0363182ba5d12cd8e0b51/sqlite_vec-0.1.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e921e592f24a5f9a18f590b6ddd530eb637e2d474e3b1972f9bbeb773aa3cb9", size = 160076 }, - { url = "https://files.pythonhosted.org/packages/6f/ad/6afd073b0f817b3e03f9e37ad626ae341805891f23c74b5292818f49ac63/sqlite_vec-0.1.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux1_x86_64.whl", hash = "sha256:1515727990b49e79bcaf75fdee2ffc7d461f8b66905013231251f1c8938e7786", size = 163388 }, - { url = "https://files.pythonhosted.org/packages/42/89/81b2907cda14e566b9bf215e2ad82fc9b349edf07d2010756ffdb902f328/sqlite_vec-0.1.9-py3-none-win_amd64.whl", hash = "sha256:4a28dc12fa4b53d7b1dced22da2488fade444e96b5d16fd2d698cd670675cf32", size = 292804 }, + { url = "https://files.pythonhosted.org/packages/68/85/9fad0045d8e7c8df3e0fa5a56c630e8e15ad6e5ca2e6106fceb666aa6638/sqlite_vec-0.1.9-py3-none-macosx_10_6_x86_64.whl", hash = "sha256:1b62a7f0a060d9475575d4e599bbf94a13d85af896bc1ce86ee80d1b5b48e5fb", size = 131171, upload-time = "2026-03-31T08:02:31.717Z" }, + { url = "https://files.pythonhosted.org/packages/a4/3d/3677e0cd2f92e5ebc43cd29fbf565b75582bff1ccfa0b8327c7508e1084f/sqlite_vec-0.1.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1d52e30513bae4cc9778ddbf6145610434081be4c3afe57cd877893bad9f6b6c", size = 165434, upload-time = "2026-03-31T08:02:32.712Z" }, + { url = "https://files.pythonhosted.org/packages/00/d4/f2b936d3bdc38eadcbd2a87875815db36430fab0363182ba5d12cd8e0b51/sqlite_vec-0.1.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e921e592f24a5f9a18f590b6ddd530eb637e2d474e3b1972f9bbeb773aa3cb9", size = 160076, upload-time = "2026-03-31T08:02:33.796Z" }, + { url = "https://files.pythonhosted.org/packages/6f/ad/6afd073b0f817b3e03f9e37ad626ae341805891f23c74b5292818f49ac63/sqlite_vec-0.1.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux1_x86_64.whl", hash = "sha256:1515727990b49e79bcaf75fdee2ffc7d461f8b66905013231251f1c8938e7786", size = 163388, upload-time = "2026-03-31T08:02:34.888Z" }, + { url = "https://files.pythonhosted.org/packages/42/89/81b2907cda14e566b9bf215e2ad82fc9b349edf07d2010756ffdb902f328/sqlite_vec-0.1.9-py3-none-win_amd64.whl", hash = "sha256:4a28dc12fa4b53d7b1dced22da2488fade444e96b5d16fd2d698cd670675cf32", size = 292804, upload-time = "2026-03-31T08:02:36.035Z" }, ] [[package]] name = "tomli" version = "2.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543 } +sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/11/db3d5885d8528263d8adc260bb2d28ebf1270b96e98f0e0268d32b8d9900/tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30", size = 154704 }, - { url = "https://files.pythonhosted.org/packages/6d/f7/675db52c7e46064a9aa928885a9b20f4124ecb9bc2e1ce74c9106648d202/tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a", size = 149454 }, - { url = "https://files.pythonhosted.org/packages/61/71/81c50943cf953efa35bce7646caab3cf457a7d8c030b27cfb40d7235f9ee/tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076", size = 237561 }, - { url = "https://files.pythonhosted.org/packages/48/c1/f41d9cb618acccca7df82aaf682f9b49013c9397212cb9f53219e3abac37/tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9", size = 243824 }, - { url = "https://files.pythonhosted.org/packages/22/e4/5a816ecdd1f8ca51fb756ef684b90f2780afc52fc67f987e3c61d800a46d/tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c", size = 242227 }, - { url = "https://files.pythonhosted.org/packages/6b/49/2b2a0ef529aa6eec245d25f0c703e020a73955ad7edf73e7f54ddc608aa5/tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc", size = 247859 }, - { url = "https://files.pythonhosted.org/packages/83/bd/6c1a630eaca337e1e78c5903104f831bda934c426f9231429396ce3c3467/tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049", size = 97204 }, - { url = "https://files.pythonhosted.org/packages/42/59/71461df1a885647e10b6bb7802d0b8e66480c61f3f43079e0dcd315b3954/tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e", size = 108084 }, - { url = "https://files.pythonhosted.org/packages/b8/83/dceca96142499c069475b790e7913b1044c1a4337e700751f48ed723f883/tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece", size = 95285 }, - { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924 }, - { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018 }, - { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948 }, - { url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", size = 253341 }, - { url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", size = 248159 }, - { url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", size = 253290 }, - { url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", size = 98141 }, - { url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", size = 108847 }, - { url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", size = 95088 }, - { url = "https://files.pythonhosted.org/packages/07/06/b823a7e818c756d9a7123ba2cda7d07bc2dd32835648d1a7b7b7a05d848d/tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54", size = 155866 }, - { url = "https://files.pythonhosted.org/packages/14/6f/12645cf7f08e1a20c7eb8c297c6f11d31c1b50f316a7e7e1e1de6e2e7b7e/tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a", size = 149887 }, - { url = "https://files.pythonhosted.org/packages/5c/e0/90637574e5e7212c09099c67ad349b04ec4d6020324539297b634a0192b0/tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897", size = 243704 }, - { url = "https://files.pythonhosted.org/packages/10/8f/d3ddb16c5a4befdf31a23307f72828686ab2096f068eaf56631e136c1fdd/tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f", size = 251628 }, - { url = "https://files.pythonhosted.org/packages/e3/f1/dbeeb9116715abee2485bf0a12d07a8f31af94d71608c171c45f64c0469d/tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d", size = 247180 }, - { url = "https://files.pythonhosted.org/packages/d3/74/16336ffd19ed4da28a70959f92f506233bd7cfc2332b20bdb01591e8b1d1/tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5", size = 251674 }, - { url = "https://files.pythonhosted.org/packages/16/f9/229fa3434c590ddf6c0aa9af64d3af4b752540686cace29e6281e3458469/tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd", size = 97976 }, - { url = "https://files.pythonhosted.org/packages/6a/1e/71dfd96bcc1c775420cb8befe7a9d35f2e5b1309798f009dca17b7708c1e/tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36", size = 108755 }, - { url = "https://files.pythonhosted.org/packages/83/7a/d34f422a021d62420b78f5c538e5b102f62bea616d1d75a13f0a88acb04a/tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd", size = 95265 }, - { url = "https://files.pythonhosted.org/packages/3c/fb/9a5c8d27dbab540869f7c1f8eb0abb3244189ce780ba9cd73f3770662072/tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf", size = 155726 }, - { url = "https://files.pythonhosted.org/packages/62/05/d2f816630cc771ad836af54f5001f47a6f611d2d39535364f148b6a92d6b/tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac", size = 149859 }, - { url = "https://files.pythonhosted.org/packages/ce/48/66341bdb858ad9bd0ceab5a86f90eddab127cf8b046418009f2125630ecb/tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662", size = 244713 }, - { url = "https://files.pythonhosted.org/packages/df/6d/c5fad00d82b3c7a3ab6189bd4b10e60466f22cfe8a08a9394185c8a8111c/tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853", size = 252084 }, - { url = "https://files.pythonhosted.org/packages/00/71/3a69e86f3eafe8c7a59d008d245888051005bd657760e96d5fbfb0b740c2/tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15", size = 247973 }, - { url = "https://files.pythonhosted.org/packages/67/50/361e986652847fec4bd5e4a0208752fbe64689c603c7ae5ea7cb16b1c0ca/tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba", size = 256223 }, - { url = "https://files.pythonhosted.org/packages/8c/9a/b4173689a9203472e5467217e0154b00e260621caa227b6fa01feab16998/tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6", size = 98973 }, - { url = "https://files.pythonhosted.org/packages/14/58/640ac93bf230cd27d002462c9af0d837779f8773bc03dee06b5835208214/tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7", size = 109082 }, - { url = "https://files.pythonhosted.org/packages/d5/2f/702d5e05b227401c1068f0d386d79a589bb12bf64c3d2c72ce0631e3bc49/tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232", size = 96490 }, - { url = "https://files.pythonhosted.org/packages/45/4b/b877b05c8ba62927d9865dd980e34a755de541eb65fffba52b4cc495d4d2/tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4", size = 164263 }, - { url = "https://files.pythonhosted.org/packages/24/79/6ab420d37a270b89f7195dec5448f79400d9e9c1826df982f3f8e97b24fd/tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c", size = 160736 }, - { url = "https://files.pythonhosted.org/packages/02/e0/3630057d8eb170310785723ed5adcdfb7d50cb7e6455f85ba8a3deed642b/tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d", size = 270717 }, - { url = "https://files.pythonhosted.org/packages/7a/b4/1613716072e544d1a7891f548d8f9ec6ce2faf42ca65acae01d76ea06bb0/tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41", size = 278461 }, - { url = "https://files.pythonhosted.org/packages/05/38/30f541baf6a3f6df77b3df16b01ba319221389e2da59427e221ef417ac0c/tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c", size = 274855 }, - { url = "https://files.pythonhosted.org/packages/77/a3/ec9dd4fd2c38e98de34223b995a3b34813e6bdadf86c75314c928350ed14/tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f", size = 283144 }, - { url = "https://files.pythonhosted.org/packages/ef/be/605a6261cac79fba2ec0c9827e986e00323a1945700969b8ee0b30d85453/tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8", size = 108683 }, - { url = "https://files.pythonhosted.org/packages/12/64/da524626d3b9cc40c168a13da8335fe1c51be12c0a63685cc6db7308daae/tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26", size = 121196 }, - { url = "https://files.pythonhosted.org/packages/5a/cd/e80b62269fc78fc36c9af5a6b89c835baa8af28ff5ad28c7028d60860320/tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396", size = 100393 }, - { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583 }, + { url = "https://files.pythonhosted.org/packages/f4/11/db3d5885d8528263d8adc260bb2d28ebf1270b96e98f0e0268d32b8d9900/tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30", size = 154704, upload-time = "2026-03-25T20:21:10.473Z" }, + { url = "https://files.pythonhosted.org/packages/6d/f7/675db52c7e46064a9aa928885a9b20f4124ecb9bc2e1ce74c9106648d202/tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a", size = 149454, upload-time = "2026-03-25T20:21:12.036Z" }, + { url = "https://files.pythonhosted.org/packages/61/71/81c50943cf953efa35bce7646caab3cf457a7d8c030b27cfb40d7235f9ee/tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076", size = 237561, upload-time = "2026-03-25T20:21:13.098Z" }, + { url = "https://files.pythonhosted.org/packages/48/c1/f41d9cb618acccca7df82aaf682f9b49013c9397212cb9f53219e3abac37/tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9", size = 243824, upload-time = "2026-03-25T20:21:14.569Z" }, + { url = "https://files.pythonhosted.org/packages/22/e4/5a816ecdd1f8ca51fb756ef684b90f2780afc52fc67f987e3c61d800a46d/tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c", size = 242227, upload-time = "2026-03-25T20:21:15.712Z" }, + { url = "https://files.pythonhosted.org/packages/6b/49/2b2a0ef529aa6eec245d25f0c703e020a73955ad7edf73e7f54ddc608aa5/tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc", size = 247859, upload-time = "2026-03-25T20:21:17.001Z" }, + { url = "https://files.pythonhosted.org/packages/83/bd/6c1a630eaca337e1e78c5903104f831bda934c426f9231429396ce3c3467/tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049", size = 97204, upload-time = "2026-03-25T20:21:18.079Z" }, + { url = "https://files.pythonhosted.org/packages/42/59/71461df1a885647e10b6bb7802d0b8e66480c61f3f43079e0dcd315b3954/tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e", size = 108084, upload-time = "2026-03-25T20:21:18.978Z" }, + { url = "https://files.pythonhosted.org/packages/b8/83/dceca96142499c069475b790e7913b1044c1a4337e700751f48ed723f883/tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece", size = 95285, upload-time = "2026-03-25T20:21:20.309Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924, upload-time = "2026-03-25T20:21:21.626Z" }, + { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018, upload-time = "2026-03-25T20:21:23.002Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948, upload-time = "2026-03-25T20:21:24.04Z" }, + { url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", size = 253341, upload-time = "2026-03-25T20:21:25.177Z" }, + { url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", size = 248159, upload-time = "2026-03-25T20:21:26.364Z" }, + { url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", size = 253290, upload-time = "2026-03-25T20:21:27.46Z" }, + { url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", size = 98141, upload-time = "2026-03-25T20:21:28.492Z" }, + { url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", size = 108847, upload-time = "2026-03-25T20:21:29.386Z" }, + { url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", size = 95088, upload-time = "2026-03-25T20:21:30.677Z" }, + { url = "https://files.pythonhosted.org/packages/07/06/b823a7e818c756d9a7123ba2cda7d07bc2dd32835648d1a7b7b7a05d848d/tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54", size = 155866, upload-time = "2026-03-25T20:21:31.65Z" }, + { url = "https://files.pythonhosted.org/packages/14/6f/12645cf7f08e1a20c7eb8c297c6f11d31c1b50f316a7e7e1e1de6e2e7b7e/tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a", size = 149887, upload-time = "2026-03-25T20:21:33.028Z" }, + { url = "https://files.pythonhosted.org/packages/5c/e0/90637574e5e7212c09099c67ad349b04ec4d6020324539297b634a0192b0/tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897", size = 243704, upload-time = "2026-03-25T20:21:34.51Z" }, + { url = "https://files.pythonhosted.org/packages/10/8f/d3ddb16c5a4befdf31a23307f72828686ab2096f068eaf56631e136c1fdd/tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f", size = 251628, upload-time = "2026-03-25T20:21:36.012Z" }, + { url = "https://files.pythonhosted.org/packages/e3/f1/dbeeb9116715abee2485bf0a12d07a8f31af94d71608c171c45f64c0469d/tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d", size = 247180, upload-time = "2026-03-25T20:21:37.136Z" }, + { url = "https://files.pythonhosted.org/packages/d3/74/16336ffd19ed4da28a70959f92f506233bd7cfc2332b20bdb01591e8b1d1/tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5", size = 251674, upload-time = "2026-03-25T20:21:38.298Z" }, + { url = "https://files.pythonhosted.org/packages/16/f9/229fa3434c590ddf6c0aa9af64d3af4b752540686cace29e6281e3458469/tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd", size = 97976, upload-time = "2026-03-25T20:21:39.316Z" }, + { url = "https://files.pythonhosted.org/packages/6a/1e/71dfd96bcc1c775420cb8befe7a9d35f2e5b1309798f009dca17b7708c1e/tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36", size = 108755, upload-time = "2026-03-25T20:21:40.248Z" }, + { url = "https://files.pythonhosted.org/packages/83/7a/d34f422a021d62420b78f5c538e5b102f62bea616d1d75a13f0a88acb04a/tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd", size = 95265, upload-time = "2026-03-25T20:21:41.219Z" }, + { url = "https://files.pythonhosted.org/packages/3c/fb/9a5c8d27dbab540869f7c1f8eb0abb3244189ce780ba9cd73f3770662072/tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf", size = 155726, upload-time = "2026-03-25T20:21:42.23Z" }, + { url = "https://files.pythonhosted.org/packages/62/05/d2f816630cc771ad836af54f5001f47a6f611d2d39535364f148b6a92d6b/tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac", size = 149859, upload-time = "2026-03-25T20:21:43.386Z" }, + { url = "https://files.pythonhosted.org/packages/ce/48/66341bdb858ad9bd0ceab5a86f90eddab127cf8b046418009f2125630ecb/tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662", size = 244713, upload-time = "2026-03-25T20:21:44.474Z" }, + { url = "https://files.pythonhosted.org/packages/df/6d/c5fad00d82b3c7a3ab6189bd4b10e60466f22cfe8a08a9394185c8a8111c/tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853", size = 252084, upload-time = "2026-03-25T20:21:45.62Z" }, + { url = "https://files.pythonhosted.org/packages/00/71/3a69e86f3eafe8c7a59d008d245888051005bd657760e96d5fbfb0b740c2/tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15", size = 247973, upload-time = "2026-03-25T20:21:46.937Z" }, + { url = "https://files.pythonhosted.org/packages/67/50/361e986652847fec4bd5e4a0208752fbe64689c603c7ae5ea7cb16b1c0ca/tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba", size = 256223, upload-time = "2026-03-25T20:21:48.467Z" }, + { url = "https://files.pythonhosted.org/packages/8c/9a/b4173689a9203472e5467217e0154b00e260621caa227b6fa01feab16998/tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6", size = 98973, upload-time = "2026-03-25T20:21:49.526Z" }, + { url = "https://files.pythonhosted.org/packages/14/58/640ac93bf230cd27d002462c9af0d837779f8773bc03dee06b5835208214/tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7", size = 109082, upload-time = "2026-03-25T20:21:50.506Z" }, + { url = "https://files.pythonhosted.org/packages/d5/2f/702d5e05b227401c1068f0d386d79a589bb12bf64c3d2c72ce0631e3bc49/tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232", size = 96490, upload-time = "2026-03-25T20:21:51.474Z" }, + { url = "https://files.pythonhosted.org/packages/45/4b/b877b05c8ba62927d9865dd980e34a755de541eb65fffba52b4cc495d4d2/tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4", size = 164263, upload-time = "2026-03-25T20:21:52.543Z" }, + { url = "https://files.pythonhosted.org/packages/24/79/6ab420d37a270b89f7195dec5448f79400d9e9c1826df982f3f8e97b24fd/tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c", size = 160736, upload-time = "2026-03-25T20:21:53.674Z" }, + { url = "https://files.pythonhosted.org/packages/02/e0/3630057d8eb170310785723ed5adcdfb7d50cb7e6455f85ba8a3deed642b/tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d", size = 270717, upload-time = "2026-03-25T20:21:55.129Z" }, + { url = "https://files.pythonhosted.org/packages/7a/b4/1613716072e544d1a7891f548d8f9ec6ce2faf42ca65acae01d76ea06bb0/tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41", size = 278461, upload-time = "2026-03-25T20:21:56.228Z" }, + { url = "https://files.pythonhosted.org/packages/05/38/30f541baf6a3f6df77b3df16b01ba319221389e2da59427e221ef417ac0c/tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c", size = 274855, upload-time = "2026-03-25T20:21:57.653Z" }, + { url = "https://files.pythonhosted.org/packages/77/a3/ec9dd4fd2c38e98de34223b995a3b34813e6bdadf86c75314c928350ed14/tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f", size = 283144, upload-time = "2026-03-25T20:21:59.089Z" }, + { url = "https://files.pythonhosted.org/packages/ef/be/605a6261cac79fba2ec0c9827e986e00323a1945700969b8ee0b30d85453/tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8", size = 108683, upload-time = "2026-03-25T20:22:00.214Z" }, + { url = "https://files.pythonhosted.org/packages/12/64/da524626d3b9cc40c168a13da8335fe1c51be12c0a63685cc6db7308daae/tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26", size = 121196, upload-time = "2026-03-25T20:22:01.169Z" }, + { url = "https://files.pythonhosted.org/packages/5a/cd/e80b62269fc78fc36c9af5a6b89c835baa8af28ff5ad28c7028d60860320/tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396", size = 100393, upload-time = "2026-03-25T20:22:02.137Z" }, + { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, ] [[package]] name = "typing-extensions" version = "4.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391 } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614 }, + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, ] [[package]] name = "watchdog" version = "6.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220 } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/56/90994d789c61df619bfc5ce2ecdabd5eeff564e1eb47512bd01b5e019569/watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26", size = 96390 }, - { url = "https://files.pythonhosted.org/packages/55/46/9a67ee697342ddf3c6daa97e3a587a56d6c4052f881ed926a849fcf7371c/watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112", size = 88389 }, - { url = "https://files.pythonhosted.org/packages/44/65/91b0985747c52064d8701e1075eb96f8c40a79df889e59a399453adfb882/watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3", size = 89020 }, - { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393 }, - { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392 }, - { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019 }, - { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471 }, - { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449 }, - { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054 }, - { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480 }, - { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451 }, - { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057 }, - { url = "https://files.pythonhosted.org/packages/05/52/7223011bb760fce8ddc53416beb65b83a3ea6d7d13738dde75eeb2c89679/watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8", size = 96390 }, - { url = "https://files.pythonhosted.org/packages/9c/62/d2b21bc4e706d3a9d467561f487c2938cbd881c69f3808c43ac1ec242391/watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a", size = 88386 }, - { url = "https://files.pythonhosted.org/packages/ea/22/1c90b20eda9f4132e4603a26296108728a8bfe9584b006bd05dd94548853/watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c", size = 89017 }, - { url = "https://files.pythonhosted.org/packages/30/ad/d17b5d42e28a8b91f8ed01cb949da092827afb9995d4559fd448d0472763/watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", size = 87902 }, - { url = "https://files.pythonhosted.org/packages/5c/ca/c3649991d140ff6ab67bfc85ab42b165ead119c9e12211e08089d763ece5/watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", size = 88380 }, - { url = "https://files.pythonhosted.org/packages/5b/79/69f2b0e8d3f2afd462029031baafb1b75d11bb62703f0e1022b2e54d49ee/watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa", size = 87903 }, - { url = "https://files.pythonhosted.org/packages/e2/2b/dc048dd71c2e5f0f7ebc04dd7912981ec45793a03c0dc462438e0591ba5d/watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e", size = 88381 }, - { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079 }, - { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078 }, - { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076 }, - { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077 }, - { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078 }, - { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077 }, - { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078 }, - { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065 }, - { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070 }, - { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067 }, + { url = "https://files.pythonhosted.org/packages/0c/56/90994d789c61df619bfc5ce2ecdabd5eeff564e1eb47512bd01b5e019569/watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26", size = 96390, upload-time = "2024-11-01T14:06:24.793Z" }, + { url = "https://files.pythonhosted.org/packages/55/46/9a67ee697342ddf3c6daa97e3a587a56d6c4052f881ed926a849fcf7371c/watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112", size = 88389, upload-time = "2024-11-01T14:06:27.112Z" }, + { url = "https://files.pythonhosted.org/packages/44/65/91b0985747c52064d8701e1075eb96f8c40a79df889e59a399453adfb882/watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3", size = 89020, upload-time = "2024-11-01T14:06:29.876Z" }, + { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393, upload-time = "2024-11-01T14:06:31.756Z" }, + { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392, upload-time = "2024-11-01T14:06:32.99Z" }, + { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019, upload-time = "2024-11-01T14:06:34.963Z" }, + { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" }, + { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" }, + { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" }, + { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" }, + { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" }, + { url = "https://files.pythonhosted.org/packages/05/52/7223011bb760fce8ddc53416beb65b83a3ea6d7d13738dde75eeb2c89679/watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8", size = 96390, upload-time = "2024-11-01T14:06:49.325Z" }, + { url = "https://files.pythonhosted.org/packages/9c/62/d2b21bc4e706d3a9d467561f487c2938cbd881c69f3808c43ac1ec242391/watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a", size = 88386, upload-time = "2024-11-01T14:06:50.536Z" }, + { url = "https://files.pythonhosted.org/packages/ea/22/1c90b20eda9f4132e4603a26296108728a8bfe9584b006bd05dd94548853/watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c", size = 89017, upload-time = "2024-11-01T14:06:51.717Z" }, + { url = "https://files.pythonhosted.org/packages/30/ad/d17b5d42e28a8b91f8ed01cb949da092827afb9995d4559fd448d0472763/watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", size = 87902, upload-time = "2024-11-01T14:06:53.119Z" }, + { url = "https://files.pythonhosted.org/packages/5c/ca/c3649991d140ff6ab67bfc85ab42b165ead119c9e12211e08089d763ece5/watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", size = 88380, upload-time = "2024-11-01T14:06:55.19Z" }, + { url = "https://files.pythonhosted.org/packages/5b/79/69f2b0e8d3f2afd462029031baafb1b75d11bb62703f0e1022b2e54d49ee/watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa", size = 87903, upload-time = "2024-11-01T14:06:57.052Z" }, + { url = "https://files.pythonhosted.org/packages/e2/2b/dc048dd71c2e5f0f7ebc04dd7912981ec45793a03c0dc462438e0591ba5d/watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e", size = 88381, upload-time = "2024-11-01T14:06:58.193Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, ] diff --git a/viz/explorer.html b/viz/explorer.html index 6dc87f5..050dcd5 100644 --- a/viz/explorer.html +++ b/viz/explorer.html @@ -3,7 +3,7 @@ -codeindex +blastradius