Skip to main content
Glama
device.ts5.7 kB
/** * Device Models * Unified device representation across Android and iOS */ import { Platform } from './constants.js'; /** * Device status */ export type DeviceStatus = 'booted' | 'shutdown' | 'booting' | 'unknown'; /** * Device type */ export type DeviceType = 'emulator' | 'simulator' | 'physical'; /** * Unified device representation */ export interface Device { /** Unique device identifier (UDID for iOS, serial for Android) */ id: string; /** Device name */ name: string; /** Platform */ platform: Platform; /** Device type */ type: DeviceType; /** Current status */ status: DeviceStatus; /** OS version */ osVersion?: string; /** Device model */ model?: string; /** Screen size if known */ screenSize?: { width: number; height: number; }; /** Whether device is the default/selected device */ isDefault?: boolean; } /** * Environment action type */ export type EnvironmentAction = 'boot' | 'shutdown' | 'restart'; /** * Environment operation result */ export interface EnvironmentResult { /** Whether operation succeeded */ success: boolean; /** Action performed */ action: EnvironmentAction; /** Target device */ device?: Device; /** Error message if failed */ error?: string; /** Duration in milliseconds */ durationMs: number; /** Additional details */ details?: string; } /** * Clean project options */ export interface CleanProjectOptions { /** Project root path */ projectPath: string; /** Clean Gradle caches */ cleanGradle?: boolean; /** Clean Xcode DerivedData */ cleanDerivedData?: boolean; /** Clean build directories */ cleanBuild?: boolean; /** Clean node_modules */ cleanNodeModules?: boolean; /** Clean CocoaPods */ cleanPods?: boolean; /** Specific module to clean (for Gradle) */ module?: string; } /** * Clean project result */ export interface CleanResult { /** Overall success */ success: boolean; /** Items cleaned */ cleaned: Array<{ type: string; path: string; success: boolean; error?: string; }>; /** Total space freed (bytes, if calculable) */ spaceFreedBytes?: number; /** Duration in milliseconds */ durationMs: number; } /** * Convert Android device to unified Device */ export function fromAndroidDevice(android: { id: string; name: string; status: string; model?: string; type?: string; }): Device { return { id: android.id, name: android.name, platform: 'android', type: android.type === 'emulator' ? 'emulator' : 'physical', status: mapStatus(android.status), model: android.model, }; } /** * Convert iOS device to unified Device */ export function fromIOSDevice(ios: { id: string; name: string; status: string; runtime?: string; isAvailable?: boolean; }): Device { // Extract OS version from runtime (e.g., "iOS 17.0" from "com.apple.CoreSimulator.SimRuntime.iOS-17-0") let osVersion: string | undefined; if (ios.runtime) { const versionMatch = ios.runtime.match(/(\d+)-(\d+)(?:-(\d+))?$/); if (versionMatch) { osVersion = `${versionMatch[1]}.${versionMatch[2]}${versionMatch[3] ? '.' + versionMatch[3] : ''}`; } } return { id: ios.id, name: ios.name, platform: 'ios', type: 'simulator', // simctl only works with simulators status: mapStatus(ios.status), osVersion, }; } /** * Map platform-specific status to unified status */ function mapStatus(status: string): DeviceStatus { const lower = status.toLowerCase(); if (lower === 'booted' || lower === 'online' || lower === 'device') { return 'booted'; } if (lower === 'shutdown' || lower === 'offline') { return 'shutdown'; } if (lower === 'booting' || lower === 'starting') { return 'booting'; } return 'unknown'; } /** * Filter devices by status */ export function filterDevicesByStatus( devices: Device[], status: DeviceStatus ): Device[] { return devices.filter((d) => d.status === status); } /** * Find device by ID or name */ export function findDevice( devices: Device[], query: string ): Device | undefined { // Exact ID match const byId = devices.find((d) => d.id === query); if (byId) return byId; // Exact name match const byName = devices.find((d) => d.name === query); if (byName) return byName; // Partial name match (case insensitive) const lowerQuery = query.toLowerCase(); return devices.find((d) => d.name.toLowerCase().includes(lowerQuery)); } /** * Get first booted device for platform */ export function getBootedDevice( devices: Device[], platform?: Platform ): Device | undefined { const filtered = platform ? devices.filter((d) => d.platform === platform) : devices; return filtered.find((d) => d.status === 'booted'); } /** * Create device summary for AI */ export function createDeviceSummary(devices: Device[]): string { if (devices.length === 0) { return 'No devices found'; } const android = devices.filter((d) => d.platform === 'android'); const ios = devices.filter((d) => d.platform === 'ios'); const lines: string[] = [`Total: ${devices.length} devices`]; if (android.length > 0) { const booted = android.filter((d) => d.status === 'booted'); lines.push(`Android: ${android.length} (${booted.length} running)`); for (const device of booted) { lines.push(` - ${device.name} (${device.id})`); } } if (ios.length > 0) { const booted = ios.filter((d) => d.status === 'booted'); lines.push(`iOS: ${ios.length} (${booted.length} running)`); for (const device of booted) { lines.push(` - ${device.name} (${device.id})`); } } return lines.join('\n'); }

Latest Blog Posts

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/abd3lraouf/specter-mcp'

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