TaskerBridges/NOTES.md

175 lines
12 KiB
Markdown
Raw Normal View History

# TaskerBridges: Phred CLI Interoperability Adapters
TaskerBridges is the adapter layer that allows commands written against `Phred\ConsoleContracts` to run inside multiple CLI runtimes with a native experience. Bridges translate Phred's runner-agnostic contracts into the APIs of specific console toolkits.
Project Phase: Idea (NOTES.md)
## 1. Core Vision
- Interoperability first: Write a command once, run it anywhere (Tasker native runner, Symfony Console, Laravel Artisan, etc.).
- Contracts-driven: Bridges never change command code; they only adapt `ConsoleContracts` to the target runtime.
- Minimal footprint: Optional, per-bridge dependencies and lazy wiring. No heavy transitive dependencies for users who don't need a given bridge.
- Native UX: When running under a given toolkit, output, helpers, and ergonomics should feel native to that toolkit.
## 2. Scope & Responsibilities
Bridges provide a cohesive set of adapters:
- Command adapter: Wraps `CommandInterface` and exposes a native command entrypoint.
- IO adapters: Implement `InputInterface`/`OutputInterface` on top of the target toolkits input/output.
- Helper adapters: Implement optional helper contracts (`InteractionInterface`, `ProgressBarInterface`, `TableInterface`, `MarkdownConverterInterface`).
- Markup translator: Converts Phreds fixed markup tags (`<success>`, `<info>`, `<error>`, `<warning>`, `<comment>`, `<b>`, `<i>`, `<u>`) to the target toolkits styles or to raw ANSI.
- Policy alignment: Honor `Verbosity` levels, non-interactive mode, TTY/color detection, and `sysexits.h` exit code semantics.
Non-goals:
- Defining new business logic or command semantics.
- Extending the fixed markup set (bridges must support the core set only).
## 3. Supported Bridges (Initial Set)
- SymfonyBridge: Adapter for `symfony/console` (targeting Symfony 6/7 lines).
- PhredBridge (Native): Minimal adapters used by the Tasker core runner.
- LaravelBridge: Adapter for Laravel's Artisan console (`illuminate/console`).
### 3.1 Future / Potential Bridges (Roadmap)
The following bridges are identified as high-value for future development or upon community request:
- **LaminasBridge**: Adapter for `laminas/laminas-cli`.
- **CakePHPBridge**: Adapter for the CakePHP Console/Shell ecosystem.
- **YiiBridge**: Adapter for Yii 2.0 console commands (Note: Yii 3.0 uses `symfony/console` and may be covered by `SymfonyBridge`).
- **AuraCliBridge**: Adapter for `Aura.Cli` for users of the Aura library suite.
- **RichOutputBridge**: A bridge leveraging a library like `CLImate` for advanced terminal UI features (colors, progress bars) when the native Phred runner is used.
Each bridge lives under `Phred\TaskerBridges\{BridgeName}\...` and can be installed/used independently via Composer suggests.
## 4. SymfonyBridge — Design
### 4.1 High-Level Mapping
- Command metadata
- `CommandInterface::getName()` -> `Symfony\Component\Console\Command\Command::setName()`
- `getDescription()` -> `setDescription()`
- `getArguments()` -> loop `addArgument($name, InputArgument::OPTIONAL|REQUIRED, $description, $default)`
- `getOptions()` -> loop `addOption($name, $shortcut, InputOption::VALUE_NONE|VALUE_OPTIONAL|VALUE_REQUIRED, $description, $default)`
- Note: `ConsoleContracts` currently models arguments/options as `name => description` (DX-minimal). Bridge MAY enhance by honoring defaults/modes if/when added to contracts in future specs.
- Execution
- The adapter class (e.g., `SymfonyCommandAdapter`) extends `Symfony\Component\Console\Command\Command` and wraps a `CommandInterface` instance.
- In `execute(InputInterface $in, OutputInterface $out)`, it:
1) Adapts Symfony input/output to Phred `InputInterface`/`OutputInterface` via IO adapters.
2) Invokes `$wrapped->execute($phredInput, $phredOutput)`.
3) Returns the integer exit code from the wrapped command.
### 4.2 IO Adapters
- `SymfonyInputAdapter` implements `GetPhred\ConsoleContracts\InputInterface` by delegating to `Symfony\Component\Console\Input\InputInterface` methods (`getArgument`, `getOption`, `hasOption`).
- `SymfonyOutputAdapter` implements `GetPhred\ConsoleContracts\OutputInterface` by delegating to `Symfony\Component\Console\Output\OutputInterface`/`Style` and applying markup translation.
Verbosity mapping:
- Phred `Verbosity::QUIET|NORMAL|VERBOSE|VERY_VERBOSE|DEBUG` <-> Symfony `OutputInterface::VERBOSITY_*`.
Non-interactive:
- Respect a runner-provided flag; adapters should avoid prompts and ensure helpers also respect non-interactive mode.
### 4.3 Markup Translation (Fixed Set)
- Translate Phred tags into Symfony formatter equivalents or raw ANSI where Symfony lacks a native tag.
- `<success>` -> Symfony style (green, bold) using `SymfonyStyle` or custom formatter style.
- `<info>` -> Symfony `<info>` (blue where applicable) or custom style to match Phreds blue guideline.
- `<error>` -> white on red background.
- `<warning>` -> black on yellow background.
- `<comment>` -> yellow.
- `<b>` -> bold; `<i>` -> italic; `<u>` -> underline (use ANSI sequences if formatter lacks direct styles).
- If output is not decorated (no TTY or colors disabled), strip tags to plain text.
### 4.4 Helper Adapters
- `InteractionInterface` -> wrap `QuestionHelper` (ask, confirm, secret, choice), ensuring non-interactive fallback behavior (return defaults, never block).
- `ProgressBarInterface` -> wrap `Symfony\Component\Console\Helper\ProgressBar`.
- `TableInterface` -> wrap `Symfony\Component\Console\Helper\Table`.
- `MarkdownConverterInterface` -> use a lightweight adapter strategy:
- Prefer Symfony-native formatting if available; otherwise convert Markdown to Phred markup (headings -> `<b>`, emphasis -> `<i>`/`<b>`, links -> underline/text), then pass through normal markup translation.
### 4.5 Error & Exit Codes
- Return integer exit codes from wrapped command directly.
- Exceptions: Allow the runner to handle globally; optionally map known `ConsoleExceptionInterface` to `ExitCode::USAGE|CONFIG|UNAVAILABLE|SOFTWARE` as appropriate.
## 5. PhredBridge (Native) — Design
- Provide minimal in-house adapters usable by the Tasker runner.
- `PhredOutputAdapter`: translates fixed markup to ANSI escape sequences:
- `<success>` -> green (e.g., `\e[32m`), `<info>` -> blue (`\e[34m`), `<error>` -> white on red (`\e[97;41m`), `<warning>` -> black on yellow (`\e[30;43m`), `<comment>` -> yellow (`\e[33m`), `<b>` -> bold (`\e[1m`), `<i>` -> italic (`\e[3m`), `<u>` -> underline (`\e[4m`). Reset with `\e[0m`.
- TTY detection and `--no-interaction`/`--no-ansi` handling (strip tags when colors disabled or piping to files).
- Provide simple `InteractionInterface`, `ProgressBarInterface`, `TableInterface`, and `MarkdownConverterInterface` implementations with zero external dependencies (basic, but reliable).
## 6. LaravelBridge — Design
### 6.1 Registration & Discovery
- Provide a `TaskerServiceProvider` for Laravel applications.
- Leverage Laravel Package Auto-Discovery via `composer.json` to register the provider automatically.
- The provider will:
- Discover Phred commands via `extra.phred-tasker` or explicit container binding.
- Register them with the Artisan application.
- Provide configuration for non-interactive defaults and formatting.
### 6.2 Container & Execution
- Resolve `CommandInterface` instances via the Laravel Service Container (`app()`), favoring constructor injection.
- Wrap commands in a `LaravelCommandAdapter` that extends `Illuminate\Console\Command`.
- Delegate execution and return integer exit codes.
### 6.3 IO & Markup
- Reuse `SymfonyBridge` IO adapters internally (Artisan's IO is built on Symfony).
- Ensure Phreds fixed markup set (`<success>`, `<info>`, `<error>`, `<warning>`, `<comment>`, `<b>`, `<i>`, `<u>`) renders natively in Artisan.
### 6.4 Helper Adapters
- `InteractionInterface` -> Map to Laravel's native console methods (`ask`, `confirm`, `secret`, `choice`).
- `ProgressBarInterface` / `TableInterface` -> Reuse SymfonyBridge adapters via Artisan.
- `MarkdownConverterInterface` -> Standard Phred implementation (lightweight regex/mapping).
## 7. Dependency & Packaging Strategy
- Composer `suggest` dependencies per bridge:
- `symfony/console` for SymfonyBridge.
- `illuminate/console` for LaravelBridge.
- Hard requirements: only `php:^8.2` and `getphred/console-contracts`.
- Conditional wiring: Bridge factory/services check for class existence before enabling a bridge.
- Namespacing: `Phred\TaskerBridges\Symfony\...`, `Phred\TaskerBridges\Phred\...`, `Phred\TaskerBridges\Laravel\...`.
## 8. Registration & Discovery
- Consumers may register bridges explicitly in DI (preferred for clarity).
- For Laravel, auto-discovery via `TaskerServiceProvider` is the primary path.
- For Symfony apps, provide a small integration guide to register `SymfonyCommandAdapter` instances in the application.
- For Tasker, PhredBridge is used by default; other bridges are opt-in and instantiated only if their dependencies are present.
## 9. Middleware Compatibility
- Bridges must compose with `ConsoleMiddlewareInterface` stacks managed by the runner. The adapter boundary is after middleware resolution so that middlewares see Phred `InputInterface`/`OutputInterface` consistently.
## 10. Performance & Lazy Loading
- Metadata access should be O(1) with minimal reflection at runtime. If attributes are used (`#[Cmd]`, `#[Arg]`, `#[Opt]`) and surfaced via `HasAttributes`, bridges continue to consume only the `CommandInterface` methods — no extra reflection needed in bridges.
- For toolkits that support lazy command discovery, prefer deferring heavy initialization until execution.
### 11. Testing Strategy (for later phases)
- Unit tests: Markup translation, verbosity mapping, non-interactive behavior, helpers integration.
- Integration tests: Execute a sample Phred command through SymfonyBridge, LaravelBridge, and PhredBridge, verify identical behavior and exit codes.
## 12. Architectural Decisions (Resolved)
### 12.1 Global Options & Flags
- Bridges will map toolkit-specific flags (e.g., Symfonys `--ansi`, `--no-interaction`) to the Phred `InputInterface` and `OutputInterface` state.
- **Purity**: Commands must NOT depend on toolkit-specific options. Instead, they should rely on the standardized Phred flags:
- `-v`, `-vv`, `-vvv`, `-q` (Verbosity)
- `-n` or `--no-interaction` (Non-interactive)
- `--no-ansi` (Color/Decoration)
- **Passthrough**: Toolkit-specific global options remain at the application layer and are consumed only by the bridge to configure the IO adapters.
### 12.2 Error Mapping Policy
- Bridges are responsible for a "Standard Translation" of common exceptions into `sysexits.h` exit codes.
- **Mapping Strategy**:
- `InvalidArgumentException` -> `ExitCode::USAGE` (64)
- `RuntimeException` -> `ExitCode::SOFTWARE` (70)
- `ConsoleExceptionInterface` (from Contracts) -> Mapped according to category (e.g., `UNAVAILABLE`, `CONFIG`).
- **Global Handler**: The primary runner (Tasker) or Bridge wrapper provides the top-level `try/catch` to ensure these codes are returned to the shell.
### 12.3 Helper Feature Parity
- **Guaranteed Minimum API**: Bridges must implement the full `ProgressBarInterface` and `TableInterface` as defined in `ConsoleContracts`.
- **Progressive Enhancement**: Bridges MAY support advanced features (e.g., table styling, progress bar steps) if the underlying toolkit supports it, but commands should avoid depending on these for core functionality.
- **Fallback**: In non-TTY or non-supported environments, bridges must provide a "silent" or "degraded" implementation (e.g., printing table as a list, silencing progress bars) to prevent command failure.
## Brainstorming / Open Questions
(All current open questions have been resolved and moved to Architectural Decisions.)