From 6d8ad067eb8ef35c4b8992db8778c6a0efa7b1ab Mon Sep 17 00:00:00 2001 From: Den Rozhnovskiy Date: Wed, 8 Jul 2026 13:18:49 +0500 Subject: [PATCH 01/18] fix(mcp): unify compare_runs params to before_run_id/after_run_id --- .../mcp/_session_patch_contract_mixin.py | 4 ++-- .../mcp/_session_review_receipt_mixin.py | 4 ++-- .../surfaces/mcp/_session_state_mixin.py | 12 +++++----- codeclone/surfaces/mcp/server.py | 8 +++---- codeclone/surfaces/mcp/service.py | 4 ++-- .../contract_snapshots/mcp_tool_schemas.json | 22 +++++++++---------- .../public_api_surface.json | 2 +- tests/test_mcp_server.py | 4 ++-- tests/test_mcp_service.py | 22 +++++++++---------- 9 files changed, 41 insertions(+), 41 deletions(-) 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/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/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", ) From f4431d1555569b3ab2c6315ad22f40afa192d3d3 Mon Sep 17 00:00:00 2001 From: Den Rozhnovskiy Date: Wed, 8 Jul 2026 17:15:47 +0500 Subject: [PATCH 02/18] perf(analysis): collapse relationship walk into single pass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid the second DFS-style relationship pass in module walking by collecting the required relationship facts during the primary traversal. Strict cold-cache A/B in the same worktree: - files_timed: 769 → 769 - phase_relationship: 2393.2 ms → 1726.6 ms (-667 ms, -27.9%) - pipeline.process: 3121 ms → 2888 ms (-233 ms, -7.5%) - cli.analyze: 3786.9 ms → 3558.1 ms (-229 ms, -6.0%) Verification: - 4248 tests passed, including goldens --- codeclone/analysis/_module_walk.py | 80 ++++++++++++++++++++---------- tests/test_extractor.py | 2 +- 2 files changed, 54 insertions(+), 28 deletions(-) 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/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", From 0050f7c5f633f6bbcf479826e8cbb4aaaaddfe56 Mon Sep 17 00:00:00 2001 From: Den Rozhnovskiy Date: Wed, 8 Jul 2026 17:52:36 +0500 Subject: [PATCH 03/18] chore(obs): add module_passes subphase timing counters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Record adoption, security, and reachability alias/binding/visit worker time as optional subphase_us counters on the phase ledger when observability is enabled. Collectors are unchanged; timers are no-ops when the ledger is inactive. Cold-cache split on this repo (769 files_timed): - phase_module_passes: 1803 ms - reachability Σ: 1201 ms (66.6% of module_passes) - security: 463 ms; adoption: 38 ms Verification: pre-commit (all hooks) and pre-push pytest green. --- codeclone/analysis/phase_ledger.py | 56 ++++++++++++++++++++- codeclone/analysis/reachability.py | 35 +++++++++++-- codeclone/analysis/units.py | 29 +++++++---- codeclone/observability/analysis_phases.py | 3 ++ tests/test_analysis_phase_ledger.py | 42 ++++++++++++++++ tests/test_observability_analysis_phases.py | 19 ++++++- 6 files changed, 168 insertions(+), 16 deletions(-) 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..2021efa2 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 @@ -1303,11 +1310,26 @@ 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) + + def _alias_pass() -> None: + alias_visitor.visit(tree) + + phase_ledger.run_subphase_us( + SUBPHASE_MODULE_PASSES_REACHABILITY_ALIAS_US, + _alias_pass, + ) binding_visitor = _RuntimeBindingVisitor(alias_visitor.aliases) - binding_visitor.visit(tree) + + 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 +1339,14 @@ def collect_runtime_reachability( included_routers=binding_visitor.included_routers, route_decorator_factories=binding_visitor.route_decorator_factories, ) - visitor.visit(tree) + + def _reachability_pass() -> None: + visitor.visit(tree) + + 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/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_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 = """ From 5632beab04213e7a35ca47b11add0647bd05ee07 Mon Sep 17 00:00:00 2001 From: Den Rozhnovskiy Date: Wed, 8 Jul 2026 18:03:32 +0500 Subject: [PATCH 04/18] perf(analysis): defer reachability facts to handler-node replay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During the binding AST walk, capture FunctionDef/ClassDef/Assign nodes in visit order. After binding completes, emit reachability facts by replaying _apply_handler_node on that list instead of a third full generic_visit pass. Alias pass stays separate so import aliases are complete before binding. Strict cold-cache A/B (same worktree, files_timed=769): - phase_module_passes: 1872.8 ms → 1795.5 ms (-77 ms, -4.1%) - reachability visit subphase: 396.4 ms → 384.3 ms (-12 ms, -3.0%) - cli.analyze: 3673 ms → 3606 ms (-67 ms, -1.8%) Verification: reachability tests + goldens green. --- codeclone/analysis/reachability.py | 67 +++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/codeclone/analysis/reachability.py b/codeclone/analysis/reachability.py index 2021efa2..d621e713 100644 --- a/codeclone/analysis/reachability.py +++ b/codeclone/analysis/reachability.py @@ -411,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 @@ -720,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: @@ -1321,7 +1350,11 @@ def _alias_pass() -> None: SUBPHASE_MODULE_PASSES_REACHABILITY_ALIAS_US, _alias_pass, ) - binding_visitor = _RuntimeBindingVisitor(alias_visitor.aliases) + handler_nodes: list[ast.AST] = [] + binding_visitor = _RuntimeBindingVisitor( + alias_visitor.aliases, + handler_nodes=handler_nodes, + ) def _binding_pass() -> None: binding_visitor.visit(tree) @@ -1339,9 +1372,11 @@ def _binding_pass() -> None: included_routers=binding_visitor.included_routers, route_decorator_factories=binding_visitor.route_decorator_factories, ) + apply_handler_node = visitor._apply_handler_node def _reachability_pass() -> None: - visitor.visit(tree) + for node in handler_nodes: + apply_handler_node(node) phase_ledger.run_subphase_us( SUBPHASE_MODULE_PASSES_REACHABILITY_VISIT_US, From 438b236c4475b5e8d722e5c46e9b52c209952c06 Mon Sep 17 00:00:00 2001 From: Den Rozhnovskiy Date: Wed, 8 Jul 2026 23:30:12 +0500 Subject: [PATCH 05/18] fix(docs): recreate docs/README-pypi.md for PyPI long description --- docs/README-pypi.md | 103 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 docs/README-pypi.md diff --git a/docs/README-pypi.md b/docs/README-pypi.md new file mode 100644 index 00000000..8918bdb4 --- /dev/null +++ b/docs/README-pypi.md @@ -0,0 +1,103 @@ +

+ + + + CodeClone + +

+ +

+ Deterministic Structural Change Controller for AI-assisted Python development +

+ +

+ PyPI + Python + Tests +

+ +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, public API + inventory, and coverage joins, 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. From e73d57d7bb89c8a8ee9bdc6235853b9ec632bcd8 Mon Sep 17 00:00:00 2001 From: Den Rozhnovskiy Date: Wed, 8 Jul 2026 23:30:16 +0500 Subject: [PATCH 06/18] fix(docs): repoint dead docs-site links in root README to current IA --- README.md | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 39de5d21..673aaeb4 100644 --- a/README.md +++ b/README.md @@ -162,8 +162,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 +194,9 @@ 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/) · +[Metrics and quality gates](https://orenlab.github.io/codeclone/guides/ci-integration/) · +[GitHub Action documentation](https://orenlab.github.io/codeclone/guides/ci-integration/) ## How CodeClone differs @@ -225,17 +225,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. @@ -275,7 +275,7 @@ 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. -[Read the Structural Change Controller guide](https://orenlab.github.io/codeclone/book/12-structural-change-controller/) +[Read the Structural Change Controller guide](https://orenlab.github.io/codeclone/concepts/controlled-change/) ## Engineering Memory — `2.1 alpha` @@ -299,8 +299,8 @@ codeclone memory search "baseline schema" --match all 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 @@ -334,10 +334,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 From 102ff7685e55d3a201eb56fe7b46e2285ea4a295 Mon Sep 17 00:00:00 2001 From: Den Rozhnovskiy Date: Wed, 8 Jul 2026 23:30:19 +0500 Subject: [PATCH 07/18] fix(claude-code): add plugin version 2.1.0a1 and repoint docs links --- plugins/claude-code-codeclone/.claude-plugin/plugin.json | 3 ++- plugins/claude-code-codeclone/README.md | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) 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/) From 42147362fd54035cdaf9e7c7590d86245939922b Mon Sep 17 00:00:00 2001 From: Den Rozhnovskiy Date: Wed, 8 Jul 2026 23:30:22 +0500 Subject: [PATCH 08/18] fix(cursor): mirror core version 2.1.0a1 and repoint docs links --- plugins/cursor-codeclone/.cursor-plugin/plugin.json | 2 +- plugins/cursor-codeclone/README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) 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/) From 67eb0fa07a4963eb5d669291bd9cb30d0020acf4 Mon Sep 17 00:00:00 2001 From: Den Rozhnovskiy Date: Wed, 8 Jul 2026 23:30:25 +0500 Subject: [PATCH 09/18] fix(codex): repoint dead docs-site links to current IA --- plugins/codeclone/.codex-plugin/plugin.json | 4 ++-- plugins/codeclone/README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) 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..f95ddc2e 100644 --- a/plugins/codeclone/README.md +++ b/plugins/codeclone/README.md @@ -114,6 +114,6 @@ own runtime via `query_platform_observability` after explicit ## 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/) From 20d061d16f20e8ca2ad43a4a8e7aca8540c2a052 Mon Sep 17 00:00:00 2001 From: Den Rozhnovskiy Date: Wed, 8 Jul 2026 23:30:27 +0500 Subject: [PATCH 10/18] fix(claude-desktop): mirror core version 2.1.0a1 and repoint docs links --- extensions/claude-desktop-codeclone/README.md | 6 +++--- extensions/claude-desktop-codeclone/manifest.json | 4 ++-- extensions/claude-desktop-codeclone/package-lock.json | 4 ++-- extensions/claude-desktop-codeclone/package.json | 2 +- extensions/claude-desktop-codeclone/test/manifest.test.js | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/extensions/claude-desktop-codeclone/README.md b/extensions/claude-desktop-codeclone/README.md index b3f88418..f50b7072 100644 --- a/extensions/claude-desktop-codeclone/README.md +++ b/extensions/claude-desktop-codeclone/README.md @@ -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 From b85ad1deb6ef878e62490f3461e9df5385bcfb3a Mon Sep 17 00:00:00 2001 From: Den Rozhnovskiy Date: Wed, 8 Jul 2026 23:30:30 +0500 Subject: [PATCH 11/18] fix(vscode): repoint dead docs-site links to current IA --- extensions/vscode-codeclone/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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://img.shields.io/github/license/orenlab/codeclone?style=flat-square&color=6366f1)](LICENSE) [![Requires CodeClone](https://img.shields.io/badge/requires-codeclone_%3E%3D2.0.0-6366f1?style=flat-square)](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/) --- From 92faf426bbc709f474795d7140574edccadf91f4 Mon Sep 17 00:00:00 2001 From: Den Rozhnovskiy Date: Wed, 8 Jul 2026 23:31:04 +0500 Subject: [PATCH 12/18] fix(docs): repoint dead docs-site link in GitHub Action README --- .github/actions/codeclone/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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/) From a2d1ee8e7da47bdcb538e85bc376fe68b229991d Mon Sep 17 00:00:00 2001 From: Den Rozhnovskiy Date: Thu, 9 Jul 2026 00:06:14 +0500 Subject: [PATCH 13/18] chore(docs): update pre-release docs --- CHANGELOG.md | 19 +++++++---- README.md | 33 ++++++++++--------- docs/README-pypi.md | 5 +-- extensions/claude-desktop-codeclone/README.md | 6 ++-- plugins/codeclone/README.md | 10 ++++++ 5 files changed, 47 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fc823ec..fab7598f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 673aaeb4..07a22b52 100644 --- a/README.md +++ b/README.md @@ -51,14 +51,14 @@ 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 | +| **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. @@ -151,12 +151,13 @@ CodeClone runs one deterministic analysis and renders the same canonical report The report covers: -- function, block, and segment clones; -- clone drift and duplicated branch families; -- complexity, coupling, cohesion, dependency cycles, and dead code; -- public API inventory and baseline-aware API break detection; -- external coverage joined with structural hotspots; -- deterministic structural health and review priorities. +- 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; +- Public API inventory and baseline-aware API break detection; +- External coverage joined with structural hotspots; +- Deterministic structural health, review priorities, and a guided, prioritized finding-review queue. ```bash codeclone . --json --html --md --sarif --text @@ -259,7 +260,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, `get_implementation_context` serves +bounded structural, call-graph, and contract context from the same analysis run, so the agent does not rediscover the +repository through broad searches. **Finish.** `finish_controlled_change`: diff --git a/docs/README-pypi.md b/docs/README-pypi.md index 8918bdb4..41d75cfa 100644 --- a/docs/README-pypi.md +++ b/docs/README-pypi.md @@ -66,8 +66,9 @@ change introduced. 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, public API - inventory, and coverage joins, rendered through CLI, HTML, JSON, Markdown, SARIF, and CI from one payload. +- **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. diff --git a/extensions/claude-desktop-codeclone/README.md b/extensions/claude-desktop-codeclone/README.md index f50b7072..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. diff --git a/plugins/codeclone/README.md b/plugins/codeclone/README.md index f95ddc2e..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,6 +119,9 @@ 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/integrations/codex/) From 876dd852dc1310e32fcaeb36fc75b50e1d86fb3a Mon Sep 17 00:00:00 2001 From: Den Rozhnovskiy Date: Thu, 9 Jul 2026 00:45:30 +0500 Subject: [PATCH 14/18] test(plugins): assert plugin manifest versions match pyproject.toml and dedupe manifest version checks via shared helper --- tests/plugin_test_helpers.py | 18 ++++++++++++++++++ tests/test_claude_code_plugin.py | 12 +++++++----- tests/test_codex_plugin.py | 20 +++++++------------- tests/test_cursor_plugin.py | 17 +---------------- 4 files changed, 33 insertions(+), 34 deletions(-) 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_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( From d0840c84bab49b46d4b0e4004eab9258c6c5d65d Mon Sep 17 00:00:00 2001 From: Den Rozhnovskiy Date: Thu, 9 Jul 2026 16:45:16 +0500 Subject: [PATCH 15/18] chore(docs): update pre-release docs --- README.md | 74 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 07a22b52..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, 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 | -| **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. @@ -151,13 +152,14 @@ CodeClone runs one deterministic analysis and renders the same canonical report The report covers: -- Function, block, and segment clones; -- Clone drift and duplicated branch families; -- Complexity, coupling, cohesion, dependency cycles, and dead code; +- 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; -- Public API inventory and baseline-aware API break detection; -- External coverage joined with structural hotspots; -- Deterministic structural health, review priorities, and a guided, prioritized finding-review queue. +- **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. ```bash codeclone . --json --html --md --sarif --text @@ -196,8 +198,7 @@ CI can reject newly introduced clones, metric regressions, API breaks, and cover existing repository to be clean first. [Baseline contract](https://orenlab.github.io/codeclone/concepts/reports/) · -[Metrics and quality gates](https://orenlab.github.io/codeclone/guides/ci-integration/) · -[GitHub Action documentation](https://orenlab.github.io/codeclone/guides/ci-integration/) +[CI integration and quality gates](https://orenlab.github.io/codeclone/guides/ci-integration/) ## How CodeClone differs @@ -218,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 @@ -260,9 +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`. While editing, `get_implementation_context` serves -bounded structural, call-graph, and contract context from the same analysis run, so the agent does not rediscover the -repository through broad searches. +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`: @@ -275,11 +280,31 @@ repository through broad searches. -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: + +- 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` Engineering Memory gives agents durable, repository-specific context without treating model output as project truth. @@ -299,6 +324,9 @@ 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. @@ -312,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`. From 2fd9c8692d529c8929698ecdadf41d5e522b64d9 Mon Sep 17 00:00:00 2001 From: Den Rozhnovskiy Date: Thu, 9 Jul 2026 19:00:51 +0500 Subject: [PATCH 16/18] fix(analytics): declare manifests dir as setuptools namespace package --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 27e42905..d5822ff1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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"] From ea1bf8509af65295140d1441f1710b0321ce894f Mon Sep 17 00:00:00 2001 From: Den Rozhnovskiy Date: Thu, 9 Jul 2026 19:08:46 +0500 Subject: [PATCH 17/18] test(packaging): discover PEP 420 data-only namespace packages --- pyproject.toml | 4 +- tests/test_packaging.py | 38 ++++- uv.lock | 355 ++++++++++++++++++++-------------------- 3 files changed, 216 insertions(+), 181 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d5822ff1..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", 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]] From 1a4f31cfd3ad5af00571e65dfee07857d098ac25 Mon Sep 17 00:00:00 2001 From: Den Rozhnovskiy Date: Thu, 9 Jul 2026 19:33:36 +0500 Subject: [PATCH 18/18] feat(release): added release date --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fab7598f..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.