Files
NetMesh/infrastructure/ai/harness/builtinSkills.ts

132 lines
9.4 KiB
TypeScript
Raw Normal View History

/**
* Built-in diagnostic skills pre-crafted multi-step shell command bundles
* targeting specific OS families. The Catty Agent calls `skill_run` with a
* skillName and sessionId; this module expands that into the right commands
* for the host's detected OS/shellType.
*
* Each skill is an ordered list of { label, shell, command } entries. The
* executor runs them sequentially and assembles the outputs into a single
* structured report the LLM can summarize for the user.
*/
export type SkillShellTarget = 'posix' | 'powershell' | 'cmd' | 'any';
export interface SkillStep {
/** Short human label shown in the assembled report. */
label: string;
/** Shell family this step is for. 'any' = run regardless. */
shell: SkillShellTarget;
/** Command to send to the terminal. */
command: string;
}
export interface BuiltinSkill {
id: string;
/** Short description the model sees in the tool's docstring. */
description: string;
/** If true, requires the session to be a remote SSH host. */
requiresRemoteHost?: boolean;
/** Steps grouped by OS family. */
steps: SkillStep[];
}
// ---------------------------------------------------------------------------
// Skill registry — keep alphabetical by id
// ---------------------------------------------------------------------------
export const BUILTIN_SKILLS: Record<string, BuiltinSkill> = {
// ---- diagnose_linux -----------------------------------------------------
diagnose_linux: {
id: 'diagnose_linux',
description:
'Quick Linux health check — CPU, memory, disk, load top processes, listening ports, Docker status, failed systemd services, recent kernel errors.',
requiresRemoteHost: true,
steps: [
{ label: 'OS / kernel / uptime', shell: 'posix', command: 'uname -a; uptime; cat /etc/os-release 2>/dev/null | head -5' },
{ label: 'CPU & memory', shell: 'posix', command: "echo '--- free -h ---'; free -h; echo '--- vmstat 1 2 ---'; vmstat 1 2 | tail -1" },
{ label: 'Disk usage', shell: 'posix', command: "df -h 2>/dev/null; echo '--- inodes ---'; df -i 2>/dev/null | head -10" },
{ label: 'Top processes by CPU', shell: 'posix', command: 'ps aux --sort=-%cpu 2>/dev/null | head -10 || ps aux | sort -k3 -rn | head -10' },
{ label: 'Listening ports', shell: 'posix', command: "ss -tlnp 2>/dev/null | head -20 || netstat -tlnp 2>/dev/null | head -20" },
{ label: 'Docker status (if present)', shell: 'posix', command: 'command -v docker >/dev/null 2>&1 && (docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" 2>&1 | head -15) || echo "docker not installed"' },
{ label: 'Failed systemd services', shell: 'posix', command: "systemctl --failed --no-pager 2>/dev/null | head -20 || echo 'systemd not available'" },
{ label: 'Recent kernel errors', shell: 'posix', command: "dmesg --level=err -n 2>/dev/null | tail -15 || journalctl -p err -n 15 --no-pager 2>/dev/null || echo 'no kernel error log available'" },
],
},
// ---- diagnose_windows ---------------------------------------------------
diagnose_windows: {
id: 'diagnose_windows',
description:
'Quick Windows health check via PowerShell — OS, CPU, memory, disk, top processes, services, network adapters, recent errors.',
requiresRemoteHost: true,
steps: [
{ label: 'OS & uptime', shell: 'powershell', command: '$os = Get-CimInstance Win32_OperatingSystem; "Computer: $($env:COMPUTERNAME)"; "OS: $($os.Caption) $($os.Version)"; "Uptime: $([math]::Round(((Get-Date) - $os.LastBootUpTime).TotalHours, 1)) hours"' },
{ label: 'CPU', shell: 'powershell', command: 'Get-CimInstance Win32_Processor | Select-Object Name, NumberOfCores, LoadPercentage | Format-List' },
{ label: 'Memory', shell: 'powershell', command: '$cs = Get-CimInstance Win32_ComputerSystem; $os = Get-CimInstance Win32_OperatingSystem; $totalGB = [math]::Round($cs.TotalPhysicalMemory/1GB, 1); $freeGB = [math]::Round($os.FreePhysicalMemory/1MB, 1); "Total: ${totalGB} GB, Free: ${freeGB} GB, Used: $([math]::Round(($totalGB - $freeGB)/$totalGB*100, 1))%"' },
{ label: 'Disk', shell: 'powershell', command: 'Get-Volume -DriveLetter * | Where-Object DriveLetter | Select-Object DriveLetter, FileSystemLabel, FileSystem, @{N="TotalGB";E={[math]::Round($_.Size/1GB,1)}}, @{N="FreeGB";E={[math]::Round($_.SizeRemaining/1GB,1)}} | Format-Table -AutoSize' },
{ label: 'Top processes (working set)', shell: 'powershell', command: 'Get-Process | Sort-Object WorkingSet64 -Descending | Select-Object -First 10 Name, Id, @{N="MB";E={[math]::Round($_.WorkingSet64/1MB,0)}}, CPU | Format-Table -AutoSize' },
{ label: 'Services running', shell: 'powershell', command: 'Get-Service | Where-Object Status -eq Running | Measure-Object | Select-Object -ExpandProperty Count | ForEach-Object { "$_ services running" }; Get-Service | Where-Object {$_.Status -ne "Running" -and $_.StartType -ne "Disabled"} | Select-Object -First 15 Name, Status, StartType | Format-Table -AutoSize' },
{ label: 'Listening ports', shell: 'powershell', command: 'Get-NetTCPConnection -State Listen -ErrorAction SilentlyContinue | Select-Object LocalAddress, LocalPort, OwningProcess | Sort-Object LocalPort | Format-Table -AutoSize' },
{ label: 'Recent errors (System log)', shell: 'powershell', command: 'Get-WinEvent -LogName System -MaxEvents 50 -ErrorAction SilentlyContinue | Where-Object {$_.LevelDisplayName -eq "Error"} | Select-Object -First 10 TimeCreated, Id, ProviderName, Message | Format-List' },
],
},
// ---- check_ports --------------------------------------------------------
check_ports: {
id: 'check_ports',
description: 'Show all listening TCP/UDP ports with process info (ss/netstat on Linux, netstat/Get-NetTCPConnection on Windows).',
steps: [
{ label: 'Listening ports (POSIX)', shell: 'posix', command: "echo '=== ss ==='; ss -tulnp 2>/dev/null || echo 'ss not available'; echo '=== netstat ==='; netstat -tulnp 2>/dev/null | head -30 || true" },
{ label: 'Listening ports (PowerShell)', shell: 'powershell', command: 'Write-Host "=== TCP Listen ===" ; Get-NetTCPConnection -State Listen -ErrorAction SilentlyContinue | Select-Object LocalAddress, LocalPort, OwningProcess | Sort-Object LocalPort | Format-Table -AutoSize; Write-Host "=== UDP ===" ; Get-NetUDPEndpoint -ErrorAction SilentlyContinue | Select-Object LocalAddress, LocalPort, OwningProcess | Sort-Object LocalPort | Format-Table -AutoSize' },
],
},
// ---- check_docker -------------------------------------------------------
check_docker: {
id: 'check_docker',
description: 'Check Docker daemon health, running containers, disk usage, and recent images.',
requiresRemoteHost: true,
steps: [
{ label: 'Docker version / info', shell: 'any', command: 'docker version 2>&1 | head -15; echo "---"; docker info 2>&1 | head -20' },
{ label: 'Containers (all)', shell: 'any', command: 'docker ps -a --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}" 2>&1' },
{ label: 'Docker disk usage', shell: 'any', command: 'docker system df 2>&1' },
{ label: 'Top images', shell: 'any', command: 'docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" 2>&1 | head -15' },
],
},
// ---- security_audit -----------------------------------------------------
security_audit: {
id: 'security_audit',
description: 'Basic Linux security posture check — SSH config, firewall, failed SSH logins, world-writable files, listening ports.',
requiresRemoteHost: true,
steps: [
{ label: 'SSHD config quick check', shell: 'posix', command: "echo '=== PermitRootLogin ==='; grep -i 'PermitRootLogin' /etc/ssh/sshd_config 2>/dev/null || echo '(not set = default)'; echo '=== PasswordAuthentication ==='; grep -i 'PasswordAuthentication' /etc/ssh/sshd_config 2>/dev/null || echo '(not set = default)'" },
{ label: 'Firewall status', shell: 'posix', command: "echo '=== ufw ==='; command -v ufw >/dev/null 2>&1 && ufw status 2>&1 || echo 'ufw not installed'; echo '=== firewalld ==='; command -v firewall-cmd >/dev/null 2>&1 && firewall-cmd --state 2>&1 || echo 'firewalld not installed'" },
{ label: 'Failed SSH logins (last)', shell: 'posix', command: "echo '=== Recent failed SSH ==='; lastb 2>/dev/null | head -10 || echo 'lastb not available'" },
{ label: 'World-writable files in /tmp (non-sticky)', shell: 'posix', command: 'find /tmp -maxdepth 2 -type f ! -sticky -perm -0002 2>/dev/null | head -10 || echo "ok"' },
{ label: 'Listening ports', shell: 'posix', command: "ss -tlnp 2>/dev/null | head -20 || netstat -tlnp 2>/dev/null | head -20" },
],
},
};
/** All skill ids, exported so callers can validate. */
export const BUILTIN_SKILL_IDS = Object.keys(BUILTIN_SKILLS);
/** Resolve a skill by id (case-insensitive). */
export function getBuiltinSkill(skillId: string): BuiltinSkill | null {
if (!skillId) return null;
return BUILTIN_SKILLS[skillId.toLowerCase()] ?? null;
}
/** Return steps matching the host's shell family (run 'any' on every host). */
export function filterStepsForShell(skill: BuiltinSkill, shellType?: string): SkillStep[] {
const shell = (shellType || 'posix').toLowerCase();
return skill.steps.filter(step => {
if (step.shell === 'any') return true;
if (step.shell === shell) return true;
// Treat 'fish' / unknown POSIX-ish shells as posix for diagnostics.
if (step.shell === 'posix' && (shell === 'fish' || shell === 'unknown' || shell === 'posix')) return true;
return false;
});
}