diff --git a/CHANGELOG.md b/CHANGELOG.md
index dd198b1..5d009ec 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,7 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
-- Registering a command outside WP-CLI throws the named `WpCliUnavailable` exception instead of a bare `\RuntimeException`. It extends `\RuntimeException`, and the message keeps its `WP-CLI is not available` prefix, followed by how to avoid it
+- `WpCliService` now depends on the new `WpCliAdapterInterface` contract (implemented by `WpCliAdapter`) instead of the concrete adapter, so that the application layer no longer depends on the infrastructure layer. Passing a `WpCliAdapter` keeps working
+- Registering a command outside WP-CLI throws the named `WpCliUnavailableException` exception instead of a bare `\RuntimeException`. It extends `\RuntimeException`, and the message keeps its `WP-CLI is not available` prefix, followed by how to avoid it
## [0.1.1] - 2026-10-13
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index bf62396..1c4e8b0 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -8,6 +8,9 @@
tests/Unit
+
+ tests/Arch.php
+
diff --git a/src/Application/Services/WpCliService.php b/src/Application/Services/WpCliService.php
index 21a9bb0..dac2785 100644
--- a/src/Application/Services/WpCliService.php
+++ b/src/Application/Services/WpCliService.php
@@ -4,7 +4,7 @@
namespace Pollora\WpCli\Application\Services;
-use Pollora\WpCli\Infrastructure\Adapters\WpCliAdapter;
+use Pollora\WpCli\Domain\Contracts\WpCliAdapterInterface;
use Psr\Log\LoggerInterface;
use WP_CLI;
@@ -23,7 +23,7 @@ class WpCliService
private array $registeredCommands = [];
public function __construct(
- private readonly WpCliAdapter $wpCliAdapter,
+ private readonly WpCliAdapterInterface $wpCliAdapter,
private readonly ?LoggerInterface $logger = null
) {}
diff --git a/src/Domain/Contracts/WpCliAdapterInterface.php b/src/Domain/Contracts/WpCliAdapterInterface.php
new file mode 100644
index 0000000..ece8325
--- /dev/null
+++ b/src/Domain/Contracts/WpCliAdapterInterface.php
@@ -0,0 +1,28 @@
+ $args Additional arguments for WP-CLI
+ *
+ * @throws \RuntimeException If WP-CLI is not available
+ * @throws \InvalidArgumentException If the handler is invalid
+ */
+ public function addCommand(string $name, string|array|object $handler, array $args = []): void;
+}
diff --git a/src/Domain/Exceptions/WpCliUnavailable.php b/src/Domain/Exceptions/WpCliUnavailableException.php
similarity index 86%
rename from src/Domain/Exceptions/WpCliUnavailable.php
rename to src/Domain/Exceptions/WpCliUnavailableException.php
index 58c9273..2acab84 100644
--- a/src/Domain/Exceptions/WpCliUnavailable.php
+++ b/src/Domain/Exceptions/WpCliUnavailableException.php
@@ -9,7 +9,7 @@
/**
* Thrown when a command is registered outside a WP-CLI process.
*/
-final class WpCliUnavailable extends RuntimeException
+final class WpCliUnavailableException extends RuntimeException
{
public static function whenRegisteringACommand(): self
{
diff --git a/src/Infrastructure/Adapters/WpCliAdapter.php b/src/Infrastructure/Adapters/WpCliAdapter.php
index a8e1d37..d2472c0 100644
--- a/src/Infrastructure/Adapters/WpCliAdapter.php
+++ b/src/Infrastructure/Adapters/WpCliAdapter.php
@@ -4,7 +4,8 @@
namespace Pollora\WpCli\Infrastructure\Adapters;
-use Pollora\WpCli\Domain\Exceptions\WpCliUnavailable;
+use Pollora\WpCli\Domain\Contracts\WpCliAdapterInterface;
+use Pollora\WpCli\Domain\Exceptions\WpCliUnavailableException;
use WP_CLI;
/**
@@ -14,7 +15,7 @@
* providing a clean interface that respects hexagonal architecture
* by isolating external dependencies in the infrastructure layer.
*/
-final class WpCliAdapter
+final class WpCliAdapter implements WpCliAdapterInterface
{
/**
* Check if WP-CLI is available.
@@ -37,7 +38,7 @@ public function isAvailable(): bool
public function addCommand(string $name, string|array|object $handler, array $args = []): void
{
if (! $this->isAvailable()) {
- throw WpCliUnavailable::whenRegisteringACommand();
+ throw WpCliUnavailableException::whenRegisteringACommand();
}
$this->validateHandler($handler);
diff --git a/tests/Unit/Domain/Exceptions/WpCliUnavailableTest.php b/tests/Unit/Domain/Exceptions/WpCliUnavailableExceptionTest.php
similarity index 70%
rename from tests/Unit/Domain/Exceptions/WpCliUnavailableTest.php
rename to tests/Unit/Domain/Exceptions/WpCliUnavailableExceptionTest.php
index eb5d259..b361330 100644
--- a/tests/Unit/Domain/Exceptions/WpCliUnavailableTest.php
+++ b/tests/Unit/Domain/Exceptions/WpCliUnavailableExceptionTest.php
@@ -2,10 +2,10 @@
declare(strict_types=1);
-use Pollora\WpCli\Domain\Exceptions\WpCliUnavailable;
+use Pollora\WpCli\Domain\Exceptions\WpCliUnavailableException;
it('says WP-CLI is missing and what to do about it', function (): void {
- $exception = WpCliUnavailable::whenRegisteringACommand();
+ $exception = WpCliUnavailableException::whenRegisteringACommand();
expect($exception)->toBeInstanceOf(RuntimeException::class)
->and($exception->getMessage())->toStartWith('WP-CLI is not available')