workspace.go

  1// Package workspace defines the Workspace interface used by all
  2// frontends (TUI, CLI) to interact with a running workspace. Two
  3// implementations exist: one wrapping a local app.App instance and one
  4// wrapping the HTTP client SDK.
  5package workspace
  6
  7import (
  8	"context"
  9	"time"
 10
 11	tea "charm.land/bubbletea/v2"
 12	"charm.land/catwalk/pkg/catwalk"
 13	mcptools "github.com/charmbracelet/crush/internal/agent/tools/mcp"
 14	"github.com/charmbracelet/crush/internal/config"
 15	"github.com/charmbracelet/crush/internal/history"
 16	"github.com/charmbracelet/crush/internal/lsp"
 17	"github.com/charmbracelet/crush/internal/message"
 18	"github.com/charmbracelet/crush/internal/oauth"
 19	"github.com/charmbracelet/crush/internal/permission"
 20	"github.com/charmbracelet/crush/internal/session"
 21)
 22
 23// LSPClientInfo holds information about an LSP client's state. This is
 24// the frontend-facing type; implementations translate from the
 25// underlying app or proto representation.
 26type LSPClientInfo struct {
 27	Name            string
 28	State           lsp.ServerState
 29	Error           error
 30	DiagnosticCount int
 31	ConnectedAt     time.Time
 32}
 33
 34// LSPEventType represents the type of LSP event.
 35type LSPEventType string
 36
 37const (
 38	LSPEventStateChanged       LSPEventType = "state_changed"
 39	LSPEventDiagnosticsChanged LSPEventType = "diagnostics_changed"
 40)
 41
 42// LSPEvent represents an LSP event forwarded to the TUI.
 43type LSPEvent struct {
 44	Type            LSPEventType
 45	Name            string
 46	State           lsp.ServerState
 47	Error           error
 48	DiagnosticCount int
 49}
 50
 51// AgentModel holds the model information exposed to the UI.
 52type AgentModel struct {
 53	CatwalkCfg catwalk.Model
 54	ModelCfg   config.SelectedModel
 55}
 56
 57// Workspace is the main abstraction consumed by the TUI and CLI. It
 58// groups every operation a frontend needs to perform against a running
 59// workspace, regardless of whether the workspace is in-process or
 60// remote.
 61type Workspace interface {
 62	// Sessions
 63	CreateSession(ctx context.Context, title string) (session.Session, error)
 64	GetSession(ctx context.Context, sessionID string) (session.Session, error)
 65	ListSessions(ctx context.Context) ([]session.Session, error)
 66	SaveSession(ctx context.Context, sess session.Session) (session.Session, error)
 67	DeleteSession(ctx context.Context, sessionID string) error
 68	CreateAgentToolSessionID(messageID, toolCallID string) string
 69	ParseAgentToolSessionID(sessionID string) (messageID string, toolCallID string, ok bool)
 70
 71	// Messages
 72	ListMessages(ctx context.Context, sessionID string) ([]message.Message, error)
 73	ListUserMessages(ctx context.Context, sessionID string) ([]message.Message, error)
 74	ListAllUserMessages(ctx context.Context) ([]message.Message, error)
 75
 76	// Agent
 77	AgentRun(ctx context.Context, sessionID, prompt string, attachments ...message.Attachment) error
 78	AgentCancel(sessionID string)
 79	AgentIsBusy() bool
 80	AgentIsSessionBusy(sessionID string) bool
 81	AgentModel() AgentModel
 82	AgentIsReady() bool
 83	AgentQueuedPrompts(sessionID string) int
 84	AgentQueuedPromptsList(sessionID string) []string
 85	AgentClearQueue(sessionID string)
 86	AgentSummarize(ctx context.Context, sessionID string) error
 87	UpdateAgentModel(ctx context.Context) error
 88	InitCoderAgent(ctx context.Context) error
 89	GetDefaultSmallModel(providerID string) config.SelectedModel
 90
 91	// Permissions
 92	//
 93	// PermissionGrant, PermissionGrantPersistent, and PermissionDeny
 94	// return true if the call resolved the pending request and false if
 95	// it had already been resolved by another subscriber (or is no
 96	// longer pending). A false return is not an error; the modal can
 97	// still close locally because the resolution will arrive via the
 98	// PermissionNotification event stream regardless of which client
 99	// won the race.
100	PermissionGrant(perm permission.PermissionRequest) bool
101	PermissionGrantPersistent(perm permission.PermissionRequest) bool
102	PermissionDeny(perm permission.PermissionRequest) bool
103	PermissionSkipRequests() bool
104	PermissionSetSkipRequests(skip bool)
105
106	// FileTracker
107	FileTrackerRecordRead(ctx context.Context, sessionID, path string)
108	FileTrackerLastReadTime(ctx context.Context, sessionID, path string) time.Time
109	FileTrackerListReadFiles(ctx context.Context, sessionID string) ([]string, error)
110
111	// History
112	ListSessionHistory(ctx context.Context, sessionID string) ([]history.File, error)
113
114	// LSP
115	LSPStart(ctx context.Context, path string)
116	LSPStopAll(ctx context.Context)
117	LSPGetStates() map[string]LSPClientInfo
118	LSPGetDiagnosticCounts(name string) lsp.DiagnosticCounts
119
120	// Config (read-only data)
121	Config() *config.Config
122	WorkingDir() string
123	Resolver() config.VariableResolver
124
125	// Config mutations (proxied to server in client mode)
126	UpdatePreferredModel(scope config.Scope, modelType config.SelectedModelType, model config.SelectedModel) error
127	SetCompactMode(scope config.Scope, enabled bool) error
128	SetProviderAPIKey(scope config.Scope, providerID string, apiKey any) error
129	SetConfigField(scope config.Scope, key string, value any) error
130	RemoveConfigField(scope config.Scope, key string) error
131	ImportCopilot() (*oauth.Token, bool)
132	RefreshOAuthToken(ctx context.Context, scope config.Scope, providerID string) error
133
134	// Project lifecycle
135	ProjectNeedsInitialization() (bool, error)
136	MarkProjectInitialized() error
137	InitializePrompt() (string, error)
138
139	// MCP operations (server-side in client mode)
140	MCPGetStates() map[string]mcptools.ClientInfo
141	MCPRefreshPrompts(ctx context.Context, name string)
142	MCPRefreshResources(ctx context.Context, name string)
143	RefreshMCPTools(ctx context.Context, name string)
144	ReadMCPResource(ctx context.Context, name, uri string) ([]MCPResourceContents, error)
145	GetMCPPrompt(clientID, promptID string, args map[string]string) (string, error)
146	EnableDockerMCP(ctx context.Context) error
147	DisableDockerMCP() error
148
149	// Events
150	Subscribe(program *tea.Program)
151	Shutdown()
152}
153
154// MCPResourceContents holds the contents of an MCP resource.
155type MCPResourceContents struct {
156	URI      string `json:"uri"`
157	MIMEType string `json:"mime_type,omitempty"`
158	Text     string `json:"text,omitempty"`
159	Blob     []byte `json:"blob,omitempty"`
160}