diff --git a/README.md b/README.md index 36169d0f2..0c35918bb 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ You can also talk to WhatsApp directly with a personal WhatsApp Web session (QR ## Common Commands - Send: `pnpm warelay send --to +12345550000 --message "Hello" --wait 20 --poll 2` +- Send (JSON output): `pnpm warelay send --to +12345550000 --message "Hello" --json` - Send via personal WhatsApp Web: first `pnpm warelay web:login` (alias: `pnpm warelay login`, scan QR), then `pnpm warelay send --provider web --to +12345550000 --message "Hi"` - Auto-replies (auto provider): `pnpm warelay relay` (uses web if logged in, otherwise twilio poll) - Auto-replies (force web): `pnpm warelay relay --provider web` diff --git a/docs/refactor/plan.md b/docs/refactor/plan.md index a25d317e8..c8f45069a 100644 --- a/docs/refactor/plan.md +++ b/docs/refactor/plan.md @@ -16,6 +16,7 @@ This is a living note capturing the cleanups underway to keep `warelay` small an - README updated to document direct WhatsApp Web support and Claude output handling. - Added zod validation for `~/.warelay/warelay.json` and a `--dry-run` flag for `send`. - Introduced a tiny logger (`src/logger.ts`) and backoff retry in Twilio polling. +- Added `--json` for `send`, logger adoption for web/twilio sends, and retries for webhook bring-up. ## In this pass - Wire more modules to the logger; keep colors/verbosity consistent. diff --git a/src/cli/program.ts b/src/cli/program.ts index 1cd00de21..48a847049 100644 --- a/src/cli/program.ts +++ b/src/cli/program.ts @@ -122,10 +122,7 @@ Examples: const provider = await pickProvider(providerPref as Provider | "auto"); if (provider === "web") { - defaultRuntime.log( - info("Provider: web (personal WhatsApp Web session)"), - ); - logWebSelfId(); + logWebSelfId(defaultRuntime, true); try { await monitorWebProvider(Boolean(opts.verbose)); return; diff --git a/src/commands/up.ts b/src/commands/up.ts index c2bff8288..cdff293a4 100644 --- a/src/commands/up.ts +++ b/src/commands/up.ts @@ -1,6 +1,7 @@ import type { CliDeps } from "../cli/deps.js"; import type { RuntimeEnv } from "../runtime.js"; import { waitForever as defaultWaitForever } from "../cli/wait.js"; +import { retryAsync } from "../infra/retry.js"; export async function upCommand( opts: { port: string; path: string; verbose?: boolean; yes?: boolean; dryRun?: boolean }, @@ -23,17 +24,22 @@ export async function upCommand( return { server: undefined, publicUrl, senderSid: undefined, waiter }; } await deps.ensureBinary("tailscale", undefined, runtime); - await deps.ensureFunnel(port, undefined, runtime); + await retryAsync(() => deps.ensureFunnel(port, undefined, runtime), 3, 500); const host = await deps.getTailnetHostname(); const publicUrl = `https://${host}${opts.path}`; runtime.log(`🌐 Public webhook URL (via Funnel): ${publicUrl}`); - const server = await deps.startWebhook( - port, - opts.path, - undefined, - Boolean(opts.verbose), - runtime, + const server = await retryAsync( + () => + deps.startWebhook( + port, + opts.path, + undefined, + Boolean(opts.verbose), + runtime, + ), + 3, + 300, ); if (!deps.createClient) { diff --git a/src/commands/webhook.ts b/src/commands/webhook.ts index 5307a4b69..42425122e 100644 --- a/src/commands/webhook.ts +++ b/src/commands/webhook.ts @@ -1,5 +1,6 @@ import type { CliDeps } from "../cli/deps.js"; import type { RuntimeEnv } from "../runtime.js"; +import { retryAsync } from "../infra/retry.js"; export async function webhookCommand( opts: { @@ -21,12 +22,17 @@ export async function webhookCommand( runtime.log(`[dry-run] would start webhook on port ${port} path ${opts.path}`); return undefined; } - const server = await deps.startWebhook( - port, - opts.path, - opts.reply, - Boolean(opts.verbose), - runtime, + const server = await retryAsync( + () => + deps.startWebhook( + port, + opts.path, + opts.reply, + Boolean(opts.verbose), + runtime, + ), + 3, + 300, ); return server; } diff --git a/src/provider-web.ts b/src/provider-web.ts index d339dd82e..469eadd32 100644 --- a/src/provider-web.ts +++ b/src/provider-web.ts @@ -364,14 +364,20 @@ function readWebSelfId() { } } -export function logWebSelfId(runtime: RuntimeEnv = defaultRuntime) { +export function logWebSelfId( + runtime: RuntimeEnv = defaultRuntime, + includeProviderPrefix = false, +) { // Human-friendly log of the currently linked personal web session. const { e164, jid } = readWebSelfId(); const details = e164 || jid ? `${e164 ?? "unknown"}${jid ? ` (jid ${jid})` : ""}` : "unknown"; - runtime.log(info(`Listening on web session: ${details}`)); + const prefix = includeProviderPrefix + ? "Provider: web (personal WhatsApp Web session) — " + : ""; + runtime.log(info(`${prefix}Listening on web session: ${details}`)); } export async function pickProvider(pref: Provider | "auto"): Promise {