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