diff --git a/.github/actions/codeclone/README.md b/.github/actions/codeclone/README.md
index c82c978d..254a0302 100644
--- a/.github/actions/codeclone/README.md
+++ b/.github/actions/codeclone/README.md
@@ -183,4 +183,4 @@ Local/self-repo validation:
- [CodeClone repository](https://github.com/orenlab/codeclone)
- [Documentation](https://orenlab.github.io/codeclone/)
-- [SARIF integration](https://orenlab.github.io/codeclone/guide/integrations/sarif/export/)
+- [SARIF integration](https://orenlab.github.io/codeclone/reference/reports/)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5fc823ec..6dc52d6d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,6 @@
# Changelog
-## [2.1.0a1] - Unreleased
+## [2.1.0a1] - 2026-07-09
CodeClone 2.1 introduces intent-first structural change control, persistent engineering context, agent workflow
evidence, platform self-observability, and broader IDE/agent integration.
@@ -29,12 +29,12 @@ evidence, platform self-observability, and broader IDE/agent integration.
governance, audit, memory, trajectory, and structural-review workflows.
- **`codeclone setup`** — lazy-loaded CLI readiness surface (`status`, `doctor`, `plan`, `apply`, `wizard`) with
capability-aware snapshots, read-only diff preview, and bounded `pyproject.toml` / `.gitignore` merges (no MCP
- intent, no baseline or report writes).
+ intent, no baseline or report writes). The CLI also gains a guided `--help` tour.
- Expanded controller, memory, trajectory, analytics, semantic-search, observability, blast-radius, patch-verification,
and diagnostic CLI/MCP surfaces. The default MCP server surface is now **38 tools** (**40** when VS Code enables the
IDE governance channel).
-- Reorganized documentation into a contract-focused 00–26 book with unified integration guidance and explicit edition
- tiers.
+- Reorganized documentation into a task-oriented site (concepts, guides, reference, integrations) with unified
+ integration guidance and explicit edition tiers.
- MCP schemas now include parameter descriptions, deterministic `next_tool` guidance, token-budget tracking, workspace
hygiene warnings, and documentation-contract linting.
- MCP response governance now advertises `context_governance` metadata for bounded agent replies. Workflow, memory, and
@@ -55,6 +55,7 @@ evidence, platform self-observability, and broader IDE/agent integration.
- Corpus Analytics control-plane contract introduced at **1.0**.
- MCP response governance contract introduced at **1.0** with deterministic `utf8_bytes_div_4_v1` context-unit
estimation and explicit `observe` / `partial_enforce` modes.
+- `compare_runs` parameters are unified to `before_run_id` / `after_run_id`.
- `derived.module_map` and `derived.review_queue` remain report-only projections excluded from the integrity digest;
they add no analysis pass, metrics family, or report schema bump.
- Live Implementation Context relationship facts remain off the canonical report and do not change canonical report
@@ -68,13 +69,19 @@ evidence, platform self-observability, and broader IDE/agent integration.
- LCOM4 excludes Protocol methods and Pydantic validation/serialization hooks; `computed_field` remains included.
- Repository coverage is enforced at **>=99%**.
+### Performance
+
+- Relationship facts are collected during the primary module walk instead of a second traversal (cold-cache
+ `phase_relationship` −28%), and reachability facts replay captured handler nodes instead of a third full AST pass.
+- MCP hot paths are bounded: findings are paged before decoration, hotspot and intent-scoped blast projections are
+ capped, analysis no longer round-trips through the report, and cache loads retain less transient memory.
+
### Fixed
-- Engineering Memory writes are durable and batch ingestion is atomic.
+- Engineering Memory writes are durable, batch ingestion is atomic, and memory/trajectory/Patch Trail lifecycle
+ handling avoids premature staleness, duplicate projections, stale workflow rows, and broken evidence links.
- Best-effort audit and memory-proposal failures are now observable instead of silently swallowed.
- Implementation-context misses return a compact actionable payload instead of empty scaffolding.
-- Memory, trajectory, and Patch Trail lifecycle handling now avoids premature staleness, duplicate projections, stale
- workflow rows, and broken evidence links.
- Workspace hygiene, intent attribution, continuation of owned work, queue handling, and recoverable-intent behavior
were corrected.
- Patch verification now rejects identical before/after runs where required, surfaces health regressions, and warns on
diff --git a/README.md b/README.md
index 39de5d21..986ab34c 100644
--- a/README.md
+++ b/README.md
@@ -51,14 +51,15 @@ CodeClone does not generate or rewrite source files, and it does not ask an LLM
is safe. Every finding and every gate comes from deterministic repository facts shared across agents, human reviewers,
IDEs, reports, and CI.
-| Capability | What it provides |
-|------------------------------------------------|--------------------------------------------------------------------------------------------------------------|
-| **Canonical structural analysis** | One deterministic report: clones, complexity, coupling, cohesion, dead code, API inventory, coverage joins |
-| **Baseline-aware governance** | Records accepted legacy debt and separates it from regressions introduced by the current change |
-| **One report, many surfaces** | CLI, HTML, JSON, Markdown, SARIF, MCP, IDE integrations, and GitHub Actions from one canonical payload |
-| **Structural Change Controller** — `2.1 alpha` | Intent-first change control, blast radius, explicit edit boundaries, patch verification, and review receipts |
-| **Engineering Memory** — `2.1 alpha` | Local, typed, evidence-linked project knowledge and reusable histories of prior controlled changes |
-| **Agent coordination** — `2.1 alpha` | Conflict-safe multi-agent intents, queues, recovery, and workspace hygiene |
+| Capability | What it provides |
+|-------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------|
+| **Canonical structural analysis** | One deterministic report: clones, complexity, coupling, cohesion, dead code, module map, API inventory, coverage joins |
+| **Baseline-aware governance** | Records accepted legacy debt and separates it from regressions introduced by the current change |
+| **One report, many surfaces** | CLI, HTML, JSON, Markdown, SARIF, MCP, IDE integrations, and GitHub Actions from one canonical payload |
+| **Structural Change Controller** — `2.1 alpha` | Intent-first change control, blast radius, explicit edit boundaries, patch verification, and review receipts |
+| **Live Implementation Context** — `2.1 alpha` | Real-time structural and call-graph context served from the current analysis run — no stale index to maintain |
+| **Engineering Memory** — `2.1 alpha` | Local, typed, evidence-linked project knowledge and reusable histories of prior controlled changes |
+| **Agent coordination** — `2.1 alpha` | Conflict-safe multi-agent intents, queues, recovery, and workspace hygiene |
CodeClone requires no hosted service or cloud account. Analysis state, controller state, Engineering Memory, and
trajectories are stored locally.
@@ -140,7 +141,7 @@ from findings that were already present, so agents and reviewers can focus on wh
Updating the baseline is an explicit governance action. Do not regenerate it merely to make a failing check pass.
-### 3. Connect your AI agent
+### 3. Connect your AI agent — `2.1 alpha`
Continue to [Agent change control](#agent-change-control--21-alpha) below to install the MCP control surface and wire
CodeClone into Claude Code, Cursor, VS Code, Codex, or Claude Desktop.
@@ -154,6 +155,8 @@ The report covers:
- function, block, and segment clones;
- clone drift and duplicated branch families;
- complexity, coupling, cohesion, dependency cycles, and dead code;
+- **Module Map** — a package/module dependency graph with cycle, hub, overloaded-module, and unwind-candidate views;
+- **Guided Finding Review** — a prioritized review queue with shared finding cards, filters, and progress tracking;
- public API inventory and baseline-aware API break detection;
- external coverage joined with structural hotspots;
- deterministic structural health and review priorities.
@@ -162,8 +165,8 @@ The report covers:
codeclone . --json --html --md --sarif --text
```
-[How CodeClone works](https://orenlab.github.io/codeclone/guide/explanation/how-it-works/) ·
-[Canonical report contract](https://orenlab.github.io/codeclone/book/05-report/)
+[How CodeClone works](https://orenlab.github.io/codeclone/concepts/structural-analysis/) ·
+[Canonical report contract](https://orenlab.github.io/codeclone/reference/reports/)
## Baseline-aware governance and CI
@@ -194,9 +197,8 @@ Use CodeClone in GitHub Actions:
CI can reject newly introduced clones, metric regressions, API breaks, and coverage regressions without requiring the
existing repository to be clean first.
-[Baseline contract](https://orenlab.github.io/codeclone/book/07-baseline/) ·
-[Metrics and quality gates](https://orenlab.github.io/codeclone/book/16-metrics-and-quality-gates/) ·
-[GitHub Action documentation](https://orenlab.github.io/codeclone/getting-started/#github-action)
+[Baseline contract](https://orenlab.github.io/codeclone/concepts/reports/) ·
+[CI integration and quality gates](https://orenlab.github.io/codeclone/guides/ci-integration/)
## How CodeClone differs
@@ -217,6 +219,10 @@ uv tool install --prerelease allow "codeclone[mcp]"
codeclone-mcp --transport stdio
```
+The server exposes **38 MCP tools** covering analysis, change control, blast radius, memory, and diagnostics. Responses
+are built for agent loops: deterministic `next_tool` guidance, token-budget-aware payloads, and replies that keep
+mandatory control facts inline while linking full evidence for drill-down.
+
Before gating agents or CI, confirm `[tool.codeclone]` and local gitignore hygiene:
```bash
@@ -225,17 +231,17 @@ codeclone setup plan
codeclone setup apply # or: codeclone setup wizard
```
-See [Repository setup and readiness](https://orenlab.github.io/codeclone/guide/setup/readiness-and-apply/).
+See [Repository setup and readiness](https://orenlab.github.io/codeclone/guides/setup-project/).
### Wire it into your client
-| Client | Setup |
-|----------------|--------------------------------------------------------------------------------------------------------|
-| VS Code | [Extension setup](https://orenlab.github.io/codeclone/guide/integrations/vscode/setup/) |
-| Cursor | [Plugin and skills](https://orenlab.github.io/codeclone/guide/integrations/cursor/install-and-skills/) |
-| Claude Code | [Plugin setup](https://orenlab.github.io/codeclone/guide/integrations/claude-code/setup/) |
-| Codex | [Plugin setup](https://orenlab.github.io/codeclone/guide/integrations/codex/setup/) |
-| Claude Desktop | [Bundle setup](https://orenlab.github.io/codeclone/guide/integrations/claude-desktop/setup/) |
+| Client | Setup |
+|----------------|-------------------------------------------------------------------------------|
+| VS Code | [Extension setup](https://orenlab.github.io/codeclone/integrations/vscode/) |
+| Cursor | [Plugin and skills](https://orenlab.github.io/codeclone/integrations/cursor/) |
+| Claude Code | [Plugin setup](https://orenlab.github.io/codeclone/integrations/claude/) |
+| Codex | [Plugin setup](https://orenlab.github.io/codeclone/integrations/codex/) |
+| Claude Desktop | [Bundle setup](https://orenlab.github.io/codeclone/integrations/claude/) |
Every client uses the same MCP interface and the same canonical structural facts.
@@ -259,7 +265,9 @@ baseline.
- returns the authoritative `edit_allowed` result.
**Edit.** The agent writes the code. CodeClone does not generate or rewrite source files. Where the host supports
-hooks, integrations can stop edits unless `edit_allowed=true`.
+hooks, integrations can stop edits unless `edit_allowed=true`. While editing, the agent stays oriented through
+[Live Implementation Context](#live-implementation-context) instead of rediscovering the repository with broad
+searches.
**Finish.** `finish_controlled_change`:
@@ -272,10 +280,30 @@ hooks, integrations can stop edits unless `edit_allowed=true`.
-The result is not an AI opinion about the patch. It is a deterministic comparison between declared intent, repository
-structure, the accepted baseline, and the actual change.
+If the patch crosses the declared boundary or introduces regressions beyond the budget, verification fails — and the
+receipt records exactly where and why. The result is not an AI opinion about the patch. It is a deterministic
+comparison between declared intent, repository structure, the accepted baseline, and the actual change.
+
+[Read the Structural Change Controller guide](https://orenlab.github.io/codeclone/concepts/controlled-change/)
+
+### Live Implementation Context
+
+`get_implementation_context` serves the agent bounded, task-scoped context directly from the current analysis run:
-[Read the Structural Change Controller guide](https://orenlab.github.io/codeclone/book/12-structural-change-controller/)
+- structural context and call relationships for the declared edit scope;
+- contract-oriented truth maps and test anchors;
+- freshness signals and active intent boundaries.
+
+There is no separate vector database drifting behind the code, and no watcher daemon re-indexing the tree. Context
+comes from the same analysis that produces findings and gates — so what the agent reads is what the verifier will
+check. Context is read-only: it informs edits but never authorizes them.
+
+### Also in the 2.1 line
+
+- **Platform Observability** — development-time tracing of CLI, MCP, analysis phases, database activity, and payload
+ pressure, so you can see what CodeClone itself is doing and what it costs.
+- **Corpus Analytics** — offline intent clustering and interpretability over recorded controlled changes, with
+ versioned profiles and inspectable JSON/HTML outputs.
## Engineering Memory — `2.1 alpha`
@@ -296,11 +324,14 @@ codeclone memory init --root .
codeclone memory search "baseline schema" --match all
```
+Retrieval is hybrid — FTS5/BM25 lexical search, optional LanceDB vector search, and Reciprocal Rank Fusion combining
+the two — with fully reproducible ranking.
+
Memory can guide an agent. It cannot authorize edits, override blast radius, change a gate, or replace canonical
report facts.
-[Engineering Memory documentation](https://orenlab.github.io/codeclone/book/13-engineering-memory/) ·
-[Trajectories and Experiences](https://orenlab.github.io/codeclone/guide/memory/trajectories-and-experiences/)
+[Engineering Memory documentation](https://orenlab.github.io/codeclone/concepts/engineering-memory/) ·
+[Trajectories and Experiences](https://orenlab.github.io/codeclone/guides/engineering-memory-workflow/)
## Trust boundaries
@@ -309,7 +340,7 @@ report facts.
- Read-only analysis commands do not modify source code or project governance state.
- Baseline updates are explicit user-approved governance actions.
- Controller and memory operations write only to their explicit local state stores.
-- Memory and trajectory evidence remain advisory.
+- Memory, trajectory, and implementation-context evidence remain advisory.
- `stdio` is the recommended transport for local clients.
- Remote HTTP exposure requires explicit `--allow-remote`.
@@ -334,10 +365,10 @@ uv run codeclone .
**[orenlab.github.io/codeclone](https://orenlab.github.io/codeclone/)**
- [Getting started](https://orenlab.github.io/codeclone/getting-started/)
-- [Structural Change Controller](https://orenlab.github.io/codeclone/book/12-structural-change-controller/)
-- [Engineering Memory](https://orenlab.github.io/codeclone/book/13-engineering-memory/)
-- [MCP usage](https://orenlab.github.io/codeclone/guide/mcp/)
-- [Configuration reference](https://orenlab.github.io/codeclone/book/10-config-and-defaults/)
+- [Structural Change Controller](https://orenlab.github.io/codeclone/concepts/controlled-change/)
+- [Engineering Memory](https://orenlab.github.io/codeclone/concepts/engineering-memory/)
+- [MCP usage](https://orenlab.github.io/codeclone/concepts/mcp/)
+- [Configuration reference](https://orenlab.github.io/codeclone/reference/configuration/)
## License
diff --git a/codeclone/analysis/_module_walk.py b/codeclone/analysis/_module_walk.py
index 288b7189..11a3c1b8 100644
--- a/codeclone/analysis/_module_walk.py
+++ b/codeclone/analysis/_module_walk.py
@@ -522,37 +522,64 @@ def _function_parameter_names(node: _qualnames.FunctionNode) -> set[str]:
return names
-def _caller_local_bindings(node: _qualnames.FunctionNode) -> frozenset[str]:
+def _accumulate_caller_binding_from_scope_node(
+ scope_node: ast.AST,
+ *,
+ bound_names: set[str],
+ global_names: set[str],
+ nonlocal_names: set[str],
+) -> None:
+ if isinstance(scope_node, ast.Name) and isinstance(
+ scope_node.ctx, ast.Store | ast.Del
+ ):
+ bound_names.add(scope_node.id)
+ elif isinstance(scope_node, ast.Import):
+ bound_names.update(
+ alias.asname or alias.name.split(".", 1)[0] for alias in scope_node.names
+ )
+ elif isinstance(scope_node, ast.ImportFrom):
+ bound_names.update(
+ alias.asname or alias.name
+ for alias in scope_node.names
+ if alias.name != "*"
+ )
+ elif isinstance(scope_node, ast.Global):
+ global_names.update(scope_node.names)
+ elif isinstance(scope_node, ast.Nonlocal):
+ nonlocal_names.update(scope_node.names)
+ else:
+ declaration_name = _scope_declaration_binding_name(scope_node)
+ if declaration_name is not None:
+ bound_names.add(declaration_name)
+
+
+def _walk_relationship_function_scope(
+ node: _qualnames.FunctionNode,
+) -> tuple[frozenset[str], tuple[ast.AST, ...]]:
+ """Single DFS over a function body for caller bindings and scope nodes."""
bound_names = _function_parameter_names(node)
global_names: set[str] = set()
nonlocal_names: set[str] = set()
- for scope_node in _iter_relationship_scope_nodes(node.body):
- if isinstance(scope_node, ast.Name) and isinstance(
- scope_node.ctx, ast.Store | ast.Del
+ scope_nodes: list[ast.AST] = []
+ stack: list[ast.AST] = list(reversed(node.body))
+ while stack:
+ scope_node = stack.pop()
+ scope_nodes.append(scope_node)
+ _accumulate_caller_binding_from_scope_node(
+ scope_node,
+ bound_names=bound_names,
+ global_names=global_names,
+ nonlocal_names=nonlocal_names,
+ )
+ if isinstance(
+ scope_node,
+ ast.FunctionDef | ast.AsyncFunctionDef | ast.ClassDef | ast.Lambda,
):
- bound_names.add(scope_node.id)
- elif isinstance(scope_node, ast.Import):
- bound_names.update(
- alias.asname or alias.name.split(".", 1)[0]
- for alias in scope_node.names
- )
- elif isinstance(scope_node, ast.ImportFrom):
- bound_names.update(
- alias.asname or alias.name
- for alias in scope_node.names
- if alias.name != "*"
- )
- elif isinstance(scope_node, ast.Global):
- global_names.update(scope_node.names)
- elif isinstance(scope_node, ast.Nonlocal):
- nonlocal_names.update(scope_node.names)
- else:
- declaration_name = _scope_declaration_binding_name(scope_node)
- if declaration_name is not None:
- bound_names.add(declaration_name)
+ continue
+ stack.extend(reversed(list(ast.iter_child_nodes(scope_node))))
bound_names.difference_update(global_names)
bound_names.difference_update(nonlocal_names)
- return frozenset(sorted(bound_names))
+ return frozenset(sorted(bound_names)), tuple(scope_nodes)
def _first_parameter_name(node: _qualnames.FunctionNode) -> str | None:
@@ -731,7 +758,7 @@ def _collect_function_relationship_facts(
facts: list[FunctionRelationshipFacts] = []
for local_name, function_node in collector.units:
source_qualname = f"{module_name}:{local_name}"
- caller_bindings = _caller_local_bindings(function_node)
+ caller_bindings, scope_nodes = _walk_relationship_function_scope(function_node)
# The enclosing class of a method is the qualname segment before its own
# name; top-level functions have none. The receiver (self/cls) is the
# first parameter, but only for non-static methods — a staticmethod's
@@ -745,7 +772,6 @@ def _collect_function_relationship_facts(
and "staticmethod" not in _decorator_simple_names(function_node)
else None
)
- scope_nodes = tuple(_iter_relationship_scope_nodes(function_node.body))
calls = tuple(node for node in scope_nodes if isinstance(node, ast.Call))
call_function_node_ids = {
id(descendant) for call in calls for descendant in ast.walk(call.func)
diff --git a/codeclone/analysis/phase_ledger.py b/codeclone/analysis/phase_ledger.py
index 96ff1979..fb96e2f8 100644
--- a/codeclone/analysis/phase_ledger.py
+++ b/codeclone/analysis/phase_ledger.py
@@ -6,11 +6,14 @@
from __future__ import annotations
+from collections.abc import Callable
from dataclasses import dataclass, fields
from enum import Enum
from time import perf_counter_ns
from types import TracebackType
-from typing import Literal
+from typing import Final, Literal, TypeVar
+
+_T = TypeVar("_T")
class AnalysisPhaseKey(str, Enum):
@@ -46,6 +49,25 @@ class AnalysisVolumeKey(str, Enum):
key.value for key in AnalysisVolumeKey
)
+SUBPHASE_MODULE_PASSES_ADOPTION_US: Final = "subphase_module_passes_adoption_us"
+SUBPHASE_MODULE_PASSES_SECURITY_US: Final = "subphase_module_passes_security_us"
+SUBPHASE_MODULE_PASSES_REACHABILITY_ALIAS_US: Final = (
+ "subphase_module_passes_reachability_alias_us"
+)
+SUBPHASE_MODULE_PASSES_REACHABILITY_BINDING_US: Final = (
+ "subphase_module_passes_reachability_binding_us"
+)
+SUBPHASE_MODULE_PASSES_REACHABILITY_VISIT_US: Final = (
+ "subphase_module_passes_reachability_visit_us"
+)
+MODULE_PASSES_SUBPHASE_US_COUNTER_SUFFIXES: tuple[str, ...] = (
+ SUBPHASE_MODULE_PASSES_ADOPTION_US,
+ SUBPHASE_MODULE_PASSES_SECURITY_US,
+ SUBPHASE_MODULE_PASSES_REACHABILITY_ALIAS_US,
+ SUBPHASE_MODULE_PASSES_REACHABILITY_BINDING_US,
+ SUBPHASE_MODULE_PASSES_REACHABILITY_VISIT_US,
+)
+
@dataclass(frozen=True, slots=True)
class PhaseTotals:
@@ -83,6 +105,7 @@ def counter_map_us(self) -> dict[str, int]:
class PhaseSnapshot:
totals: PhaseTotals
volumes: tuple[tuple[str, int], ...]
+ subphase_us: tuple[tuple[str, int], ...] = ()
@classmethod
def empty(cls) -> PhaseSnapshot:
@@ -92,14 +115,21 @@ def merge(self, other: PhaseSnapshot) -> PhaseSnapshot:
merged_volumes = self.volume_map()
for key, value in other.volumes:
merged_volumes[key] = merged_volumes.get(key, 0) + value
+ merged_subphase = self.subphase_us_map()
+ for key, value in other.subphase_us:
+ merged_subphase[key] = merged_subphase.get(key, 0) + value
return PhaseSnapshot(
totals=self.totals.merge(other.totals),
volumes=tuple(sorted(merged_volumes.items())),
+ subphase_us=tuple(sorted(merged_subphase.items())),
)
def volume_map(self) -> dict[str, int]:
return dict(self.volumes)
+ def subphase_us_map(self) -> dict[str, int]:
+ return dict(self.subphase_us)
+
class _InertPhaseContext:
__slots__ = ()
@@ -144,12 +174,13 @@ def __exit__(
class PhaseLedger:
- __slots__ = ("_active", "_totals", "_volumes")
+ __slots__ = ("_active", "_subphase_us", "_totals", "_volumes")
def __init__(self, *, active: bool) -> None:
self._active = active
self._totals: dict[AnalysisPhaseKey, int] = {}
self._volumes: dict[AnalysisVolumeKey, int] = {}
+ self._subphase_us: dict[str, int] = {}
@property
def active(self) -> bool:
@@ -169,6 +200,20 @@ def add_volume(self, key: AnalysisVolumeKey, value: int = 1) -> None:
return
self._volumes[key] = self._volumes.get(key, 0) + value
+ def add_subphase_us(self, key: str, elapsed_ns: int) -> None:
+ if not self._active:
+ return
+ self._subphase_us[key] = self._subphase_us.get(key, 0) + (elapsed_ns // 1000)
+
+ def run_subphase_us(self, key: str, fn: Callable[[], _T]) -> _T:
+ if not self._active:
+ return fn()
+ started_ns = perf_counter_ns()
+ try:
+ return fn()
+ finally:
+ self.add_subphase_us(key, perf_counter_ns() - started_ns)
+
def snapshot(self) -> PhaseSnapshot:
totals = PhaseTotals(
**{f"{key.value}_ns": self._totals.get(key, 0) for key in AnalysisPhaseKey}
@@ -178,6 +223,7 @@ def snapshot(self) -> PhaseSnapshot:
volumes=tuple(
sorted((key.value, value) for key, value in self._volumes.items())
),
+ subphase_us=tuple(sorted(self._subphase_us.items())),
)
def _add_elapsed(self, key: AnalysisPhaseKey, elapsed_ns: int) -> None:
@@ -189,8 +235,14 @@ def _add_elapsed(self, key: AnalysisPhaseKey, elapsed_ns: int) -> None:
__all__ = [
"INERT_PHASE_LEDGER",
+ "MODULE_PASSES_SUBPHASE_US_COUNTER_SUFFIXES",
"PHASE_US_COUNTER_SUFFIXES",
"PHASE_VOLUME_COUNTER_SUFFIXES",
+ "SUBPHASE_MODULE_PASSES_ADOPTION_US",
+ "SUBPHASE_MODULE_PASSES_REACHABILITY_ALIAS_US",
+ "SUBPHASE_MODULE_PASSES_REACHABILITY_BINDING_US",
+ "SUBPHASE_MODULE_PASSES_REACHABILITY_VISIT_US",
+ "SUBPHASE_MODULE_PASSES_SECURITY_US",
"AnalysisPhaseKey",
"AnalysisVolumeKey",
"PhaseLedger",
diff --git a/codeclone/analysis/reachability.py b/codeclone/analysis/reachability.py
index f381aa16..d621e713 100644
--- a/codeclone/analysis/reachability.py
+++ b/codeclone/analysis/reachability.py
@@ -18,6 +18,13 @@
RuntimeReachabilityTargetKind,
)
from .ast_helpers import ast_node_end_line, ast_node_start_line
+from .phase_ledger import (
+ INERT_PHASE_LEDGER,
+ SUBPHASE_MODULE_PASSES_REACHABILITY_ALIAS_US,
+ SUBPHASE_MODULE_PASSES_REACHABILITY_BINDING_US,
+ SUBPHASE_MODULE_PASSES_REACHABILITY_VISIT_US,
+ PhaseLedger,
+)
_RuntimeObjectKind = str
@@ -404,19 +411,37 @@ def visit_ImportFrom(self, node: ast.ImportFrom) -> None:
class _RuntimeBindingVisitor(ast.NodeVisitor):
__slots__ = (
"_aliases",
+ "_handler_nodes",
"_scope_depth",
"included_routers",
"objects",
"route_decorator_factories",
)
- def __init__(self, aliases: dict[str, str]) -> None:
+ def __init__(
+ self,
+ aliases: dict[str, str],
+ *,
+ handler_nodes: list[ast.AST] | None = None,
+ ) -> None:
self._aliases = aliases
+ self._handler_nodes = handler_nodes
self._scope_depth = 0
self.objects: dict[str, _RuntimeObjectKind] = {}
self.included_routers: set[str] = set()
self.route_decorator_factories: dict[str, _RouteDecoratorFactory] = {}
+ def visit(self, node: ast.AST) -> None:
+ if isinstance(node, ast.If) and _is_type_checking_guard(node.test):
+ return
+ handler_nodes = self._handler_nodes
+ if handler_nodes is not None and isinstance(
+ node,
+ ast.FunctionDef | ast.AsyncFunctionDef | ast.ClassDef | ast.Assign,
+ ):
+ handler_nodes.append(node)
+ super().visit(node)
+
def visit_If(self, node: ast.If) -> None:
if _is_type_checking_guard(node.test):
return
@@ -713,29 +738,40 @@ def visit_If(self, node: ast.If) -> None:
return
self.generic_visit(node)
+ def _apply_handler_node(self, node: ast.AST) -> None:
+ match node:
+ case ast.FunctionDef() | ast.AsyncFunctionDef():
+ self._handle_callable(node)
+ case ast.ClassDef():
+ self._handle_dependency_injector_container(node)
+ self._handle_starlette_base_http_middleware(node)
+ self._handle_sqlalchemy_type_decorator(node)
+ self._handle_pydantic_generate_json_schema(node)
+ self._handle_starlette_route_subclass(node)
+ self._handle_framework_application_subclass(node)
+ case ast.Assign():
+ if any(
+ isinstance(target, ast.Name) and target.id == "urlpatterns"
+ for target in node.targets
+ ):
+ self._handle_django_urlpatterns(node.value)
+ case _:
+ return
+
def visit_FunctionDef(self, node: ast.FunctionDef) -> None:
- self._handle_callable(node)
+ self._apply_handler_node(node)
self.generic_visit(node)
def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef) -> None:
- self._handle_callable(node)
+ self._apply_handler_node(node)
self.generic_visit(node)
def visit_ClassDef(self, node: ast.ClassDef) -> None:
- self._handle_dependency_injector_container(node)
- self._handle_starlette_base_http_middleware(node)
- self._handle_sqlalchemy_type_decorator(node)
- self._handle_pydantic_generate_json_schema(node)
- self._handle_starlette_route_subclass(node)
- self._handle_framework_application_subclass(node)
+ self._apply_handler_node(node)
self.generic_visit(node)
def visit_Assign(self, node: ast.Assign) -> None:
- if any(
- isinstance(target, ast.Name) and target.id == "urlpatterns"
- for target in node.targets
- ):
- self._handle_django_urlpatterns(node.value)
+ self._apply_handler_node(node)
self.generic_visit(node)
def _handle_callable(self, node: ast.FunctionDef | ast.AsyncFunctionDef) -> None:
@@ -1303,11 +1339,30 @@ def collect_runtime_reachability(
module_name: str,
filepath: str,
collector: _qualnames.QualnameCollector,
+ phase_ledger: PhaseLedger = INERT_PHASE_LEDGER,
) -> tuple[RuntimeReachabilityFact, ...]:
alias_visitor = _ImportAliasVisitor()
- alias_visitor.visit(tree)
- binding_visitor = _RuntimeBindingVisitor(alias_visitor.aliases)
- binding_visitor.visit(tree)
+
+ def _alias_pass() -> None:
+ alias_visitor.visit(tree)
+
+ phase_ledger.run_subphase_us(
+ SUBPHASE_MODULE_PASSES_REACHABILITY_ALIAS_US,
+ _alias_pass,
+ )
+ handler_nodes: list[ast.AST] = []
+ binding_visitor = _RuntimeBindingVisitor(
+ alias_visitor.aliases,
+ handler_nodes=handler_nodes,
+ )
+
+ def _binding_pass() -> None:
+ binding_visitor.visit(tree)
+
+ phase_ledger.run_subphase_us(
+ SUBPHASE_MODULE_PASSES_REACHABILITY_BINDING_US,
+ _binding_pass,
+ )
visitor = _RuntimeReachabilityVisitor(
module_name=module_name,
filepath=filepath,
@@ -1317,7 +1372,16 @@ def collect_runtime_reachability(
included_routers=binding_visitor.included_routers,
route_decorator_factories=binding_visitor.route_decorator_factories,
)
- visitor.visit(tree)
+ apply_handler_node = visitor._apply_handler_node
+
+ def _reachability_pass() -> None:
+ for node in handler_nodes:
+ apply_handler_node(node)
+
+ phase_ledger.run_subphase_us(
+ SUBPHASE_MODULE_PASSES_REACHABILITY_VISIT_US,
+ _reachability_pass,
+ )
return tuple(
sorted(
visitor.facts,
diff --git a/codeclone/analysis/units.py b/codeclone/analysis/units.py
index e6f2b791..0311baac 100644
--- a/codeclone/analysis/units.py
+++ b/codeclone/analysis/units.py
@@ -48,6 +48,8 @@
from .parser import PARSE_TIMEOUT_SECONDS, _parse_with_limits
from .phase_ledger import (
INERT_PHASE_LEDGER,
+ SUBPHASE_MODULE_PASSES_ADOPTION_US,
+ SUBPHASE_MODULE_PASSES_SECURITY_US,
AnalysisPhaseKey,
AnalysisVolumeKey,
PhaseLedger,
@@ -349,12 +351,15 @@ def extract_units_and_stats_from_source(
)
)
with phase_ledger.phase(AnalysisPhaseKey.MODULE_PASSES):
- typing_coverage, docstring_coverage = collect_module_adoption(
- tree=tree,
- module_name=module_name,
- filepath=filepath,
- collector=collector,
- imported_names=import_names,
+ typing_coverage, docstring_coverage = phase_ledger.run_subphase_us(
+ SUBPHASE_MODULE_PASSES_ADOPTION_US,
+ lambda: collect_module_adoption(
+ tree=tree,
+ module_name=module_name,
+ filepath=filepath,
+ collector=collector,
+ imported_names=import_names,
+ ),
)
api_surface = None
if collect_api_surface:
@@ -366,16 +371,20 @@ def extract_units_and_stats_from_source(
imported_names=import_names,
include_private_modules=api_include_private_modules,
)
- security_surfaces = collect_security_surfaces(
- tree=tree,
- module_name=module_name,
- filepath=filepath,
+ security_surfaces = phase_ledger.run_subphase_us(
+ SUBPHASE_MODULE_PASSES_SECURITY_US,
+ lambda: collect_security_surfaces(
+ tree=tree,
+ module_name=module_name,
+ filepath=filepath,
+ ),
)
runtime_reachability = collect_runtime_reachability(
tree=tree,
module_name=module_name,
filepath=filepath,
collector=collector,
+ phase_ledger=phase_ledger,
)
return (
diff --git a/codeclone/observability/analysis_phases.py b/codeclone/observability/analysis_phases.py
index 3732becf..f532844f 100644
--- a/codeclone/observability/analysis_phases.py
+++ b/codeclone/observability/analysis_phases.py
@@ -30,5 +30,8 @@ def apply_pipeline_process_phase_counters(
for key in PHASE_VOLUME_COUNTER_SUFFIXES:
span.set_counter(key, volumes.get(key, 0))
+ for key, value in phase_snapshot.subphase_us:
+ span.set_counter(key, value)
+
__all__ = ["apply_pipeline_process_phase_counters"]
diff --git a/codeclone/surfaces/mcp/_session_patch_contract_mixin.py b/codeclone/surfaces/mcp/_session_patch_contract_mixin.py
index 1cfc8d10..fb71bc45 100644
--- a/codeclone/surfaces/mcp/_session_patch_contract_mixin.py
+++ b/codeclone/surfaces/mcp/_session_patch_contract_mixin.py
@@ -720,8 +720,8 @@ def _full_structural_verify(
) -> dict[str, object]:
"""Full structural verification path (before + after runs)."""
compare_payload = _state_session(self).compare_runs(
- run_id_before=before.run_id,
- run_id_after=after.run_id,
+ before_run_id=before.run_id,
+ after_run_id=after.run_id,
focus="all",
)
if not bool(compare_payload.get("comparable")):
diff --git a/codeclone/surfaces/mcp/_session_review_receipt_mixin.py b/codeclone/surfaces/mcp/_session_review_receipt_mixin.py
index ab768d05..5ea248e3 100644
--- a/codeclone/surfaces/mcp/_session_review_receipt_mixin.py
+++ b/codeclone/surfaces/mcp/_session_review_receipt_mixin.py
@@ -413,8 +413,8 @@ def _receipt_structural_delta(
"verdict": "not_available",
}
compare_payload = _state_session(self).compare_runs(
- run_id_before=previous.run_id,
- run_id_after=record.run_id,
+ before_run_id=previous.run_id,
+ after_run_id=record.run_id,
focus="all",
)
return {
diff --git a/codeclone/surfaces/mcp/_session_state_mixin.py b/codeclone/surfaces/mcp/_session_state_mixin.py
index 89561889..343a01e9 100644
--- a/codeclone/surfaces/mcp/_session_state_mixin.py
+++ b/codeclone/surfaces/mcp/_session_state_mixin.py
@@ -829,8 +829,8 @@ def get_run_summary(self, run_id: str | None = None) -> dict[str, object]:
def compare_runs(
self,
*,
- run_id_before: str,
- run_id_after: str | None = None,
+ before_run_id: str,
+ after_run_id: str | None = None,
focus: ComparisonFocus = "all",
) -> dict[str, object]:
validated_focus = _helpers._validate_choice(
@@ -838,8 +838,8 @@ def compare_runs(
focus,
_VALID_COMPARISON_FOCUS,
)
- before = self._runs.get(run_id_before)
- after = self._runs.get(run_id_after)
+ before = self._runs.get(before_run_id)
+ after = self._runs.get(after_run_id)
before_findings = self._comparison_index(before, focus=validated_focus)
after_findings = self._comparison_index(after, focus=validated_focus)
before_ids = set(before_findings)
@@ -1294,8 +1294,8 @@ def generate_pr_summary(
resolved: list[dict[str, object]] = []
if previous is not None:
compare_payload = self.compare_runs(
- run_id_before=previous.run_id,
- run_id_after=record.run_id,
+ before_run_id=previous.run_id,
+ after_run_id=record.run_id,
focus="all",
)
resolved = _helpers._dict_rows(compare_payload.get("improvements"))
diff --git a/codeclone/surfaces/mcp/server.py b/codeclone/surfaces/mcp/server.py
index 8f8f0fe1..97ca282e 100644
--- a/codeclone/surfaces/mcp/server.py
+++ b/codeclone/surfaces/mcp/server.py
@@ -1144,13 +1144,13 @@ def list_hotspots(
structured_output=True,
)
def compare_runs(
- run_id_before: RunIdRequiredParam,
- run_id_after: RunIdParam = None,
+ before_run_id: RunIdRequiredParam,
+ after_run_id: RunIdParam = None,
focus: CompareFocusParam = "all",
) -> dict[str, object]:
return service.compare_runs(
- run_id_before=run_id_before,
- run_id_after=run_id_after,
+ before_run_id=before_run_id,
+ after_run_id=after_run_id,
focus=focus,
)
diff --git a/codeclone/surfaces/mcp/service.py b/codeclone/surfaces/mcp/service.py
index 24fde53d..6c81ef03 100644
--- a/codeclone/surfaces/mcp/service.py
+++ b/codeclone/surfaces/mcp/service.py
@@ -327,8 +327,8 @@ def _apply_public_method_signatures() -> None:
_kwonly("detail_level", "DetailLevel", "summary"),
),
"compare_runs": (
- _kwonly("run_id_before", "str"),
- _kwonly("run_id_after", "str | None", None),
+ _kwonly("before_run_id", "str"),
+ _kwonly("after_run_id", "str | None", None),
_kwonly("focus", "ComparisonFocus", "all"),
),
"generate_pr_summary": (
diff --git a/docs/README-pypi.md b/docs/README-pypi.md
new file mode 100644
index 00000000..41d75cfa
--- /dev/null
+++ b/docs/README-pypi.md
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+ Deterministic Structural Change Controller for AI-assisted Python development
+
+
+
+
+
+
+
+
+CodeClone helps developers use AI coding agents without losing control of structural change. Before an agent edits
+code, it records the intended change, maps the structural blast radius, and establishes explicit edit boundaries. After
+the edit, it compares the real patch with the declared scope, verifies structural regressions, and leaves an auditable
+review receipt.
+
+Every finding and every gate comes from deterministic repository facts — not an LLM opinion — shared across agents,
+human reviewers, IDEs, reports, and CI. CodeClone does not generate or rewrite source files.
+
+> **Note:** Features marked `2.1 alpha` require the
+> [CodeClone 2.1 prerelease](https://pypi.org/project/codeclone/#history). Everything else works with the current
+> stable release.
+
+## Quick start
+
+Requires Python 3.10 or newer.
+
+```bash
+uvx codeclone@latest . # analyze without installing
+uvx codeclone@latest . --html --open-html-report
+
+uv tool install codeclone # install as a local tool
+codeclone .
+```
+
+Record the accepted structural baseline once, then gate future changes against it in CI:
+
+```bash
+codeclone . --update-baseline
+codeclone . --ci
+```
+
+The baseline separates **new regressions** from findings that already existed, so CI fails only on what the current
+change introduced.
+
+## What it provides
+
+- **Structural Change Controller** — `2.1 alpha`: intent-first change control, blast radius, explicit edit boundaries,
+ patch verification, and review receipts.
+- **Baseline-aware governance** — records accepted legacy debt and separates it from regressions introduced by the
+ current change.
+- **One canonical report** — clones, complexity, coupling, cohesion, dead code, dependency cycles, a package/module
+ dependency map (Module Map), public API inventory, coverage joins, and a guided finding-review queue, rendered
+ through CLI, HTML, JSON, Markdown, SARIF, and CI from one payload.
+- **Engineering Memory** — `2.1 alpha`: local, typed, evidence-linked project knowledge and reusable histories of prior
+ controlled changes.
+- **Agent coordination** — `2.1 alpha`: conflict-safe multi-agent intents, queues, recovery, and workspace hygiene.
+
+CodeClone requires no hosted service or cloud account. Analysis state, controller state, Engineering Memory, and
+trajectories are stored locally.
+
+## MCP control surface and native clients
+
+```bash
+uv tool install --prerelease allow "codeclone[mcp]"
+codeclone-mcp --transport stdio
+```
+
+The MCP server is read-only by contract: it never mutates source files, baselines, cache, or repository state. The same
+canonical structural facts back every client — VS Code, Cursor, Claude Code, Codex, and Claude Desktop.
+
+## Links
+
+- Documentation:
+- Getting started:
+- Structural Change Controller:
+- Engineering Memory:
+- Configuration reference:
+- Source:
+- Issues:
+
+## License
+
+- Code: MPL-2.0
+- Documentation: MIT
+
+See [LICENSES.md](https://github.com/orenlab/codeclone/blob/main/LICENSES.md) for the license scope map.
diff --git a/extensions/claude-desktop-codeclone/README.md b/extensions/claude-desktop-codeclone/README.md
index b3f88418..5936b103 100644
--- a/extensions/claude-desktop-codeclone/README.md
+++ b/extensions/claude-desktop-codeclone/README.md
@@ -6,9 +6,9 @@ bundle wrapper for `codeclone-mcp`. Installs as a `.mcpb` package instead of man
Same canonical default agent MCP surface used by CLI, VS Code, Codex, and
Claude Code.
Repository read-only (source, baselines, cache, canonical reports); local stdio
-only. The bundle proxies the full MCP server, including change-control and
-session tools — ephemeral coordination under `.codeclone/intents/` and
-optional audit records when enabled.
+only. The bundle proxies the full MCP server, including change-control, Engineering
+Memory, implementation context, and session tools — ephemeral coordination
+under `.codeclone/intents/` and optional audit records when enabled.
As the local `codeclone-mcp` server gains new canonical surfaces, the bundle
exposes them without adding a second client-side interpretation layer.
@@ -109,7 +109,7 @@ npm run pack # build .mcpb
## Links
-- [Claude Desktop bundle guide](https://orenlab.github.io/codeclone/guide/integrations/claude-desktop/setup/)
-- [MCP usage guide](https://orenlab.github.io/codeclone/guide/mcp/)
-- [Change controller docs](https://orenlab.github.io/codeclone/book/12-structural-change-controller/)
+- [Claude Desktop bundle guide](https://orenlab.github.io/codeclone/integrations/claude/)
+- [MCP usage guide](https://orenlab.github.io/codeclone/concepts/mcp/)
+- [Change controller docs](https://orenlab.github.io/codeclone/concepts/controlled-change/)
- [Issues](https://github.com/orenlab/codeclone/issues)
diff --git a/extensions/claude-desktop-codeclone/manifest.json b/extensions/claude-desktop-codeclone/manifest.json
index 378c4cde..a4530e79 100644
--- a/extensions/claude-desktop-codeclone/manifest.json
+++ b/extensions/claude-desktop-codeclone/manifest.json
@@ -2,7 +2,7 @@
"manifest_version": "0.3",
"name": "codeclone",
"display_name": "CodeClone",
- "version": "2.1.0",
+ "version": "2.1.0a1",
"description": "Structural Change Controller for AI-assisted Python development — local MCP bundle for Claude Desktop.",
"long_description": "CodeClone for Claude Desktop wraps the local codeclone-mcp launcher as an MCP bundle. Structural change controller for AI-assisted Python development — same canonical default agent MCP surface used by the CLI, HTML report, VS Code extension, and Codex plugin. Repository read-only (source, baselines, cache, reports), baseline-aware, local stdio only. Includes intent declaration, blast radius, patch contract, review receipt, engineering memory, platform observability, and claim validation via validate_review_claims and finish_controlled_change. Ephemeral coordination may be stored under .codeclone/intents/ (file backend) or .codeclone/db/ (SQLite backend).",
"author": {
@@ -15,7 +15,7 @@
"url": "https://github.com/orenlab/codeclone.git"
},
"homepage": "https://github.com/orenlab/codeclone",
- "documentation": "https://orenlab.github.io/codeclone/guide/integrations/claude-desktop/setup/",
+ "documentation": "https://orenlab.github.io/codeclone/integrations/claude/",
"support": "https://github.com/orenlab/codeclone/issues",
"privacy_policies": [
"https://orenlab.github.io/codeclone/privacy-policy/"
diff --git a/extensions/claude-desktop-codeclone/package-lock.json b/extensions/claude-desktop-codeclone/package-lock.json
index 4056196f..eaac863f 100644
--- a/extensions/claude-desktop-codeclone/package-lock.json
+++ b/extensions/claude-desktop-codeclone/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@orenlab/codeclone-claude-desktop",
- "version": "2.0.0",
+ "version": "2.1.0a1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@orenlab/codeclone-claude-desktop",
- "version": "2.0.0",
+ "version": "2.1.0a1",
"license": "MPL-2.0",
"engines": {
"node": ">=20.0.0"
diff --git a/extensions/claude-desktop-codeclone/package.json b/extensions/claude-desktop-codeclone/package.json
index 1f7685c1..6f0b8fb1 100644
--- a/extensions/claude-desktop-codeclone/package.json
+++ b/extensions/claude-desktop-codeclone/package.json
@@ -1,6 +1,6 @@
{
"name": "@orenlab/codeclone-claude-desktop",
- "version": "2.1.0",
+ "version": "2.1.0a1",
"private": true,
"description": "Structural Change Controller for AI-assisted Python development — Claude Desktop MCP bundle.",
"license": "MPL-2.0",
diff --git a/extensions/claude-desktop-codeclone/test/manifest.test.js b/extensions/claude-desktop-codeclone/test/manifest.test.js
index 48438415..f7c3faba 100644
--- a/extensions/claude-desktop-codeclone/test/manifest.test.js
+++ b/extensions/claude-desktop-codeclone/test/manifest.test.js
@@ -39,7 +39,7 @@ test("manifest keeps the setup surface bounded and local", () => {
assert.deepEqual(manifest.privacy_policies, [
"https://orenlab.github.io/codeclone/privacy-policy/",
]);
- assert.equal(manifest.documentation, "https://orenlab.github.io/codeclone/guide/integrations/claude-desktop/setup/");
+ assert.equal(manifest.documentation, "https://orenlab.github.io/codeclone/integrations/claude/");
assert.equal(manifest.tools_generated, true);
// Derive the expected count from the canonical MCP contract snapshot so the
// bundle stays in lockstep with the server surface instead of drifting
diff --git a/extensions/vscode-codeclone/README.md b/extensions/vscode-codeclone/README.md
index 3298c961..7cddcf59 100644
--- a/extensions/vscode-codeclone/README.md
+++ b/extensions/vscode-codeclone/README.md
@@ -3,7 +3,7 @@
[](LICENSE)
[](https://orenlab.github.io/codeclone/)
-Native VS Code surface for [codeclone-mcp](https://orenlab.github.io/codeclone/guide/mcp/) —
+Native VS Code surface for [codeclone-mcp](https://orenlab.github.io/codeclone/concepts/mcp/) —
**Structural Change Controller for AI-assisted Python development**. Brings
baseline-aware structural analysis into the editor — triage-first, repository
read-only, and driven by the same canonical report as the CLI and HTML output. Session tools (`mark_finding_reviewed`, `clear_session_runs`) update
@@ -251,8 +251,8 @@ full analysis and MCP are disabled until workspace trust is granted.
## Documentation
- [CodeClone documentation](https://orenlab.github.io/codeclone/)
-- [MCP usage guide](https://orenlab.github.io/codeclone/guide/mcp/)
-- [MCP interface contract](https://orenlab.github.io/codeclone/book/25-mcp-interface/)
+- [MCP usage guide](https://orenlab.github.io/codeclone/concepts/mcp/)
+- [MCP interface contract](https://orenlab.github.io/codeclone/reference/mcp-tools/)
---
diff --git a/plugins/claude-code-codeclone/.claude-plugin/plugin.json b/plugins/claude-code-codeclone/.claude-plugin/plugin.json
index 69baf1b1..943f53f2 100644
--- a/plugins/claude-code-codeclone/.claude-plugin/plugin.json
+++ b/plugins/claude-code-codeclone/.claude-plugin/plugin.json
@@ -1,12 +1,13 @@
{
"name": "codeclone",
+ "version": "2.1.0a1",
"description": "Structural Change Controller for AI-assisted Python development over local codeclone-mcp.",
"author": {
"name": "Den Rozhnovskiy",
"email": "pytelemonbot@mail.ru",
"url": "https://github.com/orenlab"
},
- "homepage": "https://orenlab.github.io/codeclone/guide/integrations/claude-code/setup/",
+ "homepage": "https://orenlab.github.io/codeclone/integrations/claude/",
"repository": "https://github.com/orenlab/codeclone-claude-code",
"license": "MPL-2.0",
"keywords": [
diff --git a/plugins/claude-code-codeclone/README.md b/plugins/claude-code-codeclone/README.md
index 867b36a3..f8c6b7e8 100644
--- a/plugins/claude-code-codeclone/README.md
+++ b/plugins/claude-code-codeclone/README.md
@@ -76,6 +76,6 @@ claude plugin validate plugins/claude-code-codeclone
## Documentation
-- [Claude Code setup](https://orenlab.github.io/codeclone/guide/integrations/claude-code/setup/)
-- [MCP usage guide](https://orenlab.github.io/codeclone/guide/mcp/)
-- [Structural Change Controller](https://orenlab.github.io/codeclone/book/12-structural-change-controller/)
+- [Claude Code setup](https://orenlab.github.io/codeclone/integrations/claude/)
+- [MCP usage guide](https://orenlab.github.io/codeclone/concepts/mcp/)
+- [Structural Change Controller](https://orenlab.github.io/codeclone/concepts/controlled-change/)
diff --git a/plugins/codeclone/.codex-plugin/plugin.json b/plugins/codeclone/.codex-plugin/plugin.json
index cdcbf1fb..41a00ccb 100644
--- a/plugins/codeclone/.codex-plugin/plugin.json
+++ b/plugins/codeclone/.codex-plugin/plugin.json
@@ -7,7 +7,7 @@
"email": "pytelemonbot@mail.ru",
"url": "https://github.com/orenlab"
},
- "homepage": "https://orenlab.github.io/codeclone/guide/integrations/codex/setup/",
+ "homepage": "https://orenlab.github.io/codeclone/integrations/codex/",
"repository": "https://github.com/orenlab/codeclone",
"license": "MPL-2.0",
"keywords": [
@@ -33,7 +33,7 @@
"Skills",
"Read-only"
],
- "websiteURL": "https://orenlab.github.io/codeclone/guide/integrations/codex/setup/",
+ "websiteURL": "https://orenlab.github.io/codeclone/integrations/codex/",
"privacyPolicyURL": "https://orenlab.github.io/codeclone/privacy-policy/",
"termsOfServiceURL": "https://orenlab.github.io/codeclone/terms-of-use/",
"defaultPrompt": [
diff --git a/plugins/codeclone/README.md b/plugins/codeclone/README.md
index 29ffd3a3..e4bb2964 100644
--- a/plugins/codeclone/README.md
+++ b/plugins/codeclone/README.md
@@ -96,6 +96,9 @@ single-metric queries, pre-merge sanity checks, coverage/adoption/API snapshots.
**codeclone-production-triage** — production-first baseline snapshot: health,
counts, top production hotspots, regressions vs baseline, recommended next action.
+**codeclone-architecture-triage** — ranked demonstrated architecture problems
+from the Module Map plus targeted impact context; read-only.
+
**codeclone-blast-radius** — read-only blast-only inspection before editing
specific files; use `codeclone-implementation-context` for the bundled projection.
@@ -103,6 +106,10 @@ specific files; use `codeclone-implementation-context` for the bundled projectio
workspace intent check, blast radius, patch contract verification, claim guard,
and review receipt.
+**codeclone-implementation-context** — bounded structural, call-graph, contract,
+and change-control evidence from one stored run via `get_implementation_context`;
+use it before broad grep-style exploration.
+
**codeclone-engineering-memory** — ranked scope context before edits, FTS search,
optional semantic blend (`semantic=true` on `mode=search` when the server index
is built), draft candidates, and finish proposals. Human governance via supported
@@ -112,8 +119,11 @@ IDE Memory views or CLI `--i-know-what-im-doing`.
own runtime via `query_platform_observability` after explicit
`CODECLONE_OBSERVABILITY_ENABLED=1`. Not for end-user repository review.
+**codeclone-setup** — repository readiness through the terminal (`codeclone
+setup status | plan | apply | wizard`), not MCP.
+
## Links
-- [Codex plugin guide](https://orenlab.github.io/codeclone/guide/integrations/codex/setup/)
-- [MCP usage guide](https://orenlab.github.io/codeclone/guide/mcp/)
+- [Codex plugin guide](https://orenlab.github.io/codeclone/integrations/codex/)
+- [MCP usage guide](https://orenlab.github.io/codeclone/concepts/mcp/)
- [Privacy Policy](https://orenlab.github.io/codeclone/privacy-policy/)
diff --git a/plugins/cursor-codeclone/.cursor-plugin/plugin.json b/plugins/cursor-codeclone/.cursor-plugin/plugin.json
index 2b3d6bce..58d59dbc 100644
--- a/plugins/cursor-codeclone/.cursor-plugin/plugin.json
+++ b/plugins/cursor-codeclone/.cursor-plugin/plugin.json
@@ -1,7 +1,7 @@
{
"name": "codeclone",
"displayName": "CodeClone",
- "version": "0.1.0",
+ "version": "2.1.0a1",
"description": "Structural Change Controller for AI-assisted Python development. Deterministic structural review, baseline-aware CI gates, and explicit change boundaries for coding agents — powered by codeclone-mcp.",
"author": {
"name": "Den Rozhnovskiy",
diff --git a/plugins/cursor-codeclone/README.md b/plugins/cursor-codeclone/README.md
index 20250984..c3ebd5a9 100644
--- a/plugins/cursor-codeclone/README.md
+++ b/plugins/cursor-codeclone/README.md
@@ -188,5 +188,5 @@ ln -s /path/to/codeclone/plugins/cursor-codeclone ~/.cursor/plugins/local/codecl
## Documentation
- [CodeClone documentation](https://orenlab.github.io/codeclone/)
-- [MCP usage guide](https://orenlab.github.io/codeclone/guide/mcp/)
-- [MCP interface contract](https://orenlab.github.io/codeclone/book/25-mcp-interface/)
+- [MCP usage guide](https://orenlab.github.io/codeclone/concepts/mcp/)
+- [MCP interface contract](https://orenlab.github.io/codeclone/reference/mcp-tools/)
diff --git a/pyproject.toml b/pyproject.toml
index 27e42905..788e0139 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -106,10 +106,10 @@ dev = [
"pytest-cov>=7.1.0",
"build>=1.4.3",
"twine>=6.2.0",
- "mypy>=1.20.1",
+ "mypy>=2.1.0",
"ruff>=0.15.20",
"pre-commit>=4.5.1",
- "ty>=0.0.56",
+ "ty>=0.0.57",
"PyYAML>=6.0.2",
"jsonschema>=4.23.0",
"types-PyYAML>=6.0.12.20250915",
@@ -133,6 +133,7 @@ packages = [
"codeclone.analytics.export",
"codeclone.analytics.metrics",
"codeclone.analytics.profiles",
+ "codeclone.analytics.profiles.manifests",
"codeclone.analytics.report",
"codeclone.analytics.report.messages",
"codeclone.analytics.store",
@@ -190,7 +191,7 @@ packages = [
[tool.setuptools.package-data]
codeclone = ["py.typed"]
-"codeclone.analytics.profiles" = ["manifests/*.json"]
+"codeclone.analytics.profiles.manifests" = ["*.json"]
[tool.pytest.ini_options]
testpaths = ["tests"]
diff --git a/tests/fixtures/contract_snapshots/mcp_tool_schemas.json b/tests/fixtures/contract_snapshots/mcp_tool_schemas.json
index 3ab3f092..d217cf8d 100644
--- a/tests/fixtures/contract_snapshots/mcp_tool_schemas.json
+++ b/tests/fixtures/contract_snapshots/mcp_tool_schemas.json
@@ -1074,13 +1074,7 @@
{
"input_schema": {
"properties": {
- "focus": {
- "default": "all",
- "description": "all, clones, structural, or metrics comparison focus.",
- "title": "Focus",
- "type": "string"
- },
- "run_id_after": {
+ "after_run_id": {
"anyOf": [
{
"type": "string"
@@ -1091,16 +1085,22 @@
],
"default": null,
"description": "8-char or full run id; latest run when omitted.",
- "title": "Run Id After"
+ "title": "After Run Id"
},
- "run_id_before": {
+ "before_run_id": {
"description": "8-char or full run id from analyze response.",
- "title": "Run Id Before",
+ "title": "Before Run Id",
+ "type": "string"
+ },
+ "focus": {
+ "default": "all",
+ "description": "all, clones, structural, or metrics comparison focus.",
+ "title": "Focus",
"type": "string"
}
},
"required": [
- "run_id_before"
+ "before_run_id"
],
"title": "compare_runsArguments",
"type": "object"
diff --git a/tests/fixtures/contract_snapshots/public_api_surface.json b/tests/fixtures/contract_snapshots/public_api_surface.json
index 70057272..7fa8bbb5 100644
--- a/tests/fixtures/contract_snapshots/public_api_surface.json
+++ b/tests/fixtures/contract_snapshots/public_api_surface.json
@@ -45,7 +45,7 @@
},
{
"name": "compare_runs",
- "signature": "(self, *, run_id_before: 'str', run_id_after: 'str | None' = None, focus: 'ComparisonFocus' = 'all') -> 'dict[str, object]'"
+ "signature": "(self, *, before_run_id: 'str', after_run_id: 'str | None' = None, focus: 'ComparisonFocus' = 'all') -> 'dict[str, object]'"
},
{
"name": "create_review_receipt",
diff --git a/tests/plugin_test_helpers.py b/tests/plugin_test_helpers.py
index a33ac985..2dc23dad 100644
--- a/tests/plugin_test_helpers.py
+++ b/tests/plugin_test_helpers.py
@@ -34,6 +34,24 @@ def load_json(path: Path) -> object:
return json.loads(path.read_text(encoding="utf-8"))
+def codeclone_package_version(root: Path) -> str:
+ for line in (root / "pyproject.toml").read_text(encoding="utf-8").splitlines():
+ if line.startswith("version = "):
+ return line.split("=", 1)[1].strip().strip('"')
+ raise AssertionError("pyproject.toml version not found")
+
+
+def assert_plugin_manifest_version_license_homepage(
+ manifest: dict[str, object],
+ *,
+ package_version: str,
+ homepage: str,
+) -> None:
+ assert manifest["version"] == package_version
+ assert manifest["license"] == "MPL-2.0"
+ assert manifest["homepage"] == homepage
+
+
def parse_frontmatter(text: str) -> dict[str, str]:
match = re.match(r"^---\n(?P.*?)\n---\n", text, re.DOTALL)
assert match is not None
diff --git a/tests/test_analysis_phase_ledger.py b/tests/test_analysis_phase_ledger.py
index a03084ff..46e4a2ad 100644
--- a/tests/test_analysis_phase_ledger.py
+++ b/tests/test_analysis_phase_ledger.py
@@ -89,6 +89,48 @@ def test_phase_snapshot_merge_is_deterministic() -> None:
assert merged.volumes == (("files_timed", 2), ("units_seen", 4))
+def test_phase_ledger_records_subphase_us_only_when_active(
+ monkeypatch: pytest.MonkeyPatch,
+) -> None:
+ ticks = iter((1_000, 4_000))
+ monkeypatch.setattr(phase_mod, "perf_counter_ns", lambda: next(ticks))
+
+ inert = PhaseLedger(active=False)
+ assert inert.run_subphase_us("subphase_module_passes_adoption_us", lambda: 7) == 7
+ assert inert.snapshot().subphase_us == ()
+
+ ledger = PhaseLedger(active=True)
+ assert (
+ ledger.run_subphase_us(
+ "subphase_module_passes_adoption_us",
+ lambda: "ok",
+ )
+ == "ok"
+ )
+ assert ledger.snapshot().subphase_us == (("subphase_module_passes_adoption_us", 3),)
+
+
+def test_phase_snapshot_merge_merges_subphase_us() -> None:
+ left = PhaseSnapshot(
+ totals=PhaseTotals(),
+ volumes=(),
+ subphase_us=(("subphase_module_passes_adoption_us", 10),),
+ )
+ right = PhaseSnapshot(
+ totals=PhaseTotals(),
+ volumes=(),
+ subphase_us=(
+ ("subphase_module_passes_adoption_us", 5),
+ ("subphase_module_passes_security_us", 7),
+ ),
+ )
+ merged = left.merge(right)
+ assert merged.subphase_us == (
+ ("subphase_module_passes_adoption_us", 15),
+ ("subphase_module_passes_security_us", 7),
+ )
+
+
def test_phase_ledger_rejects_raw_string_keys() -> None:
ledger = PhaseLedger(active=True)
with pytest.raises(TypeError):
diff --git a/tests/test_claude_code_plugin.py b/tests/test_claude_code_plugin.py
index a8889645..83d07e08 100644
--- a/tests/test_claude_code_plugin.py
+++ b/tests/test_claude_code_plugin.py
@@ -13,8 +13,10 @@
from tests.plugin_test_helpers import (
CODEX_CLAUDE_SYNC_SKILL_NAMES,
assert_claude_code_plugin_readme_contract,
+ assert_plugin_manifest_version_license_homepage,
assert_plugin_skills_match_codex,
assert_repo_doc_paths_exist,
+ codeclone_package_version,
load_json,
repo_docs_source_available,
)
@@ -25,17 +27,17 @@ def test_claude_code_plugin_manifest_and_mcp_config() -> None:
plugin_root = root / "plugins" / "claude-code-codeclone"
manifest = load_json(plugin_root / ".claude-plugin" / "plugin.json")
mcp_config = load_json(plugin_root / ".mcp.json")
+ package_version = codeclone_package_version(root)
assert isinstance(manifest, dict)
assert isinstance(mcp_config, dict)
assert manifest["name"] == "codeclone"
- assert manifest["license"] == "MPL-2.0"
- assert (
- manifest["homepage"]
- == "https://orenlab.github.io/codeclone/guide/integrations/claude-code/setup/"
+ assert_plugin_manifest_version_license_homepage(
+ manifest,
+ package_version=package_version,
+ homepage="https://orenlab.github.io/codeclone/integrations/claude/",
)
assert manifest["repository"] == "https://github.com/orenlab/codeclone-claude-code"
- assert "version" not in manifest
server = mcp_config["mcpServers"]["codeclone"]
assert server == {
diff --git a/tests/test_codex_plugin.py b/tests/test_codex_plugin.py
index a8584001..0cb9d68e 100644
--- a/tests/test_codex_plugin.py
+++ b/tests/test_codex_plugin.py
@@ -13,36 +13,30 @@
from tests.plugin_test_helpers import (
assert_codex_manifest_interface,
assert_codex_plugin_readme_contract,
+ assert_plugin_manifest_version_license_homepage,
assert_repo_doc_paths_exist,
+ codeclone_package_version,
load_json,
repo_docs_source_available,
)
-def _codeclone_package_version(root: Path) -> str:
- for line in (root / "pyproject.toml").read_text(encoding="utf-8").splitlines():
- if line.startswith("version = "):
- return line.split("=", 1)[1].strip().strip('"')
- raise AssertionError("pyproject.toml version not found")
-
-
def test_codex_plugin_manifest_is_consistent() -> None:
root = Path(__file__).resolve().parents[1]
plugin_root = root / "plugins" / "codeclone"
manifest = load_json(plugin_root / ".codex-plugin" / "plugin.json")
marketplace = load_json(root / ".agents" / "plugins" / "marketplace.json")
- package_version = _codeclone_package_version(root)
+ package_version = codeclone_package_version(root)
assert isinstance(manifest, dict)
assert manifest["name"] == plugin_root.name
assert manifest["name"] == "codeclone"
- assert manifest["version"] == package_version
assert manifest["skills"] == "./skills/"
assert manifest["mcpServers"] == "./.mcp.json"
- assert manifest["license"] == "MPL-2.0"
- assert (
- manifest["homepage"]
- == "https://orenlab.github.io/codeclone/guide/integrations/codex/setup/"
+ assert_plugin_manifest_version_license_homepage(
+ manifest,
+ package_version=package_version,
+ homepage="https://orenlab.github.io/codeclone/integrations/codex/",
)
assert isinstance(marketplace, dict)
assert marketplace["plugins"][0]["name"] == manifest["name"]
diff --git a/tests/test_cursor_plugin.py b/tests/test_cursor_plugin.py
index 78f9af32..be3b8d72 100644
--- a/tests/test_cursor_plugin.py
+++ b/tests/test_cursor_plugin.py
@@ -5,7 +5,6 @@
# Copyright (c) 2026 Den Rozhnovskiy
from __future__ import annotations
-import re
from pathlib import Path
from tests.plugin_test_helpers import (
@@ -25,7 +24,7 @@ def test_cursor_plugin_json_is_valid() -> None:
assert isinstance(manifest, dict)
assert manifest["name"] == "codeclone"
- assert manifest["version"] == "0.1.0"
+ assert manifest["version"] == "2.1.0a1"
assert manifest["license"] == "MPL-2.0"
assert manifest["rules"] == "rules/"
assert manifest["skills"] == "skills/"
@@ -77,20 +76,6 @@ def test_cursor_skills_match_codex_skills() -> None:
)
-def test_cursor_plugin_version_is_semver() -> None:
- """Plugin has its own version lifecycle, independent of pyproject."""
- root = Path(__file__).resolve().parents[1]
- manifest = load_json(
- root / "plugins" / "cursor-codeclone" / ".cursor-plugin" / "plugin.json"
- )
- assert isinstance(manifest, dict)
- version = manifest["version"]
- assert isinstance(version, str)
- assert re.fullmatch(r"\d+\.\d+\.\d+", version), (
- f"Plugin version must be semver (X.Y.Z), got: {version}"
- )
-
-
def test_cursor_readme_uses_marketplace_install_flow() -> None:
root = Path(__file__).resolve().parents[1]
readme = (root / "plugins" / "cursor-codeclone" / "README.md").read_text(
diff --git a/tests/test_extractor.py b/tests/test_extractor.py
index 36604775..b8fa797b 100644
--- a/tests/test_extractor.py
+++ b/tests/test_extractor.py
@@ -2566,7 +2566,7 @@ class Inner:
inner = outer.body[1]
assert isinstance(inner, ast.FunctionDef)
- bindings = module_walk_mod._caller_local_bindings(inner)
+ bindings, _scope_nodes = module_walk_mod._walk_relationship_function_scope(inner)
assert {
"posonly",
diff --git a/tests/test_mcp_server.py b/tests/test_mcp_server.py
index e2b05a57..abba7cc6 100644
--- a/tests/test_mcp_server.py
+++ b/tests/test_mcp_server.py
@@ -699,8 +699,8 @@ def test_mcp_server_tool_roundtrip_and_resources(tmp_path: Path) -> None:
server.call_tool(
"compare_runs",
{
- "run_id_before": run_id,
- "run_id_after": changed_run_id,
+ "before_run_id": run_id,
+ "after_run_id": changed_run_id,
"focus": "all",
},
)
diff --git a/tests/test_mcp_service.py b/tests/test_mcp_service.py
index 533fef4f..7080c8fa 100644
--- a/tests/test_mcp_service.py
+++ b/tests/test_mcp_service.py
@@ -3423,8 +3423,8 @@ def test_mcp_service_changed_runs_remediation_and_review_flow(tmp_path: Path) ->
assert cast(int, changed["total"]) >= 1
comparison = service.compare_runs(
- run_id_before=str(before["run_id"]),
- run_id_after=str(after["run_id"]),
+ before_run_id=str(before["run_id"]),
+ after_run_id=str(after["run_id"]),
focus="clones",
)
_assert_comparable_comparison(comparison, verdict="regressed")
@@ -6952,8 +6952,8 @@ def test_mcp_patch_contract_verify_incomparable_and_expired_edges(
def incomparable_compare(
*,
- run_id_before: str,
- run_id_after: str | None = None,
+ before_run_id: str,
+ after_run_id: str | None = None,
focus: str = "all",
) -> dict[str, object]:
return {
@@ -6961,7 +6961,7 @@ def incomparable_compare(
"regressions": [],
"improvements": [],
"health_delta": None,
- "verdict": f"{run_id_before}:{run_id_after}:{focus}",
+ "verdict": f"{before_run_id}:{after_run_id}:{focus}",
}
monkeypatch.setattr(service, "compare_runs", incomparable_compare)
@@ -8325,8 +8325,8 @@ def test_mcp_service_remediation_and_comparison_helper_branches(
before_record = service._runs.get(str(before["run_id"]))
comparison = service.compare_runs(
- run_id_before=str(before["run_id"]),
- run_id_after=str(after["run_id"]),
+ before_run_id=str(before["run_id"]),
+ after_run_id=str(after["run_id"]),
focus="clones",
)
_assert_comparable_comparison(comparison, verdict="improved")
@@ -8482,8 +8482,8 @@ def test_mcp_service_compare_runs_marks_different_roots_incomparable(
after_record = service._runs.get(str(after["run_id"]))
comparison = service.compare_runs(
- run_id_before=str(before["run_id"]),
- run_id_after=str(after["run_id"]),
+ before_run_id=str(before["run_id"]),
+ after_run_id=str(after["run_id"]),
focus="all",
)
@@ -8587,8 +8587,8 @@ def test_mcp_service_compare_runs_marks_different_settings_incomparable(
)
comparison = service.compare_runs(
- run_id_before=str(before["run_id"]),
- run_id_after=str(after["run_id"]),
+ before_run_id=str(before["run_id"]),
+ after_run_id=str(after["run_id"]),
focus="all",
)
diff --git a/tests/test_observability_analysis_phases.py b/tests/test_observability_analysis_phases.py
index bc325c1b..1c7269be 100644
--- a/tests/test_observability_analysis_phases.py
+++ b/tests/test_observability_analysis_phases.py
@@ -65,7 +65,7 @@ def test_apply_pipeline_process_phase_counters_closed_key_set() -> None:
apply_pipeline_process_phase_counters(span, phase_snapshot=snapshot) # type: ignore[arg-type]
- assert frozenset(span.counters) == frozenset(
+ assert frozenset(span.counters) >= frozenset(
(*PHASE_US_COUNTER_SUFFIXES, *PHASE_VOLUME_COUNTER_SUFFIXES)
)
assert span.counters["phase_parse_us"] == 1500
@@ -75,6 +75,23 @@ def test_apply_pipeline_process_phase_counters_closed_key_set() -> None:
assert span.counters["blocks_emitted"] == 0
+def test_apply_pipeline_process_phase_counters_emits_subphase_us() -> None:
+ snapshot = PhaseSnapshot(
+ totals=PhaseTotals(),
+ volumes=(),
+ subphase_us=(
+ ("subphase_module_passes_adoption_us", 11),
+ ("subphase_module_passes_security_us", 22),
+ ),
+ )
+ span = _FakeSpan()
+
+ apply_pipeline_process_phase_counters(span, phase_snapshot=snapshot) # type: ignore[arg-type]
+
+ assert span.counters["subphase_module_passes_adoption_us"] == 11
+ assert span.counters["subphase_module_passes_security_us"] == 22
+
+
def test_extract_units_records_phase_snapshot_data() -> None:
ledger = PhaseLedger(active=True)
source = """
diff --git a/tests/test_packaging.py b/tests/test_packaging.py
index 2324e15d..4e319d78 100644
--- a/tests/test_packaging.py
+++ b/tests/test_packaging.py
@@ -12,12 +12,46 @@
from codeclone.config.pyproject_loader import _load_toml
+def _package_name(repo_root: Path, package_dir: Path) -> str:
+ return ".".join(package_dir.relative_to(repo_root).parts)
+
+
+def _is_data_only_namespace_package(package_dir: Path) -> bool:
+ """True for PEP 420 data dirs (no ``__init__.py``, non-Python payload files).
+
+ Setuptools treats such directories as importable packages and requires them in
+ ``[tool.setuptools].packages`` when using an explicit package list.
+ """
+
+ if not package_dir.is_dir() or (package_dir / "__init__.py").exists():
+ return False
+ if package_dir.name.startswith(".") or package_dir.name == "__pycache__":
+ return False
+ return any(
+ child.is_file() and not child.name.startswith(".") and child.suffix != ".py"
+ for child in package_dir.iterdir()
+ )
+
+
def _discover_codeclone_packages(repo_root: Path) -> set[str]:
+ """Discover regular packages plus nested data-only namespace dirs from the tree.
+
+ Discovery is filesystem-based so missing ``pyproject.toml`` entries fail the
+ test; do not derive expected packages from package-data alone.
+ """
+
codeclone_root = repo_root / "codeclone"
packages: set[str] = set()
+ regular_package_dirs: list[Path] = []
for init_path in codeclone_root.rglob("__init__.py"):
- relative = init_path.parent.relative_to(repo_root)
- packages.add(".".join(relative.parts))
+ package_dir = init_path.parent
+ packages.add(_package_name(repo_root, package_dir))
+ regular_package_dirs.append(package_dir)
+ # Data-only namespace packages live as children of a regular package.
+ for package_dir in regular_package_dirs:
+ for child in package_dir.iterdir():
+ if _is_data_only_namespace_package(child):
+ packages.add(_package_name(repo_root, child))
return packages
diff --git a/uv.lock b/uv.lock
index de410eaf..41439fc2 100644
--- a/uv.lock
+++ b/uv.lock
@@ -94,7 +94,7 @@ wheels = [
[[package]]
name = "build"
-version = "1.5.0"
+version = "1.5.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "os_name == 'nt'" },
@@ -103,9 +103,9 @@ dependencies = [
{ name = "pyproject-hooks" },
{ name = "tomli", marker = "python_full_version < '3.11'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/78/e0/df5e171f685f82f37b12e1f208064e24244911079d7b767447d1af7e0d70/build-1.5.0.tar.gz", hash = "sha256:302c22c3ba2a0fd5f3911918651341ebb3896176cbdec15bd421f80b1afc7647", size = 89796, upload-time = "2026-04-30T03:18:25.17Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/2d/21/6ec54248b4d0d51f12f3ca4aa77a128077d747a5db86cb5a2fcd9aedecbd/build-1.5.1.tar.gz", hash = "sha256:94e17f1db803ab22f46049376c44c8437c52090f0dfdf1adc43df56542d644fb", size = 112439, upload-time = "2026-07-09T06:21:59.632Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/0d/fe/6bea5c9162869c5beba5d9c8abbed835ec85bf1ec1fba05a3822325c45f3/build-1.5.0-py3-none-any.whl", hash = "sha256:13f3eecb844759ab66efec90ca17639bbf14dc06cb2fdf37a9010322d9c50a6f", size = 26018, upload-time = "2026-04-30T03:18:23.644Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/f7/2c3f99ff9282f1c1ec9f6298f2c03034658a0901eeacb3b3501cb488574c/build-1.5.1-py3-none-any.whl", hash = "sha256:f1a58fe2e5af5b0238a07b9e70207492c79ddebbdb1ad954fc86d62a56be3e0d", size = 31195, upload-time = "2026-07-09T06:21:58.551Z" },
]
[[package]]
@@ -414,7 +414,7 @@ requires-dist = [
{ name = "lancedb", marker = "extra == 'semantic-local'", specifier = ">=0.33.0" },
{ name = "llvmlite", marker = "python_full_version < '3.14' and extra == 'analytics'", specifier = ">=0.44.0,<0.48" },
{ name = "mcp", marker = "extra == 'mcp'", specifier = ">=1.28.1,<2" },
- { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.20.1" },
+ { name = "mypy", marker = "extra == 'dev'", specifier = ">=2.1.0" },
{ name = "numba", marker = "python_full_version < '3.14' and extra == 'analytics'", specifier = ">=0.61.0,<0.66" },
{ name = "orjson", specifier = ">=3.11.9" },
{ name = "packaging", specifier = ">=24.0" },
@@ -433,7 +433,7 @@ requires-dist = [
{ name = "tomli", marker = "python_full_version < '3.11'", specifier = ">=2.0.1" },
{ name = "tomlkit", specifier = ">=0.13.2" },
{ name = "twine", marker = "extra == 'dev'", specifier = ">=6.2.0" },
- { name = "ty", marker = "extra == 'dev'", specifier = ">=0.0.56" },
+ { name = "ty", marker = "extra == 'dev'", specifier = ">=0.0.57" },
{ name = "types-jsonschema", marker = "extra == 'dev'", specifier = ">=4.23.0.20250516" },
{ name = "types-pyyaml", marker = "extra == 'dev'", specifier = ">=6.0.12.20250915" },
{ name = "umap-learn", marker = "python_full_version < '3.14' and extra == 'analytics'", specifier = ">=0.5.6" },
@@ -697,11 +697,11 @@ wheels = [
[[package]]
name = "filelock"
-version = "3.29.6"
+version = "3.29.7"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/e0/c8/35bdf04fb30755e2ed758f877edf3eb4a243c2463d3a258cc28b18b7a6e2/filelock-3.29.6.tar.gz", hash = "sha256:895c532ef3f4ef04972b9446a8c4e2931a5c399ff3c4be4c9369f2639b80f793", size = 70301, upload-time = "2026-07-06T23:08:08.577Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/35/94/00f2059e4835eace3ae8fde680b932c496f8ec7bdc99168dfa53fb2e6b79/filelock-3.29.7.tar.gz", hash = "sha256:5b481979797ae69e72f0b389d89a80bdd585c260c5b3f1fb9c0a5ba9bb3f195d", size = 71521, upload-time = "2026-07-08T05:46:58.716Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/bb/49/7467c2946ccd9617f7da38187071bdc45bb9a95df51f4d63d6622432ce4e/filelock-3.29.6-py3-none-any.whl", hash = "sha256:14d5f5597d2e0c4dbd774cfb6d8132da1db44da83732aab679d54f7dcf97ab65", size = 45478, upload-time = "2026-07-06T23:08:07.197Z" },
+ { url = "https://files.pythonhosted.org/packages/60/02/be4a57b60c7149b55b9e3b3c13f609cd8eb5307c751f22bd8fb8d262e75b/filelock-3.29.7-py3-none-any.whl", hash = "sha256:987db6f789a3a2a59f55081801b2b3697cb97e2a736b5f1a9e99b559285fbc51", size = 46036, upload-time = "2026-07-08T05:46:57.53Z" },
]
[[package]]
@@ -1067,89 +1067,89 @@ wheels = [
[[package]]
name = "librt"
-version = "0.12.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/c6/e0/dbd0f2a68a1c1a1991eb7921ff6014465d56608cdc9a9fb468a616210a37/librt-0.12.0.tar.gz", hash = "sha256:cb26faedbd09c6130e9c1b64d8000efec5076ffd18d606c6cd1cf02730e6d8b0", size = 203841, upload-time = "2026-06-30T16:14:29.671Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/e1/66/c9d88366893b4b0df6b5375c27ebc9f14c43419d9e244b493be20e85bc74/librt-0.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fe3547407bbce45c09885591f90168325c5a31a6795b9a13f6b9ff3d25093d93", size = 144398, upload-time = "2026-06-30T16:12:03.947Z" },
- { url = "https://files.pythonhosted.org/packages/bd/f2/9be1c6da204701163ec3aaedbf893d2f656b363d8fa302af536ce6471eb4/librt-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5925eca673207204a3adca040a91bdd3738fc7ba48da647ccd55732692a35736", size = 148924, upload-time = "2026-06-30T16:12:05.583Z" },
- { url = "https://files.pythonhosted.org/packages/d8/f3/256824ee27649c6e0a693db25d391f97b43b52364f8efb466014a564bbc7/librt-0.12.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f9ef097a7711465a204454c69658bbb6b2a6be9bdef0eeeba9a042016d00688", size = 479654, upload-time = "2026-06-30T16:12:07.175Z" },
- { url = "https://files.pythonhosted.org/packages/a8/3f/f4adbb3f293a04bd3dc2eb91d814f5b1e221e6b4522585696ba6901a0b9a/librt-0.12.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:57abc8b65edf1a8e80e5472c81c108a7527202e5febfda9e00a684dbaeae534e", size = 472318, upload-time = "2026-06-30T16:12:08.758Z" },
- { url = "https://files.pythonhosted.org/packages/9d/b5/362c93f7b43d4ef84a3d5f156c8d4eeddb22badcf5529a1281c387abbbd7/librt-0.12.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51e6f53732a8ae5012a3b6ae092da2933be74ec4169d16038f4af87a0019afea", size = 501555, upload-time = "2026-06-30T16:12:10.623Z" },
- { url = "https://files.pythonhosted.org/packages/24/1d/2d6abf059c3a4b88a6668e7bb81af332b14463028ac8f2b08a1212eb1ebc/librt-0.12.0-cp310-cp310-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:edb5f06cdb38d6ef9fd7ae06d62962d65c881b5f965d5e8a6c53e59c15ae4338", size = 494118, upload-time = "2026-06-30T16:12:12.503Z" },
- { url = "https://files.pythonhosted.org/packages/39/c1/f91f3094be2c76361d88aca613d8b7586d15b6026714d59d2e3dc0e35f44/librt-0.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1473ef42263dfee7553a5c460f11730a4409acf0d52629b284eb1e6b13eb460a", size = 516318, upload-time = "2026-06-30T16:12:14.192Z" },
- { url = "https://files.pythonhosted.org/packages/8e/e2/5211af94252458cbed7a6250163dff9c5a84aec29609121c828375a3b319/librt-0.12.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1d6f69a06295fb6ad8dcf92b4b2d15d211842005e86eedce64d88e0633592f58", size = 522294, upload-time = "2026-06-30T16:12:15.879Z" },
- { url = "https://files.pythonhosted.org/packages/90/9b/de31f5b9fdf7fa3699c4bbbecf82ebd52013d5d6b500b70b07b0ebacbd51/librt-0.12.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:3275d0270cd07ca9c2e140ae4da34e24a0350e98c6e3815dce96ead67cf0487d", size = 502494, upload-time = "2026-06-30T16:12:17.394Z" },
- { url = "https://files.pythonhosted.org/packages/b1/48/22c18dff89f3900dddb3e470e6f7febcda37ff3667b73097a848c9a608b2/librt-0.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a4834462ec68613024d063c7efe9b188e350d40fda9ba937372039883d2a8051", size = 543422, upload-time = "2026-06-30T16:12:19.006Z" },
- { url = "https://files.pythonhosted.org/packages/52/7b/74691b4b55944227245fffef063714e3ab9707ab1111eb0068512b428c7c/librt-0.12.0-cp310-cp310-win32.whl", hash = "sha256:bcf9b55ac089e8cf201d2146833e1097812c15dcea61911e84d6a2904cf78893", size = 97642, upload-time = "2026-06-30T16:12:20.386Z" },
- { url = "https://files.pythonhosted.org/packages/c5/dc/7f8fa369a1f7cc9b090fecd373659ada0e9bab1ae4a3ac9f163eabd04977/librt-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0a122002f7e0d5c93e84465c4b3fe86621402b7b92f1e2bc0784ebe67793112", size = 117583, upload-time = "2026-06-30T16:12:21.829Z" },
- { url = "https://files.pythonhosted.org/packages/9e/ab/628490f42d1eba82f3c7e5821aa62013e6df7f525b7a9e92c048f8d1cc1c/librt-0.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3f13c1e8563102c2b17581cf37fcb2c6dae7ad485ccea93ae46258998c25f9a1", size = 143821, upload-time = "2026-06-30T16:12:23.248Z" },
- { url = "https://files.pythonhosted.org/packages/38/5f/793e8b6f4b6ac16e7d7198478c0af3670606fbb535c768d5f3e954781423/librt-0.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d1ddff067610a122387024c4df527493b909d41e54a6e5b2d0e6c1041d6dfa09", size = 148442, upload-time = "2026-06-30T16:12:24.582Z" },
- { url = "https://files.pythonhosted.org/packages/ad/92/c780fe37a9e0982f3bd8fd9a631d6b95d09a5a7201c6c50366ce843b7e42/librt-0.12.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8dc7ebb5f3eec062398e9d0ef1938acd21b589e74286c4a8906d0183318d91b", size = 478276, upload-time = "2026-06-30T16:12:26.101Z" },
- { url = "https://files.pythonhosted.org/packages/41/bb/226d444bc20d7dff4a19ec6c1ff2c13a76385eebddb59c9c00c923b67536/librt-0.12.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:198de569ea9d5f6f33808f1c00cc3db9de62bf4d6deafa3b052bd08255083038", size = 472337, upload-time = "2026-06-30T16:12:27.83Z" },
- { url = "https://files.pythonhosted.org/packages/12/79/98ac0840ee90a75d4e1155c79062860b12ccca508587ff2119fc086965f2/librt-0.12.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e958678a8bca56016aedc891b391c0e0813ea382a874b54a2c1b313c1d232720", size = 502087, upload-time = "2026-06-30T16:12:29.443Z" },
- { url = "https://files.pythonhosted.org/packages/6f/72/a6b1a0d080606a7f5f646b79a1496f21d709f8563877759ace9ce5adad73/librt-0.12.0-cp311-cp311-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:575a6eca68c8437ed4a8e0f534e31d74b562ba1049a0ee4b5f09e114bcc21be1", size = 493202, upload-time = "2026-06-30T16:12:31.077Z" },
- { url = "https://files.pythonhosted.org/packages/69/cf/e1b036b45f2fc272205ee18bf272b47e8d684bf1a75af26db440c7504359/librt-0.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:86f241c50dc9e9a3f0db6dbb37a607c8205aa87b920802dabbd50b70d40f6939", size = 514139, upload-time = "2026-06-30T16:12:33.032Z" },
- { url = "https://files.pythonhosted.org/packages/40/34/b193b3e6985469a2f8afa86c90012329c86480b6ff4f2e4bd7b5b937e134/librt-0.12.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:113417b934fbf38220a9c7fe94578cefbe7dbb047adcb75aa197905af2b13724", size = 519486, upload-time = "2026-06-30T16:12:34.996Z" },
- { url = "https://files.pythonhosted.org/packages/31/9e/7de4947b1695f247c813f833e3c1e7b77b52e52a7dba2c35411cf806b58e/librt-0.12.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:762f17c0eb6b5d74e269126996cea8a89e35ab6464c5151619163abcd8623ae2", size = 499609, upload-time = "2026-06-30T16:12:36.663Z" },
- { url = "https://files.pythonhosted.org/packages/59/11/f3730e04e758b1fbf215359062ad2d5b6bd0b0ab5ac46b1c140628795be7/librt-0.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6aa93b3bd7f7588c628f6e9bf66485d3467fd9a1ccdb8975b770178f39f35697", size = 542205, upload-time = "2026-06-30T16:12:38.56Z" },
- { url = "https://files.pythonhosted.org/packages/1f/8f/710453617eabe20e18433864f335534c8aff63fbc68d8cd9dbc70a3d08f6/librt-0.12.0-cp311-cp311-win32.whl", hash = "sha256:aaa04b44d4fe86d824616b1f9c13e34c7c01ec0c96dd2abc4f59423696f788e2", size = 98067, upload-time = "2026-06-30T16:12:40.102Z" },
- { url = "https://files.pythonhosted.org/packages/42/53/401bff50a56e95daf151d911c99adf5732af2190e8f4d11886c9a229103c/librt-0.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:9aaeeddb8e7e4ae3bb9f944e0e618418cb91c0071d5ddbfcc3584b3cf59d39f0", size = 118346, upload-time = "2026-06-30T16:12:41.388Z" },
- { url = "https://files.pythonhosted.org/packages/e5/9a/a3a9078fe88bfc2d2d99dcf1c18593938ae830089cf84c3b2532a6c49d63/librt-0.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:18a2402fa3123ab76ecca670e6fb33038fde7c1e91181b885226ec4d30af2c2c", size = 104760, upload-time = "2026-06-30T16:12:43.112Z" },
- { url = "https://files.pythonhosted.org/packages/d5/1a/5bec493821b0e85b91de4f234912b50133d1aedb875048eef27938ec3f96/librt-0.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9bce19aa7c05f91c989f9da7b567f81d21d57a2e6501e2b811aa0f3f79614c1a", size = 146756, upload-time = "2026-06-30T16:12:44.395Z" },
- { url = "https://files.pythonhosted.org/packages/b9/d0/cc04b48a57c1f275387f5578847214c4a6c21bfb24c6c8c8d6ba753fe403/librt-0.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0ace09f5bf4d982fe726015f102fb856658b41580597104e301e630ed1d8d86", size = 145537, upload-time = "2026-06-30T16:12:45.95Z" },
- { url = "https://files.pythonhosted.org/packages/9e/10/c02325556beb2aa158c9e549ddade8cc9a23b36cdad14756dbed730c1ff1/librt-0.12.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d007efe9243ede81ce75990ad7aa172da1e2024144b3eff17ba46a5fff1fff3c", size = 488637, upload-time = "2026-06-30T16:12:47.658Z" },
- { url = "https://files.pythonhosted.org/packages/cb/9e/7b49ca1c30baa9c8df96024aa09a97c35a97455e36004c9b5311703c56f3/librt-0.12.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:ad324a5e4858388a4864915b90a42efc8b374376393f14b9940f2454e791912b", size = 483651, upload-time = "2026-06-30T16:12:49.283Z" },
- { url = "https://files.pythonhosted.org/packages/4d/71/03c8c8cec39645fda451132ff9d6d662fc5aea42a1a188a77a4fddb35906/librt-0.12.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10a40cf74cdd97b6f8f905056db73f5d459783de2ca04c6ebd1bf47652818e7e", size = 518359, upload-time = "2026-06-30T16:12:50.999Z" },
- { url = "https://files.pythonhosted.org/packages/e0/ec/a9f357f94bbcba92277d22af22cff42ef706ae5d9d6d58b69bebf3a67954/librt-0.12.0-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:92e61c09de95217ae02a9d17f4f66cf073253cdc51bcfdc0f15c62c9a70baa85", size = 509510, upload-time = "2026-06-30T16:12:52.631Z" },
- { url = "https://files.pythonhosted.org/packages/7a/34/717055325d028743aa01a7691ad59a63352a26a8ff2e7eeb0c9249514150/librt-0.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0461344061d6fc3718940f5855d95647831cef6d03a6c7506897f98222784ad4", size = 527302, upload-time = "2026-06-30T16:12:54.244Z" },
- { url = "https://files.pythonhosted.org/packages/95/f8/7612eeedb3395d92f7c6a84dca5f15e282d650483a4dc01aa5b9cffdfda3/librt-0.12.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e6dfe89074732c9287b3c0f5a6af575c9ede380a788013876cc7b14fe0da0361", size = 532568, upload-time = "2026-06-30T16:12:55.74Z" },
- { url = "https://files.pythonhosted.org/packages/79/1e/a9afe85d5bb8b65dc27be3809ed1d69082079e1e9717fd2c66aa9939600c/librt-0.12.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:9efed79d51ad1383bba0855f613cca7aa91c943e709af2413ac7f4bb9936ce08", size = 521579, upload-time = "2026-06-30T16:12:57.884Z" },
- { url = "https://files.pythonhosted.org/packages/b3/1e/93aebb219d52c37ea578f83b0588cd7b040974e464d4e435086a48b4dc4d/librt-0.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1eac6cc0e23e448fb3c1446ed85ff796afb616eed5897c978d35dbec030b7c7c", size = 558743, upload-time = "2026-06-30T16:12:59.577Z" },
- { url = "https://files.pythonhosted.org/packages/3c/85/1680c0ec332f238e3145c5608d313ab0a43281e210a5dd87e3bc3cc25631/librt-0.12.0-cp312-cp312-win32.whl", hash = "sha256:0ab8ee0210047ae86ca023ccfbfe3df82077fd1c9bc021aebbf37d993ef64af0", size = 99200, upload-time = "2026-06-30T16:13:01.015Z" },
- { url = "https://files.pythonhosted.org/packages/30/0e/abca12d8904875aa2ad66327390a3f7b1b75ebc43c0a00fc763cecf32ea5/librt-0.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:51c8bfa12632c81b94401c101bcedd0c56c3a1f8fa3273ca3472b28cd2f54003", size = 119390, upload-time = "2026-06-30T16:13:02.493Z" },
- { url = "https://files.pythonhosted.org/packages/32/a5/4203481b6d3a3bb348c82ac71abf1fcb4cb3ae8422a24a8dee4cd3ac5bd7/librt-0.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:5eebd451f5def089369ba6d8ff0291303d035e8154f9f26f7633835c5b029ade", size = 105117, upload-time = "2026-06-30T16:13:03.952Z" },
- { url = "https://files.pythonhosted.org/packages/f2/87/568d948c8079c9ff3c9e8110cf85f1eb70218e1209af29d0b7b89aa4a60c/librt-0.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8d9a55760a34ae5ce70434aabb6a6c61c6c44a0ec58ca1cfd9cd86e4745d417d", size = 146808, upload-time = "2026-06-30T16:13:05.417Z" },
- { url = "https://files.pythonhosted.org/packages/e7/1d/bea471ecea210088847bb5f3c4b4b424d596518934c06679b78ca85d6e63/librt-0.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ff0b197e338b4cf432873e0d6ef025213fdea85311ec4d87d2ea88c28adf2409", size = 145503, upload-time = "2026-06-30T16:13:07.023Z" },
- { url = "https://files.pythonhosted.org/packages/eb/9e/984ad422b56de95fdce158f06b051655373784ebea0aba9a7fcbc41614d1/librt-0.12.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7e69f120a20b69e2539d603bbd4d62db38399b10f8bf73a1cf445038a621e8af", size = 488421, upload-time = "2026-06-30T16:13:08.492Z" },
- { url = "https://files.pythonhosted.org/packages/50/03/1a2f94009b07ea71f8e1a4cfe53370565b56da9caa341b89e0699325e9f5/librt-0.12.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:fde3cde595e947fc8e755b0a21f919a1622483d07c662d00496e040773d22591", size = 483488, upload-time = "2026-06-30T16:13:10.169Z" },
- { url = "https://files.pythonhosted.org/packages/aa/3b/084bdc295823fbb6ab91670047adf8f420787f9e8794bf2d140b66dc196b/librt-0.12.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d977447315fa09ea4e8c7ae9b4e22f7659b5128161c1fd55ff786b5349f73503", size = 518428, upload-time = "2026-06-30T16:13:11.681Z" },
- { url = "https://files.pythonhosted.org/packages/c9/22/5a307390b93a115ffbecd95c64eecb4e56269680e45e9415ada7285f2cf4/librt-0.12.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7ffac8a67e4143cea9a549d4822b93bc0bbaad73fc25aa0ab0ba5ec27d178677", size = 509744, upload-time = "2026-06-30T16:13:13.217Z" },
- { url = "https://files.pythonhosted.org/packages/b5/90/83f3cb6184f5d669660717b4b2e317c9ddaccf7ca5bb97f2196deac1a3b7/librt-0.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:94af1ed773ff104ef08ef3d669a0ba9d3a5916c609eb698cffe5d5476d66ff9b", size = 527749, upload-time = "2026-06-30T16:13:15.277Z" },
- { url = "https://files.pythonhosted.org/packages/7d/3b/f162be5cc88d47378e3a20776fe425fa1c2bece755da15e2783ebf06d3d6/librt-0.12.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:548199d21d22fb26398dfbbe0ba953a52465c66f3a49f38e6fddce1b127faf53", size = 532582, upload-time = "2026-06-30T16:13:17.074Z" },
- { url = "https://files.pythonhosted.org/packages/c9/28/6c5d2f6b7232fd24f284fc4cab37a459fe69a9096a09942f44cc5c55e073/librt-0.12.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c8f1f413b966a9dd3ecf80cd337b0ad7bb3de2474a4ff448ed3ebabfc3f803fc", size = 522235, upload-time = "2026-06-30T16:13:18.823Z" },
- { url = "https://files.pythonhosted.org/packages/a9/1c/bd115360587fdc22c8ae8fac14c040a556b442e2965d4370d2cf274c8b95/librt-0.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:55f13f95b629be5b6ab38918e439bf14169d6f9a8deaae55e0c14e12fb0c74b9", size = 559055, upload-time = "2026-06-30T16:13:20.509Z" },
- { url = "https://files.pythonhosted.org/packages/fe/5a/c26f49f576437014825a86faea3cec60c1ed17f976abd567b6c12b8e35a7/librt-0.12.0-cp313-cp313-pyemscripten_2025_0_wasm32.whl", hash = "sha256:8b2dc079dfe29e77a47a19073d2040fa4879aa3656501f1650f8402ddce0313c", size = 79809, upload-time = "2026-06-30T16:13:22.401Z" },
- { url = "https://files.pythonhosted.org/packages/69/0b/a55244261d9ad7375ac039b8af06d42602722e2e8b8d8d6b86e4a3888c02/librt-0.12.0-cp313-cp313-win32.whl", hash = "sha256:da58944be8270f2bfee628a9a2a60c1cf6a12c8bea8e2c9b6edf3e5414ca7793", size = 99308, upload-time = "2026-06-30T16:13:23.661Z" },
- { url = "https://files.pythonhosted.org/packages/c9/bf/ed9465e58d44c5a5637795547d0841c8934aab905ea452cac1adf14672cf/librt-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:1db4be3037e4ce065a071fa7deee93e78ebc25f448340a02a6c1c0b82c37e383", size = 119438, upload-time = "2026-06-30T16:13:25.188Z" },
- { url = "https://files.pythonhosted.org/packages/c0/44/3cad652aeb892e6e8ffe48d0fafa2bc652f28ec7ed3f4403fcbb1be4f948/librt-0.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:05fd2542892ad770b5dd45003fd080477cf220b611d3ee59b0792097eb0873a9", size = 105118, upload-time = "2026-06-30T16:13:26.533Z" },
- { url = "https://files.pythonhosted.org/packages/0e/51/3a0e05618c12423b6fc5141b590ec02a6efb645833edc8736a6c7b46d1ec/librt-0.12.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:b37ee42e09722284a6d9288fe44a191f7276060a3195939bb77c6502058dbb34", size = 145579, upload-time = "2026-06-30T16:13:27.909Z" },
- { url = "https://files.pythonhosted.org/packages/77/9e/fd399d099dfb4020f3f7c34e7e6210c389fa89f7d79ca92f5afb0395f278/librt-0.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ade11988728b3e4768dadc5696e82c60e9b35fc95335a9b4d1f5d69e753ccec7", size = 150139, upload-time = "2026-06-30T16:13:29.357Z" },
- { url = "https://files.pythonhosted.org/packages/7a/ee/610239fbd8c4b005443664c5d4c3bc1717daedd8c71369bf45011aa87194/librt-0.12.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f351ed425380e39bd86df382578aa5b8c5b98e2e265112de7379e7d030258150", size = 480457, upload-time = "2026-06-30T16:13:30.78Z" },
- { url = "https://files.pythonhosted.org/packages/0c/10/ceddc9010f26c541444be36e1153a79b64626694db2d33a524c719fa3e46/librt-0.12.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:857d2163e088c868967717ace8e980017fd868a735f3de010412af02bdc30319", size = 479002, upload-time = "2026-06-30T16:13:32.398Z" },
- { url = "https://files.pythonhosted.org/packages/4e/f1/b1523d9718e8192e5403e6b41a02742e17ba554369f0729b9f30ab590e2d/librt-0.12.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e2befc80aa5f2f5b93f28abaaf11feff6677931dd548320e44c52deaa9399744", size = 510527, upload-time = "2026-06-30T16:13:34.615Z" },
- { url = "https://files.pythonhosted.org/packages/f6/0e/0f3ff43befb18a531615736791e52fb67eaa71ff7b89e6e5f7004b64cc6e/librt-0.12.0-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:be3694dcfa97c6715dd19ac73d3e1b21a805514a5785663e57fecacd3ff64e5a", size = 500988, upload-time = "2026-06-30T16:13:36.408Z" },
- { url = "https://files.pythonhosted.org/packages/a8/1a/0278ea4a9e599dc507c43839a87f2c764ad04bf69418e2d763d58659e55f/librt-0.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2d5f67e86f45638843d025b0828f2e9e55fc45ff9180d2618ccdeaf72a796050", size = 519318, upload-time = "2026-06-30T16:13:37.883Z" },
- { url = "https://files.pythonhosted.org/packages/59/55/090e10e62be2f35265e41601337f83ac9f83be9aca1bf92692e3a82effdd/librt-0.12.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:64572c85e4ab7d572c9b72cd76b5f90b21181b1459fa6b1aac6f8958c4fcff31", size = 527127, upload-time = "2026-06-30T16:13:39.682Z" },
- { url = "https://files.pythonhosted.org/packages/1f/34/8052c9ec678be6ba751279947831f089aa69b009000b985ce91d1979669a/librt-0.12.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:8b961912b0e688c1eb4658a46bdb0606b31918d65597fbe7356ca83aa653ffcc", size = 509766, upload-time = "2026-06-30T16:13:41.266Z" },
- { url = "https://files.pythonhosted.org/packages/6f/f8/8761b36189e9ec8dc20b49fa84cef22852c6c41fcda56f760f7fc1360da5/librt-0.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:722375903e3f079436a7a33da51ce73931536dd041f9feb01536f05d8e010c96", size = 552043, upload-time = "2026-06-30T16:13:43.197Z" },
- { url = "https://files.pythonhosted.org/packages/c8/98/7283971ef6b70269938b49c7b25f670ec6325d252265fbcc996f9b364379/librt-0.12.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:a5a96a8f536b65ef1bf910c09e7e71647edde5111f6e1b51f413c6fba5bfe71b", size = 79472, upload-time = "2026-06-30T16:13:44.64Z" },
- { url = "https://files.pythonhosted.org/packages/c3/5e/b30940dea935e8ac5bd0e0abb1985f5274590d557ac3a252ca0d5392ce52/librt-0.12.0-cp314-cp314-win32.whl", hash = "sha256:8ffc99c356f1777c506e1b69dc303879153ae2640ba15b8f3d4448bc87139149", size = 94246, upload-time = "2026-06-30T16:13:45.962Z" },
- { url = "https://files.pythonhosted.org/packages/7d/4e/0af9fe63f35fa304da3b05688f30ff6a329bcc59581b1cc51dc87fd30141/librt-0.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:1e68fb20798f455cda41d20a306a23c901218883f17a4bab1ed6e1331b265fb7", size = 114951, upload-time = "2026-06-30T16:13:47.279Z" },
- { url = "https://files.pythonhosted.org/packages/b1/8e/843c495d7db35e13b84cd533898fa89145c40dc255da0bc316d53d631464/librt-0.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:2df534f97916cf38ec9b1ddafeb68ae1a4cd4a54775ff26a797026774c0517cf", size = 100562, upload-time = "2026-06-30T16:13:48.699Z" },
- { url = "https://files.pythonhosted.org/packages/75/30/c686d0f978d5fd6867c5bbad96b015c9445746764d1c228e16a2d30d9382/librt-0.12.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c09e581b1c2b8a62b809d4f4bd101ca3de93791e5b0ed1a14085d911be3dee3f", size = 153897, upload-time = "2026-06-30T16:13:50.017Z" },
- { url = "https://files.pythonhosted.org/packages/40/46/f6f2d77ce46628b48fb5280709013b5109cf3a2c46a2472093cdfc03519d/librt-0.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:976888d0d831402086e641018bcc3208e0a38f0835789da91f72894b2cb4161f", size = 156391, upload-time = "2026-06-30T16:13:51.462Z" },
- { url = "https://files.pythonhosted.org/packages/c2/46/cd790c7e19e460779471530ffab454541d6ea4a3b7d338cad7f16ff96995/librt-0.12.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:563c37cdb41d08fe1e3f08b201abac0e317ca18e88b91285466ee0a585797520", size = 564151, upload-time = "2026-06-30T16:13:53.146Z" },
- { url = "https://files.pythonhosted.org/packages/54/12/724559a15fb023cbdef7aee1e81fbfbc3ee22fd09009baa816cea63e3a60/librt-0.12.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:b97eb1a3140e279cc76f85b0fb92b7eb3dfbe0471260ee878bc9dc4bf9a0d649", size = 546002, upload-time = "2026-06-30T16:13:54.665Z" },
- { url = "https://files.pythonhosted.org/packages/4b/7e/f9d8c257ab4909f101c7c13734367749e782fd8625545f0343502c2f09f1/librt-0.12.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:06e0623351ab9904cf628245f99c714586f4dd23dc740b88c8bc670d8401a847", size = 584204, upload-time = "2026-06-30T16:13:56.301Z" },
- { url = "https://files.pythonhosted.org/packages/9b/33/64665810575ac23b6cb6ef364de51309b7803620c12885b6e895ebc29591/librt-0.12.0-cp314-cp314t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:da12f017b2e404554be14d466cd992459feaa44f252b0f18d909a85266ce1237", size = 573688, upload-time = "2026-06-30T16:13:58.1Z" },
- { url = "https://files.pythonhosted.org/packages/0f/01/27522995c6627455abc7a939d57535fb1a7836d398ccedb3d7585f46039e/librt-0.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d97f31003a5c86b9e78155a829572c3a26484064fb7ac1d9695fe628bd93d029", size = 604719, upload-time = "2026-06-30T16:13:59.831Z" },
- { url = "https://files.pythonhosted.org/packages/ee/1f/099e61b1b688551d6d2ce9d4d2ae2242a938759db8551e6cbac7f7176ee5/librt-0.12.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:bd43a6c69876aef4f04eaae3d3b99b0be64755fda274002fa445b92480bf664e", size = 598183, upload-time = "2026-06-30T16:14:01.457Z" },
- { url = "https://files.pythonhosted.org/packages/bf/c1/050400249665503bdd5b83cec518fa7b183b609341c8dcd58161775c4226/librt-0.12.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c01755c72fca1dc6b8d5c2ed228b8e7b2ffe184675c22f0f05ebd8fe188b9250", size = 582559, upload-time = "2026-06-30T16:14:03.29Z" },
- { url = "https://files.pythonhosted.org/packages/da/d1/eef8f0e6722518b65a3d3bcd9309f9f44e208ce5d6728070820f988e7078/librt-0.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:625ae561d5fa36400856dcc27464400d047bc2d5e3446be88f437b03fefd72e4", size = 626375, upload-time = "2026-06-30T16:14:04.957Z" },
- { url = "https://files.pythonhosted.org/packages/8b/78/f0bb41a6f2bbd3c77bdcc66980dc0d69ca1192a0ecec25377afcc5e6db73/librt-0.12.0-cp314-cp314t-win32.whl", hash = "sha256:8d73191883553ee0739741544bf3b00aba2a1224e45d9580b30cbc29e21dc03b", size = 97752, upload-time = "2026-06-30T16:14:06.555Z" },
- { url = "https://files.pythonhosted.org/packages/92/24/e279c27972ab051a070237cfa45728fa51670c3f22f1a4d391711e9f4c31/librt-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e1cbb037324e759f0afa270229731ff0047772667f3cb38ef5df2cabf0175ede", size = 119562, upload-time = "2026-06-30T16:14:07.908Z" },
- { url = "https://files.pythonhosted.org/packages/06/e6/42a475bfca683b0cd5366f6dd06580062b7e567bb8534d225c877c2f14f3/librt-0.12.0-cp314-cp314t-win_arm64.whl", hash = "sha256:bca1472acbd473eff61059b4409f802c5a1bcb4cd0344d06f939df9c4c125d40", size = 104282, upload-time = "2026-06-30T16:14:09.29Z" },
+version = "0.13.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/dc/2f/3908645ddddab7120b46295e541ead308109fa48dbec7d67d7a778870d60/librt-0.13.0.tar.gz", hash = "sha256:1d2a610c14ac0d0750ee0a3ab8548e83155258387891caaca04def4bf7289781", size = 211402, upload-time = "2026-07-08T12:26:29.834Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/89/2f/ec5241c38e7fa0fe6c26bfc450e78b9489a6c3c08b394b85d2c10e506975/librt-0.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:34e47058fcc69a313293d6dee94216a4f30c929ae6f2476e58c5ba635aa639d5", size = 148654, upload-time = "2026-07-08T12:24:30.622Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/1a/d651e18d3ee7aa2879322368c4f278bb7ecaa6b90caadfdec4ebfa8389f3/librt-0.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dbdd5b6509d0c2a8fe72cf494c299a61dbd58142a90a4190664ae159e4a7b547", size = 153537, upload-time = "2026-07-08T12:24:31.773Z" },
+ { url = "https://files.pythonhosted.org/packages/45/18/10bff2122577246009d9619b6569596daf69b7648812f997ca9ca0426f60/librt-0.13.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e56ea4ee4df77585a6b5c138f6538680886024fa559f5b55bd14b12e98e67b2", size = 494336, upload-time = "2026-07-08T12:24:33.079Z" },
+ { url = "https://files.pythonhosted.org/packages/67/69/87dfee871b852970f137fdeae8e2ca356c5ab38e6f21d2a3299535fc3159/librt-0.13.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:f1f9cc4d09a46d9cb3c2063ae100629d3f52a6517c3c08c2f4c9828261883929", size = 485393, upload-time = "2026-07-08T12:24:34.324Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/d5/625447a8c0441ff5f15f4ac5e1d323fb9d4d256ebfde7a3c8e003f646057/librt-0.13.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f125f5d46b20f89dc5587a55cc416b4ba2a5b2ffda36d048ee120e17598a653a", size = 515382, upload-time = "2026-07-08T12:24:35.575Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/d8/1c8c49ea04235960426444deece9092a6b3a9587a850a81bae2335317411/librt-0.13.0-cp310-cp310-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:2608d3b39f9e0b4a66a130d9150c615cba40a5090d25eeeaa225e0e46de8c0ac", size = 509483, upload-time = "2026-07-08T12:24:36.923Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/65/f1760fc48050e215201a03506c32b7270159088d01f64557b53e39e74a45/librt-0.13.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9fd35e95ab5e45c3901d37110263c7db85a961110f5460588fe37f8c131f88a7", size = 532503, upload-time = "2026-07-08T12:24:38.203Z" },
+ { url = "https://files.pythonhosted.org/packages/18/1b/793e281dcf494879eff99f642b63ebc9c7c58694a1c2d1e93362a22c7041/librt-0.13.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5f31b0aa13c9b04370d4da6be1ab7779776b3a075cceb6747a39a4be85fe1e40", size = 537027, upload-time = "2026-07-08T12:24:39.34Z" },
+ { url = "https://files.pythonhosted.org/packages/69/45/0801bbb40c9eea795d3dd3ce91c4c5f3fe7d42d23ec4be3e8cb283bcc754/librt-0.13.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0b795f5fc70fbbb787ceaf79bb3a0d627bcc33c53de51741755263ec406b775a", size = 517100, upload-time = "2026-07-08T12:24:40.907Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/6c/eb5f514f8e29d4924bc0ff4601dd7b4175557e182e7c0721e84cffa39b8a/librt-0.13.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:36b306a623aaad96fe4b378692b54f9c0789fccd833b9851753d5fbf6138cfde", size = 558653, upload-time = "2026-07-08T12:24:42.359Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/bf/f140100d1b59fe87ff40b5ecbb4e27924335b189a784e230ee465452f6c2/librt-0.13.0-cp310-cp310-win32.whl", hash = "sha256:a3762e75fcac8c9e4dacaaf438bffd9003e2ca2c531b756f3c0035deefa674c8", size = 104402, upload-time = "2026-07-08T12:24:43.668Z" },
+ { url = "https://files.pythonhosted.org/packages/22/7c/57e40fef7cfb61869341cb28bdcefe8a950bebcbecca74a397bae14dce4a/librt-0.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:d63bae12a8aeb51380be3438e4dc4bd27354d0f8e19166b2f44e3e94d6f552dc", size = 125002, upload-time = "2026-07-08T12:24:44.793Z" },
+ { url = "https://files.pythonhosted.org/packages/89/25/a6498964cfeec270c468cffdc118f69c29b412593610d55fa1327ca51ff4/librt-0.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1b5a7bbff495baedbd9b916c367d66854008f8f3b575908ded477c499dc60082", size = 148029, upload-time = "2026-07-08T12:24:45.961Z" },
+ { url = "https://files.pythonhosted.org/packages/78/59/dc86d1bffd8e0c2818bace29d9f7783cfbb8e0673bf3673b5bbd5bbe0420/librt-0.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34bc7938b9fdf14fe32a406c19c71faf894c5cee7e7474bd0be2f17200b82d14", size = 153036, upload-time = "2026-07-08T12:24:47.257Z" },
+ { url = "https://files.pythonhosted.org/packages/29/3f/b923826660f02f286186cd9303d52bb05ced0a13708edc104dc8480920e3/librt-0.13.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f40e56b61b41be5f7dec938cfeffd660668cf4b5e72c78e7bd671d66b7bc2c79", size = 493062, upload-time = "2026-07-08T12:24:48.483Z" },
+ { url = "https://files.pythonhosted.org/packages/88/87/6c0980a9c9b1302cb68d108906697b89eceb55889bb1dcf77c109aa56ca5/librt-0.13.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:9c5d02b89de5acd0379a51ec44a89476fb03df6145442e1c8ecd6bee2f91b176", size = 485510, upload-time = "2026-07-08T12:24:49.727Z" },
+ { url = "https://files.pythonhosted.org/packages/32/81/795ae3b9df5dd94079fb807e38191855e023e8c6249014ae6bc3f0d9a490/librt-0.13.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7db9a3ff32ef5f7d1703d93831a3316cdf0b537de6a1cc03cc8fdd09b9194e89", size = 515909, upload-time = "2026-07-08T12:24:51.135Z" },
+ { url = "https://files.pythonhosted.org/packages/20/e5/182de15abce8907108a6fdb41487de65beb5099b74dc5841b19b099168db/librt-0.13.0-cp311-cp311-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3dbb2a31882456cadc7053378e81ad7ed7693db4ac9f98ab5f81ef034aa8ec9f", size = 508620, upload-time = "2026-07-08T12:24:52.358Z" },
+ { url = "https://files.pythonhosted.org/packages/32/03/33978d32db76e1f66377e8f78e42a2ca3c162143331677d1f50bbad36cfb/librt-0.13.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c6014e3c80f9c1fe268ef8b0e0ef113bac672cc032f2f93866e7ddad4f3e663d", size = 530363, upload-time = "2026-07-08T12:24:53.503Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/f5/b291fbd2d00f7d8287bcbf67b5aa0c6afed4bc26cef23e079629c47a2c04/librt-0.13.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:091b60a4d2174fc1ec5c34cdc0b72efb6224753d76b7da61ebeab7a191aec8bd", size = 534209, upload-time = "2026-07-08T12:24:55.138Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/03/6f41f17939d191bc21609f220da8509316bc62797f078545fe83be522e78/librt-0.13.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:66cb1138f384a191a6d75f986064841fcfdc0cea98f7bd9c9ab9b38049917588", size = 514254, upload-time = "2026-07-08T12:24:56.276Z" },
+ { url = "https://files.pythonhosted.org/packages/af/c2/2e4befa5410a7443019c14abccc94ff619797171f6b72013635fb87f31d7/librt-0.13.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:17221a7569f8f292aa0014226e48aa25b8c2b08da18088cd230953d0ea0f9cd1", size = 557611, upload-time = "2026-07-08T12:24:57.561Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/54/8b69f81448417adbc040a2185f4e2eece1e1994b7dcfaeed4662b30f98a5/librt-0.13.0-cp311-cp311-win32.whl", hash = "sha256:fc67741da44c6eaa90e01eafb586bbba9b51eb5b6ed381ee6f5ae72eb3316d21", size = 104906, upload-time = "2026-07-08T12:24:58.806Z" },
+ { url = "https://files.pythonhosted.org/packages/76/5a/f4aaf37b50f2fde12c8c663b83fdd499cdc24f957f19543d7414bfcc9e25/librt-0.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:cc99dfb62b23c9207c33d0be8a2e2af7a42e21e6ea388b380a0c948c7b88953b", size = 125852, upload-time = "2026-07-08T12:25:00.065Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/99/bf1820e6feeabc2f218c24450ec0c995d6a91e8ba0fd3caf042c9e8adb2a/librt-0.13.0-cp311-cp311-win_arm64.whl", hash = "sha256:40ccd13c252d3fe473ffc8a57be7565abc8b64cf1b108344c859d5164f7f3e0c", size = 111832, upload-time = "2026-07-08T12:25:01.148Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/f4/b2933ddae222dac338476abb872641169a5cfed2c2bb5444a5b07b32b0c3/librt-0.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:30536798f4504c0fad0885b1d371b0539abb081e4570c9d7c641cb51141b49f0", size = 150990, upload-time = "2026-07-08T12:25:02.42Z" },
+ { url = "https://files.pythonhosted.org/packages/90/ef/db98f744ca50e6efc9c95c70ee49b77aefac31f6a3fc7c83754a42d6a74f/librt-0.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:93d24ebb82aa4420b1409c389e7857bc35bd0b668007ac8172427d5c73cc8cc5", size = 155238, upload-time = "2026-07-08T12:25:03.681Z" },
+ { url = "https://files.pythonhosted.org/packages/03/e7/a197e7bc72baf2c61ce7fdc6906a5054dc05bd8da0819aa894e4857bf87e/librt-0.13.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cb8a1adce42d8b75485a5d56a9623a50bcab995b6079f1dac59fc44034dd93d9", size = 503073, upload-time = "2026-07-08T12:25:05.049Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/e7/7887712e27da7c1ab80fcabb1de6eb24243964f6557cae530d4b70706dbd/librt-0.13.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:0763ca2ab66058174f9dee426dc64f5e0a89c24a7df8d3fe3f1836c04e25de4b", size = 496528, upload-time = "2026-07-08T12:25:06.26Z" },
+ { url = "https://files.pythonhosted.org/packages/94/f0/f2283385bb6b950b26a1410f4ce51ec27231e0b3a4b925c46366d218b198/librt-0.13.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b222493da6e7b6199db9bd79502436cf5a27da3c1f7fa83c7e285444fc93fd03", size = 531786, upload-time = "2026-07-08T12:25:07.658Z" },
+ { url = "https://files.pythonhosted.org/packages/36/11/69ac3b54766ffba5fd7e5acebfb048d66dbe1f9f2d14516c2b3edc59cf87/librt-0.13.0-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fadc63331f4388c3dc90090448f682a7e9feafc11481391c1e94f2f907a3976e", size = 524393, upload-time = "2026-07-08T12:25:09.121Z" },
+ { url = "https://files.pythonhosted.org/packages/61/5f/d72f95fd444a926a3c14b4e24979474116988dd57a45be242077c45d3c22/librt-0.13.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:70d9c62a4cffd9f23396cd5ef93fc5d11b31596b9b7d6306074abe3d5fcf09bd", size = 543026, upload-time = "2026-07-08T12:25:10.459Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/08/dcd9993ad192737a004ba263d549f8ea605b326b952e7d6205c7d4170b76/librt-0.13.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:66c0e7e6b02a155576df2c77ec933a70b72da726e248c494abf690923e624348", size = 546829, upload-time = "2026-07-08T12:25:11.716Z" },
+ { url = "https://files.pythonhosted.org/packages/96/d5/6d9bb2f54e4109a956b7128836529653eb9d740f784bc47ed10a02c1000e/librt-0.13.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:ac04bcd3328eb91d99dfedf6a60d9c1f15d3434e6f6daf922f0420f7d90b85c7", size = 535700, upload-time = "2026-07-08T12:25:13.144Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/f2/10946922503858a359492fa27f13e86228bde702116a740ac7b3cd185f24/librt-0.13.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:db327e7271e653c32040b85ae6188059c924b57d7e1e29f935523fa017cd4e82", size = 573566, upload-time = "2026-07-08T12:25:14.336Z" },
+ { url = "https://files.pythonhosted.org/packages/48/a8/94f00e3c99479a18088af3685ea016c42f3c7d5d1964d8dbb40c08d7f1aa/librt-0.13.0-cp312-cp312-win32.whl", hash = "sha256:860bd1d8ba48456ce08feaf8d343a8aaeb2fa086f2bcaa2a923fa3f7a3ff9aa3", size = 106099, upload-time = "2026-07-08T12:25:16.159Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/7b/2da9c74c1ed25a89cc4e1c8e007ea2eb4a0f1fafa3e70d757fe3242c5c5c/librt-0.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:e54a315caf843c8d77e388cadc56ea9ded569935ee2d2347d7ea94992e5aa6fa", size = 126934, upload-time = "2026-07-08T12:25:17.275Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/65/aead61bbf3b5358593f9d4779d2a0e88eaf6ec191a6342dde36dd1df6371/librt-0.13.0-cp312-cp312-win_arm64.whl", hash = "sha256:c718e99a0992127af84385378460db624103b559ab260435abcfe77a4e4ed1c1", size = 112236, upload-time = "2026-07-08T12:25:18.425Z" },
+ { url = "https://files.pythonhosted.org/packages/67/3b/18e7b63255297a2bdc9c25c8d6d4ca8eca9f63aceb1252c0f7427ac7099e/librt-0.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a468951af16155824e88bdd8326ebe5bdb371f3ec0ac04642994b98201d914f3", size = 151027, upload-time = "2026-07-08T12:25:19.638Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/68/e2248452c00d1a03b45fee1752cdc8f790a476efd2402b75181da88a9e61/librt-0.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ae01d8512cc17079e53425635327dbf3f7ff57a42c00dec348bf79791c56444c", size = 155152, upload-time = "2026-07-08T12:25:20.851Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/16/52b1c99bf19057a062aac39c900cbb81499f6f75d6c537c14463d247ba78/librt-0.13.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:32c26893cd085c1efe83219e78d866da23fb20a066101b8f68210004361d224c", size = 502499, upload-time = "2026-07-08T12:25:22.055Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/54/b811151805c795f55e0dedee6ec687b75f9982a8105d240ea3910737a77b/librt-0.13.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:5929da1981a46bcf4b28b1b9499905f0ff58e2419da402a048234e9783acbc4b", size = 496108, upload-time = "2026-07-08T12:25:23.296Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/f8/094d6b2bd93f3fdaa54db54cc788c4a365333bddad65ab02e04da0b1d004/librt-0.13.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:94b85d664d777bab6c0d709416cb42938251fda9e221b79e3a2215d85df5f4f9", size = 531576, upload-time = "2026-07-08T12:25:24.648Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/40/541733d5755824f968f7ec39d78ffbd75d145964157ae5e69a09ec6d7326/librt-0.13.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:531b2df3e9fe96b1fcf73a6d165921e4656be5f58d631d384ebce344298368db", size = 524390, upload-time = "2026-07-08T12:25:25.898Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/b5/255673cfdbf5ba663339d36cd863c897289ab4337577e19f9405ce059f36/librt-0.13.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:109b84a9edf69ad89dc1f66358659e14a031baca95e3e5b0060bd903ede8efd6", size = 543053, upload-time = "2026-07-08T12:25:27.436Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/11/ab5005e9c9850710f21e354201bf090646349d3fabf5f951eaf70235729e/librt-0.13.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1304368a3e7ffc3e9db986796cc5326fdb5943a3567ecc137cff318e4240c0e7", size = 546387, upload-time = "2026-07-08T12:25:28.65Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/04/a5d7ce1d1df1afd15ca283dcdf7530ac073e12d69ae8c40879dda96f7868/librt-0.13.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e4f9b472e7d308d94b62c801982065661158c6ed02790d6c7ddb4337cea0f9c1", size = 535970, upload-time = "2026-07-08T12:25:30.171Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/76/927e267a6daa290174ac281b23c9804c8829b042ade9c6f24a065f540958/librt-0.13.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9f836c37478f167a81200d8c8b2c920a22224564bed2c23d7aeec760965c367a", size = 573582, upload-time = "2026-07-08T12:25:31.507Z" },
+ { url = "https://files.pythonhosted.org/packages/10/24/b6c5213efe39c19f9e13605644d0cf063b4ddaa33ac2e45b088e23a70e2e/librt-0.13.0-cp313-cp313-pyemscripten_2025_0_wasm32.whl", hash = "sha256:4000d961ff9598ac6ea603c6c836a5ed49bc205ade5fc378b998dfe1e2c36628", size = 82189, upload-time = "2026-07-08T12:25:32.675Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/00/d29736be177a906ac0b84a5b04b4fbfa22c776dc2f366de4172b0f968c08/librt-0.13.0-cp313-cp313-win32.whl", hash = "sha256:79e44cff71750d299d61a678e49995b0d5935a9cda238c2574daeca3ba536927", size = 106193, upload-time = "2026-07-08T12:25:33.692Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/ac/aff6fb45393cb8912f39dfb156ef6b2d1cadb207ff465fc8f66141054be8/librt-0.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:54dab44a847d5ad1acd05c8a83fe518ae685516ecf4d3f7cc6e3df2a66767650", size = 126962, upload-time = "2026-07-08T12:25:34.769Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/3a/d68cb2b334d53fd30fac81d3a489ce4ba0d9506f4df43fcf676b68352b19/librt-0.13.0-cp313-cp313-win_arm64.whl", hash = "sha256:d4cb6fbfdf874340ab5e51450753c0f817b6958a3621125ee695bbc3de866566", size = 112127, upload-time = "2026-07-08T12:25:35.981Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/66/f49ae0d592bd45b6941e9a8bafcb6a87cddcd501ee7874707e767f01b585/librt-0.13.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:25218d94b1d2cbc0ba1d8a3f9dc9af578d9646e5ed16443a70cde1dfdcce6d71", size = 149818, upload-time = "2026-07-08T12:25:37.203Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/50/51c76d74014d04fb95b6506d286808984b78a2f7a41039094e6b2194ac48/librt-0.13.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f26629539d4893c2957a16c41bb058e1e135c1f150f6a2e25ed047f64cf3f5c6", size = 154071, upload-time = "2026-07-08T12:25:39.399Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/fe/f19b0f5f82d5a1f2da736586bc840abd00ce07d6388136ae80b7333883fc/librt-0.13.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a4517d47b2b8af26975a406fba7d314de9696d864252e0257c6ea90238cfe27f", size = 494168, upload-time = "2026-07-08T12:25:40.641Z" },
+ { url = "https://files.pythonhosted.org/packages/94/bc/b8550c75775127fd31a5f20e8775997f7b527ad661fc8ddccd7497c064f7/librt-0.13.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:f19e181de5b3a1148bb3420b8c4b0b0ea0fce6950099724ad151d6cea5acc180", size = 491054, upload-time = "2026-07-08T12:25:41.905Z" },
+ { url = "https://files.pythonhosted.org/packages/30/14/4d0204867623df3f33f86efd3d3692ba5e01321443f4d6eab35a22697618/librt-0.13.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22034924f5b42d5a56371cf271771bfeaabf235a7a8b6264bef2d20013f786c6", size = 523006, upload-time = "2026-07-08T12:25:43.327Z" },
+ { url = "https://files.pythonhosted.org/packages/19/0a/c45fc9a260934696bace1ac5df1e148ac92bd71767aee3bf7cd7a4534f4c/librt-0.13.0-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c7897db4e95e22468bdda33d8e012ceacd0182abf001e6389d763f0def6286b9", size = 515058, upload-time = "2026-07-08T12:25:44.541Z" },
+ { url = "https://files.pythonhosted.org/packages/13/0a/50c5ce45b326854ef8fa6ae4c36cf5142e5c55315eaf9e51d0ae73ac4da3/librt-0.13.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1ce61b3746545029d4f5c17d6bd74b676254ad98433086c846ffb5e8fa73f007", size = 534025, upload-time = "2026-07-08T12:25:45.825Z" },
+ { url = "https://files.pythonhosted.org/packages/89/2d/08c413c8f93fc13b8103624fce38e5caa86cd08cbbc8465870ab287af54b/librt-0.13.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:46c330e82565962c761dbce7941be2cff7db674ee807455a8d0cadc5f9b759b0", size = 540557, upload-time = "2026-07-08T12:25:47.059Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/c1/93af71fb4a364952210051811dd4e40174e79656b050c89cacac18af3330/librt-0.13.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:375f5af8f99cbaa99dd293af986e3d57caabc9ba81a5d3f021603764854197a1", size = 523201, upload-time = "2026-07-08T12:25:48.392Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/6e/9766f07b676a4889d9f8bc2864e9ba5fff165653143ef4dda7df6aa34d16/librt-0.13.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9320d34c3376ae204b2cd176e8d4883a013934e0aef822f1aed9c536490c275d", size = 565740, upload-time = "2026-07-08T12:25:49.678Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/1e/664e3472ce2b6e10e9b83f29d4a36eb982ff6b5a169ae7567bba3a4c4ff5/librt-0.13.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:9af313c66157a69dc69ea0059a66961692250e0dc95af9c385a48ffb770a0d16", size = 81611, upload-time = "2026-07-08T12:25:50.857Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/d4/8582a4d65e2234673685e07309d02c230b28a85724eb0acbf13f019b7f6e/librt-0.13.0-cp314-cp314-win32.whl", hash = "sha256:f2a7253458e34f33543551394ae4fe104b497ec2a65ac266074de64c1df82e37", size = 100106, upload-time = "2026-07-08T12:25:52.03Z" },
+ { url = "https://files.pythonhosted.org/packages/63/ce/0cb99efe6086b46cd985dc26672166fae312a239690e75871f7fafbd3fc5/librt-0.13.0-cp314-cp314-win_amd64.whl", hash = "sha256:a3dfe4edf10e8ed7e55b026a8bfc2c2a8704218b659cd4bffdf604fab966dc39", size = 121209, upload-time = "2026-07-08T12:25:53.166Z" },
+ { url = "https://files.pythonhosted.org/packages/26/85/4f3ccb083a3c9b0d42e223acdb3c3f507953324a59cdcab4826e8e2e3b89/librt-0.13.0-cp314-cp314-win_arm64.whl", hash = "sha256:68a5faee4bba381cb93b5961f684a514cf0053cb92308ff9c792c2fea0b174c6", size = 106404, upload-time = "2026-07-08T12:25:54.253Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/77/333191499538c8e8189de7a4cba8e6f49ee949fd6d6e6324b21fd1522466/librt-0.13.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:a38fb81d8376dfa2f8963b265fec07637802b0d01e2a127c19c66cb070fb24f5", size = 159231, upload-time = "2026-07-08T12:25:55.432Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/9e/2aa83758f22c278b837a1d8025898434ce2b8bff36678d5330ecaef56dff/librt-0.13.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d4c8d9bd5abce34b2e75edb3bf37ab0f34e49b1f915a40ae8468eb7c85bc5b46", size = 161300, upload-time = "2026-07-08T12:25:56.585Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/c0/86791e936553ca763d6b3c2fb4d31d596cd00e14fa631c283a40ba01559a/librt-0.13.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:387e2f1d27e89bffe0d3f520f0da0662c973fd607ca16c1808f8a5085419485e", size = 582056, upload-time = "2026-07-08T12:25:58.144Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/d3/a9ec15984a185e000c4d2a16ba28bd623124ad4c38a10974c7ff78e3a893/librt-0.13.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:4f6db193d2e5e0ed60359b9a5a682cd67205d0d3b1e459a867dd4b5c4e7eaa7a", size = 562758, upload-time = "2026-07-08T12:25:59.544Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/af/dbe36b78b19c06a55097f99305e4ea9458e2273e6ae16a3cbecaad7ee978/librt-0.13.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d38604854e8d22faadf683ec6c02bb0f886e2ba56ef981a1c36ee275f21ea22", size = 602095, upload-time = "2026-07-08T12:26:00.991Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/a8/2966891b4dd2830f5203fbee92ac2c4947653a2390ba73dfa44244fad025/librt-0.13.0-cp314-cp314t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:371f7ce73026815dafd51c50ce38416e91428b28c4b2ec97cd39271164b0045c", size = 593452, upload-time = "2026-07-08T12:26:02.352Z" },
+ { url = "https://files.pythonhosted.org/packages/61/f5/4df8bfc8405ecf8c0d525b4d69636f694bdd8620b313ec8b76e54a5926cc/librt-0.13.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3aaedf52171bee90860704c560bc798fe83b76247df47568e0197e9b13c735a0", size = 623729, upload-time = "2026-07-08T12:26:04.294Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/13/9ac202dffc8db06f75d06c08c2f9f6ff054be67d21272dcc078fa1cc0c57/librt-0.13.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:96bad8725a4f196a798366c25ce075d1f7543a4ec045ffc13e6a7ec095cdab04", size = 617077, upload-time = "2026-07-08T12:26:05.845Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/f0/ebe38610716aee5cb28efd95089bb90192096179802779381e1c5dcf239c/librt-0.13.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:6bf6a559ffe4a93bbea6cf31ddf01a7fd9ba342ef51f27beb178e318b74acd61", size = 599561, upload-time = "2026-07-08T12:26:07.21Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/5c/c2e72e236fff7abc716d5b1753b8b8cd3ea85ac46fe17d2e7c51d4e1c723/librt-0.13.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:301067672387902c55f94b51d5022304b36c966ea9fe1f21caab99a9bef487c9", size = 645511, upload-time = "2026-07-08T12:26:08.562Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/99/6203ce619dee940d6bfbe099ec3fe4be00a68e9d60f70abf906cf124fe66/librt-0.13.0-cp314-cp314t-win32.whl", hash = "sha256:5fdcf34f86de8fb66d7dc7589f96ba91c4aa46671200d400e6fd6f109a483f18", size = 104357, upload-time = "2026-07-08T12:26:09.828Z" },
+ { url = "https://files.pythonhosted.org/packages/52/dd/843b6314087c41657c7036d7914d8f294bdf9b580aa8513ea0588c8e9a3d/librt-0.13.0-cp314-cp314t-win_amd64.whl", hash = "sha256:260c33e92263fa629b4f6d3c51967a1c2158fe6c33237aaa3ebeac586b085259", size = 126998, upload-time = "2026-07-08T12:26:10.975Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/5d/3dcec2884ba1b0806d1408612555c38dd5d68e90156b59f75f6e36435c3a/librt-0.13.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2f281549a4c52ac7bb97997f14353f8bd0e53a34ca0dad1c905cfd0b4a58ae99", size = 110771, upload-time = "2026-07-08T12:26:12.303Z" },
]
[[package]]
@@ -1377,7 +1377,7 @@ wheels = [
[[package]]
name = "mypy"
-version = "2.1.0"
+version = "2.2.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "ast-serialize" },
@@ -1387,51 +1387,52 @@ dependencies = [
{ name = "tomli", marker = "python_full_version < '3.11'" },
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/82/15/cca9d88503549ed6fedeaa1d448cdddd542ee8a490232d732e278036fbf2/mypy-2.1.0.tar.gz", hash = "sha256:81e76ad12c2d804512e9b13240d1588316531bfba07558286078bfbce9613633", size = 3898359, upload-time = "2026-05-11T18:37:36.237Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/a4/71/d351dca3e9b30da2328ee9d445c88b8388072808ebfbc49eb69d30b67749/mypy-2.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:11a6beb180257a805961aea9ec591bbd0bd17f1e18d35b8456d57aee5bedfedc", size = 14778792, upload-time = "2026-05-11T18:36:23.605Z" },
- { url = "https://files.pythonhosted.org/packages/2f/45/7d51594b644c17c0bcf74ed8cd5fc33b324276d708e8506f220b70dab9d9/mypy-2.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8ef78c1d306bbf9a8a12f526c44902c9c28dffd6c52c52bf6a72641ce18d3849", size = 13645739, upload-time = "2026-05-11T18:37:22.752Z" },
- { url = "https://files.pythonhosted.org/packages/65/01/455c31b170e9468265074840bf18863a8482a24103fdaabe4e199392aa5f/mypy-2.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c209a90853081ff01d01ee895cafe10f7db1474e0d95beaeef0f6c1db9119bbd", size = 14074199, upload-time = "2026-05-11T18:35:09.292Z" },
- { url = "https://files.pythonhosted.org/packages/41/5a/93093f0b29a9e982deafde698f740a2eb2e05886e79ccf0594c7fd5413a3/mypy-2.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47cebf61abde7c088a4e27718a8b13a81655686b2e9c251f5c0915a802248166", size = 14953128, upload-time = "2026-05-11T18:31:57.678Z" },
- { url = "https://files.pythonhosted.org/packages/7f/2f/a196f5331d96170ad3d28f144d2aba690d4b2911381f68d51e489c7ab82a/mypy-2.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d57a90ae5e872138a425ec328edbc9b235d1934c4377881a33ec05b341acc9a8", size = 15249378, upload-time = "2026-05-11T18:33:00.101Z" },
- { url = "https://files.pythonhosted.org/packages/54/de/94d321cc12da9f71341ac0c270efbed5c725750c7b4c334d957de9a087d9/mypy-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:aea7f7a8a55b459c34275fc468ada6ca7c173a5e43a68f5dbe588a563d8a06b8", size = 11060994, upload-time = "2026-05-11T18:33:18.848Z" },
- { url = "https://files.pythonhosted.org/packages/e1/62/0c27ca55219a7c764a7fb88c7bb2b7b2f9780ade8bbf16bc8ed8400eef6b/mypy-2.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:c989640253f0d76843e9c6c1bbf4bd48c5e85ada61bde4beb37cb3eca035685e", size = 9976743, upload-time = "2026-05-11T18:31:25.554Z" },
- { url = "https://files.pythonhosted.org/packages/0a/a1/639f3024794a2a15899cb90707fe02e044c4412794c39c5769fd3df2e2ef/mypy-2.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a683016b16fe2f572dc04c72be7ee0504ac1605a265d0200f5cea695fb788f41", size = 14691685, upload-time = "2026-05-11T18:33:27.973Z" },
- { url = "https://files.pythonhosted.org/packages/3b/08/9a585dea4325f20d8b80dc78623fa50d1fd2173b710f6237afd6ba6ab39b/mypy-2.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1a293c534adb55271fef24a26da04b855540a8c13cc07bc5917b9fd2c394f2ca", size = 13555165, upload-time = "2026-05-11T18:32:16.107Z" },
- { url = "https://files.pythonhosted.org/packages/81/dc/7c42cc9c6cb01e8eb09961f1f738741d3e9c7e9d5c5b30ec69222625cd5f/mypy-2.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7406f4d048e71e576f5356d317e5b0a9e666dfd966bd99f9d14ca06e1a341538", size = 13994376, upload-time = "2026-05-11T18:32:39.256Z" },
- { url = "https://files.pythonhosted.org/packages/d4/fa/285946c33bce716e082c11dfeee9ee196eaf1f5042efb3581a31f9f205e4/mypy-2.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e0210d626fc8b31ccc90233754c7bc90e1f43205e85d96387f7db1285b55c398", size = 14864618, upload-time = "2026-05-11T18:34:49.765Z" },
- { url = "https://files.pythonhosted.org/packages/2b/83/82397f48af6c27e295d57979ded8490c9829040152cf7571b2f026aeb9a0/mypy-2.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3712c20deed54e814eaaa825603bada8ea1c390670a397c95b98405347acc563", size = 15102063, upload-time = "2026-05-11T18:34:05.855Z" },
- { url = "https://files.pythonhosted.org/packages/40/68/b02dec39057b88eb03dc0aa854732e26e8361f34f9d0e20c7614967d1eba/mypy-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fcaa0e479066e31f7cceb6a3bea39cb22b2ff51a6b2f24f193d19179ba17c389", size = 11060564, upload-time = "2026-05-11T18:35:36.494Z" },
- { url = "https://files.pythonhosted.org/packages/cf/a8/ea3dcbef31f99b634f2ee23bb0321cbc8c1b388b76a861eb849f13c347dc/mypy-2.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:0b1a5260c95aa443083f9ed3592662941951bca3d4ca224a5dc517c38b7cf666", size = 9966983, upload-time = "2026-05-11T18:37:14.139Z" },
- { url = "https://files.pythonhosted.org/packages/95/b1/55861beb5c339b44f9a2ba92df9e2cb1eeb4ae1eee674cdf7772c797778b/mypy-2.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:244358bf1c0da7722230bce60683d52e8e9fd030554926f15b747a84efb5b3af", size = 14874381, upload-time = "2026-05-11T18:37:31.784Z" },
- { url = "https://files.pythonhosted.org/packages/0b/b3/b7f770114b7d0ac92d0f76e8d93c2780844a70488a90e91821927850da86/mypy-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4ec7c57657493c7a75534df2751c8ae2cda383c16ecc55d2106c54476b1b16f6", size = 13665501, upload-time = "2026-05-11T18:34:23.063Z" },
- { url = "https://files.pythonhosted.org/packages/b6/f3/8ae2037967e2126689a0c11d99e2b707134a565191e92c60ca2572aec60a/mypy-2.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8161b6ff4392410023224f0969d17db93e1e154bc3e4ba62598e720723ae211", size = 14045750, upload-time = "2026-05-11T18:31:48.151Z" },
- { url = "https://files.pythonhosted.org/packages/a0/32/615eb5911859e43d054941b0d0a7d06cfa2870eba86529cf385b052b111c/mypy-2.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bf03e12003084a67395184d3eb8cbd6a489dc3655b5664b28c210a9e2403ab0b", size = 15061630, upload-time = "2026-05-11T18:37:06.898Z" },
- { url = "https://files.pythonhosted.org/packages/d4/03/4eafbfff8bfab1b87082741eae6e6a624028c984e6708b73bce2a8570c9d/mypy-2.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:20509760fd791c51579d573153407d226385ec1f8bcce55d730b354f3336bc22", size = 15288831, upload-time = "2026-05-11T18:31:18.07Z" },
- { url = "https://files.pythonhosted.org/packages/99/ee/919661478e5891a3c96e549c036e467e64563ab85995b10c53c8358e16a3/mypy-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:6753d0c1fdd6b1a23b9e4f283ce80b2153b724adcb2653b20b85a8a28ac6436b", size = 11135228, upload-time = "2026-05-11T18:34:31.23Z" },
- { url = "https://files.pythonhosted.org/packages/24/0a/6a12b9782ca0831a553192f351679f4548abc9d19a7cc93bb7feb02084c7/mypy-2.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:98ebb6589bb3b6d0c6f0c459d53ca55b8091fbc13d277c4041c885392e8195e8", size = 10040684, upload-time = "2026-05-11T18:36:48.199Z" },
- { url = "https://files.pythonhosted.org/packages/6e/dd/c7191469c777f07689c032a8f7326e393ea34c92d6d76eb7ce5ba57ea66d/mypy-2.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35aac3bb114e03888f535d5eb51b8bafbb3266586b599da1940f9b1be3ec5bd5", size = 14852174, upload-time = "2026-05-11T18:31:38.929Z" },
- { url = "https://files.pythonhosted.org/packages/55/8c/aed55408879043d72bb9135f4d0d19a02b886dd569631e113e3d2706cb8d/mypy-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8de55a8c861f2a49331f807be98d90caeceeef520bde13d43a160207f8af613e", size = 13651542, upload-time = "2026-05-11T18:36:04.636Z" },
- { url = "https://files.pythonhosted.org/packages/3a/8e/f371a824b1f1fa8ea6e3dbb8703d232977d572be2329554a3bc4d960302f/mypy-2.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5fdf2941a07434af755837d9880f7d7d25f1dacb1af9dcd4b9b66f2220a3024e", size = 14033929, upload-time = "2026-05-11T18:35:55.742Z" },
- { url = "https://files.pythonhosted.org/packages/94/21/f54be870d6dd53a82c674407e0f8eed7174b05ec78d42e5abd7b42e84fd5/mypy-2.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e195b817c13f02352a9c124301f9f30f078405444679b6753c1b96b6eed37285", size = 15039200, upload-time = "2026-05-11T18:33:10.281Z" },
- { url = "https://files.pythonhosted.org/packages/17/99/bf21748626a40ce59fd29a39386ab46afec88b7bd2f0fa6c3a97c995523f/mypy-2.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5431d42af987ebd92ba2f71d45c85ed41d8e6ca9f5fd209a69f68f707d2469e5", size = 15272690, upload-time = "2026-05-11T18:32:07.205Z" },
- { url = "https://files.pythonhosted.org/packages/d6/d7/9e90d2cf47100bea550ed2bc7b0d4de3a62181d84d5e37da0003e8462637/mypy-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:767fe8c66dc3e01e19e1737d4c38ebefead16125e1b8e58ad421903b376f5c65", size = 11147435, upload-time = "2026-05-11T18:33:56.477Z" },
- { url = "https://files.pythonhosted.org/packages/ec/46/e5c449e858798e35ffc90946282a27c62a77be743fe17480e4977374eb91/mypy-2.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:ecfe70d43775ab99562ab128ce49854a362044c9f894961f68f898c23cb7429d", size = 10035052, upload-time = "2026-05-11T18:32:30.049Z" },
- { url = "https://files.pythonhosted.org/packages/b0/ca/b279a672e874aedd5498ae25f722dacc8aa86bbffb939b3f97cbb1cf6686/mypy-2.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:7354c5a7f69d9345c3d6e69921d57088eea3ddeeb6b20d34c1b3855b02c36ec2", size = 14848422, upload-time = "2026-05-11T18:35:45.984Z" },
- { url = "https://files.pythonhosted.org/packages/27/e6/3efe56c631d959b9b4454e208b0ac4b7f4f58b404c89f8bec7b49efdfc21/mypy-2.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:49890d4f76ac9e06ec117f9e09f3174da70a620a0c300953d8595c926e80947f", size = 13677374, upload-time = "2026-05-11T18:36:57.188Z" },
- { url = "https://files.pythonhosted.org/packages/84/7f/8107ea87a44fd1f1b59882442f033c9c3488c127201b1d1d15f1cbd6022e/mypy-2.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:761be68e023ef5d94678772396a8af1220030f80837a3afd8d0aef3b419666f4", size = 14055743, upload-time = "2026-05-11T18:35:18.361Z" },
- { url = "https://files.pythonhosted.org/packages/51/4d/b6d34db183133b83761b9199a82d31557cdbb70a380d8c3b3438e11882a3/mypy-2.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c90345fc182dc363b891350457ec69c35140858538f38b4540845afcc32b1aef", size = 15020937, upload-time = "2026-05-11T18:34:59.618Z" },
- { url = "https://files.pythonhosted.org/packages/ff/d7/f08360c691d758acb02f45022c34d98b92892f4ea756644e1000d4b9f3d8/mypy-2.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b84802e7b5a6daf1f5e15bc9fcd7ddae77be13981ffab037f1c67bb84d67d135", size = 15253371, upload-time = "2026-05-11T18:36:41.081Z" },
- { url = "https://files.pythonhosted.org/packages/67/1b/09460a13719530a19bce27bd3bc8449e83569dd2ba7faf51c9c3c30c0b61/mypy-2.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:022c771234936ceac541ebaf836fe9e2abeb3f5e09aff21588fe543ff006fe21", size = 11326429, upload-time = "2026-05-11T18:34:13.526Z" },
- { url = "https://files.pythonhosted.org/packages/40/62/75dbf0f82f7b6680340efc614af29dd0b3c17b8a4f1cd09b8bd2fd6bc814/mypy-2.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:498207db725cec88829a6a5c2fc771205fd043719ef98bc49aba8fb9fc4e6d57", size = 10218799, upload-time = "2026-05-11T18:32:23.491Z" },
- { url = "https://files.pythonhosted.org/packages/b2/66/caca04ed7d972fb6eb6dd1ccd6df1de5c38fae8c5b3dc1c4e8e0d85ee6b9/mypy-2.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7d5e5cad0efeba72b93cd17490cc0d69c5ac9ca132994fe3fb0314808aeeb83e", size = 15923458, upload-time = "2026-05-11T18:35:28.64Z" },
- { url = "https://files.pythonhosted.org/packages/ed/52/2d90cbe49d014b13ed7ff337930c30bad35893fe38a1e4641e756bb62191/mypy-2.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ff715050c127d724fd260a2e666e7747fdd83511c0c47d449d98238970aef780", size = 14757697, upload-time = "2026-05-11T18:36:14.208Z" },
- { url = "https://files.pythonhosted.org/packages/ac/37/d98f4a14e081b238992d0ed96b6d39c7cc0148c9699eb71eaa68629665ea/mypy-2.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:82208da9e09414d520e912d3e462d454854bed0810b71540bb016dcbca7308fd", size = 15405638, upload-time = "2026-05-11T18:33:48.249Z" },
- { url = "https://files.pythonhosted.org/packages/a3/c2/15c46613b24a84fad2aea1248bf9619b99c2767ae9071fe224c179a0b7d4/mypy-2.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e79ebc1b904b84f0310dff7469655a9c36c7a68bddb37bdd42b67a332df61d08", size = 16215852, upload-time = "2026-05-11T18:32:50.296Z" },
- { url = "https://files.pythonhosted.org/packages/5c/90/9c16a57f482c76d25f6379762b56bbf65c711d8158cf271fb2802cfb0640/mypy-2.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e583edc957cfb0deb142079162ae826f58449b116c1d442f2d91c69d9fced081", size = 16452695, upload-time = "2026-05-11T18:33:38.182Z" },
- { url = "https://files.pythonhosted.org/packages/0f/4c/215a4eeb63cacc5f17f516691ea7285d11e249802b942476bff15922a314/mypy-2.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b33b6cd332695bba180d55e717a79d3038e479a2c49cc5eb3d53603409b9a5d7", size = 12866622, upload-time = "2026-05-11T18:34:39.945Z" },
- { url = "https://files.pythonhosted.org/packages/4b/50/1043e1db5f455ffe4c9ab22747cd8ca2bc492b1e4f4e21b130a44ee2b217/mypy-2.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:4f910fe825376a7b66ef7ca8c98e5a149e8cd64c19ae71d84047a74ee060d4e6", size = 10610798, upload-time = "2026-05-11T18:36:31.444Z" },
- { url = "https://files.pythonhosted.org/packages/0d/2a/13ca1f292f6db1b98ff495ef3467736b331621c5917cad984b7043e7348d/mypy-2.1.0-py3-none-any.whl", hash = "sha256:a663814603a5c563fb87a4f96fb473eeb30d1f5a4885afcf44f9db000a366289", size = 2693302, upload-time = "2026-05-11T18:31:29.246Z" },
+sdist = { url = "https://files.pythonhosted.org/packages/e9/7e/be536678c6ae49ef058aba4b483d8c7bc104f471479016066f345bc1f5f8/mypy-2.2.0.tar.gz", hash = "sha256:2cdd99d48590dce6f6b7f1961eda75386364398fcdaad86923bc0f0231bf9baf", size = 3950939, upload-time = "2026-07-08T01:37:27.335Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5f/f1/a818c375094e20a74ec51444cce6979cedd61d476f860c2f084ea8653bd2/mypy-2.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:97d21f3a1582ef30d0b77f9ca3ad88b4263f3c5aea9e7380cb5d7175160aec7e", size = 14903842, upload-time = "2026-07-08T01:33:27.944Z" },
+ { url = "https://files.pythonhosted.org/packages/33/15/f332590488a8e4bb4a24036484c8bc750fe01fbef09701451a8790ac4c44/mypy-2.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2529017942b951cc43db2e2712b71cc3aa7e9d90567630c03ed63d430aeec61a", size = 13902986, upload-time = "2026-07-08T01:36:59.24Z" },
+ { url = "https://files.pythonhosted.org/packages/38/9f/7ae37860922d264b536790a3307caa195eb8abb733f2e81608229bbb0f07/mypy-2.2.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0823d7f273f3b4a49df7573eac271ddbf77a0e5f53e24d294a4f0f77ad22e1d7", size = 14132163, upload-time = "2026-07-08T01:34:16.111Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/6d/25c31c85a793340a4a9be593f8fe2cea08fd7b615f8b602b3f52f2d822f6/mypy-2.2.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d78a0fc90704894bc9948d78affad14b882b08183a7c30412d185748aaa9418b", size = 15070110, upload-time = "2026-07-08T01:34:44.933Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/67/7adf1caa143f6a0d9c564de24e0c1ed48340185110c3b918adc2f447192b/mypy-2.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6efab25fa3568569fda06928743382900860c48be9200c1758ef5ce94b532714", size = 15371554, upload-time = "2026-07-08T01:34:27.688Z" },
+ { url = "https://files.pythonhosted.org/packages/49/cb/ceca928213076f540d9b068c3655c52d43549f124c1f6dece5ecb747bbeb/mypy-2.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:daeaf5287091d68f674c91416cabab0f80f36e347ed17fded38d7ebde682e9d1", size = 11063618, upload-time = "2026-07-08T01:36:13.235Z" },
+ { url = "https://files.pythonhosted.org/packages/41/24/08caa177a4f2e0c44b96d5ad85f2754761b45bb6d65841451ef5dc9edb86/mypy-2.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:f8d97940a0259e09c219903579720b2df12170c0c3a3b3799837c1fb63deb44e", size = 10070720, upload-time = "2026-07-08T01:37:13.251Z" },
+ { url = "https://files.pythonhosted.org/packages/96/2e/1ea8028583fef6561d146b51d738d91268201313ecf69e603e808a740e74/mypy-2.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ea6fe1a30f3e7dc574d641497ffead2428046b0f8bc5804d13b4e4392fdc317b", size = 14739569, upload-time = "2026-07-08T01:35:33.202Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/67/c0607da57d78358b3b4fbfa90ee8ca5c6bd1dbb997c9648904ad4d8861d8/mypy-2.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6965829a6d847a0925f51149472bbeb7a39332fb4801972fdfd9cedd9f8d43a4", size = 13821442, upload-time = "2026-07-08T01:33:45.991Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/56/0407007d4ec7a762bac20724af1f0a57a9d860186c39e73105b6b8396fa2/mypy-2.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5a906bfc9c4c5de3ece6dc4726f8076d56ce9be1720baf0c6f84e926c10262a4", size = 14049813, upload-time = "2026-07-08T01:35:44.282Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/d1/d718e006c8fed4bece7a1bebeea6dcd05f31433af552fc45a82fef426379/mypy-2.2.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:91df92625cb3452758f27f4965b000fb05ad89b00c282cc3430a7bd6b0e5389e", size = 14978473, upload-time = "2026-07-08T01:36:54.064Z" },
+ { url = "https://files.pythonhosted.org/packages/82/03/dae7299c45a84efb1590875f92652a5beb2da98a2cff9a567995e2583fe4/mypy-2.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d42893d15894fd34f395090e2d78315ba7c637d5ee221683e02893f578c2f548", size = 15224649, upload-time = "2026-07-08T01:35:15.988Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/8e/738e4e73d030f20852a81383c74319ca4a9a4fdaadc3a75823588fe2c833/mypy-2.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3abaeec02cdc72e30a147d99eb81852b6b745a2c8d19607e25241d79b1abbce", size = 11049851, upload-time = "2026-07-08T01:34:39.31Z" },
+ { url = "https://files.pythonhosted.org/packages/94/09/6c58caedb3fa5831a9b179687cd7dc252c66a61dca4800e5ba19c8eff82b/mypy-2.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:c39bdb7ceab252d15011e26d3a254b4aaa3bbf121b551febfa301df9b0c69abe", size = 10060307, upload-time = "2026-07-08T01:33:21.852Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/be/fbaba7b0ee89874fb11668416dec9e5585c190b676b0796cff26a9290fe8/mypy-2.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:484a2be712b245ac6e89847141f1f50c612b0a924aa25917e63e6cfcf4da07cd", size = 14928025, upload-time = "2026-07-08T01:37:24.376Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/8f/f79a7c5a76671b0f563d4beaa7d99fe90df4500d2c1d2ba1be0432121bcf/mypy-2.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fb0a020dc68480d40e484675558ed637140df1ccbf896a81ba68bca85f2b50a0", size = 13793027, upload-time = "2026-07-08T01:34:33.937Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/b9/3db0086bab611d34e26061b86189e6f71de6d22a9b81699a93b006eabcf6/mypy-2.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc361340732ce7108fa0308812caf02bb6868f16112f1efd35bcad88badf3327", size = 14108322, upload-time = "2026-07-08T01:36:08.316Z" },
+ { url = "https://files.pythonhosted.org/packages/58/29/4f1e13979a848de2a0fd385462354b58358b6e8b3d9661663e308f6e3d5d/mypy-2.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b0179a3a0b833f724a65f22613607cf7ea941ab17ec34fa283f8d6dfe21d9fa9", size = 15190198, upload-time = "2026-07-08T01:36:20.168Z" },
+ { url = "https://files.pythonhosted.org/packages/14/f7/7759f6294d9d25d86671957d0974a215a2a24d429526e26a2f603de951c5/mypy-2.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9e0899b13da1e4ba44b880550f247402ce90ffecc71c54b220bcbe7ecb34f394", size = 15424222, upload-time = "2026-07-08T01:33:39.398Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/1b/05b212bef4d2234b5f0b551ea53ce0680d8075b2e79861c765f70b590945/mypy-2.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:511320b17467402e2906130e185abffffa3d7648aff1444fc2abb61f4c8a087d", size = 11135191, upload-time = "2026-07-08T01:35:03.019Z" },
+ { url = "https://files.pythonhosted.org/packages/92/51/495e7122f6589948b36d3820a046461906756a0eb1b6dedc13ebfec7815e/mypy-2.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:7589f370b33dcdd95708f5340f13a67c2c49140957f934b42ef63064d343cca0", size = 10132502, upload-time = "2026-07-08T01:34:04.508Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/5f/2d7a9ac5646274cd6e77ce3abcc2a9ece760c2b21f4c4b9f301711e07855/mypy-2.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6968f27347ef539c443ddfd6897e79db525ddb8c856aa8fbf14c34f310ca5193", size = 14931618, upload-time = "2026-07-08T01:33:51.702Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/8a/1adaa7caaa104f87021b1ac71252d62e646e9b623d77900ac7a0ae252bf3/mypy-2.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3df226d2a0ae2c3b03845af217800a68e2965d4b14914c99b78d3a2c8ae23299", size = 13857718, upload-time = "2026-07-08T01:35:27.555Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/15/b11586b5aebbb82213e297fc30a6fcf3bed6a9deea3739cd8dd87621f3fd/mypy-2.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fc53553996aca2094216ad9306a6f06c5265d206c1bcb54dd367560bd3557825", size = 14059704, upload-time = "2026-07-08T01:33:57.363Z" },
+ { url = "https://files.pythonhosted.org/packages/03/db/071e05ab442596bdf7a845e830d5ef7128a0175281038245b171a6b16873/mypy-2.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:996abf2f0bebf572556c60720e8dc0cf5292b64060fa68d7f2bc9caa48e01b6f", size = 15128719, upload-time = "2026-07-08T01:33:33.855Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/1c/c4b84eafb85ee315da72471523cc1bf7d7c42164085c42333601da7a8817/mypy-2.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ec287c2381898c652bf8ff79448627fe1a9ee76d22005181fac7315a485c7108", size = 15378692, upload-time = "2026-07-08T01:34:10.468Z" },
+ { url = "https://files.pythonhosted.org/packages/68/a4/59a0ee94877fdfe2958cec9b6add72a75393063c79cb60ab4026dd5e10c2/mypy-2.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:c2c967a7685fa93fcf1a778b3ebe76e756b28ba14655f539d7b61ff3da69352a", size = 11150911, upload-time = "2026-07-08T01:35:21.603Z" },
+ { url = "https://files.pythonhosted.org/packages/90/e4/6a9144be50180ed43d8c92de9b03dff504daa92b5bcc0353e8960799a23b/mypy-2.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:d59a4b80351ec92e5f7415fcdd008bd77fcbefc7adf9cbc7ffe4eb9f71617734", size = 10125389, upload-time = "2026-07-08T01:36:36.164Z" },
+ { url = "https://files.pythonhosted.org/packages/73/32/0aa8d8d197023ca6040f7b25a486cb47037b6350b0d3bae657c8f85fb43f/mypy-2.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1f6c3d76853071409ac58fc0aadfb276a22af5f190fdaa02152a858088a39ebd", size = 14926083, upload-time = "2026-07-08T01:36:02.365Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/7c/35bbe0cb10e6699f90e988e537aaf4282a6c16e37f58848a242eb0a98bde/mypy-2.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:bdaa177e80cc3292824d4ef3670b5b58771ee8d57c290e0c9c89e7968212332c", size = 13879985, upload-time = "2026-07-08T01:36:31.093Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/0c/1597fbebd873e9b63452317740ae3dd32692cec5da180cc65acd96cd28cf/mypy-2.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:80923e6d6e7878291f537ee11052f974954c20cb569798429a5dc265eb780b47", size = 14076883, upload-time = "2026-07-08T01:34:21.789Z" },
+ { url = "https://files.pythonhosted.org/packages/68/35/2ec021a83ec01b5d522639f78d8b36adade7fa4821db0f48fd6d82e861f3/mypy-2.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f24bd465a09077c8d64be8f19a6646db467a55490fd315fe7871afe6bb9645", size = 15103567, upload-time = "2026-07-08T01:36:47.717Z" },
+ { url = "https://files.pythonhosted.org/packages/53/3a/8cb3529f6d6800c7d069935e5c83a05d80263847b8a947cf6b0b16a9e958/mypy-2.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:db34595464869f474708e769413d1d739fc33a69850f253757b9a4cc20bc1fec", size = 15354641, upload-time = "2026-07-08T01:36:41.592Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/4d/320bc9a9553f8a9db5e847ec5ded762ef7ed7403c76c4ba2e8181c80e2f0/mypy-2.2.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:b48092132c7b0ef4322773fecae62fc5b0bc339be348badeec8af502122a4a51", size = 7694355, upload-time = "2026-07-08T01:37:03.291Z" },
+ { url = "https://files.pythonhosted.org/packages/90/05/bf3b349e2f885cd3aab488111bb9049439c28bc028dac5073350d3df8fbe/mypy-2.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:6fc0e98b95e31755ca06d89f75fafa7820fbb3ea2caace6d83cba17625cd0acb", size = 11329146, upload-time = "2026-07-08T01:35:38.318Z" },
+ { url = "https://files.pythonhosted.org/packages/41/a5/558b06e6cfe17ab88bb38f7b370b6bc68a74ba177c9e138db9748e422d2d/mypy-2.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:bc73a5b4d40e8a3e6b12ef82eb0c90430964e34016a36c2aff4e3bfe37ba41f0", size = 10316586, upload-time = "2026-07-08T01:36:25.458Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/21/f0b96f19a9b8ba111a45ffbe9508e818b7f6990469b38f6888943f7bfd3a/mypy-2.2.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:6257bd4b4c0ae2148548b869a1ff3758e38645b92c8fe65eca401866c3c551c1", size = 15922565, upload-time = "2026-07-08T01:35:56.282Z" },
+ { url = "https://files.pythonhosted.org/packages/18/f2/1dbcb20b0865d5e992541450a8c73f2fcc90f8bd7d8a4b81313e16934870/mypy-2.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:dfa22b3ae862ac1ce76f5976ddd402651b5f090bcfd49c6d0484b8983a29eaf8", size = 14816515, upload-time = "2026-07-08T01:34:58.167Z" },
+ { url = "https://files.pythonhosted.org/packages/84/a2/18cce9c7d5b4d14010d1f13836da11b234dda917b17ca8671fc32c136997/mypy-2.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:30a430bf26fe8cf372f3933fbd83e633d6561868803645a20e4e6d4523f52a3b", size = 15272246, upload-time = "2026-07-08T01:37:08.72Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/71/24d720c7924829bd675cbde2d0fa779f50abf676ca617f53d6a8bfef5fa7/mypy-2.2.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d58655a60e823b1a4c9ebcda072897fb0193c2f3e6f8e7c433e152aa4cb00233", size = 16226295, upload-time = "2026-07-08T01:34:51.861Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/5e/785730990fc863ad8340b4ab44ac4ca23270aecff92c180ccdf27f9f5869/mypy-2.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d4452c955caf14e28bb046cbd0c3671272e6381630a8b81b0da9713558148890", size = 16493275, upload-time = "2026-07-08T01:35:09.337Z" },
+ { url = "https://files.pythonhosted.org/packages/93/33/55b1edf16f639f153972380d6977b81f65509c5b8f9c86b58b94b7990b03/mypy-2.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:68f5b7f7f755200f68c7181e3dfb28be9858162257690e539759c9f57721e388", size = 11749038, upload-time = "2026-07-08T01:35:50.071Z" },
+ { url = "https://files.pythonhosted.org/packages/61/36/67424748a4e65e97f0e05bf00df379dfb6c2d817f82cc3a4ce5c96d99beb/mypy-2.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:78d201accfafce3801d978f2b8dbbd473a9ce364cc0a0dfd9192fe47d977e129", size = 10704254, upload-time = "2026-07-08T01:37:17.971Z" },
+ { url = "https://files.pythonhosted.org/packages/28/cb/142c2097ca02c0d295b00625ff946808bdda65acda17d163c680d8a6a474/mypy-2.2.0-py3-none-any.whl", hash = "sha256:ecc138da861e932d1344214da4bae866b21900a9c2778824b51fe2fb47f5180e", size = 2726094, upload-time = "2026-07-08T01:34:00.075Z" },
]
[[package]]
@@ -1500,9 +1501,9 @@ name = "numba"
version = "0.65.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "llvmlite" },
+ { name = "llvmlite", marker = "python_full_version < '3.14'" },
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
- { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
+ { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f6/c5/db2ac3685833d626c0dcae6bd2330cd68433e1fd248d15f70998160d3ad7/numba-0.65.1.tar.gz", hash = "sha256:19357146c32fe9ed25059ab915e8465fb13951cf6b0aace3826b76886373ab23", size = 2765600, upload-time = "2026-04-24T02:02:56.551Z" }
wheels = [
@@ -2350,14 +2351,14 @@ name = "pynndescent"
version = "0.6.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "joblib" },
- { name = "llvmlite" },
- { name = "numba" },
+ { name = "joblib", marker = "python_full_version < '3.14'" },
+ { name = "llvmlite", marker = "python_full_version < '3.14'" },
+ { name = "numba", marker = "python_full_version < '3.14'" },
{ name = "scikit-learn", version = "1.7.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
- { name = "scikit-learn", version = "1.9.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
+ { name = "scikit-learn", version = "1.9.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
{ name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" },
- { name = "scipy", version = "1.18.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
+ { name = "scipy", version = "1.18.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12' and python_full_version < '3.14'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/4a/fb/7f58c397fb31666756457ee2ac4c0289ef2daad57f4ae4be8dec12f80b03/pynndescent-0.6.0.tar.gz", hash = "sha256:7ffde0fb5b400741e055a9f7d377e3702e02250616834231f6c209e39aac24f5", size = 2992987, upload-time = "2026-01-08T21:29:58.943Z" }
wheels = [
@@ -2428,15 +2429,15 @@ wheels = [
[[package]]
name = "python-discovery"
-version = "1.4.3"
+version = "1.4.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "filelock" },
{ name = "platformdirs" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/66/26/8b004cc36f430345136f6f00fa1aa9ed596c8ed1e8504625fa79522ff39c/python_discovery-1.4.3.tar.gz", hash = "sha256:ad57d7045a862460d4a235986c33f13ed707d3aeb9153fa47eb7dfd0d4673289", size = 70438, upload-time = "2026-07-03T13:21:51.621Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/4c/81/58c70036dffeccb7fe7d79d6260c69f7a28272bbd3909c29a01ea9422744/python_discovery-1.4.4.tar.gz", hash = "sha256:5cad33982d412c1f3ffb8f9ca4ea292c9680bca3942451d30b69c37fce53a4a3", size = 72212, upload-time = "2026-07-08T23:06:50.691Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/28/78/9b77ecb4644d1bbea94d29abf78f21c47eca6eb79e9745b702ec0bed2e19/python_discovery-1.4.3-py3-none-any.whl", hash = "sha256:b6e1e4a7d9e3f6948c39746ffe8218225162d738ba39d05ab1d2f6c1cac4878c", size = 33885, upload-time = "2026-07-03T13:21:50.174Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/ae/84bc0d2440c95772272bb6f4b3d09ccf08b2898fce89b3d4f969a9fc74e9/python_discovery-1.4.4-py3-none-any.whl", hash = "sha256:abebe9120b43453b68c908acfb1e72a19d1a959ed2cb620ad38fc57d08056dbe", size = 34181, upload-time = "2026-07-08T23:06:49.402Z" },
]
[[package]]
@@ -3578,27 +3579,27 @@ wheels = [
[[package]]
name = "ty"
-version = "0.0.56"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/55/07/fb29aea5235b0aa8ecfc4d1cc6ddf9fba8b863d67d96c6d345694d644c43/ty-0.0.56.tar.gz", hash = "sha256:84d114dc3796361c0fc72945016eabd74d46b9ee64f198cb0e485719704681e5", size = 6050123, upload-time = "2026-07-01T16:44:56.036Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/dc/48/bce79e7ca5c1cc529d3e0d37ddd1121aea4b68a4f749974ad1cc77161871/ty-0.0.56-py3-none-linux_armv6l.whl", hash = "sha256:186d4a53e15747c947e1ec3d7eec8e345d8e40a1ca10e634c585db52497e87dd", size = 11643066, upload-time = "2026-07-01T16:44:18.374Z" },
- { url = "https://files.pythonhosted.org/packages/80/d1/22555d8a1d719661f10050f3865d877bbf497da908961c75fe22217dd18a/ty-0.0.56-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:aae1a980fd9535da0469b7ba2b2e1b54a907743a5e0f442dd57eee9f5bfd034c", size = 11407487, upload-time = "2026-07-01T16:44:20.956Z" },
- { url = "https://files.pythonhosted.org/packages/cf/2d/b3b7a74ce8bc59ef48843ad80179bb0d9598bbd6cfc0d11d519bdf6b1352/ty-0.0.56-py3-none-macosx_11_0_arm64.whl", hash = "sha256:afd3058c0a6c5f241e814734f133008c93ee805f61c9cf4ce7412b8822b5d9ad", size = 10962270, upload-time = "2026-07-01T16:44:22.959Z" },
- { url = "https://files.pythonhosted.org/packages/64/ac/6c2fd7de0304a8a7218a756af74f7e62a5e8540fdb175e0a869e51042345/ty-0.0.56-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:058b52f7a823ac13aae3cae30809dd6b5145794b64d8478f9ef38c75d79b4483", size = 11471406, upload-time = "2026-07-01T16:44:25.327Z" },
- { url = "https://files.pythonhosted.org/packages/50/b6/11d861156861c03c7726b74558f9a0e0092661aff83a4fda1279df28c425/ty-0.0.56-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2c66e00c1522add1f2bbdd2e45828c953b35c306b7bef03ec9169c75a63699a0", size = 11445612, upload-time = "2026-07-01T16:44:27.531Z" },
- { url = "https://files.pythonhosted.org/packages/fb/ba/09df108582090f3c0770ec4bc8675affed60248f6793a78d909be16211d9/ty-0.0.56-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40903d71c669a30691b5a5d5728056c7877a1bd6be4f233a38883a8b28cf34d7", size = 12093889, upload-time = "2026-07-01T16:44:29.548Z" },
- { url = "https://files.pythonhosted.org/packages/d7/f7/dbb4b4ccb69cd64c209ae55b1ab788ace8222c2bc1f6845be9e7cbedbf25/ty-0.0.56-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:63fe3947fe0c46c69a7d950e6832ee70a9ec17321fefbff3d2e3c20baf9e5bd0", size = 12666337, upload-time = "2026-07-01T16:44:31.586Z" },
- { url = "https://files.pythonhosted.org/packages/86/e9/73f903fe4a3d9ea02f26f57c1eb07e3b1029ec92b0e8c2364718893440e3/ty-0.0.56-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:71a0c1a72f9854532e710e119b6871ffe4542c8a65146f1f65dcd78fecd885b4", size = 12280247, upload-time = "2026-07-01T16:44:33.637Z" },
- { url = "https://files.pythonhosted.org/packages/d6/90/cebd222495832f1a00dcd321ba25f3cab804221a4991b992c2178bec68ee/ty-0.0.56-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70d1665596494e24d8ebd198438872b5a56ec3cae5f2bcf6c673be797acc4e3c", size = 11991107, upload-time = "2026-07-01T16:44:36.122Z" },
- { url = "https://files.pythonhosted.org/packages/b7/07/8f7337a07250f42d975cdb6decf47fc5b421e6c7da5e3e7be1e85f63a7e5/ty-0.0.56-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:778f99e51558afc1dbbe48ee38ab6aae7b31390ed8c1a1ef1499b295e9f1e82f", size = 12298970, upload-time = "2026-07-01T16:44:38.243Z" },
- { url = "https://files.pythonhosted.org/packages/3c/b9/a52cd59034a48f5f18c6b155cc2cc36861d874b6d0af204b12c898024c3d/ty-0.0.56-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:867bc5708e0066bb4ff6c7db524bd5deea2676c62bfe71d3303138b3be850af0", size = 11425683, upload-time = "2026-07-01T16:44:40.473Z" },
- { url = "https://files.pythonhosted.org/packages/1d/2e/48e42d33357d52eefb695c0c3fcfc96879b73668a7447d1d1e0ad774fedc/ty-0.0.56-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a6012f4189c928edb330a37deb9930f982380bd4aa7c4b8e0428eec9651c7551", size = 11469258, upload-time = "2026-07-01T16:44:42.513Z" },
- { url = "https://files.pythonhosted.org/packages/d5/01/ad1b4138be1e3fa97863af3925aa2134f17a593240c35dc38c3429fb5ad1/ty-0.0.56-py3-none-musllinux_1_2_i686.whl", hash = "sha256:8ee83de1a7ff4cc32837ec06134ce391d441bc5b35ecd8d3cfe053f120f3e4c1", size = 11758736, upload-time = "2026-07-01T16:44:44.567Z" },
- { url = "https://files.pythonhosted.org/packages/09/34/9d81967ff240eaa57e9249728ef7b7790747cf6d3c9a98ec86b2cfdcc8ee/ty-0.0.56-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:62619b3b0e2c6248ef30d3f0e2f2217ae9893040585be07f32324242f197cd6f", size = 12100242, upload-time = "2026-07-01T16:44:46.584Z" },
- { url = "https://files.pythonhosted.org/packages/c3/36/f51d4666d2de6cf33c1f3a1fcc4bb6b70b197dd6ceaa491eef71d78fe8e8/ty-0.0.56-py3-none-win32.whl", hash = "sha256:b30687bb5cd9729d34c889a289edf32770388d9bb05243e534e723fb45e0381b", size = 11093759, upload-time = "2026-07-01T16:44:49.171Z" },
- { url = "https://files.pythonhosted.org/packages/5e/b4/8fb5d4acfa4afb152245b20fa263069a7547bd1f8e4bfca4eda280c897d7/ty-0.0.56-py3-none-win_amd64.whl", hash = "sha256:ad4c8c47b6f4e3f9ed3fc0b1a5d650088d229e17dd8f63c1826d6bbe94cc3235", size = 12100327, upload-time = "2026-07-01T16:44:51.26Z" },
- { url = "https://files.pythonhosted.org/packages/b8/fc/6a183e71edde90d0c35c2303f23f7a45b6891d1a2c45daf7b8f869831e19/ty-0.0.56-py3-none-win_arm64.whl", hash = "sha256:57538f273d444a5f1293fa7860e967178afe3917611fc5eff16b64e1204fe0d6", size = 11538780, upload-time = "2026-07-01T16:44:53.8Z" },
+version = "0.0.57"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/19/16/d01c968d405acae51c07872e80f30f3a586235bdf52c9847ca0917a230a3/ty-0.0.57.tar.gz", hash = "sha256:bc058f564868690283a0420d09c269ec8be21e8e43b4b49ee975a17623092e44", size = 6100787, upload-time = "2026-07-08T11:33:59.904Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3e/9c/a7948b05f2a3f43d511f88ef5c4f56d7edb8acc8caa5f56d7c5831f52c84/ty-0.0.57-py3-none-linux_armv6l.whl", hash = "sha256:cb6d3371dd8c78950b75bee31a36b94564a54a1f0eecafbbf05715ac1a5287d6", size = 11760058, upload-time = "2026-07-08T11:33:18.671Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/92/3776380decba3965bcaa1ea2b56f5b133aa3ef549bfbe4b79eb122dcc15d/ty-0.0.57-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e58b90491a48ec757bd50f512f3eb92c1c64b7d46a4db83677e9b60222e1d2bb", size = 11492105, upload-time = "2026-07-08T11:33:21.267Z" },
+ { url = "https://files.pythonhosted.org/packages/13/be/912f8422d06fd1e29805a7c781e3ce4c821917e0e3d00f0cf176c0529469/ty-0.0.57-py3-none-macosx_11_0_arm64.whl", hash = "sha256:dbb8207f75122c658ca21bf405cea8202e490240440461ae3e0c5a6f67ae668f", size = 11078675, upload-time = "2026-07-08T11:33:23.804Z" },
+ { url = "https://files.pythonhosted.org/packages/06/86/6ed526df554b491ce3d07bbec04f7a10304243bc994ab989352c85134b1e/ty-0.0.57-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:651243f391809de80b01be1729c5d0cecc7b952d7d22cfbf56f0b4f069703195", size = 11614379, upload-time = "2026-07-08T11:33:26.041Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/95/78af20f309abce31fa616e0142f85756e665a9965669b823181ff695ffec/ty-0.0.57-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:28c5392bbd7c4d6a4c1b1646a709231db675dc094f49bf71b7de83757125e93b", size = 11563854, upload-time = "2026-07-08T11:33:28.144Z" },
+ { url = "https://files.pythonhosted.org/packages/88/dc/bf9231d5563b9e61a1eec9782184a4055afaa87259644cd9ed1376a7dc5c/ty-0.0.57-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d981535094ab492aaef6f71d9348bcf90e42e6de4cb50de2dd7fbabd8378360", size = 12229897, upload-time = "2026-07-08T11:33:30.262Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/dd/012008190a997097ebe500b9704baaad9135bfa033b9530a9b8f69f1d11f/ty-0.0.57-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:719b41fd6df61352866cad952d7bfb4873c893a70e806d37d0f1d30ad4f26cd5", size = 12816002, upload-time = "2026-07-08T11:33:32.747Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/2f/0e42c361e38e04747ed2b3d3299512edd4ea6060d8e3124e3c6f2d2465a1/ty-0.0.57-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a1641a609b025e13f44115c7071b39b02675044a78fbfedef239a5f7da50b393", size = 12323420, upload-time = "2026-07-08T11:33:35.426Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/01/18f1e03108d1ae8e515c92fb304994a66eaafd47037f928fd42fd3a1e29d/ty-0.0.57-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a33f96a9dd6919fe8b1d3512cd99f16be4a51388f265de135fea2c2fbf0b4317", size = 12119481, upload-time = "2026-07-08T11:33:37.808Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/48/570b73fb3e32554ff03aa9f6650b33a504cdfa027a8b50a5ab087e56b20d/ty-0.0.57-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:f0a1014a922b2b7f79a46e5cdbaa6feb7403a444631292b8666382a98a04de20", size = 12427299, upload-time = "2026-07-08T11:33:39.964Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/37/76b27f6a92e12525d09cd65d3c3b5aea419cf4782b13320db95ac3d310f0/ty-0.0.57-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d73aaed84023bf682819f871377b255fae9098898c50475426ac9bdfcd986872", size = 11562292, upload-time = "2026-07-08T11:33:42.392Z" },
+ { url = "https://files.pythonhosted.org/packages/84/8b/d0c398147b00f336595e1a00a5895b3924251205c11b8d73cb0668281f1c/ty-0.0.57-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:f3e2104704063c00ab8a757af3e95378b32624a3e8d8149aad5251877bf82959", size = 11565833, upload-time = "2026-07-08T11:33:44.778Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/74/dab9745e977ef38751ec710f74e40d21fddbd04a80338dd5597c98899eed/ty-0.0.57-py3-none-musllinux_1_2_i686.whl", hash = "sha256:07ad760763646d8f1567ea5d899e6d217212acd8539b7afed5a370d93693553b", size = 11864967, upload-time = "2026-07-08T11:33:47.36Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/57/350812143b49dac7aa655f40a1f45d4821ca9b56b75d9b68d5e603269044/ty-0.0.57-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b4a6e1f0fee7df3e65fb0b9cbe9f99a4be39198558ed9aacc31a98d210ad7bcc", size = 12239054, upload-time = "2026-07-08T11:33:49.586Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/d0/b3e3d9c6cce3debda6247aa435e81d18ec62fabfec13f35f6c6957066f47/ty-0.0.57-py3-none-win32.whl", hash = "sha256:f8d488c0535a8f0386dbe2c9bcb31d467ae0c68d0c9945113018937828ebaabb", size = 11225353, upload-time = "2026-07-08T11:33:52.569Z" },
+ { url = "https://files.pythonhosted.org/packages/77/db/6ce240ee31413f9dc7467e31377553e92e2664252ee7d33aa9290a7a94bb/ty-0.0.57-py3-none-win_amd64.whl", hash = "sha256:de9529a7dcc3e529b08c14634dc4e7066ebea5cd55006afc02bde8033efe7c91", size = 12272419, upload-time = "2026-07-08T11:33:54.889Z" },
+ { url = "https://files.pythonhosted.org/packages/44/de/48662fa2c42289f309eeb8b5539cbe840e10002b65ac0700cb7889e92532/ty-0.0.57-py3-none-win_arm64.whl", hash = "sha256:7f3352777ce40c4906145f3c3e10b71716d8d35c0c9e3a0070d84f61dda0755f", size = 11686309, upload-time = "2026-07-08T11:33:57.246Z" },
]
[[package]]
@@ -3648,16 +3649,16 @@ name = "umap-learn"
version = "0.5.12"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "numba" },
+ { name = "numba", marker = "python_full_version < '3.14'" },
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
- { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
- { name = "pynndescent" },
+ { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
+ { name = "pynndescent", marker = "python_full_version < '3.14'" },
{ name = "scikit-learn", version = "1.7.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
- { name = "scikit-learn", version = "1.9.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
+ { name = "scikit-learn", version = "1.9.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
{ name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" },
- { name = "scipy", version = "1.18.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
- { name = "tqdm" },
+ { name = "scipy", version = "1.18.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12' and python_full_version < '3.14'" },
+ { name = "tqdm", marker = "python_full_version < '3.14'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/02/ee/af4171241117f85c74b5ca6448ea1033cc28d599c13651d67289bacd4083/umap_learn-0.5.12.tar.gz", hash = "sha256:6aff02ecac5f2aad9f3c65ee518d7ae93e1a985ae38721fdcffceee4232c33c7", size = 96672, upload-time = "2026-04-08T20:03:54.012Z" }
wheels = [
@@ -3675,16 +3676,16 @@ wheels = [
[[package]]
name = "uvicorn"
-version = "0.50.2"
+version = "0.51.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
{ name = "h11" },
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/9f/f6/cc9aadc0e481344a42095d222bfa764122fb8cfba708d1922917bd8bfb01/uvicorn-0.50.2.tar.gz", hash = "sha256:b92bf03509b82bcb9d49e7335b4fd364518ad021c2dc18b4e6a2fec8c955a0bb", size = 93716, upload-time = "2026-07-06T10:38:31.984Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/a2/65/b7c6c443ccc58678c91e1e973bbe2a878591538655d6e1d47f24ba1c51f3/uvicorn-0.51.0.tar.gz", hash = "sha256:f6f4b69b657c312f516dd2d268ab9ae6f254b11e4bac504f37b2ab58b24dd0b0", size = 94412, upload-time = "2026-07-08T10:59:05.962Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/aa/f0/7c228ee10c7ab8fd3a21d06579a6f7c6075c6ce72594a20fb5d2f206ff24/uvicorn-0.50.2-py3-none-any.whl", hash = "sha256:4ae72a385630bcc17a0adb8290f26c993865e0b43a2114c2aab96420172c056a", size = 72846, upload-time = "2026-07-06T10:38:30.543Z" },
+ { url = "https://files.pythonhosted.org/packages/45/ec/dbb7e5a6b91f86bfb9eb7d2988a2730907b6a729875b949c7f022e8b88fa/uvicorn-0.51.0-py3-none-any.whl", hash = "sha256:5d38af6cd620f2ae3849fb44fd4879e0890aa1febe8d47eb355fb45d93fe6a5b", size = 73219, upload-time = "2026-07-08T10:59:04.44Z" },
]
[[package]]