/* RFC-0921: signing.key.generate command handler — generates Ed25519 keypairs and saves them to disk. Does not publish keys — that is a consumer concern (Nachweis, Integrity). Does not compute key IDs — that is domain-specific. RFC-0921: initial signing.key.generate command 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-1149: migrate ambient filesystem and process IO to the WorkspaceIO port across engine and shared */ import type { KernelCommandInput, KernelCommandResult, KernelRuntimeContext, } from "@warpgogol/werkstatt-engine/kernel"; import { generateKeyPair, saveKeyPair, keyExists, toHex } from "./index.ts"; import type { KeyEncoding } from "@warpgogol/werkstatt-shared/signing"; export interface SigningKeyGenerateResult { privateKeyPath: string; publicKeyPath: string; publicKeyHex: string; encoding: KeyEncoding; } function flagString(input: KernelCommandInput, name: string): string | undefined { const v = input.flags[name]; return typeof v === "string" ? v : undefined; } function flagBool(input: KernelCommandInput, name: string): boolean { const v = input.flags[name]; return v === true || v === "true"; } export async function runSigningKeyGenerate( input: KernelCommandInput, context: KernelRuntimeContext, ): Promise> { const outputDir = flagString(input, "output-dir"); const encoding = (flagString(input, "encoding") ?? "hex") as KeyEncoding; const force = flagBool(input, "force"); if (!outputDir) throw new Error("[signing.key.generate] --output-dir is required"); if (encoding !== "hex" && encoding !== "pem") { throw new Error(`[signing.key.generate] --encoding must be "hex" or "pem", got "${encoding}"`); } if ( (await keyExists(`${outputDir}/signing.key${encoding === "pem" ? ".pem" : ""}`, context.io)) && !force ) { throw new Error( `[signing.key.generate] KEY_FILE_EXISTS: key file already exists in '${outputDir}'. Use --force to overwrite.`, ); } const keyPair = await generateKeyPair(); const { privateKeyPath, publicKeyPath } = await saveKeyPair( keyPair, outputDir, encoding, context.io, ); return { data: { privateKeyPath, publicKeyPath, publicKeyHex: toHex(keyPair.publicKey), encoding, }, exitCode: 0, summary: `[signing.key.generate] generated Ed25519 keypair (${encoding}) → ${outputDir}`, }; }