/* RFC-0565: dht.status command handler. Reports local DHT node status including config, cache entries, and peer connectivity. Local-only query — no network I/O except for checking if the DHT node is reachable. Do not start a DHT node — status is read from config and cache files only. Status is read-only — it reports config, cache, and peer state without mutation. RFC-0565: initial implementation — dht.status handler. RFC-1097: step 6 — compass.migrate codemod run Mechanical v1 to v2 header migration across the workspace: 942 files rewritten — CHANGE_SUMMARY windows collapsed into history, forbidden v1 blocks stripped, KEY_DECISIONS seeded from @ai-invariant comments (5 files) or TODO placeholders (103 files), blocks reordered to canonical order. RFC-1097: sweep — werkstatt-engine clean Sweep batch 4: 73 Compass headers on headerless engine files (certification, component-runtime, isolation, evolution, testing), real KEY_DECISIONS on 75 files (kernel, cache, dht, swim, gitmesh, runtime), ~80 purpose expansions (CONTRACT-02/PURPOSE-02), non-goals on 13 CONTRACT-03 files, CS-07 history literal fix repo-wide (253 files). Policy: .template.ts/.template.astro excludedPaths. werkstatt-engine now 0 diagnostics. RFC-1254: drop unused io-migration leftovers */ import { join } from "node:path"; import type { KernelCommandInput, KernelCommandResult, KernelRuntimeContext, } from "@warpgogol/werkstatt-shared/kernel"; import { loadDhtConfig } from "./config.ts"; import { loadCache } from "./cache.ts"; const IDENTITY_FILENAME = "werkstatt.identity.json"; const SWIM_FILENAME = "werkstatt.swim.json"; interface DhtStatusResult { initialized: boolean; configPath: string | null; bindAddr: string | null; bootstrapNodes: string[]; replicationFactor: number | null; cacheEntries: number; cachePath: string; identityBootstrapped: boolean; swimConfigured: boolean; diagnostics?: string[]; } export async function runDhtStatus( _input: KernelCommandInput, context: KernelRuntimeContext, ): Promise> { const { workspaceRoot } = context; // Check DHT config let config = null; let configPath: string | null = null; try { config = await loadDhtConfig(workspaceRoot); configPath = join(workspaceRoot, "werkstatt.dht.json"); } catch { // Not initialized } // Check identity let identityBootstrapped = false; try { await context.io.readFile(join(workspaceRoot, IDENTITY_FILENAME)); identityBootstrapped = true; } catch { // Not bootstrapped } // Check SWIM let swimConfigured = false; try { await context.io.readFile(join(workspaceRoot, SWIM_FILENAME)); swimConfigured = true; } catch { // Not configured } // Load cache const cache = await loadCache(workspaceRoot); const cachePath = join(workspaceRoot, "werkstatt.dht.cache.json"); const cacheEntries = Object.keys(cache.entries).length; if (!config) { return { data: { initialized: false, configPath: null, bindAddr: null, bootstrapNodes: [], replicationFactor: null, cacheEntries, cachePath, identityBootstrapped, swimConfigured, diagnostics: [ `dht.status: DHT not initialized — run dht.node.init first`, ...(!identityBootstrapped ? [`dht.status: identity not bootstrapped — run identity.bootstrap first (RFC-0558)`] : []), ], }, exitCode: 0, summary: `[dht.status] not initialized`, }; } return { data: { initialized: true, configPath, bindAddr: config.bindAddr, bootstrapNodes: config.bootstrapNodes, replicationFactor: config.replicationFactor, cacheEntries, cachePath, identityBootstrapped, swimConfigured, }, exitCode: 0, summary: `[dht.status] initialized, bind=${config.bindAddr}, bootstrap=${config.bootstrapNodes.length} nodes, cache=${cacheEntries} entries`, }; }