From d6408b2853dce7f2dcf46621e912a24040a9c855 Mon Sep 17 00:00:00 2001 From: clawbot Date: Tue, 10 Feb 2026 18:23:19 -0800 Subject: [PATCH] fix: CLI client types mismatched server response format - SessionResponse: use 'id' (int64) not 'session_id'/'client_id' - StateResponse: match actual server response shape - GetMembers: strip '#' from channel name for URL path - These bugs prevented the CLI from working correctly with the server --- cmd/chat-cli/api/client.go | 5 ++++- cmd/chat-cli/api/types.go | 42 ++++++++++++++++---------------------- cmd/chat-cli/main.go | 2 +- 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/cmd/chat-cli/api/client.go b/cmd/chat-cli/api/client.go index 42334d2..205f39d 100644 --- a/cmd/chat-cli/api/client.go +++ b/cmd/chat-cli/api/client.go @@ -7,6 +7,7 @@ import ( "io" "net/http" "net/url" + "strings" "time" ) @@ -167,7 +168,9 @@ func (c *Client) ListChannels() ([]Channel, error) { // GetMembers returns members of a channel. func (c *Client) GetMembers(channel string) ([]string, error) { - data, err := c.do("GET", "/api/v1/channels/"+url.PathEscape(channel)+"/members", nil) + // Server route is /channels/{channel}/members where channel is without '#' + name := strings.TrimPrefix(channel, "#") + data, err := c.do("GET", "/api/v1/channels/"+url.PathEscape(name)+"/members", nil) if err != nil { return nil, err } diff --git a/cmd/chat-cli/api/types.go b/cmd/chat-cli/api/types.go index c12811f..d66069f 100644 --- a/cmd/chat-cli/api/types.go +++ b/cmd/chat-cli/api/types.go @@ -1,4 +1,4 @@ -package chatapi +package api import "time" @@ -9,45 +9,40 @@ type SessionRequest struct { // SessionResponse is the response from POST /api/v1/session. type SessionResponse struct { - SessionID string `json:"sessionId"` - ClientID string `json:"clientId"` - Nick string `json:"nick"` - Token string `json:"token"` + ID int64 `json:"id"` + Nick string `json:"nick"` + Token string `json:"token"` } // StateResponse is the response from GET /api/v1/state. type StateResponse struct { - SessionID string `json:"sessionId"` - ClientID string `json:"clientId"` - Nick string `json:"nick"` - Channels []string `json:"channels"` + ID int64 `json:"id"` + Nick string `json:"nick"` + Channels []string `json:"channels"` } // Message represents a chat message envelope. type Message struct { - Command string `json:"command"` - From string `json:"from,omitempty"` - To string `json:"to,omitempty"` - Params []string `json:"params,omitempty"` - Body any `json:"body,omitempty"` - ID string `json:"id,omitempty"` - TS string `json:"ts,omitempty"` - Meta any `json:"meta,omitempty"` + Command string `json:"command"` + From string `json:"from,omitempty"` + To string `json:"to,omitempty"` + Params []string `json:"params,omitempty"` + Body interface{} `json:"body,omitempty"` + ID string `json:"id,omitempty"` + TS string `json:"ts,omitempty"` + Meta interface{} `json:"meta,omitempty"` } -// BodyLines returns the body as a slice of strings (for text -// messages). +// BodyLines returns the body as a slice of strings (for text messages). func (m *Message) BodyLines() []string { switch v := m.Body.(type) { - case []any: + case []interface{}: lines := make([]string, 0, len(v)) - for _, item := range v { if s, ok := item.(string); ok { lines = append(lines, s) } } - return lines case []string: return v @@ -61,7 +56,7 @@ type Channel struct { Name string `json:"name"` Topic string `json:"topic"` Members int `json:"members"` - CreatedAt string `json:"createdAt"` + CreatedAt string `json:"created_at"` } // ServerInfo is the response from GET /api/v1/server. @@ -89,6 +84,5 @@ func (m *Message) ParseTS() time.Time { if err != nil { return time.Now() } - return t } diff --git a/cmd/chat-cli/main.go b/cmd/chat-cli/main.go index 95713a6..317d95a 100644 --- a/cmd/chat-cli/main.go +++ b/cmd/chat-cli/main.go @@ -145,7 +145,7 @@ func (a *App) cmdConnect(serverURL string) { a.lastQID = 0 a.mu.Unlock() - a.ui.AddStatus(fmt.Sprintf("[green]Connected! Nick: %s, Session: %s", resp.Nick, resp.SessionID)) + a.ui.AddStatus(fmt.Sprintf("[green]Connected! Nick: %s, Session: %d", resp.Nick, resp.ID)) a.ui.SetStatus(resp.Nick, "", "connected") // Start polling.