Skip to content

Commit 803b800

Browse files
JohanYPclaude
andcommitted
feat(channels): support WhatsApp-only mode (Telegram becomes optional)
Until now Telegram was a hard requirement. The bot would refuse to start without TELEGRAM_BOT_TOKEN and TELEGRAM_ALLOWED_USER_ID, even when the user only wanted to use WhatsApp. This commit lifts that constraint so each instance can pick: Telegram only, Telegram + WhatsApp, or WhatsApp only. Config (src/config.ts) - Adds telegram.enabled = (token present AND user_id valid). - Telegram env vars are now optional. Whatever is missing simply turns the channel off. - Cross-channel invariant: at least one of telegram.enabled / whatsapp.enabled must be true; otherwise loadConfig() throws with a clear hint to run setup.sh. Validation (src/runtime/bootstrap.ts) - validateRuntimeEnvValues now accepts WhatsApp-only configs. - Catches half-configured Telegram (token without user_id) so users don't silently fall through to WhatsApp-only because of a typo. - New tests cover: WhatsApp-only valid, both channels valid, no channel invalid, partial Telegram invalid. Bootstrap (src/app/start-bot-app.ts) - Telegram bot creation, scheduled-task runtime init, webhook check and bot.start() are all guarded by config.telegram.enabled. - WhatsApp-only mode replaces grammy's blocking long-poll with a Promise resolved by the shutdown handler — Baileys runs in the background and the process stays alive on signals. Setup (setup.sh) - New STEP 2/12 — Messaging Channels — asks Telegram only / both / WhatsApp only at the start of the wizard. - STEP 3 (Telegram token) and STEP 4 (User ID) are skipped with a visible "(skipped)" line when the user picked WhatsApp only. - STEP 8 (WhatsApp number) is skipped when WhatsApp is off. - Generated .env still writes empty Telegram lines so the user sees what the alternative is and can flip it later. - Summary block reflects each channel's enabled/disabled state. CLI (bin/opencode-assistant) - --doctor stops requiring TELEGRAM_BOT_TOKEN. It now reports each channel's status independently, and only fails if neither is configured. - WhatsApp QR hint switched from `--logs bot` to the `--qr` shortcut. Scheduled tasks (src/scheduled-task/runtime.ts) - No code change: the runtime already gates registerTask() on initialized; in WhatsApp-only mode start-bot-app.ts simply skips initialize() and logs that /task is unavailable in this mode. Docs - docs/WHATSAPP_SETUP.md: documents the three modes, the WhatsApp-only caveats (no /task, no permission/question UI), and the multi-channel .env layout. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent fc2d224 commit 803b800

7 files changed

Lines changed: 334 additions & 113 deletions

File tree

‎bin/opencode-assistant‎

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -587,30 +587,37 @@ cmd_doctor() {
587587
check "Docker installed" command -v docker
588588
check "Docker daemon responding" docker info
589589

590-
# .env
590+
# .env — at least one channel must be configured (Telegram or WhatsApp).
591+
# Each channel is checked independently; doctor reports which are active.
591592
if [[ -f "$REPO_DIR/.env" ]]; then
592-
if grep -qE '^TELEGRAM_BOT_TOKEN=.+' "$REPO_DIR/.env"; then
593-
ok ".env present with TELEGRAM_BOT_TOKEN"
594-
else
595-
err ".env exists but TELEGRAM_BOT_TOKEN is empty — run ./setup.sh"
596-
fails=$((fails + 1))
593+
local has_telegram=false has_whatsapp=false
594+
595+
if grep -qE '^TELEGRAM_BOT_TOKEN=.+' "$REPO_DIR/.env" \
596+
&& grep -qE '^TELEGRAM_ALLOWED_USER_ID=[1-9][0-9]*' "$REPO_DIR/.env"; then
597+
ok "Telegram channel configured"
598+
has_telegram=true
597599
fi
598600

599-
# WhatsApp (only validated when the user opted in)
600601
if grep -qE '^WHATSAPP_ENABLED=true' "$REPO_DIR/.env"; then
601602
if grep -qE '^WHATSAPP_ALLOWED_NUMBER=[0-9]{8,}' "$REPO_DIR/.env"; then
602-
ok "WhatsApp enabled with allowed number"
603+
ok "WhatsApp channel configured"
604+
has_whatsapp=true
603605
# If the auth dir is empty AND the bot is up, the user hasn't paired yet.
604606
if [[ "$(container_state bot)" == "running" ]] \
605607
&& dc exec -T bot test -d /app/data/whatsapp-auth >/dev/null 2>&1 \
606608
&& [[ -z "$(dc exec -T bot ls /app/data/whatsapp-auth 2>/dev/null | tr -d '\r')" ]]; then
607-
warn "WhatsApp auth dir is empty — scan the QR with: opencode-assistant --logs bot"
609+
warn "WhatsApp auth dir is empty — scan the QR with: opencode-assistant --qr"
608610
fi
609611
else
610612
err "WHATSAPP_ENABLED=true but WHATSAPP_ALLOWED_NUMBER missing or invalid"
611613
fails=$((fails + 1))
612614
fi
613615
fi
616+
617+
if ! $has_telegram && ! $has_whatsapp; then
618+
err "No messaging channel configured — run ./setup.sh (Telegram and/or WhatsApp required)"
619+
fails=$((fails + 1))
620+
fi
614621
else
615622
err ".env not found — run ./setup.sh"
616623
fails=$((fails + 1))

‎docs/WHATSAPP_SETUP.md‎

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
1-
# WhatsApp setup (optional second channel)
1+
# WhatsApp setup
22

3-
The bot can connect to WhatsApp as a second channel alongside Telegram, using a **separate dedicated phone number**. Opt-in, disabled by default.
3+
Opencode-Assistant can run with WhatsApp as a **second channel alongside Telegram** or as the **only channel** (no Telegram). Both modes use [Baileys](https://github.com/WhiskeySockets/Baileys), an unofficial WhatsApp Web client, and require a **dedicated phone number** — see the warnings below.
4+
5+
## Available modes
6+
7+
| Mode | When to choose it |
8+
|---|---|
9+
| **Telegram only** (default) | Best UX: inline pickers, pinned status, `/skills`, `/projects`, `/task`, etc. all work |
10+
| **Telegram + WhatsApp** | Talk to the bot from either app; reminders fire on both. Telegram remains where permission/question dialogs appear |
11+
| **WhatsApp only** | No Telegram account needed. More limited UX (see below) |
12+
13+
The wizard's `STEP 2/12 — Messaging Channels` asks which mode you want before collecting the relevant credentials.
414

515
## What works in V1
616

@@ -13,14 +23,22 @@ The bot can connect to WhatsApp as a second channel alongside Telegram, using a
1323
- ✅ Numbered-menu reply for `/sessions` (reply with `1`, `2`, ...)
1424
- ✅ Reminders and weekly memory backup notifications fire on **both** channels (Telegram + WhatsApp), driven by a multi-target registry in `cron/reminder.ts`
1525

16-
## Known V1 limitations
26+
## Known V1 limitations (apply to all modes)
1727

18-
- ⚠️ **Permission and question dialogs still live in Telegram.** When a prompt sent from WhatsApp triggers a permission request (bash, edit, webfetch...) or a question, the dialog appears in Telegram. Approve there and the WhatsApp prompt completes. If you don't have a Telegram device handy, the prompt will block until it times out. Mirroring these dialogs to WhatsApp as numbered menus is on the V1.x roadmap (requires SSE fanout + dual state managers).
1928
- ⚠️ **No streaming responses** — WhatsApp users see the final reply only, not intermediate tool-call updates. The bot uses `session.prompt` (sync) instead of `promptAsync` + SSE.
2029
- ⚠️ **Audio output is plain MP3, not push-to-talk** (no waveform UI). PTT requires OPUS encoding which would need ffmpeg in the container; deferred to V1.x.
21-
- ⚠️ **No model/agent/variant pickers, no `/skills`, no `/projects`, no `/task`** from WhatsApp. Use Telegram for those.
30+
- ⚠️ **No model/agent/variant pickers, no `/skills`, no `/projects`, no `/task`** from WhatsApp. Use Telegram for those when running in mixed mode.
2231
- ⚠️ **Concurrent prompts on the same session are rejected** with a "previous task is still running" hint.
2332

33+
## WhatsApp-only mode — extra limitations
34+
35+
When you choose "WhatsApp only" in the wizard, **no Telegram bot is started**. That means:
36+
37+
- ❌ **Scheduled tasks (`/task`) are unavailable.** They require Telegram-rendered output (inline keyboards for continue/cancel buttons). Reminders that don't run an OpenCode session still work via the cron registry.
38+
- ❌ **Permission and question dialogs from OpenCode have no UI surface.** A prompt that triggers `bash`/`edit`/`webfetch` permission will hang. Either skip prompts that need permissions, or run in mixed mode and approve from Telegram.
39+
40+
In **mixed mode** (Telegram + WhatsApp), permission/question dialogs still appear in Telegram even when the prompt was sent from WhatsApp. Approve there and the WhatsApp prompt completes. Mirroring those dialogs to WhatsApp as numbered menus is on the V1.x roadmap.
41+
2442
## Requirements
2543

2644
- A **dedicated WhatsApp account** (a phone number that will be the bot). Don't link your main personal account — Meta may ban numbers that talk to unofficial clients like Baileys.
@@ -31,13 +49,20 @@ The bot can connect to WhatsApp as a second channel alongside Telegram, using a
3149
In `.env`:
3250

3351
```bash
52+
# Telegram (leave empty for WhatsApp-only mode)
53+
TELEGRAM_BOT_TOKEN=
54+
TELEGRAM_ALLOWED_USER_ID=
55+
56+
# WhatsApp
3457
WHATSAPP_ENABLED=true
3558
WHATSAPP_ALLOWED_NUMBER=34666999999 # country code + number, no +
3659
# WHATSAPP_AUTH_DIR=./data/whatsapp-auth # default; rarely overridden
3760
```
3861

3962
`WHATSAPP_ALLOWED_NUMBER` accepts either bare digits (`34666999999`) or full Baileys JID (`34666999999@s.whatsapp.net`). The bot normalizes both.
4063

64+
**At least one channel must be configured** — empty Telegram fields + `WHATSAPP_ENABLED=false` is rejected at startup.
65+
4166
## First start
4267

4368
```bash

0 commit comments

Comments
 (0)