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