diff --git a/src/config/config.ts b/src/config/config.ts index 21584b75e..4d8419c09 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -10,17 +10,17 @@ export type ClaudeOutputFormat = "text" | "json" | "stream-json"; export type SessionScope = "per-sender" | "global"; export type SessionConfig = { - scope?: SessionScope; - resetTriggers?: string[]; - idleMinutes?: number; - store?: string; - sessionArgNew?: string[]; - sessionArgResume?: string[]; - sessionArgBeforeBody?: boolean; - sendSystemOnce?: boolean; - sessionIntro?: string; - typingIntervalSeconds?: number; - }; + scope?: SessionScope; + resetTriggers?: string[]; + idleMinutes?: number; + store?: string; + sessionArgNew?: string[]; + sessionArgResume?: string[]; + sessionArgBeforeBody?: boolean; + sendSystemOnce?: boolean; + sessionIntro?: string; + typingIntervalSeconds?: number; +}; export type LoggingConfig = { level?: "silent" | "fatal" | "error" | "warn" | "info" | "debug" | "trace"; @@ -28,29 +28,29 @@ export type LoggingConfig = { }; export type WarelayConfig = { - logging?: LoggingConfig; - inbound?: { - allowFrom?: string[]; // E.164 numbers allowed to trigger auto-reply (without whatsapp:) - transcribeAudio?: { - // Optional CLI to turn inbound audio into text; templated args, must output transcript to stdout. - command: string[]; - timeoutSeconds?: number; - }; - reply?: { - mode: ReplyMode; - text?: string; // for mode=text, can contain {{Body}} - command?: string[]; // for mode=command, argv with templates - cwd?: string; // working directory for command execution - template?: string; // prepend template string when building command/prompt - timeoutSeconds?: number; // optional command timeout; defaults to 600s - bodyPrefix?: string; // optional string prepended to Body before templating - mediaUrl?: string; // optional media attachment (path or URL) - session?: SessionConfig; - claudeOutputFormat?: ClaudeOutputFormat; // when command starts with `claude`, force an output format - mediaMaxMb?: number; // optional cap for outbound media (default 5MB) - typingIntervalSeconds?: number; // how often to refresh typing indicator while command runs - }; -}; + logging?: LoggingConfig; + inbound?: { + allowFrom?: string[]; // E.164 numbers allowed to trigger auto-reply (without whatsapp:) + transcribeAudio?: { + // Optional CLI to turn inbound audio into text; templated args, must output transcript to stdout. + command: string[]; + timeoutSeconds?: number; + }; + reply?: { + mode: ReplyMode; + text?: string; // for mode=text, can contain {{Body}} + command?: string[]; // for mode=command, argv with templates + cwd?: string; // working directory for command execution + template?: string; // prepend template string when building command/prompt + timeoutSeconds?: number; // optional command timeout; defaults to 600s + bodyPrefix?: string; // optional string prepended to Body before templating + mediaUrl?: string; // optional media attachment (path or URL) + session?: SessionConfig; + claudeOutputFormat?: ClaudeOutputFormat; // when command starts with `claude`, force an output format + mediaMaxMb?: number; // optional cap for outbound media (default 5MB) + typingIntervalSeconds?: number; // how often to refresh typing indicator while command runs + }; + }; }; export const CONFIG_PATH = path.join(os.homedir(), ".warelay", "warelay.json"); diff --git a/src/index.core.test.ts b/src/index.core.test.ts index 8e9288c6c..d0e6bd21c 100644 --- a/src/index.core.test.ts +++ b/src/index.core.test.ts @@ -640,44 +640,44 @@ describe("config and templating", () => { expect(onReplyStart.mock.calls.length).toBeGreaterThanOrEqual(3); }); - it("uses session typing interval override", async () => { - const onReplyStart = vi.fn(); - const runSpy = vi.spyOn(index, "runCommandWithTimeout").mockImplementation( - () => - new Promise((resolve) => - setTimeout( - () => - resolve({ - stdout: "done\n", - stderr: "", - code: 0, - signal: null, - killed: false, - }), - 120, - ), - ), - ); - const cfg = { - inbound: { - reply: { - mode: "command" as const, - command: ["echo", "{{Body}}"], - session: { typingIntervalSeconds: 0.02 }, - }, - }, - }; + it("uses session typing interval override", async () => { + const onReplyStart = vi.fn(); + const runSpy = vi.spyOn(index, "runCommandWithTimeout").mockImplementation( + () => + new Promise((resolve) => + setTimeout( + () => + resolve({ + stdout: "done\n", + stderr: "", + code: 0, + signal: null, + killed: false, + }), + 120, + ), + ), + ); + const cfg = { + inbound: { + reply: { + mode: "command" as const, + command: ["echo", "{{Body}}"], + session: { typingIntervalSeconds: 0.02 }, + }, + }, + }; - const promise = index.getReplyFromConfig( - { Body: "hi", From: "+1", To: "+2" }, - { onReplyStart }, - cfg, - runSpy, - ); - await new Promise((r) => setTimeout(r, 200)); - await promise; - expect(onReplyStart.mock.calls.length).toBeGreaterThanOrEqual(3); - }); + const promise = index.getReplyFromConfig( + { Body: "hi", From: "+1", To: "+2" }, + { onReplyStart }, + cfg, + runSpy, + ); + await new Promise((r) => setTimeout(r, 200)); + await promise; + expect(onReplyStart.mock.calls.length).toBeGreaterThanOrEqual(3); + }); it("injects Claude output format + print flag when configured", async () => { const runSpy = vi.spyOn(index, "runCommandWithTimeout").mockResolvedValue({