Skip to main content
Glama

Context Pods

by conorluddy
turbo-integration.tsโ€ข8.2 kB
/** * TurboRepo integration utilities for Context-Pods CLI */ import { promises as fs } from 'fs'; import path from 'path'; import { execa } from 'execa'; import type { Result } from 'execa'; import type { CLIConfig } from '../types/cli-types.js'; import { output } from './output-formatter.js'; /** * TurboRepo configuration interface */ interface TurboConfig { globalDependencies?: string[]; pipeline?: Record< string, { dependsOn?: string[]; outputs?: string[]; cache?: boolean; inputs?: string[]; } >; } /** * TurboRepo integration manager */ export class TurboIntegration { private workspaceRoot: string; private config: CLIConfig; constructor(workspaceRoot: string, config: CLIConfig) { this.workspaceRoot = workspaceRoot; this.config = config; } /** * Check if TurboRepo is available and enabled */ async isAvailable(): Promise<boolean> { if (!this.config.turbo.enabled) { return false; } try { // Check if turbo is installed await execa('turbo', ['--version'], { cwd: this.workspaceRoot }); // Check if turbo.json exists const turboConfigPath = path.join(this.workspaceRoot, 'turbo.json'); await fs.access(turboConfigPath); return true; } catch { return false; } } /** * Run a TurboRepo command */ async run( command: string, options: { args?: string[]; filter?: string; cwd?: string; verbose?: boolean; } = {}, ): Promise<Result> { const { args = [], filter, cwd = this.workspaceRoot, verbose = false } = options; const turboArgs = [command, ...args]; if (filter) { turboArgs.push('--filter', filter); } if (verbose) { output.debug(`Running: turbo ${turboArgs.join(' ')}`); } return await execa('turbo', turboArgs, { cwd, stdio: verbose ? 'inherit' : 'pipe', }); } /** * Build specific packages or all packages */ async build(filter?: string, verbose = false): Promise<void> { if (!(await this.isAvailable())) { throw new Error('TurboRepo is not available. Run npm install or enable turbo in config.'); } output.startSpinner('Building packages...'); try { await this.run('build', { filter, verbose }); output.succeedSpinner('Build completed successfully'); } catch (error) { output.failSpinner('Build failed'); throw error; } } /** * Run tests for specific packages or all packages */ async test(filter?: string, verbose = false): Promise<void> { if (!(await this.isAvailable())) { throw new Error('TurboRepo is not available. Run npm install or enable turbo in config.'); } output.startSpinner('Running tests...'); try { await this.run('test', { filter, verbose }); output.succeedSpinner('Tests completed successfully'); } catch (error) { output.failSpinner('Tests failed'); throw error; } } /** * Run linting for specific packages or all packages */ async lint(filter?: string, verbose = false): Promise<void> { if (!(await this.isAvailable())) { throw new Error('TurboRepo is not available. Run npm install or enable turbo in config.'); } output.startSpinner('Running linter...'); try { await this.run('lint', { filter, verbose }); output.succeedSpinner('Linting completed successfully'); } catch (error) { output.failSpinner('Linting failed'); throw error; } } /** * Start development mode */ async dev(filter?: string, _verbose = false): Promise<void> { if (!(await this.isAvailable())) { throw new Error('TurboRepo is not available. Run npm install or enable turbo in config.'); } output.info('Starting development mode...'); try { // Run in development mode (this will keep running) await this.run('dev', { filter, verbose: true }); } catch (error) { output.error('Development mode failed'); throw error; } } /** * Clean build artifacts */ async clean(filter?: string, _verbose = false): Promise<void> { if (!(await this.isAvailable())) { output.warn('TurboRepo not available, skipping turbo clean'); return; } output.startSpinner('Cleaning build artifacts...'); try { await this.run('clean', { filter, verbose: _verbose }); output.succeedSpinner('Clean completed successfully'); } catch (error) { output.failSpinner('Clean failed'); throw error; } } /** * Get TurboRepo configuration */ async getTurboConfig(): Promise<TurboConfig | null> { try { const turboConfigPath = path.join(this.workspaceRoot, 'turbo.json'); const configContent = await fs.readFile(turboConfigPath, 'utf-8'); return JSON.parse(configContent); } catch { return null; } } /** * Update TurboRepo configuration */ async updateTurboConfig(updates: Partial<TurboConfig>): Promise<void> { const turboConfigPath = path.join(this.workspaceRoot, 'turbo.json'); try { const existingConfig = (await this.getTurboConfig()) || {}; const newConfig = { ...existingConfig, ...updates, pipeline: { ...existingConfig.pipeline, ...updates.pipeline, }, }; await fs.writeFile(turboConfigPath, JSON.stringify(newConfig, null, 2)); output.success('TurboRepo configuration updated'); } catch (error) { output.error('Failed to update TurboRepo configuration'); throw error; } } /** * Add CLI-specific tasks to TurboRepo configuration */ async addCLITasks(): Promise<void> { const cliTasks = { 'cli:wrap': { dependsOn: ['build'], cache: false, outputs: ['generated/**'], }, 'cli:generate': { dependsOn: ['build'], cache: false, outputs: ['generated/**'], }, 'cli:dev': { dependsOn: ['build'], cache: false, persistent: true, }, }; await this.updateTurboConfig({ pipeline: cliTasks, }); } /** * Check if workspace has Node.js packages that can benefit from optimization */ async hasNodeJSPackages(): Promise<boolean> { try { const packagesDir = path.join(this.workspaceRoot, 'packages'); const entries = await fs.readdir(packagesDir, { withFileTypes: true }); for (const entry of entries) { if (entry.isDirectory()) { const packageJsonPath = path.join(packagesDir, entry.name, 'package.json'); try { await fs.access(packageJsonPath); return true; } catch { // Continue checking other directories } } } return false; } catch { return false; } } /** * Get workspace packages information */ async getWorkspacePackages(): Promise< Array<{ name: string; path: string; hasTypeScript: boolean }> > { const packages: Array<{ name: string; path: string; hasTypeScript: boolean }> = []; try { const packagesDir = path.join(this.workspaceRoot, 'packages'); const entries = await fs.readdir(packagesDir, { withFileTypes: true }); for (const entry of entries) { if (entry.isDirectory()) { const packagePath = path.join(packagesDir, entry.name); const packageJsonPath = path.join(packagePath, 'package.json'); try { const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8'); const packageJson = JSON.parse(packageJsonContent); const hasTypeScript = await fs .access(path.join(packagePath, 'tsconfig.json')) .then(() => true) .catch(() => false); packages.push({ name: packageJson.name || entry.name, path: packagePath, hasTypeScript, }); } catch { // Skip invalid packages } } } } catch { // No packages directory or access error } return packages; } }

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/conorluddy/ContextPods'

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