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