// Control — kill-switch, force-jump (2-step + TOTP), config reload. const { Card, Pill, fmtTs } = window.UI; function PageControl({ app, setApp }) { return (

control

operator actions · changes here move real funds in live mode

); } function KillSwitchCard({ app, setApp }) { const [confirm, setConfirm] = React.useState(''); const [busy, setBusy] = React.useState(false); const [err, setErr] = React.useState(''); const halted = app.halted; const reason = halted || ''; const halt = async () => { if (confirm.trim() !== 'HALT') return; setBusy(true); setErr(''); try { const r = await window.API.post('/api/v1/control/halt', { reason: 'manual: stopped via /control by operator' }); setApp(s => ({ ...s, halted: r.reason || 'manual halt' })); setConfirm(''); } catch (e) { setErr(e.message || 'halt failed'); } finally { setBusy(false); } }; const resume = async () => { setBusy(true); setErr(''); try { await window.API.post('/api/v1/control/resume', {}); setApp(s => ({ ...s, halted: null })); } catch (e) { setErr(e.message || 'resume failed'); } finally { setBusy(false); } }; return (
{halted ? : }
{halted ? 'system halted' : 'system running'}
{halted && (
{reason}
)} {/* "last trip" needs an api_events lookup that ships in M11.2 alongside the risk gate; suppressed for now to avoid showing a fake timestamp. */}
{!halted ? (

stops the dispatcher; in-flight orders are reconciled but no new intents are emitted. persists across restart.

) : (

resume re-arms the dispatcher. risk gates are re-evaluated before any new order is sent.

)} {err && (
{err}
)}
); } function ForceJumpCard({ app }) { const acct = (app.accounts || []).find(a => a.id === app.account) || null; const coins = (acct && Array.isArray(acct.coins)) ? acct.coins.filter(c => c !== acct.bridge) : []; const initialFrom = (acct && acct.current_coin) || coins[0] || ''; const initialTo = coins.find(c => c !== initialFrom) || ''; const [step, setStep] = React.useState(1); const [from, setFrom] = React.useState(initialFrom); const [to, setTo] = React.useState(initialTo); const [note, setNote] = React.useState(''); const [nonce, setNonce] = React.useState(''); const [code, setCode] = React.useState(''); const [entered, setEntered] = React.useState(''); const [done, setDone] = React.useState(false); const [busy, setBusy] = React.useState(false); const [err, setErr] = React.useState(''); const request = async () => { setBusy(true); setErr(''); try { const r = await window.API.post('/api/v1/control/force-jump', { action: 'request', account_id: acct ? acct.accountID : 0, from, to, note, }); setNonce(r.nonce || ''); setCode(r.code || ''); setStep(2); } catch (e) { setErr(e.message || 'request failed'); } finally { setBusy(false); } }; const confirm = async () => { setBusy(true); setErr(''); try { await window.API.post('/api/v1/control/force-jump', { action: 'confirm', nonce, code: entered, }); setDone(true); } catch (e) { setErr(e.message || 'confirm failed'); } finally { setBusy(false); } }; const reset = () => { setStep(1); setNonce(''); setCode(''); setEntered(''); setDone(false); setNote(''); setErr(''); }; return (
{/* progress */}
= 1} done={step > 1}>request
1 ? 'bg-pos-0' : 'bg-line-0'}`}>
= 2} done={done}>confirm
{step === 1 && !done && ( <>
{from} {to}
{err &&
{err}
} )} {step === 2 && !done && ( <>
nonce {nonce}
verification code
{code}

re-enter below

setEntered(e.target.value.replace(/\D/g,'').slice(0,6))} placeholder="000000" autoFocus className="w-full bg-bg-2 border border-line-1 mono text-[20px] tracking-[0.4em] text-center h-12 text-ink-0 focus:border-amb-0 outline-none"/>
{err &&
{err}
} )} {done && (
force-jump submitted
{from} → {to} · queued in outbox
)}
); } function StepDot({ active, done, children }) { return (
{done ? '✓' : (active ? '•' : '·')}
{children}
); } function ReloadCard() { const [state, setState] = React.useState('idle'); // idle, loading, ok, diff const reload = () => { setState('loading'); setTimeout(() => setState(Math.random() > 0.5 ? 'ok' : 'diff'), 700); }; return (

re-reads configs/bot.yaml. compatible changes apply hot; incompatible diffs are reported.

{state === 'ok' && (
reload ok · 0 incompatible
)} {state === 'diff' && (
2 incompatible changes
{`- accounts[0].bridge: USDT → USDC
- strategy.binance-main.ema_alpha: 0.05 → 0.01`}
            
requires bot restart to apply
)}
); } window.PageControl = PageControl;