chore: purge warelay references
This commit is contained in:
12
CHANGELOG.md
12
CHANGELOG.md
@@ -23,7 +23,7 @@
|
||||
## 1.4.1 — 2025-12-04
|
||||
|
||||
### Changes
|
||||
- Added `warelay agent` CLI command to talk directly to the configured agent using existing session handling (no WhatsApp send), with JSON output and delivery option.
|
||||
- Added `clawdis agent` CLI command to talk directly to the configured agent using existing session handling (no WhatsApp send), with JSON output and delivery option.
|
||||
- `/new` reset trigger now works even when inbound messages have timestamp prefixes (e.g., `[Dec 4 17:35]`).
|
||||
- WhatsApp mention parsing accepts nullable arrays and flattens safely to avoid missed mentions.
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
### Highlights
|
||||
- **Thinking directives & state:** `/t|/think|/thinking <level>` (aliases off|minimal|low|medium|high|max/highest). Inline applies to that message; directive-only message pins the level for the session; `/think:off` clears. Resolution: inline > session override > `inbound.reply.thinkingDefault` > off. Pi/Tau get `--thinking <level>` (except off); other agents append cue words (`think` → `think hard` → `think harder` → `ultrathink`). Heartbeat probe uses `HEARTBEAT /think:high`.
|
||||
- **Group chats (web provider):** Warelay now fully supports WhatsApp groups: mention-gated triggers (including image-only @ mentions), recent group history injection, per-group sessions, sender attribution, and a first-turn primer with group subject/member roster; heartbeats are skipped for groups.
|
||||
- **Group chats (web provider):** Clawdis now fully supports WhatsApp groups: mention-gated triggers (including image-only @ mentions), recent group history injection, per-group sessions, sender attribution, and a first-turn primer with group subject/member roster; heartbeats are skipped for groups.
|
||||
- **Group session primer:** The first turn of a group session now tells the agent it is in a WhatsApp group and lists known members/subject so it can address the right speaker.
|
||||
- **Media failures are surfaced:** When a web auto-reply media fetch/send fails (e.g., HTTP 404), we now append a warning to the fallback text so you know the attachment was skipped.
|
||||
- **Verbose directives + session hints:** `/v|/verbose on|full|off` mirrors thinking: inline > session > config default. Directive-only replies with an acknowledgement; invalid levels return a hint. When enabled, tool results from JSON-emitting agents (Pi/Tau, etc.) are forwarded as metadata-only `[🛠️ <tool-name> <arg>]` messages (now streamed as they happen), and new sessions surface a `🧭 New session: <id>` hint.
|
||||
@@ -53,7 +53,7 @@
|
||||
- Verbose tool messages now include emoji + args + a short result preview for bash/read/edit/write/attach (derived from RPC tool start/end events).
|
||||
|
||||
### Security / Hardening
|
||||
- IPC socket hardened (0700 dir / 0600 socket, no symlinks/foreign owners); `warelay logout` also prunes session store.
|
||||
- IPC socket hardened (0700 dir / 0600 socket, no symlinks/foreign owners); `clawdis logout` also prunes session store.
|
||||
- Media server blocks symlinks and enforces path containment; logging rotates daily and prunes >24h.
|
||||
|
||||
### Bug Fixes
|
||||
@@ -81,11 +81,11 @@
|
||||
- Heartbeat alerts now honor `responsePrefix`.
|
||||
- Command failures return user-friendly messages.
|
||||
- Test session isolation to avoid touching real `sessions.json`.
|
||||
- IPC reuse for `warelay send/heartbeat` prevents Signal/WhatsApp session corruption.
|
||||
- IPC reuse for `clawdis send/heartbeat` prevents Signal/WhatsApp session corruption.
|
||||
- Web send respects media kind (image/audio/video/document) with correct limits.
|
||||
|
||||
### Changes
|
||||
- IPC relay socket at `~/.warelay/relay.sock` with automatic CLI fallback.
|
||||
- IPC relay socket at `~/.clawdis/relay.sock` with automatic CLI fallback.
|
||||
- Batched inbound messages with timestamps; typing indicator after IPC sends.
|
||||
- Watchdog restarts WhatsApp after long inactivity; heartbeat logging includes minutes since last message.
|
||||
- Early `allowFrom` filtering before decryption.
|
||||
@@ -94,7 +94,7 @@
|
||||
## 1.2.2 — 2025-11-28
|
||||
|
||||
### Changes
|
||||
- Manual heartbeat sends: `warelay heartbeat --message/--body` (web provider only); `--dry-run` previews payloads.
|
||||
- Manual heartbeat sends: `clawdis heartbeat --message/--body` (web provider only); `--dry-run` previews payloads.
|
||||
|
||||
## 1.2.1 — 2025-11-28
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@ final class RelayProcessManager: ObservableObject {
|
||||
}
|
||||
|
||||
private func resolveCommand() -> [String] {
|
||||
// Keep it simple: rely on system-installed clawdis/warelay.
|
||||
// Keep it simple: rely on a system-installed clawdis binary.
|
||||
// Default to `clawdis relay`; users can provide an override via env if needed.
|
||||
if let override = ProcessInfo.processInfo.environment["CLAWDIS_RELAY_CMD"],
|
||||
!override.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||||
@@ -211,9 +211,9 @@ final class RelayProcessManager: ObservableObject {
|
||||
return [pnpm, "clawdis", "relay"]
|
||||
}
|
||||
if let node = self.findExecutable(named: "node") {
|
||||
let warelay = self.defaultProjectRoot().appendingPathComponent("bin/warelay.js").path
|
||||
if FileManager.default.isReadableFile(atPath: warelay) {
|
||||
return [node, warelay, "relay"]
|
||||
let clawdis = self.defaultProjectRoot().appendingPathComponent("bin/clawdis.js").path
|
||||
if FileManager.default.isReadableFile(atPath: clawdis) {
|
||||
return [node, clawdis, "relay"]
|
||||
}
|
||||
}
|
||||
return ["clawdis", "relay"]
|
||||
|
||||
@@ -155,10 +155,6 @@ enum SessionLoader {
|
||||
private static let legacyStorePaths: [String] = [
|
||||
standardize(FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent(".clawdis/sessions.json")
|
||||
.path),
|
||||
standardize(FileManager.default.homeDirectoryForCurrentUser
|
||||
.appendingPathComponent(".warelay/sessions/sessions.json").path),
|
||||
standardize(FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent(".warelay/sessions.json")
|
||||
.path),
|
||||
]
|
||||
|
||||
static func configHints() -> SessionConfigHints {
|
||||
|
||||
@@ -5,7 +5,7 @@ Use `pnpm` (Node 22+) from the repo root. Keep the working tree clean before tag
|
||||
1) **Version & metadata**
|
||||
- [ ] Bump `package.json` version (e.g., `1.1.0`).
|
||||
- [ ] Update CLI/version strings: `src/cli/program.ts` and the Baileys user agent in `src/provider-web.ts`.
|
||||
- [ ] Confirm package metadata (name, description, repository, keywords, license) and `bin` map points to `dist/index.js` for `warelay`/`warely`/`wa`.
|
||||
- [ ] Confirm package metadata (name, description, repository, keywords, license) and `bin` map points to `dist/index.js` for `clawdis`.
|
||||
- [ ] If dependencies changed, run `pnpm install` so `pnpm-lock.yaml` is current.
|
||||
|
||||
2) **Build & artifacts**
|
||||
@@ -26,10 +26,10 @@ Use `pnpm` (Node 22+) from the repo root. Keep the working tree clean before tag
|
||||
- [ ] Confirm git status is clean; commit and push as needed.
|
||||
- [ ] `npm login` (verify 2FA) if needed.
|
||||
- [ ] `npm publish --access public` (use `--tag beta` for pre-releases).
|
||||
- [ ] Verify the registry: `npm view warelay version` and `npx -y warelay@X.Y.Z --version` (or `--help`).
|
||||
- [ ] Verify the registry: `npm view clawdis version` and `npx -y clawdis@X.Y.Z --version` (or `--help`).
|
||||
|
||||
6) **Post-publish**
|
||||
- [ ] Tag and push: `git tag vX.Y.Z && git push origin vX.Y.Z` (or `git push --tags`).
|
||||
- [ ] Create/refresh the GitHub release for `vX.Y.Z` with **title `warelay X.Y.Z`** (not just the tag); body should inline the product-facing bullets from the changelog (no bare links) **and must not repeat the title inside the body**; attach the `npm pack` tarball + checksums if you generated them.
|
||||
- [ ] From a clean temp directory (no `package.json`), run `npx -y warelay@X.Y.Z send --help` to confirm install/CLI entrypoints work.
|
||||
- [ ] Create/refresh the GitHub release for `vX.Y.Z` with **title `clawdis X.Y.Z`** (not just the tag); body should inline the product-facing bullets from the changelog (no bare links) **and must not repeat the title inside the body**; attach the `npm pack` tarball + checksums if you generated them.
|
||||
- [ ] From a clean temp directory (no `package.json`), run `npx -y clawdis@X.Y.Z send --help` to confirm install/CLI entrypoints work.
|
||||
- [ ] Announce/share release notes.
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# Plan: `warelay agent` (direct-to-agent invocation)
|
||||
# Plan: `clawdis agent` (direct-to-agent invocation)
|
||||
|
||||
Goal: Add a CLI subcommand that talks directly to the configured agent/command runner (no WhatsApp send), while reusing the same session handling and config warelay already uses for auto-replies.
|
||||
Goal: Add a CLI subcommand that talks directly to the configured agent/command runner (no WhatsApp send), while reusing the same session handling and config clawdis already uses for auto-replies.
|
||||
|
||||
## Why
|
||||
- Sometimes we want to poke the agent directly (same prompt templates/sessions) without sending a WhatsApp message.
|
||||
- Current flows (`send`, relay, directives) always route through WhatsApp or add wrapping text; we need a clean “talk to agent now” tool.
|
||||
|
||||
## Behavior
|
||||
- Command: `warelay agent`
|
||||
- Command: `clawdis agent`
|
||||
- Required: `--message <text>`
|
||||
- Session selection:
|
||||
- If `--session-id` given, use it.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Building Your Own AI Personal Assistant with warelay
|
||||
# Building Your Own AI Personal Assistant with clawdis
|
||||
|
||||
> **TL;DR:** CLAWDIS (Pi/Tau only) lets you run a proactive assistant over WhatsApp. It can check in on you, remember context across conversations, run commands on your Mac, and even wake you up with music. This doc was originally written for Claude Code; where you see `claude ...`, use `pi --mode rpc ...` instead. A Pi-specific rewrite is coming soon.
|
||||
|
||||
@@ -33,11 +33,11 @@ This is experimental software running experimental AI. The author uses it daily,
|
||||
|
||||
### Why a Dedicated Number?
|
||||
|
||||
warelay uses WhatsApp Web to receive messages. If you link your personal WhatsApp, *you* become the assistant - every message to you goes to Claude. Instead, give Claude its own identity:
|
||||
clawdis uses WhatsApp Web to receive messages. If you link your personal WhatsApp, *you* become the assistant - every message to you goes to Claude. Instead, give Claude its own identity:
|
||||
|
||||
- 📱 **Get a second SIM** - cheap prepaid SIM, eSIM, or old phone with a number
|
||||
- 💬 **Install WhatsApp** on that phone and verify the number
|
||||
- 🔗 **Link to warelay** - run `warelay login` and scan the QR with that phone's WhatsApp
|
||||
- 🔗 **Link to clawdis** - run `clawdis login` and scan the QR with that phone's WhatsApp
|
||||
- ✉️ **Message your AI** - now you (and others) can text that number to reach Claude
|
||||
|
||||
### The Setup
|
||||
@@ -52,7 +52,7 @@ Your Phone (personal) Second Phone (AI)
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ Your Mac │
|
||||
│ (warelay) │
|
||||
│ (clawdis) │
|
||||
│ Claude Code │
|
||||
└─────────────────┘
|
||||
```
|
||||
@@ -65,7 +65,7 @@ The second phone just needs to stay on and connected to the internet occasionall
|
||||
|
||||

|
||||
|
||||
Clawd is @steipete's personal AI assistant built on warelay. Here's what makes it special:
|
||||
Clawd is @steipete's personal AI assistant built on clawdis. Here's what makes it special:
|
||||
|
||||
- **Always available** via WhatsApp - no app switching, works on any device
|
||||
- **Proactive heartbeats** - Clawd checks in every 10 minutes and can alert you to things (low battery, calendar reminders, anything it notices)
|
||||
@@ -73,11 +73,11 @@ Clawd is @steipete's personal AI assistant built on warelay. Here's what makes i
|
||||
- **Full Mac access** - can run commands, take screenshots, control Spotify, read/write files
|
||||
- **Personal workspace** - has its own folder (`~/clawd`) where it stores notes, memories, and artifacts
|
||||
|
||||
The magic is in the combination: WhatsApp's ubiquity + Claude's intelligence + warelay's plumbing + your Mac's capabilities.
|
||||
The magic is in the combination: WhatsApp's ubiquity + Claude's intelligence + clawdis's plumbing + your Mac's capabilities.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Node 22+, `warelay` installed: `npm install -g warelay`
|
||||
- Node 22+, `clawdis` installed: `npm install -g clawdis`
|
||||
- Claude CLI installed and logged in:
|
||||
```sh
|
||||
brew install anthropic-ai/cli/claude
|
||||
@@ -91,7 +91,7 @@ This is the actual config running on @steipete's Mac (`~/.clawdis/clawdis.json`)
|
||||
|
||||
```json5
|
||||
{
|
||||
logging: { level: "trace", file: "/tmp/warelay/warelay.log" },
|
||||
logging: { level: "trace", file: "/tmp/clawdis/clawdis.log" },
|
||||
inbound: {
|
||||
allowFrom: ["+1234567890"], // your phone number
|
||||
reply: {
|
||||
@@ -153,7 +153,7 @@ Peter trusts you with a lot of power. Don't betray that trust.`,
|
||||
|
||||
## Heartbeats: Your Proactive Assistant
|
||||
|
||||
This is where warelay gets interesting. Every 10 minutes (configurable), warelay pings Claude with:
|
||||
This is where clawdis gets interesting. Every 10 minutes (configurable), clawdis pings Claude with:
|
||||
|
||||
```
|
||||
HEARTBEAT /think:high
|
||||
@@ -197,23 +197,23 @@ Set to `0` to disable heartbeats entirely.
|
||||
|
||||
Test it anytime:
|
||||
```sh
|
||||
warelay heartbeat --provider web --to +1234567890 --verbose
|
||||
clawdis heartbeat --provider web --to +1234567890 --verbose
|
||||
```
|
||||
|
||||
## How Messages Flow
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ WhatsApp │────▶│ warelay │────▶│ Claude │────▶│ Your Mac │
|
||||
│ WhatsApp │────▶│ clawdis │────▶│ Claude │────▶│ Your Mac │
|
||||
│ (phone) │◀────│ relay │◀────│ CLI │◀────│ (commands) │
|
||||
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
|
||||
```
|
||||
|
||||
1. **Inbound**: WhatsApp message arrives via Baileys (WhatsApp Web protocol)
|
||||
2. **Queue**: warelay queues it (one Claude run at a time)
|
||||
2. **Queue**: clawdis queues it (one Claude run at a time)
|
||||
3. **Typing**: "composing" indicator shows while Claude thinks
|
||||
4. **Execute**: Claude runs with full shell access in your `cwd`
|
||||
5. **Parse**: warelay extracts text + any `MEDIA:` paths from output
|
||||
5. **Parse**: clawdis extracts text + any `MEDIA:` paths from output
|
||||
6. **Reply**: Response sent back to WhatsApp
|
||||
|
||||
## Media: Images, Voice, Documents
|
||||
@@ -232,19 +232,19 @@ Inbound images/audio/video are downloaded and available as `{{MediaPath}}`. Voic
|
||||
```
|
||||
|
||||
### Sending Media
|
||||
Include `MEDIA:/path/to/file.png` in Claude's output to attach images. warelay handles resizing and format conversion automatically.
|
||||
Include `MEDIA:/path/to/file.png` in Claude's output to attach images. clawdis handles resizing and format conversion automatically.
|
||||
|
||||
## Starting the Relay
|
||||
|
||||
```sh
|
||||
# Foreground (see all logs)
|
||||
warelay relay --provider web --verbose
|
||||
clawdis relay --provider web --verbose
|
||||
|
||||
# Background in tmux (recommended)
|
||||
warelay relay:tmux
|
||||
clawdis relay:tmux
|
||||
|
||||
# With immediate heartbeat on startup
|
||||
warelay relay:heartbeat:tmux
|
||||
clawdis relay:heartbeat:tmux
|
||||
```
|
||||
|
||||
## Tips for a Great Personal Assistant
|
||||
@@ -402,7 +402,7 @@ mcporter handles OAuth flows for services like Linear and Notion, and keeps your
|
||||
3. **GitHub + Linear** = AI manages your dev workflow end-to-end
|
||||
4. **Chrome DevTools** = AI can see and interact with web pages
|
||||
|
||||
The combination of warelay (WhatsApp) + MCPs (services) + Claude Code (execution) creates a surprisingly capable personal assistant.
|
||||
The combination of clawdis (WhatsApp) + MCPs (services) + Claude Code (execution) creates a surprisingly capable personal assistant.
|
||||
|
||||
### browser-tools for Web Scraping
|
||||
|
||||
@@ -475,7 +475,7 @@ Returns song title, artist, album, and Spotify link. Works great for identifying
|
||||
|
||||
## See It In Action
|
||||
|
||||
Check out these tweets showing warelay + Clawd in the wild:
|
||||
Check out these tweets showing clawdis + Clawd in the wild:
|
||||
|
||||
- [Clawd with full system access via WhatsApp](https://x.com/steipete/status/1993342394184745270) - "I'll be nice to Clawd"
|
||||
- [Voice support - talk with Clawd on the go](https://x.com/steipete/status/1993455673229840588) - and it talks back!
|
||||
|
||||
@@ -4,7 +4,7 @@ Author: steipete · Status: draft spec · Date: 2025-12-05
|
||||
|
||||
## Purpose
|
||||
- Single macOS menu-bar app named **Clawdis** that:
|
||||
- Shows native notifications for Clawdis/warelay events.
|
||||
- Shows native notifications for Clawdis/clawdis events.
|
||||
- Owns TCC prompts (Notifications, Accessibility, Screen Recording, Automation/AppleScript, Microphone, Speech Recognition).
|
||||
- Brokers privileged actions (screen capture, shell with elevated UI context) via XPC.
|
||||
- Provides a tiny CLI (`clawdis-mac`) that talks to the app; Node/TS shells out to it.
|
||||
@@ -65,7 +65,7 @@ struct Response { ok: Bool; message?: String; payload?: Data }
|
||||
- `status`
|
||||
- Internals: builds Request, connects via AsyncXPCConnection, prints Response as JSON to stdout.
|
||||
|
||||
## Integration with warelay/Clawdis (Node/TS)
|
||||
## Integration with clawdis/Clawdis (Node/TS)
|
||||
- Add helper module that shells to `clawdis-mac`:
|
||||
- Prefer `ensure-permissions` before actions that need TCC.
|
||||
- Use `notify` for desktop toasts; fall back to JS notifier only if CLI missing or platform ≠ macOS.
|
||||
|
||||
@@ -149,15 +149,15 @@ export CLAWDIS_CONFIG_PATH=~/.clawdis/clawdis.json
|
||||
|
||||
## Migrating from Warelay
|
||||
|
||||
If you're upgrading from the old `warelay` name:
|
||||
If you're upgrading from the old `clawdis` name:
|
||||
|
||||
```bash
|
||||
# Move config
|
||||
mv ~/.warelay ~/.clawdis
|
||||
mv ~/.clawdis/warelay.json ~/.clawdis/clawdis.json
|
||||
mv ~/.clawdis ~/.clawdis
|
||||
mv ~/.clawdis/clawdis.json ~/.clawdis/clawdis.json
|
||||
|
||||
# Update any hardcoded paths in your config
|
||||
sed -i '' 's/warelay/clawdis/g' ~/.clawdis/clawdis.json
|
||||
sed -i '' 's/clawdis/clawdis/g' ~/.clawdis/clawdis.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -37,9 +37,9 @@ Goal: add a simple heartbeat poll for command-based auto-replies (Pi/Tau) that o
|
||||
## Documentation
|
||||
- Add a short README snippet under configuration showing `heartbeatMinutes` and the sentinel rule.
|
||||
- Expose CLI triggers:
|
||||
- `warelay heartbeat` (web provider, defaults to first `allowFrom`; optional `--to` override)
|
||||
- `clawdis heartbeat` (web provider, defaults to first `allowFrom`; optional `--to` override)
|
||||
- `--session-id <uuid>` forces resuming a specific session for that heartbeat
|
||||
- `warelay relay:heartbeat` to run the relay loop with an immediate heartbeat (no tmux)
|
||||
- `warelay relay:heartbeat:tmux` to run the same in tmux (detached, attachable)
|
||||
- `clawdis relay:heartbeat` to run the relay loop with an immediate heartbeat (no tmux)
|
||||
- `clawdis relay:heartbeat:tmux` to run the same in tmux (detached, attachable)
|
||||
- Relay supports `--heartbeat-now` to fire once at startup (including the tmux helper).
|
||||
- When multiple sessions are active or `allowFrom` is only `"*"`, require `--to <E.164>` or `--all` for manual heartbeats to avoid ambiguous targets.
|
||||
|
||||
@@ -59,7 +59,7 @@ clawdis status
|
||||
|
||||
- [Configuration Guide](./configuration.md) — Setting up your CLAWDIS
|
||||
- [Agent Integration](./agents.md) — Connecting AI agents
|
||||
- [Direct Agent CLI](./agent-send.md) — Use `warelay agent` without sending WhatsApp messages
|
||||
- [Direct Agent CLI](./agent-send.md) — Use `clawdis agent` without sending WhatsApp messages
|
||||
- [Group Chats](./groups.md) — Mention patterns and filtering
|
||||
- [Media Handling](./media.md) — Images, voice, documents
|
||||
- [Session Management](./session.md) — How conversations are keyed and reset
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Date: 2025-12-06 · Status: draft · Owner: steipete
|
||||
|
||||
## Goal
|
||||
Run the Node-based Clawdis/warelay relay as a direct child of the LSUIElement app (instead of a launchd agent) while keeping all TCC-sensitive work inside the Swift app/XPC and wiring the existing “Clawdis Active” toggle to start/stop the child.
|
||||
Run the Node-based Clawdis/clawdis relay as a direct child of the LSUIElement app (instead of a launchd agent) while keeping all TCC-sensitive work inside the Swift app/XPC and wiring the existing “Clawdis Active” toggle to start/stop the child.
|
||||
|
||||
## When to prefer the child-process mode
|
||||
- You want relay lifetime strictly coupled to the menu-bar app (dies when the app quits) and controlled by the “Clawdis Active” toggle without touching launchd.
|
||||
@@ -30,7 +30,7 @@ Run the Node-based Clawdis/warelay relay as a direct child of the LSUIElement ap
|
||||
- `execution: Execution?` from `Swift Subprocess` to track the child.
|
||||
- `start(config)` called when “Clawdis Active” flips ON:
|
||||
- binary: bundled Node or packaged relay CLI under `Clawdis.app/Contents/Resources/Relay/`
|
||||
- args: current warelay/clawdis entrypoint and flags
|
||||
- args: current clawdis/clawdis entrypoint and flags
|
||||
- cwd/env: point to `~/.clawdis` as today; inject `PATH` if the embedded Node isn’t on PATH
|
||||
- output: stream stdout/stderr to `/tmp/clawdis-relay.log` (cap buffer via Subprocess OutputLimits)
|
||||
- restart: optional linear/backoff restart if exit was non-zero and Active is still true
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
# Web Relay Troubleshooting (Nov 26, 2025)
|
||||
|
||||
## Symptoms & quick fixes
|
||||
- **Stream Errored / Conflict / status 409–515:** WhatsApp closed the socket because another session is active or creds went stale. Run `warelay logout` then `warelay login --provider web` and restart the relay.
|
||||
- **Logged out:** Console prints “session logged out”; re-link with `warelay login --provider web`.
|
||||
- **Stream Errored / Conflict / status 409–515:** WhatsApp closed the socket because another session is active or creds went stale. Run `clawdis logout` then `clawdis login --provider web` and restart the relay.
|
||||
- **Logged out:** Console prints “session logged out”; re-link with `clawdis login --provider web`.
|
||||
- **Repeated retries then exit:** Reconnects are capped (default 12 attempts). Tune with `--web-retries`, `--web-retry-initial`, `--web-retry-max`, or config `web.reconnect`.
|
||||
- **No inbound messages:** Ensure the QR-linked account is online in WhatsApp, and check logs for `web-heartbeat` to confirm auth age/connection.
|
||||
- **Fast nuke:** From an allowed WhatsApp sender you can send `/restart` to kick `com.steipete.clawdis` via launchd; wait a few seconds for it to relink.
|
||||
|
||||
## Helpful commands
|
||||
- Start relay web-only: `pnpm warelay relay --provider web --verbose`
|
||||
- Show who is linked: `pnpm warelay relay --provider web --verbose` (first line prints the linked E.164)
|
||||
- Logout (clear creds): `pnpm warelay logout`
|
||||
- Relink: `pnpm warelay login --provider web`
|
||||
- Tail logs (default): `tail -f /tmp/warelay/warelay.log`
|
||||
- Start relay web-only: `pnpm clawdis relay --provider web --verbose`
|
||||
- Show who is linked: `pnpm clawdis relay --provider web --verbose` (first line prints the linked E.164)
|
||||
- Logout (clear creds): `pnpm clawdis logout`
|
||||
- Relink: `pnpm clawdis login --provider web`
|
||||
- Tail logs (default): `tail -f /tmp/clawdis/clawdis.log`
|
||||
|
||||
## Reading the logs
|
||||
- `web-reconnect`: close reasons, retry/backoff, max-attempt exit.
|
||||
@@ -25,7 +25,7 @@
|
||||
- Chatty monitors: increase `--web-heartbeat` interval if log volume is high.
|
||||
|
||||
## If it keeps failing
|
||||
1) `warelay logout` → `warelay login --provider web` (fresh QR link).
|
||||
1) `clawdis logout` → `clawdis login --provider web` (fresh QR link).
|
||||
2) Ensure no other device/browser is using the same WA Web session.
|
||||
3) Check WhatsApp mobile app is online and not in low-power mode.
|
||||
4) If status is 515, let the client restart once after pairing (already handled automatically).
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Clawdis treats **one session as primary**. By default the canonical key is `main`; set `inbound.reply.session.mainKey` to change it. Older/local sessions can stay on disk, but only the primary key is used for desktop/web chat and direct agent calls.
|
||||
|
||||
## Where state lives
|
||||
- Store file: `~/.clawdis/sessions/sessions.json` (legacy: `~/.warelay/sessions.json`).
|
||||
- Store file: `~/.clawdis/sessions/sessions.json` (legacy: `~/.clawdis/sessions.json`).
|
||||
- Transcripts: `~/.clawdis/sessions/<SessionId>.jsonl` (one file per session id).
|
||||
- The store is a map `sessionKey -> { sessionId, updatedAt, ... }`. Deleting entries is safe; they are recreated on demand.
|
||||
|
||||
|
||||
10
docs/tmux.md
10
docs/tmux.md
@@ -6,12 +6,12 @@
|
||||
- Keep the relay code itself tmux-agnostic; tmux is only a launcher concern.
|
||||
|
||||
## Commands
|
||||
- `warelay relay:tmux` — restarts the `warelay-relay` session running `pnpm warelay relay --verbose`, then attaches (skips attach when stdout isn’t a TTY).
|
||||
- `warelay relay:tmux:attach` — attach to the existing session without restarting it.
|
||||
- `warelay relay:heartbeat:tmux` — same as `relay:tmux` but adds `--heartbeat-now` so Pi is pinged immediately on startup.
|
||||
- `clawdis relay:tmux` — restarts the `clawdis-relay` session running `pnpm clawdis relay --verbose`, then attaches (skips attach when stdout isn’t a TTY).
|
||||
- `clawdis relay:tmux:attach` — attach to the existing session without restarting it.
|
||||
- `clawdis relay:heartbeat:tmux` — same as `relay:tmux` but adds `--heartbeat-now` so Pi is pinged immediately on startup.
|
||||
|
||||
All helpers use the fixed session name `warelay-relay`.
|
||||
All helpers use the fixed session name `clawdis-relay`.
|
||||
|
||||
## Logs
|
||||
- The relay always writes to the configured file logger (defaults to `/tmp/warelay/warelay.log`); on start it prints the active log path and level.
|
||||
- The relay always writes to the configured file logger (defaults to `/tmp/clawdis/clawdis.log`); on start it prints the active log path and level.
|
||||
- tmux is just for interactive viewing; you can also tail the log file or use another supervisor if you prefer.
|
||||
|
||||
@@ -5,18 +5,12 @@
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
"bin": {
|
||||
"clawdis": "bin/warelay.js",
|
||||
"warelay": "bin/warelay.js",
|
||||
"warely": "bin/warelay.js",
|
||||
"wa": "bin/warelay.js"
|
||||
"clawdis": "dist/index.js"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "tsx src/index.ts",
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"start": "tsx src/index.ts",
|
||||
"warelay": "tsx src/index.ts",
|
||||
"warely": "tsx src/index.ts",
|
||||
"wa": "tsx src/index.ts",
|
||||
"clawdis": "tsx src/index.ts",
|
||||
"clawdis:rpc": "tsx src/index.ts agent --mode rpc --json",
|
||||
"lint": "biome check src",
|
||||
|
||||
@@ -355,7 +355,7 @@ describe("runCommandReply (pi)", () => {
|
||||
});
|
||||
|
||||
it("parses MEDIA tokens and respects mediaMaxMb for local files", async () => {
|
||||
const tmp = path.join(os.tmpdir(), `warelay-test-${Date.now()}.bin`);
|
||||
const tmp = path.join(os.tmpdir(), `clawdis-test-${Date.now()}.bin`);
|
||||
const bigBuffer = Buffer.alloc(2 * 1024 * 1024, 1);
|
||||
await fs.writeFile(tmp, bigBuffer);
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ describe("transcribeInboundAudio", () => {
|
||||
|
||||
it("downloads mediaUrl to temp file and returns transcript", async () => {
|
||||
const tmpBuf = Buffer.from("audio-bytes");
|
||||
const tmpFile = path.join(os.tmpdir(), `warelay-audio-${Date.now()}.ogg`);
|
||||
const tmpFile = path.join(os.tmpdir(), `clawdis-audio-${Date.now()}.ogg`);
|
||||
await fs.writeFile(tmpFile, tmpBuf);
|
||||
|
||||
const fetchMock = vi.fn(async () => ({
|
||||
|
||||
@@ -30,7 +30,7 @@ const configSpy = vi.spyOn(configModule, "loadConfig");
|
||||
function makeStorePath() {
|
||||
return path.join(
|
||||
os.tmpdir(),
|
||||
`warelay-agent-test-${Date.now()}-${Math.random()}.json`,
|
||||
`clawdis-agent-test-${Date.now()}-${Math.random()}.json`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { PassThrough } from "node:stream";
|
||||
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const realOs = await vi.importActual<typeof import("node:os")>("node:os");
|
||||
const HOME = path.join(realOs.tmpdir(), "warelay-home-redirect");
|
||||
const HOME = path.join(realOs.tmpdir(), "clawdis-home-redirect");
|
||||
const mockRequest = vi.fn();
|
||||
|
||||
vi.doMock("node:os", () => ({
|
||||
|
||||
@@ -4,7 +4,7 @@ import sharp from "sharp";
|
||||
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const realOs = await vi.importActual<typeof import("node:os")>("node:os");
|
||||
const HOME = path.join(realOs.tmpdir(), "warelay-home-test");
|
||||
const HOME = path.join(realOs.tmpdir(), "clawdis-home-test");
|
||||
|
||||
vi.mock("node:os", () => ({
|
||||
default: { homedir: () => HOME, tmpdir: () => realOs.tmpdir() },
|
||||
@@ -25,7 +25,7 @@ describe("media store", () => {
|
||||
|
||||
it("creates and returns media directory", async () => {
|
||||
const dir = await store.ensureMediaDir();
|
||||
expect(dir).toContain("warelay-home-test");
|
||||
expect(dir).toContain("clawdis-home-test");
|
||||
const stat = await fs.stat(dir);
|
||||
expect(stat.isDirectory()).toBe(true);
|
||||
});
|
||||
|
||||
@@ -37,7 +37,7 @@ describe("withWhatsAppPrefix", () => {
|
||||
describe("ensureDir", () => {
|
||||
it("creates nested directory", async () => {
|
||||
const tmp = await fs.promises.mkdtemp(
|
||||
path.join(os.tmpdir(), "warelay-test-"),
|
||||
path.join(os.tmpdir(), "clawdis-test-"),
|
||||
);
|
||||
const target = path.join(tmp, "nested", "dir");
|
||||
await ensureDir(target);
|
||||
|
||||
@@ -71,5 +71,5 @@ export function sleep(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
// Fixed configuration root; legacy ~/.warelay is no longer used.
|
||||
// Fixed configuration root; legacy ~/.clawdis is no longer used.
|
||||
export const CONFIG_DIR = path.join(os.homedir(), ".clawdis");
|
||||
|
||||
@@ -28,7 +28,7 @@ import {
|
||||
const makeSessionStore = async (
|
||||
entries: Record<string, unknown> = {},
|
||||
): Promise<{ storePath: string; cleanup: () => Promise<void> }> => {
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "warelay-session-"));
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-session-"));
|
||||
const storePath = path.join(dir, "sessions.json");
|
||||
await fs.writeFile(storePath, JSON.stringify(entries));
|
||||
return {
|
||||
@@ -229,7 +229,7 @@ describe("runWebHeartbeatOnce", () => {
|
||||
|
||||
it("does not refresh updatedAt when heartbeat is skipped", async () => {
|
||||
const tmpDir = await fs.mkdtemp(
|
||||
path.join(os.tmpdir(), "warelay-heartbeat-"),
|
||||
path.join(os.tmpdir(), "clawdis-heartbeat-"),
|
||||
);
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const now = Date.now();
|
||||
@@ -269,7 +269,7 @@ describe("runWebHeartbeatOnce", () => {
|
||||
|
||||
it("heartbeat reuses existing session id when last inbound is present", async () => {
|
||||
const tmpDir = await fs.mkdtemp(
|
||||
path.join(os.tmpdir(), "warelay-heartbeat-session-"),
|
||||
path.join(os.tmpdir(), "clawdis-heartbeat-session-"),
|
||||
);
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const sessionId = "sess-keep";
|
||||
@@ -319,7 +319,7 @@ describe("runWebHeartbeatOnce", () => {
|
||||
|
||||
it("heartbeat honors session-id override and seeds store", async () => {
|
||||
const tmpDir = await fs.mkdtemp(
|
||||
path.join(os.tmpdir(), "warelay-heartbeat-override-"),
|
||||
path.join(os.tmpdir(), "clawdis-heartbeat-override-"),
|
||||
);
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
await fs.writeFile(storePath, JSON.stringify({}));
|
||||
@@ -527,7 +527,7 @@ describe("web auto-reply", () => {
|
||||
|
||||
it("skips reply heartbeat when requests are running", async () => {
|
||||
const tmpDir = await fs.mkdtemp(
|
||||
path.join(os.tmpdir(), "warelay-heartbeat-queue-"),
|
||||
path.join(os.tmpdir(), "clawdis-heartbeat-queue-"),
|
||||
);
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
await fs.writeFile(storePath, JSON.stringify({}));
|
||||
@@ -1126,7 +1126,7 @@ describe("web auto-reply", () => {
|
||||
|
||||
it("emits heartbeat logs with connection metadata", async () => {
|
||||
vi.useFakeTimers();
|
||||
const logPath = `/tmp/warelay-heartbeat-${crypto.randomUUID()}.log`;
|
||||
const logPath = `/tmp/clawdis-heartbeat-${crypto.randomUUID()}.log`;
|
||||
setLoggerOverride({ level: "trace", file: logPath });
|
||||
|
||||
const runtime = {
|
||||
@@ -1168,7 +1168,7 @@ describe("web auto-reply", () => {
|
||||
});
|
||||
|
||||
it("logs outbound replies to file", async () => {
|
||||
const logPath = `/tmp/warelay-log-test-${crypto.randomUUID()}.log`;
|
||||
const logPath = `/tmp/clawdis-log-test-${crypto.randomUUID()}.log`;
|
||||
setLoggerOverride({ level: "trace", file: logPath });
|
||||
|
||||
let capturedOnMessage:
|
||||
@@ -1362,7 +1362,7 @@ describe("web auto-reply", () => {
|
||||
sendMedia: vi.fn(),
|
||||
});
|
||||
|
||||
// HEARTBEAT_OK should NOT have prefix - warelay needs exact match
|
||||
// HEARTBEAT_OK should NOT have prefix - clawdis needs exact match
|
||||
expect(reply).toHaveBeenCalledWith(HEARTBEAT_TOKEN);
|
||||
resetLoadConfigMock();
|
||||
});
|
||||
|
||||
@@ -18,7 +18,7 @@ vi.mock("../config/config.js", () => ({
|
||||
|
||||
const HOME = path.join(
|
||||
os.tmpdir(),
|
||||
`warelay-inbound-media-${crypto.randomUUID()}`,
|
||||
`clawdis-inbound-media-${crypto.randomUUID()}`,
|
||||
);
|
||||
process.env.HOME = HOME;
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ describe("web media loading", () => {
|
||||
.jpeg({ quality: 95 })
|
||||
.toBuffer();
|
||||
|
||||
const file = path.join(os.tmpdir(), `warelay-media-${Date.now()}.jpg`);
|
||||
const file = path.join(os.tmpdir(), `clawdis-media-${Date.now()}.jpg`);
|
||||
tmpFiles.push(file);
|
||||
await fs.writeFile(file, buffer);
|
||||
|
||||
@@ -45,7 +45,7 @@ describe("web media loading", () => {
|
||||
})
|
||||
.png()
|
||||
.toBuffer();
|
||||
const wrongExt = path.join(os.tmpdir(), `warelay-media-${Date.now()}.bin`);
|
||||
const wrongExt = path.join(os.tmpdir(), `clawdis-media-${Date.now()}.bin`);
|
||||
tmpFiles.push(wrongExt);
|
||||
await fs.writeFile(wrongExt, pngBuffer);
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ describe("web monitor inbox", () => {
|
||||
it("logs inbound bodies to file", async () => {
|
||||
const logPath = path.join(
|
||||
os.tmpdir(),
|
||||
`warelay-log-test-${crypto.randomUUID()}.log`,
|
||||
`clawdis-log-test-${crypto.randomUUID()}.log`,
|
||||
);
|
||||
setLoggerOverride({ level: "trace", file: logPath });
|
||||
|
||||
|
||||
Reference in New Issue
Block a user