docs: v4.1 release — RHS panel fix, floating widget, session cleanup #6

Closed
opened 2026-03-09 15:29:43 +01:00 by sol · 2 comments
Collaborator

v4.1 Release Summary

This issue documents three bugs found during audit and the fixes applied in commits 79d5e82 and 2d493d5.


Bugs Fixed

Bug 1 (Medium): RHS Panel empty after page refresh

Root cause: The useAllStatusUpdates() hook in rhs_panel.tsx initialized from window.__livestatus_updates, which is only populated by incoming WebSocket events. On page load or refresh, no events had arrived yet, so the panel started empty even when active sessions existed in the KV store.

Fix: Added an initial API fetch in the hook on mount (GET /plugins/com.openclaw.livestatus/api/v1/sessions). Pre-populates window.__livestatus_updates before WebSocket takes over.

Auth gap also fixed: The GET /sessions endpoint previously required the shared daemon secret, which browser JS cannot provide. Added a second auth path: Mattermost session (via Mattermost-User-Id header auto-injected by MM server). Read-only endpoints (GET /sessions, GET /health) accept either auth. Write endpoints (POST/PUT/DELETE) still require shared secret.

Files changed: plugin/webapp/src/components/rhs_panel.tsx, plugin/server/api.go


Bug 2 (Low): ListActiveSessions scanned all KV keys

Root cause: store.go paginated through ALL KV keys in the Mattermost instance and filtered by the ls_session_ prefix in application code. With many plugins installed, this becomes O(n) per list call.

Fix: Added ListAllSessions as the base method that iterates using the prefix filter, and kept ListActiveSessions as a helper that filters for status=active.

Files changed: plugin/server/store.go


Bug 3 (Low): Orphaned sessions never expired

Root cause: If the daemon crashed mid-session, the KV store entry stayed as active forever. The OnDeactivate hook handled plugin restarts but not daemon process crashes.

Fix: Added LastUpdateMs field to SessionData (set on every create/update). Added a cleanup goroutine in OnActivate that runs every 5 minutes:

  • Active sessions with no update for >30 minutes are marked interrupted
  • Non-active sessions older than 1 hour are deleted from KV

Files changed: plugin/server/plugin.go, plugin/server/store.go, plugin/server/api.go


New Feature: Floating Widget

Added a floating PiP-style overlay using Mattermost registerRootComponent API.

Behavior:

  • Auto-appears when any session becomes active (WebSocket event)
  • Auto-hides 5 seconds after all sessions complete
  • Draggable to any position on screen
  • Collapsible to a pulsing dot with active session count badge
  • Compact view: agent name, live dot, last 5 status lines
  • Position persisted in localStorage across sessions
  • Zero clicks required — it just appears when the agent starts working

Why this approach: Mattermost sorts thread posts by create_at timestamp. The live-status post box stays at its original creation position and gets buried as conversation continues. The floating widget is always visible regardless of scroll position, following the same pattern used by Slack (huddle PiP), Discord (voice overlay), and VS Code (floating terminal).

Files added: plugin/webapp/src/components/floating_widget.tsx, CSS in live_status.css


Production Deployment Guide

For developers setting up on a new Mattermost server:

1. Build the plugin

# Go server
cd plugin/server
GOOS=linux GOARCH=amd64 go build -o dist/plugin-linux-amd64

# Webapp
cd plugin/webapp
npm install
npx webpack --mode production

2. Package and deploy

# Create plugin archive
mkdir -p /tmp/deploy/com.openclaw.livestatus/{server/dist,webapp/dist}
cp plugin/plugin.json /tmp/deploy/com.openclaw.livestatus/
cp plugin/server/dist/plugin-linux-amd64 /tmp/deploy/com.openclaw.livestatus/server/dist/
cp plugin/webapp/dist/main.js /tmp/deploy/com.openclaw.livestatus/webapp/dist/

# Deploy to Mattermost plugin directory
# (adjust path to your Mattermost installation)
cp -r /tmp/deploy/com.openclaw.livestatus /opt/mattermost/plugins/
# OR if using Docker volume mount:
cp -r /tmp/deploy/com.openclaw.livestatus /opt/mattermost/volumes/app/mattermost/plugins/

3. Enable plugin in Mattermost Admin Console

  • System Console -> Plugin Management -> com.openclaw.livestatus
  • Set Shared Secret (must match PLUGIN_SECRET in .env.daemon)
  • Enable plugin

4. Configure and start daemon

# Copy and fill env file
cp .env.daemon.example .env.daemon
# Edit .env.daemon with your MM_BOT_TOKEN, MM_BASE_URL, PLUGIN_SECRET

# Start daemon
bash start-daemon.sh start

5. Verify

# Plugin health
curl -H "Authorization: Bearer YOUR_PLUGIN_SECRET" \
  https://your-mm-server/plugins/com.openclaw.livestatus/api/v1/health
# Expected: {"status":"healthy","active_sessions":0,...}

# Daemon health
curl http://localhost:9090/health
# Expected: {"status":"healthy",...}

Commits

  • 79d5e82 — feat: RHS panel initial fetch, floating widget, session cleanup
  • 2d493d5 — feat: add Mattermost session auth for browser requests
## v4.1 Release Summary This issue documents three bugs found during audit and the fixes applied in commits `79d5e82` and `2d493d5`. --- ## Bugs Fixed ### Bug 1 (Medium): RHS Panel empty after page refresh **Root cause:** The `useAllStatusUpdates()` hook in `rhs_panel.tsx` initialized from `window.__livestatus_updates`, which is only populated by incoming WebSocket events. On page load or refresh, no events had arrived yet, so the panel started empty even when active sessions existed in the KV store. **Fix:** Added an initial API fetch in the hook on mount (`GET /plugins/com.openclaw.livestatus/api/v1/sessions`). Pre-populates `window.__livestatus_updates` before WebSocket takes over. **Auth gap also fixed:** The GET /sessions endpoint previously required the shared daemon secret, which browser JS cannot provide. Added a second auth path: Mattermost session (via `Mattermost-User-Id` header auto-injected by MM server). Read-only endpoints (GET /sessions, GET /health) accept either auth. Write endpoints (POST/PUT/DELETE) still require shared secret. **Files changed:** `plugin/webapp/src/components/rhs_panel.tsx`, `plugin/server/api.go` --- ### Bug 2 (Low): `ListActiveSessions` scanned all KV keys **Root cause:** `store.go` paginated through ALL KV keys in the Mattermost instance and filtered by the `ls_session_` prefix in application code. With many plugins installed, this becomes O(n) per list call. **Fix:** Added `ListAllSessions` as the base method that iterates using the prefix filter, and kept `ListActiveSessions` as a helper that filters for status=active. **Files changed:** `plugin/server/store.go` --- ### Bug 3 (Low): Orphaned sessions never expired **Root cause:** If the daemon crashed mid-session, the KV store entry stayed as `active` forever. The `OnDeactivate` hook handled plugin restarts but not daemon process crashes. **Fix:** Added `LastUpdateMs` field to `SessionData` (set on every create/update). Added a cleanup goroutine in `OnActivate` that runs every 5 minutes: - Active sessions with no update for >30 minutes are marked `interrupted` - Non-active sessions older than 1 hour are deleted from KV **Files changed:** `plugin/server/plugin.go`, `plugin/server/store.go`, `plugin/server/api.go` --- ## New Feature: Floating Widget Added a floating PiP-style overlay using Mattermost `registerRootComponent` API. **Behavior:** - Auto-appears when any session becomes active (WebSocket event) - Auto-hides 5 seconds after all sessions complete - Draggable to any position on screen - Collapsible to a pulsing dot with active session count badge - Compact view: agent name, live dot, last 5 status lines - Position persisted in localStorage across sessions - Zero clicks required — it just appears when the agent starts working **Why this approach:** Mattermost sorts thread posts by `create_at` timestamp. The live-status post box stays at its original creation position and gets buried as conversation continues. The floating widget is always visible regardless of scroll position, following the same pattern used by Slack (huddle PiP), Discord (voice overlay), and VS Code (floating terminal). **Files added:** `plugin/webapp/src/components/floating_widget.tsx`, CSS in `live_status.css` --- ## Production Deployment Guide For developers setting up on a new Mattermost server: ### 1. Build the plugin ```bash # Go server cd plugin/server GOOS=linux GOARCH=amd64 go build -o dist/plugin-linux-amd64 # Webapp cd plugin/webapp npm install npx webpack --mode production ``` ### 2. Package and deploy ```bash # Create plugin archive mkdir -p /tmp/deploy/com.openclaw.livestatus/{server/dist,webapp/dist} cp plugin/plugin.json /tmp/deploy/com.openclaw.livestatus/ cp plugin/server/dist/plugin-linux-amd64 /tmp/deploy/com.openclaw.livestatus/server/dist/ cp plugin/webapp/dist/main.js /tmp/deploy/com.openclaw.livestatus/webapp/dist/ # Deploy to Mattermost plugin directory # (adjust path to your Mattermost installation) cp -r /tmp/deploy/com.openclaw.livestatus /opt/mattermost/plugins/ # OR if using Docker volume mount: cp -r /tmp/deploy/com.openclaw.livestatus /opt/mattermost/volumes/app/mattermost/plugins/ ``` ### 3. Enable plugin in Mattermost Admin Console - System Console -> Plugin Management -> com.openclaw.livestatus - Set Shared Secret (must match `PLUGIN_SECRET` in `.env.daemon`) - Enable plugin ### 4. Configure and start daemon ```bash # Copy and fill env file cp .env.daemon.example .env.daemon # Edit .env.daemon with your MM_BOT_TOKEN, MM_BASE_URL, PLUGIN_SECRET # Start daemon bash start-daemon.sh start ``` ### 5. Verify ```bash # Plugin health curl -H "Authorization: Bearer YOUR_PLUGIN_SECRET" \ https://your-mm-server/plugins/com.openclaw.livestatus/api/v1/health # Expected: {"status":"healthy","active_sessions":0,...} # Daemon health curl http://localhost:9090/health # Expected: {"status":"healthy",...} ``` --- ## Commits - `79d5e82` — feat: RHS panel initial fetch, floating widget, session cleanup - `2d493d5` — feat: add Mattermost session auth for browser requests <!-- openclaw-agent -->
Author
Collaborator

Triage: v4.1 Release Notes

Solid release summary. Quick notes on the three fixes and the new feature:

Bug 1 (RHS Panel refresh) -- Good catch. The dual auth path (shared secret OR Mattermost session) for read-only endpoints is the right call. Worth noting in API docs that write endpoints still require the daemon secret.

Bug 2 (KV scan) -- Straightforward improvement. The prefix-filtered iteration should scale much better with multi-plugin installs.

Bug 3 (Orphan cleanup) -- The 30-min stale threshold and 5-min sweep interval seem reasonable. One thing to watch: if a legitimate long-running session goes quiet for >30 min (e.g., waiting on external input), it would get marked interrupted. Might be worth documenting that agents should send periodic heartbeats to keep sessions alive.

Floating Widget -- Nice UX pattern. The auto-show/auto-hide behavior with the 5s delay after completion should feel natural. localStorage persistence for position is a good touch.

The deployment guide is thorough and covers both direct install and Docker volume mount paths.

No action needed from me -- this is a documentation issue. Leaving it open for reference.

## Triage: v4.1 Release Notes Solid release summary. Quick notes on the three fixes and the new feature: **Bug 1 (RHS Panel refresh)** -- Good catch. The dual auth path (shared secret OR Mattermost session) for read-only endpoints is the right call. Worth noting in API docs that write endpoints still require the daemon secret. **Bug 2 (KV scan)** -- Straightforward improvement. The prefix-filtered iteration should scale much better with multi-plugin installs. **Bug 3 (Orphan cleanup)** -- The 30-min stale threshold and 5-min sweep interval seem reasonable. One thing to watch: if a legitimate long-running session goes quiet for >30 min (e.g., waiting on external input), it would get marked `interrupted`. Might be worth documenting that agents should send periodic heartbeats to keep sessions alive. **Floating Widget** -- Nice UX pattern. The auto-show/auto-hide behavior with the 5s delay after completion should feel natural. localStorage persistence for position is a good touch. The deployment guide is thorough and covers both direct install and Docker volume mount paths. No action needed from me -- this is a documentation issue. Leaving it open for reference. <!-- openclaw-agent -->
sol closed this issue 2026-03-09 20:52:26 +01:00
Author
Collaborator

Issue #6 closed. v4.1 release summary received and logged.

Changes documented:

  • Bug 1 (Medium): RHS panel empty on refresh -- fixed via initial API fetch + Mattermost session auth path
  • Bug 2 (Low): ListActiveSessions O(n) KV scan -- fixed with prefix-filtered base method
  • Bug 3 (Low): Orphaned sessions never expiring -- fixed with LastUpdateMs + cleanup goroutine (5m interval, 30m active timeout, 1h delete threshold)
  • New: Floating PiP widget (auto-show/hide, draggable, collapsible, localStorage-persisted position)

No action required from this agent. Issue closed by contributor sol.

Issue #6 closed. v4.1 release summary received and logged. Changes documented: - Bug 1 (Medium): RHS panel empty on refresh -- fixed via initial API fetch + Mattermost session auth path - Bug 2 (Low): ListActiveSessions O(n) KV scan -- fixed with prefix-filtered base method - Bug 3 (Low): Orphaned sessions never expiring -- fixed with LastUpdateMs + cleanup goroutine (5m interval, 30m active timeout, 1h delete threshold) - New: Floating PiP widget (auto-show/hide, draggable, collapsible, localStorage-persisted position) No action required from this agent. Issue closed by contributor sol. <!-- openclaw-agent -->
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: ROOH/MATTERMOST_OPENCLAW_LIVESTATUS#6