Files
whetstone_DSL/HANDOFF-2026-03-09-sprint291.md

158 lines
5.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Whetstone Handoff — Sprint 291: HTTP/SSE Daemon Mode
**Date:** 2026-03-09
**Steps:** 19831987
**Tests:** 5/5 passing
---
## What Was Built
Eliminates the dual-process bug where each Claude Code session spawned its own
`whetstone_mcp` stdio process with independent in-memory state. `start_recording`
in one session and `get_metrics` in another would hit different processes and lose
data. Recording state, workspace, buffers, and AST were all split.
**Fix:** HTTP+SSE daemon mode. One shared daemon process, all sessions connect via
MCP HTTP+SSE transport. Single in-memory state for everything.
### New files
- `editor/src/MCPHttpServer.h` — HTTP+SSE server (Step 1983)
- Uses cpp-httplib (fetched via FetchContent, header-only)
- `GET /sse` — opens SSE stream, sends `event: endpoint` with session URL
- `POST /message?sessionId=X` — routes JSON-RPC to handler, pushes response to SSE
- `GET /health` — status JSON `{status, sessions, port}`
- Per-connection `Session` struct: mutex + condition_variable + queue<string>
- 25s keepalive timeout (sends SSE comment to prevent proxy drops)
- Writes `{workspace}/.whetstone/daemon.pid` on start, removes on exit
- `editor/src/Sprint291IntegrationSummary.h` — sprint metadata (Step 1986)
- `editor/tests/step1987_test.cpp` — integration tests (Step 1987)
- `tools/start-whetstone-daemon.sh` — idempotent startup script (Step 1986)
### Modified files
- `editor/src/MCPBridge.h` — added `runHttp(int port, const std::string& workspace)`
- `editor/src/mcp_main.cpp` — added `--daemon` and `--port N` flags (default 7600),
PID lockfile, duplicate daemon guard via `kill(pid, 0)` check
- `editor/CMakeLists.txt` — FetchContent for cpp-httplib, step1983-1987 targets
- `Documents/.mcp.json` (not in this repo) — switched from `command:` (stdio) to
`"type": "sse", "url": "http://127.0.0.1:7600/sse"`
---
## How to Use It
### Starting the daemon (do this once before any Claude Code sessions)
```bash
cd /home/bill/Documents/CLionProjects/whetstone_DSL
tools/start-whetstone-daemon.sh
# prints PID when ready; idempotent — safe to run again if already up
```
Verify it's running:
```bash
curl http://127.0.0.1:7600/health
# → {"status":"ok","sessions":0,"port":7600}
```
### Autostart (so you don't have to do it manually)
Add to `~/.bashrc` or `~/.profile`:
```bash
# Auto-start whetstone daemon if not running
if ! curl -sf http://127.0.0.1:7600/health >/dev/null 2>&1; then
/home/bill/Documents/CLionProjects/whetstone_DSL/tools/start-whetstone-daemon.sh >/dev/null 2>&1 &
fi
```
Or as a systemd user service:
```bash
cat > ~/.config/systemd/user/whetstone-daemon.service << 'EOF'
[Unit]
Description=Whetstone MCP Daemon
After=network.target
[Service]
Type=simple
ExecStart=/home/bill/Documents/CLionProjects/whetstone_DSL/editor/build-native/whetstone_mcp \
--daemon \
--port 7600 \
--workspace /home/bill/Documents/CLionProjects/whetstone_DSL \
--language cpp
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target
EOF
systemctl --user enable --now whetstone-daemon
```
### Stopping the daemon
```bash
kill $(cat /home/bill/Documents/CLionProjects/whetstone_DSL/.whetstone/daemon.pid)
# or
pkill -f "whetstone_mcp --daemon"
```
### Falling back to stdio mode
Change `.mcp.json` back to:
```json
{
"mcpServers": {
"whetstone": {
"command": "/home/bill/Documents/CLionProjects/whetstone_DSL/editor/build-native/whetstone_mcp",
"args": ["--workspace", "/home/bill/Documents/CLionProjects/whetstone_DSL", "--language", "cpp"]
}
}
}
```
---
## Architecture Notes
### MCP HTTP+SSE transport (2024-11-05 spec)
1. Client opens `GET /sse` — receives `event: endpoint\ndata: /message?sessionId=<uuid>`
2. Client sends requests via `POST /message?sessionId=<uuid>`
3. Server pushes responses back over the SSE stream as `event: message\ndata: <json>`
### Thread safety
- `sessions_` map protected by `sessionsMtx_`
- Each session has its own mutex + cv + queue — POST handler and SSE provider communicate via cv.notify_one()
- cpp-httplib handles one thread per connection automatically
### Session lifecycle
- Session created on `GET /sse`, stored in map
- Session removed via the httplib `ContentProviderResourceReleaser` callback when SSE connection closes
- PID lockfile prevents two daemons on the same workspace
---
## Build
```bash
cd /home/bill/Documents/CLionProjects/whetstone_DSL/editor
cmake -S . -B build-native -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH="$(pwd)/build-native/vcpkg_installed/x64-linux"
cmake --build build-native --target whetstone_mcp step1987_test --parallel
./build-native/step1987_test # 5/5 should pass
```
cpp-httplib is fetched via FetchContent (v0.18.1) — no vcpkg required.
---
## What Comes Next
- **Phase 7 (TBD):** Plan in a new session
- **Daemon autostart:** Systemd user service is the cleanest long-term solution
- **Language selection:** Current daemon starts with `--language cpp`. For Python projects,
the daemon needs `--language python` or a language-switching mechanism. As a workaround,
run separate daemons on different ports with different languages and point project-specific
`.mcp.json` files at the appropriate port.
- **Multi-language daemon:** Future improvement — a single daemon that accepts
`language` as a per-request parameter rather than a startup flag.