feat: Telegram fleet alerts, forge sigil scramble, UI polish, agent ops

- Calibrate: per-event Telegram/SMTP toggles, test notification, chat ID help
- Notify on agent connect/reconnect, offline/hashrate/rejection, forge complete
- Sigil scramble post-forge uniquification and Dispense Reveal ceremony
- Full system check, desktop push, BITS/host-binary persistence, Path Tracer
- Dashboard/Crucible visual polish, haptics, sacred geometry, mobile nav
- README documents alerts, sigil scramble, and pack-usb workflow
- USB bundle repacked via pack-usb.bat (AetherForge.exe + synced agent source)
This commit is contained in:
AetherForge
2026-06-03 20:32:59 -07:00
parent 03937edba7
commit d52479c9a6
139 changed files with 10611 additions and 369 deletions

View File

@@ -13,6 +13,7 @@ import { downloadApiFile, downloadAuthedFile } from '../api/download';
import { getStoredAuth } from '../api/auth';
import { useWebSocket } from '../hooks/useWebSocket';
import { DEFAULT_FLEET_FILTERS } from '../help/fleetFilters';
import { generateSampleSeries, validateChartSeries } from '../help/chartSampleData';
import NeonCard from './NeonCard/NeonCard';
import { HelpTip, FieldHint } from './HelpTip';
@@ -316,7 +317,23 @@ describe('HashrateChart', () => {
it('shows empty state when data is empty', () => {
render(<HashrateChart data={[]} title="Fleet Hash" />);
expect(screen.getByText('Fleet Hash')).toBeInTheDocument();
expect(screen.getByText(/Awaiting signal from fleet/i)).toBeInTheDocument();
expect(screen.getByText(/Calibrating chart telemetry/i)).toBeInTheDocument();
});
it('renders chart with validated sample series', () => {
const sample = generateSampleSeries('hashrate', 24);
expect(validateChartSeries(sample).ok).toBe(true);
render(
<HashrateChart
data={sample}
displayMode="sample"
title="Fleet Hash"
color="#00f5ff"
unit="H/s"
/>
);
expect(screen.getByText(/PEAK/)).toBeInTheDocument();
expect(screen.getByText(/PROJECTION/)).toBeInTheDocument();
});
it('renders chart with data points', () => {
@@ -728,6 +745,8 @@ describe('AmbientBackground', () => {
const { container } = render(<AmbientBackground />);
expect(container.querySelector('.ambient-bg')).toBeTruthy();
expect(container.querySelector('.ambient-sacred-geo')).toBeTruthy();
expect(container.querySelector('.ambient-geo-hex-veil')).toBeTruthy();
expect(container.querySelectorAll('.ambient-geo-corner').length).toBeGreaterThanOrEqual(2);
});
});