hexastack-qual 0.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. hexastack_qual-0.7.0/PKG-INFO +103 -0
  2. hexastack_qual-0.7.0/README.md +82 -0
  3. hexastack_qual-0.7.0/pyproject.toml +75 -0
  4. hexastack_qual-0.7.0/pyproject.toml.orig +68 -0
  5. hexastack_qual-0.7.0/src/hexastack_qual/__init__.py +18 -0
  6. hexastack_qual-0.7.0/src/hexastack_qual/adapters/__init__.py +14 -0
  7. hexastack_qual-0.7.0/src/hexastack_qual/adapters/cqrs/__init__.py +50 -0
  8. hexastack_qual-0.7.0/src/hexastack_qual/adapters/cqrs/commands.py +88 -0
  9. hexastack_qual-0.7.0/src/hexastack_qual/adapters/cqrs/handlers.py +187 -0
  10. hexastack_qual-0.7.0/src/hexastack_qual/adapters/cqrs/queries.py +90 -0
  11. hexastack_qual-0.7.0/src/hexastack_qual/adapters/events/__init__.py +13 -0
  12. hexastack_qual-0.7.0/src/hexastack_qual/adapters/events/publisher.py +105 -0
  13. hexastack_qual-0.7.0/src/hexastack_qual/adapters/hexaqual/__init__.py +14 -0
  14. hexastack_qual-0.7.0/src/hexastack_qual/adapters/hexaqual/runner.py +628 -0
  15. hexastack_qual-0.7.0/src/hexastack_qual/adapters/mcp/__init__.py +37 -0
  16. hexastack_qual-0.7.0/src/hexastack_qual/adapters/mcp/server.py +77 -0
  17. hexastack_qual-0.7.0/src/hexastack_qual/adapters/mcp/tools.py +351 -0
  18. hexastack_qual-0.7.0/src/hexastack_qual/adapters/ui/__init__.py +13 -0
  19. hexastack_qual-0.7.0/src/hexastack_qual/adapters/ui/panel.py +88 -0
  20. hexastack_qual-0.7.0/src/hexastack_qual/domain/__init__.py +54 -0
  21. hexastack_qual-0.7.0/src/hexastack_qual/domain/events.py +93 -0
  22. hexastack_qual-0.7.0/src/hexastack_qual/domain/exceptions.py +134 -0
  23. hexastack_qual-0.7.0/src/hexastack_qual/domain/models.py +296 -0
  24. hexastack_qual-0.7.0/src/hexastack_qual/infra/__init__.py +15 -0
  25. hexastack_qual-0.7.0/src/hexastack_qual/infra/bootstrap.py +117 -0
  26. hexastack_qual-0.7.0/src/hexastack_qual/infra/cli.py +75 -0
  27. hexastack_qual-0.7.0/src/hexastack_qual/ports/__init__.py +20 -0
  28. hexastack_qual-0.7.0/src/hexastack_qual/ports/auditor.py +122 -0
  29. hexastack_qual-0.7.0/src/hexastack_qual/ports/diagnostics.py +55 -0
  30. hexastack_qual-0.7.0/src/hexastack_qual/ports/mutator.py +66 -0
  31. hexastack_qual-0.7.0/src/hexastack_qual/ports/openssf.py +109 -0
@@ -0,0 +1,103 @@
1
+ Metadata-Version: 2.4
2
+ Name: hexastack-qual
3
+ Version: 0.7.0
4
+ Summary: Hexagonal quality, governance, and release adapter integrating hexaqual with CQRS, MCP, UI, and Events
5
+ Author: Richard West
6
+ Author-email: Richard West <dopplereffect.us@gmail.com>
7
+ License-Expression: Apache-2.0
8
+ Requires-Dist: hexaqual[all]>=0.9.0
9
+ Requires-Dist: hexastack-core
10
+ Requires-Dist: hexastack-cqrs
11
+ Requires-Dist: hexastack-qual[events,mcp,ui] ; extra == 'all'
12
+ Requires-Dist: hexastack-events ; extra == 'events'
13
+ Requires-Dist: hexastack-mcp ; extra == 'mcp'
14
+ Requires-Dist: hexastack-ui ; extra == 'ui'
15
+ Requires-Python: >=3.13
16
+ Provides-Extra: all
17
+ Provides-Extra: events
18
+ Provides-Extra: mcp
19
+ Provides-Extra: ui
20
+ Description-Content-Type: text/markdown
21
+
22
+ # hexastack-qual
23
+
24
+ > 🛡️ **Hexagonal quality, governance, and release adapter integrating hexaqual with CQRS, MCP, UI, and Events.**
25
+
26
+ Part of the [Hexastack](https://dopplereffect.us/hexastack/) ecosystem.
27
+
28
+ ---
29
+
30
+ ## 🌟 Overview
31
+
32
+ `hexastack-qual` bridges [**Hexaqual**](https://github.com/TheTrueSCU/hexaqual) into Hexastack applications:
33
+ - **CQRS Execution Pipeline**: Execute sanity checks, statement formatting, and mutant audits via decoupled `Command` and `Query` objects with full OpenTelemetry tracing and structured logging.
34
+ - **Model Context Protocol (MCP)**: Expose `@mcp_tool` and `@mcp_resource` endpoints for AI coding assistants (Claude Desktop, Cursor, Antigravity) to audit complexity, test parity, and mutant resilience.
35
+ - **DevTools Console Panel**: Mount a reactive NiceGUI dashboard in `/devtools` showing live quality gauges and one-click remediation actions.
36
+ - **Distributed Event Publishing**: Emit domain events (`QualityGateFailedEvent`, `CriticalMutantSurvivingEvent`) over `hexastack-events` to Apprise or NATS.
37
+
38
+ ---
39
+
40
+ ## 📦 Installation
41
+
42
+ ```bash
43
+ # Core adapter (CQRS pipeline + Hexaqual runner)
44
+ pip install hexastack-qual
45
+
46
+ # With Model Context Protocol (MCP) server support
47
+ pip install "hexastack-qual[mcp]"
48
+
49
+ # With NiceGUI DevTools console tab
50
+ pip install "hexastack-qual[ui]"
51
+
52
+ # With distributed event publishing
53
+ pip install "hexastack-qual[events]"
54
+
55
+ # All extras
56
+ pip install "hexastack-qual[all]"
57
+ ```
58
+
59
+ ---
60
+
61
+ ## 🚀 Quickstart
62
+
63
+ ### 1. CQRS Pipeline Execution
64
+
65
+ ```python
66
+ from hexastack_cqrs.infra.pipeline import ExecutionPipeline
67
+ from hexastack_qual.adapters.cqrs.commands import RunSanityCheckCommand
68
+ from hexastack_qual.adapters.cqrs.queries import GetQualityScorecardQuery
69
+
70
+ # Dispatch queries and commands via the CQRS pipeline
71
+ scorecard = await pipeline.execute(GetQualityScorecardQuery(package="core"))
72
+ print(
73
+ f"Healthy: {scorecard.is_healthy}, Violations: {len(scorecard.complexity_violations)}"
74
+ )
75
+
76
+ result = await pipeline.execute(RunSanityCheckCommand(package="core", skip_tests=True))
77
+ print(f"Sanity status: {result.success}")
78
+ ```
79
+
80
+ ### 2. Exposing Quality over MCP
81
+
82
+ ```python
83
+ from hexastack_qual.adapters.mcp import get_quality_tools
84
+
85
+ # Attach quality inspection tools to an AI agent
86
+ agent = create_cqrs_agent(
87
+ pipeline=pipeline,
88
+ tools=get_quality_tools(),
89
+ system_prompt="You are an autonomous refactoring agent with self-verification tools.",
90
+ )
91
+ ```
92
+
93
+ ---
94
+
95
+ ## 🏛️ Architecture
96
+
97
+ ```
98
+ hexastack_qual/
99
+ ├── domain/ # Pure models (QualityScorecard, ComplexityMetric), exceptions, and events
100
+ ├── ports/ # QualityAuditorPort, MutationInspectorPort, PrDiagnosticPort
101
+ ├── adapters/ # Hexaqual runner, CQRS handlers, MCP tools, NiceGUI panel, Events publisher
102
+ └── infra/ # QualBootstrapper (DI container registration) and Typer CLI
103
+ ```
@@ -0,0 +1,82 @@
1
+ # hexastack-qual
2
+
3
+ > 🛡️ **Hexagonal quality, governance, and release adapter integrating hexaqual with CQRS, MCP, UI, and Events.**
4
+
5
+ Part of the [Hexastack](https://dopplereffect.us/hexastack/) ecosystem.
6
+
7
+ ---
8
+
9
+ ## 🌟 Overview
10
+
11
+ `hexastack-qual` bridges [**Hexaqual**](https://github.com/TheTrueSCU/hexaqual) into Hexastack applications:
12
+ - **CQRS Execution Pipeline**: Execute sanity checks, statement formatting, and mutant audits via decoupled `Command` and `Query` objects with full OpenTelemetry tracing and structured logging.
13
+ - **Model Context Protocol (MCP)**: Expose `@mcp_tool` and `@mcp_resource` endpoints for AI coding assistants (Claude Desktop, Cursor, Antigravity) to audit complexity, test parity, and mutant resilience.
14
+ - **DevTools Console Panel**: Mount a reactive NiceGUI dashboard in `/devtools` showing live quality gauges and one-click remediation actions.
15
+ - **Distributed Event Publishing**: Emit domain events (`QualityGateFailedEvent`, `CriticalMutantSurvivingEvent`) over `hexastack-events` to Apprise or NATS.
16
+
17
+ ---
18
+
19
+ ## 📦 Installation
20
+
21
+ ```bash
22
+ # Core adapter (CQRS pipeline + Hexaqual runner)
23
+ pip install hexastack-qual
24
+
25
+ # With Model Context Protocol (MCP) server support
26
+ pip install "hexastack-qual[mcp]"
27
+
28
+ # With NiceGUI DevTools console tab
29
+ pip install "hexastack-qual[ui]"
30
+
31
+ # With distributed event publishing
32
+ pip install "hexastack-qual[events]"
33
+
34
+ # All extras
35
+ pip install "hexastack-qual[all]"
36
+ ```
37
+
38
+ ---
39
+
40
+ ## 🚀 Quickstart
41
+
42
+ ### 1. CQRS Pipeline Execution
43
+
44
+ ```python
45
+ from hexastack_cqrs.infra.pipeline import ExecutionPipeline
46
+ from hexastack_qual.adapters.cqrs.commands import RunSanityCheckCommand
47
+ from hexastack_qual.adapters.cqrs.queries import GetQualityScorecardQuery
48
+
49
+ # Dispatch queries and commands via the CQRS pipeline
50
+ scorecard = await pipeline.execute(GetQualityScorecardQuery(package="core"))
51
+ print(
52
+ f"Healthy: {scorecard.is_healthy}, Violations: {len(scorecard.complexity_violations)}"
53
+ )
54
+
55
+ result = await pipeline.execute(RunSanityCheckCommand(package="core", skip_tests=True))
56
+ print(f"Sanity status: {result.success}")
57
+ ```
58
+
59
+ ### 2. Exposing Quality over MCP
60
+
61
+ ```python
62
+ from hexastack_qual.adapters.mcp import get_quality_tools
63
+
64
+ # Attach quality inspection tools to an AI agent
65
+ agent = create_cqrs_agent(
66
+ pipeline=pipeline,
67
+ tools=get_quality_tools(),
68
+ system_prompt="You are an autonomous refactoring agent with self-verification tools.",
69
+ )
70
+ ```
71
+
72
+ ---
73
+
74
+ ## 🏛️ Architecture
75
+
76
+ ```
77
+ hexastack_qual/
78
+ ├── domain/ # Pure models (QualityScorecard, ComplexityMetric), exceptions, and events
79
+ ├── ports/ # QualityAuditorPort, MutationInspectorPort, PrDiagnosticPort
80
+ ├── adapters/ # Hexaqual runner, CQRS handlers, MCP tools, NiceGUI panel, Events publisher
81
+ └── infra/ # QualBootstrapper (DI container registration) and Typer CLI
82
+ ```
@@ -0,0 +1,75 @@
1
+ [project]
2
+ name = "hexastack-qual"
3
+ version = "0.7.0"
4
+ description = "Hexagonal quality, governance, and release adapter integrating hexaqual with CQRS, MCP, UI, and Events"
5
+ readme = "README.md"
6
+ license = "Apache-2.0"
7
+ requires-python = ">=3.13"
8
+ dependencies = [
9
+ "hexaqual[all]>=0.9.0",
10
+ "hexastack-core",
11
+ "hexastack-cqrs",
12
+ ]
13
+
14
+ [[project.authors]]
15
+ name = "Richard West"
16
+ email = "dopplereffect.us@gmail.com"
17
+
18
+ [project.optional-dependencies]
19
+ events = ["hexastack-events"]
20
+ mcp = ["hexastack-mcp"]
21
+ ui = ["hexastack-ui"]
22
+ all = ["hexastack-qual[events,mcp,ui]"]
23
+
24
+ [project.entry-points."hexastack.bootstrappers"]
25
+ qual = "hexastack_qual.infra.bootstrap:QualBootstrapper"
26
+
27
+ [build-system]
28
+ requires = ["uv_build>=0.12.3,<0.13.0"]
29
+ build-backend = "uv_build"
30
+
31
+ [tool.uv.sources.hexastack-core]
32
+ workspace = true
33
+
34
+ [tool.uv.sources.hexastack-cqrs]
35
+ workspace = true
36
+
37
+ [tool.uv.sources.hexastack-events]
38
+ workspace = true
39
+
40
+ [tool.uv.sources.hexastack-mcp]
41
+ workspace = true
42
+
43
+ [tool.uv.sources.hexastack-ui]
44
+ workspace = true
45
+
46
+ [tool.importlinter]
47
+ root_packages = ["hexastack_qual"]
48
+
49
+ [[tool.importlinter.contracts]]
50
+ name = "Hexagonal architecture layer hierarchy"
51
+ type = "layers"
52
+ containers = ["hexastack_qual"]
53
+ layers = [
54
+ "infra",
55
+ "adapters",
56
+ "ports",
57
+ "domain",
58
+ ]
59
+
60
+ [tool.mutmut]
61
+ runner = 'pytest -x --assert=plain -o addopts=""'
62
+ paths_to_mutate = "src"
63
+
64
+ [tool.pytest-gremlins]
65
+ paths = ["src"]
66
+ operators = [
67
+ "arithmetic",
68
+ "boolean",
69
+ "boundary",
70
+ "comparison",
71
+ "return",
72
+ ]
73
+ workers = "auto"
74
+ batch_size = 10
75
+ cache = true
@@ -0,0 +1,68 @@
1
+ [project]
2
+ name = "hexastack-qual"
3
+ version = "0.7.0"
4
+ description = "Hexagonal quality, governance, and release adapter integrating hexaqual with CQRS, MCP, UI, and Events"
5
+ readme = "README.md"
6
+ license = "Apache-2.0"
7
+ authors = [
8
+ { name = "Richard West", email = "dopplereffect.us@gmail.com" }
9
+ ]
10
+ requires-python = ">=3.13"
11
+ dependencies = [
12
+ "hexaqual[all]>=0.9.0",
13
+ "hexastack-core",
14
+ "hexastack-cqrs",
15
+ ]
16
+
17
+ [project.optional-dependencies]
18
+ events = [
19
+ "hexastack-events",
20
+ ]
21
+ mcp = [
22
+ "hexastack-mcp",
23
+ ]
24
+ ui = [
25
+ "hexastack-ui",
26
+ ]
27
+ all = [
28
+ "hexastack-qual[events,mcp,ui]",
29
+ ]
30
+
31
+ [project.entry-points."hexastack.bootstrappers"]
32
+ qual = "hexastack_qual.infra.bootstrap:QualBootstrapper"
33
+
34
+ [build-system]
35
+ requires = ["uv_build>=0.12.3,<0.13.0"]
36
+ build-backend = "uv_build"
37
+
38
+ [tool.uv.sources]
39
+ hexastack-core = { workspace = true }
40
+ hexastack-cqrs = { workspace = true }
41
+ hexastack-events = { workspace = true }
42
+ hexastack-mcp = { workspace = true }
43
+ hexastack-ui = { workspace = true }
44
+
45
+ [tool.importlinter]
46
+ root_packages = ["hexastack_qual"]
47
+
48
+ [[tool.importlinter.contracts]]
49
+ name = "Hexagonal architecture layer hierarchy"
50
+ type = "layers"
51
+ containers = ["hexastack_qual"]
52
+ layers = [
53
+ "infra",
54
+ "adapters",
55
+ "ports",
56
+ "domain",
57
+ ]
58
+
59
+ [tool.mutmut]
60
+ runner = "pytest -x --assert=plain -o addopts=\"\""
61
+ paths_to_mutate = "src"
62
+
63
+ [tool.pytest-gremlins]
64
+ paths = ["src"]
65
+ operators = ["arithmetic", "boolean", "boundary", "comparison", "return"]
66
+ workers = "auto"
67
+ batch_size = 10
68
+ cache = true
@@ -0,0 +1,18 @@
1
+ """Hexastack Quality & Governance Adapter.
2
+
3
+ Bridges the Hexaqual engine into Hexastack applications, providing CQRS
4
+ dispatching, MCP server tools, reactive DevTools panels, and distributed event
5
+ publishing.
6
+
7
+ Notes/Architectural Intent:
8
+ Serves as the root package for hexastack-qual. Exports package version
9
+ and core domain models while preserving lazy loading for optional extras.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ __version__ = "0.7.0"
15
+
16
+ __all__ = [
17
+ "__version__",
18
+ ]
@@ -0,0 +1,14 @@
1
+ """Adapters for hexastack-qual.
2
+
3
+ Notes/Architectural Intent:
4
+ Houses concrete adapters for Hexaqual engine, CQRS message handlers, MCP
5
+ tool endpoints, NiceGUI DevTools panels, and distributed event publishers.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from hexastack_qual.adapters.hexaqual.runner import HexaqualRunnerAdapter
11
+
12
+ __all__ = [
13
+ "HexaqualRunnerAdapter",
14
+ ]
@@ -0,0 +1,50 @@
1
+ """CQRS messages and handlers for hexastack-qual.
2
+
3
+ Notes/Architectural Intent:
4
+ Exports Commands, Queries, and corresponding Handlers for dispatching
5
+ quality audits through the Hexastack ExecutionPipeline.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from hexastack_qual.adapters.cqrs.commands import (
11
+ FormatStatementsCommand,
12
+ RunMutationTestingCommand,
13
+ RunSanityCheckCommand,
14
+ SyncAgentAssetsCommand,
15
+ )
16
+ from hexastack_qual.adapters.cqrs.handlers import (
17
+ FormatStatementsHandler,
18
+ GetPrHealthHandler,
19
+ GetQualityScorecardHandler,
20
+ GetTestImpactHandler,
21
+ InspectMutantsHandler,
22
+ RunMutationTestingHandler,
23
+ RunSanityCheckHandler,
24
+ SyncAgentAssetsHandler,
25
+ )
26
+ from hexastack_qual.adapters.cqrs.queries import (
27
+ GetPrHealthQuery,
28
+ GetQualityScorecardQuery,
29
+ GetTestImpactQuery,
30
+ InspectMutantsQuery,
31
+ )
32
+
33
+ __all__ = [
34
+ "FormatStatementsCommand",
35
+ "FormatStatementsHandler",
36
+ "GetPrHealthHandler",
37
+ "GetPrHealthQuery",
38
+ "GetQualityScorecardHandler",
39
+ "GetQualityScorecardQuery",
40
+ "GetTestImpactHandler",
41
+ "GetTestImpactQuery",
42
+ "InspectMutantsHandler",
43
+ "InspectMutantsQuery",
44
+ "RunMutationTestingCommand",
45
+ "RunMutationTestingHandler",
46
+ "RunSanityCheckCommand",
47
+ "RunSanityCheckHandler",
48
+ "SyncAgentAssetsCommand",
49
+ "SyncAgentAssetsHandler",
50
+ ]
@@ -0,0 +1,88 @@
1
+ """CQRS commands for hexastack-qual.
2
+
3
+ Notes/Architectural Intent:
4
+ Encapsulates state-changing intent: running sanity gates, auto-fixing
5
+ statements, executing mutation tests, and syncing agent assets.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from pydantic import ConfigDict, Field
11
+
12
+ from hexastack_core.domain import Command
13
+
14
+
15
+ class RunSanityCheckCommand(Command):
16
+ """Command to execute full or scoped sanity check quality gate.
17
+
18
+ Notes/Architectural Intent:
19
+ Triggers cognitive complexity, test parity, and __all__ validation.
20
+ """
21
+
22
+ model_config = ConfigDict(frozen=True)
23
+
24
+ package: str | None = Field(
25
+ default=None,
26
+ description="Target package name or None for workspace.",
27
+ )
28
+ skip_tests: bool = Field(
29
+ default=True,
30
+ description="Whether to skip unit test suites.",
31
+ )
32
+
33
+
34
+ class FormatStatementsCommand(Command):
35
+ """Command to auto-format and sort __all__ export statements.
36
+
37
+ Notes/Architectural Intent:
38
+ Modifies target files in-place to enforce casefold ordering.
39
+ """
40
+
41
+ model_config = ConfigDict(frozen=True)
42
+
43
+ package: str | None = Field(
44
+ default=None,
45
+ description="Target package name or None for workspace.",
46
+ )
47
+
48
+
49
+ class RunMutationTestingCommand(Command):
50
+ """Command to execute mutation testing across target components.
51
+
52
+ Notes/Architectural Intent:
53
+ Executes mutmut runner and compiles surviving mutant scorecards.
54
+ """
55
+
56
+ model_config = ConfigDict(frozen=True)
57
+
58
+ package: str | None = Field(
59
+ default=None,
60
+ description="Target package name or None for workspace.",
61
+ )
62
+ reset: bool = Field(
63
+ default=False,
64
+ description="Whether to clear existing mutation cache before running.",
65
+ )
66
+
67
+
68
+ class SyncAgentAssetsCommand(Command):
69
+ """Command to re-synchronize universal AI agent rules and workflows.
70
+
71
+ Notes/Architectural Intent:
72
+ Materializes latest hexaqual agent assets into .agents/.
73
+ """
74
+
75
+ model_config = ConfigDict(frozen=True)
76
+
77
+ dry_run: bool = Field(
78
+ default=False,
79
+ description="If True, verifies sync without writing files.",
80
+ )
81
+
82
+
83
+ __all__ = [
84
+ "FormatStatementsCommand",
85
+ "RunMutationTestingCommand",
86
+ "RunSanityCheckCommand",
87
+ "SyncAgentAssetsCommand",
88
+ ]
@@ -0,0 +1,187 @@
1
+ """CQRS command and query handlers for hexastack-qual.
2
+
3
+ Notes/Architectural Intent:
4
+ Connects CQRS message dispatching to QualityAuditorPort, MutationInspectorPort,
5
+ and PrDiagnosticPort, with optional event emission across EventBusPort.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from typing import TYPE_CHECKING
11
+
12
+ from hexaqual.adapters.agents import FileSystemAgentAssetAdapter
13
+ from hexaqual.adapters.workspace import get_repo_root
14
+
15
+ from hexastack_qual.adapters.cqrs.commands import (
16
+ FormatStatementsCommand,
17
+ RunMutationTestingCommand,
18
+ RunSanityCheckCommand,
19
+ SyncAgentAssetsCommand,
20
+ )
21
+ from hexastack_qual.adapters.cqrs.queries import (
22
+ GetPrHealthQuery,
23
+ GetQualityScorecardQuery,
24
+ GetTestImpactQuery,
25
+ InspectMutantsQuery,
26
+ )
27
+ from hexastack_qual.domain.events import (
28
+ QualityGateFailedEvent,
29
+ StatementsFixedEvent,
30
+ )
31
+ from hexastack_qual.domain.models import (
32
+ MutantReport,
33
+ PrHealthSummary,
34
+ QualityScorecard,
35
+ )
36
+
37
+ if TYPE_CHECKING:
38
+ from hexastack_cqrs.ports.buses import EventBusPort
39
+ from hexastack_qual.ports.auditor import QualityAuditorPort
40
+ from hexastack_qual.ports.diagnostics import PrDiagnosticPort
41
+ from hexastack_qual.ports.mutator import MutationInspectorPort
42
+
43
+
44
+ class RunSanityCheckHandler:
45
+ """Handler for RunSanityCheckCommand."""
46
+
47
+ def __init__(
48
+ self,
49
+ auditor: QualityAuditorPort,
50
+ event_bus: EventBusPort | None = None,
51
+ ) -> None:
52
+ """Initialize handler with auditor port and optional event bus."""
53
+ self._auditor = auditor
54
+ self._event_bus = event_bus
55
+
56
+ async def __call__(self, command: RunSanityCheckCommand) -> QualityScorecard:
57
+ """Execute sanity check and emit failure event if unhealthy."""
58
+ scorecard = self._auditor.run_sanity(
59
+ package=command.package,
60
+ skip_tests=command.skip_tests,
61
+ )
62
+ if not scorecard.is_healthy and self._event_bus:
63
+ failed_names = [
64
+ c.check_name for c in scorecard.checks if c.status == "fail"
65
+ ]
66
+ event = QualityGateFailedEvent(
67
+ target=scorecard.target,
68
+ failed_checks=failed_names,
69
+ )
70
+ await self._event_bus.publish(event)
71
+ return scorecard
72
+
73
+
74
+ class FormatStatementsHandler:
75
+ """Handler for FormatStatementsCommand."""
76
+
77
+ def __init__(
78
+ self,
79
+ auditor: QualityAuditorPort,
80
+ event_bus: EventBusPort | None = None,
81
+ ) -> None:
82
+ """Initialize handler with auditor port and optional event bus."""
83
+ self._auditor = auditor
84
+ self._event_bus = event_bus
85
+
86
+ async def __call__(self, command: FormatStatementsCommand) -> int:
87
+ """Fix statement formatting and emit event if files modified."""
88
+ modified_count = self._auditor.fix_statements(package=command.package)
89
+ if modified_count > 0 and self._event_bus:
90
+ event = StatementsFixedEvent(
91
+ target=command.package or "workspace",
92
+ files_modified=modified_count,
93
+ )
94
+ await self._event_bus.publish(event)
95
+ return modified_count
96
+
97
+
98
+ class RunMutationTestingHandler:
99
+ """Handler for RunMutationTestingCommand."""
100
+
101
+ def __init__(self, mutator: MutationInspectorPort) -> None:
102
+ """Initialize handler with mutation inspector port."""
103
+ self._mutator = mutator
104
+
105
+ async def __call__(self, command: RunMutationTestingCommand) -> MutantReport:
106
+ """Execute mutation testing runner."""
107
+ return self._mutator.run_mutation_testing(
108
+ package=command.package,
109
+ reset=command.reset,
110
+ )
111
+
112
+
113
+ class SyncAgentAssetsHandler:
114
+ """Handler for SyncAgentAssetsCommand."""
115
+
116
+ async def __call__(self, command: SyncAgentAssetsCommand) -> int:
117
+ """Synchronize universal AI agent rules and workflows."""
118
+ root = get_repo_root()
119
+ adapter = FileSystemAgentAssetAdapter()
120
+ res = adapter.sync_assets(root, dry_run=command.dry_run)
121
+ return res.created_count + res.updated_count
122
+
123
+
124
+ class GetQualityScorecardHandler:
125
+ """Handler for GetQualityScorecardQuery."""
126
+
127
+ def __init__(self, auditor: QualityAuditorPort) -> None:
128
+ """Initialize handler with auditor port."""
129
+ self._auditor = auditor
130
+
131
+ async def __call__(self, query: GetQualityScorecardQuery) -> QualityScorecard:
132
+ """Execute sanity check and return scorecard."""
133
+ return self._auditor.run_sanity(
134
+ package=query.package,
135
+ skip_tests=query.skip_tests,
136
+ )
137
+
138
+
139
+ class InspectMutantsHandler:
140
+ """Handler for InspectMutantsQuery."""
141
+
142
+ def __init__(self, mutator: MutationInspectorPort) -> None:
143
+ """Initialize handler with mutator port."""
144
+ self._mutator = mutator
145
+
146
+ async def __call__(self, query: InspectMutantsQuery) -> MutantReport:
147
+ """Inspect surviving mutants."""
148
+ return self._mutator.inspect_surviving_mutants(
149
+ package=query.package,
150
+ actionable_only=query.actionable_only,
151
+ )
152
+
153
+
154
+ class GetTestImpactHandler:
155
+ """Handler for GetTestImpactQuery."""
156
+
157
+ def __init__(self, diagnostics: PrDiagnosticPort) -> None:
158
+ """Initialize handler with diagnostics port."""
159
+ self._diagnostics = diagnostics
160
+
161
+ async def __call__(self, query: GetTestImpactQuery) -> list[str]:
162
+ """Compute impacted test suites."""
163
+ return self._diagnostics.get_test_impact(base_ref=query.base_ref)
164
+
165
+
166
+ class GetPrHealthHandler:
167
+ """Handler for GetPrHealthQuery."""
168
+
169
+ def __init__(self, diagnostics: PrDiagnosticPort) -> None:
170
+ """Initialize handler with diagnostics port."""
171
+ self._diagnostics = diagnostics
172
+
173
+ async def __call__(self, query: GetPrHealthQuery) -> PrHealthSummary:
174
+ """Inspect pull request diagnostic health."""
175
+ return self._diagnostics.get_pr_health(pr_number=query.pr_number)
176
+
177
+
178
+ __all__ = [
179
+ "FormatStatementsHandler",
180
+ "GetPrHealthHandler",
181
+ "GetQualityScorecardHandler",
182
+ "GetTestImpactHandler",
183
+ "InspectMutantsHandler",
184
+ "RunMutationTestingHandler",
185
+ "RunSanityCheckHandler",
186
+ "SyncAgentAssetsHandler",
187
+ ]