feat: add comprehensive framework features and deployment improvements

Major additions:
- Storage abstraction layer with filesystem and in-memory implementations
- Gitea API integration with MCP tools for repository management
- Console dialog mode with interactive command execution
- WireGuard VPN DNS fix implementation and documentation
- HTTP client streaming response support
- Router generic result type
- Parameter type validator for framework core

Framework enhancements:
- Console command registry improvements
- Console dialog components
- Method signature analyzer updates
- Route mapper refinements
- MCP server and tool mapper updates
- Queue job chain and dependency commands
- Discovery tokenizer improvements

Infrastructure:
- Deployment architecture documentation
- Ansible playbook updates for WireGuard client regeneration
- Production environment configuration updates
- Docker Compose local configuration updates
- Remove obsolete docker-compose.yml (replaced by environment-specific configs)

Documentation:
- PERMISSIONS.md for access control guidelines
- WireGuard DNS fix implementation details
- Console dialog mode usage guide
- Deployment architecture overview

Testing:
- Multi-purpose attribute tests
- Gitea Actions integration tests (typed and untyped)
This commit is contained in:
2025-11-04 20:39:48 +01:00
parent 700fe8118b
commit 3ed2685e74
80 changed files with 9891 additions and 850 deletions

View File

@@ -0,0 +1,92 @@
<?php
declare(strict_types=1);
use App\Framework\Console\ConsoleCommand;
use App\Framework\Core\ParameterTypeValidator;
use App\Framework\Examples\MultiPurposeAction;
use App\Framework\Mcp\McpTool;
use App\Framework\Reflection\WrappedReflectionMethod;
use App\Framework\Reflection\Cache\MethodCache;
use App\Framework\Core\ValueObjects\ClassName;
test('multi-purpose method has multiple attributes', function () {
$className = ClassName::create(MultiPurposeAction::class);
$methodName = 'listUsers';
// Create a mock method cache (simplified for testing)
$reflectionMethod = new \ReflectionMethod(MultiPurposeAction::class, $methodName);
$attributes = $reflectionMethod->getAttributes();
$attributeNames = array_map(fn($attr) => $attr->getName(), $attributes);
expect($attributeNames)->toContain(McpTool::class);
expect($attributeNames)->toContain(ConsoleCommand::class);
// Note: Route attribute checking would need Route class import
});
test('parameter type validator recognizes builtin types', function () {
$validator = new ParameterTypeValidator();
// Use reflection from actual method to test builtin types
$reflectionMethod = new \ReflectionMethod(MultiPurposeAction::class, 'listUsers');
$parameters = $reflectionMethod->getParameters();
// Test string parameter
$stringParam = $parameters[0]; // $status: string
expect($validator->isBuiltinType($stringParam->getType()))->toBeTrue();
// Test int parameter
$intParam = $parameters[1]; // $limit: int
expect($validator->isBuiltinType($intParam->getType()))->toBeTrue();
// Test bool parameter
$boolParam = $parameters[2]; // $includeDetails: bool
expect($validator->isBuiltinType($boolParam->getType()))->toBeTrue();
});
test('parameter type validator rejects non-builtin types', function () {
$validator = new ParameterTypeValidator();
// Use reflection from a method that has non-builtin types (if available)
// For now, test with a class that doesn't exist in our test
$reflectionClass = new \ReflectionClass(MultiPurposeAction::class);
// All methods in MultiPurposeAction should have only builtin types
// So we'll test with a known non-builtin type string
$classType = new \ReflectionClass(\stdClass::class);
$method = $classType->getMethod('__construct');
$parameters = $method->getParameters();
// If there are parameters, check they're not builtin (if they're object types)
if (count($parameters) > 0 && $parameters[0]->getType() instanceof \ReflectionNamedType) {
$typeName = $parameters[0]->getType()->getName();
if (! in_array($typeName, ['string', 'int', 'float', 'bool', 'array', 'mixed'], true)) {
expect($validator->isBuiltinType($parameters[0]->getType()))->toBeFalse();
}
}
});
test('multi-purpose method returns ActionResult', function () {
$action = new MultiPurposeAction();
$result = $action->listUsers('active', 10, false);
expect($result)->toBeInstanceOf(\App\Framework\Router\ActionResult::class);
expect($result)->toBeInstanceOf(\App\Framework\Router\Result\JsonResult::class);
});
test('ConsoleResult implements ActionResult', function () {
$textResult = new \App\Framework\Console\Result\TextResult('Test message');
expect($textResult)->toBeInstanceOf(\App\Framework\Router\ActionResult::class);
expect($textResult)->toBeInstanceOf(\App\Framework\Console\Result\ConsoleResult::class);
});
test('ToolResult implements ActionResult', function () {
$toolResult = \App\Framework\Mcp\Core\ValueObjects\ToolResult::success(['data' => 'test']);
expect($toolResult)->toBeInstanceOf(\App\Framework\Router\ActionResult::class);
expect($toolResult)->toBeInstanceOf(\App\Framework\Mcp\Core\ValueObjects\ToolResult::class);
});