proto.go

  1package proto
  2
  3import (
  4	"encoding/json"
  5	"errors"
  6	"time"
  7
  8	"charm.land/catwalk/pkg/catwalk"
  9	"git.secluded.site/crush/internal/config"
 10	"git.secluded.site/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}