proto.go

  1package proto
  2
  3import (
  4	"encoding/json"
  5	"errors"
  6	"time"
  7
  8	"charm.land/catwalk/pkg/catwalk"
  9	"github.com/charmbracelet/crush/internal/config"
 10	"github.com/charmbracelet/crush/internal/lsp"
 11)
 12
 13// Workspace represents a running app.App workspace with its associated
 14// resources and state.
 15type Workspace struct {
 16	ID       string         `json:"id"`
 17	Path     string         `json:"path"`
 18	YOLO     bool           `json:"yolo,omitempty"`
 19	Debug    bool           `json:"debug,omitempty"`
 20	DataDir  string         `json:"data_dir,omitempty"`
 21	Version  string         `json:"version,omitempty"`
 22	ClientID string         `json:"client_id,omitempty"`
 23	Config   *config.Config `json:"config,omitempty"`
 24	Env      []string       `json:"env,omitempty"`
 25}
 26
 27// Error represents an error response.
 28type Error struct {
 29	Message string `json:"message"`
 30}
 31
 32// ConfigChanged is published whenever the workspace's configuration is
 33// mutated by a backend operation. Clients react by re-fetching the
 34// workspace snapshot so cached config stays in sync across subscribers.
 35type ConfigChanged struct {
 36	WorkspaceID string `json:"workspace_id"`
 37}
 38
 39// AgentInfo represents information about the agent.
 40type AgentInfo struct {
 41	IsBusy   bool                 `json:"is_busy"`
 42	IsReady  bool                 `json:"is_ready"`
 43	Model    catwalk.Model        `json:"model"`
 44	ModelCfg config.SelectedModel `json:"model_cfg"`
 45}
 46
 47// IsZero checks if the AgentInfo is zero-valued.
 48func (a AgentInfo) IsZero() bool {
 49	return !a.IsBusy && !a.IsReady && a.Model.ID == ""
 50}
 51
 52// AgentMessage represents a message sent to the agent.
 53type AgentMessage struct {
 54	SessionID   string       `json:"session_id"`
 55	Prompt      string       `json:"prompt"`
 56	Attachments []Attachment `json:"attachments,omitempty"`
 57}
 58
 59// AgentSession represents a session with its busy status.
 60type AgentSession struct {
 61	Session
 62	IsBusy bool `json:"is_busy"`
 63}
 64
 65// IsZero checks if the AgentSession is zero-valued.
 66func (a AgentSession) IsZero() bool {
 67	return a.ID == "" && !a.IsBusy
 68}
 69
 70// PermissionAction represents an action taken on a permission request.
 71type PermissionAction string
 72
 73const (
 74	PermissionAllow           PermissionAction = "allow"
 75	PermissionAllowForSession PermissionAction = "allow_session"
 76	PermissionDeny            PermissionAction = "deny"
 77)
 78
 79// MarshalText implements the [encoding.TextMarshaler] interface.
 80func (p PermissionAction) MarshalText() ([]byte, error) {
 81	return []byte(p), nil
 82}
 83
 84// UnmarshalText implements the [encoding.TextUnmarshaler] interface.
 85func (p *PermissionAction) UnmarshalText(text []byte) error {
 86	*p = PermissionAction(text)
 87	return nil
 88}
 89
 90// PermissionGrant represents a permission grant request.
 91type PermissionGrant struct {
 92	Permission PermissionRequest `json:"permission"`
 93	Action     PermissionAction  `json:"action"`
 94}
 95
 96// PermissionGrantResponse is the server's response to a permission
 97// grant call. Resolved is true when this call resolved the pending
 98// request, and false when the request had already been resolved by a
 99// previous caller (e.g., another client in a multi-subscriber UI). A
100// false value is not an error.
101type PermissionGrantResponse struct {
102	Resolved bool `json:"resolved"`
103}
104
105// PermissionSkipRequest represents a request to skip permission prompts.
106type PermissionSkipRequest struct {
107	Skip bool `json:"skip"`
108}
109
110// LSPEventType represents the type of LSP event.
111type LSPEventType string
112
113const (
114	LSPEventStateChanged       LSPEventType = "state_changed"
115	LSPEventDiagnosticsChanged LSPEventType = "diagnostics_changed"
116)
117
118// MarshalText implements the [encoding.TextMarshaler] interface.
119func (e LSPEventType) MarshalText() ([]byte, error) {
120	return []byte(e), nil
121}
122
123// UnmarshalText implements the [encoding.TextUnmarshaler] interface.
124func (e *LSPEventType) UnmarshalText(data []byte) error {
125	*e = LSPEventType(data)
126	return nil
127}
128
129// LSPEvent represents an event in the LSP system.
130type LSPEvent struct {
131	Type            LSPEventType    `json:"type"`
132	Name            string          `json:"name"`
133	State           lsp.ServerState `json:"state"`
134	Error           error           `json:"error,omitempty"`
135	DiagnosticCount int             `json:"diagnostic_count,omitempty"`
136}
137
138// MarshalJSON implements the [json.Marshaler] interface.
139func (e LSPEvent) MarshalJSON() ([]byte, error) {
140	type Alias LSPEvent
141	return json.Marshal(&struct {
142		Error string `json:"error,omitempty"`
143		Alias
144	}{
145		Error: func() string {
146			if e.Error != nil {
147				return e.Error.Error()
148			}
149			return ""
150		}(),
151		Alias: Alias(e),
152	})
153}
154
155// UnmarshalJSON implements the [json.Unmarshaler] interface.
156func (e *LSPEvent) UnmarshalJSON(data []byte) error {
157	type Alias LSPEvent
158	aux := &struct {
159		Error string `json:"error,omitempty"`
160		Alias
161	}{
162		Alias: Alias(*e),
163	}
164	if err := json.Unmarshal(data, &aux); err != nil {
165		return err
166	}
167	*e = LSPEvent(aux.Alias)
168	if aux.Error != "" {
169		e.Error = errors.New(aux.Error)
170	}
171	return nil
172}
173
174// LSPClientInfo holds information about an LSP client's state.
175type LSPClientInfo struct {
176	Name            string          `json:"name"`
177	State           lsp.ServerState `json:"state"`
178	Error           error           `json:"error,omitempty"`
179	DiagnosticCount int             `json:"diagnostic_count,omitempty"`
180	ConnectedAt     time.Time       `json:"connected_at"`
181}
182
183// MarshalJSON implements the [json.Marshaler] interface.
184func (i LSPClientInfo) MarshalJSON() ([]byte, error) {
185	type Alias LSPClientInfo
186	return json.Marshal(&struct {
187		Error string `json:"error,omitempty"`
188		Alias
189	}{
190		Error: func() string {
191			if i.Error != nil {
192				return i.Error.Error()
193			}
194			return ""
195		}(),
196		Alias: Alias(i),
197	})
198}
199
200// UnmarshalJSON implements the [json.Unmarshaler] interface.
201func (i *LSPClientInfo) UnmarshalJSON(data []byte) error {
202	type Alias LSPClientInfo
203	aux := &struct {
204		Error string `json:"error,omitempty"`
205		Alias
206	}{
207		Alias: Alias(*i),
208	}
209	if err := json.Unmarshal(data, &aux); err != nil {
210		return err
211	}
212	*i = LSPClientInfo(aux.Alias)
213	if aux.Error != "" {
214		i.Error = errors.New(aux.Error)
215	}
216	return nil
217}