/* RFC-0753: dns.record.delete command handler — deletes a single DNS record from Cloudflare by record ID or by name+type. Requires --record-id or --name + --type. Supports --dry-run. Do not delete all records in a zone — use individual calls. Do not delete records that are still declared in dns-records.yaml — remove from declaration first. RFC-0753: initial dns.record.delete command handler. RFC-1237: resolve dry-run via context.dryRun fallback — consumeCommonFlags strips --dry-run into context.dryRun before dispatch, so a flags-only read was permanently false under werkstatt run (enforced by KERNEL-FLAG-10). RFC-1249: wire werkstatt.commands.validate into packages.check + retire CMD-OUTPUT debt */ import type { KernelCommandInput, KernelCommandResult, KernelRuntimeContext, } from "@warpgogol/werkstatt-engine/kernel"; import { discoverSystems } from "../sternsystem/registry-io.ts"; import { listDnsRecords, deleteDnsRecord } from "../leitstand/adapters/cloudflare-api.ts"; import { flagString, flagBoolean, resolveDnsZoneId, resolveDnsEnv, resolveZoneDomainForSystem, } from "./dns-helpers.ts"; export interface DnsRecordDeleteResult { command: "dns.record.delete"; systemId: string; zone: string; dryRun: boolean; deleted: Array<{ id: string; type: string; name: string; }>; state: "deleted" | "dry-run" | "not-found"; } export async function runDnsRecordDelete( input: KernelCommandInput, context: KernelRuntimeContext, ): Promise> { const { workspaceRoot } = context; const systemId = flagString(input, "system"); if (!systemId) throw new Error("[dns.record.delete] --system is required"); const recordId = flagString(input, "record-id"); const name = flagString(input, "name"); const recordType = flagString(input, "type"); const dryRun = context.dryRun === true || flagBoolean(input, "dry-run") === true; if (!recordId && !(name && recordType)) { throw new Error( "[dns.record.delete] Either --record-id or both --name and --type are required.", ); } const { systems } = await discoverSystems(workspaceRoot); const zoneDomain = resolveZoneDomainForSystem(systems, systemId); const zoneId = resolveDnsZoneId(systems, zoneDomain); const env = await resolveDnsEnv(); const apiToken = env["CLOUDFLARE_API_TOKEN"]; if (!apiToken) { throw new Error( "[dns.record.delete] CLOUDFLARE_API_TOKEN is not set. " + "Set it in the environment or .env file.", ); } const deleted: DnsRecordDeleteResult["deleted"] = []; if (recordId) { if (dryRun) { deleted.push({ id: recordId, type: "(unknown)", name: "(unknown)" }); } else { await deleteDnsRecord(zoneId, apiToken, recordId); deleted.push({ id: recordId, type: "(unknown)", name: "(unknown)" }); } } else { const liveRecords = await listDnsRecords(zoneId, apiToken, name); const matching = liveRecords.filter((r) => r.name === name && r.type === recordType); if (matching.length === 0) { return { data: { command: "dns.record.delete", systemId, zone: zoneDomain, dryRun, deleted: [], state: "not-found", }, exitCode: 0, summary: `[dns.record.delete] ${systemId}: no records found for ${recordType}:${name}`, nextSteps: [ { action: `List existing records: pnpm exec werkstatt run dns.record.list --site ${systemId}`, kind: "optional", }, ], }; } for (const record of matching) { if (dryRun) { deleted.push({ id: record.id, type: record.type, name: record.name }); } else { await deleteDnsRecord(zoneId, apiToken, record.id); deleted.push({ id: record.id, type: record.type, name: record.name }); } } } return { data: { command: "dns.record.delete", systemId, zone: zoneDomain, dryRun, deleted, state: dryRun ? "dry-run" : "deleted", }, exitCode: 0, summary: `[dns.record.delete] ${systemId}: ${deleted.length} record(s) ${dryRun ? "would be deleted" : "deleted"} in zone ${zoneDomain}`, nextSteps: dryRun ? [ { action: `Delete for real: pnpm exec werkstatt run dns.record.delete --site ${systemId} --type ${recordType} --name ${name}`, kind: "optional", }, ] : undefined, }; }