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}