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// PermissionSkipRequest represents a request to skip permission prompts.
 90type PermissionSkipRequest struct {
 91	Skip bool `json:"skip"`
 92}
 93
 94// LSPEventType represents the type of LSP event.
 95type LSPEventType string
 96
 97const (
 98	LSPEventStateChanged       LSPEventType = "state_changed"
 99	LSPEventDiagnosticsChanged LSPEventType = "diagnostics_changed"
100)
101
102// MarshalText implements the [encoding.TextMarshaler] interface.
103func (e LSPEventType) MarshalText() ([]byte, error) {
104	return []byte(e), nil
105}
106
107// UnmarshalText implements the [encoding.TextUnmarshaler] interface.
108func (e *LSPEventType) UnmarshalText(data []byte) error {
109	*e = LSPEventType(data)
110	return nil
111}
112
113// LSPEvent represents an event in the LSP system.
114type LSPEvent struct {
115	Type            LSPEventType    `json:"type"`
116	Name            string          `json:"name"`
117	State           lsp.ServerState `json:"state"`
118	Error           error           `json:"error,omitempty"`
119	DiagnosticCount int             `json:"diagnostic_count,omitempty"`
120}
121
122// MarshalJSON implements the [json.Marshaler] interface.
123func (e LSPEvent) MarshalJSON() ([]byte, error) {
124	type Alias LSPEvent
125	return json.Marshal(&struct {
126		Error string `json:"error,omitempty"`
127		Alias
128	}{
129		Error: func() string {
130			if e.Error != nil {
131				return e.Error.Error()
132			}
133			return ""
134		}(),
135		Alias: Alias(e),
136	})
137}
138
139// UnmarshalJSON implements the [json.Unmarshaler] interface.
140func (e *LSPEvent) UnmarshalJSON(data []byte) error {
141	type Alias LSPEvent
142	aux := &struct {
143		Error string `json:"error,omitempty"`
144		Alias
145	}{
146		Alias: Alias(*e),
147	}
148	if err := json.Unmarshal(data, &aux); err != nil {
149		return err
150	}
151	*e = LSPEvent(aux.Alias)
152	if aux.Error != "" {
153		e.Error = errors.New(aux.Error)
154	}
155	return nil
156}
157
158// LSPClientInfo holds information about an LSP client's state.
159type LSPClientInfo struct {
160	Name            string          `json:"name"`
161	State           lsp.ServerState `json:"state"`
162	Error           error           `json:"error,omitempty"`
163	DiagnosticCount int             `json:"diagnostic_count,omitempty"`
164	ConnectedAt     time.Time       `json:"connected_at"`
165}
166
167// MarshalJSON implements the [json.Marshaler] interface.
168func (i LSPClientInfo) MarshalJSON() ([]byte, error) {
169	type Alias LSPClientInfo
170	return json.Marshal(&struct {
171		Error string `json:"error,omitempty"`
172		Alias
173	}{
174		Error: func() string {
175			if i.Error != nil {
176				return i.Error.Error()
177			}
178			return ""
179		}(),
180		Alias: Alias(i),
181	})
182}
183
184// UnmarshalJSON implements the [json.Unmarshaler] interface.
185func (i *LSPClientInfo) UnmarshalJSON(data []byte) error {
186	type Alias LSPClientInfo
187	aux := &struct {
188		Error string `json:"error,omitempty"`
189		Alias
190	}{
191		Alias: Alias(*i),
192	}
193	if err := json.Unmarshal(data, &aux); err != nil {
194		return err
195	}
196	*i = LSPClientInfo(aux.Alias)
197	if aux.Error != "" {
198		i.Error = errors.New(aux.Error)
199	}
200	return nil
201}