fix(mac): bundle web chat UI deps
This commit is contained in:
@@ -1,66 +1,45 @@
|
||||
# Session Management
|
||||
|
||||
CLAWDIS keeps lightweight session state so your agent can remember context between messages. Sessions are stored in a small JSON file and expire automatically after idle time or when you reset them.
|
||||
Clawdis treats **one session as primary**. By default the canonical key is `main`; set `inbound.reply.session.mainKey` to change it. Older/local sessions can stay on disk, but only the primary key is used for desktop/web chat and direct agent calls.
|
||||
|
||||
## Where sessions live
|
||||
## Where state lives
|
||||
- Store file: `~/.clawdis/sessions/sessions.json` (legacy: `~/.warelay/sessions.json`).
|
||||
- Transcripts: `~/.clawdis/sessions/<SessionId>.jsonl` (one file per session id).
|
||||
- The store is a map `sessionKey -> { sessionId, updatedAt, ... }`. Deleting entries is safe; they are recreated on demand.
|
||||
|
||||
- Default path: `~/.clawdis/sessions.json` (legacy: `~/.warelay/sessions.json`).
|
||||
- Override with `inbound.reply.session.store` in your config if you want a custom location.
|
||||
- The file is a plain map of `sessionKey -> { sessionId, updatedAt, ... }`; it is safe to delete if you want a full reset.
|
||||
## Mapping transports → session keys
|
||||
- Direct chats (WhatsApp, Telegram, desktop Web Chat) all collapse to the **primary key** so they share context.
|
||||
- Multiple phone numbers can map to that same key; they act as transports into the same conversation.
|
||||
- Group chats still isolate state with `group:<jid>` keys; do not reuse the primary key for groups.
|
||||
|
||||
## How session keys are chosen
|
||||
|
||||
- Direct chats: by default collapse to the canonical key `main` so all 1:1 channels (WhatsApp, WebChat, Telegram) share a single session.
|
||||
- Group chats: `group:<whatsapp-jid>` so group history stays isolated from DMs.
|
||||
- Global mode: set `inbound.reply.session.scope = "global"` to force a single shared session for all chats.
|
||||
- Unknown senders fall back to `unknown`.
|
||||
|
||||
To change the canonical key (or disable collapsing), set `inbound.reply.session.mainKey` to another string or leave it empty.
|
||||
|
||||
## When sessions reset
|
||||
|
||||
- Idle timeout: `inbound.reply.session.idleMinutes` (default 60). If no messages arrive within this window, a new `sessionId` is created on the next message.
|
||||
- Reset triggers: `inbound.reply.session.resetTriggers` (default `['/new']`). Sending exactly `/new` or `/new <text>` starts a fresh session and passes the remaining text to the agent.
|
||||
- Manual nuke: delete the store file or remove specific keys with `jq`/your editor; a new file is created on the next message.
|
||||
|
||||
## Configuration recap
|
||||
## Lifecyle
|
||||
- Idle expiry: `inbound.reply.session.idleMinutes` (default 60). After the timeout a new `sessionId` is minted on the next message.
|
||||
- Reset triggers: exact `/new` (plus any extras in `resetTriggers`) start a fresh session id and pass the remainder of the message through.
|
||||
- Manual reset: delete specific keys from the store or remove the JSONL transcript; the next message recreates them.
|
||||
|
||||
## Configuration (primary-only example)
|
||||
```json5
|
||||
// ~/.clawdis/clawdis.json
|
||||
{
|
||||
inbound: {
|
||||
reply: {
|
||||
session: {
|
||||
scope: "per-sender", // or "global"
|
||||
resetTriggers: ["/new"], // additional triggers allowed
|
||||
idleMinutes: 120, // extend or shrink timeout (min 1)
|
||||
store: "~/state/clawdis-sessions.json", // optional custom path
|
||||
mainKey: "main" // canonical direct-chat bucket
|
||||
scope: "per-sender", // keep group keys separate
|
||||
idleMinutes: 120,
|
||||
resetTriggers: ["/new"],
|
||||
store: "~/.clawdis/sessions/sessions.json",
|
||||
mainKey: "main" // marks the primary session
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
## Surfaces (channel labels)
|
||||
|
||||
Each inbound message can carry a `Surface` hint in the templating context (e.g., `whatsapp`, `webchat`, `telegram`, `voice`). Routing stays deterministic: replies are sent back to the origin surface, but the shared `main` session keeps context unified across direct channels. Groups retain their `group:<jid>` buckets.
|
||||
|
||||
## WebChat history
|
||||
|
||||
WebChat always attaches to the `main` session and hydrates the full Tau JSONL transcript from `~/.clawdis/sessions/<SessionId>.jsonl`, so desktop view reflects all turns, even those that arrived via WhatsApp/Telegram.
|
||||
```
|
||||
|
||||
Other session-related behaviors:
|
||||
- `thinkingLevel` and `verboseLevel` persist per session so inline directives stick until the session resets.
|
||||
- Heartbeats reuse the existing session for a recipient when available (good for keeping context warm).
|
||||
|
||||
## Inspecting sessions
|
||||
|
||||
- `clawdis status` shows the session store path, total count, and the five most recent keys with ages.
|
||||
- `clawdis sessions` lists every session (filter with `--active <minutes>` or use `--json` for scripts). It also reports token usage per session; set `inbound.reply.agent.contextTokens` to see the budget percentage (defaults to ~200k tokens for Opus 4.5 via pi-ai defaults).
|
||||
- For a deeper look, open the JSON store directly; the keys match the rules above.
|
||||
## Inspecting
|
||||
- `pnpm clawdis status` — shows store path and recent sessions.
|
||||
- `pnpm clawdis sessions --json` — dumps every entry (filter with `--active <minutes>`).
|
||||
- JSONL transcripts can be opened directly to review full turns.
|
||||
|
||||
## Tips
|
||||
|
||||
- Keep groups isolated: mention-based triggers plus the `group:<jid>` session key prevent group traffic from contaminating your DM history.
|
||||
- If you automate cleanup, prefer deleting specific keys instead of the whole file to keep other conversations intact.
|
||||
- Keep the primary key dedicated to 1:1 traffic; let groups keep their own keys.
|
||||
- When automating cleanup, delete individual keys instead of the whole store to preserve context elsewhere.
|
||||
|
||||
@@ -1,27 +1,23 @@
|
||||
# Web Chat (macOS menu bar)
|
||||
|
||||
The macOS Clawdis app ships a built-in web chat window that reuses your primary Clawd session instead of creating a new one. This is meant for quick desktop access without exposing any local HTTP ports.
|
||||
The macOS Clawdis app embeds the `pi-web-ui` chat surface inside `WKWebView`, wired directly to your **primary session** (`main` unless `inbound.reply.session.mainKey` overrides it). No HTTP server is started; assets are bundled into the app and loaded from `file://`, so nothing is exposed on the network.
|
||||
|
||||
## How it works
|
||||
- **UI bundle**: `apps/macos/Sources/Clawdis/Resources/WebChat/` contains `pi-web-ui` dist plus vendor deps and a tiny `pi-ai` stub.
|
||||
- **Bridge**: a `WKScriptMessageHandler` named `clawdis` passes chat turns to `pnpm clawdis agent --to <sessionKey> --message ... --json` and returns the first payload text. Everything stays in-process—no sockets, no local web server.
|
||||
- **Session**: always uses the primary key; history is hydrated from `~/.clawdis/sessions/<SessionId>.jsonl` so turns from WhatsApp/Telegram show up here too.
|
||||
|
||||
- UI: `pi-mono/packages/web-ui` bundle loaded in a `WKWebView`.
|
||||
- Bridge: `WKScriptMessageHandler` named `clawdis` (see `apps/macos/Sources/Clawdis/WebChatWindow.swift`). The page posts `sessionKey` + message; Swift shells `pnpm clawdis agent --to <sessionKey> --message <text> --json` and returns the first payload text to the page. No sockets are opened.
|
||||
- Session selection: always uses the canonical `main` session key (or `inbound.reply.session.mainKey`), hydrating from the Tau JSONL session file so you see the full history even when messages arrived via WhatsApp/Telegram.
|
||||
- Assets: the entire `pi-web-ui` dist plus dependencies (pi-ai, mini-lit, lit, lucide, pdfjs-dist, docx-preview, jszip) is bundled into `apps/macos/Sources/Clawdis/Resources/WebChat/` and shipped with the app. No external checkout is required at runtime.
|
||||
## Building/updating the bundle
|
||||
1. Ensure `../pi-mono` is present and `pnpm install` has been run there.
|
||||
2. Sync vendor files: copied from `../pi-mono/node_modules` into `apps/macos/Sources/Clawdis/Resources/WebChat/vendor` (run via repo scripts when updating).
|
||||
3. The mac app loads assets relative to the bundled folder with an import map; no external CDN or HTTP endpoints are used.
|
||||
4. Rebuild/restart the app with `./scripts/restart-mac.sh` (required so the new resources land in the app bundle).
|
||||
|
||||
## Requirements
|
||||
## Limitations
|
||||
- Text-only, single-turn response (no streaming yet; tools/attachments not plumbed).
|
||||
- The embedded `pi-ai` is a stub sufficient for UI wiring; provider selection is fixed to the primary Clawd session.
|
||||
|
||||
- `pnpm` on PATH.
|
||||
- `pnpm install` already run in the repo so `pnpm clawdis agent ...` works.
|
||||
- `pi-mono` checked out at `../pi-mono` with `packages/web-ui/dist` built.
|
||||
|
||||
## Limitations / TODO
|
||||
|
||||
- Single-turn (no streaming), text-only; attachments/tools not wired yet.
|
||||
- Absolute dist path; bundle should be copied into app resources and versioned.
|
||||
- Errors from the agent subprocess are minimally surfaced.
|
||||
|
||||
## Usage
|
||||
|
||||
- Launch the macOS Clawdis menu bar app, click the lobster icon → “Open Chat”.
|
||||
- Type and send; replies continue the primary Clawd session.
|
||||
## Troubleshooting
|
||||
- Right-click → “Inspect Element” opens Web Inspector. Check the console for `boot:` messages.
|
||||
- Blank view usually means import map or vendor assets are missing; confirm files exist under `Resources/WebChat/vendor` and the import map points to relative paths.
|
||||
- Errors are rendered in-page in red if the boot script fails after parsing.
|
||||
|
||||
Reference in New Issue
Block a user