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