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// AgentInfo represents information about the agent.
 33type AgentInfo struct {
 34	IsBusy   bool                 `json:"is_busy"`
 35	IsReady  bool                 `json:"is_ready"`
 36	Model    catwalk.Model        `json:"model"`
 37	ModelCfg config.SelectedModel `json:"model_cfg"`
 38}
 39
 40// IsZero checks if the AgentInfo is zero-valued.
 41func (a AgentInfo) IsZero() bool {
 42	return !a.IsBusy && !a.IsReady && a.Model.ID == ""
 43}
 44
 45// AgentMessage represents a message sent to the agent.
 46type AgentMessage struct {
 47	SessionID   string       `json:"session_id"`
 48	Prompt      string       `json:"prompt"`
 49	Attachments []Attachment `json:"attachments,omitempty"`
 50}
 51
 52// AgentSession represents a session with its busy status.
 53type AgentSession struct {
 54	Session
 55	IsBusy bool `json:"is_busy"`
 56}
 57
 58// IsZero checks if the AgentSession is zero-valued.
 59func (a AgentSession) IsZero() bool {
 60	return a.ID == "" && !a.IsBusy
 61}
 62
 63// PermissionAction represents an action taken on a permission request.
 64type PermissionAction string
 65
 66const (
 67	PermissionAllow           PermissionAction = "allow"
 68	PermissionAllowForSession PermissionAction = "allow_session"
 69	PermissionDeny            PermissionAction = "deny"
 70)
 71
 72// MarshalText implements the [encoding.TextMarshaler] interface.
 73func (p PermissionAction) MarshalText() ([]byte, error) {
 74	return []byte(p), nil
 75}
 76
 77// UnmarshalText implements the [encoding.TextUnmarshaler] interface.
 78func (p *PermissionAction) UnmarshalText(text []byte) error {
 79	*p = PermissionAction(text)
 80	return nil
 81}
 82
 83// PermissionGrant represents a permission grant request.
 84type PermissionGrant struct {
 85	Permission PermissionRequest `json:"permission"`
 86	Action     PermissionAction  `json:"action"`
 87}
 88
 89// PermissionGrantResponse is the server's response to a permission
 90// grant call. Resolved is true when this call resolved the pending
 91// request, and false when the request had already been resolved by a
 92// previous caller (e.g., another client in a multi-subscriber UI). A
 93// false value is not an error.
 94type PermissionGrantResponse struct {
 95	Resolved bool `json:"resolved"`
 96}
 97
 98// PermissionSkipRequest represents a request to skip permission prompts.
 99type PermissionSkipRequest struct {
100	Skip bool `json:"skip"`
101}
102
103// LSPEventType represents the type of LSP event.
104type LSPEventType string
105
106const (
107	LSPEventStateChanged       LSPEventType = "state_changed"
108	LSPEventDiagnosticsChanged LSPEventType = "diagnostics_changed"
109)
110
111// MarshalText implements the [encoding.TextMarshaler] interface.
112func (e LSPEventType) MarshalText() ([]byte, error) {
113	return []byte(e), nil
114}
115
116// UnmarshalText implements the [encoding.TextUnmarshaler] interface.
117func (e *LSPEventType) UnmarshalText(data []byte) error {
118	*e = LSPEventType(data)
119	return nil
120}
121
122// LSPEvent represents an event in the LSP system.
123type LSPEvent struct {
124	Type            LSPEventType    `json:"type"`
125	Name            string          `json:"name"`
126	State           lsp.ServerState `json:"state"`
127	Error           error           `json:"error,omitempty"`
128	DiagnosticCount int             `json:"diagnostic_count,omitempty"`
129}
130
131// MarshalJSON implements the [json.Marshaler] interface.
132func (e LSPEvent) MarshalJSON() ([]byte, error) {
133	type Alias LSPEvent
134	return json.Marshal(&struct {
135		Error string `json:"error,omitempty"`
136		Alias
137	}{
138		Error: func() string {
139			if e.Error != nil {
140				return e.Error.Error()
141			}
142			return ""
143		}(),
144		Alias: Alias(e),
145	})
146}
147
148// UnmarshalJSON implements the [json.Unmarshaler] interface.
149func (e *LSPEvent) UnmarshalJSON(data []byte) error {
150	type Alias LSPEvent
151	aux := &struct {
152		Error string `json:"error,omitempty"`
153		Alias
154	}{
155		Alias: Alias(*e),
156	}
157	if err := json.Unmarshal(data, &aux); err != nil {
158		return err
159	}
160	*e = LSPEvent(aux.Alias)
161	if aux.Error != "" {
162		e.Error = errors.New(aux.Error)
163	}
164	return nil
165}
166
167// LSPClientInfo holds information about an LSP client's state.
168type LSPClientInfo struct {
169	Name            string          `json:"name"`
170	State           lsp.ServerState `json:"state"`
171	Error           error           `json:"error,omitempty"`
172	DiagnosticCount int             `json:"diagnostic_count,omitempty"`
173	ConnectedAt     time.Time       `json:"connected_at"`
174}
175
176// MarshalJSON implements the [json.Marshaler] interface.
177func (i LSPClientInfo) MarshalJSON() ([]byte, error) {
178	type Alias LSPClientInfo
179	return json.Marshal(&struct {
180		Error string `json:"error,omitempty"`
181		Alias
182	}{
183		Error: func() string {
184			if i.Error != nil {
185				return i.Error.Error()
186			}
187			return ""
188		}(),
189		Alias: Alias(i),
190	})
191}
192
193// UnmarshalJSON implements the [json.Unmarshaler] interface.
194func (i *LSPClientInfo) UnmarshalJSON(data []byte) error {
195	type Alias LSPClientInfo
196	aux := &struct {
197		Error string `json:"error,omitempty"`
198		Alias
199	}{
200		Alias: Alias(*i),
201	}
202	if err := json.Unmarshal(data, &aux); err != nil {
203		return err
204	}
205	*i = LSPClientInfo(aux.Alias)
206	if aux.Error != "" {
207		i.Error = errors.New(aux.Error)
208	}
209	return nil
210}