From b4a995dbe5848a26f1a00111915fd3f098699efa Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 24 Nov 2025 16:02:39 +0100 Subject: [PATCH] Document config options and log auto-reply timing --- README.md | 33 +++++++++++++++++++++++++++++++++ src/index.ts | 9 +++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 48bedaf237..d1e3d14abf 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,39 @@ Put a JSON5 config at `~/.warelay/warelay.json`. Examples: } ``` +### Options reference (JSON5) + +- `inbound.allowFrom?: string[]` — optional allowlist of E.164 numbers (no `whatsapp:` prefix). If set, only these senders trigger auto-replies. +- `inbound.reply.mode: "text" | "command"` + - `text` — send `inbound.reply.text` after templating. + - `command` — run `inbound.reply.command` (argv array) after templating; trimmed stdout becomes the reply. +- `inbound.reply.text?: string` — used when `mode` is `text`; supports `{{Body}}`, `{{From}}`, `{{To}}`, `{{MessageSid}}`. +- `inbound.reply.command?: string[]` — argv for the command to run; templated per element. +- `inbound.reply.template?: string` — optional string prepended as the second argv element (handy for adding a prompt prefix). + +Example with an allowlist and Claude CLI one-shot (uses a sample number): + +```json5 +{ + inbound: { + allowFrom: ["+15551230000"], + reply: { + mode: "command", + command: [ + "claude", + "--print", + "--output-format", + "text", + "--dangerously-skip-permissions", + "--system-prompt", + "You are an auto-reply bot on WhatsApp. Respond concisely.", + "{{Body}}" + ] + } + } +} +``` + During dev you can run without building: `pnpm dev -- ` (e.g. `pnpm dev -- send --to +1...`). Auto-replies apply in webhook and polling modes. ## Notes diff --git a/src/index.ts b/src/index.ts index 3349369299..865bf93dcc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -43,6 +43,7 @@ type TwilioRequestOptions = { uri: string; params?: Record; form?: Record; + body?: unknown; }; type TwilioSender = { sid: string; sender_id: string }; @@ -390,8 +391,8 @@ async function getReplyFromConfig( const finalArgv = templatePrefix ? [argv[0], templatePrefix, ...argv.slice(1)] : argv; + const started = Date.now(); try { - if (globalVerbose) console.log(`RUN `); const { stdout } = await execFileAsync(finalArgv[0], finalArgv.slice(1), { maxBuffer: 1024 * 1024, }); @@ -399,9 +400,13 @@ async function getReplyFromConfig( logVerbose( `Command auto-reply stdout (trimmed): ${trimmed || ""}`, ); + logVerbose(`Command auto-reply finished in ${Date.now() - started}ms`); return trimmed || undefined; } catch (err) { - console.error("Command auto-reply failed", err); + console.error( + `Command auto-reply failed after ${Date.now() - started}ms`, + err, + ); return undefined; } }