TaskerBridges/NOTES.md

175 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.)