Add AV/Defender tests and clear PROBLEMS.md antivirus rows.

Cover mining diagnostics JSON blockers, AV-Safe preset fields, defender_off error paths, and Calibrate exclusion .ps1 generation with Go + Vitest; honest AV limits already documented in settingHelp.
This commit is contained in:
AetherForge
2026-06-07 06:34:56 -07:00
parent 74c006a04b
commit 7831e70dd4
35 changed files with 436 additions and 197 deletions

View File

@@ -17,8 +17,8 @@
background-image:
linear-gradient(rgba(201, 162, 39, 0.04) 1px, transparent 1px),
linear-gradient(90deg, rgba(201, 162, 39, 0.04) 1px, transparent 1px),
linear-gradient(rgba(0, 245, 255, 0.02) 1px, transparent 1px),
linear-gradient(90deg, rgba(0, 245, 255, 0.02) 1px, transparent 1px);
linear-gradient(rgba(0, 232, 245, 0.02) 1px, transparent 1px),
linear-gradient(90deg, rgba(0, 232, 245, 0.02) 1px, transparent 1px);
background-size: 80px 80px, 80px 80px, 20px 20px, 20px 20px;
animation: grid-drift var(--weather-grid-drift) linear infinite;
transform: perspective(500px) rotateX(60deg) scale(2);
@@ -43,7 +43,7 @@
.ambient-orb-cyan {
width: 400px;
height: 400px;
background: rgba(0, 245, 255, 0.12);
background: rgba(0, 232, 245, 0.12);
top: 10%;
right: 5%;
animation-delay: 0s;
@@ -72,7 +72,7 @@
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, transparent, rgba(0, 245, 255, 0.15), transparent);
background: linear-gradient(90deg, transparent, rgba(0, 232, 245, 0.15), transparent);
animation: scanline 8s linear infinite;
opacity: 0.5;
}

View File

@@ -36,7 +36,7 @@
animation-delay: 0s;
}
.ambient-sparkle--2 {
color: rgba(0, 245, 255, 0.45);
color: rgba(0, 232, 245, 0.45);
top: 72%;
left: 68%;
animation-delay: -1.2s;
@@ -57,7 +57,7 @@
.ambient-sparkle:nth-child(5) {
top: 8%;
left: 55%;
color: rgba(0, 245, 255, 0.35);
color: rgba(0, 232, 245, 0.35);
animation-delay: -0.8s;
}
.ambient-sparkle:nth-child(6) {
@@ -81,7 +81,7 @@
.ambient-sparkle:nth-child(9) {
top: 35%;
left: 8%;
color: rgba(0, 245, 255, 0.38);
color: rgba(0, 232, 245, 0.38);
animation-delay: -2.8s;
}
.ambient-sparkle:nth-child(10) {

View File

@@ -37,7 +37,7 @@
font-size: 1.1rem;
font-weight: 700;
color: var(--neon-cyan);
text-shadow: 0 0 12px rgba(0, 245, 255, 0.5);
text-shadow: 0 0 12px rgba(0, 232, 245, 0.5);
line-height: 1.2;
}

View File

@@ -49,7 +49,7 @@
border: 1px solid var(--border-brass);
border-radius: 2px;
padding: 0.75rem 1rem;
box-shadow: 0 0 20px rgba(0, 245, 255, 0.15), var(--shadow-panel);
box-shadow: 0 0 20px rgba(0, 232, 245, 0.15), var(--shadow-panel);
}
.neon-tooltip-time {

View File

@@ -33,7 +33,7 @@ interface HashrateChartProps {
const GRAD_IDS = ['cyan', 'magenta', 'amber', 'green', 'purple'] as const;
function colorToId(color: string): string {
if (color.includes('e8f5') || color.includes('f5ff') || color.includes('06b6d4') || color === '#00e8f5' || color === '#00f5ff' || color.includes('neon-cyan')) return 'cyan';
if (color.includes('e8f5') || color.includes('f5ff') || color.includes('06b6d4') || color === '#00e8f5' || color === '#00e8f5' || color.includes('neon-cyan')) return 'cyan';
if (color.includes('2da6') || color.includes('8b5cf6')) return 'magenta';
if (color.includes('b020') || color.includes('eab308')) return 'amber';
if (color.includes('39ff') || color.includes('22c55e')) return 'green';

View File

@@ -175,7 +175,7 @@
.access-depth-tag--active {
color: var(--neon-cyan);
border: 1px solid rgba(0, 245, 255, 0.35);
border: 1px solid rgba(0, 232, 245, 0.35);
}
.access-depth-tag--skip {
@@ -248,7 +248,7 @@
font-weight: 700;
letter-spacing: 0.08em;
color: var(--neon-cyan);
border: 1px solid rgba(0, 245, 255, 0.45);
border: 1px solid rgba(0, 232, 245, 0.45);
border-radius: 3px;
padding: 1px 6px;
cursor: help;

View File

@@ -223,7 +223,7 @@
outline: none;
}
.upgrade-select:focus { border-color: var(--neon-cyan, #00e5ff); }
.upgrade-select:focus { border-color: var(--neon-cyan, #00e8f5); }
.upgrade-btn {
white-space: nowrap;

View File

@@ -27,9 +27,9 @@
aspect-ratio: 1;
min-height: 160px;
border-radius: 8px;
border: 1px solid rgba(0, 245, 255, 0.18);
border: 1px solid rgba(0, 232, 245, 0.18);
background:
radial-gradient(ellipse at 50% 45%, rgba(0, 245, 255, 0.06) 0%, transparent 65%),
radial-gradient(ellipse at 50% 45%, rgba(0, 232, 245, 0.06) 0%, transparent 65%),
rgba(0, 0, 0, 0.45);
overflow: hidden;
}
@@ -38,8 +38,8 @@
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(0, 245, 255, 0.04) 1px, transparent 1px),
linear-gradient(90deg, rgba(0, 245, 255, 0.04) 1px, transparent 1px);
linear-gradient(rgba(0, 232, 245, 0.04) 1px, transparent 1px),
linear-gradient(90deg, rgba(0, 232, 245, 0.04) 1px, transparent 1px);
background-size: 20% 20%;
pointer-events: none;
}
@@ -94,7 +94,7 @@
box-shadow:
0 0 0 3px rgba(255, 255, 255, 0.25),
0 0 22px var(--dot-color, var(--neon-cyan)),
0 0 36px rgba(0, 245, 255, 0.55);
0 0 36px rgba(0, 232, 245, 0.55);
}
100% {
transform: translate(-50%, -50%) scale(1);

View File

@@ -48,7 +48,7 @@
align-items: center;
gap: 0.75rem;
padding: 0.6rem 0.75rem;
border: 1px solid rgba(0, 245, 255, 0.15);
border: 1px solid rgba(0, 232, 245, 0.15);
border-radius: 6px;
background: rgba(0, 0, 0, 0.2);
}
@@ -142,15 +142,15 @@
.agent-action-btn {
padding: 0.4rem 0.75rem;
font-size: 0.75rem;
border: 1px solid rgba(0, 245, 255, 0.35);
background: rgba(0, 245, 255, 0.08);
border: 1px solid rgba(0, 232, 245, 0.35);
background: rgba(0, 232, 245, 0.08);
color: var(--text-primary);
border-radius: 4px;
cursor: pointer;
}
.agent-action-btn:hover {
background: rgba(0, 245, 255, 0.18);
background: rgba(0, 232, 245, 0.18);
}
.agent-action-btn.danger {
@@ -164,7 +164,7 @@
overflow: auto;
padding: 0.75rem;
background: rgba(0, 0, 0, 0.35);
border: 1px solid rgba(0, 245, 255, 0.2);
border: 1px solid rgba(0, 232, 245, 0.2);
border-radius: 6px;
font-family: var(--font-mono, monospace);
font-size: 0.72rem;

View File

@@ -16,8 +16,8 @@
.lotl-tier-badge--active,
.cn-lotl.lotl-active {
color: var(--neon-cyan);
background: rgba(0, 245, 255, 0.12);
border: 1px solid rgba(0, 245, 255, 0.28);
background: rgba(0, 232, 245, 0.12);
border: 1px solid rgba(0, 232, 245, 0.28);
}
.lotl-tier-badge--fail,
@@ -71,7 +71,7 @@
.lotl-attempts-block {
margin: 0.35rem 0 0.5rem;
padding: 0.45rem 0.65rem;
border-left: 2px solid rgba(0, 245, 255, 0.35);
border-left: 2px solid rgba(0, 232, 245, 0.35);
background: rgba(0, 0, 0, 0.35);
border-radius: 0 4px 4px 0;
font-family: var(--font-tech);

View File

@@ -46,7 +46,7 @@
}
.protocol-tunnel-card {
border: 1px solid rgba(0, 245, 255, 0.15);
border: 1px solid rgba(0, 232, 245, 0.15);
border-radius: 6px;
padding: 0.65rem 0.75rem;
background: rgba(0, 0, 0, 0.25);

View File

@@ -18,20 +18,20 @@
width: 1rem;
height: 1rem;
border-radius: 2px;
background: rgba(0, 245, 255, 0.1);
border: 1px solid rgba(0, 245, 255, 0.35);
background: rgba(0, 232, 245, 0.1);
border: 1px solid rgba(0, 232, 245, 0.35);
color: var(--neon-cyan);
font-size: 0.6875rem;
font-weight: 700;
box-shadow: 0 0 8px rgba(0, 245, 255, 0.2);
box-shadow: 0 0 8px rgba(0, 232, 245, 0.2);
transition: background 0.15s, box-shadow 0.15s, border-color 0.15s;
}
.help-tip-trigger:hover .help-tip-icon,
.help-tip-trigger:focus-visible .help-tip-icon {
background: rgba(0, 245, 255, 0.22);
border-color: rgba(0, 245, 255, 0.65);
box-shadow: 0 0 12px rgba(0, 245, 255, 0.45);
background: rgba(0, 232, 245, 0.22);
border-color: rgba(0, 232, 245, 0.65);
box-shadow: 0 0 12px rgba(0, 232, 245, 0.45);
}
.help-tip-label {
@@ -48,11 +48,11 @@
line-height: 1.45;
color: #e8f4f8;
background: rgba(6, 14, 18, 0.97);
border: 1px solid rgba(0, 245, 255, 0.45);
border: 1px solid rgba(0, 232, 245, 0.45);
border-radius: 4px;
box-shadow:
0 4px 24px rgba(0, 0, 0, 0.55),
0 0 16px rgba(0, 245, 255, 0.12);
0 0 16px rgba(0, 232, 245, 0.12);
pointer-events: auto;
animation: help-tip-in 0.12s ease-out;
}

View File

@@ -8,7 +8,7 @@
width: 260px;
background: linear-gradient(180deg, rgba(16, 12, 8, 0.97) 0%, rgba(8, 6, 4, 0.98) 100%);
border-right: 1px solid var(--border-brass);
box-shadow: 4px 0 40px rgba(0, 0, 0, 0.5), inset -1px 0 0 rgba(0, 245, 255, 0.08);
box-shadow: 4px 0 40px rgba(0, 0, 0, 0.5), inset -1px 0 0 rgba(0, 232, 245, 0.08);
display: flex;
flex-direction: column;
position: fixed;
@@ -156,10 +156,10 @@
}
.nav-item.active {
background: linear-gradient(90deg, rgba(0, 245, 255, 0.12), transparent);
background: linear-gradient(90deg, rgba(0, 232, 245, 0.12), transparent);
color: var(--neon-cyan);
border-color: rgba(0, 245, 255, 0.35);
box-shadow: inset 0 0 20px rgba(0, 245, 255, 0.08);
border-color: rgba(0, 232, 245, 0.35);
box-shadow: inset 0 0 20px rgba(0, 232, 245, 0.08);
}
.nav-icon {
@@ -402,7 +402,7 @@
.readout-bar-fill.readout-bar-active {
background: linear-gradient(90deg, var(--neon-green), var(--neon-cyan));
box-shadow: 0 0 6px rgba(0, 245, 255, 0.35);
box-shadow: 0 0 6px rgba(0, 232, 245, 0.35);
animation: bar-shimmer 2.5s ease-in-out infinite;
background-size: 200% 100%;
}
@@ -451,7 +451,7 @@
.sig-ver {
font-size: 0.55rem;
color: rgba(0, 245, 255, 0.35);
color: rgba(0, 232, 245, 0.35);
letter-spacing: 0.18em;
}

View File

@@ -119,7 +119,7 @@
}
.mobile-bottom-nav-item.active {
background: rgba(0, 245, 255, 0.08);
background: rgba(0, 232, 245, 0.08);
}
.mobile-menu-backdrop {
@@ -171,7 +171,7 @@
}
.mobile-more-link.active {
background: rgba(0, 245, 255, 0.1);
background: rgba(0, 232, 245, 0.1);
color: var(--neon-cyan);
}

View File

@@ -0,0 +1,37 @@
.sacred-page-header {
position: relative;
}
.sacred-page-header::before {
content: '';
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 1px;
pointer-events: none;
background: linear-gradient(
90deg,
transparent,
rgba(201, 162, 39, 0.5) 15%,
rgba(0, 232, 245, 0.35) 50%,
rgba(201, 162, 39, 0.5) 85%,
transparent
);
}
.sacred-page-header-motif {
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
width: 48px;
height: 48px;
opacity: 0.2;
pointer-events: none;
}
.deck-hero-status + .sacred-page-header-motif,
.deck-hero-actions + .sacred-page-header-motif {
right: 0.5rem;
}

View File

@@ -0,0 +1,36 @@
/**
* @vitest-environment happy-dom
*/
import { describe, expect, it, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import SacredPageHeader from './SacredPageHeader';
vi.mock('../../HelpTip', () => ({
HelpTip: ({ field }: { field: string }) => <span data-testid={`help-${field}`}>?</span>,
}));
vi.mock('./motifs', () => ({
SacredMotif: () => <svg data-testid="sacred-motif" />,
}));
describe('SacredPageHeader', () => {
it('renders deck-hero chrome with eyebrow, title, subtitle, and motif', () => {
const { container } = render(
<SacredPageHeader
eyebrow="NETWORK OPS"
title="Path Tracer"
subtitle="Multi-hop WireGuard chain."
helpField="pt_path_tracer"
actions={<button type="button">Go</button>}
/>,
);
expect(container.querySelector('.deck-hero.sacred-page-header')).toBeTruthy();
expect(screen.getByText('NETWORK OPS')).toBeInTheDocument();
expect(screen.getByRole('heading', { level: 1 })).toHaveTextContent('Path Tracer');
expect(screen.getByText('Multi-hop WireGuard chain.')).toBeInTheDocument();
expect(screen.getByTestId('help-pt_path_tracer')).toBeInTheDocument();
expect(screen.getByTestId('sacred-motif')).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Go' })).toBeInTheDocument();
});
});

View File

@@ -0,0 +1,45 @@
import type { ReactNode } from 'react';
import { HelpTip } from '../../HelpTip';
import { SacredMotif } from './motifs';
import './SacredPageHeader.css';
export interface SacredPageHeaderProps {
eyebrow?: string;
title: ReactNode;
subtitle?: ReactNode;
helpField?: string;
actions?: ReactNode;
status?: ReactNode;
className?: string;
heroClassName?: string;
}
/** Unified operator-deck page hero — eyebrow, title, subtitle, optional sacred motif. */
export default function SacredPageHeader({
eyebrow,
title,
subtitle,
helpField,
actions,
status,
className = '',
heroClassName = '',
}: SacredPageHeaderProps) {
return (
<header className={`deck-hero sacred-page-header ${heroClassName} ${className}`.trim()}>
<div className="deck-hero-text">
{eyebrow ? <p className="deck-eyebrow font-tech">{eyebrow}</p> : null}
<h1>
{title}
{helpField ? <> <HelpTip field={helpField} /></> : null}
</h1>
{subtitle ? <p className="page-subtitle">{subtitle}</p> : null}
</div>
{actions ? <div className="deck-hero-actions">{actions}</div> : null}
{status ? <div className="deck-hero-status">{status}</div> : null}
<div className="sacred-page-header-motif" aria-hidden>
<SacredMotif name="hex" opacity={0.55} />
</div>
</header>
);
}