docs: consolidate documentation into organized structure

- Move 12 markdown files from root to docs/ subdirectories
- Organize documentation by category:
  • docs/troubleshooting/ (1 file)  - Technical troubleshooting guides
  • docs/deployment/      (4 files) - Deployment and security documentation
  • docs/guides/          (3 files) - Feature-specific guides
  • docs/planning/        (4 files) - Planning and improvement proposals

Root directory cleanup:
- Reduced from 16 to 4 markdown files in root
- Only essential project files remain:
  • CLAUDE.md (AI instructions)
  • README.md (Main project readme)
  • CLEANUP_PLAN.md (Current cleanup plan)
  • SRC_STRUCTURE_IMPROVEMENTS.md (Structure improvements)

This improves:
 Documentation discoverability
 Logical organization by purpose
 Clean root directory
 Better maintainability
This commit is contained in:
2025-10-05 11:05:04 +02:00
parent 887847dde6
commit 5050c7d73a
36686 changed files with 196456 additions and 12398919 deletions

View File

@@ -7,6 +7,11 @@ namespace App\Framework\Mcp;
use App\Framework\Core\AttributeMapper;
use App\Framework\Reflection\WrappedReflectionClass;
use App\Framework\Reflection\WrappedReflectionMethod;
use App\Framework\Mcp\Core\ValueObjects\OutputFormat;
use ReflectionNamedType;
use ReflectionUnionType;
use ReflectionIntersectionType;
use ReflectionEnum;
final readonly class McpToolMapper implements AttributeMapper
{
@@ -26,13 +31,227 @@ final readonly class McpToolMapper implements AttributeMapper
return [
'name' => $attributeInstance->name,
'description' => $attributeInstance->description,
'inputSchema' => $attributeInstance->inputSchema,
'inputSchema' => $this->generateInputSchema($reflectionTarget, $attributeInstance),
'class' => $class->getFullyQualified(),
'method' => $reflectionTarget->getName(),
'parameters' => $this->extractParameters($reflectionTarget),
];
}
private function generateInputSchema(WrappedReflectionMethod $method, McpTool $tool): array
{
$schema = [
'type' => 'object',
'properties' => [],
'required' => [],
'title' => $tool->name,
'description' => $tool->description,
];
if (!empty($tool->category)) {
$schema['category'] = $tool->category;
}
if (!empty($tool->tags)) {
$schema['tags'] = $tool->tags;
}
foreach ($method->getParameters() as $param) {
$paramName = $param->getName();
$paramSchema = $this->generateParameterSchema($param);
$schema['properties'][$paramName] = $paramSchema;
if (!$param->isOptional()) {
$schema['required'][] = $paramName;
}
}
return $schema;
}
private function generateParameterSchema(\ReflectionParameter $param): array
{
$type = $param->getType();
$schema = $this->mapPhpTypeToJsonSchema($type);
// Add description based on parameter name
$schema['description'] = $this->generateParameterDescription($param);
// Add default value if parameter is optional
if ($param->isOptional()) {
try {
$defaultValue = $param->getDefaultValue();
$schema['default'] = $defaultValue;
} catch (\ReflectionException) {
// Some defaults (like class constants) can't be retrieved
$schema['default'] = null;
}
}
return $schema;
}
private function mapPhpTypeToJsonSchema(?\ReflectionType $type): array
{
if ($type === null) {
return ['type' => 'string', 'description' => 'Mixed type parameter'];
}
if ($type instanceof ReflectionNamedType) {
return $this->mapNamedTypeToSchema($type);
}
if ($type instanceof ReflectionUnionType) {
return $this->mapUnionTypeToSchema($type);
}
if ($type instanceof ReflectionIntersectionType) {
return ['type' => 'object', 'description' => 'Intersection type'];
}
return ['type' => 'string', 'description' => 'Unknown type'];
}
private function mapNamedTypeToSchema(ReflectionNamedType $type): array
{
$typeName = $type->getName();
return match ($typeName) {
'string' => ['type' => 'string'],
'int' => ['type' => 'integer'],
'float' => ['type' => 'number'],
'bool' => ['type' => 'boolean'],
'array' => ['type' => 'array', 'items' => ['type' => 'string']],
'null' => ['type' => 'null'],
'mixed' => ['description' => 'Mixed type - can be any value'],
default => $this->mapComplexTypeToSchema($typeName)
};
}
private function mapComplexTypeToSchema(string $typeName): array
{
// Handle enums
if (class_exists($typeName) && enum_exists($typeName)) {
return $this->mapEnumToSchema($typeName);
}
// Handle OutputFormat specifically
if ($typeName === OutputFormat::class || str_ends_with($typeName, 'OutputFormat')) {
return [
'type' => 'string',
'enum' => ['array', 'json', 'table', 'tree', 'text', 'mermaid', 'plantuml'],
'default' => 'array',
'description' => 'Output format for the response'
];
}
// Handle other classes
if (class_exists($typeName)) {
return [
'type' => 'object',
'description' => "Instance of {$typeName}"
];
}
// Fallback for unknown types
return [
'type' => 'string',
'description' => "Parameter of type {$typeName}"
];
}
private function mapEnumToSchema(string $enumClass): array
{
try {
$reflection = new ReflectionEnum($enumClass);
$cases = [];
foreach ($reflection->getCases() as $case) {
$cases[] = $case->getValue();
}
return [
'type' => 'string',
'enum' => $cases,
'description' => "Enum values from {$enumClass}"
];
} catch (\ReflectionException) {
return [
'type' => 'string',
'description' => "Enum type {$enumClass}"
];
}
}
private function mapUnionTypeToSchema(ReflectionUnionType $type): array
{
$types = [];
$hasNull = false;
foreach ($type->getTypes() as $unionType) {
if ($unionType instanceof ReflectionNamedType && $unionType->getName() === 'null') {
$hasNull = true;
continue;
}
$schema = $this->mapPhpTypeToJsonSchema($unionType);
$types[] = $schema;
}
if (count($types) === 1) {
$schema = $types[0];
if ($hasNull) {
$schema['nullable'] = true;
}
return $schema;
}
return [
'anyOf' => $types,
'nullable' => $hasNull,
'description' => 'Union type parameter'
];
}
private function generateParameterDescription(\ReflectionParameter $param): string
{
$name = $param->getName();
$type = $param->getType();
// Generate human-readable descriptions based on parameter names
$descriptions = [
'path' => 'File or directory path',
'file' => 'File path',
'directory' => 'Directory path',
'format' => 'Output format for the response',
'includeHidden' => 'Whether to include hidden files',
'includeAnalysis' => 'Whether to include detailed analysis',
'includeSecurity' => 'Whether to include security assessment',
'includeMetrics' => 'Whether to include performance metrics',
'includeHealthCheck' => 'Whether to include health check information',
'controller' => 'Controller class name to filter by',
'method' => 'HTTP method to filter by',
'focus' => 'Area of focus for analysis',
'task' => 'Task description for the agent',
'sortBy' => 'Field to sort results by',
'sortOrder' => 'Sort order (asc or desc)',
'pattern' => 'Search pattern or regex',
'limit' => 'Maximum number of results to return',
'offset' => 'Number of results to skip',
'recursive' => 'Whether to search recursively',
'caseSensitive' => 'Whether search should be case sensitive',
];
if (isset($descriptions[$name])) {
return $descriptions[$name];
}
$typeName = $type instanceof ReflectionNamedType ? $type->getName() : 'mixed';
return "Parameter of type {$typeName}";
}
private function extractParameters(WrappedReflectionMethod $method): array
{
$parameters = [];