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