diff --git a/.gitignore b/.gitignore index 09a54faf8..37406be95 100644 --- a/.gitignore +++ b/.gitignore @@ -15,13 +15,13 @@ ui/test-results/ # Bun build artifacts *.bun-build apps/macos/.build/ -apps/shared/ClawdisKit/.build/ +apps/shared/ClawdbotKit/.build/ bin/ -bin/clawdis-mac +bin/clawdbot-mac bin/docs-list apps/macos/.build-local/ apps/macos/.swiftpm/ -apps/shared/ClawdisKit/.swiftpm/ +apps/shared/ClawdbotKit/.swiftpm/ Core/ apps/ios/*.xcodeproj/ apps/ios/*.xcworkspace/ diff --git a/AGENTS.md b/AGENTS.md index f1ee1923a..b72103643 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,7 +7,7 @@ ## Build, Test, and Development Commands - Install deps: `pnpm install` -- Run CLI in dev: `pnpm clawdis ...` (tsx entry) or `pnpm dev` for `src/index.ts`. +- Run CLI in dev: `pnpm clawdbot ...` (tsx entry) or `pnpm dev` for `src/index.ts`. - Type-check/build: `pnpm build` (tsc) - Lint/format: `pnpm lint` (biome check), `pnpm format` (biome format) - Tests: `pnpm test` (vitest); coverage: `pnpm test:coverage` @@ -32,13 +32,13 @@ - PRs should summarize scope, note testing performed, and mention any user-facing changes or new flags. ## Security & Configuration Tips -- Web provider stores creds at `~/.clawdis/credentials/`; rerun `clawdis login` if logged out. -- Pi sessions live under `~/.clawdis/sessions/` by default; the base directory is not configurable. +- Web provider stores creds at `~/.clawdbot/credentials/`; rerun `clawdbot login` if logged out. +- Pi sessions live under `~/.clawdbot/sessions/` by default; the base directory is not configurable. - Never commit or publish real phone numbers, videos, or live configuration values. Use obviously fake placeholders in docs, tests, and examples. ## Agent-Specific Notes -- Gateway currently runs only as the menubar app (launchctl shows `application.com.steipete.clawdis.debug.*`), there is no separate LaunchAgent/helper label installed. Restart via the Clawdis Mac app or `scripts/restart-mac.sh`; to verify/kill use `launchctl print gui/$UID | grep clawdis` rather than expecting `com.steipete.clawdis`. **When debugging on macOS, start/stop the gateway via the app, not ad-hoc tmux sessions; kill any temporary tunnels before handoff.** -- macOS logs: use `./scripts/clawlog.sh` (aka `vtlog`) to query unified logs for subsystem `com.steipete.clawdis`; it supports follow/tail/category filters and expects passwordless sudo for `/usr/bin/log`. +- Gateway currently runs only as the menubar app (launchctl shows `application.com.steipete.clawdbot.debug.*`), there is no separate LaunchAgent/helper label installed. Restart via the Clawdbot Mac app or `scripts/restart-mac.sh`; to verify/kill use `launchctl print gui/$UID | grep clawdbot` rather than expecting `com.steipete.clawdbot`. **When debugging on macOS, start/stop the gateway via the app, not ad-hoc tmux sessions; kill any temporary tunnels before handoff.** +- macOS logs: use `./scripts/clawlog.sh` (aka `vtlog`) to query unified logs for subsystem `com.steipete.clawdbot`; it supports follow/tail/category filters and expects passwordless sudo for `/usr/bin/log`. - Also read the shared guardrails at `~/Projects/oracle/AGENTS.md` and `~/Projects/agent-scripts/AGENTS.MD` before making changes; align with any cross-repo rules noted there. - SwiftUI state management (iOS/macOS): prefer the `Observation` framework (`@Observable`, `@Bindable`) over `ObservableObject`/`@StateObject`; don’t introduce new `ObservableObject` unless required for compatibility, and migrate existing usages when touching related code. - Connection providers: when adding a new connection, update every UI surface and docs (macOS app, web UI, mobile if applicable, onboarding/overview docs) and add matching status + configuration forms so provider lists and settings stay in sync. @@ -52,27 +52,27 @@ - **Multi-agent safety:** do **not** create/remove/modify `git worktree` checkouts (or edit `.worktrees/*`) unless Peter explicitly asks. - **Multi-agent safety:** do **not** switch branches / check out a different branch unless Peter explicitly asks. - **Multi-agent safety:** running multiple agents is OK as long as each agent has its own session. -- When asked to open a “session” file, open the Pi session logs under `~/.clawdis/sessions/*.jsonl` (newest unless a specific ID is given), not the default `sessions.json`. If logs are needed from Mac Studio, SSH via Tailscale and read the same path there. -- Menubar dimming + restart flow mirrors Trimmy: use `scripts/restart-mac.sh` (kills all Clawdis variants, runs `swift build`, packages, relaunches). Icon dimming depends on MenuBarExtraAccess wiring in AppMain; keep `appearsDisabled` updates intact when touching the status item. +- When asked to open a “session” file, open the Pi session logs under `~/.clawdbot/sessions/*.jsonl` (newest unless a specific ID is given), not the default `sessions.json`. If logs are needed from Mac Studio, SSH via Tailscale and read the same path there. +- Menubar dimming + restart flow mirrors Trimmy: use `scripts/restart-mac.sh` (kills all Clawdbot variants, runs `swift build`, packages, relaunches). Icon dimming depends on MenuBarExtraAccess wiring in AppMain; keep `appearsDisabled` updates intact when touching the status item. - Do not rebuild the macOS app over SSH; rebuilds must be run directly on the Mac. - Never send streaming/partial replies to external messaging surfaces (WhatsApp, Telegram); only final replies should be delivered there. Streaming/tool events may still go to internal UIs/control channel. - Voice wake forwarding tips: - - Command template should stay `clawdis-mac agent --message "${text}" --thinking low`; `VoiceWakeForwarder` already shell-escapes `${text}`. Don’t add extra quotes. - - launchd PATH is minimal; ensure the app’s launch agent sets PATH to include `/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/steipete/Library/pnpm` so `pnpm`/`clawdis` binaries resolve when invoked via `clawdis-mac`. - - For manual `clawdis send` messages that include `!`, use the heredoc pattern noted below to avoid the Bash tool’s escaping. + - Command template should stay `clawdbot-mac agent --message "${text}" --thinking low`; `VoiceWakeForwarder` already shell-escapes `${text}`. Don’t add extra quotes. + - launchd PATH is minimal; ensure the app’s launch agent sets PATH to include `/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/steipete/Library/pnpm` so `pnpm`/`clawdbot` binaries resolve when invoked via `clawdbot-mac`. + - For manual `clawdbot send` messages that include `!`, use the heredoc pattern noted below to avoid the Bash tool’s escaping. ## Exclamation Mark Escaping Workaround -The Claude Code Bash tool escapes `!` to `\\!` in command arguments. When using `clawdis send` with messages containing exclamation marks, use heredoc syntax: +The Claude Code Bash tool escapes `!` to `\\!` in command arguments. When using `clawdbot send` with messages containing exclamation marks, use heredoc syntax: ```bash # WRONG - will send "Hello\\!" with backslash -clawdis send --to "+1234" --message 'Hello!' +clawdbot send --to "+1234" --message 'Hello!' # CORRECT - use heredoc to avoid escaping -clawdis send --to "+1234" --message "$(cat <<'EOF' +clawdbot send --to "+1234" --message "$(cat <<'EOF' Hello! EOF )" ``` -This is a Claude Code quirk, not a clawdis bug. +This is a Claude Code quirk, not a clawdbot bug. diff --git a/CHANGELOG.md b/CHANGELOG.md index f41dc7112..ce7e4b813 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,13 +3,15 @@ ## Unreleased ### Breaking -- Identifiers: rename bundle IDs and internal domains to `com.clawdis.*` (macOS: `com.clawdis.mac`, iOS: `com.clawdis.ios`, Android: `com.clawdis.android`) and update the gateway LaunchAgent label to `com.clawdis.gateway`. -- Agent tools: drop the `clawdis_` prefix (`browser`, `canvas`, `nodes`, `cron`, `gateway`). +- Project rename: Clawdis → Clawdbot. All CLIs, package/binary names, bundle IDs, config/state paths (`~/.clawdbot`), env vars (`CLAWDBOT_*`), gateway URLs, and docs now use Clawdbot. Old `clawdis` names no longer work. +- Identifiers: rename bundle IDs and internal domains to `com.clawdbot.*` (macOS: `com.clawdbot.mac`, iOS: `com.clawdbot.ios`, Android: `com.clawdbot.android`) and update the gateway LaunchAgent label to `com.clawdbot.gateway`. +- Agent tools: drop the `clawdbot_` prefix (`browser`, `canvas`, `nodes`, `cron`, `gateway`). - Bash tool: remove `stdinMode: "pty"`/node-pty support; use the tmux skill for real TTYs. - Sessions: primary session key is fixed to `main` (or `global` for global scope); `session.mainKey` is ignored. ### Features -- Gateway: support `gateway.port` + `CLAWDIS_GATEWAY_PORT` across CLI, TUI, and macOS app. +- Highlight: agent-to-agent ping-pong (reply-back loop) with `REPLY_SKIP` plus target announce step with `ANNOUNCE_SKIP` (max turns configurable, 0–5). +- Gateway: support `gateway.port` + `CLAWDBOT_GATEWAY_PORT` across CLI, TUI, and macOS app. - Gateway: add config hot reload with hybrid restart strategy (`gateway.reload`) and per-section reload handling. - Canvas host: add `canvasHost.liveReload` to disable file watching + reload injection. - UI: centralize tool display metadata and show action/detail summaries across Web Chat, SwiftUI, Android, and the TUI. @@ -20,6 +22,7 @@ - Discord: emit system events for reaction add/remove with per-guild reaction notifications (off|own|all|allowlist) (#140) — thanks @thewilloftheshadow. - Agent: add optional per-session Docker sandbox for tool execution (`agent.sandbox`) with allow/deny policy and auto-pruning. - Agent: add sandboxed Chromium browser (CDP + optional noVNC observer) for sandboxed sessions. +- Agent: add configurable Docker hardening options for sandboxed sessions (resource limits, seccomp/apparmor, DNS/hosts) and default network isolation. - Nodes: add `location.get` with Always/Precise settings on macOS/iOS/Android plus CLI/tool support. - Sessions: add agent‑to‑agent post step with `ANNOUNCE_SKIP` to suppress channel announcements. @@ -57,7 +60,7 @@ - Logging: decouple file log levels from console verbosity; verbose-only details are captured when `logging.level` is debug/trace. - Build: fix regex literal in tool-meta path detection (watch build error). - Build: require AVX2 Bun for x86_64 relay packaging (reject baseline builds). -- Build: drop stale ClawdisCLI product from macOS build-and-run script. +- Build: drop stale ClawdbotCLI product from macOS build-and-run script. - Auto-reply: add run-level telemetry + typing TTL guardrails to diagnose stuck replies. - WhatsApp: honor per-group mention gating overrides when group ids are stored as session keys. - Canvas host: reuse shared handler to avoid double file watchers and close watchers on error (EMFILE resilience). @@ -95,8 +98,8 @@ - Sessions: group keys now use `surface:group:` / `surface:channel:`; legacy `group:*` keys migrate on next message; `groupdm` keys are no longer recognized. - Discord: remove legacy `discord.allowFrom`, `discord.guildAllowFrom`, and `discord.requireMention`; use `discord.dm` + `discord.guilds`. - Providers: Discord/Telegram no longer auto-start from env tokens alone; add `discord: { enabled: true }` / `telegram: { enabled: true }` to your config when using `DISCORD_BOT_TOKEN` / `TELEGRAM_BOT_TOKEN`. -- Config: remove `routing.allowFrom`; use `whatsapp.allowFrom` instead (run `clawdis doctor` to migrate). -- Config: remove `routing.groupChat.requireMention` + `telegram.requireMention`; use `whatsapp.groups`, `imessage.groups`, and `telegram.groups` defaults instead (run `clawdis doctor` to migrate). +- Config: remove `routing.allowFrom`; use `whatsapp.allowFrom` instead (run `clawdbot doctor` to migrate). +- Config: remove `routing.groupChat.requireMention` + `telegram.requireMention`; use `whatsapp.groups`, `imessage.groups`, and `telegram.groups` defaults instead (run `clawdbot doctor` to migrate). ### Features - Discord: expand `discord` tool actions (reactions, stickers, polls, threads, search, moderation gates) (#115) — thanks @thewilloftheshadow. @@ -104,7 +107,7 @@ - Talk mode: continuous speech conversations (macOS/iOS/Android) with ElevenLabs TTS, reply directives, and optional interrupt-on-speech. - Auto-reply: expand queue modes (steer/followup/collect/steer-backlog) with debounce/cap/drop options and followup backlog handling. - UI: add optional `ui.seamColor` accent to tint the Talk Mode side bubble (macOS/iOS/Android). -- Nix mode: opt-in declarative config + read-only settings UI when `CLAWDIS_NIX_MODE=1` (thanks @joshp123 for the persistence — earned my trust; I'll merge these going forward). +- Nix mode: opt-in declarative config + read-only settings UI when `CLAWDBOT_NIX_MODE=1` (thanks @joshp123 for the persistence — earned my trust; I'll merge these going forward). - CLI: add Google Antigravity OAuth auth option for Claude Opus 4.5/Gemini 3 (#88) — thanks @mukhtharcm. - Agent runtime: accept legacy `Z_AI_API_KEY` for Z.AI provider auth (maps to `ZAI_API_KEY`). - Groups: add per-group mention gating defaults/overrides for Telegram/WhatsApp/iMessage via `*.groups` with `"*"` defaults; Discord now supports `discord.guilds."*"` as a default. @@ -114,7 +117,7 @@ - iMessage: add imsg JSON-RPC integration (stdio), chat_id routing, and group chat support. - Chat UI: add recent-session dropdown switcher (main first) in macOS/iOS/Android + Control UI. - UI: add Discord/Signal/iMessage connection panels in macOS + Control UI (thanks @thewilloftheshadow). -- Discord: allow agent-triggered reactions via `clawdis_discord` when enabled, and surface message ids in context. +- Discord: allow agent-triggered reactions via `clawdbot_discord` when enabled, and surface message ids in context. - Discord: revamp guild routing config with per-guild/channel rules and slugged display names; add optional group DM support (default off). - Discord: remove legacy guild/channel ignore lists in favor of per-guild allowlists (and proposed per-guild ignore lists). - Skills: add Trello skill for board/list/card management (thanks @clawd). @@ -126,7 +129,7 @@ - CLI: add `configure`, `doctor`, and `update` wizards for ongoing setup, health checks, and modernization. - CLI: add Signal CLI auto-install from GitHub releases in the wizard and persist wizard run metadata in config. - CLI: add remote gateway client config (gateway.remote.*) with Bonjour-assisted discovery. -- CLI: enhance `clawdis tui` with model/session pickers, tool cards, and slash commands (local or remote). +- CLI: enhance `clawdbot tui` with model/session pickers, tool cards, and slash commands (local or remote). - Gateway: allow `sessions.patch` to set per-session model overrides (used by the TUI `/model` flow). - Skills: allow `bun` as a node manager for skill installs. - Skills: add `things-mac` (Things 3 CLI) for read/search plus add/update via URL scheme. @@ -151,7 +154,7 @@ - Chat UI: add extra top padding before the first message bubble in Web Chat (macOS/iOS/Android). - Control UI: refine Web Chat session selector styling (chevron spacing + background). - WebChat: stream live updates for sessions even when runs start outside the chat UI. -- Gateway CLI: read `CLAWDIS_GATEWAY_PASSWORD` from environment in `callGateway()` — allows `doctor`/`health` commands to auth without explicit `--password` flag. +- Gateway CLI: read `CLAWDBOT_GATEWAY_PASSWORD` from environment in `callGateway()` — allows `doctor`/`health` commands to auth without explicit `--password` flag. - Gateway: add password auth support for remote gateway connections (thanks @jeffersonwarrior). - Auto-reply: strip stray leading/trailing `HEARTBEAT_OK` from normal replies; drop short (≤ 30 chars) heartbeat acks. - WhatsApp auto-reply: default to self-only when no config is present. @@ -201,7 +204,7 @@ - Docs: clarify self-chat mode and group mention gating config (#111) — thanks @rafaelreis-r. - Browser tools: `upload` supports auto-click refs, direct `inputRef`/`element` file inputs, and emits input/change after `setFiles` so JS-heavy sites pick up attachments. - Browser tools: harden CDP readiness (HTTP + WS), retry CDP connects, and auto-restart the clawd browser when the socket handshake stalls. -- Browser CLI: add `clawdis browser reset-profile` to move the clawd profile to Trash when it gets wedged. +- Browser CLI: add `clawdbot browser reset-profile` to move the clawd profile to Trash when it gets wedged. - Signal: fix daemon startup race (wait for `/api/v1/check`) and normalize JSON-RPC `version` probe parsing. - Docs/Signal: clarify bot-number vs personal-account setup (self-chat loop protection) and add a quickstart config snippet. - Docs: refresh the CLI wizard guide and highlight onboarding in the README. @@ -265,7 +268,7 @@ - macOS menu: top status line now shows pending node pairing approvals (incl. repairs). - CLI: avoid spurious gateway close errors after successful request/response cycles. - Agent runtime: clamp tool-result images to the 5MB Anthropic limit to avoid hard request rejections. -- Agent runtime: write v2 session headers so Pi session branching stays in the Clawdis sessions dir. +- Agent runtime: write v2 session headers so Pi session branching stays in the Clawdbot sessions dir. - Tests: add Swift Testing coverage for camera errors and Kotest coverage for Android bridge endpoints. ## 2.0.0-beta4 — 2025-12-27 @@ -281,12 +284,12 @@ ## 2.0.0-beta3 — 2025-12-27 ### Highlights -- First-class Clawdis tools (browser, canvas, nodes, cron) replace the old `clawdis-*` skills; tool schemas are now injected directly into the agent runtime. -- Per-session model selection + custom model providers: `models.providers` merges into `~/.clawdis/agent/models.json` (merge/replace modes) for LiteLLM, local OpenAI-compatible servers, Anthropic proxies, etc. +- First-class Clawdbot tools (browser, canvas, nodes, cron) replace the old `clawdbot-*` skills; tool schemas are now injected directly into the agent runtime. +- Per-session model selection + custom model providers: `models.providers` merges into `~/.clawdbot/agent/models.json` (merge/replace modes) for LiteLLM, local OpenAI-compatible servers, Anthropic proxies, etc. - Group chat activation modes: per-group `/activation mention|always` command with status visibility. - Discord bot transport for DMs and guild text channels, with allowlists + mention gating. - Gateway webhooks: external `wake` and isolated `agent` hooks with dedicated token auth. -- Hook mappings + Gmail Pub/Sub helper (`clawdis hooks gmail setup/run`) with auto-renew + Tailscale Funnel support. +- Hook mappings + Gmail Pub/Sub helper (`clawdbot hooks gmail setup/run`) with auto-renew + Tailscale Funnel support. - Command queue modes + per-session overrides (`/queue ...`) and new `agent.maxConcurrent` cap for safe parallelism across sessions. - Background bash tasks: `bash` auto-yields after 20s (or on demand) with a `process` tool to list/poll/log/write/kill sessions. - Gateway in-process restart: `gateway` tool action triggers a SIGUSR1 restart without needing a supervisor. @@ -383,7 +386,7 @@ ### Tests - Coverage added for models config merging, WhatsApp reply context, QR login flows, auto-reply behavior, and gateway SIGTERM timeouts. - Added gateway webhook coverage (auth, validation, and summary posting). -- Vitest now isolates HOME/XDG config roots so tests never touch a real `~/.clawdis` install. +- Vitest now isolates HOME/XDG config roots so tests never touch a real `~/.clawdbot` install. ## 2.0.0-beta2 — 2025-12-21 @@ -411,41 +414,41 @@ Second beta focused on bundled gateway packaging, skills management, onboarding - Remote/local gateway: auto-enable local gateway, clearer labels, re-ensure remote tunnel, hide local bridge discovery in remote mode. ### Build, CI, deps -- Bundled playwright-core + chromium-bidi/long; bun gateway bytecode builds; swiftformat/biome CI fixes; iOS lint script updates; Android icon/compiler updates; ignored new ClawdisKit `.swiftpm` path. +- Bundled playwright-core + chromium-bidi/long; bun gateway bytecode builds; swiftformat/biome CI fixes; iOS lint script updates; Android icon/compiler updates; ignored new ClawdbotKit `.swiftpm` path. ### Docs - README architecture refresh + npm header image fix; onboarding/bootstrap steps; skills install guidance + new skills; browser/canvas control docs; bundled gateway + DMG packaging notes. ## 2.0.0-beta1 — 2025-12-19 -First Clawdis release post rebrand. This is a semver-major because we dropped legacy providers/agents and moved defaults to new paths while adding a full macOS companion app, a WebSocket Gateway, and an iOS node. +First Clawdbot release post rebrand. This is a semver-major because we dropped legacy providers/agents and moved defaults to new paths while adding a full macOS companion app, a WebSocket Gateway, and an iOS node. ### Bug Fixes - macOS: Voice Wake / push-to-talk no longer initialize `AVAudioEngine` at app launch, preventing Bluetooth headphones from switching into headset profile when voice features are unused. (Thanks @Nachx639) ### Breaking -- Renamed to **Clawdis**: defaults now live under `~/.clawdis` (sessions in `~/.clawdis/sessions/`, IPC at `~/.clawdis/clawdis.sock`, logs in `/tmp/clawdis`). Launchd labels and config filenames follow the new name; legacy stores are copied forward on first run. +- Renamed to **Clawdbot**: defaults now live under `~/.clawdbot` (sessions in `~/.clawdbot/sessions/`, IPC at `~/.clawdbot/clawdbot.sock`, logs in `/tmp/clawdbot`). Launchd labels and config filenames follow the new name; legacy stores are copied forward on first run. - Pi only: only the embedded Pi runtime remains, and the agent CLI/CLI flags for Claude/Codex/Gemini were removed. The Pi CLI runs in RPC mode with a persistent worker. - WhatsApp Web is the only transport; Twilio support and related CLI flags/tests were removed. - Direct chats now collapse into a single `main` session by default (no config needed); groups stay isolated as `group:`. -- Gateway is now a loopback-only WebSocket daemon (`ws://127.0.0.1:18789`) that owns all providers/state; clients (CLI, WebChat, macOS app, nodes) connect to it. Start it explicitly (`clawdis gateway …`) or via Clawdis.app; helper subcommands no longer auto-spawn a gateway. +- Gateway is now a loopback-only WebSocket daemon (`ws://127.0.0.1:18789`) that owns all providers/state; clients (CLI, WebChat, macOS app, nodes) connect to it. Start it explicitly (`clawdbot gateway …`) or via Clawdbot.app; helper subcommands no longer auto-spawn a gateway. ### Gateway, nodes, and automation -- New typed Gateway WS protocol (JSON schema validated) with `clawdis gateway {health,status,send,agent,call}` helpers and structured presence/instance updates for all clients. +- New typed Gateway WS protocol (JSON schema validated) with `clawdbot gateway {health,status,send,agent,call}` helpers and structured presence/instance updates for all clients. - Optional LAN-facing bridge (`tcp://0.0.0.0:18790`) keeps the Gateway loopback-only while enabling direct Bonjour-discovered connections for paired nodes. -- Node pairing + management via `clawdis nodes {pending,approve,reject,invoke}` (used by the iOS node and future remote nodes). -- Cron jobs are Gateway-owned (`clawdis cron …`) with run history stored as JSONL and support for “isolated summary” posting into the main session. +- Node pairing + management via `clawdbot nodes {pending,approve,reject,invoke}` (used by the iOS node and future remote nodes). +- Cron jobs are Gateway-owned (`clawdbot cron …`) with run history stored as JSONL and support for “isolated summary” posting into the main session. ### macOS companion app -- **Clawdis.app menu bar companion**: packaged, signed bundle with gateway start/stop, launchd toggle, project-root and pnpm/node auto-resolution, live log shortcut, restart button, and status/recipient table plus badges/dimming for attention and paused states. +- **Clawdbot.app menu bar companion**: packaged, signed bundle with gateway start/stop, launchd toggle, project-root and pnpm/node auto-resolution, live log shortcut, restart button, and status/recipient table plus badges/dimming for attention and paused states. - **On-device Voice Wake**: Apple speech recognizer with wake-word table, language picker, live mic meter, “hold until silence,” animated ears/legs, and main-session routing that replies on the **last used surface** (WhatsApp/Telegram/WebChat). Delivery failures are logged, and the run remains visible via WebChat/session logs. - **WebChat & Debugging**: bundled WebChat UI, Debug tab with heartbeat sliders, session-store picker, log opener (`clawlog`), gateway restart, health probes, and scrollable settings panes. -- **Browser control**: manage clawd’s dedicated Chrome/Chromium with tab listing/open/focus/close, screenshots, DOM query/dump, and “AI snapshots” (aria/domSnapshot/ai) via `clawdis browser …` and UI controls. +- **Browser control**: manage clawd’s dedicated Chrome/Chromium with tab listing/open/focus/close, screenshots, DOM query/dump, and “AI snapshots” (aria/domSnapshot/ai) via `clawdbot browser …` and UI controls. - **Remote gateway control**: Bonjour discovery for local masters plus SSH-tunnel fallback for remote control when multicast is unavailable. ### iOS node - New iOS companion app that pairs to the Gateway bridge, reports presence as a node, and exposes a WKWebView “Canvas” for agent-driven UI. -- `clawdis nodes invoke` supports `canvas.eval` and `canvas.snapshot` to drive and verify the iOS Canvas (fails fast when the iOS node is backgrounded). +- `clawdbot nodes invoke` supports `canvas.eval` and `canvas.snapshot` to drive and verify the iOS Canvas (fails fast when the iOS node is backgrounded). - Voice wake words are configurable in-app; the iOS node reconnects to the last bridge when credentials are still present in Keychain. ### WhatsApp & agent experience @@ -453,12 +456,12 @@ First Clawdis release post rebrand. This is a semver-major because we dropped le - Thinking/verbosity directives: `/think` and `/verbose` acknowledge and persist per session while allowing inline overrides; verbose mode streams tool metadata with emoji/args/previews and coalesces bursts to reduce WhatsApp noise. - Heartbeats: configurable cadence with CLI/GUI toggles; directive acks suppressed during heartbeats; array/multi-payload replies normalized for Baileys. - Reply quality: smarter chunking on words/newlines, fallback warnings when media fails to send, self-number mention detection, and primed group sessions send the roster on first turn. -- In-chat `/status`: prints agent readiness, session context usage %, current thinking/verbose options, and when the WhatsApp web creds were refreshed (helps decide when to re-scan QR); still available via `clawdis status` CLI for web session health. +- In-chat `/status`: prints agent readiness, session context usage %, current thinking/verbose options, and when the WhatsApp web creds were refreshed (helps decide when to re-scan QR); still available via `clawdbot status` CLI for web session health. ### CLI, RPC, and health -- New `clawdis agent` command plus a persistent Pi RPC worker (auto-started) enables direct agent chats; `clawdis status` renders a colored session/recipient table. -- `clawdis health` probes WhatsApp link status, connect latency, heartbeat interval, session-store recency, and IPC socket presence (JSON mode for monitors). -- Added `--help`/`--version` flags; login/logout accept `--provider` (WhatsApp default). Console output is mirrored into pino logs under `/tmp/clawdis`. +- New `clawdbot agent` command plus a persistent Pi RPC worker (auto-started) enables direct agent chats; `clawdbot status` renders a colored session/recipient table. +- `clawdbot health` probes WhatsApp link status, connect latency, heartbeat interval, session-store recency, and IPC socket presence (JSON mode for monitors). +- Added `--help`/`--version` flags; login/logout accept `--provider` (WhatsApp default). Console output is mirrored into pino logs under `/tmp/clawdbot`. - RPC stability: stdin/stdout loop for Pi, auto-restart worker, raw error surfacing, and deliver-via-RPC when JSON agent output is returned. ### Security & hardening @@ -468,32 +471,32 @@ First Clawdis release post rebrand. This is a semver-major because we dropped le ### Docs - Added `docs/telegram.md` outlining the Telegram Bot API provider (grammY) and how it shares the `main` session. Default grammY throttler keeps Bot API calls under rate limits. -- Gateway can run WhatsApp + Telegram together when configured; `clawdis send --provider telegram …` sends via the Telegram bot (webhook/proxy options documented). +- Gateway can run WhatsApp + Telegram together when configured; `clawdbot send --provider telegram …` sends via the Telegram bot (webhook/proxy options documented). ## 1.5.0 — 2025-12-05 ### Breaking - Dropped all non-Pi agents (Claude, Codex, Gemini, Opencode); only the embedded Pi runtime remains and related CLI helpers have been removed. -- Removed Twilio support and all related commands/options (webhook/up/provider flags/wait-poll); CLAWDIS is Baileys Web-only. +- Removed Twilio support and all related commands/options (webhook/up/provider flags/wait-poll); CLAWDBOT is Baileys Web-only. ### Changes - Default agent handling now favors Pi RPC while falling back to plain command execution for non-Pi invocations, keeping heartbeat/session plumbing intact. - Documentation updated to reflect Pi-only support and to mark legacy Claude paths as historical. -- Status command reports web session health + session recipients; config paths are locked to `~/.clawdis` with session metadata stored under `~/.clawdis/sessions/`. +- Status command reports web session health + session recipients; config paths are locked to `~/.clawdbot` with session metadata stored under `~/.clawdbot/sessions/`. - Simplified send/agent/gateway/heartbeat to web-only delivery; removed Twilio mocks/tests and dead code. - Pi RPC timeout is now inactivity-based (5m without events) and error messages show seconds only. -- Pi sessions now write to `~/.clawdis/sessions/` by default (legacy session logs from older installs are copied over when present). +- Pi sessions now write to `~/.clawdbot/sessions/` by default (legacy session logs from older installs are copied over when present). - Directive triggers (`/think`, `/verbose`, `/stop` et al.) now reply immediately using normalized bodies (timestamps/group prefixes stripped) without waiting for the agent. - Directive/system acks carry a `⚙️` prefix and verbose parsing rejects typoed `/ver*` strings so unrelated text doesn’t flip verbosity. - Batched history blocks no longer trip directive parsing; `/think` in prior messages won't emit stray acknowledgements. - RPC fallbacks no longer echo the user's prompt (e.g., pasting a link) when the agent returns no assistant text. - Heartbeat prompts with `/think` no longer send directive acks; heartbeat replies stay silent on settings. -- `clawdis sessions` now renders a colored table (a la oracle) with context usage shown in k tokens and percent of the context window. +- `clawdbot sessions` now renders a colored table (a la oracle) with context usage shown in k tokens and percent of the context window. ## 1.4.1 — 2025-12-04 ### Changes -- 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. +- Added `clawdbot 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. @@ -501,7 +504,7 @@ First Clawdis release post rebrand. This is a semver-major because we dropped le ### 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 > `agent.thinkingDefault` > off. Pi gets `--thinking ` (except off); other agents append cue words (`think` → `think hard` → `think harder` → `ultrathink`). Heartbeat probe uses `HEARTBEAT /think:high`. -- **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 chats (web provider):** Clawdbot 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, etc.) are forwarded as metadata-only `[🛠️ ]` messages (now streamed as they happen), and new sessions surface a `🧭 New session: ` hint. @@ -510,7 +513,7 @@ First Clawdis release post rebrand. This is a semver-major because we dropped le - **Pi stability:** RPC replies buffered until the assistant turn finishes; parsers return consistent `texts[]`; web auto-replies keep a warm Pi RPC process to avoid cold starts. - **Claude prompt flow:** One-time `sessionIntro` with per-message `/think:high` bodyPrefix; system prompt always sent on first turn even with `sendSystemOnce`. - **Heartbeat UX:** Backpressure skips reply heartbeats while other commands run; skips don’t refresh session `updatedAt`; web heartbeats normalize array payloads and optional `heartbeatCommand`. -- **Control via WhatsApp:** Send `/restart` to restart the launchd service (`com.steipete.clawdis`) from your allowed numbers. +- **Control via WhatsApp:** Send `/restart` to restart the launchd service (`com.steipete.clawdbot`) from your allowed numbers. - **Pi completion signal:** RPC now resolves on Pi’s `agent_end` (or process exit) so late assistant messages aren’t truncated; 5-minute hard cap only as a failsafe. ### Reliability & UX @@ -523,7 +526,7 @@ First Clawdis release post rebrand. This is a semver-major because we dropped le - 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); `clawdis logout` also prunes session store. +- IPC socket hardened (0700 dir / 0600 socket, no symlinks/foreign owners); `clawdbot logout` also prunes session store. - Media server blocks symlinks and enforces path containment; logging rotates daily and prunes >24h. ### Bug Fixes @@ -551,11 +554,11 @@ First Clawdis release post rebrand. This is a semver-major because we dropped le - Heartbeat alerts now honor `responsePrefix`. - Command failures return user-friendly messages. - Test session isolation to avoid touching real `sessions.json`. -- (Removed in 2.0.0) IPC reuse for `clawdis send/heartbeat` prevents Signal/WhatsApp session corruption. +- (Removed in 2.0.0) IPC reuse for `clawdbot send/heartbeat` prevents Signal/WhatsApp session corruption. - Web send respects media kind (image/audio/video/document) with correct limits. ### Changes -- (Removed in 2.0.0) IPC gateway socket at `~/.clawdis/ipc/gateway.sock` with automatic CLI fallback. +- (Removed in 2.0.0) IPC gateway socket at `~/.clawdbot/ipc/gateway.sock` with automatic CLI fallback. - Batched inbound messages with timestamps; typing indicator after sends. - Watchdog restarts WhatsApp after long inactivity; heartbeat logging includes minutes since last message. - Early `allowFrom` filtering before decryption. @@ -564,7 +567,7 @@ First Clawdis release post rebrand. This is a semver-major because we dropped le ## 1.2.2 — 2025-11-28 ### Changes -- Manual heartbeat sends: `clawdis heartbeat --message/--body` (web provider only); `--dry-run` previews payloads. +- Manual heartbeat sends: `clawdbot heartbeat --message/--body` (web provider only); `--dry-run` previews payloads. ## 1.2.1 — 2025-11-28 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ce22ee8b3..cae915317 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,9 +1,9 @@ -# Contributing to Clawdis +# Contributing to Clawdbot Welcome to the lobster tank! 🦞 ## Quick Links -- **GitHub:** https://github.com/steipete/clawdis +- **GitHub:** https://github.com/clawdbot/clawdbot - **Discord:** https://discord.gg/qkhbAGHRBT - **X/Twitter:** [@steipete](https://x.com/steipete) / [@clawdbot](https://x.com/clawdbot) @@ -20,11 +20,11 @@ Welcome to the lobster tank! 🦞 ## How to Contribute 1. **Bugs & small fixes** → Open a PR! -2. **New features / architecture** → Start a [GitHub Discussion](https://github.com/steipete/clawdis/discussions) or ask in Discord first +2. **New features / architecture** → Start a [GitHub Discussion](https://github.com/clawdbot/clawdbot/discussions) or ask in Discord first 3. **Questions** → Discord #setup-help ## Before You PR -- Test locally with your Clawdis instance +- Test locally with your Clawdbot instance - Run linter: `npm run lint` - Keep PRs focused (one thing per PR) - Describe what & why diff --git a/Dockerfile.sandbox-browser b/Dockerfile.sandbox-browser index 849e92a16..b6dee841b 100644 --- a/Dockerfile.sandbox-browser +++ b/Dockerfile.sandbox-browser @@ -19,9 +19,9 @@ RUN apt-get update \ xvfb \ && rm -rf /var/lib/apt/lists/* -COPY scripts/sandbox-browser-entrypoint.sh /usr/local/bin/clawdis-sandbox-browser -RUN chmod +x /usr/local/bin/clawdis-sandbox-browser +COPY scripts/sandbox-browser-entrypoint.sh /usr/local/bin/clawdbot-sandbox-browser +RUN chmod +x /usr/local/bin/clawdbot-sandbox-browser EXPOSE 9222 5900 6080 -CMD ["clawdis-sandbox-browser"] +CMD ["clawdbot-sandbox-browser"] diff --git a/README.md b/README.md index 5fc5f99a3..e3460e892 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# 🦞 CLAWDIS — Personal AI Assistant +# 🦞 CLAWDBOT — Personal AI Assistant

- CLAWDIS + CLAWDBOT

@@ -9,20 +9,20 @@

- CI status - GitHub release + CI status + GitHub release Discord MIT License

-**Clawdis** is a *personal AI assistant* you run on your own devices. +**Clawdbot** is a *personal AI assistant* you run on your own devices. It answers you on the surfaces you already use (WhatsApp, Telegram, Discord, iMessage, WebChat), can speak and listen on macOS/iOS, and can render a live Canvas you control. The Gateway is just the control plane — the product is the assistant. If you want a personal, single-user assistant that feels local, fast, and always-on, this is it. Website: https://clawd.me · Docs: [`docs/index.md`](docs/index.md) · FAQ: [`docs/faq.md`](docs/faq.md) · Wizard: [`docs/wizard.md`](docs/wizard.md) · Docker (optional): [`docs/docker.md`](docs/docker.md) · Discord: https://discord.gg/clawd -Preferred setup: run the onboarding wizard (`clawdis onboard`). It walks through gateway, workspace, providers, and skills. The CLI wizard is the recommended path and works on **macOS, Windows, and Linux**. +Preferred setup: run the onboarding wizard (`clawdbot onboard`). It walks through gateway, workspace, providers, and skills. The CLI wizard is the recommended path and works on **macOS, Windows, and Linux**. Using Claude Pro/Max subscription? See `docs/onboarding.md` for the Anthropic OAuth setup. @@ -36,13 +36,13 @@ Your surfaces └──────────────┬────────────────┘ │ ├─ Pi agent (RPC) - ├─ CLI (clawdis …) + ├─ CLI (clawdbot …) ├─ WebChat (browser) - ├─ macOS app (Clawdis.app) + ├─ macOS app (Clawdbot.app) └─ iOS node (Canvas + voice) ``` -## What Clawdis does +## What Clawdbot does - **Personal assistant** — one user, one identity, one memory surface. - **Multi-surface inbox** — WhatsApp, Telegram, Discord, iMessage, WebChat, macOS, iOS. Signal support via `signal-cli` (see `docs/signal.md`). iMessage uses `imsg` (see `docs/imessage.md`). @@ -51,7 +51,7 @@ Your surfaces - **Automation-ready** — browser control, media handling, and tool streaming. - **Local-first control plane** — the Gateway owns state, everything else connects. - **Group chats** — mention-based by default, `/activation always|mention` per group (owner-only). -- **Nix mode** — opt-in declarative config + read-only UI when `CLAWDIS_NIX_MODE=1`. +- **Nix mode** — opt-in declarative config + read-only UI when `CLAWDBOT_NIX_MODE=1`. ## How it works (short) @@ -70,25 +70,25 @@ pnpm build pnpm ui:build # Recommended: run the onboarding wizard -pnpm clawdis onboard +pnpm clawdbot onboard -# Link WhatsApp (stores creds in ~/.clawdis/credentials) -pnpm clawdis login +# Link WhatsApp (stores creds in ~/.clawdbot/credentials) +pnpm clawdbot login # Start the gateway -pnpm clawdis gateway --port 18789 --verbose +pnpm clawdbot gateway --port 18789 --verbose # Dev loop (auto-reload on TS changes) pnpm gateway:watch # Send a message -pnpm clawdis send --to +1234567890 --message "Hello from Clawdis" +pnpm clawdbot send --to +1234567890 --message "Hello from Clawdbot" # Talk to the assistant (optionally deliver back to WhatsApp/Telegram/Discord) -pnpm clawdis agent --message "Ship checklist" --thinking high +pnpm clawdbot agent --message "Ship checklist" --thinking high ``` -If you run from source, prefer `pnpm clawdis …` (not global `clawdis`). +If you run from source, prefer `pnpm clawdbot …` (not global `clawdbot`). ## Chat commands @@ -115,14 +115,14 @@ Send these in WhatsApp/Telegram/WebChat (group commands are owner-only): - **Discovery + pairing**: Bonjour discovery via `BridgeDiscoveryModel` (NWBrowser). `BridgeConnectionController` auto‑connects using Keychain token or allows manual host/port. - **Node runtime**: `BridgeSession` (actor) maintains the `NWConnection`, hello handshake, ping/pong, RPC requests, and `invoke` callbacks. - **Capabilities + commands**: advertises `canvas`, `screen`, `camera`, `voiceWake` (settings‑driven) and executes `canvas.*`, `canvas.a2ui.*`, `camera.*`, `screen.record` (`NodeAppModel.handleInvoke`). -- **Canvas**: `WKWebView` with bundled Canvas scaffold + A2UI, JS eval, snapshot capture, and `clawdis://` deep‑link interception (`ScreenController`). -- **Voice + deep links**: voice wake sends `voice.transcript` events; `clawdis://agent` links emit `agent.request`. Voice wake triggers sync via `voicewake.get` + `voicewake.changed`. +- **Canvas**: `WKWebView` with bundled Canvas scaffold + A2UI, JS eval, snapshot capture, and `clawdbot://` deep‑link interception (`ScreenController`). +- **Voice + deep links**: voice wake sends `voice.transcript` events; `clawdbot://agent` links emit `agent.request`. Voice wake triggers sync via `voicewake.get` + `voicewake.changed`. ## Companion apps The **macOS app is critical**: it runs the menu‑bar control plane, owns local permissions (TCC), hosts Voice Wake, exposes WebChat/debug tools, and coordinates local/remote gateway mode. Most “assistant” UX lives here. -### macOS (Clawdis.app) +### macOS (Clawdbot.app) - Menu bar control for the Gateway and health. - Voice Wake + push-to-talk overlay. @@ -135,7 +135,7 @@ Build/run: `./scripts/restart-mac.sh` (packages + launches). - Pairs as a node via the Bridge. - Voice trigger forwarding + Canvas surface. -- Controlled via `clawdis nodes …`. +- Controlled via `clawdbot nodes …`. Runbook: `docs/ios/connect.md`. @@ -153,7 +153,7 @@ Runbook: `docs/ios/connect.md`. ## Configuration -Minimal `~/.clawdis/clawdis.json`: +Minimal `~/.clawdbot/clawdbot.json`: ```json5 { @@ -165,7 +165,7 @@ Minimal `~/.clawdis/clawdis.json`: ### WhatsApp -- Link the device: `pnpm clawdis login` (stores creds in `~/.clawdis/credentials`). +- Link the device: `pnpm clawdbot login` (stores creds in `~/.clawdbot/credentials`). - Allowlist who can talk to the assistant via `whatsapp.allowFrom`. ### Telegram @@ -223,13 +223,13 @@ Browser control (optional): ## Email hooks (Gmail) ```bash -clawdis hooks gmail setup --account you@gmail.com -clawdis hooks gmail run +clawdbot hooks gmail setup --account you@gmail.com +clawdbot hooks gmail run ``` - [`docs/security.md`](docs/security.md) - [`docs/troubleshooting.md`](docs/troubleshooting.md) - [`docs/ios/connect.md`](docs/ios/connect.md) -- [`docs/clawdis-mac.md`](docs/clawdis-mac.md) +- [`docs/clawdbot-mac.md`](docs/clawdbot-mac.md) ## Contributing @@ -239,7 +239,7 @@ AI/vibe-coded PRs welcome! 🤖 ## Clawd -Clawdis was built for **Clawd**, a space lobster AI assistant. +Clawdbot was built for **Clawd**, a space lobster AI assistant. - https://clawd.me - https://soul.md diff --git a/appcast.xml b/appcast.xml index ed3682187..fb48cadb3 100644 --- a/appcast.xml +++ b/appcast.xml @@ -1,15 +1,15 @@ - Clawdis + Clawdbot 2.0.0-beta5 Sat, 03 Jan 2026 07:15:16 +0100 - https://raw.githubusercontent.com/steipete/clawdis/main/appcast.xml + https://raw.githubusercontent.com/clawdbot/clawdbot/main/appcast.xml 2765 2.0.0-beta5 15.0 - Clawdis 2.0.0-beta5 + Clawdbot 2.0.0-beta5

Fixed

  • Media: preserve GIF animation when uploading to Discord/other providers (skip JPEG optimization for image/gif).
  • @@ -30,8 +30,8 @@
  • Sessions: group keys now use surface:group: / surface:channel:; legacy group:* keys migrate on next message; groupdm keys are no longer recognized.
  • Discord: remove legacy discord.allowFrom, discord.guildAllowFrom, and discord.requireMention; use discord.dm + discord.guilds.
  • Providers: Discord/Telegram no longer auto-start from env tokens alone; add discord: { enabled: true } / telegram: { enabled: true } to your config when using DISCORD_BOT_TOKEN / TELEGRAM_BOT_TOKEN.
  • -
  • Config: remove routing.allowFrom; use whatsapp.allowFrom instead (run clawdis doctor to migrate).
  • -
  • Config: remove routing.groupChat.requireMention + telegram.requireMention; use whatsapp.groups, imessage.groups, and telegram.groups defaults instead (run clawdis doctor to migrate).
  • +
  • Config: remove routing.allowFrom; use whatsapp.allowFrom instead (run clawdbot doctor to migrate).
  • +
  • Config: remove routing.groupChat.requireMention + telegram.requireMention; use whatsapp.groups, imessage.groups, and telegram.groups defaults instead (run clawdbot doctor to migrate).

Features

    @@ -40,7 +40,7 @@
  • Talk mode: continuous speech conversations (macOS/iOS/Android) with ElevenLabs TTS, reply directives, and optional interrupt-on-speech.
  • Auto-reply: expand queue modes (steer/followup/collect/steer-backlog) with debounce/cap/drop options and followup backlog handling.
  • UI: add optional ui.seamColor accent to tint the Talk Mode side bubble (macOS/iOS/Android).
  • -
  • Nix mode: opt-in declarative config + read-only settings UI when CLAWDIS_NIX_MODE=1 (thanks @joshp123 for the persistence — earned my trust; I'll merge these going forward).
  • +
  • Nix mode: opt-in declarative config + read-only settings UI when CLAWDBOT_NIX_MODE=1 (thanks @joshp123 for the persistence — earned my trust; I'll merge these going forward).
  • CLI: add Google Antigravity OAuth auth option for Claude Opus 4.5/Gemini 3 (#88) — thanks @mukhtharcm.
  • Agent runtime: accept legacy Z_AI_API_KEY for Z.AI provider auth (maps to ZAI_API_KEY).
  • Groups: add per-group mention gating defaults/overrides for Telegram/WhatsApp/iMessage via *.groups with "*" defaults; Discord now supports discord.guilds."*" as a default.
  • @@ -50,7 +50,7 @@
  • iMessage: add imsg JSON-RPC integration (stdio), chat_id routing, and group chat support.
  • Chat UI: add recent-session dropdown switcher (main first) in macOS/iOS/Android + Control UI.
  • UI: add Discord/Signal/iMessage connection panels in macOS + Control UI (thanks @thewilloftheshadow).
  • -
  • Discord: allow agent-triggered reactions via clawdis_discord when enabled, and surface message ids in context.
  • +
  • Discord: allow agent-triggered reactions via clawdbot_discord when enabled, and surface message ids in context.
  • Discord: revamp guild routing config with per-guild/channel rules and slugged display names; add optional group DM support (default off).
  • Discord: remove legacy guild/channel ignore lists in favor of per-guild allowlists (and proposed per-guild ignore lists).
  • Skills: add Trello skill for board/list/card management (thanks @clawd).
  • @@ -62,7 +62,7 @@
  • CLI: add configure, doctor, and update wizards for ongoing setup, health checks, and modernization.
  • CLI: add Signal CLI auto-install from GitHub releases in the wizard and persist wizard run metadata in config.
  • CLI: add remote gateway client config (gateway.remote.*) with Bonjour-assisted discovery.
  • -
  • CLI: enhance clawdis tui with model/session pickers, tool cards, and slash commands (local or remote).
  • +
  • CLI: enhance clawdbot tui with model/session pickers, tool cards, and slash commands (local or remote).
  • Gateway: allow sessions.patch to set per-session model overrides (used by the TUI /model flow).
  • Skills: allow bun as a node manager for skill installs.
  • Skills: add things-mac (Things 3 CLI) for read/search plus add/update via URL scheme.
  • @@ -87,7 +87,7 @@
  • Chat UI: add extra top padding before the first message bubble in Web Chat (macOS/iOS/Android).
  • Control UI: refine Web Chat session selector styling (chevron spacing + background).
  • WebChat: stream live updates for sessions even when runs start outside the chat UI.
  • -
  • Gateway CLI: read CLAWDIS_GATEWAY_PASSWORD from environment in callGateway() — allows doctor/health commands to auth without explicit --password flag.
  • +
  • Gateway CLI: read CLAWDBOT_GATEWAY_PASSWORD from environment in callGateway() — allows doctor/health commands to auth without explicit --password flag.
  • Gateway: add password auth support for remote gateway connections (thanks @jeffersonwarrior).
  • Auto-reply: strip stray leading/trailing HEARTBEAT_OK from normal replies; drop short (≤ 30 chars) heartbeat acks.
  • WhatsApp auto-reply: default to self-only when no config is present.
  • @@ -137,7 +137,7 @@
  • Docs: clarify self-chat mode and group mention gating config (#111) — thanks @rafaelreis-r.
  • Browser tools: upload supports auto-click refs, direct inputRef/element file inputs, and emits input/change after setFiles so JS-heavy sites pick up attachments.
  • Browser tools: harden CDP readiness (HTTP + WS), retry CDP connects, and auto-restart the clawd browser when the socket handshake stalls.
  • -
  • Browser CLI: add clawdis browser reset-profile to move the clawd profile to Trash when it gets wedged.
  • +
  • Browser CLI: add clawdbot browser reset-profile to move the clawd profile to Trash when it gets wedged.
  • Signal: fix daemon startup race (wait for /api/v1/check) and normalize JSON-RPC version probe parsing.
  • Docs/Signal: clarify bot-number vs personal-account setup (self-chat loop protection) and add a quickstart config snippet.
  • Docs: refresh the CLI wizard guide and highlight onboarding in the README.
  • @@ -201,12 +201,12 @@
  • macOS menu: top status line now shows pending node pairing approvals (incl. repairs).
  • CLI: avoid spurious gateway close errors after successful request/response cycles.
  • Agent runtime: clamp tool-result images to the 5MB Anthropic limit to avoid hard request rejections.
  • -
  • Agent runtime: write v2 session headers so Pi session branching stays in the Clawdis sessions dir.
  • +
  • Agent runtime: write v2 session headers so Pi session branching stays in the Clawdbot sessions dir.
  • Tests: add Swift Testing coverage for camera errors and Kotest coverage for Android bridge endpoints.
-

View full changelog

+

View full changelog

]]>
- +
\ No newline at end of file diff --git a/apps/android/README.md b/apps/android/README.md index c015ff84c..02908b82d 100644 --- a/apps/android/README.md +++ b/apps/android/README.md @@ -1,6 +1,6 @@ -## Clawdis Node (Android) (internal) +## Clawdbot Node (Android) (internal) -Modern Android node app: connects to the **Gateway-owned bridge** (`_clawdis-bridge._tcp`) over TCP and exposes **Canvas + Chat + Camera**. +Modern Android node app: connects to the **Gateway-owned bridge** (`_clawdbot-bridge._tcp`) over TCP and exposes **Canvas + Chat + Camera**. Notes: - The node keeps the connection alive via a **foreground service** (persistent notification with a Disconnect action). @@ -25,7 +25,7 @@ cd apps/android 1) Start the gateway (on your “master” machine): ```bash -pnpm clawdis gateway --port 18789 --verbose +pnpm clawdbot gateway --port 18789 --verbose ``` 2) In the Android app: @@ -34,8 +34,8 @@ pnpm clawdis gateway --port 18789 --verbose 3) Approve pairing (on the gateway machine): ```bash -clawdis nodes pending -clawdis nodes approve +clawdbot nodes pending +clawdbot nodes approve ``` More details: `docs/android/connect.md`. diff --git a/apps/android/app/build.gradle.kts b/apps/android/app/build.gradle.kts index 1c7dbaa51..f244b2dd8 100644 --- a/apps/android/app/build.gradle.kts +++ b/apps/android/app/build.gradle.kts @@ -6,17 +6,17 @@ plugins { } android { - namespace = "com.clawdis.android" + namespace = "com.clawdbot.android" compileSdk = 36 sourceSets { getByName("main") { - assets.srcDir(file("../../shared/ClawdisKit/Sources/ClawdisKit/Resources")) + assets.srcDir(file("../../shared/ClawdbotKit/Sources/ClawdbotKit/Resources")) } } defaultConfig { - applicationId = "com.clawdis.android" + applicationId = "com.clawdbot.android" minSdk = 31 targetSdk = 36 versionCode = 1 diff --git a/apps/android/app/src/main/AndroidManifest.xml b/apps/android/app/src/main/AndroidManifest.xml index a14b8c079..df2aa94b3 100644 --- a/apps/android/app/src/main/AndroidManifest.xml +++ b/apps/android/app/src/main/AndroidManifest.xml @@ -32,7 +32,7 @@ android:label="@string/app_name" android:supportsRtl="true" android:networkSecurityConfig="@xml/network_security_config" - android:theme="@style/Theme.ClawdisNode"> + android:theme="@style/Theme.ClawdbotNode"> Quint(status, server, connected, voiceMode, voiceListening) }.collect { (status, server, connected, voiceMode, voiceListening) -> - val title = if (connected) "Clawdis Node · Connected" else "Clawdis Node" + val title = if (connected) "Clawdbot Node · Connected" else "Clawdbot Node" val voiceSuffix = if (voiceMode == VoiceWakeMode.Always) { if (voiceListening) " · Voice Wake: Listening" else " · Voice Wake: Paused" @@ -91,7 +91,7 @@ class NodeForegroundService : Service() { "Connection", NotificationManager.IMPORTANCE_LOW, ).apply { - description = "Clawdis node connection status" + description = "Clawdbot node connection status" setShowBadge(false) } mgr.createNotificationChannel(channel) @@ -146,7 +146,7 @@ class NodeForegroundService : Service() { private const val CHANNEL_ID = "connection" private const val NOTIFICATION_ID = 1 - private const val ACTION_STOP = "com.clawdis.android.action.STOP" + private const val ACTION_STOP = "com.clawdbot.android.action.STOP" fun start(context: Context) { val intent = Intent(context, NodeForegroundService::class.java) diff --git a/apps/android/app/src/main/java/com/clawdis/android/NodeRuntime.kt b/apps/android/app/src/main/java/com/clawdbot/android/NodeRuntime.kt similarity index 89% rename from apps/android/app/src/main/java/com/clawdis/android/NodeRuntime.kt rename to apps/android/app/src/main/java/com/clawdbot/android/NodeRuntime.kt index 203bf75b3..14d1c27fe 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/NodeRuntime.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/NodeRuntime.kt @@ -1,4 +1,4 @@ -package com.clawdis.android +package com.clawdbot.android import android.Manifest import android.content.Context @@ -7,31 +7,31 @@ import android.location.LocationManager import android.os.Build import android.os.SystemClock import androidx.core.content.ContextCompat -import com.clawdis.android.chat.ChatController -import com.clawdis.android.chat.ChatMessage -import com.clawdis.android.chat.ChatPendingToolCall -import com.clawdis.android.chat.ChatSessionEntry -import com.clawdis.android.chat.OutgoingAttachment -import com.clawdis.android.bridge.BridgeDiscovery -import com.clawdis.android.bridge.BridgeEndpoint -import com.clawdis.android.bridge.BridgePairingClient -import com.clawdis.android.bridge.BridgeSession -import com.clawdis.android.node.CameraCaptureManager -import com.clawdis.android.node.LocationCaptureManager -import com.clawdis.android.BuildConfig -import com.clawdis.android.node.CanvasController -import com.clawdis.android.node.ScreenRecordManager -import com.clawdis.android.node.SmsManager -import com.clawdis.android.protocol.ClawdisCapability -import com.clawdis.android.protocol.ClawdisCameraCommand -import com.clawdis.android.protocol.ClawdisCanvasA2UIAction -import com.clawdis.android.protocol.ClawdisCanvasA2UICommand -import com.clawdis.android.protocol.ClawdisCanvasCommand -import com.clawdis.android.protocol.ClawdisScreenCommand -import com.clawdis.android.protocol.ClawdisLocationCommand -import com.clawdis.android.protocol.ClawdisSmsCommand -import com.clawdis.android.voice.TalkModeManager -import com.clawdis.android.voice.VoiceWakeManager +import com.clawdbot.android.chat.ChatController +import com.clawdbot.android.chat.ChatMessage +import com.clawdbot.android.chat.ChatPendingToolCall +import com.clawdbot.android.chat.ChatSessionEntry +import com.clawdbot.android.chat.OutgoingAttachment +import com.clawdbot.android.bridge.BridgeDiscovery +import com.clawdbot.android.bridge.BridgeEndpoint +import com.clawdbot.android.bridge.BridgePairingClient +import com.clawdbot.android.bridge.BridgeSession +import com.clawdbot.android.node.CameraCaptureManager +import com.clawdbot.android.node.LocationCaptureManager +import com.clawdbot.android.BuildConfig +import com.clawdbot.android.node.CanvasController +import com.clawdbot.android.node.ScreenRecordManager +import com.clawdbot.android.node.SmsManager +import com.clawdbot.android.protocol.ClawdbotCapability +import com.clawdbot.android.protocol.ClawdbotCameraCommand +import com.clawdbot.android.protocol.ClawdbotCanvasA2UIAction +import com.clawdbot.android.protocol.ClawdbotCanvasA2UICommand +import com.clawdbot.android.protocol.ClawdbotCanvasCommand +import com.clawdbot.android.protocol.ClawdbotScreenCommand +import com.clawdbot.android.protocol.ClawdbotLocationCommand +import com.clawdbot.android.protocol.ClawdbotSmsCommand +import com.clawdbot.android.voice.TalkModeManager +import com.clawdbot.android.voice.VoiceWakeManager import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -369,38 +369,38 @@ class NodeRuntime(context: Context) { private fun buildInvokeCommands(): List = buildList { - add(ClawdisCanvasCommand.Present.rawValue) - add(ClawdisCanvasCommand.Hide.rawValue) - add(ClawdisCanvasCommand.Navigate.rawValue) - add(ClawdisCanvasCommand.Eval.rawValue) - add(ClawdisCanvasCommand.Snapshot.rawValue) - add(ClawdisCanvasA2UICommand.Push.rawValue) - add(ClawdisCanvasA2UICommand.PushJSONL.rawValue) - add(ClawdisCanvasA2UICommand.Reset.rawValue) - add(ClawdisScreenCommand.Record.rawValue) + add(ClawdbotCanvasCommand.Present.rawValue) + add(ClawdbotCanvasCommand.Hide.rawValue) + add(ClawdbotCanvasCommand.Navigate.rawValue) + add(ClawdbotCanvasCommand.Eval.rawValue) + add(ClawdbotCanvasCommand.Snapshot.rawValue) + add(ClawdbotCanvasA2UICommand.Push.rawValue) + add(ClawdbotCanvasA2UICommand.PushJSONL.rawValue) + add(ClawdbotCanvasA2UICommand.Reset.rawValue) + add(ClawdbotScreenCommand.Record.rawValue) if (cameraEnabled.value) { - add(ClawdisCameraCommand.Snap.rawValue) - add(ClawdisCameraCommand.Clip.rawValue) + add(ClawdbotCameraCommand.Snap.rawValue) + add(ClawdbotCameraCommand.Clip.rawValue) } if (locationMode.value != LocationMode.Off) { - add(ClawdisLocationCommand.Get.rawValue) + add(ClawdbotLocationCommand.Get.rawValue) } if (sms.canSendSms()) { - add(ClawdisSmsCommand.Send.rawValue) + add(ClawdbotSmsCommand.Send.rawValue) } } private fun buildCapabilities(): List = buildList { - add(ClawdisCapability.Canvas.rawValue) - add(ClawdisCapability.Screen.rawValue) - if (cameraEnabled.value) add(ClawdisCapability.Camera.rawValue) - if (sms.canSendSms()) add(ClawdisCapability.Sms.rawValue) + add(ClawdbotCapability.Canvas.rawValue) + add(ClawdbotCapability.Screen.rawValue) + if (cameraEnabled.value) add(ClawdbotCapability.Camera.rawValue) + if (sms.canSendSms()) add(ClawdbotCapability.Sms.rawValue) if (voiceWakeMode.value != VoiceWakeMode.Off && hasRecordAudioPermission()) { - add(ClawdisCapability.VoiceWake.rawValue) + add(ClawdbotCapability.VoiceWake.rawValue) } if (locationMode.value != LocationMode.Off) { - add(ClawdisCapability.Location.rawValue) + add(ClawdbotCapability.Location.rawValue) } } @@ -552,7 +552,7 @@ class NodeRuntime(context: Context) { val actionId = (userActionObj["id"] as? JsonPrimitive)?.content?.trim().orEmpty().ifEmpty { java.util.UUID.randomUUID().toString() } - val name = ClawdisCanvasA2UIAction.extractActionName(userActionObj) ?: return@launch + val name = ClawdbotCanvasA2UIAction.extractActionName(userActionObj) ?: return@launch val surfaceId = (userActionObj["surfaceId"] as? JsonPrimitive)?.content?.trim().orEmpty().ifEmpty { "main" } @@ -562,7 +562,7 @@ class NodeRuntime(context: Context) { val sessionKey = "main" val message = - ClawdisCanvasA2UIAction.formatAgentMessage( + ClawdbotCanvasA2UIAction.formatAgentMessage( actionName = name, sessionKey = sessionKey, surfaceId = surfaceId, @@ -596,7 +596,7 @@ class NodeRuntime(context: Context) { try { canvas.eval( - ClawdisCanvasA2UIAction.jsDispatchA2UIActionStatus( + ClawdbotCanvasA2UIAction.jsDispatchA2UIActionStatus( actionId = actionId, ok = connected && error == null, error = error, @@ -713,10 +713,10 @@ class NodeRuntime(context: Context) { private suspend fun handleInvoke(command: String, paramsJson: String?): BridgeSession.InvokeResult { if ( - command.startsWith(ClawdisCanvasCommand.NamespacePrefix) || - command.startsWith(ClawdisCanvasA2UICommand.NamespacePrefix) || - command.startsWith(ClawdisCameraCommand.NamespacePrefix) || - command.startsWith(ClawdisScreenCommand.NamespacePrefix) + command.startsWith(ClawdbotCanvasCommand.NamespacePrefix) || + command.startsWith(ClawdbotCanvasA2UICommand.NamespacePrefix) || + command.startsWith(ClawdbotCameraCommand.NamespacePrefix) || + command.startsWith(ClawdbotScreenCommand.NamespacePrefix) ) { if (!isForeground.value) { return BridgeSession.InvokeResult.error( @@ -725,13 +725,13 @@ class NodeRuntime(context: Context) { ) } } - if (command.startsWith(ClawdisCameraCommand.NamespacePrefix) && !cameraEnabled.value) { + if (command.startsWith(ClawdbotCameraCommand.NamespacePrefix) && !cameraEnabled.value) { return BridgeSession.InvokeResult.error( code = "CAMERA_DISABLED", message = "CAMERA_DISABLED: enable Camera in Settings", ) } - if (command.startsWith(ClawdisLocationCommand.NamespacePrefix) && + if (command.startsWith(ClawdbotLocationCommand.NamespacePrefix) && locationMode.value == LocationMode.Off ) { return BridgeSession.InvokeResult.error( @@ -741,18 +741,18 @@ class NodeRuntime(context: Context) { } return when (command) { - ClawdisCanvasCommand.Present.rawValue -> { + ClawdbotCanvasCommand.Present.rawValue -> { val url = CanvasController.parseNavigateUrl(paramsJson) canvas.navigate(url) BridgeSession.InvokeResult.ok(null) } - ClawdisCanvasCommand.Hide.rawValue -> BridgeSession.InvokeResult.ok(null) - ClawdisCanvasCommand.Navigate.rawValue -> { + ClawdbotCanvasCommand.Hide.rawValue -> BridgeSession.InvokeResult.ok(null) + ClawdbotCanvasCommand.Navigate.rawValue -> { val url = CanvasController.parseNavigateUrl(paramsJson) canvas.navigate(url) BridgeSession.InvokeResult.ok(null) } - ClawdisCanvasCommand.Eval.rawValue -> { + ClawdbotCanvasCommand.Eval.rawValue -> { val js = CanvasController.parseEvalJs(paramsJson) ?: return BridgeSession.InvokeResult.error( @@ -770,7 +770,7 @@ class NodeRuntime(context: Context) { } BridgeSession.InvokeResult.ok("""{"result":${result.toJsonString()}}""") } - ClawdisCanvasCommand.Snapshot.rawValue -> { + ClawdbotCanvasCommand.Snapshot.rawValue -> { val snapshotParams = CanvasController.parseSnapshotParams(paramsJson) val base64 = try { @@ -787,7 +787,7 @@ class NodeRuntime(context: Context) { } BridgeSession.InvokeResult.ok("""{"format":"${snapshotParams.format.rawValue}","base64":"$base64"}""") } - ClawdisCanvasA2UICommand.Reset.rawValue -> { + ClawdbotCanvasA2UICommand.Reset.rawValue -> { val a2uiUrl = resolveA2uiHostUrl() ?: return BridgeSession.InvokeResult.error( code = "A2UI_HOST_NOT_CONFIGURED", @@ -803,7 +803,7 @@ class NodeRuntime(context: Context) { val res = canvas.eval(a2uiResetJS) BridgeSession.InvokeResult.ok(res) } - ClawdisCanvasA2UICommand.Push.rawValue, ClawdisCanvasA2UICommand.PushJSONL.rawValue -> { + ClawdbotCanvasA2UICommand.Push.rawValue, ClawdbotCanvasA2UICommand.PushJSONL.rawValue -> { val messages = try { decodeA2uiMessages(command, paramsJson) @@ -826,7 +826,7 @@ class NodeRuntime(context: Context) { val res = canvas.eval(js) BridgeSession.InvokeResult.ok(res) } - ClawdisCameraCommand.Snap.rawValue -> { + ClawdbotCameraCommand.Snap.rawValue -> { showCameraHud(message = "Taking photo…", kind = CameraHudKind.Photo) triggerCameraFlash() val res = @@ -840,7 +840,7 @@ class NodeRuntime(context: Context) { showCameraHud(message = "Photo captured", kind = CameraHudKind.Success, autoHideMs = 1600) BridgeSession.InvokeResult.ok(res.payloadJson) } - ClawdisCameraCommand.Clip.rawValue -> { + ClawdbotCameraCommand.Clip.rawValue -> { val includeAudio = paramsJson?.contains("\"includeAudio\":true") != false if (includeAudio) externalAudioCaptureActive.value = true try { @@ -859,7 +859,7 @@ class NodeRuntime(context: Context) { if (includeAudio) externalAudioCaptureActive.value = false } } - ClawdisLocationCommand.Get.rawValue -> { + ClawdbotLocationCommand.Get.rawValue -> { val mode = locationMode.value if (!isForeground.value && mode != LocationMode.Always) { return BridgeSession.InvokeResult.error( @@ -912,7 +912,7 @@ class NodeRuntime(context: Context) { BridgeSession.InvokeResult.error(code = "LOCATION_UNAVAILABLE", message = message) } } - ClawdisScreenCommand.Record.rawValue -> { + ClawdbotScreenCommand.Record.rawValue -> { // Status pill mirrors screen recording state so it stays visible without overlay stacking. _screenRecordActive.value = true try { @@ -928,7 +928,7 @@ class NodeRuntime(context: Context) { _screenRecordActive.value = false } } - ClawdisSmsCommand.Send.rawValue -> { + ClawdbotSmsCommand.Send.rawValue -> { val res = sms.send(paramsJson) if (res.ok) { BridgeSession.InvokeResult.ok(res.payloadJson) @@ -999,7 +999,7 @@ class NodeRuntime(context: Context) { val raw = session.currentCanvasHostUrl()?.trim().orEmpty() if (raw.isBlank()) return null val base = raw.trimEnd('/') - return "${base}/__clawdis__/a2ui/?platform=android" + return "${base}/__clawdbot__/a2ui/?platform=android" } private suspend fun ensureA2uiReady(a2uiUrl: String): Boolean { @@ -1034,7 +1034,7 @@ class NodeRuntime(context: Context) { val jsonlField = (obj["jsonl"] as? JsonPrimitive)?.content?.trim().orEmpty() val hasMessagesArray = obj["messages"] is JsonArray - if (command == ClawdisCanvasA2UICommand.PushJSONL.rawValue || (!hasMessagesArray && jsonlField.isNotBlank())) { + if (command == ClawdbotCanvasA2UICommand.PushJSONL.rawValue || (!hasMessagesArray && jsonlField.isNotBlank())) { val jsonl = jsonlField if (jsonl.isBlank()) throw IllegalArgumentException("INVALID_REQUEST: jsonl required") val messages = @@ -1091,7 +1091,7 @@ private const val a2uiReadyCheckJS: String = """ (() => { try { - return !!globalThis.clawdisA2UI && typeof globalThis.clawdisA2UI.applyMessages === 'function'; + return !!globalThis.clawdbotA2UI && typeof globalThis.clawdbotA2UI.applyMessages === 'function'; } catch (_) { return false; } @@ -1102,8 +1102,8 @@ private const val a2uiResetJS: String = """ (() => { try { - if (!globalThis.clawdisA2UI) return { ok: false, error: "missing clawdisA2UI" }; - return globalThis.clawdisA2UI.reset(); + if (!globalThis.clawdbotA2UI) return { ok: false, error: "missing clawdbotA2UI" }; + return globalThis.clawdbotA2UI.reset(); } catch (e) { return { ok: false, error: String(e?.message ?? e) }; } @@ -1114,9 +1114,9 @@ private fun a2uiApplyMessagesJS(messagesJson: String): String { return """ (() => { try { - if (!globalThis.clawdisA2UI) return { ok: false, error: "missing clawdisA2UI" }; + if (!globalThis.clawdbotA2UI) return { ok: false, error: "missing clawdbotA2UI" }; const messages = $messagesJson; - return globalThis.clawdisA2UI.applyMessages(messages); + return globalThis.clawdbotA2UI.applyMessages(messages); } catch (e) { return { ok: false, error: String(e?.message ?? e) }; } diff --git a/apps/android/app/src/main/java/com/clawdis/android/PermissionRequester.kt b/apps/android/app/src/main/java/com/clawdbot/android/PermissionRequester.kt similarity index 97% rename from apps/android/app/src/main/java/com/clawdis/android/PermissionRequester.kt rename to apps/android/app/src/main/java/com/clawdbot/android/PermissionRequester.kt index 290fb4982..fa294aa24 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/PermissionRequester.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/PermissionRequester.kt @@ -1,4 +1,4 @@ -package com.clawdis.android +package com.clawdbot.android import android.content.pm.PackageManager import android.content.Intent @@ -115,7 +115,7 @@ class PermissionRequester(private val activity: ComponentActivity) { private fun buildRationaleMessage(permissions: List): String { val labels = permissions.map { permissionLabel(it) } - return "Clawdis needs ${labels.joinToString(", ")} permissions to continue." + return "Clawdbot needs ${labels.joinToString(", ")} permissions to continue." } private fun buildSettingsMessage(permissions: List): String { diff --git a/apps/android/app/src/main/java/com/clawdis/android/ScreenCaptureRequester.kt b/apps/android/app/src/main/java/com/clawdbot/android/ScreenCaptureRequester.kt similarity index 95% rename from apps/android/app/src/main/java/com/clawdis/android/ScreenCaptureRequester.kt rename to apps/android/app/src/main/java/com/clawdbot/android/ScreenCaptureRequester.kt index 3cf730100..d270d5273 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/ScreenCaptureRequester.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/ScreenCaptureRequester.kt @@ -1,4 +1,4 @@ -package com.clawdis.android +package com.clawdbot.android import android.app.Activity import android.content.Context @@ -55,7 +55,7 @@ class ScreenCaptureRequester(private val activity: ComponentActivity) { suspendCancellableCoroutine { cont -> AlertDialog.Builder(activity) .setTitle("Screen recording required") - .setMessage("Clawdis needs to record the screen for this command.") + .setMessage("Clawdbot needs to record the screen for this command.") .setPositiveButton("Continue") { _, _ -> cont.resume(true) } .setNegativeButton("Not now") { _, _ -> cont.resume(false) } .setOnCancelListener { cont.resume(false) } diff --git a/apps/android/app/src/main/java/com/clawdis/android/SecurePrefs.kt b/apps/android/app/src/main/java/com/clawdbot/android/SecurePrefs.kt similarity index 99% rename from apps/android/app/src/main/java/com/clawdis/android/SecurePrefs.kt rename to apps/android/app/src/main/java/com/clawdbot/android/SecurePrefs.kt index ef2ccf004..1b1c955fd 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/SecurePrefs.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/SecurePrefs.kt @@ -1,6 +1,6 @@ @file:Suppress("DEPRECATION") -package com.clawdis.android +package com.clawdbot.android import android.content.Context import androidx.core.content.edit @@ -31,7 +31,7 @@ class SecurePrefs(context: Context) { private val prefs = EncryptedSharedPreferences.create( context, - "clawdis.node.secure", + "clawdbot.node.secure", masterKey, EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM, diff --git a/apps/android/app/src/main/java/com/clawdis/android/VoiceWakeMode.kt b/apps/android/app/src/main/java/com/clawdbot/android/VoiceWakeMode.kt similarity index 91% rename from apps/android/app/src/main/java/com/clawdis/android/VoiceWakeMode.kt rename to apps/android/app/src/main/java/com/clawdbot/android/VoiceWakeMode.kt index 1236c3621..e8a6eff15 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/VoiceWakeMode.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/VoiceWakeMode.kt @@ -1,4 +1,4 @@ -package com.clawdis.android +package com.clawdbot.android enum class VoiceWakeMode(val rawValue: String) { Off("off"), diff --git a/apps/android/app/src/main/java/com/clawdis/android/WakeWords.kt b/apps/android/app/src/main/java/com/clawdbot/android/WakeWords.kt similarity index 94% rename from apps/android/app/src/main/java/com/clawdis/android/WakeWords.kt rename to apps/android/app/src/main/java/com/clawdbot/android/WakeWords.kt index 2a4864ad1..855a0de7c 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/WakeWords.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/WakeWords.kt @@ -1,4 +1,4 @@ -package com.clawdis.android +package com.clawdbot.android object WakeWords { const val maxWords: Int = 32 diff --git a/apps/android/app/src/main/java/com/clawdis/android/bridge/BonjourEscapes.kt b/apps/android/app/src/main/java/com/clawdbot/android/bridge/BonjourEscapes.kt similarity index 96% rename from apps/android/app/src/main/java/com/clawdis/android/bridge/BonjourEscapes.kt rename to apps/android/app/src/main/java/com/clawdbot/android/bridge/BonjourEscapes.kt index 8659ee8ba..9334572fd 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/bridge/BonjourEscapes.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/bridge/BonjourEscapes.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.bridge +package com.clawdbot.android.bridge object BonjourEscapes { fun decode(input: String): String { diff --git a/apps/android/app/src/main/java/com/clawdis/android/bridge/BridgeDiscovery.kt b/apps/android/app/src/main/java/com/clawdbot/android/bridge/BridgeDiscovery.kt similarity index 98% rename from apps/android/app/src/main/java/com/clawdis/android/bridge/BridgeDiscovery.kt rename to apps/android/app/src/main/java/com/clawdbot/android/bridge/BridgeDiscovery.kt index 18c877909..287f069cd 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/bridge/BridgeDiscovery.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/bridge/BridgeDiscovery.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.bridge +package com.clawdbot.android.bridge import android.content.Context import android.net.ConnectivityManager @@ -51,9 +51,9 @@ class BridgeDiscovery( private val nsd = context.getSystemService(NsdManager::class.java) private val connectivity = context.getSystemService(ConnectivityManager::class.java) private val dns = DnsResolver.getInstance() - private val serviceType = "_clawdis-bridge._tcp." - private val wideAreaDomain = "clawdis.internal." - private val logTag = "Clawdis/BridgeDiscovery" + private val serviceType = "_clawdbot-bridge._tcp." + private val wideAreaDomain = "clawdbot.internal." + private val logTag = "Clawdbot/BridgeDiscovery" private val localById = ConcurrentHashMap() private val unicastById = ConcurrentHashMap() diff --git a/apps/android/app/src/main/java/com/clawdis/android/bridge/BridgeEndpoint.kt b/apps/android/app/src/main/java/com/clawdbot/android/bridge/BridgeEndpoint.kt similarity index 93% rename from apps/android/app/src/main/java/com/clawdis/android/bridge/BridgeEndpoint.kt rename to apps/android/app/src/main/java/com/clawdbot/android/bridge/BridgeEndpoint.kt index b7a39efbe..0f90730ba 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/bridge/BridgeEndpoint.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/bridge/BridgeEndpoint.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.bridge +package com.clawdbot.android.bridge data class BridgeEndpoint( val stableId: String, diff --git a/apps/android/app/src/main/java/com/clawdis/android/bridge/BridgePairingClient.kt b/apps/android/app/src/main/java/com/clawdbot/android/bridge/BridgePairingClient.kt similarity index 99% rename from apps/android/app/src/main/java/com/clawdis/android/bridge/BridgePairingClient.kt rename to apps/android/app/src/main/java/com/clawdbot/android/bridge/BridgePairingClient.kt index 6b2c79201..e57faea9e 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/bridge/BridgePairingClient.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/bridge/BridgePairingClient.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.bridge +package com.clawdbot.android.bridge import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/apps/android/app/src/main/java/com/clawdis/android/bridge/BridgeSession.kt b/apps/android/app/src/main/java/com/clawdbot/android/bridge/BridgeSession.kt similarity index 99% rename from apps/android/app/src/main/java/com/clawdis/android/bridge/BridgeSession.kt rename to apps/android/app/src/main/java/com/clawdbot/android/bridge/BridgeSession.kt index 0325a98e3..c9633db3a 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/bridge/BridgeSession.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/bridge/BridgeSession.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.bridge +package com.clawdbot.android.bridge import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CoroutineScope @@ -11,7 +11,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext -import com.clawdis.android.BuildConfig +import com.clawdbot.android.BuildConfig import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonObject @@ -217,7 +217,7 @@ class BridgeSession( // Local JVM unit tests use android.jar stubs; Log.d can throw "not mocked". runCatching { android.util.Log.d( - "ClawdisBridge", + "ClawdbotBridge", "canvasHostUrl resolved=${canvasHostUrl ?: "none"} (raw=${rawCanvasUrl ?: "none"})", ) } diff --git a/apps/android/app/src/main/java/com/clawdis/android/chat/ChatController.kt b/apps/android/app/src/main/java/com/clawdbot/android/chat/ChatController.kt similarity index 99% rename from apps/android/app/src/main/java/com/clawdis/android/chat/ChatController.kt rename to apps/android/app/src/main/java/com/clawdbot/android/chat/ChatController.kt index 921c6e7b3..01041b08d 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/chat/ChatController.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/chat/ChatController.kt @@ -1,6 +1,6 @@ -package com.clawdis.android.chat +package com.clawdbot.android.chat -import com.clawdis.android.bridge.BridgeSession +import com.clawdbot.android.bridge.BridgeSession import java.util.UUID import java.util.concurrent.ConcurrentHashMap import kotlinx.coroutines.CoroutineScope diff --git a/apps/android/app/src/main/java/com/clawdis/android/chat/ChatModels.kt b/apps/android/app/src/main/java/com/clawdbot/android/chat/ChatModels.kt similarity index 96% rename from apps/android/app/src/main/java/com/clawdis/android/chat/ChatModels.kt rename to apps/android/app/src/main/java/com/clawdbot/android/chat/ChatModels.kt index 7f0af0cea..ad84e8c69 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/chat/ChatModels.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/chat/ChatModels.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.chat +package com.clawdbot.android.chat data class ChatMessage( val id: String, diff --git a/apps/android/app/src/main/java/com/clawdis/android/node/CameraCaptureManager.kt b/apps/android/app/src/main/java/com/clawdbot/android/node/CameraCaptureManager.kt similarity index 98% rename from apps/android/app/src/main/java/com/clawdis/android/node/CameraCaptureManager.kt rename to apps/android/app/src/main/java/com/clawdbot/android/node/CameraCaptureManager.kt index f2c32d856..514524491 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/node/CameraCaptureManager.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/node/CameraCaptureManager.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.node +package com.clawdbot.android.node import android.Manifest import android.content.Context @@ -20,7 +20,7 @@ import androidx.camera.video.VideoRecordEvent import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat.checkSelfPermission import androidx.core.graphics.scale -import com.clawdis.android.PermissionRequester +import com.clawdbot.android.PermissionRequester import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withTimeout @@ -152,7 +152,7 @@ class CameraCaptureManager(private val context: Context) { provider.unbindAll() provider.bindToLifecycle(owner, selector, videoCapture) - val file = File.createTempFile("clawdis-clip-", ".mp4") + val file = File.createTempFile("clawdbot-clip-", ".mp4") val outputOptions = FileOutputOptions.Builder(file).build() val finalized = kotlinx.coroutines.CompletableDeferred() @@ -256,7 +256,7 @@ private suspend fun Context.cameraProvider(): ProcessCameraProvider = private suspend fun ImageCapture.takeJpegBytes(executor: Executor): ByteArray = suspendCancellableCoroutine { cont -> - val file = File.createTempFile("clawdis-snap-", ".jpg") + val file = File.createTempFile("clawdbot-snap-", ".jpg") val options = ImageCapture.OutputFileOptions.Builder(file).build() takePicture( options, diff --git a/apps/android/app/src/main/java/com/clawdis/android/node/CanvasController.kt b/apps/android/app/src/main/java/com/clawdbot/android/node/CanvasController.kt similarity index 97% rename from apps/android/app/src/main/java/com/clawdis/android/node/CanvasController.kt rename to apps/android/app/src/main/java/com/clawdbot/android/node/CanvasController.kt index 78fca4e4d..c7c7a76e1 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/node/CanvasController.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/node/CanvasController.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.node +package com.clawdbot.android.node import android.graphics.Bitmap import android.graphics.Canvas @@ -17,7 +17,7 @@ import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive -import com.clawdis.android.BuildConfig +import com.clawdbot.android.BuildConfig import kotlin.coroutines.resume class CanvasController { @@ -84,12 +84,12 @@ class CanvasController { withWebViewOnMain { wv -> if (currentUrl == null) { if (BuildConfig.DEBUG) { - Log.d("ClawdisCanvas", "load scaffold: $scaffoldAssetUrl") + Log.d("ClawdbotCanvas", "load scaffold: $scaffoldAssetUrl") } wv.loadUrl(scaffoldAssetUrl) } else { if (BuildConfig.DEBUG) { - Log.d("ClawdisCanvas", "load url: $currentUrl") + Log.d("ClawdbotCanvas", "load url: $currentUrl") } wv.loadUrl(currentUrl) } @@ -106,7 +106,7 @@ class CanvasController { val js = """ (() => { try { - const api = globalThis.__clawdis; + const api = globalThis.__clawdbot; if (!api) return; if (typeof api.setDebugStatusEnabled === 'function') { api.setDebugStatusEnabled(${if (enabled) "true" else "false"}); diff --git a/apps/android/app/src/main/java/com/clawdis/android/node/JpegSizeLimiter.kt b/apps/android/app/src/main/java/com/clawdbot/android/node/JpegSizeLimiter.kt similarity index 98% rename from apps/android/app/src/main/java/com/clawdis/android/node/JpegSizeLimiter.kt rename to apps/android/app/src/main/java/com/clawdbot/android/node/JpegSizeLimiter.kt index 6790ad70a..ec71e9a4b 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/node/JpegSizeLimiter.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/node/JpegSizeLimiter.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.node +package com.clawdbot.android.node import kotlin.math.max import kotlin.math.min diff --git a/apps/android/app/src/main/java/com/clawdis/android/node/LocationCaptureManager.kt b/apps/android/app/src/main/java/com/clawdbot/android/node/LocationCaptureManager.kt similarity index 99% rename from apps/android/app/src/main/java/com/clawdis/android/node/LocationCaptureManager.kt rename to apps/android/app/src/main/java/com/clawdbot/android/node/LocationCaptureManager.kt index ace3bdc03..dab8593e7 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/node/LocationCaptureManager.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/node/LocationCaptureManager.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.node +package com.clawdbot.android.node import android.annotation.SuppressLint import android.content.Context diff --git a/apps/android/app/src/main/java/com/clawdis/android/node/ScreenRecordManager.kt b/apps/android/app/src/main/java/com/clawdbot/android/node/ScreenRecordManager.kt similarity index 94% rename from apps/android/app/src/main/java/com/clawdis/android/node/ScreenRecordManager.kt rename to apps/android/app/src/main/java/com/clawdbot/android/node/ScreenRecordManager.kt index 78d0bb584..ade6da02c 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/node/ScreenRecordManager.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/node/ScreenRecordManager.kt @@ -1,11 +1,11 @@ -package com.clawdis.android.node +package com.clawdbot.android.node import android.content.Context import android.hardware.display.DisplayManager import android.media.MediaRecorder import android.media.projection.MediaProjectionManager import android.util.Base64 -import com.clawdis.android.ScreenCaptureRequester +import com.clawdbot.android.ScreenCaptureRequester import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.withContext @@ -16,13 +16,13 @@ class ScreenRecordManager(private val context: Context) { data class Payload(val payloadJson: String) @Volatile private var screenCaptureRequester: ScreenCaptureRequester? = null - @Volatile private var permissionRequester: com.clawdis.android.PermissionRequester? = null + @Volatile private var permissionRequester: com.clawdbot.android.PermissionRequester? = null fun attachScreenCaptureRequester(requester: ScreenCaptureRequester) { screenCaptureRequester = requester } - fun attachPermissionRequester(requester: com.clawdis.android.PermissionRequester) { + fun attachPermissionRequester(requester: com.clawdbot.android.PermissionRequester) { permissionRequester = requester } @@ -62,7 +62,7 @@ class ScreenRecordManager(private val context: Context) { val height = metrics.heightPixels val densityDpi = metrics.densityDpi - val file = File.createTempFile("clawdis-screen-", ".mp4") + val file = File.createTempFile("clawdbot-screen-", ".mp4") if (includeAudio) ensureMicPermission() val recorder = MediaRecorder() @@ -89,7 +89,7 @@ class ScreenRecordManager(private val context: Context) { val surface = recorder.surface virtualDisplay = projection.createVirtualDisplay( - "clawdis-screen", + "clawdbot-screen", width, height, densityDpi, diff --git a/apps/android/app/src/main/java/com/clawdis/android/node/SmsManager.kt b/apps/android/app/src/main/java/com/clawdbot/android/node/SmsManager.kt similarity index 98% rename from apps/android/app/src/main/java/com/clawdis/android/node/SmsManager.kt rename to apps/android/app/src/main/java/com/clawdbot/android/node/SmsManager.kt index 353e49dc3..e449993d2 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/node/SmsManager.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/node/SmsManager.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.node +package com.clawdbot.android.node import android.Manifest import android.content.Context @@ -11,7 +11,7 @@ import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.jsonObject import kotlinx.serialization.encodeToString -import com.clawdis.android.PermissionRequester +import com.clawdbot.android.PermissionRequester /** * Sends SMS messages via the Android SMS API. diff --git a/apps/android/app/src/main/java/com/clawdis/android/protocol/ClawdisCanvasA2UIAction.kt b/apps/android/app/src/main/java/com/clawdbot/android/protocol/ClawdbotCanvasA2UIAction.kt similarity index 89% rename from apps/android/app/src/main/java/com/clawdis/android/protocol/ClawdisCanvasA2UIAction.kt rename to apps/android/app/src/main/java/com/clawdbot/android/protocol/ClawdbotCanvasA2UIAction.kt index d5f8683ea..a6d6ee136 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/protocol/ClawdisCanvasA2UIAction.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/protocol/ClawdbotCanvasA2UIAction.kt @@ -1,9 +1,9 @@ -package com.clawdis.android.protocol +package com.clawdbot.android.protocol import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive -object ClawdisCanvasA2UIAction { +object ClawdbotCanvasA2UIAction { fun extractActionName(userAction: JsonObject): String? { val name = (userAction["name"] as? JsonPrimitive) @@ -61,6 +61,6 @@ object ClawdisCanvasA2UIAction { val err = (error ?: "").replace("\\", "\\\\").replace("\"", "\\\"") val okLiteral = if (ok) "true" else "false" val idEscaped = actionId.replace("\\", "\\\\").replace("\"", "\\\"") - return "window.dispatchEvent(new CustomEvent('clawdis:a2ui-action-status', { detail: { id: \"${idEscaped}\", ok: ${okLiteral}, error: \"${err}\" } }));" + return "window.dispatchEvent(new CustomEvent('clawdbot:a2ui-action-status', { detail: { id: \"${idEscaped}\", ok: ${okLiteral}, error: \"${err}\" } }));" } } diff --git a/apps/android/app/src/main/java/com/clawdis/android/protocol/ClawdisProtocolConstants.kt b/apps/android/app/src/main/java/com/clawdbot/android/protocol/ClawdbotProtocolConstants.kt similarity index 69% rename from apps/android/app/src/main/java/com/clawdis/android/protocol/ClawdisProtocolConstants.kt rename to apps/android/app/src/main/java/com/clawdbot/android/protocol/ClawdbotProtocolConstants.kt index d63d50c25..bfdb5f782 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/protocol/ClawdisProtocolConstants.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/protocol/ClawdbotProtocolConstants.kt @@ -1,6 +1,6 @@ -package com.clawdis.android.protocol +package com.clawdbot.android.protocol -enum class ClawdisCapability(val rawValue: String) { +enum class ClawdbotCapability(val rawValue: String) { Canvas("canvas"), Camera("camera"), Screen("screen"), @@ -9,7 +9,7 @@ enum class ClawdisCapability(val rawValue: String) { Location("location"), } -enum class ClawdisCanvasCommand(val rawValue: String) { +enum class ClawdbotCanvasCommand(val rawValue: String) { Present("canvas.present"), Hide("canvas.hide"), Navigate("canvas.navigate"), @@ -22,7 +22,7 @@ enum class ClawdisCanvasCommand(val rawValue: String) { } } -enum class ClawdisCanvasA2UICommand(val rawValue: String) { +enum class ClawdbotCanvasA2UICommand(val rawValue: String) { Push("canvas.a2ui.push"), PushJSONL("canvas.a2ui.pushJSONL"), Reset("canvas.a2ui.reset"), @@ -33,7 +33,7 @@ enum class ClawdisCanvasA2UICommand(val rawValue: String) { } } -enum class ClawdisCameraCommand(val rawValue: String) { +enum class ClawdbotCameraCommand(val rawValue: String) { Snap("camera.snap"), Clip("camera.clip"), ; @@ -43,7 +43,7 @@ enum class ClawdisCameraCommand(val rawValue: String) { } } -enum class ClawdisScreenCommand(val rawValue: String) { +enum class ClawdbotScreenCommand(val rawValue: String) { Record("screen.record"), ; @@ -52,7 +52,7 @@ enum class ClawdisScreenCommand(val rawValue: String) { } } -enum class ClawdisSmsCommand(val rawValue: String) { +enum class ClawdbotSmsCommand(val rawValue: String) { Send("sms.send"), ; @@ -61,7 +61,7 @@ enum class ClawdisSmsCommand(val rawValue: String) { } } -enum class ClawdisLocationCommand(val rawValue: String) { +enum class ClawdbotLocationCommand(val rawValue: String) { Get("location.get"), ; diff --git a/apps/android/app/src/main/java/com/clawdis/android/tools/ToolDisplay.kt b/apps/android/app/src/main/java/com/clawdbot/android/tools/ToolDisplay.kt similarity index 99% rename from apps/android/app/src/main/java/com/clawdis/android/tools/ToolDisplay.kt rename to apps/android/app/src/main/java/com/clawdbot/android/tools/ToolDisplay.kt index ca0f7b83c..aed5d0b4b 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/tools/ToolDisplay.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/tools/ToolDisplay.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.tools +package com.clawdbot.android.tools import android.content.Context import kotlinx.serialization.Serializable diff --git a/apps/android/app/src/main/java/com/clawdis/android/ui/CameraHudOverlay.kt b/apps/android/app/src/main/java/com/clawdbot/android/ui/CameraHudOverlay.kt similarity index 97% rename from apps/android/app/src/main/java/com/clawdis/android/ui/CameraHudOverlay.kt rename to apps/android/app/src/main/java/com/clawdbot/android/ui/CameraHudOverlay.kt index 0e135eaeb..2143ba7f8 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/ui/CameraHudOverlay.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/ui/CameraHudOverlay.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.ui +package com.clawdbot.android.ui import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box diff --git a/apps/android/app/src/main/java/com/clawdis/android/ui/ChatSheet.kt b/apps/android/app/src/main/java/com/clawdbot/android/ui/ChatSheet.kt similarity index 52% rename from apps/android/app/src/main/java/com/clawdis/android/ui/ChatSheet.kt rename to apps/android/app/src/main/java/com/clawdbot/android/ui/ChatSheet.kt index 8813e62d7..6f15e5922 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/ui/ChatSheet.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/ui/ChatSheet.kt @@ -1,8 +1,8 @@ -package com.clawdis.android.ui +package com.clawdbot.android.ui import androidx.compose.runtime.Composable -import com.clawdis.android.MainViewModel -import com.clawdis.android.ui.chat.ChatSheetContent +import com.clawdbot.android.MainViewModel +import com.clawdbot.android.ui.chat.ChatSheetContent @Composable fun ChatSheet(viewModel: MainViewModel) { diff --git a/apps/android/app/src/main/java/com/clawdis/android/ui/ClawdisTheme.kt b/apps/android/app/src/main/java/com/clawdbot/android/ui/ClawdbotTheme.kt similarity index 92% rename from apps/android/app/src/main/java/com/clawdis/android/ui/ClawdisTheme.kt rename to apps/android/app/src/main/java/com/clawdbot/android/ui/ClawdbotTheme.kt index 3f319b49a..0eea8da39 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/ui/ClawdisTheme.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/ui/ClawdbotTheme.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.ui +package com.clawdbot.android.ui import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material3.MaterialTheme @@ -9,7 +9,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext @Composable -fun ClawdisTheme(content: @Composable () -> Unit) { +fun ClawdbotTheme(content: @Composable () -> Unit) { val context = LocalContext.current val isDark = isSystemInDarkTheme() val colorScheme = if (isDark) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) diff --git a/apps/android/app/src/main/java/com/clawdis/android/ui/RootScreen.kt b/apps/android/app/src/main/java/com/clawdbot/android/ui/RootScreen.kt similarity index 96% rename from apps/android/app/src/main/java/com/clawdis/android/ui/RootScreen.kt rename to apps/android/app/src/main/java/com/clawdbot/android/ui/RootScreen.kt index 55056a713..1ea73c98a 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/ui/RootScreen.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/ui/RootScreen.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.ui +package com.clawdbot.android.ui import android.annotation.SuppressLint import android.Manifest @@ -65,8 +65,8 @@ import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.window.Popup import androidx.compose.ui.window.PopupProperties import androidx.core.content.ContextCompat -import com.clawdis.android.CameraHudKind -import com.clawdis.android.MainViewModel +import com.clawdbot.android.CameraHudKind +import com.clawdbot.android.MainViewModel @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -334,7 +334,7 @@ private fun CanvasView(viewModel: MainViewModel, modifier: Modifier = Modifier) WebSettingsCompat.setAlgorithmicDarkeningAllowed(settings, false) } if (isDebuggable) { - Log.d("ClawdisWebView", "userAgent: ${settings.userAgentString}") + Log.d("ClawdbotWebView", "userAgent: ${settings.userAgentString}") } isScrollContainer = true overScrollMode = View.OVER_SCROLL_IF_CONTENT_SCROLLS @@ -349,7 +349,7 @@ private fun CanvasView(viewModel: MainViewModel, modifier: Modifier = Modifier) ) { if (!isDebuggable) return if (!request.isForMainFrame) return - Log.e("ClawdisWebView", "onReceivedError: ${error.errorCode} ${error.description} ${request.url}") + Log.e("ClawdbotWebView", "onReceivedError: ${error.errorCode} ${error.description} ${request.url}") } override fun onReceivedHttpError( @@ -360,14 +360,14 @@ private fun CanvasView(viewModel: MainViewModel, modifier: Modifier = Modifier) if (!isDebuggable) return if (!request.isForMainFrame) return Log.e( - "ClawdisWebView", + "ClawdbotWebView", "onReceivedHttpError: ${errorResponse.statusCode} ${errorResponse.reasonPhrase} ${request.url}", ) } override fun onPageFinished(view: WebView, url: String?) { if (isDebuggable) { - Log.d("ClawdisWebView", "onPageFinished: $url") + Log.d("ClawdbotWebView", "onPageFinished: $url") } viewModel.canvas.onPageFinished() } @@ -378,7 +378,7 @@ private fun CanvasView(viewModel: MainViewModel, modifier: Modifier = Modifier) ): Boolean { if (isDebuggable) { Log.e( - "ClawdisWebView", + "ClawdbotWebView", "onRenderProcessGone didCrash=${detail.didCrash()} priorityAtExit=${detail.rendererPriorityAtExit()}", ) } @@ -391,7 +391,7 @@ private fun CanvasView(viewModel: MainViewModel, modifier: Modifier = Modifier) if (!isDebuggable) return false val msg = consoleMessage ?: return false Log.d( - "ClawdisWebView", + "ClawdbotWebView", "console ${msg.messageLevel()} @ ${msg.sourceId()}:${msg.lineNumber()} ${msg.message()}", ) return false @@ -423,7 +423,7 @@ private class CanvasA2UIActionBridge(private val onMessage: (String) -> Unit) { } companion object { - const val interfaceName: String = "clawdisCanvasA2UIAction" + const val interfaceName: String = "clawdbotCanvasA2UIAction" } } diff --git a/apps/android/app/src/main/java/com/clawdis/android/ui/SettingsSheet.kt b/apps/android/app/src/main/java/com/clawdbot/android/ui/SettingsSheet.kt similarity index 98% rename from apps/android/app/src/main/java/com/clawdis/android/ui/SettingsSheet.kt rename to apps/android/app/src/main/java/com/clawdbot/android/ui/SettingsSheet.kt index 330c6c983..21eb72daa 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/ui/SettingsSheet.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/ui/SettingsSheet.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.ui +package com.clawdbot.android.ui import android.Manifest import android.content.Context @@ -52,11 +52,11 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.core.content.ContextCompat -import com.clawdis.android.BuildConfig -import com.clawdis.android.LocationMode -import com.clawdis.android.MainViewModel -import com.clawdis.android.NodeForegroundService -import com.clawdis.android.VoiceWakeMode +import com.clawdbot.android.BuildConfig +import com.clawdbot.android.LocationMode +import com.clawdbot.android.MainViewModel +import com.clawdbot.android.NodeForegroundService +import com.clawdbot.android.VoiceWakeMode @Composable fun SettingsSheet(viewModel: MainViewModel) { @@ -436,7 +436,7 @@ fun SettingsSheet(viewModel: MainViewModel) { Column(verticalArrangement = Arrangement.spacedBy(6.dp), modifier = Modifier.fillMaxWidth()) { ListItem( headlineContent = { Text("Foreground Only") }, - supportingContent = { Text("Listens only while Clawdis is open.") }, + supportingContent = { Text("Listens only while Clawdbot is open.") }, trailingContent = { RadioButton( selected = voiceWakeMode == VoiceWakeMode.Foreground, @@ -482,7 +482,7 @@ fun SettingsSheet(viewModel: MainViewModel) { Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) { Button( onClick = { - val parsed = com.clawdis.android.WakeWords.parseCommaSeparated(wakeWordsText) + val parsed = com.clawdbot.android.WakeWords.parseCommaSeparated(wakeWordsText) viewModel.setWakeWords(parsed) }, enabled = isConnected, @@ -580,7 +580,7 @@ fun SettingsSheet(viewModel: MainViewModel) { ) ListItem( headlineContent = { Text("While Using") }, - supportingContent = { Text("Only while Clawdis is open.") }, + supportingContent = { Text("Only while Clawdbot is open.") }, trailingContent = { RadioButton( selected = locationMode == LocationMode.WhileUsing, @@ -627,7 +627,7 @@ fun SettingsSheet(viewModel: MainViewModel) { item { ListItem( headlineContent = { Text("Prevent Sleep") }, - supportingContent = { Text("Keeps the screen awake while Clawdis is open.") }, + supportingContent = { Text("Keeps the screen awake while Clawdbot is open.") }, trailingContent = { Switch(checked = preventSleep, onCheckedChange = viewModel::setPreventSleep) }, ) } diff --git a/apps/android/app/src/main/java/com/clawdis/android/ui/StatusPill.kt b/apps/android/app/src/main/java/com/clawdbot/android/ui/StatusPill.kt similarity index 99% rename from apps/android/app/src/main/java/com/clawdis/android/ui/StatusPill.kt rename to apps/android/app/src/main/java/com/clawdbot/android/ui/StatusPill.kt index ae5e3894e..db88a97f8 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/ui/StatusPill.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/ui/StatusPill.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.ui +package com.clawdbot.android.ui import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row diff --git a/apps/android/app/src/main/java/com/clawdis/android/ui/TalkOrbOverlay.kt b/apps/android/app/src/main/java/com/clawdbot/android/ui/TalkOrbOverlay.kt similarity index 99% rename from apps/android/app/src/main/java/com/clawdis/android/ui/TalkOrbOverlay.kt rename to apps/android/app/src/main/java/com/clawdbot/android/ui/TalkOrbOverlay.kt index 908809bed..32225b486 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/ui/TalkOrbOverlay.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/ui/TalkOrbOverlay.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.ui +package com.clawdbot.android.ui import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.RepeatMode diff --git a/apps/android/app/src/main/java/com/clawdis/android/ui/chat/ChatComposer.kt b/apps/android/app/src/main/java/com/clawdbot/android/ui/chat/ChatComposer.kt similarity index 99% rename from apps/android/app/src/main/java/com/clawdis/android/ui/chat/ChatComposer.kt rename to apps/android/app/src/main/java/com/clawdbot/android/ui/chat/ChatComposer.kt index 8459d3b26..ab23a4980 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/ui/chat/ChatComposer.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/ui/chat/ChatComposer.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.ui.chat +package com.clawdbot.android.ui.chat import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -38,7 +38,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp -import com.clawdis.android.chat.ChatSessionEntry +import com.clawdbot.android.chat.ChatSessionEntry @Composable fun ChatComposer( diff --git a/apps/android/app/src/main/java/com/clawdis/android/ui/chat/ChatMarkdown.kt b/apps/android/app/src/main/java/com/clawdbot/android/ui/chat/ChatMarkdown.kt similarity index 99% rename from apps/android/app/src/main/java/com/clawdis/android/ui/chat/ChatMarkdown.kt rename to apps/android/app/src/main/java/com/clawdbot/android/ui/chat/ChatMarkdown.kt index 217577013..f15673fb3 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/ui/chat/ChatMarkdown.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/ui/chat/ChatMarkdown.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.ui.chat +package com.clawdbot.android.ui.chat import android.graphics.BitmapFactory import android.util.Base64 diff --git a/apps/android/app/src/main/java/com/clawdis/android/ui/chat/ChatMessageListCard.kt b/apps/android/app/src/main/java/com/clawdbot/android/ui/chat/ChatMessageListCard.kt similarity index 96% rename from apps/android/app/src/main/java/com/clawdis/android/ui/chat/ChatMessageListCard.kt rename to apps/android/app/src/main/java/com/clawdbot/android/ui/chat/ChatMessageListCard.kt index 5950ce0a5..a3229d4a2 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/ui/chat/ChatMessageListCard.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/ui/chat/ChatMessageListCard.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.ui.chat +package com.clawdbot.android.ui.chat import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -20,8 +20,8 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.unit.dp -import com.clawdis.android.chat.ChatMessage -import com.clawdis.android.chat.ChatPendingToolCall +import com.clawdbot.android.chat.ChatMessage +import com.clawdbot.android.chat.ChatPendingToolCall @Composable fun ChatMessageListCard( diff --git a/apps/android/app/src/main/java/com/clawdis/android/ui/chat/ChatMessageViews.kt b/apps/android/app/src/main/java/com/clawdbot/android/ui/chat/ChatMessageViews.kt similarity index 97% rename from apps/android/app/src/main/java/com/clawdis/android/ui/chat/ChatMessageViews.kt rename to apps/android/app/src/main/java/com/clawdbot/android/ui/chat/ChatMessageViews.kt index 9f93e9cd0..59479744e 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/ui/chat/ChatMessageViews.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/ui/chat/ChatMessageViews.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.ui.chat +package com.clawdbot.android.ui.chat import android.graphics.BitmapFactory import android.util.Base64 @@ -31,10 +31,10 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp import androidx.compose.foundation.Image -import com.clawdis.android.chat.ChatMessage -import com.clawdis.android.chat.ChatMessageContent -import com.clawdis.android.chat.ChatPendingToolCall -import com.clawdis.android.tools.ToolDisplayRegistry +import com.clawdbot.android.chat.ChatMessage +import com.clawdbot.android.chat.ChatMessageContent +import com.clawdbot.android.chat.ChatPendingToolCall +import com.clawdbot.android.tools.ToolDisplayRegistry import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import androidx.compose.ui.platform.LocalContext diff --git a/apps/android/app/src/main/java/com/clawdis/android/ui/chat/ChatSessionsDialog.kt b/apps/android/app/src/main/java/com/clawdbot/android/ui/chat/ChatSessionsDialog.kt similarity index 97% rename from apps/android/app/src/main/java/com/clawdis/android/ui/chat/ChatSessionsDialog.kt rename to apps/android/app/src/main/java/com/clawdbot/android/ui/chat/ChatSessionsDialog.kt index 69f065cb0..9474b2362 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/ui/chat/ChatSessionsDialog.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/ui/chat/ChatSessionsDialog.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.ui.chat +package com.clawdbot.android.ui.chat import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -20,7 +20,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import com.clawdis.android.chat.ChatSessionEntry +import com.clawdbot.android.chat.ChatSessionEntry @Composable fun ChatSessionsDialog( diff --git a/apps/android/app/src/main/java/com/clawdis/android/ui/chat/ChatSheetContent.kt b/apps/android/app/src/main/java/com/clawdbot/android/ui/chat/ChatSheetContent.kt similarity index 97% rename from apps/android/app/src/main/java/com/clawdis/android/ui/chat/ChatSheetContent.kt rename to apps/android/app/src/main/java/com/clawdbot/android/ui/chat/ChatSheetContent.kt index ec42abca5..6b791d130 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/ui/chat/ChatSheetContent.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/ui/chat/ChatSheetContent.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.ui.chat +package com.clawdbot.android.ui.chat import android.content.ContentResolver import android.net.Uri @@ -19,8 +19,8 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp -import com.clawdis.android.MainViewModel -import com.clawdis.android.chat.OutgoingAttachment +import com.clawdbot.android.MainViewModel +import com.clawdbot.android.chat.OutgoingAttachment import java.io.ByteArrayOutputStream import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch diff --git a/apps/android/app/src/main/java/com/clawdis/android/ui/chat/SessionFilters.kt b/apps/android/app/src/main/java/com/clawdbot/android/ui/chat/SessionFilters.kt similarity index 93% rename from apps/android/app/src/main/java/com/clawdis/android/ui/chat/SessionFilters.kt rename to apps/android/app/src/main/java/com/clawdbot/android/ui/chat/SessionFilters.kt index df04b7913..8ba2b8c84 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/ui/chat/SessionFilters.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/ui/chat/SessionFilters.kt @@ -1,6 +1,6 @@ -package com.clawdis.android.ui.chat +package com.clawdbot.android.ui.chat -import com.clawdis.android.chat.ChatSessionEntry +import com.clawdbot.android.chat.ChatSessionEntry private const val MAIN_SESSION_KEY = "main" private const val RECENT_WINDOW_MS = 24 * 60 * 60 * 1000L diff --git a/apps/android/app/src/main/java/com/clawdis/android/voice/StreamingMediaDataSource.kt b/apps/android/app/src/main/java/com/clawdbot/android/voice/StreamingMediaDataSource.kt similarity index 98% rename from apps/android/app/src/main/java/com/clawdis/android/voice/StreamingMediaDataSource.kt rename to apps/android/app/src/main/java/com/clawdbot/android/voice/StreamingMediaDataSource.kt index 4bd84138a..6b1536ad5 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/voice/StreamingMediaDataSource.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/voice/StreamingMediaDataSource.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.voice +package com.clawdbot.android.voice import android.media.MediaDataSource import kotlin.math.min diff --git a/apps/android/app/src/main/java/com/clawdis/android/voice/TalkDirectiveParser.kt b/apps/android/app/src/main/java/com/clawdbot/android/voice/TalkDirectiveParser.kt similarity index 99% rename from apps/android/app/src/main/java/com/clawdis/android/voice/TalkDirectiveParser.kt rename to apps/android/app/src/main/java/com/clawdbot/android/voice/TalkDirectiveParser.kt index a7c3c25e3..02d2c3967 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/voice/TalkDirectiveParser.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/voice/TalkDirectiveParser.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.voice +package com.clawdbot.android.voice import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement diff --git a/apps/android/app/src/main/java/com/clawdis/android/voice/TalkModeManager.kt b/apps/android/app/src/main/java/com/clawdbot/android/voice/TalkModeManager.kt similarity index 99% rename from apps/android/app/src/main/java/com/clawdis/android/voice/TalkModeManager.kt rename to apps/android/app/src/main/java/com/clawdbot/android/voice/TalkModeManager.kt index f56663bea..198c6af9c 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/voice/TalkModeManager.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/voice/TalkModeManager.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.voice +package com.clawdbot.android.voice import android.Manifest import android.content.Context @@ -20,7 +20,7 @@ import android.speech.tts.TextToSpeech import android.speech.tts.UtteranceProgressListener import android.util.Log import androidx.core.content.ContextCompat -import com.clawdis.android.bridge.BridgeSession +import com.clawdbot.android.bridge.BridgeSession import java.net.HttpURLConnection import java.net.URL import java.util.UUID diff --git a/apps/android/app/src/main/java/com/clawdis/android/voice/VoiceWakeCommandExtractor.kt b/apps/android/app/src/main/java/com/clawdbot/android/voice/VoiceWakeCommandExtractor.kt similarity index 97% rename from apps/android/app/src/main/java/com/clawdis/android/voice/VoiceWakeCommandExtractor.kt rename to apps/android/app/src/main/java/com/clawdbot/android/voice/VoiceWakeCommandExtractor.kt index 71019f3e7..1f527b8c8 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/voice/VoiceWakeCommandExtractor.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/voice/VoiceWakeCommandExtractor.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.voice +package com.clawdbot.android.voice object VoiceWakeCommandExtractor { fun extractCommand(text: String, triggerWords: List): String? { diff --git a/apps/android/app/src/main/java/com/clawdis/android/voice/VoiceWakeManager.kt b/apps/android/app/src/main/java/com/clawdbot/android/voice/VoiceWakeManager.kt similarity index 99% rename from apps/android/app/src/main/java/com/clawdis/android/voice/VoiceWakeManager.kt rename to apps/android/app/src/main/java/com/clawdbot/android/voice/VoiceWakeManager.kt index 4d69b35d8..69863b4cc 100644 --- a/apps/android/app/src/main/java/com/clawdis/android/voice/VoiceWakeManager.kt +++ b/apps/android/app/src/main/java/com/clawdbot/android/voice/VoiceWakeManager.kt @@ -1,4 +1,4 @@ -package com.clawdis.android.voice +package com.clawdbot.android.voice import android.content.Context import android.content.Intent diff --git a/apps/android/app/src/main/res/values/strings.xml b/apps/android/app/src/main/res/values/strings.xml index 4299a7813..5e4d8a77d 100644 --- a/apps/android/app/src/main/res/values/strings.xml +++ b/apps/android/app/src/main/res/values/strings.xml @@ -1,4 +1,4 @@ - Clawdis Node + Clawdbot Node diff --git a/apps/android/app/src/main/res/values/themes.xml b/apps/android/app/src/main/res/values/themes.xml index 881dbe537..fe7c9b17f 100644 --- a/apps/android/app/src/main/res/values/themes.xml +++ b/apps/android/app/src/main/res/values/themes.xml @@ -1,5 +1,5 @@ - - -
+ +
-
Ready
-
Waiting for agent
+
Ready
+
Waiting for agent
`; - if (html.includes("__CLAWDIS_CONTROL_UI_BASE_PATH__")) return html; + if (html.includes("__CLAWDBOT_CONTROL_UI_BASE_PATH__")) return html; const headClose = html.indexOf(""); if (headClose !== -1) { return `${html.slice(0, headClose)}${script}${html.slice(headClose)}`; diff --git a/src/gateway/hooks-mapping.test.ts b/src/gateway/hooks-mapping.test.ts index dc8045d82..fd2d9a598 100644 --- a/src/gateway/hooks-mapping.test.ts +++ b/src/gateway/hooks-mapping.test.ts @@ -39,7 +39,7 @@ describe("hooks mapping", () => { }); it("runs transform module", async () => { - const dir = fs.mkdtempSync(path.join(os.tmpdir(), "clawdis-hooks-")); + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "clawdbot-hooks-")); const modPath = path.join(dir, "transform.mjs"); const placeholder = "${" + "payload.name}"; fs.writeFileSync( @@ -75,7 +75,7 @@ describe("hooks mapping", () => { }); it("treats null transform as a handled skip", async () => { - const dir = fs.mkdtempSync(path.join(os.tmpdir(), "clawdis-hooks-skip-")); + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "clawdbot-hooks-skip-")); const modPath = path.join(dir, "transform.mjs"); fs.writeFileSync(modPath, "export default () => null;"); diff --git a/src/gateway/hooks-mapping.ts b/src/gateway/hooks-mapping.ts index 64ea10d98..1146828b5 100644 --- a/src/gateway/hooks-mapping.ts +++ b/src/gateway/hooks-mapping.ts @@ -2,7 +2,7 @@ import path from "node:path"; import { pathToFileURL } from "node:url"; import { - CONFIG_PATH_CLAWDIS, + CONFIG_PATH_CLAWDBOT, type HookMappingConfig, type HooksConfig, } from "../config/config.js"; @@ -130,7 +130,7 @@ export function resolveHookMappings( } if (mappings.length === 0) return []; - const configDir = path.dirname(CONFIG_PATH_CLAWDIS); + const configDir = path.dirname(CONFIG_PATH_CLAWDBOT); const transformsDir = hooks?.transformsDir ? resolvePath(configDir, hooks.transformsDir) : configDir; diff --git a/src/gateway/hooks.test.ts b/src/gateway/hooks.test.ts index bc7c4fda5..1537c5ba5 100644 --- a/src/gateway/hooks.test.ts +++ b/src/gateway/hooks.test.ts @@ -1,6 +1,6 @@ import type { IncomingMessage } from "node:http"; import { describe, expect, test } from "vitest"; -import type { ClawdisConfig } from "../config/config.js"; +import type { ClawdbotConfig } from "../config/config.js"; import { extractHookToken, normalizeAgentPayload, @@ -16,7 +16,7 @@ describe("gateway hooks helpers", () => { token: "secret", path: "hooks///", }, - } as ClawdisConfig; + } as ClawdbotConfig; const resolved = resolveHooksConfig(base); expect(resolved?.basePath).toBe("/hooks"); expect(resolved?.token).toBe("secret"); @@ -25,7 +25,7 @@ describe("gateway hooks helpers", () => { test("resolveHooksConfig rejects root path", () => { const cfg = { hooks: { enabled: true, token: "x", path: "/" }, - } as ClawdisConfig; + } as ClawdbotConfig; expect(() => resolveHooksConfig(cfg)).toThrow("hooks.path may not be '/'"); }); @@ -33,14 +33,14 @@ describe("gateway hooks helpers", () => { const req = { headers: { authorization: "Bearer top", - "x-clawdis-token": "header", + "x-clawdbot-token": "header", }, } as unknown as IncomingMessage; const url = new URL("http://localhost/hooks/wake?token=query"); expect(extractHookToken(req, url)).toBe("top"); const req2 = { - headers: { "x-clawdis-token": "header" }, + headers: { "x-clawdbot-token": "header" }, } as unknown as IncomingMessage; expect(extractHookToken(req2, url)).toBe("header"); diff --git a/src/gateway/hooks.ts b/src/gateway/hooks.ts index ef32d5d26..160695ee3 100644 --- a/src/gateway/hooks.ts +++ b/src/gateway/hooks.ts @@ -1,6 +1,6 @@ import { randomUUID } from "node:crypto"; import type { IncomingMessage } from "node:http"; -import type { ClawdisConfig } from "../config/config.js"; +import type { ClawdbotConfig } from "../config/config.js"; import { type HookMappingResolved, resolveHookMappings, @@ -17,7 +17,7 @@ export type HooksConfigResolved = { }; export function resolveHooksConfig( - cfg: ClawdisConfig, + cfg: ClawdbotConfig, ): HooksConfigResolved | null { if (cfg.hooks?.enabled !== true) return null; const token = cfg.hooks?.token?.trim(); @@ -57,8 +57,8 @@ export function extractHookToken( if (token) return token; } const headerToken = - typeof req.headers["x-clawdis-token"] === "string" - ? req.headers["x-clawdis-token"].trim() + typeof req.headers["x-clawdbot-token"] === "string" + ? req.headers["x-clawdbot-token"].trim() : ""; if (headerToken) return headerToken; const queryToken = url.searchParams.get("token"); diff --git a/src/gateway/server-bridge.ts b/src/gateway/server-bridge.ts index b8c261013..5dcbf34a7 100644 --- a/src/gateway/server-bridge.ts +++ b/src/gateway/server-bridge.ts @@ -26,7 +26,7 @@ import type { CliDeps } from "../cli/deps.js"; import { agentCommand } from "../commands/agent.js"; import type { HealthSummary } from "../commands/health.js"; import { - CONFIG_PATH_CLAWDIS, + CONFIG_PATH_CLAWDBOT, loadConfig, parseConfigJson5, readConfigFileSnapshot, @@ -249,7 +249,7 @@ export function createBridgeHandlers(ctx: BridgeHandlersContext) { ok: true, payloadJSON: JSON.stringify({ ok: true, - path: CONFIG_PATH_CLAWDIS, + path: CONFIG_PATH_CLAWDBOT, config: validated.config, }), }; diff --git a/src/gateway/server-browser.ts b/src/gateway/server-browser.ts index 89ae834be..d7316bc76 100644 --- a/src/gateway/server-browser.ts +++ b/src/gateway/server-browser.ts @@ -3,10 +3,10 @@ export type BrowserControlServer = { }; export async function startBrowserControlServerIfEnabled(): Promise { - if (process.env.CLAWDIS_SKIP_BROWSER_CONTROL_SERVER === "1") return null; + if (process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER === "1") return null; // Lazy import: keeps startup fast, but still bundles for the embedded // gateway (bun --compile) via the static specifier path. - const override = process.env.CLAWDIS_BROWSER_CONTROL_MODULE?.trim(); + const override = process.env.CLAWDBOT_BROWSER_CONTROL_MODULE?.trim(); const mod = override ? await import(override) : await import("../browser/server.js"); diff --git a/src/gateway/server-discovery.ts b/src/gateway/server-discovery.ts index 7418736db..c6f252b58 100644 --- a/src/gateway/server-discovery.ts +++ b/src/gateway/server-discovery.ts @@ -13,16 +13,16 @@ export type ResolveBonjourCliPathOptions = { export function formatBonjourInstanceName(displayName: string) { const trimmed = displayName.trim(); - if (!trimmed) return "Clawdis"; - if (/clawdis/i.test(trimmed)) return trimmed; - return `${trimmed} (Clawdis)`; + if (!trimmed) return "Clawdbot"; + if (/clawdbot/i.test(trimmed)) return trimmed; + return `${trimmed} (Clawdbot)`; } export function resolveBonjourCliPath( opts: ResolveBonjourCliPathOptions = {}, ): string | undefined { const env = opts.env ?? process.env; - const envPath = env.CLAWDIS_CLI_PATH?.trim(); + const envPath = env.CLAWDBOT_CLI_PATH?.trim(); if (envPath) return envPath; const statSync = opts.statSync ?? fs.statSync; @@ -36,7 +36,7 @@ export function resolveBonjourCliPath( const execPath = opts.execPath ?? process.execPath; const execDir = path.dirname(execPath); - const siblingCli = path.join(execDir, "clawdis"); + const siblingCli = path.join(execDir, "clawdbot"); if (isFile(siblingCli)) return siblingCli; const argv = opts.argv ?? process.argv; @@ -49,7 +49,7 @@ export function resolveBonjourCliPath( const cwd = opts.cwd ?? process.cwd(); const distCli = path.join(cwd, "dist", "index.js"); if (isFile(distCli)) return distCli; - const binCli = path.join(cwd, "bin", "clawdis.js"); + const binCli = path.join(cwd, "bin", "clawdbot.js"); if (isFile(binCli)) return binCli; return undefined; @@ -60,7 +60,7 @@ export async function resolveTailnetDnsHint(opts?: { exec?: typeof runExec; }): Promise { const env = opts?.env ?? process.env; - const envRaw = env.CLAWDIS_TAILNET_DNS?.trim(); + const envRaw = env.CLAWDBOT_TAILNET_DNS?.trim(); const envValue = envRaw && envRaw.length > 0 ? envRaw.replace(/\.$/, "") : ""; if (envValue) return envValue; diff --git a/src/gateway/server-methods/config.ts b/src/gateway/server-methods/config.ts index 0faec9ceb..59dd90548 100644 --- a/src/gateway/server-methods/config.ts +++ b/src/gateway/server-methods/config.ts @@ -1,5 +1,5 @@ import { - CONFIG_PATH_CLAWDIS, + CONFIG_PATH_CLAWDBOT, parseConfigJson5, readConfigFileSnapshot, validateConfigObject, @@ -96,7 +96,7 @@ export const configHandlers: GatewayRequestHandlers = { true, { ok: true, - path: CONFIG_PATH_CLAWDIS, + path: CONFIG_PATH_CLAWDBOT, config: validated.config, }, undefined, diff --git a/src/gateway/server-methods/providers.ts b/src/gateway/server-methods/providers.ts index a7cd52cfc..6b794f749 100644 --- a/src/gateway/server-methods/providers.ts +++ b/src/gateway/server-methods/providers.ts @@ -1,4 +1,4 @@ -import type { ClawdisConfig } from "../../config/config.js"; +import type { ClawdbotConfig } from "../../config/config.js"; import { loadConfig, readConfigFileSnapshot, @@ -250,7 +250,7 @@ export const providersHandlers: GatewayRequestHandlers = { if (nextTelegram) { delete nextTelegram.botToken; } - const nextCfg = { ...cfg } as ClawdisConfig; + const nextCfg = { ...cfg } as ClawdbotConfig; if (nextTelegram && Object.keys(nextTelegram).length > 0) { nextCfg.telegram = nextTelegram; } else { diff --git a/src/gateway/server-methods/skills.ts b/src/gateway/server-methods/skills.ts index fc86548b8..a3dea2320 100644 --- a/src/gateway/server-methods/skills.ts +++ b/src/gateway/server-methods/skills.ts @@ -1,7 +1,7 @@ import { installSkill } from "../../agents/skills-install.js"; import { buildWorkspaceSkillStatus } from "../../agents/skills-status.js"; import { DEFAULT_AGENT_WORKSPACE_DIR } from "../../agents/workspace.js"; -import type { ClawdisConfig } from "../../config/config.js"; +import type { ClawdbotConfig } from "../../config/config.js"; import { loadConfig, writeConfigFile } from "../../config/config.js"; import { resolveUserPath } from "../../utils.js"; import { @@ -112,7 +112,7 @@ export const skillsHandlers: GatewayRequestHandlers = { } entries[p.skillKey] = current; skills.entries = entries; - const nextConfig: ClawdisConfig = { + const nextConfig: ClawdbotConfig = { ...cfg, skills, }; diff --git a/src/gateway/server-providers.ts b/src/gateway/server-providers.ts index c92e8c056..b204e2b61 100644 --- a/src/gateway/server-providers.ts +++ b/src/gateway/server-providers.ts @@ -1,4 +1,4 @@ -import type { ClawdisConfig } from "../config/config.js"; +import type { ClawdbotConfig } from "../config/config.js"; import { monitorDiscordProvider } from "../discord/index.js"; import { probeDiscord } from "../discord/probe.js"; import { shouldLogVerbose } from "../globals.js"; @@ -70,7 +70,7 @@ export type ProviderRuntimeSnapshot = { type SubsystemLogger = ReturnType; type ProviderManagerOptions = { - loadConfig: () => ClawdisConfig; + loadConfig: () => ClawdbotConfig; logWhatsApp: SubsystemLogger; logTelegram: SubsystemLogger; logDiscord: SubsystemLogger; diff --git a/src/gateway/server.agent.test.ts b/src/gateway/server.agent.test.ts index 32c37bbdf..cc1bada2a 100644 --- a/src/gateway/server.agent.test.ts +++ b/src/gateway/server.agent.test.ts @@ -24,7 +24,7 @@ installGatewayTestHooks(); describe("gateway server agent", () => { test("agent falls back to allowFrom when lastTo is stale", async () => { testState.allowFrom = ["+436769770569"]; - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, @@ -67,7 +67,7 @@ describe("gateway server agent", () => { }); test("agent routes main last-channel whatsapp", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, @@ -111,7 +111,7 @@ describe("gateway server agent", () => { }); test("agent routes main last-channel telegram", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, @@ -155,7 +155,7 @@ describe("gateway server agent", () => { }); test("agent routes main last-channel discord", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, @@ -199,7 +199,7 @@ describe("gateway server agent", () => { }); test("agent routes main last-channel signal", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, @@ -244,7 +244,7 @@ describe("gateway server agent", () => { test("agent ignores webchat last-channel for routing", async () => { testState.allowFrom = ["+1555"]; - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, @@ -415,7 +415,7 @@ describe("gateway server agent", () => { }); test("agent events stream to webchat clients when run context is registered", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, diff --git a/src/gateway/server.auth.test.ts b/src/gateway/server.auth.test.ts index 782e27a42..8bf588f10 100644 --- a/src/gateway/server.auth.test.ts +++ b/src/gateway/server.auth.test.ts @@ -32,7 +32,7 @@ describe("gateway server auth/connect", () => { ); test("connect (req) handshake returns hello-ok payload", async () => { - const { CONFIG_PATH_CLAWDIS, STATE_DIR_CLAWDIS } = await import( + const { CONFIG_PATH_CLAWDBOT, STATE_DIR_CLAWDBOT } = await import( "../config/config.js" ); const port = await getFreePort(); @@ -49,8 +49,8 @@ describe("gateway server auth/connect", () => { } | undefined; expect(payload?.type).toBe("hello-ok"); - expect(payload?.snapshot?.configPath).toBe(CONFIG_PATH_CLAWDIS); - expect(payload?.snapshot?.stateDir).toBe(STATE_DIR_CLAWDIS); + expect(payload?.snapshot?.configPath).toBe(CONFIG_PATH_CLAWDBOT); + expect(payload?.snapshot?.stateDir).toBe(STATE_DIR_CLAWDBOT); ws.close(); await server.close(); @@ -79,9 +79,9 @@ describe("gateway server auth/connect", () => { ws.close(); await server.close(); if (prevToken === undefined) { - delete process.env.CLAWDIS_GATEWAY_TOKEN; + delete process.env.CLAWDBOT_GATEWAY_TOKEN; } else { - process.env.CLAWDIS_GATEWAY_TOKEN = prevToken; + process.env.CLAWDBOT_GATEWAY_TOKEN = prevToken; } }); diff --git a/src/gateway/server.chat.test.ts b/src/gateway/server.chat.test.ts index 67757450d..463d9f5e4 100644 --- a/src/gateway/server.chat.test.ts +++ b/src/gateway/server.chat.test.ts @@ -19,7 +19,7 @@ installGatewayTestHooks(); describe("gateway server chat", () => { test("chat.send blocked by send policy", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); testState.sessionConfig = { sendPolicy: { @@ -68,7 +68,7 @@ describe("gateway server chat", () => { }); test("agent blocked by send policy for sessionKey", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); testState.sessionConfig = { sendPolicy: { @@ -158,7 +158,7 @@ describe("gateway server chat", () => { return typeof text === "string" ? text : undefined; }; - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, @@ -274,7 +274,7 @@ describe("gateway server chat", () => { reasoning: true, }, ]; - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, @@ -316,7 +316,7 @@ describe("gateway server chat", () => { }); test("chat.history caps payload bytes", { timeout: 15_000 }, async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, @@ -371,7 +371,7 @@ describe("gateway server chat", () => { }); test("chat.send does not overwrite last delivery route", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, @@ -416,7 +416,7 @@ describe("gateway server chat", () => { "chat.abort cancels an in-flight chat.send", { timeout: 15000 }, async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, @@ -521,7 +521,7 @@ describe("gateway server chat", () => { ); test("chat.abort cancels while saving the session store", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, @@ -608,7 +608,7 @@ describe("gateway server chat", () => { }); test("chat.abort returns aborted=false for unknown runId", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, @@ -632,7 +632,7 @@ describe("gateway server chat", () => { }); test("chat.abort rejects mismatched sessionKey", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, @@ -709,7 +709,7 @@ describe("gateway server chat", () => { }, 15_000); test("chat.abort is a no-op after chat.send completes", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, @@ -764,7 +764,7 @@ describe("gateway server chat", () => { }); test("chat.send preserves run ordering for queued runs", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, diff --git a/src/gateway/server.cron.test.ts b/src/gateway/server.cron.test.ts index b2af8bbc8..e9519aa88 100644 --- a/src/gateway/server.cron.test.ts +++ b/src/gateway/server.cron.test.ts @@ -27,7 +27,7 @@ installGatewayTestHooks(); describe("gateway server cron", () => { test("supports cron.add and cron.list", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-cron-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-cron-")); testState.cronStorePath = path.join(dir, "cron", "jobs.json"); await fs.mkdir(path.dirname(testState.cronStorePath), { recursive: true }); await fs.writeFile( @@ -70,7 +70,7 @@ describe("gateway server cron", () => { test("writes cron run history to runs/.jsonl", async () => { const dir = await fs.mkdtemp( - path.join(os.tmpdir(), "clawdis-gw-cron-log-"), + path.join(os.tmpdir(), "clawdbot-gw-cron-log-"), ); testState.cronStorePath = path.join(dir, "cron", "jobs.json"); await fs.mkdir(path.dirname(testState.cronStorePath), { recursive: true }); @@ -143,7 +143,7 @@ describe("gateway server cron", () => { test("writes cron run history to per-job runs/ when store is jobs.json", async () => { const dir = await fs.mkdtemp( - path.join(os.tmpdir(), "clawdis-gw-cron-log-jobs-"), + path.join(os.tmpdir(), "clawdbot-gw-cron-log-jobs-"), ); const cronDir = path.join(dir, "cron"); testState.cronStorePath = path.join(cronDir, "jobs.json"); @@ -216,7 +216,7 @@ describe("gateway server cron", () => { test("enables cron scheduler by default and runs due jobs automatically", async () => { const dir = await fs.mkdtemp( - path.join(os.tmpdir(), "clawdis-gw-cron-default-on-"), + path.join(os.tmpdir(), "clawdbot-gw-cron-default-on-"), ); testState.cronStorePath = path.join(dir, "cron", "jobs.json"); testState.cronEnabled = undefined; diff --git a/src/gateway/server.hooks.test.ts b/src/gateway/server.hooks.test.ts index 752828b2b..defe83a99 100644 --- a/src/gateway/server.hooks.test.ts +++ b/src/gateway/server.hooks.test.ts @@ -103,7 +103,7 @@ describe("gateway server hooks", () => { await server.close(); }); - test("hooks wake accepts x-clawdis-token header", async () => { + test("hooks wake accepts x-clawdbot-token header", async () => { testState.hooksConfig = { enabled: true, token: "hook-secret" }; const port = await getFreePort(); const server = await startGatewayServer(port); @@ -111,7 +111,7 @@ describe("gateway server hooks", () => { method: "POST", headers: { "Content-Type": "application/json", - "x-clawdis-token": "hook-secret", + "x-clawdbot-token": "hook-secret", }, body: JSON.stringify({ text: "Header auth" }), }); diff --git a/src/gateway/server.misc.test.ts b/src/gateway/server.misc.test.ts index d8637a403..6ae7fd6b3 100644 --- a/src/gateway/server.misc.test.ts +++ b/src/gateway/server.misc.test.ts @@ -18,8 +18,8 @@ installGatewayTestHooks(); describe("gateway server misc", () => { test("hello-ok advertises the gateway port for canvas host", async () => { - const prevToken = process.env.CLAWDIS_GATEWAY_TOKEN; - process.env.CLAWDIS_GATEWAY_TOKEN = "secret"; + const prevToken = process.env.CLAWDBOT_GATEWAY_TOKEN; + process.env.CLAWDBOT_GATEWAY_TOKEN = "secret"; testTailnetIPv4.value = "100.64.0.1"; testState.gatewayBind = "lan"; const canvasPort = await getFreePort(); @@ -41,9 +41,9 @@ describe("gateway server misc", () => { ws.close(); await server.close(); if (prevToken === undefined) { - delete process.env.CLAWDIS_GATEWAY_TOKEN; + delete process.env.CLAWDBOT_GATEWAY_TOKEN; } else { - process.env.CLAWDIS_GATEWAY_TOKEN = prevToken; + process.env.CLAWDBOT_GATEWAY_TOKEN = prevToken; } }); diff --git a/src/gateway/server.models-voicewake.test.ts b/src/gateway/server.models-voicewake.test.ts index 138ee1565..2c21c9dca 100644 --- a/src/gateway/server.models-voicewake.test.ts +++ b/src/gateway/server.models-voicewake.test.ts @@ -21,7 +21,7 @@ describe("gateway server models + voicewake", () => { "voicewake.get returns defaults and voicewake.set broadcasts", { timeout: 15_000 }, async () => { - const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-home-")); + const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-home-")); const prevHome = process.env.HOME; process.env.HOME = homeDir; @@ -60,7 +60,7 @@ describe("gateway server models + voicewake", () => { const onDisk = JSON.parse( await fs.readFile( - path.join(homeDir, ".clawdis", "settings", "voicewake.json"), + path.join(homeDir, ".clawdbot", "settings", "voicewake.json"), "utf8", ), ) as { triggers?: unknown; updatedAtMs?: unknown }; @@ -79,7 +79,7 @@ describe("gateway server models + voicewake", () => { ); test("pushes voicewake.changed to nodes on connect and on updates", async () => { - const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-home-")); + const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-home-")); const prevHome = process.env.HOME; process.env.HOME = homeDir; diff --git a/src/gateway/server.node-bridge.test.ts b/src/gateway/server.node-bridge.test.ts index 96587d2ca..830c29b58 100644 --- a/src/gateway/server.node-bridge.test.ts +++ b/src/gateway/server.node-bridge.test.ts @@ -37,7 +37,7 @@ installGatewayTestHooks(); describe("gateway server node/bridge", () => { test("supports gateway-owned node pairing methods and events", async () => { - const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-home-")); + const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-home-")); const prevHome = process.env.HOME; process.env.HOME = homeDir; @@ -149,7 +149,7 @@ describe("gateway server node/bridge", () => { }); test("routes node.invoke to the node bridge", async () => { - const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-home-")); + const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-home-")); const prevHome = process.env.HOME; process.env.HOME = homeDir; @@ -198,7 +198,7 @@ describe("gateway server node/bridge", () => { }); test("routes camera.list invoke to the node bridge", async () => { - const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-home-")); + const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-home-")); const prevHome = process.env.HOME; process.env.HOME = homeDir; @@ -245,7 +245,7 @@ describe("gateway server node/bridge", () => { }); test("node.describe returns supported invoke commands for paired nodes", async () => { - const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-home-")); + const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-home-")); const prevHome = process.env.HOME; process.env.HOME = homeDir; @@ -303,7 +303,7 @@ describe("gateway server node/bridge", () => { }); test("node.describe works for connected unpaired nodes (caps + commands)", async () => { - const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-home-")); + const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-home-")); const prevHome = process.env.HOME; process.env.HOME = homeDir; @@ -363,7 +363,7 @@ describe("gateway server node/bridge", () => { }); test("node.list includes connected unpaired nodes with capabilities + commands", async () => { - const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-home-")); + const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-home-")); const prevHome = process.env.HOME; process.env.HOME = homeDir; @@ -470,7 +470,7 @@ describe("gateway server node/bridge", () => { }); test("emits presence updates for bridge connect/disconnect", async () => { - const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-home-")); + const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-home-")); const prevHome = process.env.HOME; process.env.HOME = homeDir; try { @@ -539,7 +539,7 @@ describe("gateway server node/bridge", () => { }); test("bridge RPC chat.history returns session messages", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, @@ -598,7 +598,7 @@ describe("gateway server node/bridge", () => { }); test("bridge RPC sessions.list returns session rows", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, @@ -646,7 +646,7 @@ describe("gateway server node/bridge", () => { }); test("bridge chat events are pushed to subscribed nodes", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, @@ -723,7 +723,7 @@ describe("gateway server node/bridge", () => { }); test("bridge voice transcript defaults to main session", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, @@ -771,7 +771,7 @@ describe("gateway server node/bridge", () => { }); test("bridge voice transcript triggers chat events for webchat clients", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, @@ -862,7 +862,7 @@ describe("gateway server node/bridge", () => { }); test("bridge chat.abort cancels while saving the session store", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-")); testState.sessionStorePath = path.join(dir, "sessions.json"); await fs.writeFile( testState.sessionStorePath, diff --git a/src/gateway/server.reload.test.ts b/src/gateway/server.reload.test.ts index 91910ceed..21f99b403 100644 --- a/src/gateway/server.reload.test.ts +++ b/src/gateway/server.reload.test.ts @@ -163,22 +163,22 @@ describe("gateway hot reload", () => { let prevSkipGmail: string | undefined; beforeEach(() => { - prevSkipProviders = process.env.CLAWDIS_SKIP_PROVIDERS; - prevSkipGmail = process.env.CLAWDIS_SKIP_GMAIL_WATCHER; - process.env.CLAWDIS_SKIP_PROVIDERS = "0"; - delete process.env.CLAWDIS_SKIP_GMAIL_WATCHER; + prevSkipProviders = process.env.CLAWDBOT_SKIP_PROVIDERS; + prevSkipGmail = process.env.CLAWDBOT_SKIP_GMAIL_WATCHER; + process.env.CLAWDBOT_SKIP_PROVIDERS = "0"; + delete process.env.CLAWDBOT_SKIP_GMAIL_WATCHER; }); afterEach(() => { if (prevSkipProviders === undefined) { - delete process.env.CLAWDIS_SKIP_PROVIDERS; + delete process.env.CLAWDBOT_SKIP_PROVIDERS; } else { - process.env.CLAWDIS_SKIP_PROVIDERS = prevSkipProviders; + process.env.CLAWDBOT_SKIP_PROVIDERS = prevSkipProviders; } if (prevSkipGmail === undefined) { - delete process.env.CLAWDIS_SKIP_GMAIL_WATCHER; + delete process.env.CLAWDBOT_SKIP_GMAIL_WATCHER; } else { - process.env.CLAWDIS_SKIP_GMAIL_WATCHER = prevSkipGmail; + process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = prevSkipGmail; } }); diff --git a/src/gateway/server.sessions-send.test.ts b/src/gateway/server.sessions-send.test.ts index d2dec2a89..4cdc1d504 100644 --- a/src/gateway/server.sessions-send.test.ts +++ b/src/gateway/server.sessions-send.test.ts @@ -1,7 +1,7 @@ import fs from "node:fs/promises"; import path from "node:path"; import { describe, expect, it, vi } from "vitest"; -import { createClawdisTools } from "../agents/clawdis-tools.js"; +import { createClawdbotTools } from "../agents/clawdbot-tools.js"; import { resolveSessionTranscriptPath } from "../config/sessions.js"; import { emitAgentEvent } from "../infra/agent-events.js"; import { @@ -16,8 +16,8 @@ installGatewayTestHooks(); describe("sessions_send gateway loopback", () => { it("returns reply when job finishes before agent.wait", async () => { const port = await getFreePort(); - const prevPort = process.env.CLAWDIS_GATEWAY_PORT; - process.env.CLAWDIS_GATEWAY_PORT = String(port); + const prevPort = process.env.CLAWDBOT_GATEWAY_PORT; + process.env.CLAWDBOT_GATEWAY_PORT = String(port); const server = await startGatewayServer(port); const spy = vi.mocked(agentCommand); @@ -71,7 +71,7 @@ describe("sessions_send gateway loopback", () => { }); try { - const tool = createClawdisTools().find( + const tool = createClawdbotTools().find( (candidate) => candidate.name === "sessions_send", ); if (!tool) throw new Error("missing sessions_send tool"); @@ -94,9 +94,9 @@ describe("sessions_send gateway loopback", () => { expect(firstCall?.lane).toBe("nested"); } finally { if (prevPort === undefined) { - delete process.env.CLAWDIS_GATEWAY_PORT; + delete process.env.CLAWDBOT_GATEWAY_PORT; } else { - process.env.CLAWDIS_GATEWAY_PORT = prevPort; + process.env.CLAWDBOT_GATEWAY_PORT = prevPort; } await server.close(); } diff --git a/src/gateway/server.sessions.test.ts b/src/gateway/server.sessions.test.ts index 97dd9c6c6..1c8ef9176 100644 --- a/src/gateway/server.sessions.test.ts +++ b/src/gateway/server.sessions.test.ts @@ -16,7 +16,7 @@ installGatewayTestHooks(); describe("gateway server sessions", () => { test("lists and patches session store via sessions.* RPC", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-sessions-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-sessions-")); const storePath = path.join(dir, "sessions.json"); const now = Date.now(); testState.sessionStorePath = storePath; @@ -220,7 +220,7 @@ describe("gateway server sessions", () => { }); test("sessions.delete rejects main and aborts active runs", async () => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-sessions-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-sessions-")); const storePath = path.join(dir, "sessions.json"); testState.sessionStorePath = storePath; diff --git a/src/gateway/server.ts b/src/gateway/server.ts index efda86281..080b76469 100644 --- a/src/gateway/server.ts +++ b/src/gateway/server.ts @@ -20,12 +20,12 @@ import { import { createDefaultDeps } from "../cli/deps.js"; import { getHealthSnapshot, type HealthSummary } from "../commands/health.js"; import { - CONFIG_PATH_CLAWDIS, + CONFIG_PATH_CLAWDBOT, isNixMode, loadConfig, migrateLegacyConfig, readConfigFileSnapshot, - STATE_DIR_CLAWDIS, + STATE_DIR_CLAWDBOT, writeConfigFile, } from "../config/config.js"; import { loadSessionStore, resolveStorePath } from "../config/sessions.js"; @@ -49,7 +49,7 @@ import { onHeartbeatEvent } from "../infra/heartbeat-events.js"; import { startHeartbeatRunner } from "../infra/heartbeat-runner.js"; import { requestHeartbeatNow } from "../infra/heartbeat-wake.js"; import { getMachineDisplayName } from "../infra/machine-name.js"; -import { ensureClawdisCliOnPath } from "../infra/path-env.js"; +import { ensureClawdbotCliOnPath } from "../infra/path-env.js"; import { enqueueSystemEvent } from "../infra/system-events.js"; import { listSystemPresence, @@ -131,7 +131,7 @@ import type { DedupeEntry } from "./server-shared.js"; import { formatError } from "./server-utils.js"; import { formatForLog, logWs, summarizeAgentEventForWsLog } from "./ws-log.js"; -ensureClawdisCliOnPath(); +ensureClawdbotCliOnPath(); const log = createSubsystemLogger("gateway"); const logCanvas = log.child("canvas"); @@ -329,8 +329,8 @@ function buildSnapshot(): Snapshot { stateVersion: { presence: presenceVersion, health: healthVersion }, uptimeMs, // Surface resolved paths so UIs can display the true config location. - configPath: CONFIG_PATH_CLAWDIS, - stateDir: STATE_DIR_CLAWDIS, + configPath: CONFIG_PATH_CLAWDBOT, + stateDir: STATE_DIR_CLAWDBOT, }; } @@ -367,7 +367,7 @@ export async function startGatewayServer( ); if (!migrated) { throw new Error( - 'Legacy config entries detected but auto-migration failed. Run "clawdis doctor" to migrate.', + 'Legacy config entries detected but auto-migration failed. Run "clawdbot doctor" to migrate.', ); } await writeConfigFile(migrated); @@ -407,9 +407,9 @@ export async function startGatewayServer( }; const tailscaleMode = tailscaleConfig.mode ?? "off"; const token = - authConfig.token ?? process.env.CLAWDIS_GATEWAY_TOKEN ?? undefined; + authConfig.token ?? process.env.CLAWDBOT_GATEWAY_TOKEN ?? undefined; const password = - authConfig.password ?? process.env.CLAWDIS_GATEWAY_PASSWORD ?? undefined; + authConfig.password ?? process.env.CLAWDBOT_GATEWAY_PASSWORD ?? undefined; const authMode: ResolvedGatewayAuth["mode"] = authConfig.mode ?? (password ? "password" : token ? "token" : "none"); const allowTailscale = @@ -423,12 +423,12 @@ export async function startGatewayServer( }; let hooksConfig = resolveHooksConfig(cfgAtStart); const canvasHostEnabled = - process.env.CLAWDIS_SKIP_CANVAS_HOST !== "1" && + process.env.CLAWDBOT_SKIP_CANVAS_HOST !== "1" && cfgAtStart.canvasHost?.enabled !== false; assertGatewayAuthConfigured(resolvedAuth); if (tailscaleMode === "funnel" && authMode !== "password") { throw new Error( - "tailscale funnel requires gateway auth mode=password (set gateway.auth.password or CLAWDIS_GATEWAY_PASSWORD)", + "tailscale funnel requires gateway auth mode=password (set gateway.auth.password or CLAWDBOT_GATEWAY_PASSWORD)", ); } if (tailscaleMode !== "off" && !isLoopbackHost(bindHost)) { @@ -438,7 +438,7 @@ export async function startGatewayServer( } if (!isLoopbackHost(bindHost) && authMode === "none") { throw new Error( - `refusing to bind gateway to ${bindHost}:${port} without auth (set gateway.auth or CLAWDIS_GATEWAY_TOKEN)`, + `refusing to bind gateway to ${bindHost}:${port} without auth (set gateway.auth or CLAWDBOT_GATEWAY_TOKEN)`, ); } @@ -672,7 +672,7 @@ export async function startGatewayServer( const buildCronService = (cfg: ReturnType) => { const storePath = resolveCronStorePath(cfg.cron?.store); const cronEnabled = - process.env.CLAWDIS_SKIP_CRON !== "1" && cfg.cron?.enabled !== false; + process.env.CLAWDBOT_SKIP_CRON !== "1" && cfg.cron?.enabled !== false; const cron = new CronService({ storePath, cronEnabled, @@ -807,7 +807,7 @@ export async function startGatewayServer( const bridgeEnabled = (() => { if (cfgAtStart.bridge?.enabled !== undefined) return cfgAtStart.bridge.enabled === true; - return process.env.CLAWDIS_BRIDGE_ENABLED !== "0"; + return process.env.CLAWDBOT_BRIDGE_ENABLED !== "0"; })(); const bridgePort = (() => { @@ -817,8 +817,8 @@ export async function startGatewayServer( ) { return cfgAtStart.bridge.port; } - if (process.env.CLAWDIS_BRIDGE_PORT !== undefined) { - const parsed = Number.parseInt(process.env.CLAWDIS_BRIDGE_PORT, 10); + if (process.env.CLAWDBOT_BRIDGE_PORT !== undefined) { + const parsed = Number.parseInt(process.env.CLAWDBOT_BRIDGE_PORT, 10); return Number.isFinite(parsed) && parsed > 0 ? parsed : 18790; } return 18790; @@ -827,7 +827,7 @@ export async function startGatewayServer( const bridgeHost = (() => { // Back-compat: allow an env var override when no bind policy is configured. if (cfgAtStart.bridge?.bind === undefined) { - const env = process.env.CLAWDIS_BRIDGE_HOST?.trim(); + const env = process.env.CLAWDBOT_BRIDGE_HOST?.trim(); if (env) return env; } @@ -1059,7 +1059,7 @@ export async function startGatewayServer( const tailnetDns = await resolveTailnetDnsHint(); try { - const sshPortEnv = process.env.CLAWDIS_SSH_PORT?.trim(); + const sshPortEnv = process.env.CLAWDBOT_SSH_PORT?.trim(); const sshPortParsed = sshPortEnv ? Number.parseInt(sshPortEnv, 10) : NaN; const sshPort = Number.isFinite(sshPortParsed) && sshPortParsed > 0 @@ -1392,7 +1392,7 @@ export async function startGatewayServer( protocol: PROTOCOL_VERSION, server: { version: - process.env.CLAWDIS_VERSION ?? + process.env.CLAWDBOT_VERSION ?? process.env.npm_package_version ?? "dev", commit: process.env.GIT_COMMIT, @@ -1594,7 +1594,7 @@ export async function startGatewayServer( } // Start Gmail watcher if configured (hooks.gmail.account). - if (process.env.CLAWDIS_SKIP_GMAIL_WATCHER !== "1") { + if (process.env.CLAWDBOT_SKIP_GMAIL_WATCHER !== "1") { try { const gmailResult = await startGmailWatcher(cfgAtStart); if (gmailResult.started) { @@ -1612,15 +1612,15 @@ export async function startGatewayServer( } // Launch configured providers (WhatsApp Web, Discord, Slack, Telegram) so gateway replies via the - // surface the message came from. Tests can opt out via CLAWDIS_SKIP_PROVIDERS. - if (process.env.CLAWDIS_SKIP_PROVIDERS !== "1") { + // surface the message came from. Tests can opt out via CLAWDBOT_SKIP_PROVIDERS. + if (process.env.CLAWDBOT_SKIP_PROVIDERS !== "1") { try { await startProviders(); } catch (err) { logProviders.error(`provider startup failed: ${String(err)}`); } } else { - logProviders.info("skipping provider start (CLAWDIS_SKIP_PROVIDERS=1)"); + logProviders.info("skipping provider start (CLAWDBOT_SKIP_PROVIDERS=1)"); } const applyHotReload = async ( @@ -1663,7 +1663,7 @@ export async function startGatewayServer( if (plan.restartGmailWatcher) { await stopGmailWatcher().catch(() => {}); - if (process.env.CLAWDIS_SKIP_GMAIL_WATCHER !== "1") { + if (process.env.CLAWDBOT_SKIP_GMAIL_WATCHER !== "1") { try { const gmailResult = await startGmailWatcher(nextConfig); if (gmailResult.started) { @@ -1680,15 +1680,15 @@ export async function startGatewayServer( } } else { logHooks.info( - "skipping gmail watcher restart (CLAWDIS_SKIP_GMAIL_WATCHER=1)", + "skipping gmail watcher restart (CLAWDBOT_SKIP_GMAIL_WATCHER=1)", ); } } if (plan.restartProviders.size > 0) { - if (process.env.CLAWDIS_SKIP_PROVIDERS === "1") { + if (process.env.CLAWDBOT_SKIP_PROVIDERS === "1") { logProviders.info( - "skipping provider reload (CLAWDIS_SKIP_PROVIDERS=1)", + "skipping provider reload (CLAWDBOT_SKIP_PROVIDERS=1)", ); } else { const restartProvider = async ( @@ -1780,7 +1780,7 @@ export async function startGatewayServer( warn: (msg) => logReload.warn(msg), error: (msg) => logReload.error(msg), }, - watchPath: CONFIG_PATH_CLAWDIS, + watchPath: CONFIG_PATH_CLAWDBOT, }); return { diff --git a/src/gateway/session-utils.ts b/src/gateway/session-utils.ts index f08f5dfcc..3deba73d9 100644 --- a/src/gateway/session-utils.ts +++ b/src/gateway/session-utils.ts @@ -8,7 +8,7 @@ import { DEFAULT_PROVIDER, } from "../agents/defaults.js"; import { resolveConfiguredModelRef } from "../agents/model-selection.js"; -import { type ClawdisConfig, loadConfig } from "../config/config.js"; +import { type ClawdbotConfig, loadConfig } from "../config/config.js"; import { buildGroupDisplayName, loadSessionStore, @@ -97,7 +97,7 @@ export function resolveSessionTranscriptCandidates( candidates.push(path.join(dir, `${sessionId}.jsonl`)); } candidates.push( - path.join(os.homedir(), ".clawdis", "sessions", `${sessionId}.jsonl`), + path.join(os.homedir(), ".clawdbot", "sessions", `${sessionId}.jsonl`), ); return candidates; } @@ -180,7 +180,7 @@ export function parseGroupKey( } export function getSessionDefaults( - cfg: ClawdisConfig, + cfg: ClawdbotConfig, ): GatewaySessionsDefaults { const resolved = resolveConfiguredModelRef({ cfg, @@ -198,7 +198,7 @@ export function getSessionDefaults( } export function resolveSessionModelRef( - cfg: ClawdisConfig, + cfg: ClawdbotConfig, entry?: SessionEntry, ): { provider: string; model: string } { const resolved = resolveConfiguredModelRef({ @@ -217,7 +217,7 @@ export function resolveSessionModelRef( } export function listSessionsFromStore(params: { - cfg: ClawdisConfig; + cfg: ClawdbotConfig; storePath: string; store: Record; opts: import("./protocol/index.js").SessionsListParams; diff --git a/src/gateway/test-helpers.ts b/src/gateway/test-helpers.ts index e08430580..fe2d99db8 100644 --- a/src/gateway/test-helpers.ts +++ b/src/gateway/test-helpers.ts @@ -161,7 +161,7 @@ vi.mock("../config/config.js", async () => { "../config/config.js", ); const resolveConfigPath = () => - path.join(os.homedir(), ".clawdis", "clawdis.json"); + path.join(os.homedir(), ".clawdbot", "clawdbot.json"); const readConfigFileSnapshot = async () => { if (testState.legacyIssues.length > 0) { @@ -230,8 +230,8 @@ vi.mock("../config/config.js", async () => { return { ...actual, - CONFIG_PATH_CLAWDIS: resolveConfigPath(), - STATE_DIR_CLAWDIS: path.dirname(resolveConfigPath()), + CONFIG_PATH_CLAWDBOT: resolveConfigPath(), + STATE_DIR_CLAWDBOT: path.dirname(resolveConfigPath()), get isNixMode() { return testIsNixMode.value; }, @@ -325,7 +325,7 @@ vi.mock("../commands/agent.js", () => ({ agentCommand, })); -process.env.CLAWDIS_SKIP_PROVIDERS = "1"; +process.env.CLAWDBOT_SKIP_PROVIDERS = "1"; let previousHome: string | undefined; let tempHome: string | undefined; @@ -334,7 +334,7 @@ export function installGatewayTestHooks() { beforeEach(async () => { previousHome = process.env.HOME; tempHome = await fs.mkdtemp( - path.join(os.tmpdir(), "clawdis-gateway-home-"), + path.join(os.tmpdir(), "clawdbot-gateway-home-"), ); process.env.HOME = tempHome; sessionStoreSaveDelayMs.value = 0; @@ -440,11 +440,11 @@ export async function startServerWithClient( opts?: GatewayServerOptions, ) { const port = await getFreePort(); - const prev = process.env.CLAWDIS_GATEWAY_TOKEN; + const prev = process.env.CLAWDBOT_GATEWAY_TOKEN; if (token === undefined) { - delete process.env.CLAWDIS_GATEWAY_TOKEN; + delete process.env.CLAWDBOT_GATEWAY_TOKEN; } else { - process.env.CLAWDIS_GATEWAY_TOKEN = token; + process.env.CLAWDBOT_GATEWAY_TOKEN = token; } const server = await startGatewayServer(port, opts); const ws = new WebSocket(`ws://127.0.0.1:${port}`); diff --git a/src/hooks/gmail-ops.ts b/src/hooks/gmail-ops.ts index ed1649fc8..be8d74cac 100644 --- a/src/hooks/gmail-ops.ts +++ b/src/hooks/gmail-ops.ts @@ -1,8 +1,8 @@ import { spawn } from "node:child_process"; import { - type ClawdisConfig, - CONFIG_PATH_CLAWDIS, + type ClawdbotConfig, + CONFIG_PATH_CLAWDBOT, loadConfig, readConfigFileSnapshot, resolveGatewayPort, @@ -96,7 +96,7 @@ export async function runGmailSetup(opts: GmailSetupOptions) { const configSnapshot = await readConfigFileSnapshot(); if (!configSnapshot.valid) { - throw new Error(`Config invalid: ${CONFIG_PATH_CLAWDIS}`); + throw new Error(`Config invalid: ${CONFIG_PATH_CLAWDBOT}`); } const baseConfig = configSnapshot.config; @@ -206,7 +206,7 @@ export async function runGmailSetup(opts: GmailSetupOptions) { true, ); - const nextConfig: ClawdisConfig = { + const nextConfig: ClawdbotConfig = { ...baseConfig, hooks: { ...baseConfig.hooks, @@ -274,8 +274,8 @@ export async function runGmailSetup(opts: GmailSetupOptions) { defaultRuntime.log(`- subscription: ${subscription}`); defaultRuntime.log(`- push endpoint: ${pushEndpoint}`); defaultRuntime.log(`- hook url: ${hookUrl}`); - defaultRuntime.log(`- config: ${CONFIG_PATH_CLAWDIS}`); - defaultRuntime.log("Next: clawdis hooks gmail run"); + defaultRuntime.log(`- config: ${CONFIG_PATH_CLAWDBOT}`); + defaultRuntime.log("Next: clawdbot hooks gmail run"); } export async function runGmailService(opts: GmailRunOptions) { diff --git a/src/hooks/gmail-setup-utils.test.ts b/src/hooks/gmail-setup-utils.test.ts index 2eeb7da79..b14d5de45 100644 --- a/src/hooks/gmail-setup-utils.test.ts +++ b/src/hooks/gmail-setup-utils.test.ts @@ -10,7 +10,7 @@ beforeEach(() => { describe("resolvePythonExecutablePath", () => { it("resolves a working python path and caches the result", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-python-")); + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-python-")); const originalPath = process.env.PATH; try { const realPython = path.join(tmp, "python-real"); diff --git a/src/hooks/gmail-watcher.ts b/src/hooks/gmail-watcher.ts index 6ec7ea377..bd4e07969 100644 --- a/src/hooks/gmail-watcher.ts +++ b/src/hooks/gmail-watcher.ts @@ -7,7 +7,7 @@ import { type ChildProcess, spawn } from "node:child_process"; import { hasBinary } from "../agents/skills.js"; -import type { ClawdisConfig } from "../config/config.js"; +import type { ClawdbotConfig } from "../config/config.js"; import { createSubsystemLogger } from "../logging.js"; import { runCommandWithTimeout } from "../process/exec.js"; import { @@ -104,7 +104,7 @@ export type GmailWatcherStartResult = { * Called automatically by the gateway if hooks.gmail is configured. */ export async function startGmailWatcher( - cfg: ClawdisConfig, + cfg: ClawdbotConfig, ): Promise { // Check if gmail hooks are configured if (!cfg.hooks?.enabled) { diff --git a/src/hooks/gmail.test.ts b/src/hooks/gmail.test.ts index fb8041b57..3956d33a8 100644 --- a/src/hooks/gmail.test.ts +++ b/src/hooks/gmail.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { type ClawdisConfig, DEFAULT_GATEWAY_PORT } from "../config/config.js"; +import { type ClawdbotConfig, DEFAULT_GATEWAY_PORT } from "../config/config.js"; import { buildDefaultHookUrl, buildTopicPath, @@ -16,7 +16,7 @@ const baseConfig = { pushToken: "push-token", }, }, -} satisfies ClawdisConfig; +} satisfies ClawdbotConfig; describe("gmail hook config", () => { it("builds default hook url", () => { diff --git a/src/hooks/gmail.ts b/src/hooks/gmail.ts index 42da43ba1..f14de6899 100644 --- a/src/hooks/gmail.ts +++ b/src/hooks/gmail.ts @@ -1,7 +1,7 @@ import { randomBytes } from "node:crypto"; import { - type ClawdisConfig, + type ClawdbotConfig, DEFAULT_GATEWAY_PORT, type HooksGmailTailscaleMode, resolveGatewayPort, @@ -98,7 +98,7 @@ export function buildDefaultHookUrl( } export function resolveGmailHookRuntimeConfig( - cfg: ClawdisConfig, + cfg: ClawdbotConfig, overrides: GmailHookOverrides, ): { ok: true; value: GmailHookRuntimeConfig } | { ok: false; error: string } { const hooks = cfg.hooks; diff --git a/src/imessage/monitor.test.ts b/src/imessage/monitor.test.ts index 84840a197..433fbc239 100644 --- a/src/imessage/monitor.test.ts +++ b/src/imessage/monitor.test.ts @@ -27,7 +27,7 @@ vi.mock("./send.js", () => ({ })); vi.mock("../config/sessions.js", () => ({ - resolveStorePath: vi.fn(() => "/tmp/clawdis-sessions.json"), + resolveStorePath: vi.fn(() => "/tmp/clawdbot-sessions.json"), updateLastRoute: (...args: unknown[]) => updateLastRouteMock(...args), })); diff --git a/src/index.ts b/src/index.ts index b3bfd7c30..cc9d1f58a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,7 +19,7 @@ import { import { ensureBinary } from "./infra/binaries.js"; import { normalizeEnv } from "./infra/env.js"; import { isMainModule } from "./infra/is-main.js"; -import { ensureClawdisCliOnPath } from "./infra/path-env.js"; +import { ensureClawdbotCliOnPath } from "./infra/path-env.js"; import { describePortOwner, ensurePortAvailable, @@ -34,7 +34,7 @@ import { assertProvider, normalizeE164, toWhatsappJid } from "./utils.js"; dotenv.config({ quiet: true }); normalizeEnv(); -ensureClawdisCliOnPath(); +ensureClawdbotCliOnPath(); // Capture all console output into structured logs while keeping stdout/stderr behavior. enableConsoleCapture(); @@ -80,7 +80,7 @@ if (isMain) { // These log the error and exit gracefully instead of crashing without trace. process.on("unhandledRejection", (reason, _promise) => { console.error( - "[clawdis] Unhandled promise rejection:", + "[clawdbot] Unhandled promise rejection:", reason instanceof Error ? (reason.stack ?? reason.message) : reason, ); process.exit(1); @@ -88,7 +88,7 @@ if (isMain) { process.on("uncaughtException", (error) => { console.error( - "[clawdis] Uncaught exception:", + "[clawdbot] Uncaught exception:", error.stack ?? error.message, ); process.exit(1); @@ -96,7 +96,7 @@ if (isMain) { void program.parseAsync(process.argv).catch((err) => { console.error( - "[clawdis] CLI failed:", + "[clawdbot] CLI failed:", err instanceof Error ? (err.stack ?? err.message) : err, ); process.exit(1); diff --git a/src/infra/bonjour-discovery.ts b/src/infra/bonjour-discovery.ts index 210a1a605..a6ae02f41 100644 --- a/src/infra/bonjour-discovery.ts +++ b/src/infra/bonjour-discovery.ts @@ -43,9 +43,9 @@ function parseDnsSdBrowse(stdout: string): string[] { const instances = new Set(); for (const raw of stdout.split("\n")) { const line = raw.trim(); - if (!line || !line.includes("_clawdis-bridge._tcp")) continue; + if (!line || !line.includes("_clawdbot-bridge._tcp")) continue; if (!line.includes("Add")) continue; - const match = line.match(/_clawdis-bridge\._tcp\.?\s+(.+)$/); + const match = line.match(/_clawdbot-bridge\._tcp\.?\s+(.+)$/); if (match?.[1]) { instances.add(match[1].trim()); } @@ -97,14 +97,14 @@ async function discoverViaDnsSd( timeoutMs: number, ): Promise { const browse = await runCommandWithTimeout( - ["dns-sd", "-B", "_clawdis-bridge._tcp", "local."], + ["dns-sd", "-B", "_clawdbot-bridge._tcp", "local."], { timeoutMs }, ); const instances = parseDnsSdBrowse(browse.stdout); const results: GatewayBonjourBeacon[] = []; for (const instance of instances) { const resolved = await runCommandWithTimeout( - ["dns-sd", "-L", instance, "_clawdis-bridge._tcp", "local."], + ["dns-sd", "-L", instance, "_clawdbot-bridge._tcp", "local."], { timeoutMs }, ); const parsed = parseDnsSdResolve(resolved.stdout, instance); @@ -120,9 +120,9 @@ function parseAvahiBrowse(stdout: string): GatewayBonjourBeacon[] { for (const raw of stdout.split("\n")) { const line = raw.trimEnd(); if (!line) continue; - if (line.startsWith("=") && line.includes("_clawdis-bridge._tcp")) { + if (line.startsWith("=") && line.includes("_clawdbot-bridge._tcp")) { if (current) results.push(current); - const marker = " _clawdis-bridge._tcp"; + const marker = " _clawdbot-bridge._tcp"; const idx = line.indexOf(marker); const left = idx >= 0 ? line.slice(0, idx).trim() : line; const parts = left.split(/\s+/); @@ -171,7 +171,7 @@ async function discoverViaAvahi( timeoutMs: number, ): Promise { const browse = await runCommandWithTimeout( - ["avahi-browse", "-rt", "_clawdis-bridge._tcp"], + ["avahi-browse", "-rt", "_clawdbot-bridge._tcp"], { timeoutMs }, ); return parseAvahiBrowse(browse.stdout); diff --git a/src/infra/bonjour.test.ts b/src/infra/bonjour.test.ts index cdcd0793d..1acb21dfc 100644 --- a/src/infra/bonjour.test.ts +++ b/src/infra/bonjour.test.ts @@ -100,14 +100,14 @@ describe("gateway bonjour advertiser", () => { sshPort: 2222, bridgePort: 18790, tailnetDns: "host.tailnet.ts.net", - cliPath: "/opt/homebrew/bin/clawdis", + cliPath: "/opt/homebrew/bin/clawdbot", }); expect(createService).toHaveBeenCalledTimes(1); const [bridgeCall] = createService.mock.calls as Array< [Record] >; - expect(bridgeCall?.[0]?.type).toBe("clawdis-bridge"); + expect(bridgeCall?.[0]?.type).toBe("clawdbot-bridge"); expect(bridgeCall?.[0]?.port).toBe(18790); expect(bridgeCall?.[0]?.domain).toBe("local"); expect(bridgeCall?.[0]?.hostname).toBe("test-host"); @@ -121,7 +121,7 @@ describe("gateway bonjour advertiser", () => { "2222", ); expect((bridgeCall?.[0]?.txt as Record)?.cliPath).toBe( - "/opt/homebrew/bin/clawdis", + "/opt/homebrew/bin/clawdbot", ); expect((bridgeCall?.[0]?.txt as Record)?.transport).toBe( "bridge", @@ -297,7 +297,7 @@ describe("gateway bonjour advertiser", () => { }); const [bridgeCall] = createService.mock.calls as Array<[ServiceCall]>; - expect(bridgeCall?.[0]?.name).toBe("Mac (Clawdis)"); + expect(bridgeCall?.[0]?.name).toBe("Mac (Clawdbot)"); expect(bridgeCall?.[0]?.domain).toBe("local"); expect(bridgeCall?.[0]?.hostname).toBe("Mac"); expect((bridgeCall?.[0]?.txt as Record)?.lanHost).toBe( diff --git a/src/infra/bonjour.ts b/src/infra/bonjour.ts index cb8e7e17e..d8becf195 100644 --- a/src/infra/bonjour.ts +++ b/src/infra/bonjour.ts @@ -18,7 +18,7 @@ export type GatewayBonjourAdvertiseOpts = { }; function isDisabledByEnv() { - if (process.env.CLAWDIS_DISABLE_BONJOUR === "1") return true; + if (process.env.CLAWDBOT_DISABLE_BONJOUR === "1") return true; if (process.env.NODE_ENV === "test") return true; if (process.env.VITEST) return true; return false; @@ -26,12 +26,12 @@ function isDisabledByEnv() { function safeServiceName(name: string) { const trimmed = name.trim(); - return trimmed.length > 0 ? trimmed : "Clawdis"; + return trimmed.length > 0 ? trimmed : "Clawdbot"; } function prettifyInstanceName(name: string) { const normalized = name.trim().replace(/\s+/g, " "); - return normalized.replace(/\s+\(Clawdis\)\s*$/i, "").trim() || normalized; + return normalized.replace(/\s+\(Clawdbot\)\s*$/i, "").trim() || normalized; } type BonjourService = { @@ -94,11 +94,11 @@ export async function startGatewayBonjourAdvertiser( .hostname() .replace(/\.local$/i, "") .split(".")[0] - .trim() || "clawdis"; + .trim() || "clawdbot"; const instanceName = typeof opts.instanceName === "string" && opts.instanceName.trim() ? opts.instanceName.trim() - : `${hostname} (Clawdis)`; + : `${hostname} (Clawdbot)`; const displayName = prettifyInstanceName(instanceName); const txtBase: Record = { @@ -126,7 +126,7 @@ export async function startGatewayBonjourAdvertiser( if (typeof opts.bridgePort === "number" && opts.bridgePort > 0) { const bridge = responder.createService({ name: safeServiceName(instanceName), - type: "clawdis-bridge", + type: "clawdbot-bridge", protocol: Protocol.TCP, port: opts.bridgePort, domain: "local", diff --git a/src/infra/bridge/server.test.ts b/src/infra/bridge/server.test.ts index eff8263aa..58375bafc 100644 --- a/src/infra/bridge/server.test.ts +++ b/src/infra/bridge/server.test.ts @@ -61,13 +61,13 @@ describe("node bridge server", () => { }; beforeAll(async () => { - process.env.CLAWDIS_ENABLE_BRIDGE_IN_TESTS = "1"; - baseDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-bridge-test-")); + process.env.CLAWDBOT_ENABLE_BRIDGE_IN_TESTS = "1"; + baseDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-bridge-test-")); }); afterAll(async () => { await fs.rm(baseDir, { recursive: true, force: true }); - delete process.env.CLAWDIS_ENABLE_BRIDGE_IN_TESTS; + delete process.env.CLAWDBOT_ENABLE_BRIDGE_IN_TESTS; }); it("rejects hello when not paired", async () => { diff --git a/src/infra/bridge/server.ts b/src/infra/bridge/server.ts index 6abcdf86a..bff99abec 100644 --- a/src/infra/bridge/server.ts +++ b/src/infra/bridge/server.ts @@ -171,7 +171,7 @@ async function sleep(ms: number) { export async function startNodeBridgeServer( opts: NodeBridgeServerOpts, ): Promise { - if (isTestEnv() && process.env.CLAWDIS_ENABLE_BRIDGE_IN_TESTS !== "1") { + if (isTestEnv() && process.env.CLAWDBOT_ENABLE_BRIDGE_IN_TESTS !== "1") { return { port: 0, close: async () => {}, diff --git a/src/infra/heartbeat-runner.test.ts b/src/infra/heartbeat-runner.test.ts index c2927dd8f..c555e237b 100644 --- a/src/infra/heartbeat-runner.test.ts +++ b/src/infra/heartbeat-runner.test.ts @@ -4,7 +4,7 @@ import path from "node:path"; import { describe, expect, it, vi } from "vitest"; import { HEARTBEAT_PROMPT } from "../auto-reply/heartbeat.js"; import * as replyModule from "../auto-reply/reply.js"; -import type { ClawdisConfig } from "../config/config.js"; +import type { ClawdbotConfig } from "../config/config.js"; import { resolveHeartbeatDeliveryTarget, resolveHeartbeatIntervalMs, @@ -42,7 +42,7 @@ describe("resolveHeartbeatPrompt", () => { }); it("uses a trimmed override when configured", () => { - const cfg: ClawdisConfig = { + const cfg: ClawdbotConfig = { agent: { heartbeat: { prompt: " ping " } }, }; expect(resolveHeartbeatPrompt(cfg)).toBe("ping"); @@ -56,7 +56,7 @@ describe("resolveHeartbeatDeliveryTarget", () => { }; it("respects target none", () => { - const cfg: ClawdisConfig = { + const cfg: ClawdbotConfig = { agent: { heartbeat: { target: "none" } }, }; expect(resolveHeartbeatDeliveryTarget({ cfg, entry: baseEntry })).toEqual({ @@ -66,7 +66,7 @@ describe("resolveHeartbeatDeliveryTarget", () => { }); it("uses last route by default", () => { - const cfg: ClawdisConfig = {}; + const cfg: ClawdbotConfig = {}; const entry = { ...baseEntry, lastChannel: "whatsapp" as const, @@ -79,7 +79,7 @@ describe("resolveHeartbeatDeliveryTarget", () => { }); it("skips when last route is webchat", () => { - const cfg: ClawdisConfig = {}; + const cfg: ClawdbotConfig = {}; const entry = { ...baseEntry, lastChannel: "webchat" as const, @@ -92,7 +92,7 @@ describe("resolveHeartbeatDeliveryTarget", () => { }); it("applies allowFrom fallback for WhatsApp targets", () => { - const cfg: ClawdisConfig = { + const cfg: ClawdbotConfig = { agent: { heartbeat: { target: "whatsapp", to: "+1999" } }, whatsapp: { allowFrom: ["+1555", "+1666"] }, }; @@ -109,7 +109,7 @@ describe("resolveHeartbeatDeliveryTarget", () => { }); it("keeps explicit telegram targets", () => { - const cfg: ClawdisConfig = { + const cfg: ClawdbotConfig = { agent: { heartbeat: { target: "telegram", to: "123" } }, }; expect(resolveHeartbeatDeliveryTarget({ cfg, entry: baseEntry })).toEqual({ @@ -121,7 +121,7 @@ describe("resolveHeartbeatDeliveryTarget", () => { describe("runHeartbeatOnce", () => { it("uses the last non-empty payload for delivery", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-hb-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-")); const storePath = path.join(tmpDir, "sessions.json"); const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); try { @@ -141,7 +141,7 @@ describe("runHeartbeatOnce", () => { ), ); - const cfg: ClawdisConfig = { + const cfg: ClawdbotConfig = { agent: { heartbeat: { every: "5m", target: "whatsapp", to: "+1555" }, }, @@ -182,7 +182,7 @@ describe("runHeartbeatOnce", () => { }); it("skips WhatsApp delivery when not linked or running", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-hb-")); + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-")); const storePath = path.join(tmpDir, "sessions.json"); const replySpy = vi.spyOn(replyModule, "getReplyFromConfig"); try { @@ -202,7 +202,7 @@ describe("runHeartbeatOnce", () => { ), ); - const cfg: ClawdisConfig = { + const cfg: ClawdbotConfig = { agent: { heartbeat: { every: "5m", target: "whatsapp", to: "+1555" }, }, diff --git a/src/infra/heartbeat-runner.ts b/src/infra/heartbeat-runner.ts index 5099734a8..c78630ceb 100644 --- a/src/infra/heartbeat-runner.ts +++ b/src/infra/heartbeat-runner.ts @@ -6,7 +6,7 @@ import { import { getReplyFromConfig } from "../auto-reply/reply.js"; import type { ReplyPayload } from "../auto-reply/types.js"; import { parseDurationMs } from "../cli/parse-duration.js"; -import type { ClawdisConfig } from "../config/config.js"; +import type { ClawdbotConfig } from "../config/config.js"; import { loadConfig } from "../config/config.js"; import { loadSessionStore, @@ -79,7 +79,7 @@ export function setHeartbeatsEnabled(enabled: boolean) { } export function resolveHeartbeatIntervalMs( - cfg: ClawdisConfig, + cfg: ClawdbotConfig, overrideEvery?: string, ) { const raw = overrideEvery ?? cfg.agent?.heartbeat?.every; @@ -96,13 +96,13 @@ export function resolveHeartbeatIntervalMs( return ms; } -export function resolveHeartbeatPrompt(cfg: ClawdisConfig) { +export function resolveHeartbeatPrompt(cfg: ClawdbotConfig) { const raw = cfg.agent?.heartbeat?.prompt; const trimmed = typeof raw === "string" ? raw.trim() : ""; return trimmed || HEARTBEAT_PROMPT; } -function resolveHeartbeatSession(cfg: ClawdisConfig) { +function resolveHeartbeatSession(cfg: ClawdbotConfig) { const sessionCfg = cfg.session; const scope = sessionCfg?.scope ?? "per-sender"; const mainKey = (sessionCfg?.mainKey ?? "main").trim() || "main"; @@ -164,7 +164,7 @@ function resolveHeartbeatSender(params: { } async function resolveWhatsAppReadiness( - cfg: ClawdisConfig, + cfg: ClawdbotConfig, deps?: HeartbeatDeps, ): Promise<{ ok: boolean; reason: string }> { if (cfg.web?.enabled === false) { @@ -184,7 +184,7 @@ async function resolveWhatsAppReadiness( } export function resolveHeartbeatDeliveryTarget(params: { - cfg: ClawdisConfig; + cfg: ClawdbotConfig; entry?: SessionEntry; }): HeartbeatDeliveryTarget { const { cfg, entry } = params; @@ -417,7 +417,7 @@ async function deliverHeartbeatReply(params: { } export async function runHeartbeatOnce(opts: { - cfg?: ClawdisConfig; + cfg?: ClawdbotConfig; reason?: string; deps?: HeartbeatDeps; }): Promise { @@ -568,7 +568,7 @@ export async function runHeartbeatOnce(opts: { } export function startHeartbeatRunner(opts: { - cfg?: ClawdisConfig; + cfg?: ClawdbotConfig; runtime?: RuntimeEnv; abortSignal?: AbortSignal; }) { diff --git a/src/infra/is-main.test.ts b/src/infra/is-main.test.ts index c54a1d681..7a847f5c2 100644 --- a/src/infra/is-main.test.ts +++ b/src/infra/is-main.test.ts @@ -28,7 +28,7 @@ describe("isMainModule", () => { it("returns false when running under PM2 but this module is imported", () => { expect( isMainModule({ - currentFile: "/repo/node_modules/clawdis/dist/index.js", + currentFile: "/repo/node_modules/clawdbot/dist/index.js", argv: ["node", "/repo/app.js"], cwd: "/repo", env: { pm_exec_path: "/repo/app.js", pm_id: "0" }, diff --git a/src/infra/machine-name.ts b/src/infra/machine-name.ts index 3ff8a7bbc..04c0825a1 100644 --- a/src/infra/machine-name.ts +++ b/src/infra/machine-name.ts @@ -24,7 +24,7 @@ function fallbackHostName() { os .hostname() .replace(/\.local$/i, "") - .trim() || "clawdis" + .trim() || "clawdbot" ); } diff --git a/src/infra/node-pairing.ts b/src/infra/node-pairing.ts index 6cef7dcf6..e98a2b556 100644 --- a/src/infra/node-pairing.ts +++ b/src/infra/node-pairing.ts @@ -49,7 +49,7 @@ type NodePairingStateFile = { const PENDING_TTL_MS = 5 * 60 * 1000; function defaultBaseDir() { - return path.join(os.homedir(), ".clawdis"); + return path.join(os.homedir(), ".clawdbot"); } function resolvePaths(baseDir?: string) { diff --git a/src/infra/path-env.test.ts b/src/infra/path-env.test.ts index 7f2bf2379..a4d485d52 100644 --- a/src/infra/path-env.test.ts +++ b/src/infra/path-env.test.ts @@ -4,24 +4,24 @@ import path from "node:path"; import { describe, expect, it } from "vitest"; -import { ensureClawdisCliOnPath } from "./path-env.js"; +import { ensureClawdbotCliOnPath } from "./path-env.js"; -describe("ensureClawdisCliOnPath", () => { - it("prepends the bundled Relay dir when a sibling clawdis exists", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-path-")); +describe("ensureClawdbotCliOnPath", () => { + it("prepends the bundled Relay dir when a sibling clawdbot exists", async () => { + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-path-")); try { const relayDir = path.join(tmp, "Relay"); await fs.mkdir(relayDir, { recursive: true }); - const cliPath = path.join(relayDir, "clawdis"); + const cliPath = path.join(relayDir, "clawdbot"); await fs.writeFile(cliPath, "#!/bin/sh\necho ok\n", "utf-8"); await fs.chmod(cliPath, 0o755); const originalPath = process.env.PATH; - const originalFlag = process.env.CLAWDIS_PATH_BOOTSTRAPPED; + const originalFlag = process.env.CLAWDBOT_PATH_BOOTSTRAPPED; process.env.PATH = "/usr/bin"; - delete process.env.CLAWDIS_PATH_BOOTSTRAPPED; + delete process.env.CLAWDBOT_PATH_BOOTSTRAPPED; try { - ensureClawdisCliOnPath({ + ensureClawdbotCliOnPath({ execPath: cliPath, cwd: tmp, homeDir: tmp, @@ -32,8 +32,8 @@ describe("ensureClawdisCliOnPath", () => { } finally { process.env.PATH = originalPath; if (originalFlag === undefined) - delete process.env.CLAWDIS_PATH_BOOTSTRAPPED; - else process.env.CLAWDIS_PATH_BOOTSTRAPPED = originalFlag; + delete process.env.CLAWDBOT_PATH_BOOTSTRAPPED; + else process.env.CLAWDBOT_PATH_BOOTSTRAPPED = originalFlag; } } finally { await fs.rm(tmp, { recursive: true, force: true }); @@ -42,11 +42,11 @@ describe("ensureClawdisCliOnPath", () => { it("is idempotent", () => { const originalPath = process.env.PATH; - const originalFlag = process.env.CLAWDIS_PATH_BOOTSTRAPPED; + const originalFlag = process.env.CLAWDBOT_PATH_BOOTSTRAPPED; process.env.PATH = "/bin"; - process.env.CLAWDIS_PATH_BOOTSTRAPPED = "1"; + process.env.CLAWDBOT_PATH_BOOTSTRAPPED = "1"; try { - ensureClawdisCliOnPath({ + ensureClawdbotCliOnPath({ execPath: "/tmp/does-not-matter", cwd: "/tmp", homeDir: "/tmp", @@ -56,26 +56,26 @@ describe("ensureClawdisCliOnPath", () => { } finally { process.env.PATH = originalPath; if (originalFlag === undefined) - delete process.env.CLAWDIS_PATH_BOOTSTRAPPED; - else process.env.CLAWDIS_PATH_BOOTSTRAPPED = originalFlag; + delete process.env.CLAWDBOT_PATH_BOOTSTRAPPED; + else process.env.CLAWDBOT_PATH_BOOTSTRAPPED = originalFlag; } }); it("prepends mise shims when available", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-path-")); + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-path-")); const originalPath = process.env.PATH; - const originalFlag = process.env.CLAWDIS_PATH_BOOTSTRAPPED; + const originalFlag = process.env.CLAWDBOT_PATH_BOOTSTRAPPED; const originalMiseDataDir = process.env.MISE_DATA_DIR; try { const relayDir = path.join(tmp, "Relay"); await fs.mkdir(relayDir, { recursive: true }); - const relayCli = path.join(relayDir, "clawdis"); + const relayCli = path.join(relayDir, "clawdbot"); await fs.writeFile(relayCli, "#!/bin/sh\necho ok\n", "utf-8"); await fs.chmod(relayCli, 0o755); const localBinDir = path.join(tmp, "node_modules", ".bin"); await fs.mkdir(localBinDir, { recursive: true }); - const localCli = path.join(localBinDir, "clawdis"); + const localCli = path.join(localBinDir, "clawdbot"); await fs.writeFile(localCli, "#!/bin/sh\necho ok\n", "utf-8"); await fs.chmod(localCli, 0o755); @@ -84,9 +84,9 @@ describe("ensureClawdisCliOnPath", () => { await fs.mkdir(shimsDir, { recursive: true }); process.env.MISE_DATA_DIR = miseDataDir; process.env.PATH = "/usr/bin"; - delete process.env.CLAWDIS_PATH_BOOTSTRAPPED; + delete process.env.CLAWDBOT_PATH_BOOTSTRAPPED; - ensureClawdisCliOnPath({ + ensureClawdbotCliOnPath({ execPath: relayCli, cwd: tmp, homeDir: tmp, @@ -104,8 +104,8 @@ describe("ensureClawdisCliOnPath", () => { } finally { process.env.PATH = originalPath; if (originalFlag === undefined) - delete process.env.CLAWDIS_PATH_BOOTSTRAPPED; - else process.env.CLAWDIS_PATH_BOOTSTRAPPED = originalFlag; + delete process.env.CLAWDBOT_PATH_BOOTSTRAPPED; + else process.env.CLAWDBOT_PATH_BOOTSTRAPPED = originalFlag; if (originalMiseDataDir === undefined) delete process.env.MISE_DATA_DIR; else process.env.MISE_DATA_DIR = originalMiseDataDir; await fs.rm(tmp, { recursive: true, force: true }); diff --git a/src/infra/path-env.ts b/src/infra/path-env.ts index f7667559a..bba3d3e82 100644 --- a/src/infra/path-env.ts +++ b/src/infra/path-env.ts @@ -2,7 +2,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -type EnsureClawdisPathOpts = { +type EnsureClawdbotPathOpts = { execPath?: string; cwd?: string; homeDir?: string; @@ -47,7 +47,7 @@ function mergePath(params: { existing: string; prepend: string[] }): string { return merged.join(path.delimiter); } -function candidateBinDirs(opts: EnsureClawdisPathOpts): string[] { +function candidateBinDirs(opts: EnsureClawdbotPathOpts): string[] { const execPath = opts.execPath ?? process.execPath; const cwd = opts.cwd ?? process.cwd(); const homeDir = opts.homeDir ?? os.homedir(); @@ -55,19 +55,19 @@ function candidateBinDirs(opts: EnsureClawdisPathOpts): string[] { const candidates: string[] = []; - // Bun bundled (macOS app): `clawdis` lives in the Relay dir (process.execPath). + // Bun bundled (macOS app): `clawdbot` lives in the Relay dir (process.execPath). try { const execDir = path.dirname(execPath); - const siblingClawdis = path.join(execDir, "clawdis"); - if (isExecutable(siblingClawdis)) candidates.push(execDir); + const siblingClawdbot = path.join(execDir, "clawdbot"); + if (isExecutable(siblingClawdbot)) candidates.push(execDir); } catch { // ignore } - // Project-local installs (best effort): if a `node_modules/.bin/clawdis` exists near cwd, + // Project-local installs (best effort): if a `node_modules/.bin/clawdbot` exists near cwd, // include it. This helps when running under launchd or other minimal PATH environments. const localBinDir = path.join(cwd, "node_modules", ".bin"); - if (isExecutable(path.join(localBinDir, "clawdis"))) + if (isExecutable(path.join(localBinDir, "clawdbot"))) candidates.push(localBinDir); const miseDataDir = @@ -90,12 +90,12 @@ function candidateBinDirs(opts: EnsureClawdisPathOpts): string[] { } /** - * Best-effort PATH bootstrap so skills that require the `clawdis` CLI can run + * Best-effort PATH bootstrap so skills that require the `clawdbot` CLI can run * under launchd/minimal environments (and inside the macOS bun bundle). */ -export function ensureClawdisCliOnPath(opts: EnsureClawdisPathOpts = {}) { - if (process.env.CLAWDIS_PATH_BOOTSTRAPPED === "1") return; - process.env.CLAWDIS_PATH_BOOTSTRAPPED = "1"; +export function ensureClawdbotCliOnPath(opts: EnsureClawdbotPathOpts = {}) { + if (process.env.CLAWDBOT_PATH_BOOTSTRAPPED === "1") return; + process.env.CLAWDBOT_PATH_BOOTSTRAPPED = "1"; const existing = opts.pathEnv ?? process.env.PATH ?? ""; const prepend = candidateBinDirs(opts); diff --git a/src/infra/ports.ts b/src/infra/ports.ts index 72f901ed0..e4e83f74c 100644 --- a/src/infra/ports.ts +++ b/src/infra/ports.ts @@ -85,10 +85,10 @@ export async function handlePortError( if (details) { runtime.error(info("Port listener details:")); runtime.error(details); - if (/clawdis|src\/index\.ts|dist\/index\.js/.test(details)) { + if (/clawdbot|src\/index\.ts|dist\/index\.js/.test(details)) { runtime.error( warn( - "It looks like another clawdis instance is already running. Stop it or pick a different port.", + "It looks like another clawdbot instance is already running. Stop it or pick a different port.", ), ); } diff --git a/src/infra/provider-summary.ts b/src/infra/provider-summary.ts index f085614ff..f7aff300e 100644 --- a/src/infra/provider-summary.ts +++ b/src/infra/provider-summary.ts @@ -1,5 +1,5 @@ import chalk from "chalk"; -import { type ClawdisConfig, loadConfig } from "../config/config.js"; +import { type ClawdbotConfig, loadConfig } from "../config/config.js"; import { resolveTelegramToken } from "../telegram/token.js"; import { normalizeE164 } from "../utils.js"; import { @@ -9,7 +9,7 @@ import { } from "../web/session.js"; export async function buildProviderSummary( - cfg?: ClawdisConfig, + cfg?: ClawdbotConfig, ): Promise { const effective = cfg ?? loadConfig(); const lines: string[] = []; diff --git a/src/infra/restart.ts b/src/infra/restart.ts index 926251059..76d442ed1 100644 --- a/src/infra/restart.ts +++ b/src/infra/restart.ts @@ -1,15 +1,15 @@ import { spawnSync } from "node:child_process"; -const DEFAULT_LAUNCHD_LABEL = "com.clawdis.mac"; -const DEFAULT_SYSTEMD_UNIT = "clawdis-gateway.service"; +const DEFAULT_LAUNCHD_LABEL = "com.clawdbot.mac"; +const DEFAULT_SYSTEMD_UNIT = "clawdbot-gateway.service"; -export function triggerClawdisRestart(): +export function triggerClawdbotRestart(): | "launchctl" | "systemd" | "supervisor" { if (process.platform !== "darwin") { if (process.platform === "linux") { - const unit = process.env.CLAWDIS_SYSTEMD_UNIT || DEFAULT_SYSTEMD_UNIT; + const unit = process.env.CLAWDBOT_SYSTEMD_UNIT || DEFAULT_SYSTEMD_UNIT; const userRestart = spawnSync("systemctl", ["--user", "restart", unit], { stdio: "ignore", }); @@ -27,7 +27,7 @@ export function triggerClawdisRestart(): return "supervisor"; } - const label = process.env.CLAWDIS_LAUNCHD_LABEL || DEFAULT_LAUNCHD_LABEL; + const label = process.env.CLAWDBOT_LAUNCHD_LABEL || DEFAULT_LAUNCHD_LABEL; const uid = typeof process.getuid === "function" ? process.getuid() : undefined; const target = uid !== undefined ? `gui/${uid}/${label}` : label; diff --git a/src/infra/runtime-guard.ts b/src/infra/runtime-guard.ts index 04a45a9f6..3037e2e6c 100644 --- a/src/infra/runtime-guard.ts +++ b/src/infra/runtime-guard.ts @@ -73,11 +73,11 @@ export function assertSupportedRuntime( runtime.error( [ - "clawdis requires Node >=22.0.0.", + "clawdbot requires Node >=22.0.0.", `Detected: ${runtimeLabel} (exec: ${execLabel}).`, `PATH searched: ${details.pathEnv}`, "Install Node: https://nodejs.org/en/download", - "Upgrade Node and re-run clawdis.", + "Upgrade Node and re-run clawdbot.", ].join("\n"), ); runtime.exit(1); diff --git a/src/infra/system-presence.test.ts b/src/infra/system-presence.test.ts index 828322105..8f56acb6d 100644 --- a/src/infra/system-presence.test.ts +++ b/src/infra/system-presence.test.ts @@ -12,7 +12,7 @@ describe("system-presence", () => { const instanceIdLower = instanceIdUpper.toLowerCase(); upsertPresence(instanceIdUpper, { - host: "clawdis", + host: "clawdbot", mode: "app", instanceId: instanceIdUpper, reason: "connect", diff --git a/src/infra/system-presence.ts b/src/infra/system-presence.ts index 087358fea..a3744a11b 100644 --- a/src/infra/system-presence.ts +++ b/src/infra/system-presence.ts @@ -57,7 +57,7 @@ function initSelfPresence() { const host = os.hostname(); const ip = resolvePrimaryIPv4() ?? undefined; const version = - process.env.CLAWDIS_VERSION ?? process.env.npm_package_version ?? "unknown"; + process.env.CLAWDBOT_VERSION ?? process.env.npm_package_version ?? "unknown"; const modelIdentifier = (() => { const p = os.platform(); if (p === "darwin") { diff --git a/src/infra/tailscale.ts b/src/infra/tailscale.ts index 84df0da74..3bd7ff9ad 100644 --- a/src/infra/tailscale.ts +++ b/src/infra/tailscale.ts @@ -176,7 +176,7 @@ export async function ensureFunnel( ); runtime.error( info( - "Tip: Funnel is optional for CLAWDIS. You can keep running the web gateway without it: `pnpm clawdis gateway`", + "Tip: Funnel is optional for CLAWDBOT. You can keep running the web gateway without it: `pnpm clawdbot gateway`", ), ); if (shouldLogVerbose()) { diff --git a/src/infra/voicewake.test.ts b/src/infra/voicewake.test.ts index 9317452a5..13d39544f 100644 --- a/src/infra/voicewake.test.ts +++ b/src/infra/voicewake.test.ts @@ -13,7 +13,7 @@ import { describe("voicewake store", () => { it("returns defaults when missing", async () => { const baseDir = await fs.mkdtemp( - path.join(os.tmpdir(), "clawdis-voicewake-"), + path.join(os.tmpdir(), "clawdbot-voicewake-"), ); const cfg = await loadVoiceWakeConfig(baseDir); expect(cfg.triggers).toEqual(defaultVoiceWakeTriggers()); @@ -22,7 +22,7 @@ describe("voicewake store", () => { it("sanitizes and persists triggers", async () => { const baseDir = await fs.mkdtemp( - path.join(os.tmpdir(), "clawdis-voicewake-"), + path.join(os.tmpdir(), "clawdbot-voicewake-"), ); const saved = await setVoiceWakeTriggers( [" hi ", "", " there "], @@ -38,7 +38,7 @@ describe("voicewake store", () => { it("falls back to defaults when triggers empty", async () => { const baseDir = await fs.mkdtemp( - path.join(os.tmpdir(), "clawdis-voicewake-"), + path.join(os.tmpdir(), "clawdbot-voicewake-"), ); const saved = await setVoiceWakeTriggers(["", " "], baseDir); expect(saved.triggers).toEqual(defaultVoiceWakeTriggers()); diff --git a/src/infra/voicewake.ts b/src/infra/voicewake.ts index f6edfa656..379c634b0 100644 --- a/src/infra/voicewake.ts +++ b/src/infra/voicewake.ts @@ -11,7 +11,7 @@ export type VoiceWakeConfig = { const DEFAULT_TRIGGERS = ["clawd", "claude", "computer"]; function defaultBaseDir() { - return path.join(os.homedir(), ".clawdis"); + return path.join(os.homedir(), ".clawdbot"); } function resolvePath(baseDir?: string) { diff --git a/src/infra/widearea-dns.test.ts b/src/infra/widearea-dns.test.ts index 8b398b6ba..6f99c40c5 100644 --- a/src/infra/widearea-dns.test.ts +++ b/src/infra/widearea-dns.test.ts @@ -6,11 +6,11 @@ import { } from "./widearea-dns.js"; describe("wide-area DNS-SD zone rendering", () => { - it("renders a clawdis.internal zone with bridge PTR/SRV/TXT records", () => { + it("renders a clawdbot.internal zone with bridge PTR/SRV/TXT records", () => { const txt = renderWideAreaBridgeZoneText({ serial: 2025121701, bridgePort: 18790, - displayName: "Mac Studio (Clawdis)", + displayName: "Mac Studio (Clawdbot)", tailnetIPv4: "100.123.224.76", tailnetIPv6: "fd7a:115c:a1e0::8801:e04c", hostLabel: "studio-london", @@ -21,19 +21,19 @@ describe("wide-area DNS-SD zone rendering", () => { expect(txt).toContain(`studio-london IN A 100.123.224.76`); expect(txt).toContain(`studio-london IN AAAA fd7a:115c:a1e0::8801:e04c`); expect(txt).toContain( - `_clawdis-bridge._tcp IN PTR studio-london._clawdis-bridge._tcp`, + `_clawdbot-bridge._tcp IN PTR studio-london._clawdbot-bridge._tcp`, ); expect(txt).toContain( - `studio-london._clawdis-bridge._tcp IN SRV 0 0 18790 studio-london`, + `studio-london._clawdbot-bridge._tcp IN SRV 0 0 18790 studio-london`, ); - expect(txt).toContain(`displayName=Mac Studio (Clawdis)`); + expect(txt).toContain(`displayName=Mac Studio (Clawdbot)`); }); it("includes tailnetDns when provided", () => { const txt = renderWideAreaBridgeZoneText({ serial: 2025121701, bridgePort: 18790, - displayName: "Mac Studio (Clawdis)", + displayName: "Mac Studio (Clawdbot)", tailnetIPv4: "100.123.224.76", tailnetDns: "peters-mac-studio-1.sheep-coho.ts.net", hostLabel: "studio-london", diff --git a/src/infra/widearea-dns.ts b/src/infra/widearea-dns.ts index fdc67d52c..172802e4e 100644 --- a/src/infra/widearea-dns.ts +++ b/src/infra/widearea-dns.ts @@ -4,8 +4,8 @@ import path from "node:path"; import { CONFIG_DIR, ensureDir } from "../utils.js"; -export const WIDE_AREA_DISCOVERY_DOMAIN = "clawdis.internal."; -export const WIDE_AREA_ZONE_FILENAME = "clawdis.internal.db"; +export const WIDE_AREA_DISCOVERY_DOMAIN = "clawdbot.internal."; +export const WIDE_AREA_ZONE_FILENAME = "clawdbot.internal.db"; export function getWideAreaZonePath(): string { return path.join(CONFIG_DIR, "dns", WIDE_AREA_ZONE_FILENAME); @@ -54,7 +54,7 @@ function extractSerial(zoneText: string): number | null { } function extractContentHash(zoneText: string): string | null { - const match = zoneText.match(/^\s*;\s*clawdis-content-hash:\s*(\S+)\s*$/m); + const match = zoneText.match(/^\s*;\s*clawdbot-content-hash:\s*(\S+)\s*$/m); return match?.[1] ?? null; } @@ -79,11 +79,11 @@ export type WideAreaBridgeZoneOpts = { }; function renderZone(opts: WideAreaBridgeZoneOpts & { serial: number }): string { - const hostname = os.hostname().split(".")[0] ?? "clawdis"; - const hostLabel = dnsLabel(opts.hostLabel ?? hostname, "clawdis"); + const hostname = os.hostname().split(".")[0] ?? "clawdbot"; + const hostLabel = dnsLabel(opts.hostLabel ?? hostname, "clawdbot"); const instanceLabel = dnsLabel( opts.instanceLabel ?? `${hostname}-bridge`, - "clawdis-bridge", + "clawdbot-bridge", ); const txt = [ @@ -109,13 +109,13 @@ function renderZone(opts: WideAreaBridgeZoneOpts & { serial: number }): string { } records.push( - `_clawdis-bridge._tcp IN PTR ${instanceLabel}._clawdis-bridge._tcp`, + `_clawdbot-bridge._tcp IN PTR ${instanceLabel}._clawdbot-bridge._tcp`, ); records.push( - `${instanceLabel}._clawdis-bridge._tcp IN SRV 0 0 ${opts.bridgePort} ${hostLabel}`, + `${instanceLabel}._clawdbot-bridge._tcp IN SRV 0 0 ${opts.bridgePort} ${hostLabel}`, ); records.push( - `${instanceLabel}._clawdis-bridge._tcp IN TXT ${txt.map(txtQuote).join(" ")}`, + `${instanceLabel}._clawdbot-bridge._tcp IN TXT ${txt.map(txtQuote).join(" ")}`, ); const contentBody = `${records.join("\n")}\n`; @@ -128,7 +128,7 @@ function renderZone(opts: WideAreaBridgeZoneOpts & { serial: number }): string { .join("\n")}\n`; const contentHash = computeContentHash(hashBody); - return `; clawdis-content-hash: ${contentHash}\n${contentBody}`; + return `; clawdbot-content-hash: ${contentHash}\n${contentBody}`; } export function renderWideAreaBridgeZoneText( diff --git a/src/logger.test.ts b/src/logger.test.ts index 0f7dde097..6dea8d503 100644 --- a/src/logger.test.ts +++ b/src/logger.test.ts @@ -71,10 +71,10 @@ describe("logger helpers", () => { resetLogger(); setLoggerOverride({}); // force defaults regardless of user config const today = new Date().toISOString().slice(0, 10); - const todayPath = path.join(DEFAULT_LOG_DIR, `clawdis-${today}.log`); + const todayPath = path.join(DEFAULT_LOG_DIR, `clawdbot-${today}.log`); // create an old file to be pruned - const oldPath = path.join(DEFAULT_LOG_DIR, "clawdis-2000-01-01.log"); + const oldPath = path.join(DEFAULT_LOG_DIR, "clawdbot-2000-01-01.log"); fs.mkdirSync(DEFAULT_LOG_DIR, { recursive: true }); fs.writeFileSync(oldPath, "old"); fs.utimesSync(oldPath, new Date(0), new Date(0)); @@ -91,7 +91,7 @@ describe("logger helpers", () => { }); function pathForTest() { - const file = path.join(os.tmpdir(), `clawdis-log-${crypto.randomUUID()}.log`); + const file = path.join(os.tmpdir(), `clawdbot-log-${crypto.randomUUID()}.log`); fs.mkdirSync(path.dirname(file), { recursive: true }); return file; } diff --git a/src/logging.ts b/src/logging.ts index ac3b24246..2bb5a6845 100644 --- a/src/logging.ts +++ b/src/logging.ts @@ -4,16 +4,16 @@ import util from "node:util"; import { Chalk } from "chalk"; import { Logger as TsLogger } from "tslog"; -import { type ClawdisConfig, loadConfig } from "./config/config.js"; +import { type ClawdbotConfig, loadConfig } from "./config/config.js"; import { isVerbose } from "./globals.js"; import { defaultRuntime, type RuntimeEnv } from "./runtime.js"; // Pin to /tmp so mac Debug UI and docs match; os.tmpdir() can be a per-user // randomized path on macOS which made the “Open log” button a no-op. -export const DEFAULT_LOG_DIR = "/tmp/clawdis"; -export const DEFAULT_LOG_FILE = path.join(DEFAULT_LOG_DIR, "clawdis.log"); // legacy single-file path +export const DEFAULT_LOG_DIR = "/tmp/clawdbot"; +export const DEFAULT_LOG_FILE = path.join(DEFAULT_LOG_DIR, "clawdbot.log"); // legacy single-file path -const LOG_PREFIX = "clawdis"; +const LOG_PREFIX = "clawdbot"; const LOG_SUFFIX = ".log"; const MAX_LOG_AGE_MS = 24 * 60 * 60 * 1000; // 24h @@ -72,7 +72,7 @@ function normalizeLevel(level?: string): Level { } function resolveSettings(): ResolvedSettings { - const cfg: ClawdisConfig["logging"] | undefined = + const cfg: ClawdbotConfig["logging"] | undefined = overrideSettings ?? loadConfig().logging; const level = normalizeLevel(cfg?.level); const file = cfg?.file ?? defaultRollingPathForToday(); @@ -80,7 +80,7 @@ function resolveSettings(): ResolvedSettings { } function resolveConsoleSettings(): ConsoleSettings { - const cfg: ClawdisConfig["logging"] | undefined = + const cfg: ClawdbotConfig["logging"] | undefined = overrideSettings ?? loadConfig().logging; const level = normalizeConsoleLevel(cfg?.consoleLevel); const style = normalizeConsoleStyle(cfg?.consoleStyle); @@ -140,7 +140,7 @@ function buildLogger(settings: ResolvedSettings): TsLogger { pruneOldRollingLogs(path.dirname(settings.file)); } const logger = new TsLogger({ - name: "clawdis", + name: "clawdbot", minLevel: levelToMinLevel(settings.level), type: "hidden", // no ansi formatting }); diff --git a/src/macos/gateway-daemon.ts b/src/macos/gateway-daemon.ts index 922243e05..2f499b245 100644 --- a/src/macos/gateway-daemon.ts +++ b/src/macos/gateway-daemon.ts @@ -1,10 +1,10 @@ #!/usr/bin/env node import process from "node:process"; -declare const __CLAWDIS_VERSION__: string; +declare const __CLAWDBOT_VERSION__: string; const BUNDLED_VERSION = - typeof __CLAWDIS_VERSION__ === "string" ? __CLAWDIS_VERSION__ : "0.0.0"; + typeof __CLAWDBOT_VERSION__ === "string" ? __CLAWDBOT_VERSION__ : "0.0.0"; function argValue(args: string[], flag: string): string | undefined { const idx = args.indexOf(flag); @@ -23,7 +23,7 @@ type GatewayWsLogStyle = "auto" | "full" | "compact"; async function main() { if (hasFlag(args, "--version") || hasFlag(args, "-v")) { - // Match `clawdis --version` behavior for Swift env/version checks. + // Match `clawdbot --version` behavior for Swift env/version checks. // Keep output a single line. console.log(BUNDLED_VERSION); process.exit(0); @@ -64,7 +64,7 @@ async function main() { const cfg = loadConfig(); const portRaw = argValue(args, "--port") ?? - process.env.CLAWDIS_GATEWAY_PORT ?? + process.env.CLAWDBOT_GATEWAY_PORT ?? (typeof cfg.gateway?.port === "number" ? String(cfg.gateway.port) : "") ?? "18789"; const port = Number.parseInt(portRaw, 10); @@ -75,7 +75,7 @@ async function main() { const bindRaw = argValue(args, "--bind") ?? - process.env.CLAWDIS_GATEWAY_BIND ?? + process.env.CLAWDBOT_GATEWAY_BIND ?? cfg.gateway?.bind ?? "loopback"; const bind = @@ -93,7 +93,7 @@ async function main() { } const token = argValue(args, "--token"); - if (token) process.env.CLAWDIS_GATEWAY_TOKEN = token; + if (token) process.env.CLAWDBOT_GATEWAY_TOKEN = token; let server: Awaited> | null = null; let shuttingDown = false; diff --git a/src/macos/relay.ts b/src/macos/relay.ts index c9ad39dda..670d7316c 100644 --- a/src/macos/relay.ts +++ b/src/macos/relay.ts @@ -1,10 +1,10 @@ #!/usr/bin/env node import process from "node:process"; -declare const __CLAWDIS_VERSION__: string | undefined; +declare const __CLAWDBOT_VERSION__: string | undefined; const BUNDLED_VERSION = - typeof __CLAWDIS_VERSION__ === "string" ? __CLAWDIS_VERSION__ : "0.0.0"; + typeof __CLAWDBOT_VERSION__ === "string" ? __CLAWDBOT_VERSION__ : "0.0.0"; function hasFlag(args: string[], flag: string): boolean { return args.includes(flag); @@ -37,8 +37,8 @@ async function main() { const { default: dotenv } = await import("dotenv"); dotenv.config({ quiet: true }); - const { ensureClawdisCliOnPath } = await import("../infra/path-env.js"); - ensureClawdisCliOnPath(); + const { ensureClawdbotCliOnPath } = await import("../infra/path-env.js"); + ensureClawdbotCliOnPath(); const { enableConsoleCapture } = await import("../logging.js"); enableConsoleCapture(); @@ -51,7 +51,7 @@ async function main() { process.on("unhandledRejection", (reason, _promise) => { console.error( - "[clawdis] Unhandled promise rejection:", + "[clawdbot] Unhandled promise rejection:", reason instanceof Error ? (reason.stack ?? reason.message) : reason, ); process.exit(1); @@ -59,7 +59,7 @@ async function main() { process.on("uncaughtException", (error) => { console.error( - "[clawdis] Uncaught exception:", + "[clawdbot] Uncaught exception:", error.stack ?? error.message, ); process.exit(1); diff --git a/src/media/host.ts b/src/media/host.ts index e082859ad..5038b10a1 100644 --- a/src/media/host.ts +++ b/src/media/host.ts @@ -36,7 +36,7 @@ export async function ensureMediaHosted( if (needsServerStart && !opts.startServer) { await fs.rm(saved.path).catch(() => {}); throw new Error( - "Media hosting requires the webhook/Funnel server. Start `clawdis webhook`/`clawdis up` or re-run with --serve-media.", + "Media hosting requires the webhook/Funnel server. Start `clawdbot webhook`/`clawdbot up` or re-run with --serve-media.", ); } if (needsServerStart && opts.startServer) { diff --git a/src/media/image-ops.ts b/src/media/image-ops.ts index da272623a..02b936b18 100644 --- a/src/media/image-ops.ts +++ b/src/media/image-ops.ts @@ -17,8 +17,8 @@ function isBun(): boolean { function prefersSips(): boolean { return ( - process.env.CLAWDIS_IMAGE_BACKEND === "sips" || - (process.env.CLAWDIS_IMAGE_BACKEND !== "sharp" && + process.env.CLAWDBOT_IMAGE_BACKEND === "sips" || + (process.env.CLAWDBOT_IMAGE_BACKEND !== "sharp" && isBun() && process.platform === "darwin") ); @@ -31,7 +31,7 @@ async function loadSharp(): Promise<(buffer: Buffer) => ReturnType> { } async function withTempDir(fn: (dir: string) => Promise): Promise { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-img-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-img-")); try { return await fn(dir); } finally { diff --git a/src/media/store.header-ext.test.ts b/src/media/store.header-ext.test.ts index d24f46c2e..f04d196c3 100644 --- a/src/media/store.header-ext.test.ts +++ b/src/media/store.header-ext.test.ts @@ -3,7 +3,7 @@ import path from "node:path"; import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; const realOs = await vi.importActual("node:os"); -const HOME = path.join(realOs.tmpdir(), "clawdis-home-header-ext-test"); +const HOME = path.join(realOs.tmpdir(), "clawdbot-home-header-ext-test"); vi.mock("node:os", () => ({ default: { homedir: () => HOME, tmpdir: () => realOs.tmpdir() }, diff --git a/src/media/store.redirect.test.ts b/src/media/store.redirect.test.ts index bd7b552d6..cceae9a4d 100644 --- a/src/media/store.redirect.test.ts +++ b/src/media/store.redirect.test.ts @@ -14,7 +14,7 @@ import { } from "vitest"; const realOs = await vi.importActual("node:os"); -const HOME = path.join(realOs.tmpdir(), "clawdis-home-redirect"); +const HOME = path.join(realOs.tmpdir(), "clawdbot-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 755a7ae91..20448cfe7 100644 --- a/src/media/store.test.ts +++ b/src/media/store.test.ts @@ -5,7 +5,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(), "clawdis-home-test"); +const HOME = path.join(realOs.tmpdir(), "clawdbot-home-test"); vi.mock("node:os", () => ({ default: { homedir: () => HOME, tmpdir: () => realOs.tmpdir() }, @@ -26,7 +26,7 @@ describe("media store", () => { it("creates and returns media directory", async () => { const dir = await store.ensureMediaDir(); - expect(dir).toContain("clawdis-home-test"); + expect(dir).toContain("clawdbot-home-test"); const stat = await fs.stat(dir); expect(stat.isDirectory()).toBe(true); }); diff --git a/src/process/exec.test.ts b/src/process/exec.test.ts index 27ffe3f03..3cb917c3e 100644 --- a/src/process/exec.test.ts +++ b/src/process/exec.test.ts @@ -8,11 +8,11 @@ describe("runCommandWithTimeout", () => { [ process.execPath, "-e", - 'process.stdout.write(process.env.CLAWDIS_TEST_ENV ?? "")', + 'process.stdout.write(process.env.CLAWDBOT_TEST_ENV ?? "")', ], { timeoutMs: 5_000, - env: { CLAWDIS_TEST_ENV: "ok" }, + env: { CLAWDBOT_TEST_ENV: "ok" }, }, ); diff --git a/src/sessions/send-policy.test.ts b/src/sessions/send-policy.test.ts index 57d9da70b..7dd99ffda 100644 --- a/src/sessions/send-policy.test.ts +++ b/src/sessions/send-policy.test.ts @@ -1,18 +1,18 @@ import { describe, expect, it } from "vitest"; -import type { ClawdisConfig } from "../config/config.js"; +import type { ClawdbotConfig } from "../config/config.js"; import type { SessionEntry } from "../config/sessions.js"; import { resolveSendPolicy } from "./send-policy.js"; describe("resolveSendPolicy", () => { it("defaults to allow", () => { - const cfg = {} as ClawdisConfig; + const cfg = {} as ClawdbotConfig; expect(resolveSendPolicy({ cfg })).toBe("allow"); }); it("entry override wins", () => { const cfg = { session: { sendPolicy: { default: "allow" } }, - } as ClawdisConfig; + } as ClawdbotConfig; const entry: SessionEntry = { sessionId: "s", updatedAt: 0, @@ -34,7 +34,7 @@ describe("resolveSendPolicy", () => { ], }, }, - } as ClawdisConfig; + } as ClawdbotConfig; const entry: SessionEntry = { sessionId: "s", updatedAt: 0, @@ -54,7 +54,7 @@ describe("resolveSendPolicy", () => { rules: [{ action: "deny", match: { keyPrefix: "cron:" } }], }, }, - } as ClawdisConfig; + } as ClawdbotConfig; expect(resolveSendPolicy({ cfg, sessionKey: "cron:job-1" })).toBe("deny"); }); }); diff --git a/src/sessions/send-policy.ts b/src/sessions/send-policy.ts index 2dcf299c1..10b5311fc 100644 --- a/src/sessions/send-policy.ts +++ b/src/sessions/send-policy.ts @@ -1,4 +1,4 @@ -import type { ClawdisConfig } from "../config/config.js"; +import type { ClawdbotConfig } from "../config/config.js"; import type { SessionChatType, SessionEntry } from "../config/sessions.js"; export type SessionSendPolicyDecision = "allow" | "deny"; @@ -34,7 +34,7 @@ function deriveChatTypeFromKey(key?: string): SessionChatType | undefined { } export function resolveSendPolicy(params: { - cfg: ClawdisConfig; + cfg: ClawdbotConfig; entry?: SessionEntry; sessionKey?: string; surface?: string; diff --git a/src/telegram/bot.media.test.ts b/src/telegram/bot.media.test.ts index 31f726e45..cf474e08e 100644 --- a/src/telegram/bot.media.test.ts +++ b/src/telegram/bot.media.test.ts @@ -89,7 +89,7 @@ describe("telegram inbound media", () => { photo: [{ file_id: "fid" }], date: 1736380800, // 2025-01-09T00:00:00Z }, - me: { username: "clawdis_bot" }, + me: { username: "clawdbot_bot" }, getFile: async () => ({ file_path: "photos/1.jpg" }), }); @@ -145,7 +145,7 @@ describe("telegram inbound media", () => { chat: { id: 1234, type: "private" }, photo: [{ file_id: "fid" }], }, - me: { username: "clawdis_bot" }, + me: { username: "clawdbot_bot" }, getFile: async () => ({ file_path: "photos/2.jpg" }), }); @@ -191,7 +191,7 @@ describe("telegram inbound media", () => { chat: { id: 1234, type: "private" }, photo: [{ file_id: "fid" }], }, - me: { username: "clawdis_bot" }, + me: { username: "clawdbot_bot" }, getFile: async () => ({}), }); diff --git a/src/telegram/bot.test.ts b/src/telegram/bot.test.ts index e27273507..b113c892b 100644 --- a/src/telegram/bot.test.ts +++ b/src/telegram/bot.test.ts @@ -90,7 +90,7 @@ describe("createTelegramBot", () => { }; await handler({ message, - me: { username: "clawdis_bot" }, + me: { username: "clawdbot_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -115,7 +115,7 @@ describe("createTelegramBot", () => { ) => Promise; await handler({ message: { chat: { id: 42, type: "private" }, text: "hi" }, - me: { username: "clawdis_bot" }, + me: { username: "clawdbot_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -146,7 +146,7 @@ describe("createTelegramBot", () => { from: { first_name: "Ada" }, }, }, - me: { username: "clawdis_bot" }, + me: { username: "clawdbot_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -179,7 +179,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_id: 101, }, - me: { username: "clawdis_bot" }, + me: { username: "clawdbot_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -212,7 +212,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_id: 101, }, - me: { username: "clawdis_bot" }, + me: { username: "clawdbot_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -247,7 +247,7 @@ describe("createTelegramBot", () => { date: 1736380800, message_id: 101, }, - me: { username: "clawdis_bot" }, + me: { username: "clawdbot_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -278,7 +278,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "clawdis_bot" }, + me: { username: "clawdbot_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -311,7 +311,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "clawdis_bot" }, + me: { username: "clawdbot_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); @@ -341,7 +341,7 @@ describe("createTelegramBot", () => { text: "hello", date: 1736380800, }, - me: { username: "clawdis_bot" }, + me: { username: "clawdbot_bot" }, getFile: async () => ({ download: async () => new Uint8Array() }), }); diff --git a/src/telegram/token.test.ts b/src/telegram/token.test.ts index bb117dceb..8ea73719f 100644 --- a/src/telegram/token.test.ts +++ b/src/telegram/token.test.ts @@ -4,11 +4,11 @@ import path from "node:path"; import { afterEach, describe, expect, it, vi } from "vitest"; -import type { ClawdisConfig } from "../config/config.js"; +import type { ClawdbotConfig } from "../config/config.js"; import { resolveTelegramToken } from "./token.js"; function withTempDir(): string { - return fs.mkdtempSync(path.join(os.tmpdir(), "clawdis-telegram-token-")); + return fs.mkdtempSync(path.join(os.tmpdir(), "clawdbot-telegram-token-")); } describe("resolveTelegramToken", () => { @@ -18,7 +18,7 @@ describe("resolveTelegramToken", () => { it("prefers env token over config", () => { vi.stubEnv("TELEGRAM_BOT_TOKEN", "env-token"); - const cfg = { telegram: { botToken: "cfg-token" } } as ClawdisConfig; + const cfg = { telegram: { botToken: "cfg-token" } } as ClawdbotConfig; const res = resolveTelegramToken(cfg); expect(res.token).toBe("env-token"); expect(res.source).toBe("env"); @@ -29,7 +29,7 @@ describe("resolveTelegramToken", () => { const dir = withTempDir(); const tokenFile = path.join(dir, "token.txt"); fs.writeFileSync(tokenFile, "file-token\n", "utf-8"); - const cfg = { telegram: { tokenFile } } as ClawdisConfig; + const cfg = { telegram: { tokenFile } } as ClawdbotConfig; const res = resolveTelegramToken(cfg); expect(res.token).toBe("file-token"); expect(res.source).toBe("tokenFile"); @@ -38,7 +38,7 @@ describe("resolveTelegramToken", () => { it("falls back to config token when no env or tokenFile", () => { vi.stubEnv("TELEGRAM_BOT_TOKEN", ""); - const cfg = { telegram: { botToken: "cfg-token" } } as ClawdisConfig; + const cfg = { telegram: { botToken: "cfg-token" } } as ClawdbotConfig; const res = resolveTelegramToken(cfg); expect(res.token).toBe("cfg-token"); expect(res.source).toBe("config"); @@ -50,7 +50,7 @@ describe("resolveTelegramToken", () => { const tokenFile = path.join(dir, "missing-token.txt"); const cfg = { telegram: { tokenFile, botToken: "cfg-token" }, - } as ClawdisConfig; + } as ClawdbotConfig; const res = resolveTelegramToken(cfg); expect(res.token).toBe(""); expect(res.source).toBe("none"); diff --git a/src/telegram/token.ts b/src/telegram/token.ts index b82d35ab8..88dd194e6 100644 --- a/src/telegram/token.ts +++ b/src/telegram/token.ts @@ -1,6 +1,6 @@ import fs from "node:fs"; -import type { ClawdisConfig } from "../config/config.js"; +import type { ClawdbotConfig } from "../config/config.js"; export type TelegramTokenSource = "env" | "tokenFile" | "config" | "none"; @@ -15,7 +15,7 @@ type ResolveTelegramTokenOpts = { }; export function resolveTelegramToken( - cfg?: ClawdisConfig, + cfg?: ClawdbotConfig, opts: ResolveTelegramTokenOpts = {}, ): TelegramTokenResolution { const envToken = (opts.envToken ?? process.env.TELEGRAM_BOT_TOKEN)?.trim(); diff --git a/src/tui/gateway-chat.ts b/src/tui/gateway-chat.ts index 219cd1fd2..b55af013a 100644 --- a/src/tui/gateway-chat.ts +++ b/src/tui/gateway-chat.ts @@ -87,7 +87,7 @@ export class GatewayChatClient { url: resolved.url, token: resolved.token, password: resolved.password, - clientName: "clawdis-tui", + clientName: "clawdbot-tui", clientVersion: VERSION, platform: process.platform, mode: "tui", @@ -210,7 +210,7 @@ export function resolveGatewayConnection(opts: GatewayConnectionOptions) { ? typeof remote?.token === "string" && remote.token.trim().length > 0 ? remote.token.trim() : undefined - : process.env.CLAWDIS_GATEWAY_TOKEN?.trim() || + : process.env.CLAWDBOT_GATEWAY_TOKEN?.trim() || (typeof authToken === "string" && authToken.trim().length > 0 ? authToken.trim() : undefined)); @@ -219,7 +219,7 @@ export function resolveGatewayConnection(opts: GatewayConnectionOptions) { (typeof opts.password === "string" && opts.password.trim().length > 0 ? opts.password.trim() : undefined) || - process.env.CLAWDIS_GATEWAY_PASSWORD?.trim() || + process.env.CLAWDBOT_GATEWAY_PASSWORD?.trim() || (typeof remote?.password === "string" && remote.password.trim().length > 0 ? remote.password.trim() : undefined); diff --git a/src/tui/tui.ts b/src/tui/tui.ts index 722ddd507..5ff7bafd0 100644 --- a/src/tui/tui.ts +++ b/src/tui/tui.ts @@ -146,7 +146,7 @@ export async function runTui(opts: TuiOptions) { const updateHeader = () => { header.setText( theme.header( - `clawdis tui - ${client.connection.url} - session ${currentSessionKey}`, + `clawdbot tui - ${client.connection.url} - session ${currentSessionKey}`, ), ); }; diff --git a/src/utils.test.ts b/src/utils.test.ts index fdd232fdd..bef3ea296 100644 --- a/src/utils.test.ts +++ b/src/utils.test.ts @@ -38,7 +38,7 @@ describe("withWhatsAppPrefix", () => { describe("ensureDir", () => { it("creates nested directory", async () => { const tmp = await fs.promises.mkdtemp( - path.join(os.tmpdir(), "clawdis-test-"), + path.join(os.tmpdir(), "clawdbot-test-"), ); const target = path.join(tmp, "nested", "dir"); await ensureDir(target); diff --git a/src/utils.ts b/src/utils.ts index 801784fa6..ad4001bc0 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -133,5 +133,5 @@ export function shortenHomeInString(input: string): string { return input.split(home).join("~"); } -// Fixed configuration root; legacy ~/.clawdis is no longer used. -export const CONFIG_DIR = path.join(os.homedir(), ".clawdis"); +// Fixed configuration root; legacy ~/.clawdbot is no longer used. +export const CONFIG_DIR = path.join(os.homedir(), ".clawdbot"); diff --git a/src/version.ts b/src/version.ts index a132c208e..958caf450 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1,6 +1,6 @@ import { createRequire } from "node:module"; -declare const __CLAWDIS_VERSION__: string | undefined; +declare const __CLAWDBOT_VERSION__: string | undefined; function readVersionFromPackageJson(): string | null { try { @@ -12,11 +12,11 @@ function readVersionFromPackageJson(): string | null { } } -// Single source of truth for the current clawdis version. +// Single source of truth for the current clawdbot version. // - Embedded/bundled builds: injected define or env var. // - Dev/npm builds: package.json. export const VERSION = - (typeof __CLAWDIS_VERSION__ === "string" && __CLAWDIS_VERSION__) || - process.env.CLAWDIS_BUNDLED_VERSION || + (typeof __CLAWDBOT_VERSION__ === "string" && __CLAWDBOT_VERSION__) || + process.env.CLAWDBOT_BUNDLED_VERSION || readVersionFromPackageJson() || "0.0.0"; diff --git a/src/web/auto-reply.test.ts b/src/web/auto-reply.test.ts index 61964f736..05fd023a9 100644 --- a/src/web/auto-reply.test.ts +++ b/src/web/auto-reply.test.ts @@ -18,7 +18,7 @@ vi.mock("../agents/pi-embedded.js", () => ({ import { runEmbeddedPiAgent } from "../agents/pi-embedded.js"; import { getReplyFromConfig } from "../auto-reply/reply.js"; -import type { ClawdisConfig } from "../config/config.js"; +import type { ClawdbotConfig } from "../config/config.js"; import { resetLogger, setLoggerOverride } from "../logging.js"; import { HEARTBEAT_TOKEN, @@ -58,7 +58,7 @@ const rmDirWithRetries = async (dir: string): Promise => { beforeEach(async () => { previousHome = process.env.HOME; - tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-web-home-")); + tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-web-home-")); process.env.HOME = tempHome; }); @@ -73,7 +73,7 @@ afterEach(async () => { const makeSessionStore = async ( entries: Record = {}, ): Promise<{ storePath: string; cleanup: () => Promise }> => { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-session-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-session-")); const storePath = path.join(dir, "sessions.json"); await fs.writeFile(storePath, JSON.stringify(entries)); const cleanup = async () => { @@ -112,7 +112,7 @@ describe("partial reply gating", () => { const replyResolver = vi.fn().mockResolvedValue({ text: "final reply" }); - const mockConfig: ClawdisConfig = { + const mockConfig: ClawdbotConfig = { whatsapp: { allowFrom: ["*"], }, @@ -159,7 +159,7 @@ describe("partial reply gating", () => { const replyResolver = vi.fn().mockResolvedValue(undefined); - const mockConfig: ClawdisConfig = { + const mockConfig: ClawdbotConfig = { whatsapp: { allowFrom: ["*"], }, @@ -500,11 +500,11 @@ describe("web auto-reply", () => { const firstArgs = resolver.mock.calls[0][0]; const secondArgs = resolver.mock.calls[1][0]; expect(firstArgs.Body).toContain( - "[WhatsApp +1 2025-01-01T01:00+01:00{Europe/Vienna}] [clawdis] first", + "[WhatsApp +1 2025-01-01T01:00+01:00{Europe/Vienna}] [clawdbot] first", ); expect(firstArgs.Body).not.toContain("second"); expect(secondArgs.Body).toContain( - "[WhatsApp +1 2025-01-01T02:00+01:00{Europe/Vienna}] [clawdis] second", + "[WhatsApp +1 2025-01-01T02:00+01:00{Europe/Vienna}] [clawdbot] second", ); expect(secondArgs.Body).not.toContain("first"); @@ -1265,7 +1265,7 @@ describe("web auto-reply", () => { it("emits heartbeat logs with connection metadata", async () => { vi.useFakeTimers(); - const logPath = `/tmp/clawdis-heartbeat-${crypto.randomUUID()}.log`; + const logPath = `/tmp/clawdbot-heartbeat-${crypto.randomUUID()}.log`; setLoggerOverride({ level: "trace", file: logPath }); const runtime = { @@ -1307,7 +1307,7 @@ describe("web auto-reply", () => { }); it("logs outbound replies to file", async () => { - const logPath = `/tmp/clawdis-log-test-${crypto.randomUUID()}.log`; + const logPath = `/tmp/clawdbot-log-test-${crypto.randomUUID()}.log`; setLoggerOverride({ level: "trace", file: logPath }); let capturedOnMessage: diff --git a/src/web/auto-reply.ts b/src/web/auto-reply.ts index 19797a978..816ce0b2c 100644 --- a/src/web/auto-reply.ts +++ b/src/web/auto-reply.ts @@ -943,7 +943,7 @@ export async function monitorWebProvider( let messagePrefix = cfg.messages?.messagePrefix; if (messagePrefix === undefined) { const hasAllowFrom = (cfg.whatsapp?.allowFrom?.length ?? 0) > 0; - messagePrefix = hasAllowFrom ? "" : "[clawdis]"; + messagePrefix = hasAllowFrom ? "" : "[clawdbot]"; } const prefixStr = messagePrefix ? `${messagePrefix} ` : ""; const senderLabel = @@ -1552,7 +1552,7 @@ export async function monitorWebProvider( if (loggedOut) { runtime.error( - "WhatsApp session logged out. Run `clawdis login --provider web` to relink.", + "WhatsApp session logged out. Run `clawdbot login --provider web` to relink.", ); await closeListener(); break; diff --git a/src/web/inbound.media.test.ts b/src/web/inbound.media.test.ts index d350bdad7..031bb114d 100644 --- a/src/web/inbound.media.test.ts +++ b/src/web/inbound.media.test.ts @@ -20,7 +20,7 @@ vi.mock("../config/config.js", () => ({ const HOME = path.join( os.tmpdir(), - `clawdis-inbound-media-${crypto.randomUUID()}`, + `clawdbot-inbound-media-${crypto.randomUUID()}`, ); process.env.HOME = HOME; diff --git a/src/web/login.ts b/src/web/login.ts index bd9034907..9abbf4909 100644 --- a/src/web/login.ts +++ b/src/web/login.ts @@ -59,7 +59,7 @@ export async function loginWeb( await fs.rm(resolveWebAuthDir(), { recursive: true, force: true }); console.error( danger( - "WhatsApp reported the session is logged out. Cleared cached web session; please rerun clawdis login and scan the QR again.", + "WhatsApp reported the session is logged out. Cleared cached web session; please rerun clawdbot login and scan the QR again.", ), ); throw new Error("Session logged out; cache cleared. Re-run login."); diff --git a/src/web/logout.test.ts b/src/web/logout.test.ts index 4ed53edd1..af8dea03e 100644 --- a/src/web/logout.test.ts +++ b/src/web/logout.test.ts @@ -17,7 +17,7 @@ describe("web logout", () => { beforeEach(() => { vi.clearAllMocks(); - tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "clawdis-logout-")); + tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "clawdbot-logout-")); vi.spyOn(os, "homedir").mockReturnValue(tmpDir); vi.resetModules(); vi.doMock("../utils.js", async () => { @@ -25,7 +25,7 @@ describe("web logout", () => { await vi.importActual("../utils.js"); return { ...actual, - CONFIG_DIR: path.join(tmpDir, ".clawdis"), + CONFIG_DIR: path.join(tmpDir, ".clawdbot"), }; }); }); @@ -45,12 +45,12 @@ describe("web logout", () => { "deletes cached credentials when present", { timeout: 15_000 }, async () => { - const credsDir = path.join(tmpDir, ".clawdis", "credentials"); + const credsDir = path.join(tmpDir, ".clawdbot", "credentials"); fs.mkdirSync(credsDir, { recursive: true }); fs.writeFileSync(path.join(credsDir, "creds.json"), "{}"); const sessionsPath = path.join( tmpDir, - ".clawdis", + ".clawdbot", "sessions", "sessions.json", ); diff --git a/src/web/media.test.ts b/src/web/media.test.ts index e5a6f394c..8cf90da8b 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(), `clawdis-media-${Date.now()}.jpg`); + const file = path.join(os.tmpdir(), `clawdbot-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(), `clawdis-media-${Date.now()}.bin`); + const wrongExt = path.join(os.tmpdir(), `clawdbot-media-${Date.now()}.bin`); tmpFiles.push(wrongExt); await fs.writeFile(wrongExt, pngBuffer); @@ -110,7 +110,7 @@ describe("web media loading", () => { 0x3b, // minimal LZW data + trailer ]); - const file = path.join(os.tmpdir(), `clawdis-media-${Date.now()}.gif`); + const file = path.join(os.tmpdir(), `clawdbot-media-${Date.now()}.gif`); tmpFiles.push(file); await fs.writeFile(file, gifBuffer); diff --git a/src/web/monitor-inbox.test.ts b/src/web/monitor-inbox.test.ts index d8f3886ea..9220e5cfc 100644 --- a/src/web/monitor-inbox.test.ts +++ b/src/web/monitor-inbox.test.ts @@ -322,7 +322,7 @@ describe("web monitor inbox", () => { it("logs inbound bodies to file", async () => { const logPath = path.join( os.tmpdir(), - `clawdis-log-test-${crypto.randomUUID()}.log`, + `clawdbot-log-test-${crypto.randomUUID()}.log`, ); setLoggerOverride({ level: "trace", file: logPath }); diff --git a/src/web/qr-image.test.ts b/src/web/qr-image.test.ts index 157025025..8b0d585a4 100644 --- a/src/web/qr-image.test.ts +++ b/src/web/qr-image.test.ts @@ -4,7 +4,7 @@ import { renderQrPngBase64 } from "./qr-image.js"; describe("renderQrPngBase64", () => { it("renders a PNG data payload", async () => { - const b64 = await renderQrPngBase64("clawdis"); + const b64 = await renderQrPngBase64("clawdbot"); const buf = Buffer.from(b64, "base64"); expect(buf.subarray(0, 8).toString("hex")).toBe("89504e470d0a1a0a"); }); diff --git a/src/web/reconnect.test.ts b/src/web/reconnect.test.ts index 19ecb71e0..ef64c732a 100644 --- a/src/web/reconnect.test.ts +++ b/src/web/reconnect.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import type { ClawdisConfig } from "../config/config.js"; +import type { ClawdbotConfig } from "../config/config.js"; import { computeBackoff, DEFAULT_HEARTBEAT_SECONDS, @@ -11,7 +11,7 @@ import { } from "./reconnect.js"; describe("web reconnect helpers", () => { - const cfg: ClawdisConfig = {}; + const cfg: ClawdbotConfig = {}; it("resolves sane reconnect defaults with clamps", () => { const policy = resolveReconnectPolicy(cfg, { diff --git a/src/web/reconnect.ts b/src/web/reconnect.ts index e6fd487c9..8f8322528 100644 --- a/src/web/reconnect.ts +++ b/src/web/reconnect.ts @@ -1,6 +1,6 @@ import { randomUUID } from "node:crypto"; -import type { ClawdisConfig } from "../config/config.js"; +import type { ClawdbotConfig } from "../config/config.js"; export type ReconnectPolicy = { initialMs: number; @@ -23,7 +23,7 @@ const clamp = (val: number, min: number, max: number) => Math.max(min, Math.min(max, val)); export function resolveHeartbeatSeconds( - cfg: ClawdisConfig, + cfg: ClawdbotConfig, overrideSeconds?: number, ): number { const candidate = overrideSeconds ?? cfg.web?.heartbeatSeconds; @@ -32,7 +32,7 @@ export function resolveHeartbeatSeconds( } export function resolveReconnectPolicy( - cfg: ClawdisConfig, + cfg: ClawdbotConfig, overrides?: Partial, ): ReconnectPolicy { const reconnectOverrides = cfg.web?.reconnect ?? {}; diff --git a/src/web/session.test.ts b/src/web/session.test.ts index 6aa2e91d3..eff62109f 100644 --- a/src/web/session.test.ts +++ b/src/web/session.test.ts @@ -111,7 +111,7 @@ describe("web session", () => { }); it("does not clobber creds backup when creds.json is corrupted", async () => { - const credsSuffix = path.join(".clawdis", "credentials", "creds.json"); + const credsSuffix = path.join(".clawdbot", "credentials", "creds.json"); const copySpy = vi .spyOn(fsSync, "copyFileSync") @@ -191,8 +191,8 @@ describe("web session", () => { }); it("rotates creds backup when creds.json is valid JSON", async () => { - const credsSuffix = path.join(".clawdis", "credentials", "creds.json"); - const backupSuffix = path.join(".clawdis", "credentials", "creds.json.bak"); + const credsSuffix = path.join(".clawdbot", "credentials", "creds.json"); + const backupSuffix = path.join(".clawdbot", "credentials", "creds.json.bak"); const copySpy = vi .spyOn(fsSync, "copyFileSync") diff --git a/src/web/session.ts b/src/web/session.ts index 6e90182e5..310dd0d62 100644 --- a/src/web/session.ts +++ b/src/web/session.ts @@ -21,7 +21,7 @@ import { CONFIG_DIR, ensureDir, jidToE164 } from "../utils.js"; import { VERSION } from "../version.js"; export function resolveWebAuthDir() { - return path.join(os.homedir(), ".clawdis", "credentials"); + return path.join(os.homedir(), ".clawdbot", "credentials"); } function resolveWebCredsPath() { @@ -143,7 +143,7 @@ export async function createWaSocket( version, logger, printQRInTerminal: false, - browser: ["clawdis", "cli", VERSION], + browser: ["clawdbot", "cli", VERSION], syncFullHistory: false, markOnlineOnConnect: false, }); @@ -165,7 +165,7 @@ export async function createWaSocket( const status = getStatusCode(lastDisconnect?.error); if (status === DisconnectReason.loggedOut) { console.error( - danger("WhatsApp session logged out. Run: clawdis login"), + danger("WhatsApp session logged out. Run: clawdbot login"), ); } } @@ -413,7 +413,7 @@ export async function pickProvider(pref: Provider | "auto"): Promise { const hasWeb = await webAuthExists(); if (!hasWeb) { throw new Error( - "No WhatsApp Web session found. Run `clawdis login --verbose` to link.", + "No WhatsApp Web session found. Run `clawdbot login --verbose` to link.", ); } return choice; diff --git a/src/web/test-helpers.ts b/src/web/test-helpers.ts index 09cf84c57..ed01b0f8e 100644 --- a/src/web/test-helpers.ts +++ b/src/web/test-helpers.ts @@ -4,7 +4,7 @@ import type { MockBaileysSocket } from "../../test/mocks/baileys.js"; import { createMockBaileys } from "../../test/mocks/baileys.js"; // Use globalThis to store the mock config so it survives vi.mock hoisting -const CONFIG_KEY = Symbol.for("clawdis:testConfigMock"); +const CONFIG_KEY = Symbol.for("clawdbot:testConfigMock"); const DEFAULT_CONFIG = { whatsapp: { // Tests can override; default remains open to avoid surprising fixtures @@ -53,7 +53,7 @@ vi.mock("../media/store.js", () => ({ vi.mock("@whiskeysockets/baileys", () => { const created = createMockBaileys(); (globalThis as Record)[ - Symbol.for("clawdis:lastSocket") + Symbol.for("clawdbot:lastSocket") ] = created.lastSocket; return created.mod; }); @@ -75,7 +75,7 @@ export const baileys = (await import( export function resetBaileysMocks() { const recreated = createMockBaileys(); (globalThis as Record)[ - Symbol.for("clawdis:lastSocket") + Symbol.for("clawdbot:lastSocket") ] = recreated.lastSocket; baileys.makeWASocket.mockImplementation(recreated.mod.makeWASocket); baileys.useMultiFileAuthState.mockImplementation( @@ -91,7 +91,7 @@ export function resetBaileysMocks() { export function getLastSocket(): MockBaileysSocket { const getter = (globalThis as Record)[ - Symbol.for("clawdis:lastSocket") + Symbol.for("clawdbot:lastSocket") ]; if (typeof getter === "function") return (getter as () => MockBaileysSocket)(); diff --git a/src/wizard/onboarding.ts b/src/wizard/onboarding.ts index 13a1a27a3..9bd4f6d6e 100644 --- a/src/wizard/onboarding.ts +++ b/src/wizard/onboarding.ts @@ -33,9 +33,9 @@ import type { OnboardOptions, ResetScope, } from "../commands/onboard-types.js"; -import type { ClawdisConfig } from "../config/config.js"; +import type { ClawdbotConfig } from "../config/config.js"; import { - CONFIG_PATH_CLAWDIS, + CONFIG_PATH_CLAWDBOT, readConfigFileSnapshot, resolveGatewayPort, writeConfigFile, @@ -54,10 +54,10 @@ export async function runOnboardingWizard( prompter: WizardPrompter, ) { printWizardHeader(runtime); - await prompter.intro("Clawdis onboarding"); + await prompter.intro("Clawdbot onboarding"); const snapshot = await readConfigFileSnapshot(); - let baseConfig: ClawdisConfig = snapshot.valid ? snapshot.config : {}; + let baseConfig: ClawdbotConfig = snapshot.valid ? snapshot.config : {}; if (snapshot.exists) { const title = snapshot.valid @@ -109,10 +109,10 @@ export async function runOnboardingWizard( const localUrl = `ws://127.0.0.1:${localPort}`; const localProbe = await probeGatewayReachable({ url: localUrl, - token: process.env.CLAWDIS_GATEWAY_TOKEN, + token: process.env.CLAWDBOT_GATEWAY_TOKEN, password: baseConfig.gateway?.auth?.password ?? - process.env.CLAWDIS_GATEWAY_PASSWORD, + process.env.CLAWDBOT_GATEWAY_PASSWORD, }); const remoteUrl = baseConfig.gateway?.remote?.url?.trim() ?? ""; const remoteProbe = remoteUrl @@ -150,7 +150,7 @@ export async function runOnboardingWizard( let nextConfig = await promptRemoteGatewayConfig(baseConfig, prompter); nextConfig = applyWizardMetadata(nextConfig, { command: "onboard", mode }); await writeConfigFile(nextConfig); - runtime.log(`Updated ${CONFIG_PATH_CLAWDIS}`); + runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`); await prompter.outro("Remote gateway configured."); return; } @@ -166,7 +166,7 @@ export async function runOnboardingWizard( workspaceInput.trim() || DEFAULT_WORKSPACE, ); - let nextConfig: ClawdisConfig = { + let nextConfig: ClawdbotConfig = { ...baseConfig, agent: { ...baseConfig.agent, @@ -424,7 +424,7 @@ export async function runOnboardingWizard( }); await writeConfigFile(nextConfig); - runtime.log(`Updated ${CONFIG_PATH_CLAWDIS}`); + runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`); await ensureWorkspaceAndSessions(workspaceDir, runtime); nextConfig = await setupSkills(nextConfig, workspaceDir, runtime, prompter); @@ -466,8 +466,8 @@ export async function runOnboardingWizard( await resolveGatewayProgramArguments({ port, dev: devMode }); const environment: Record = { PATH: process.env.PATH, - CLAWDIS_GATEWAY_TOKEN: gatewayToken, - CLAWDIS_LAUNCHD_LABEL: + CLAWDBOT_GATEWAY_TOKEN: gatewayToken, + CLAWDBOT_LAUNCHD_LABEL: process.platform === "darwin" ? GATEWAY_LAUNCH_AGENT_LABEL : undefined, diff --git a/test/gateway.multi.e2e.test.ts b/test/gateway.multi.e2e.test.ts index 7d5b08790..f3510f6be 100644 --- a/test/gateway.multi.e2e.test.ts +++ b/test/gateway.multi.e2e.test.ts @@ -100,11 +100,11 @@ const spawnGatewayInstance = async (name: string): Promise => { const bridgePort = await getFreePort(); const hookToken = `token-${name}-${randomUUID()}`; const homeDir = await fs.mkdtemp( - path.join(os.tmpdir(), `clawdis-e2e-${name}-`), + path.join(os.tmpdir(), `clawdbot-e2e-${name}-`), ); - const configDir = path.join(homeDir, ".clawdis"); + const configDir = path.join(homeDir, ".clawdbot"); await fs.mkdir(configDir, { recursive: true }); - const configPath = path.join(configDir, "clawdis.json"); + const configPath = path.join(configDir, "clawdbot.json"); const config = { gateway: { port }, hooks: { enabled: true, token: hookToken, path: "/hooks" }, @@ -135,16 +135,16 @@ const spawnGatewayInstance = async (name: string): Promise => { env: { ...process.env, HOME: homeDir, - CLAWDIS_CONFIG_PATH: configPath, - CLAWDIS_STATE_DIR: path.join(homeDir, ".clawdis", "state"), - CLAWDIS_GATEWAY_TOKEN: "", - CLAWDIS_GATEWAY_PASSWORD: "", - CLAWDIS_SKIP_PROVIDERS: "1", - CLAWDIS_SKIP_BROWSER_CONTROL_SERVER: "1", - CLAWDIS_SKIP_CANVAS_HOST: "1", - CLAWDIS_ENABLE_BRIDGE_IN_TESTS: "1", - CLAWDIS_BRIDGE_HOST: "127.0.0.1", - CLAWDIS_BRIDGE_PORT: String(bridgePort), + CLAWDBOT_CONFIG_PATH: configPath, + CLAWDBOT_STATE_DIR: path.join(homeDir, ".clawdbot", "state"), + CLAWDBOT_GATEWAY_TOKEN: "", + CLAWDBOT_GATEWAY_PASSWORD: "", + CLAWDBOT_SKIP_PROVIDERS: "1", + CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER: "1", + CLAWDBOT_SKIP_CANVAS_HOST: "1", + CLAWDBOT_ENABLE_BRIDGE_IN_TESTS: "1", + CLAWDBOT_BRIDGE_HOST: "127.0.0.1", + CLAWDBOT_BRIDGE_PORT: String(bridgePort), }, stdio: ["ignore", "pipe", "pipe"], }, @@ -375,7 +375,7 @@ const pairNode = async (inst: GatewayInstance, nodeId: string) => { version: "1.0.0", }); - const baseDir = path.join(inst.homeDir, ".clawdis"); + const baseDir = path.join(inst.homeDir, ".clawdbot"); const requestId = await waitForPairRequest(baseDir, nodeId); const approved = await approveNodePairing(requestId, baseDir); expect(approved).toBeTruthy(); @@ -414,14 +414,14 @@ describe("gateway multi-instance e2e", () => { const [healthA, healthB] = (await Promise.all([ runCliJson(["health", "--json", "--timeout", "10000"], { - CLAWDIS_GATEWAY_PORT: String(gwA.port), - CLAWDIS_GATEWAY_TOKEN: "", - CLAWDIS_GATEWAY_PASSWORD: "", + CLAWDBOT_GATEWAY_PORT: String(gwA.port), + CLAWDBOT_GATEWAY_TOKEN: "", + CLAWDBOT_GATEWAY_PASSWORD: "", }), runCliJson(["health", "--json", "--timeout", "10000"], { - CLAWDIS_GATEWAY_PORT: String(gwB.port), - CLAWDIS_GATEWAY_TOKEN: "", - CLAWDIS_GATEWAY_PASSWORD: "", + CLAWDBOT_GATEWAY_PORT: String(gwB.port), + CLAWDBOT_GATEWAY_TOKEN: "", + CLAWDBOT_GATEWAY_PASSWORD: "", }), ])) as [HealthPayload, HealthPayload]; expect(healthA.ok).toBe(true); @@ -449,15 +449,15 @@ describe("gateway multi-instance e2e", () => { runCliJson( ["nodes", "status", "--json", "--url", `ws://127.0.0.1:${gwA.port}`], { - CLAWDIS_GATEWAY_TOKEN: "", - CLAWDIS_GATEWAY_PASSWORD: "", + CLAWDBOT_GATEWAY_TOKEN: "", + CLAWDBOT_GATEWAY_PASSWORD: "", }, ), runCliJson( ["nodes", "status", "--json", "--url", `ws://127.0.0.1:${gwB.port}`], { - CLAWDIS_GATEWAY_TOKEN: "", - CLAWDIS_GATEWAY_PASSWORD: "", + CLAWDBOT_GATEWAY_TOKEN: "", + CLAWDBOT_GATEWAY_PASSWORD: "", }, ), ])) as [NodeListPayload, NodeListPayload]; diff --git a/test/setup.ts b/test/setup.ts index 733d4347f..f368aa4e1 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -8,12 +8,12 @@ const originalXdgConfigHome = process.env.XDG_CONFIG_HOME; const originalXdgDataHome = process.env.XDG_DATA_HOME; const originalXdgStateHome = process.env.XDG_STATE_HOME; const originalXdgCacheHome = process.env.XDG_CACHE_HOME; -const originalTestHome = process.env.CLAWDIS_TEST_HOME; +const originalTestHome = process.env.CLAWDBOT_TEST_HOME; -const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "clawdis-test-home-")); +const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "clawdbot-test-home-")); process.env.HOME = tempHome; process.env.USERPROFILE = tempHome; -process.env.CLAWDIS_TEST_HOME = tempHome; +process.env.CLAWDBOT_TEST_HOME = tempHome; process.env.XDG_CONFIG_HOME = path.join(tempHome, ".config"); process.env.XDG_DATA_HOME = path.join(tempHome, ".local", "share"); process.env.XDG_STATE_HOME = path.join(tempHome, ".local", "state"); @@ -31,7 +31,7 @@ process.on("exit", () => { restoreEnv("XDG_DATA_HOME", originalXdgDataHome); restoreEnv("XDG_STATE_HOME", originalXdgStateHome); restoreEnv("XDG_CACHE_HOME", originalXdgCacheHome); - restoreEnv("CLAWDIS_TEST_HOME", originalTestHome); + restoreEnv("CLAWDBOT_TEST_HOME", originalTestHome); try { fs.rmSync(tempHome, { recursive: true, force: true }); } catch { diff --git a/ui/index.html b/ui/index.html index c6296e9f7..6c71e342f 100644 --- a/ui/index.html +++ b/ui/index.html @@ -3,11 +3,11 @@ - Clawdis Control + Clawdbot Control - + diff --git a/ui/package.json b/ui/package.json index c297dd92c..0a72c92e9 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,5 +1,5 @@ { - "name": "clawdis-control-ui", + "name": "clawdbot-control-ui", "private": true, "type": "module", "scripts": { diff --git a/ui/src/styles/base.css b/ui/src/styles/base.css index b376d83d2..bb86c202f 100644 --- a/ui/src/styles/base.css +++ b/ui/src/styles/base.css @@ -155,7 +155,7 @@ html.theme-transition::view-transition-new(theme) { } } -clawdis-app { +clawdbot-app { display: block; position: relative; z-index: 1; diff --git a/ui/src/ui/app-render.ts b/ui/src/ui/app-render.ts index 0e3fb471c..ad283bcd1 100644 --- a/ui/src/ui/app-render.ts +++ b/ui/src/ui/app-render.ts @@ -198,7 +198,7 @@ export function renderApp(state: AppViewState) {
-
Clawdis Control
+
Clawdbot Control
Gateway dashboard
diff --git a/ui/src/ui/app.ts b/ui/src/ui/app.ts index d27a2a357..ca3d19550 100644 --- a/ui/src/ui/app.ts +++ b/ui/src/ui/app.ts @@ -142,7 +142,7 @@ function formatToolOutput(value: unknown): string | null { declare global { interface Window { - __CLAWDIS_CONTROL_UI_BASE_PATH__?: string; + __CLAWDBOT_CONTROL_UI_BASE_PATH__?: string; } } @@ -167,8 +167,8 @@ const DEFAULT_CRON_FORM: CronFormState = { postToMainPrefix: "", }; -@customElement("clawdis-app") -export class ClawdisApp extends LitElement { +@customElement("clawdbot-app") +export class ClawdbotApp extends LitElement { @state() settings: UiSettings = loadSettings(); @state() password = ""; @state() tab: Tab = "chat"; @@ -396,7 +396,7 @@ export class ClawdisApp extends LitElement { url: this.settings.gatewayUrl, token: this.settings.token.trim() ? this.settings.token : undefined, password: this.password.trim() ? this.password : undefined, - clientName: "clawdis-control-ui", + clientName: "clawdbot-control-ui", mode: "webchat", onHello: (hello) => { this.connected = true; @@ -663,7 +663,7 @@ export class ClawdisApp extends LitElement { private inferBasePath() { if (typeof window === "undefined") return ""; - const configured = window.__CLAWDIS_CONTROL_UI_BASE_PATH__; + const configured = window.__CLAWDBOT_CONTROL_UI_BASE_PATH__; if (typeof configured === "string" && configured.trim()) { return normalizeBasePath(configured); } diff --git a/ui/src/ui/gateway.ts b/ui/src/ui/gateway.ts index 7dd7722b3..22b930a7e 100644 --- a/ui/src/ui/gateway.ts +++ b/ui/src/ui/gateway.ts @@ -110,7 +110,7 @@ export class GatewayBrowserClient { minProtocol: 2, maxProtocol: 2, client: { - name: this.opts.clientName ?? "clawdis-control-ui", + name: this.opts.clientName ?? "clawdbot-control-ui", version: this.opts.clientVersion ?? "dev", platform: this.opts.platform ?? navigator.platform ?? "web", mode: this.opts.mode ?? "webchat", diff --git a/ui/src/ui/navigation.browser.test.ts b/ui/src/ui/navigation.browser.test.ts index d940998aa..f7b522b4c 100644 --- a/ui/src/ui/navigation.browser.test.ts +++ b/ui/src/ui/navigation.browser.test.ts @@ -1,12 +1,12 @@ import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { ClawdisApp } from "./app"; +import { ClawdbotApp } from "./app"; -const originalConnect = ClawdisApp.prototype.connect; +const originalConnect = ClawdbotApp.prototype.connect; function mountApp(pathname: string) { window.history.replaceState({}, "", pathname); - const app = document.createElement("clawdis-app") as ClawdisApp; + const app = document.createElement("clawdbot-app") as ClawdbotApp; document.body.append(app); return app; } @@ -18,16 +18,16 @@ function nextFrame() { } beforeEach(() => { - ClawdisApp.prototype.connect = () => { + ClawdbotApp.prototype.connect = () => { // no-op: avoid real gateway WS connections in browser tests }; - window.__CLAWDIS_CONTROL_UI_BASE_PATH__ = undefined; + window.__CLAWDBOT_CONTROL_UI_BASE_PATH__ = undefined; document.body.innerHTML = ""; }); afterEach(() => { - ClawdisApp.prototype.connect = originalConnect; - window.__CLAWDIS_CONTROL_UI_BASE_PATH__ = undefined; + ClawdbotApp.prototype.connect = originalConnect; + window.__CLAWDBOT_CONTROL_UI_BASE_PATH__ = undefined; document.body.innerHTML = ""; }); @@ -50,22 +50,22 @@ describe("control UI routing", () => { }); it("infers nested base paths", async () => { - const app = mountApp("/apps/clawdis/cron"); + const app = mountApp("/apps/clawdbot/cron"); await app.updateComplete; - expect(app.basePath).toBe("/apps/clawdis"); + expect(app.basePath).toBe("/apps/clawdbot"); expect(app.tab).toBe("cron"); - expect(window.location.pathname).toBe("/apps/clawdis/cron"); + expect(window.location.pathname).toBe("/apps/clawdbot/cron"); }); it("honors explicit base path overrides", async () => { - window.__CLAWDIS_CONTROL_UI_BASE_PATH__ = "/clawdis"; - const app = mountApp("/clawdis/sessions"); + window.__CLAWDBOT_CONTROL_UI_BASE_PATH__ = "/clawdbot"; + const app = mountApp("/clawdbot/sessions"); await app.updateComplete; - expect(app.basePath).toBe("/clawdis"); + expect(app.basePath).toBe("/clawdbot"); expect(app.tab).toBe("sessions"); - expect(window.location.pathname).toBe("/clawdis/sessions"); + expect(window.location.pathname).toBe("/clawdbot/sessions"); }); it("updates the URL when clicking nav items", async () => { diff --git a/ui/src/ui/navigation.ts b/ui/src/ui/navigation.ts index 54ae29701..9999d527b 100644 --- a/ui/src/ui/navigation.ts +++ b/ui/src/ui/navigation.ts @@ -142,7 +142,7 @@ export function subtitleForTab(tab: Tab) { case "chat": return "Direct gateway chat session for quick interventions."; case "config": - return "Edit ~/.clawdis/clawdis.json safely."; + return "Edit ~/.clawdbot/clawdbot.json safely."; case "debug": return "Gateway snapshots, events, and manual RPC calls."; default: diff --git a/ui/src/ui/storage.ts b/ui/src/ui/storage.ts index b6bbddf6f..2cb066ace 100644 --- a/ui/src/ui/storage.ts +++ b/ui/src/ui/storage.ts @@ -1,4 +1,4 @@ -const KEY = "clawdis.control.settings.v1"; +const KEY = "clawdbot.control.settings.v1"; import type { ThemeMode } from "./theme"; diff --git a/ui/src/ui/views/config.ts b/ui/src/ui/views/config.ts index 389d41b0e..c11ee4204 100644 --- a/ui/src/ui/views/config.ts +++ b/ui/src/ui/views/config.ts @@ -61,7 +61,7 @@ export function renderConfig(props: ConfigProps) {
- Writes to ~/.clawdis/clawdis.json. Some changes + Writes to ~/.clawdbot/clawdbot.json. Some changes require a gateway restart.
diff --git a/ui/src/ui/views/overview.ts b/ui/src/ui/views/overview.ts index 17846e57c..6a728808a 100644 --- a/ui/src/ui/views/overview.ts +++ b/ui/src/ui/views/overview.ts @@ -56,7 +56,7 @@ export function renderOverview(props: OverviewProps) { const v = (e.target as HTMLInputElement).value; props.onSettingsChange({ ...props.settings, token: v }); }} - placeholder="CLAWDIS_GATEWAY_TOKEN" + placeholder="CLAWDBOT_GATEWAY_TOKEN" />