Skip to main content
Glama

CTX: Context as Code (CaC) tool

by context-hub
MIT License
235
  • Apple
  • Linux
GenerateCommand.php7.79 kB
<?php declare(strict_types=1); namespace Butschster\ContextGenerator\Console; use Butschster\ContextGenerator\Application\AppScope; use Butschster\ContextGenerator\Config\ConfigurationProvider; use Butschster\ContextGenerator\Config\Exception\ConfigLoaderException; use Butschster\ContextGenerator\Config\Registry\ConfigRegistryAccessor; use Butschster\ContextGenerator\Console\Renderer\GenerateCommandRenderer; use Butschster\ContextGenerator\DirectoriesInterface; use Butschster\ContextGenerator\Document\Compiler\DocumentCompiler; use Spiral\Files\FilesInterface; use Spiral\Console\Attribute\Option; use Spiral\Core\Container; use Spiral\Core\Scope; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; #[AsCommand( name: 'generate', description: 'Generate context files from configuration', aliases: ['build', 'compile'], )] final class GenerateCommand extends BaseCommand { #[Option( name: 'inline', shortcut: 'i', description: 'Inline JSON configuration string. If provided, file-based configuration will be ignored', )] protected ?string $inlineJson = null; #[Option( name: 'config-file', shortcut: 'c', description: 'Path to configuration file (absolute or relative to current directory).', )] protected ?string $configPath = null; #[Option( name: 'work-dir', shortcut: 'w', description: 'Path to working directory. If not provided, will use the current working directory', )] protected ?string $workDir = null; #[Option( name: 'env', shortcut: 'e', description: 'Path to .env (like .env.local) file. If not provided, will ignore any .env files', )] protected ?string $envFileName = null; #[Option( name: 'json', description: 'Output JSON instead of context files', )] protected bool $asJson = false; public function __invoke(Container $container, DirectoriesInterface $dirs): int { // Determine the effective root path based on config file path $dirs = $dirs ->determineRootPath($this->configPath, $this->inlineJson) ->withOutputPath($this->workDir) ->withEnvFile($this->envFileName); $container->getBinder('root')->bind( DirectoriesInterface::class, $dirs, ); return $container->runScope( bindings: new Scope( bindings: [ DirectoriesInterface::class => $dirs, ], ), scope: fn(Container $container): int => $container->runScope( bindings: new Scope( name: AppScope::Compiler, bindings: [ DirectoriesInterface::class => $dirs, ], ), scope: function ( DocumentCompiler $compiler, ConfigurationProvider $configProvider, DirectoriesInterface $dirs, FilesInterface $files, ): int { try { // Get the appropriate loader based on options provided if ($this->inlineJson !== null) { $this->logger->info('Using inline JSON configuration...'); $loader = $configProvider->fromString($this->inlineJson); } elseif ($this->configPath !== null) { $this->logger->info(\sprintf('Loading configuration from %s...', $this->configPath)); $loader = $configProvider->fromPath($dirs->getConfigPath()->toString()); } else { $this->logger->info('Loading configuration from default location...'); $loader = $configProvider->fromDefaultLocation(); } } catch (ConfigLoaderException $e) { $this->logger->error('Failed to load configuration', [ 'error' => $e->getMessage(), ]); if ($this->asJson) { $this->output->writeln(\json_encode([ 'status' => 'error', 'message' => 'Failed to load configuration', 'error' => $e->getMessage(), ])); } else { $this->output->error(\sprintf('Failed to load configuration: %s', $e->getMessage())); } return Command::FAILURE; } // Create the renderer for consistent output formatting $renderer = new GenerateCommandRenderer( output: $this->output, files: $files, basePath: $dirs->getOutputPath()->toString(), ); // Display summary header $this->output->writeln(''); $config = new ConfigRegistryAccessor($loader->load()); $imports = $config->getImports(); if ($imports !== null && !$this->asJson) { $renderer->renderImports($imports); } if ($config->getDocuments() === null || $config->getDocuments()->getItems() === []) { if ($this->asJson) { $this->output->writeln(\json_encode([ 'status' => 'success', 'message' => 'No documents found in configuration.', 'imports' => $imports, 'prompts' => $config->getPrompts(), 'tools' => $config->getTools(), ])); } else { $this->output->warning('No documents found in configuration.'); } return Command::SUCCESS; } $result = []; foreach ($config->getDocuments() as $document) { $this->logger->info(\sprintf('Compiling %s...', $document->description)); $compiledDocument = $compiler->compile($document); if (!$this->asJson) { $renderer->renderCompilationResult($document, $compiledDocument); } else { $result[] = [ 'output_path' => $compiledDocument->outputPath, 'context_path' => $compiledDocument->contextPath, 'errors' => $compiledDocument->errors, ]; } } if ($this->asJson) { $this->output->writeln(\json_encode([ 'status' => 'success', 'message' => 'Documents compiled successfully', 'result' => $result, 'imports' => $imports, 'prompts' => $config->getPrompts(), 'tools' => $config->getTools(), ])); } else { $this->output->writeln(''); } return Command::SUCCESS; }, ), ); } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/context-hub/generator'

If you have feedback or need assistance with the MCP directory API, please join our Discord server