onMessageEdited optimistically set edited_at, then fetched the full
message. If the fetch failed the "Edited" indicator persisted even though
the content was stale. Fix by capturing the original edited_at and
reverting it in the catch block — consistent with editMessage rollback.
connect() is async/fire-and-forget — if the user switches rooms while
WS is still connecting, the subscribeRoom() call captures the stale
(activeRoomId) closure value and subscribes to the wrong room. Fix by
re-reading activeRoomIdRef.current after the await so we always subscribe
to the room that is active when the connection actually opens.
- useEffect([wsClient]): remove wsClient from deps to prevent
React StrictMode double-mount from disconnecting the real client.
First mount connects client-1; StrictMode cleanup disconnects it.
Second mount connects client-2; first mount's second cleanup would
then disconnect client-2, leaving WS permanently unconnected.
Changing to useEffect([]) + optional chaining fixes this.
- revokeMessage: add optimistic removal + rollback on server rejection,
consistent with editMessage pattern. Previously a failed delete left the
message visible with no feedback.
- sendMessage: guard with sendingRef to prevent concurrent in-flight
sends (was missing — rapid clicks could create duplicate messages)
- resubscribeAll: log at warn level instead of silently swallowing,
so operators can observe auth expiry or persistent failure patterns
- RoomMessageBubble: apply opacity-60 when isPending or isFailed,
and hide action toolbar for pending messages (can't react/act on
unconfirmed messages)
Backend:
- Atomic seq assignment via Redis Lua script: INCR + GET run atomically
inside a Lua script, preventing duplicate seqs under concurrent requests.
DB reconciliation only triggers on cross-server handoff (rare path).
- Broadcast channel capacity: 10,000 → 100,000 to prevent message drops
under high-throughput rooms.
Frontend:
- Optimistic sendMessage: adds message to UI immediately (marked
isOptimistic=true) so user sees it instantly. Replaces with
server-confirmed message on success, marks as isOptimisticError on
failure. Fire-and-forget to IndexedDB for persistence.
- Seq-based dedup in onRoomMessage: replaces optimistic message by
matching seq, preventing duplicates when WS arrives before REST confirm.
- Reconnect jitter: replaced deterministic backoff with full jitter
(random within backoff window), preventing thundering herd on server
restart.
- Visual WS status dot in room header: green=connected, amber
(pulsing)=connecting, red=error/disconnected.
- isPending check extended to cover both old 'temp-' prefix and new
isOptimistic flag, showing 'Sending...' / 'Failed' badges.
- Badge: 'Command as Service · Human + Agent Engineering'
- Subtitle: 'Every action is a command. Every command is versioned,
auditable, and composable.'
- Terminal demo: show service deploy, skill run, and replay commands
- Features: lead with Command as Service, rewrite all descriptions
around the command stream paradigm
- Section header: 'Build. Review. Automate. All via Commands.'
- Highlight: 'Your CLI is also your API'
- Nav/Footer: surface Command as Service in Platform menu
Add ssh_clone_url and https_clone_url to ProjectRepositoryItem,
constructed from config.ssh_domain() and config.git_http_domain().
Update frontend RepoInfo interface and header.tsx to use the
server-provided URLs instead of hardcoded values.
The generated client returns AxiosError as resp when throwOnError=false.
Check resp.error (set by the client to err.response?.data) for the
business-level code/error fields rather than relying on HTTP status.
- Add landing subpages: pricing, skills, solutions, network, about, docs
- Nav pop cards link to all subpages with nested routes
- Homepage: full landing content with top nav (no sidebar) for logged-in users
- Rewrite copy based on real backend: Git repos, Issues/PRs, Rooms, AI Agents
- Introduce "Command as Service" as core product concept
- Terminal demo shows realistic gitdata CLI commands
- Footer links updated to real routes
- Fix workspace redirect slug guard (undefined route)