Add forge pipeline polish, simple forge UX, and fleet management upgrades.

Fusion copies prep icon and version info via go-winres; optional Garble obfuscation, Authenticode signing, and dry-run size estimates. Forge Simple mode with smart defaults; fleet roster gets compact expandable cards, filters, bulk commands, per-agent notes/tags, and typed WebSocket payloads.
This commit is contained in:
drjones
2026-05-28 21:48:20 -07:00
parent fda72041f0
commit c95a4373de
45 changed files with 2282 additions and 272 deletions

View File

@@ -176,6 +176,11 @@ export default function SettingsPage() {
strict_wallet_validation: false,
dashboard_subtitle: '',
open_firewall_on_start: true,
obfuscate_default: false,
sign_enabled: false,
sign_cert_thumbprint: '',
sign_tool_path: '',
sign_timestamp_url: 'http://timestamp.digicert.com',
};
return (
@@ -210,7 +215,27 @@ export default function SettingsPage() {
{serverInfo.local_ips?.length > 0 && (
<p className="form-hint">IPs on this host: {serverInfo.local_ips.join(' · ')}</p>
)}
<p className="form-hint">Set Public URL below if you want the Forge to default to a specific address.</p>
<p className="form-hint">Workers need this LAN address not localhost. Click below to apply best defaults, then Save Calibration.</p>
<button
type="button"
className="btn btn-primary btn-sm"
style={{ marginTop: '0.75rem' }}
onClick={() => {
if (!config) return;
updateField('server.public_url', serverInfo.suggested_url);
updateField('server.open_firewall_on_start', true);
updateField('server.obfuscate_default', false);
updateField('server.sign_enabled', false);
if (!config.wallet.address?.trim()) {
setSaveMessage('Set your Monero wallet below, then Save Calibration.');
} else {
setSaveMessage('Best defaults applied to the form — click Save Calibration to keep them.');
}
}}
>
Use best defaults
</button>
<FieldHint field="calibrate_quick_setup" />
</NeonCard>
)}
@@ -233,9 +258,18 @@ export default function SettingsPage() {
</div>
<div className="form-group">
<label className="label">Public URL (LAN) <HelpTip field="public_url" /></label>
<input type="text" className="input mono" placeholder={serverInfo?.suggested_url || 'http://192.168.1.x:8989'}
value={s.public_url}
onChange={(e) => updateField('server.public_url', e.target.value)} />
<div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap', alignItems: 'center' }}>
<input type="text" className="input mono" style={{ flex: 1, minWidth: '200px' }}
placeholder={serverInfo?.suggested_url || 'http://192.168.1.x:8989'}
value={s.public_url}
onChange={(e) => updateField('server.public_url', e.target.value)} />
{serverInfo?.suggested_url && (
<button type="button" className="btn btn-outline btn-sm"
onClick={() => updateField('server.public_url', serverInfo.suggested_url)}>
Use detected LAN
</button>
)}
</div>
<FieldHint field="public_url" />
</div>
<div className="form-group">
@@ -291,9 +325,11 @@ export default function SettingsPage() {
<h2 className="font-display">Fleet Payout Wallet</h2>
<p className="section-desc">Default wallet the server uses when connecting to the pool. The Forge pre-fills this when building miners.</p>
<div className="form-group">
<label className="label">XMR Address <HelpTip field="wallet" /></label>
<input type="text" className="input mono" value={config.wallet.address}
<label className="label">XMR Address <HelpTip field="calibrate_wallet" /></label>
<input type="text" className="input mono" placeholder="4… (95 chars)"
value={config.wallet.address}
onChange={(e) => updateField('wallet.address', e.target.value)} />
<FieldHint field="calibrate_wallet" />
</div>
<div className="form-group">
<label className="label">Payment ID (optional)</label>
@@ -395,6 +431,47 @@ export default function SettingsPage() {
)}
</NeonCard>
<NeonCard accent="brass" className="settings-section">
<h2 className="font-display">Forge Pipeline</h2>
<p className="section-desc">Defaults for obfuscation and code signing applied when forging on this control PC.</p>
<div className="form-group checkbox-group">
<label className="checkbox-label">
<input type="checkbox" className="checkbox" checked={s.obfuscate_default ?? false}
onChange={(e) => updateField('server.obfuscate_default', e.target.checked)} />
<span>Default: obfuscate new forges with Garble <HelpTip field="obfuscate_default" /></span>
</label>
<FieldHint field="obfuscate_default" />
</div>
<div className="form-group checkbox-group">
<label className="checkbox-label">
<input type="checkbox" className="checkbox" checked={s.sign_enabled ?? false}
onChange={(e) => updateField('server.sign_enabled', e.target.checked)} />
<span>Default: sign forged executables <HelpTip field="sign_enabled" /></span>
</label>
<FieldHint field="sign_enabled" />
</div>
<div className="form-group">
<label className="label">Code signing cert thumbprint (SHA-1) <HelpTip field="sign_cert_thumbprint" /></label>
<input type="text" className="input mono" placeholder="AB CD EF ..."
value={s.sign_cert_thumbprint || ''}
onChange={(e) => updateField('server.sign_cert_thumbprint', e.target.value)} />
<FieldHint field="sign_cert_thumbprint" />
</div>
<div className="form-group">
<label className="label">signtool.exe path (optional) <HelpTip field="sign_tool_path" /></label>
<input type="text" className="input mono" placeholder="Auto-detect from Windows SDK"
value={s.sign_tool_path || ''}
onChange={(e) => updateField('server.sign_tool_path', e.target.value)} />
</div>
<div className="form-group">
<label className="label">Timestamp server URL <HelpTip field="sign_timestamp_url" /></label>
<input type="text" className="input mono"
value={s.sign_timestamp_url || 'http://timestamp.digicert.com'}
onChange={(e) => updateField('server.sign_timestamp_url', e.target.value)} />
<FieldHint field="sign_timestamp_url" />
</div>
</NeonCard>
<NeonCard accent="green" className="settings-section">
<h2 className="font-display">Data & Limits</h2>
<p className="section-desc">Retention and capacity for this host.</p>