Add House Party Protocol for fleet-wide queued destruction

This commit is contained in:
2026-09-18 00:39:19 -04:00
parent 586133c711
commit 274aedb66e
7 changed files with 212 additions and 3 deletions
@@ -0,0 +1,18 @@
import { json } from '@sveltejs/kit';
import { housePartyTargets, queueHouseParty } from '$lib/server/fleet/house-party.js';
import { kick } from '$lib/server/pipeline/worker.js';
export function GET() {
return json({ servers: housePartyTargets() }, { headers: { 'Cache-Control': 'no-store' } });
}
export async function POST({ request }: { request: Request }) {
const body = await request.json().catch(() => null);
if (!Array.isArray(body?.servers) || !body.servers.every((name: unknown) => typeof name === 'string')) {
return json({ error: 'A reviewed server list is required.' }, { status: 400 });
}
const result = queueHouseParty(body.servers);
if (!result.ok) return json(result, { status: 409 });
void kick().catch(err => console.error('[house-party] worker kick failed:', err));
return json(result, { status: 202 });
}
+11
View File
@@ -7,6 +7,7 @@
import DeployServerDialog from '$ui/components/DeployServerDialog.svelte';
import BlueprintBuilder from '$ui/components/BlueprintBuilder.svelte';
import DeployCollectionDialog from '$ui/components/DeployCollectionDialog.svelte';
import HousePartyDialog from '$ui/components/HousePartyDialog.svelte';
import type { BlueprintSummary, CollectionSummary } from '$lib/deployment-plan.js';
interface Deployment {
@@ -23,6 +24,8 @@
let builderOpen = $state(false);
let editingBlueprint = $state<BlueprintSummary | null>(null);
let collectionOpen = $state(false);
let housePartyOpen = $state(false);
let housePartyNotice = $state('');
let collections = $state<CollectionSummary[]>([]);
let blueprints = $state<BlueprintSummary[]>([]);
let blueprintsLoading = $state(true);
@@ -92,6 +95,12 @@
<DeployServerDialog bind:open onblueprint={loadBlueprints} />
<BlueprintBuilder bind:open={builderOpen} blueprint={editingBlueprint} onsaved={blueprintSaved} />
<DeployCollectionDialog bind:open={collectionOpen} {blueprintId} />
<div class="fleet-shutdown">
<div><strong>Call it a night.</strong><p>Queue the whole fleet for removal once each server is empty.</p></div>
<Button variant="danger" onclick={() => housePartyOpen = true}>House Party Protocol</Button>
</div>
<HousePartyDialog bind:open={housePartyOpen} onqueued={count => { housePartyNotice = `Destruction queued for ${count} server${count === 1 ? '' : 's'}. Follow progress in In flight below.`; void load(); }} />
{#if housePartyNotice}<p role="status">{housePartyNotice}</p>{/if}
<section>
<h2>Your blueprints <span>{blueprints.length}</span></h2>
{#if blueprintError}<p role="alert" class="error">{blueprintError} <button onclick={loadBlueprints}>Retry</button></p>{/if}
@@ -171,6 +180,8 @@
{/snippet}
<style>
.fleet-shutdown { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; padding: 18px 20px; border: 1px solid var(--border-subtle); border-radius: 12px; }
.fleet-shutdown p { margin: 5px 0 0; font-size: 13px; color: var(--text-secondary); }
.page { display: flex; flex-direction: column; gap: 28px; }
.row-head, .filters, .meta { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.row-head { justify-content: space-between; }