Discovered during smoke-testing on hzhang's laptop:
1. `--channels server:X --dangerously-load-development-channels server:X`
makes Claude Code list the channel twice and the second copy never
inherits dev-mode, leaving "server: entries need
--dangerously-load-development-channels" stuck in the status panel.
Fix: pass channel ONLY via --dangerously-load-development-channels.
2. Without a controlling TTY, Claude Code's dev-mode confirmation dialog
blocks forever waiting for keystrokes that never arrive. Fix: spawn
claude wrapped in `script -q -c CMD PTYLOG` so it gets a PTY, then
write "\r" to stdin at several timeouts (cheap to over-send).
3. process-manager.markReady was matching on PID, but the PID in the
bridge hello frame is the ClaudePlugin (bun) process's pid, not the
script-wrapped claude process's pid we tracked. Fix: match on
openclaw-session-key, which is consistent on both sides.
4. First spawn for a new session can't use --resume (no transcript exists
yet) — claude errors out. Fix: probe
~/.claude/projects/<workspace-slug>/<uuid>.jsonl for existence and use
--session-id on fresh sessions, --resume after a process restart.
5. Add --debug-file per session so future debugging has the gating logs.
6. Local definePluginEntry shim (no openclaw runtime dependency) so
`bun index.ts` works standalone for laptop smoke tests.
End-to-end verified twice on laptop: curl POST -> SSE delta with the
exact reply text. Average cold-start ~10s, hot path 2-3s.