diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d04e481c..a5fae4d06 100644 --- a/CHANGELOG.md +++ b/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 ` (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 ` (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 `[πŸ› οΈ ]` messages (now streamed as they happen), and new sessions surface a `🧭 New session: ` 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 diff --git a/apps/macos/Sources/Clawdis/RelayProcessManager.swift b/apps/macos/Sources/Clawdis/RelayProcessManager.swift index 633113fac..b8c373732 100644 --- a/apps/macos/Sources/Clawdis/RelayProcessManager.swift +++ b/apps/macos/Sources/Clawdis/RelayProcessManager.swift @@ -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"] diff --git a/apps/macos/Sources/Clawdis/SessionData.swift b/apps/macos/Sources/Clawdis/SessionData.swift index f3847add2..b2baa3a40 100644 --- a/apps/macos/Sources/Clawdis/SessionData.swift +++ b/apps/macos/Sources/Clawdis/SessionData.swift @@ -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 { diff --git a/docs/RELEASING.md b/docs/RELEASING.md index f074134f6..de8a3efa4 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -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. diff --git a/docs/agent-send.md b/docs/agent-send.md index 45e8edd22..1b07cde4b 100644 --- a/docs/agent-send.md +++ b/docs/agent-send.md @@ -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 ` - Session selection: - If `--session-id` given, use it. diff --git a/docs/clawd.md b/docs/clawd.md index 5264be1cd..cfb23a6f3 100644 --- a/docs/clawd.md +++ b/docs/clawd.md @@ -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 in action on WhatsApp](whatsapp-clawd.jpg) -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! diff --git a/docs/clawdis-mac.md b/docs/clawdis-mac.md index 09ee33cbe..1beb83d85 100644 --- a/docs/clawdis-mac.md +++ b/docs/clawdis-mac.md @@ -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. diff --git a/docs/configuration.md b/docs/configuration.md index 66bccedf0..2dd07405d 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -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 ``` --- diff --git a/docs/heartbeat.md b/docs/heartbeat.md index ed5384373..86f854148 100644 --- a/docs/heartbeat.md +++ b/docs/heartbeat.md @@ -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 ` 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 ` or `--all` for manual heartbeats to avoid ambiguous targets. diff --git a/docs/index.md b/docs/index.md index de3adf769..87990c7bd 100644 --- a/docs/index.md +++ b/docs/index.md @@ -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 diff --git a/docs/mac/child-process.md b/docs/mac/child-process.md index b0680f436..0b03d2ec5 100644 --- a/docs/mac/child-process.md +++ b/docs/mac/child-process.md @@ -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 diff --git a/docs/refactor/web-relay-troubleshooting.md b/docs/refactor/web-relay-troubleshooting.md index e8dcf0f16..66a328a72 100644 --- a/docs/refactor/web-relay-troubleshooting.md +++ b/docs/refactor/web-relay-troubleshooting.md @@ -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). diff --git a/docs/session.md b/docs/session.md index 2b2071abb..e3cea26cf 100644 --- a/docs/session.md +++ b/docs/session.md @@ -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/.jsonl` (one file per session id). - The store is a map `sessionKey -> { sessionId, updatedAt, ... }`. Deleting entries is safe; they are recreated on demand. diff --git a/docs/tmux.md b/docs/tmux.md index 782b7b48d..a6340b727 100644 --- a/docs/tmux.md +++ b/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. diff --git a/package.json b/package.json index 193ed8eb6..e59affcdf 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/auto-reply/command-reply.test.ts b/src/auto-reply/command-reply.test.ts index 7c7da2c25..b19cf2366 100644 --- a/src/auto-reply/command-reply.test.ts +++ b/src/auto-reply/command-reply.test.ts @@ -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); diff --git a/src/auto-reply/transcription.test.ts b/src/auto-reply/transcription.test.ts index 4cdd94543..3100e2acd 100644 --- a/src/auto-reply/transcription.test.ts +++ b/src/auto-reply/transcription.test.ts @@ -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 () => ({ diff --git a/src/commands/agent.test.ts b/src/commands/agent.test.ts index ad65771f5..4597899ae 100644 --- a/src/commands/agent.test.ts +++ b/src/commands/agent.test.ts @@ -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`, ); } diff --git a/src/media/store.redirect.test.ts b/src/media/store.redirect.test.ts index 07126de39..eec5cdc77 100644 --- a/src/media/store.redirect.test.ts +++ b/src/media/store.redirect.test.ts @@ -5,7 +5,7 @@ import { PassThrough } from "node:stream"; import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; const realOs = await vi.importActual("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", () => ({ diff --git a/src/media/store.test.ts b/src/media/store.test.ts index 182106818..76611cf28 100644 --- a/src/media/store.test.ts +++ b/src/media/store.test.ts @@ -4,7 +4,7 @@ import sharp from "sharp"; import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; const realOs = await vi.importActual("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); }); diff --git a/src/utils.test.ts b/src/utils.test.ts index 997fea1a5..a2bc0d975 100644 --- a/src/utils.test.ts +++ b/src/utils.test.ts @@ -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); diff --git a/src/utils.ts b/src/utils.ts index 38d526de0..cdc69590c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -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"); diff --git a/src/web/auto-reply.test.ts b/src/web/auto-reply.test.ts index 86f0abe74..f1b99ff75 100644 --- a/src/web/auto-reply.test.ts +++ b/src/web/auto-reply.test.ts @@ -28,7 +28,7 @@ import { const makeSessionStore = async ( entries: Record = {}, ): Promise<{ storePath: string; cleanup: () => Promise }> => { - 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(); }); diff --git a/src/web/inbound.media.test.ts b/src/web/inbound.media.test.ts index c975cb86e..b9d0e9875 100644 --- a/src/web/inbound.media.test.ts +++ b/src/web/inbound.media.test.ts @@ -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; diff --git a/src/web/media.test.ts b/src/web/media.test.ts index 0d88b05bb..827c34041 100644 --- a/src/web/media.test.ts +++ b/src/web/media.test.ts @@ -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); diff --git a/src/web/monitor-inbox.test.ts b/src/web/monitor-inbox.test.ts index 1c3b0af29..6742f2d9f 100644 --- a/src/web/monitor-inbox.test.ts +++ b/src/web/monitor-inbox.test.ts @@ -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 });