Skip to main content
Glama

MCP Xcode

by Stefan-Nitu
BuildProjectUseCase.ts5.55 kB
// No infrastructure imports! Only domain and application layer // Domain import { BuildRequest } from '../domain/BuildRequest.js'; import { BuildResult } from '../domain/BuildResult.js'; // Application ports import { IBuildCommand } from '../../../application/ports/BuildPorts.js'; import { ICommandExecutor } from '../../../application/ports/CommandPorts.js'; import { IAppLocator } from '../../../application/ports/ArtifactPorts.js'; import { ILogManager } from '../../../application/ports/LoggingPorts.js'; import { IOutputParser } from '../../../application/ports/OutputParserPorts.js'; import { IBuildDestinationMapper } from '../../../application/ports/MappingPorts.js'; import { IOutputFormatter } from '../../../application/ports/OutputFormatterPorts.js'; /** * Use Case: Build an Xcode project * Orchestrates the build process using domain logic and infrastructure services */ export class BuildProjectUseCase { constructor( private destinationMapper: IBuildDestinationMapper, private commandBuilder: IBuildCommand, private executor: ICommandExecutor, private appLocator: IAppLocator, private logManager: ILogManager, private outputParser: IOutputParser, private outputFormatter: IOutputFormatter ) {} async execute(request: BuildRequest): Promise<BuildResult> { // Request is already validated and created at the border (BuildXcodeTool) // Use case just orchestrates business logic // 3. Map domain destination to infrastructure format const mappedDestination = await this.destinationMapper.toXcodeBuildOptions( request.destination ); // 4. Build command with already-mapped values const command = this.commandBuilder.build( request.projectPath.toString(), request.projectPath.isWorkspace, { scheme: request.scheme, configuration: request.configuration, destination: mappedDestination.destination, additionalSettings: mappedDestination.additionalSettings, derivedDataPath: request.derivedDataPath } ); // Log via LogManager instead of direct logger this.logManager.saveDebugData('build-command', { command }, request.projectPath.name); // 5. Execute build const result = await this.executor.execute(command, { maxBuffer: 50 * 1024 * 1024, shell: '/bin/bash' }); // 6. Format the output (e.g., through xcbeautify) const rawOutput = result.stdout + (result.stderr ? `\n${result.stderr}` : ''); let output: string; try { output = await this.outputFormatter.format(rawOutput); } catch (formatterError: any) { // If formatter fails (e.g., xcbeautify not installed), return build failure this.logManager.saveDebugData('formatter-error', { error: formatterError.message, rawOutput: rawOutput.substring(0, 500) // Save first 500 chars for debugging }, request.projectPath.name); const logPath = this.logManager.saveLog('build', rawOutput, request.projectPath.name, { scheme: request.scheme, configuration: request.configuration, destination: request.destination, exitCode: result.exitCode, command, formatterError: formatterError.message }); // Return build failure with formatter error return BuildResult.failed( [], // No parsed issues since formatter failed result.exitCode || 1, logPath, formatterError ); } // 7. Process result if (result.exitCode === 0) { // Success path const appPath = await this.appLocator.findApp(request.derivedDataPath); // Parse output to extract any warnings even for successful builds const parsed = this.outputParser.parseBuildOutput(output); const warnings = parsed.issues.filter(issue => issue.isWarning()); // Log success via LogManager this.logManager.saveDebugData('build-success', { project: request.projectPath.name, scheme: request.scheme, configuration: request.configuration, destination: request.destination, warningCount: warnings.length }, request.projectPath.name); const logPath = this.logManager.saveLog('build', output, request.projectPath.name, { scheme: request.scheme, configuration: request.configuration, destination: request.destination, exitCode: result.exitCode, command }); return BuildResult.succeeded(appPath, logPath, warnings); } else { // Failure path // Log failure via LogManager this.logManager.saveDebugData('build-failure', { exitCode: result.exitCode }, request.projectPath.name); // Use injected output parser const parsed = this.outputParser.parseBuildOutput(output); const logPath = this.logManager.saveLog('build', output, request.projectPath.name, { scheme: request.scheme, configuration: request.configuration, destination: request.destination, exitCode: result.exitCode, command, issues: parsed.issues }); // Extract errors from issues for logging const errors = parsed.issues.filter(issue => issue.isError()); if (errors.length > 0) { this.logManager.saveDebugData('build-errors', errors, request.projectPath.name); } // Return failure result return BuildResult.failed(parsed.issues, result.exitCode, logPath); } } }

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/Stefan-Nitu/mcp-xcode'

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