feat: add config validation and send dry-run

This commit is contained in:
Peter Steinberger
2025-11-25 03:46:26 +01:00
parent a89d7319a9
commit 8bd406f6b1
5 changed files with 116 additions and 1 deletions

View File

@@ -3,6 +3,7 @@ import os from "node:os";
import path from "node:path";
import JSON5 from "json5";
import { z } from "zod";
export type ReplyMode = "text" | "command";
export type ClaudeOutputFormat = "text" | "json" | "stream-json";
@@ -36,6 +37,50 @@ export type WarelayConfig = {
export const CONFIG_PATH = path.join(os.homedir(), ".warelay", "warelay.json");
const ReplySchema = z
.object({
mode: z.union([z.literal("text"), z.literal("command")]),
text: z.string().optional(),
command: z.array(z.string()).optional(),
template: z.string().optional(),
timeoutSeconds: z.number().int().positive().optional(),
bodyPrefix: z.string().optional(),
session: z
.object({
scope: z.union([z.literal("per-sender"), z.literal("global")]).optional(),
resetTriggers: z.array(z.string()).optional(),
idleMinutes: z.number().int().positive().optional(),
store: z.string().optional(),
sessionArgNew: z.array(z.string()).optional(),
sessionArgResume: z.array(z.string()).optional(),
sessionArgBeforeBody: z.boolean().optional(),
})
.optional(),
claudeOutputFormat: z
.union([
z.literal("text"),
z.literal("json"),
z.literal("stream-json"),
z.undefined(),
])
.optional(),
})
.refine(
(val) => (val.mode === "text" ? Boolean(val.text) : Boolean(val.command)),
{
message: "reply.text is required for mode=text; reply.command is required for mode=command",
},
);
const WarelaySchema = z.object({
inbound: z
.object({
allowFrom: z.array(z.string()).optional(),
reply: ReplySchema.optional(),
})
.optional(),
});
export function loadConfig(): WarelayConfig {
// Read ~/.warelay/warelay.json (JSON5) if present.
try {
@@ -43,7 +88,13 @@ export function loadConfig(): WarelayConfig {
const raw = fs.readFileSync(CONFIG_PATH, "utf-8");
const parsed = JSON5.parse(raw);
if (typeof parsed !== "object" || parsed === null) return {};
return parsed as WarelayConfig;
const validated = WarelaySchema.safeParse(parsed);
if (!validated.success) {
console.error("Invalid warelay config:");
validated.error.issues.forEach((iss) => console.error(`- ${iss.path.join(".")}: ${iss.message}`));
return {};
}
return validated.data as WarelayConfig;
} catch (err) {
console.error(`Failed to read config at ${CONFIG_PATH}`, err);
return {};