or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

environment-state.mdindex.mdinput-output.mdjob-summaries.mdlogging-annotations.mdoidc-tokens.mdoutput-grouping.mdpath-utilities.mdplatform-detection.md
tile.json

platform-detection.mddocs/

Platform Detection

Runtime environment detection and system information gathering for platform-specific logic. This module provides utilities to detect the operating system, architecture, and detailed system information, enabling actions to adapt their behavior based on the execution environment.

Overview

The platform detection utilities help you write actions that work correctly across GitHub's hosted runners (Windows, macOS, Linux) and self-hosted runners with different configurations. You can use these utilities to conditionally execute platform-specific code, select appropriate tools, or adjust behavior based on the runtime environment.

Capabilities

Platform Constants

Basic platform detection constants that identify the current operating system.

/**
 * Platform detection constants
 */
namespace platform {
  /** Current platform string (equivalent to os.platform()) */
  const platform: string;
  
  /** Current architecture string (equivalent to os.arch()) */
  const arch: string;
  
  /** True if running on Windows platform */
  const isWindows: boolean;
  
  /** True if running on macOS platform */
  const isMacOS: boolean;
  
  /** True if running on Linux platform */
  const isLinux: boolean;
}

Usage Examples:

import { platform } from '@actions/core';

// Check current platform
console.log(`Running on: ${platform.platform}`); // 'win32', 'darwin', 'linux', etc.
console.log(`Architecture: ${platform.arch}`);   // 'x64', 'arm64', etc.

// Platform-specific logic
if (platform.isWindows) {
  console.log('Executing Windows-specific code');
  await runWindowsCommand();
} else if (platform.isMacOS) {
  console.log('Executing macOS-specific code');
  await runMacCommand();
} else if (platform.isLinux) {
  console.log('Executing Linux-specific code');
  await runLinuxCommand();
}

// Architecture-specific logic
if (platform.arch === 'arm64') {
  console.log('Running on ARM64 architecture');
  await downloadArmBinary();
} else if (platform.arch === 'x64') {
  console.log('Running on x64 architecture');
  await downloadX64Binary();
}

Detailed Platform Information

Get comprehensive system information including OS name, version, and all platform detection flags.

/**
 * Get detailed platform information
 * @returns Promise resolving to detailed platform information
 */
function getDetails(): Promise<PlatformDetails>;

interface PlatformDetails {
  /** Human-readable OS name */
  name: string;
  /** Platform identifier */
  platform: string;
  /** System architecture */
  arch: string;
  /** OS version */
  version: string;
  /** True if running on Windows */
  isWindows: boolean;
  /** True if running on macOS */
  isMacOS: boolean;
  /** True if running on Linux */
  isLinux: boolean;
}

Usage Examples:

import { platform } from '@actions/core';

// Get detailed system information
const details = await platform.getDetails();

console.log(`OS Name: ${details.name}`);
console.log(`Platform: ${details.platform}`);
console.log(`Architecture: ${details.arch}`);
console.log(`Version: ${details.version}`);

// Example outputs:
// Windows: name="Microsoft Windows Server 2022", version="10.0.20348"
// macOS: name="macOS", version="12.6.1"
// Linux: name="Ubuntu", version="20.04"

// Use detailed info for compatibility checks
if (details.isWindows && parseFloat(details.version.split('.')[0]) >= 10) {
  console.log('Windows 10+ detected, using modern APIs');
} else if (details.isMacOS && details.version >= '12.0') {
  console.log('macOS Monterey+ detected');
} else if (details.isLinux && details.name.includes('Ubuntu')) {
  console.log(`Ubuntu ${details.version} detected`);
}

Common Patterns

Conditional Tool Installation

import { platform, info, exec } from '@actions/core';

async function installTools() {
  const details = await platform.getDetails();
  
  info(`Installing tools for ${details.name} ${details.version}`);
  
  if (platform.isWindows) {
    // Install tools via Chocolatey or direct download
    await exec.exec('choco', ['install', 'nodejs', 'git', '-y']);
    
    // Windows-specific configuration
    await exec.exec('setx', ['PATH', '%PATH%;C:\\Tools\\bin']);
    
  } else if (platform.isMacOS) {
    // Install tools via Homebrew
    await exec.exec('brew', ['install', 'node', 'git']);
    
    // macOS-specific configuration
    if (platform.arch === 'arm64') {
      info('Configuring for Apple Silicon');
      await exec.exec('arch', ['-arm64', 'brew', 'install', 'native-tools']);
    }
    
  } else if (platform.isLinux) {
    // Install tools via package manager
    if (details.name.includes('Ubuntu') || details.name.includes('Debian')) {
      await exec.exec('sudo', ['apt-get', 'update']);
      await exec.exec('sudo', ['apt-get', 'install', '-y', 'nodejs', 'git']);
    } else if (details.name.includes('CentOS') || details.name.includes('Red Hat')) {
      await exec.exec('sudo', ['yum', 'install', '-y', 'nodejs', 'git']);
    }
  }
  
  info('Tool installation completed');
}

Platform-Specific File Handling

import { platform, toPlatformPath, info } from '@actions/core';
import * as path from 'path';

async function setupPaths() {
  const details = await platform.getDetails();
  
  let configDir: string;
  let dataDir: string;
  let executableExt: string;
  
  if (platform.isWindows) {
    configDir = path.join(process.env.APPDATA || 'C:\\Users\\Default\\AppData\\Roaming', 'MyApp');
    dataDir = path.join(process.env.LOCALAPPDATA || 'C:\\Users\\Default\\AppData\\Local', 'MyApp');
    executableExt = '.exe';
    
    // Windows-specific permissions
    await exec.exec('icacls', [configDir, '/grant', 'Everyone:F']);
    
  } else if (platform.isMacOS) {
    const homeDir = process.env.HOME || '/Users/runner';
    configDir = path.join(homeDir, 'Library', 'Preferences', 'MyApp');
    dataDir = path.join(homeDir, 'Library', 'Application Support', 'MyApp');
    executableExt = '';
    
    // macOS-specific permissions
    await exec.exec('chmod', ['755', configDir]);
    
  } else if (platform.isLinux) {
    const homeDir = process.env.HOME || '/home/runner';
    configDir = path.join(homeDir, '.config', 'myapp');
    dataDir = path.join(homeDir, '.local', 'share', 'myapp');
    executableExt = '';
    
    // Linux-specific permissions
    await exec.exec('chmod', ['755', configDir]);
  }
  
  // Create directories
  await fs.promises.mkdir(configDir, { recursive: true });
  await fs.promises.mkdir(dataDir, { recursive: true });
  
  info(`Configuration directory: ${configDir}`);
  info(`Data directory: ${dataDir}`);
  info(`Executable extension: ${executableExt || 'none'}`);
  
  return { configDir, dataDir, executableExt };
}

Performance Optimization Based on Platform

import { platform, info } from '@actions/core';

async function optimizeForPlatform() {
  const details = await platform.getDetails();
  
  let workerCount: number;
  let memoryLimit: string;
  let useNativeModules: boolean;
  
  if (platform.isWindows) {
    // Windows optimization
    workerCount = Math.max(1, os.cpus().length - 1); // Leave one core free
    memoryLimit = '4GB';
    useNativeModules = details.version.includes('Server'); // Only on Server editions
    
    info('Optimizing for Windows environment');
    
  } else if (platform.isMacOS) {
    // macOS optimization
    workerCount = os.cpus().length; // macOS handles scheduling well
    memoryLimit = platform.arch === 'arm64' ? '8GB' : '4GB'; // M1/M2 have more memory
    useNativeModules = true; // Usually have development tools
    
    info(`Optimizing for macOS ${platform.arch === 'arm64' ? 'Apple Silicon' : 'Intel'}`);
    
  } else if (platform.isLinux) {
    // Linux optimization
    workerCount = Math.min(os.cpus().length, 4); // Conservative on Linux
    memoryLimit = '2GB'; // GitHub runners have limited memory
    useNativeModules = true; // Usually have build tools
    
    info('Optimizing for Linux environment');
  }
  
  // Apply optimizations
  process.env.UV_THREADPOOL_SIZE = workerCount.toString();
  process.env.NODE_OPTIONS = `--max-old-space-size=${parseInt(memoryLimit) * 1024}`;
  
  return { workerCount, memoryLimit, useNativeModules };
}

Cross-Platform Command Execution

import { platform, exec, info } from '@actions/core';

async function runCommand(command: string, args: string[] = []) {
  const details = await platform.getDetails();
    
  if (platform.isWindows) {
    // Use PowerShell for complex commands on Windows
    const psCommand = `${command} ${args.join(' ')}`;
    await exec.exec('powershell', ['-Command', psCommand]);
    
  } else {
    // Direct execution on Unix-like systems
    await exec.exec(command, args);
  }
}

async function getSystemInfo() {
  const details = await platform.getDetails();
  const systemInfo: any = {};
  
  if (platform.isWindows) {
    // Windows system information
    const { stdout: computerInfo } = await exec.getExecOutput(
      'powershell', 
      ['-Command', 'Get-ComputerInfo | ConvertTo-Json']
    );
    systemInfo.computer = JSON.parse(computerInfo);
    
    const { stdout: diskInfo } = await exec.getExecOutput(
      'powershell',
      ['-Command', 'Get-WmiObject -Class Win32_LogicalDisk | ConvertTo-Json']
    );
    systemInfo.disks = JSON.parse(diskInfo);
    
  } else if (platform.isMacOS) {
    // macOS system information
    const { stdout: hwInfo } = await exec.getExecOutput('system_profiler', ['SPHardwareDataType', '-json']);
    systemInfo.hardware = JSON.parse(hwInfo);
    
    const { stdout: diskInfo } = await exec.getExecOutput('df', ['-h']);
    systemInfo.disks = diskInfo;
    
  } else if (platform.isLinux) {
    // Linux system information
    const { stdout: cpuInfo } = await exec.getExecOutput('lscpu', ['-J']);
    systemInfo.cpu = JSON.parse(cpuInfo);
    
    const { stdout: memInfo } = await exec.getExecOutput('cat', ['/proc/meminfo']);
    systemInfo.memory = memInfo;
    
    const { stdout: diskInfo } = await exec.getExecOutput('df', ['-h']);
    systemInfo.disks = diskInfo;
  }
  
  return systemInfo;
}

Runner Environment Detection

import { platform, info, getInput } from '@actions/core';

async function detectRunnerEnvironment() {
  const details = await platform.getDetails();
  const isGitHubHosted = process.env.GITHUB_ACTIONS === 'true' && 
                         process.env.RUNNER_ENVIRONMENT === 'github-hosted';
  
  info(`Platform: ${details.platform}`);
  info(`Architecture: ${details.arch}`);
  info(`OS: ${details.name} ${details.version}`);
  info(`Runner Type: ${isGitHubHosted ? 'GitHub-hosted' : 'Self-hosted'}`);
  
  // GitHub-hosted runner specifics
  if (isGitHubHosted) {
    const runnerImageVersion = process.env.ImageVersion;
    const runnerOS = process.env.ImageOS;
    
    info(`Runner Image: ${runnerOS} ${runnerImageVersion}`);
    
    // Optimize for GitHub-hosted runners
    if (platform.isLinux) {
      info('GitHub-hosted Linux runner detected');
      // Use optimizations specific to GitHub's Linux environment
    } else if (platform.isWindows) {
      info('GitHub-hosted Windows runner detected');
      // Use optimizations specific to GitHub's Windows environment
    } else if (platform.isMacOS) {
      info('GitHub-hosted macOS runner detected');
      // Use optimizations specific to GitHub's macOS environment
    }
  } else {
    info('Self-hosted runner detected - using conservative settings');
  }
  
  return {
    platform: details.platform,
    arch: details.arch,
    osName: details.name,
    osVersion: details.version,
    isGitHubHosted,
    runnerImage: process.env.ImageOS,
    imageVersion: process.env.ImageVersion
  };
}

Compatibility Checking

import { platform, warning, setFailed, info } from '@actions/core';

async function checkCompatibility() {
  const details = await platform.getDetails();
  const issues: string[] = [];
  
  // Check minimum OS versions
  if (platform.isWindows) {
    const version = parseFloat(details.version.split('.')[0]);
    if (version < 10) {
      issues.push(`Windows ${version} is not supported. Minimum version: Windows 10`);
    }
    
    if (platform.arch !== 'x64') {
      issues.push(`Windows ${platform.arch} architecture is not supported`);
    }
    
  } else if (platform.isMacOS) {
    const majorVersion = parseInt(details.version.split('.')[0]);
    if (majorVersion < 11) {
      issues.push(`macOS ${details.version} is not supported. Minimum version: macOS 11`);
    }
    
  } else if (platform.isLinux) {
    if (details.name.includes('Ubuntu')) {
      const version = parseFloat(details.version);
      if (version < 18.04) {
        issues.push(`Ubuntu ${details.version} is not supported. Minimum version: Ubuntu 18.04`);
      }
    } else if (!details.name.includes('Ubuntu') && !details.name.includes('Debian')) {
      warning(`Untested Linux distribution: ${details.name}. Results may vary.`);
    }
  }
  
  // Check architecture support
  if (!['x64', 'arm64'].includes(platform.arch)) {
    issues.push(`Unsupported architecture: ${platform.arch}`);
  }
  
  // Report issues
  if (issues.length > 0) {
    for (const issue of issues) {
      warning(issue);
    }
    setFailed(`Compatibility check failed: ${issues.length} issues found`);
  } else {
    info(`Compatibility check passed for ${details.name} ${details.version} ${platform.arch}`);
  }
  
  return issues.length === 0;
}

Resource Monitoring

import { platform, info, warning } from '@actions/core';
import * as os from 'os';

async function monitorResources() {
  const details = await platform.getDetails();
  
  // Memory monitoring
  const totalMemory = os.totalmem();
  const freeMemory = os.freemem();
  const usedMemory = totalMemory - freeMemory;
  const memoryUsagePercent = (usedMemory / totalMemory) * 100;
  
  info(`Memory: ${Math.round(usedMemory / 1024 / 1024)}MB / ${Math.round(totalMemory / 1024 / 1024)}MB (${memoryUsagePercent.toFixed(1)}%)`);
  
  if (memoryUsagePercent > 90) {
    warning('High memory usage detected');
  }
  
  // CPU monitoring
  const cpus = os.cpus();
  info(`CPUs: ${cpus.length}x ${cpus[0].model}`);
  
  // Platform-specific monitoring
  if (platform.isLinux) {
    try {
      const { stdout } = await exec.getExecOutput('cat', ['/proc/loadavg']);
      const loadAvg = stdout.trim().split(' ').slice(0, 3);
      info(`Load Average: ${loadAvg.join(', ')}`);
      
      if (parseFloat(loadAvg[0]) > cpus.length) {
        warning('High system load detected');
      }
    } catch (error) {
      // Load average not available
    }
  }
  
  return {
    platform: details.platform,
    totalMemoryMB: Math.round(totalMemory / 1024 / 1024),
    usedMemoryMB: Math.round(usedMemory / 1024 / 1024),
    memoryUsagePercent: memoryUsagePercent,
    cpuCount: cpus.length,
    cpuModel: cpus[0].model
  };
}

Platform-Specific Considerations

Windows Runners

  • Use PowerShell for complex operations
  • Handle path separators correctly
  • Consider Windows-specific permissions
  • Account for case-insensitive filesystem
  • Be aware of Windows Server editions vs desktop Windows

macOS Runners

  • Handle both Intel and Apple Silicon architectures
  • Use Homebrew for package management
  • Consider macOS-specific directory structures
  • Handle code signing requirements
  • Account for macOS security policies

Linux Runners

  • Support multiple distributions (Ubuntu, Debian, CentOS, etc.)
  • Use appropriate package managers
  • Handle different init systems
  • Consider container environments
  • Account for varying default configurations

Architecture Considerations

  • x64 (Intel/AMD 64-bit): Most common architecture
  • arm64 (ARM 64-bit): Apple Silicon Macs, some Linux systems
  • Handle architecture-specific binary downloads
  • Consider performance differences between architectures