Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 80d9d288c2 | |||
| dd55a80430 | |||
| f7cdb12101 | |||
| 3b8783ec0e | |||
| 4d2a8a80d4 | |||
| d51a3e9b48 | |||
| cadd29e147 |
@@ -1,5 +1,19 @@
|
||||
# Changelog
|
||||
|
||||
## 0.1.1 — 2025-11-25
|
||||
|
||||
### CLI polish
|
||||
- Added a proper executable shim so `npx warelay@0.1.x --help` runs the CLI directly.
|
||||
- Help/version banner now uses the README tagline with color, and the help footer includes colored examples with short explanations.
|
||||
- `send` and `status` gained a `--verbose` flag for consistent noisy output when debugging.
|
||||
- Lowercased branding in docs/UA; web provider UA is `warelay/cli/0.1.1`.
|
||||
|
||||
## 0.1.2 — 2025-11-25
|
||||
|
||||
### CI/build fix
|
||||
- Fixed commander help configuration (`subcommandTerm`) so TypeScript builds pass in CI.
|
||||
- Bumped version/UA to 0.1.2; no functional changes beyond the CI fix.
|
||||
|
||||
## 0.1.0 — 2025-11-25
|
||||
|
||||
### CLI & Providers
|
||||
|
||||
@@ -124,7 +124,7 @@ Templating tokens: `{{Body}}`, `{{BodyStripped}}`, `{{From}}`, `{{To}}`, `{{Mess
|
||||
|
||||
## FAQ & Safety (quick answers)
|
||||
- Twilio errors: **63016 “permission to send an SMS has not been enabled”** → ensure your number is WhatsApp-enabled; **63007 template not approved** → send a free-form session message within 24h or use an approved template; **63112 policy violation** → adjust content, shorten to <1600 chars, avoid links that trigger spam filters. Re-run `pnpm warelay status` to see the exact Twilio response body.
|
||||
- Does this store my messages? Warelay only writes `~/.warelay/warelay.json` (config), `~/.warelay/credentials/` (WhatsApp Web auth), and `~/.warelay/sessions.json` (session IDs + timestamps). It does **not** persist message bodies beyond the session store. Logs print to stdout/stderr; redirect or rotate if needed.
|
||||
- Does this store my messages? warelay only writes `~/.warelay/warelay.json` (config), `~/.warelay/credentials/` (WhatsApp Web auth), and `~/.warelay/sessions.json` (session IDs + timestamps). It does **not** persist message bodies beyond the session store. Logs print to stdout/stderr; redirect or rotate if needed.
|
||||
- Personal WhatsApp safety: Automation on personal accounts can be rate-limited or logged out by WhatsApp. Use `--provider web` sparingly, keep messages human-like, and re-run `login` if the session is dropped.
|
||||
- Limits to remember: WhatsApp text limit ~1600 chars; avoid rapid bursts—space sends by a few seconds; keep webhook replies under a couple seconds for good UX; command auto-replies time out after 600s by default.
|
||||
- Deploy / keep running: Use `tmux` or `screen` for ad-hoc (`tmux new -s warelay -- pnpm warelay relay --provider twilio`). For long-running hosts, wrap `pnpm warelay relay ...` or `pnpm warelay webhook --ingress tailscale ...` in a systemd service or macOS LaunchAgent; ensure environment variables are loaded in that context.
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
import("../dist/index.js").then((mod) => {
|
||||
if (mod?.program?.parseAsync) {
|
||||
mod.program.parseAsync(process.argv);
|
||||
}
|
||||
});
|
||||
@@ -12,7 +12,7 @@ This guide shows the exact way to wire **warelay** to the Claude CLI so inbound
|
||||
- Optional: set `ANTHROPIC_API_KEY` in your shell profile for non-interactive use.
|
||||
|
||||
## Create your warelay config
|
||||
Warelay reads `~/.warelay/warelay.json` (JSON5 accepted). Add a command-mode reply that points at the Claude CLI:
|
||||
warelay reads `~/.warelay/warelay.json` (JSON5 accepted). Add a command-mode reply that points at the Claude CLI:
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -38,13 +38,13 @@ Warelay reads `~/.warelay/warelay.json` (JSON5 accepted). Add a command-mode rep
|
||||
```
|
||||
|
||||
Notes on this configuration:
|
||||
- Warelay automatically injects a Claude identity prefix and the correct `--output-format`/`-p` flags when `command[0]` is `claude` and `claudeOutputFormat` is set.
|
||||
- warelay automatically injects a Claude identity prefix and the correct `--output-format`/`-p` flags when `command[0]` is `claude` and `claudeOutputFormat` is set.
|
||||
- Sessions are stored in `~/.warelay/sessions.json`; `scope: per-sender` keeps separate threads for each contact.
|
||||
- `bodyPrefix` is added before the inbound message body that reaches Claude. The string above mirrors the built-in 1500-character WhatsApp guardrail.
|
||||
|
||||
## How the flow works
|
||||
1. An inbound message (Twilio webhook, Twilio poller, or WhatsApp Web listener) arrives.
|
||||
2. Warelay enqueues the command in a process-wide FIFO queue so only one Claude run happens at a time (`src/process/command-queue.ts`).
|
||||
2. warelay enqueues the command in a process-wide FIFO queue so only one Claude run happens at a time (`src/process/command-queue.ts`).
|
||||
3. Typing indicators are sent (Twilio) or `composing` presence is sent (Web) while Claude runs.
|
||||
4. Claude stdout is parsed:
|
||||
- JSON mode is handled automatically if you set `claudeOutputFormat: "json"`; otherwise text is used.
|
||||
@@ -52,7 +52,7 @@ Notes on this configuration:
|
||||
5. The reply (text and optional media) is sent back via the same provider that received the message.
|
||||
|
||||
## Media and attachments
|
||||
- To send an image from Claude, include a line like `MEDIA:https://example.com/pic.jpg` in the output. Warelay will:
|
||||
- To send an image from Claude, include a line like `MEDIA:https://example.com/pic.jpg` in the output. warelay will:
|
||||
- Host local paths for Twilio using the media server/Tailscale Funnel.
|
||||
- Send buffers directly for the Web provider.
|
||||
- Inbound media is downloaded (≤5 MB) and exposed to your templates as `{{MediaPath}}`, `{{MediaUrl}}`, and `{{MediaType}}`. You can mention this in your prompt if you want Claude to reason about the attachment.
|
||||
|
||||
+4
-4
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "warelay",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.2",
|
||||
"description": "WhatsApp relay CLI (send, monitor, webhook, auto-reply) using Twilio",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
"bin": {
|
||||
"warelay": "dist/index.js",
|
||||
"warely": "dist/index.js",
|
||||
"wa": "dist/index.js"
|
||||
"warelay": "bin/warelay.js",
|
||||
"warely": "bin/warelay.js",
|
||||
"wa": "bin/warelay.js"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "tsx src/index.ts",
|
||||
|
||||
+67
-1
@@ -1,3 +1,4 @@
|
||||
import chalk from "chalk";
|
||||
import { Command } from "commander";
|
||||
import { sendCommand } from "../commands/send.js";
|
||||
import { statusCommand } from "../commands/status.js";
|
||||
@@ -17,11 +18,76 @@ import { spawnRelayTmux } from "./relay_tmux.js";
|
||||
|
||||
export function buildProgram() {
|
||||
const program = new Command();
|
||||
const PROGRAM_VERSION = "0.1.2";
|
||||
const TAGLINE =
|
||||
"Send, receive, and auto-reply on WhatsApp—Twilio-backed or QR-linked.";
|
||||
|
||||
program
|
||||
.name("warelay")
|
||||
.description("WhatsApp relay CLI (Twilio or WhatsApp Web session)")
|
||||
.version("1.0.0");
|
||||
.version(PROGRAM_VERSION);
|
||||
|
||||
const formatIntroLine = (version: string, rich = true) => {
|
||||
const base = `📡 warelay ${version} — ${TAGLINE}`;
|
||||
return rich && chalk.level > 0
|
||||
? `${chalk.bold.cyan("📡 warelay")} ${chalk.white(version)} ${chalk.gray("—")} ${chalk.green(TAGLINE)}`
|
||||
: base;
|
||||
};
|
||||
|
||||
program.configureHelp({
|
||||
optionTerm: (option) => chalk.yellow(option.flags),
|
||||
subcommandTerm: (cmd) => chalk.green(cmd.name()),
|
||||
});
|
||||
|
||||
program.configureOutput({
|
||||
writeOut: (str) => {
|
||||
const colored = str
|
||||
.replace(/^Usage:/gm, chalk.bold.cyan("Usage:"))
|
||||
.replace(/^Options:/gm, chalk.bold.cyan("Options:"))
|
||||
.replace(/^Commands:/gm, chalk.bold.cyan("Commands:"));
|
||||
process.stdout.write(colored);
|
||||
},
|
||||
writeErr: (str) => process.stderr.write(str),
|
||||
outputError: (str, write) => write(chalk.red(str)),
|
||||
});
|
||||
|
||||
if (process.argv.includes("-V") || process.argv.includes("--version")) {
|
||||
console.log(formatIntroLine(PROGRAM_VERSION));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
program.addHelpText("beforeAll", `\n${formatIntroLine(PROGRAM_VERSION)}\n`);
|
||||
const examples = [
|
||||
[
|
||||
"warelay login --verbose",
|
||||
"Link personal WhatsApp Web and show QR + connection logs.",
|
||||
],
|
||||
[
|
||||
'warelay send --to +15551234567 --message "Hi" --provider web --json',
|
||||
"Send via your web session and print JSON result.",
|
||||
],
|
||||
[
|
||||
"warelay relay --provider auto --interval 5 --lookback 15 --verbose",
|
||||
"Auto-reply loop: prefer Web when logged in, otherwise Twilio polling.",
|
||||
],
|
||||
[
|
||||
"warelay webhook --ingress tailscale --port 42873 --path /webhook/whatsapp --verbose",
|
||||
"Start webhook + Tailscale Funnel and update Twilio callbacks.",
|
||||
],
|
||||
[
|
||||
"warelay status --limit 10 --lookback 60 --json",
|
||||
"Show last 10 messages from the past hour as JSON.",
|
||||
],
|
||||
] as const;
|
||||
|
||||
const fmtExamples = examples
|
||||
.map(([cmd, desc]) => ` ${chalk.green(cmd)}\n ${chalk.gray(desc)}`)
|
||||
.join("\n");
|
||||
|
||||
program.addHelpText(
|
||||
"afterAll",
|
||||
`\n${chalk.bold.cyan("Examples:")}\n${fmtExamples}\n`,
|
||||
);
|
||||
|
||||
program
|
||||
.command("login")
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ export async function createWaSocket(printQr: boolean, verbose: boolean) {
|
||||
version,
|
||||
logger,
|
||||
printQRInTerminal: false,
|
||||
browser: ["Warelay", "CLI", "1.0.0"],
|
||||
browser: ["warelay", "cli", "0.1.2"],
|
||||
syncFullHistory: false,
|
||||
markOnlineOnConnect: false,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user