@caretive/caret-cli 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/.npmrc.tmp +2 -0
  2. package/README.md +72 -0
  3. package/cmd/cline/main.go +348 -0
  4. package/cmd/cline-host/main.go +71 -0
  5. package/e2e/default_update_test.go +154 -0
  6. package/e2e/helpers_test.go +378 -0
  7. package/e2e/main_test.go +47 -0
  8. package/e2e/mixed_stress_test.go +120 -0
  9. package/e2e/sqlite_helper.go +161 -0
  10. package/e2e/start_list_test.go +178 -0
  11. package/go.mod +64 -0
  12. package/go.sum +162 -0
  13. package/man/cline.1 +331 -0
  14. package/man/cline.1.md +332 -0
  15. package/package.json +54 -0
  16. package/pkg/cli/auth/auth_cline_provider.go +285 -0
  17. package/pkg/cli/auth/auth_menu.go +323 -0
  18. package/pkg/cli/auth/auth_subscription.go +130 -0
  19. package/pkg/cli/auth/byo_quick_setup.go +247 -0
  20. package/pkg/cli/auth/models_cline.go +141 -0
  21. package/pkg/cli/auth/models_list_fetch.go +156 -0
  22. package/pkg/cli/auth/models_list_static.go +69 -0
  23. package/pkg/cli/auth/providers_byo.go +184 -0
  24. package/pkg/cli/auth/providers_list.go +517 -0
  25. package/pkg/cli/auth/update_api_configurations.go +647 -0
  26. package/pkg/cli/auth/wizard_byo.go +764 -0
  27. package/pkg/cli/auth/wizard_byo_bedrock.go +193 -0
  28. package/pkg/cli/auth/wizard_byo_oca.go +366 -0
  29. package/pkg/cli/auth.go +43 -0
  30. package/pkg/cli/clerror/cline_error.go +187 -0
  31. package/pkg/cli/config/manager.go +208 -0
  32. package/pkg/cli/config/settings_renderer.go +198 -0
  33. package/pkg/cli/config.go +152 -0
  34. package/pkg/cli/display/ansi.go +27 -0
  35. package/pkg/cli/display/banner.go +211 -0
  36. package/pkg/cli/display/deduplicator.go +95 -0
  37. package/pkg/cli/display/markdown_renderer.go +139 -0
  38. package/pkg/cli/display/renderer.go +304 -0
  39. package/pkg/cli/display/segment_streamer.go +212 -0
  40. package/pkg/cli/display/streaming.go +134 -0
  41. package/pkg/cli/display/system_renderer.go +269 -0
  42. package/pkg/cli/display/tool_renderer.go +455 -0
  43. package/pkg/cli/display/tool_result_parser.go +371 -0
  44. package/pkg/cli/display/typewriter.go +210 -0
  45. package/pkg/cli/doctor.go +65 -0
  46. package/pkg/cli/global/cline-clients.go +501 -0
  47. package/pkg/cli/global/global.go +113 -0
  48. package/pkg/cli/global/registry.go +304 -0
  49. package/pkg/cli/handlers/ask_handlers.go +339 -0
  50. package/pkg/cli/handlers/handler.go +130 -0
  51. package/pkg/cli/handlers/say_handlers.go +521 -0
  52. package/pkg/cli/instances.go +506 -0
  53. package/pkg/cli/logs.go +382 -0
  54. package/pkg/cli/output/coordinator.go +167 -0
  55. package/pkg/cli/output/input_model.go +497 -0
  56. package/pkg/cli/sqlite/locks.go +366 -0
  57. package/pkg/cli/task/history_handler.go +72 -0
  58. package/pkg/cli/task/input_handler.go +577 -0
  59. package/pkg/cli/task/manager.go +1283 -0
  60. package/pkg/cli/task/settings_parser.go +754 -0
  61. package/pkg/cli/task/stream_coordinator.go +60 -0
  62. package/pkg/cli/task.go +675 -0
  63. package/pkg/cli/terminal/keyboard.go +695 -0
  64. package/pkg/cli/tui/HELP_WANTED.md +1 -0
  65. package/pkg/cli/types/history.go +17 -0
  66. package/pkg/cli/types/messages.go +329 -0
  67. package/pkg/cli/types/state.go +59 -0
  68. package/pkg/cli/updater/updater.go +409 -0
  69. package/pkg/cli/version.go +43 -0
  70. package/pkg/common/constants.go +6 -0
  71. package/pkg/common/schema.go +54 -0
  72. package/pkg/common/types.go +54 -0
  73. package/pkg/common/utils.go +185 -0
  74. package/pkg/generated/field_overrides.go +39 -0
  75. package/pkg/generated/providers.go +1584 -0
  76. package/pkg/hostbridge/diff.go +351 -0
  77. package/pkg/hostbridge/disabled/watch.go +39 -0
  78. package/pkg/hostbridge/disabled/window.go +63 -0
  79. package/pkg/hostbridge/disabled/workspace.go +66 -0
  80. package/pkg/hostbridge/env.go +166 -0
  81. package/pkg/hostbridge/grpc_server.go +113 -0
  82. package/pkg/hostbridge/simple.go +43 -0
  83. package/pkg/hostbridge/simple_workspace.go +85 -0
  84. package/pkg/hostbridge/window.go +129 -0
  85. package/scripts/publish-caret-cli.sh +39 -0
@@ -0,0 +1,130 @@
1
+ package handlers
2
+
3
+ import (
4
+ "github.com/cline/cli/pkg/cli/display"
5
+ "github.com/cline/cli/pkg/cli/types"
6
+ )
7
+
8
+ // MessageHandler defines the interface for handling different message types
9
+ type MessageHandler interface {
10
+ // CanHandle returns true if this handler can process the given message
11
+ CanHandle(msg *types.ClineMessage) bool
12
+
13
+ // Handle processes the message and renders it using the display context
14
+ Handle(msg *types.ClineMessage, dc *DisplayContext) error
15
+
16
+ // GetPriority returns the priority of this handler (higher = more priority)
17
+ GetPriority() int
18
+
19
+ // GetName returns a human-readable name for this handler
20
+ GetName() string
21
+ }
22
+
23
+ // DisplayContext provides context and utilities for message handlers
24
+ type DisplayContext struct {
25
+ State *types.ConversationState
26
+ Renderer *display.Renderer
27
+ ToolRenderer *display.ToolRenderer
28
+ SystemRenderer *display.SystemMessageRenderer
29
+ IsLast bool
30
+ IsPartial bool
31
+ Verbose bool
32
+ MessageIndex int
33
+ IsStreamingMode bool
34
+ IsInteractive bool
35
+ }
36
+
37
+ // BaseHandler provides common functionality for message handlers
38
+ type BaseHandler struct {
39
+ name string
40
+ priority int
41
+ }
42
+
43
+ // NewBaseHandler creates a new base handler
44
+ func NewBaseHandler(name string, priority int) *BaseHandler {
45
+ return &BaseHandler{
46
+ name: name,
47
+ priority: priority,
48
+ }
49
+ }
50
+
51
+ // GetName returns the handler name
52
+ func (h *BaseHandler) GetName() string {
53
+ return h.name
54
+ }
55
+
56
+ // GetPriority returns the handler priority
57
+ func (h *BaseHandler) GetPriority() int {
58
+ return h.priority
59
+ }
60
+
61
+ // HandlerRegistry manages a collection of message handlers
62
+ type HandlerRegistry struct {
63
+ handlers []MessageHandler
64
+ }
65
+
66
+ // NewHandlerRegistry creates a new handler registry
67
+ func NewHandlerRegistry() *HandlerRegistry {
68
+ return &HandlerRegistry{
69
+ handlers: make([]MessageHandler, 0),
70
+ }
71
+ }
72
+
73
+ // Register adds a handler to the registry
74
+ func (r *HandlerRegistry) Register(handler MessageHandler) {
75
+ r.handlers = append(r.handlers, handler)
76
+
77
+ // Sort handlers by priority (highest first)
78
+ for i := len(r.handlers) - 1; i > 0; i-- {
79
+ if r.handlers[i].GetPriority() > r.handlers[i-1].GetPriority() {
80
+ r.handlers[i], r.handlers[i-1] = r.handlers[i-1], r.handlers[i]
81
+ } else {
82
+ break
83
+ }
84
+ }
85
+ }
86
+
87
+ // Handle finds the appropriate handler and processes the message
88
+ func (r *HandlerRegistry) Handle(msg *types.ClineMessage, dc *DisplayContext) error {
89
+ for _, handler := range r.handlers {
90
+ if handler.CanHandle(msg) {
91
+ return handler.Handle(msg, dc)
92
+ }
93
+ }
94
+
95
+ // If no specific handler found, use default text handler
96
+ return r.handleDefault(msg, dc)
97
+ }
98
+
99
+ // handleDefault provides default handling for unrecognized messages
100
+ func (r *HandlerRegistry) handleDefault(msg *types.ClineMessage, dc *DisplayContext) error {
101
+ if msg.Text == "" {
102
+ return nil
103
+ }
104
+
105
+ prefix := "RESPONSE:"
106
+
107
+ return dc.Renderer.RenderMessage(prefix, msg.Text, true)
108
+ }
109
+
110
+ // GetHandlers returns all registered handlers
111
+ func (r *HandlerRegistry) GetHandlers() []MessageHandler {
112
+ return r.handlers
113
+ }
114
+
115
+ // GetHandlerByName finds a handler by name
116
+ func (r *HandlerRegistry) GetHandlerByName(name string) MessageHandler {
117
+ for _, handler := range r.handlers {
118
+ if handler.GetName() == name {
119
+ return handler
120
+ }
121
+ }
122
+ return nil
123
+ }
124
+
125
+ // HandlerPriorities defines standard priority levels for handlers
126
+ const (
127
+ PriorityHigh = 100
128
+ PriorityNormal = 50
129
+ PriorityLow = 10
130
+ )
@@ -0,0 +1,521 @@
1
+ package handlers
2
+
3
+ import (
4
+ "encoding/json"
5
+ "fmt"
6
+ "strings"
7
+
8
+ "github.com/cline/cli/pkg/cli/clerror"
9
+ "github.com/cline/cli/pkg/cli/types"
10
+ "github.com/cline/cli/pkg/cli/output"
11
+ )
12
+
13
+ // SayHandler handles SAY type messages
14
+ type SayHandler struct {
15
+ *BaseHandler
16
+ }
17
+
18
+ // NewSayHandler creates a new SAY handler
19
+ func NewSayHandler() *SayHandler {
20
+ return &SayHandler{
21
+ BaseHandler: NewBaseHandler("say", PriorityNormal),
22
+ }
23
+ }
24
+
25
+ // CanHandle returns true if this is a SAY message
26
+ func (h *SayHandler) CanHandle(msg *types.ClineMessage) bool {
27
+ return msg.IsSay()
28
+ }
29
+
30
+ // Handle processes SAY messages
31
+ func (h *SayHandler) Handle(msg *types.ClineMessage, dc *DisplayContext) error {
32
+ timestamp := msg.GetTimestamp()
33
+
34
+ switch msg.Say {
35
+ case string(types.SayTypeTask):
36
+ return h.handleTask(msg, dc)
37
+ case string(types.SayTypeError):
38
+ return h.handleError(msg, dc)
39
+ case string(types.SayTypeAPIReqStarted):
40
+ return h.handleAPIReqStarted(msg, dc)
41
+ case string(types.SayTypeAPIReqFinished):
42
+ return h.handleAPIReqFinished(msg, dc)
43
+ case string(types.SayTypeText):
44
+ return h.handleText(msg, dc)
45
+ case string(types.SayTypeReasoning):
46
+ return h.handleReasoning(msg, dc)
47
+ case string(types.SayTypeCompletionResult):
48
+ return h.handleCompletionResult(msg, dc)
49
+ case string(types.SayTypeUserFeedback):
50
+ return h.handleUserFeedback(msg, dc)
51
+ case string(types.SayTypeUserFeedbackDiff):
52
+ return h.handleUserFeedbackDiff(msg, dc)
53
+ case string(types.SayTypeAPIReqRetried):
54
+ return h.handleAPIReqRetried(msg, dc)
55
+ case string(types.SayTypeErrorRetry):
56
+ return h.handleErrorRetry(msg, dc)
57
+ case string(types.SayTypeCommand):
58
+ return h.handleCommand(msg, dc)
59
+ case string(types.SayTypeCommandOutput):
60
+ return h.handleCommandOutput(msg, dc)
61
+ case string(types.SayTypeTool):
62
+ return h.handleTool(msg, dc)
63
+ case string(types.SayTypeShellIntegrationWarning):
64
+ return h.handleShellIntegrationWarning(msg, dc)
65
+ case string(types.SayTypeBrowserActionLaunch):
66
+ return h.handleBrowserActionLaunch(msg, dc)
67
+ case string(types.SayTypeBrowserAction):
68
+ return h.handleBrowserAction(msg, dc)
69
+ case string(types.SayTypeBrowserActionResult):
70
+ return h.handleBrowserActionResult(msg, dc)
71
+ case string(types.SayTypeMcpServerRequestStarted):
72
+ return h.handleMcpServerRequestStarted(msg, dc)
73
+ case string(types.SayTypeMcpServerResponse):
74
+ return h.handleMcpServerResponse(msg, dc)
75
+ case string(types.SayTypeMcpNotification):
76
+ return h.handleMcpNotification(msg, dc)
77
+ case string(types.SayTypeUseMcpServer):
78
+ return h.handleUseMcpServer(msg, dc)
79
+ case string(types.SayTypeDiffError):
80
+ return h.handleDiffError(msg, dc)
81
+ case string(types.SayTypeDeletedAPIReqs):
82
+ return h.handleDeletedAPIReqs(msg, dc)
83
+ case string(types.SayTypeClineignoreError):
84
+ return h.handleClineignoreError(msg, dc)
85
+ case string(types.SayTypeCheckpointCreated):
86
+ return h.handleCheckpointCreated(msg, dc, timestamp)
87
+ case string(types.SayTypeLoadMcpDocumentation):
88
+ return h.handleLoadMcpDocumentation(msg, dc)
89
+ case string(types.SayTypeInfo):
90
+ return h.handleInfo(msg, dc)
91
+ case string(types.SayTypeTaskProgress):
92
+ return h.handleTaskProgress(msg, dc)
93
+ default:
94
+ return h.handleDefault(msg, dc)
95
+ }
96
+ }
97
+
98
+ // handleTask handles task messages
99
+ func (h *SayHandler) handleTask(msg *types.ClineMessage, dc *DisplayContext) error {
100
+ return nil
101
+ }
102
+
103
+ // handleError handles error messages
104
+ func (h *SayHandler) handleError(msg *types.ClineMessage, dc *DisplayContext) error {
105
+ return dc.Renderer.RenderMessage("ERROR", msg.Text, true)
106
+ }
107
+
108
+ // handleAPIReqStarted handles API request started messages
109
+ func (h *SayHandler) handleAPIReqStarted(msg *types.ClineMessage, dc *DisplayContext) error {
110
+ // Parse API request info
111
+ apiInfo := types.APIRequestInfo{Cost: -1}
112
+ if err := json.Unmarshal([]byte(msg.Text), &apiInfo); err != nil {
113
+ return dc.Renderer.RenderMessage("API INFO", msg.Text, true)
114
+ }
115
+
116
+ // Check for streaming failed message with error details
117
+ if apiInfo.StreamingFailedMessage != "" {
118
+ clineErr, _ := clerror.ParseClineError(apiInfo.StreamingFailedMessage)
119
+ if clineErr != nil {
120
+ return h.renderClineError(clineErr, dc)
121
+ }
122
+ }
123
+
124
+ // Handle different API request states
125
+ if apiInfo.CancelReason != "" {
126
+ if apiInfo.CancelReason == "user_cancelled" {
127
+ return dc.Renderer.RenderMessage("API INFO", "Request Cancelled", true)
128
+ } else if apiInfo.CancelReason == "retries_exhausted" {
129
+ return dc.Renderer.RenderMessage("API INFO", "Request Failed (Retries Exhausted)", true)
130
+ }
131
+ return dc.Renderer.RenderMessage("API INFO", "Streaming Failed", true)
132
+ }
133
+
134
+ if apiInfo.Cost >= 0 {
135
+ return dc.Renderer.RenderAPI("request completed", &apiInfo)
136
+ }
137
+
138
+ // Check for retry status
139
+ if apiInfo.RetryStatus != nil {
140
+ return dc.Renderer.RenderRetry(
141
+ apiInfo.RetryStatus.Attempt,
142
+ apiInfo.RetryStatus.MaxAttempts,
143
+ apiInfo.RetryStatus.DelaySec)
144
+ }
145
+
146
+ return dc.Renderer.RenderAPI("processing request", &apiInfo)
147
+ }
148
+
149
+ // renderClineError renders a ClineError with appropriate formatting based on type
150
+ func (h *SayHandler) renderClineError(err *clerror.ClineError, dc *DisplayContext) error {
151
+ if dc.SystemRenderer == nil {
152
+ return dc.Renderer.RenderMessage("ERROR", err.Message, true)
153
+ }
154
+
155
+ switch err.GetErrorType() {
156
+ case clerror.ErrorTypeBalance:
157
+ return dc.SystemRenderer.RenderBalanceError(err)
158
+ case clerror.ErrorTypeAuth:
159
+ return dc.SystemRenderer.RenderAuthError(err)
160
+ case clerror.ErrorTypeRateLimit:
161
+ return dc.SystemRenderer.RenderRateLimitError(err)
162
+ default:
163
+ return dc.SystemRenderer.RenderAPIError(err)
164
+ }
165
+ }
166
+
167
+ // handleAPIReqFinished handles API request finished messages
168
+ func (h *SayHandler) handleAPIReqFinished(msg *types.ClineMessage, dc *DisplayContext) error {
169
+ // This message type is typically not displayed as it's handled by the started message
170
+ return nil
171
+ }
172
+
173
+ // handleText handles regular text messages
174
+ func (h *SayHandler) handleText(msg *types.ClineMessage, dc *DisplayContext) error {
175
+ if msg.Text == "" {
176
+ return nil
177
+ }
178
+
179
+ // Special case for the user's task input
180
+ if dc.MessageIndex == 0 {
181
+ markdown := formatUserMessage(msg.Text)
182
+ rendered := dc.Renderer.RenderMarkdown(markdown)
183
+ output.Printf("%s", rendered)
184
+ output.Printf("\n")
185
+ return nil
186
+ }
187
+
188
+ // Regular Cline text response
189
+ var rendered string
190
+ if dc.IsStreamingMode {
191
+ // In streaming mode, header already shown by partial stream
192
+ rendered = dc.Renderer.RenderMarkdown(msg.Text)
193
+ output.Printf("%s\n", rendered)
194
+ } else {
195
+ // In non-streaming mode, render header + body together
196
+ markdown := fmt.Sprintf("### Cline responds\n\n%s", msg.Text)
197
+ rendered = dc.Renderer.RenderMarkdown(markdown)
198
+ output.Printf("\n%s\n", rendered)
199
+ }
200
+ return nil
201
+ }
202
+
203
+ // handleReasoning handles reasoning messages
204
+ func (h *SayHandler) handleReasoning(msg *types.ClineMessage, dc *DisplayContext) error {
205
+ if msg.Text == "" {
206
+ return nil
207
+ }
208
+
209
+ var rendered string
210
+ if dc.IsStreamingMode {
211
+ // In streaming mode, header already shown by partial stream
212
+ rendered = dc.Renderer.RenderMarkdown(msg.Text)
213
+ output.Printf("%s\n", rendered)
214
+ } else {
215
+ // In non-streaming mode, render header + body together
216
+ markdown := fmt.Sprintf("### Cline is thinking\n\n%s", msg.Text)
217
+ rendered = dc.Renderer.RenderMarkdown(markdown)
218
+ output.Printf("\n%s\n", rendered)
219
+ }
220
+ return nil
221
+ }
222
+
223
+ func (h *SayHandler) handleCompletionResult(msg *types.ClineMessage, dc *DisplayContext) error {
224
+ text := msg.Text
225
+
226
+ if strings.HasSuffix(text, "HAS_CHANGES") {
227
+ text = strings.TrimSuffix(text, "HAS_CHANGES")
228
+ }
229
+
230
+ var rendered string
231
+ if dc.IsStreamingMode {
232
+ // In streaming mode, header already shown by partial stream
233
+ rendered = dc.Renderer.RenderMarkdown(text)
234
+ output.Printf("%s\n", rendered)
235
+ } else {
236
+ // In non-streaming mode, render header + body together
237
+ markdown := fmt.Sprintf("### Task completed\n\n%s", text)
238
+ rendered = dc.Renderer.RenderMarkdown(markdown)
239
+ output.Printf("\n%s\n", rendered)
240
+ }
241
+ return nil
242
+ }
243
+
244
+ func formatUserMessage(text string) string {
245
+ lines := strings.Split(text, "\n")
246
+
247
+ // Wrap each line in backticks
248
+ for i, line := range lines {
249
+ if line != "" {
250
+ lines[i] = fmt.Sprintf("`%s`", line)
251
+ }
252
+ }
253
+
254
+ return strings.Join(lines, "\n")
255
+ }
256
+
257
+
258
+ // handleUserFeedback handles user feedback messages
259
+ func (h *SayHandler) handleUserFeedback(msg *types.ClineMessage, dc *DisplayContext) error {
260
+ if msg.Text != "" {
261
+ markdown := formatUserMessage(msg.Text)
262
+ rendered := dc.Renderer.RenderMarkdown(markdown)
263
+ output.Printf("%s", rendered)
264
+ return nil
265
+ } else {
266
+ return dc.Renderer.RenderMessage("USER", "[Provided feedback without text]", true)
267
+ }
268
+ }
269
+
270
+ // handleUserFeedbackDiff handles user feedback diff messages
271
+ func (h *SayHandler) handleUserFeedbackDiff(msg *types.ClineMessage, dc *DisplayContext) error {
272
+ var toolMsg types.ToolMessage
273
+ if err := json.Unmarshal([]byte(msg.Text), &toolMsg); err != nil {
274
+ return dc.Renderer.RenderMessage("USER DIFF", msg.Text, true)
275
+ }
276
+
277
+ message := fmt.Sprintf("User manually edited: %s\n\nDiff:\n%s",
278
+ toolMsg.Path,
279
+ toolMsg.Diff)
280
+
281
+ return dc.Renderer.RenderMessage("USER DIFF", message, true)
282
+ }
283
+
284
+ // handleAPIReqRetried handles API request retry messages
285
+ func (h *SayHandler) handleAPIReqRetried(msg *types.ClineMessage, dc *DisplayContext) error {
286
+ return dc.Renderer.RenderMessage("API INFO", "Retrying request", true)
287
+ }
288
+
289
+ // handleErrorRetry handles error retry status messages
290
+ func (h *SayHandler) handleErrorRetry(msg *types.ClineMessage, dc *DisplayContext) error {
291
+ // Parse retry info from message text
292
+ type ErrorRetryInfo struct {
293
+ Attempt int `json:"attempt"`
294
+ MaxAttempts int `json:"maxAttempts"`
295
+ DelaySeconds int `json:"delaySeconds"`
296
+ Failed bool `json:"failed"`
297
+ }
298
+
299
+ var retryInfo ErrorRetryInfo
300
+ if err := json.Unmarshal([]byte(msg.Text), &retryInfo); err != nil {
301
+ // Fallback to simple message if parsing fails
302
+ return dc.Renderer.RenderMessage("API INFO", "Auto-retry in progress", true)
303
+ }
304
+
305
+ if retryInfo.Failed {
306
+ // Retry failed after max attempts
307
+ message := fmt.Sprintf("Auto-retry failed after %d attempts. Manual intervention required.", retryInfo.MaxAttempts)
308
+ if dc.SystemRenderer != nil {
309
+ return dc.SystemRenderer.RenderWarning("Auto-Retry Failed", message)
310
+ }
311
+ return dc.Renderer.RenderMessage("WARNING", message, true)
312
+ }
313
+
314
+ // Retry in progress
315
+ message := fmt.Sprintf("Attempt %d/%d - Retrying in %d seconds...",
316
+ retryInfo.Attempt, retryInfo.MaxAttempts, retryInfo.DelaySeconds)
317
+ return dc.Renderer.RenderMessage("API INFO", message, true)
318
+ }
319
+
320
+ // handleCommand handles command execution announcements
321
+ func (h *SayHandler) handleCommand(msg *types.ClineMessage, dc *DisplayContext) error {
322
+ if msg.Text == "" {
323
+ return nil
324
+ }
325
+
326
+ // Use unified ToolRenderer
327
+ rendered := dc.ToolRenderer.RenderCommandExecution(msg.Text)
328
+ output.Print(rendered)
329
+
330
+ return nil
331
+ }
332
+
333
+ // handleCommandOutput handles command output messages
334
+ func (h *SayHandler) handleCommandOutput(msg *types.ClineMessage, dc *DisplayContext) error {
335
+ if msg.Text == "" {
336
+ return nil
337
+ }
338
+
339
+ // Use unified ToolRenderer
340
+ rendered := dc.ToolRenderer.RenderCommandOutput(msg.Text)
341
+ output.Print(rendered)
342
+
343
+ return nil
344
+ }
345
+
346
+ func (h *SayHandler) handleTool(msg *types.ClineMessage, dc *DisplayContext) error {
347
+ var tool types.ToolMessage
348
+ if err := json.Unmarshal([]byte(msg.Text), &tool); err != nil {
349
+ return dc.Renderer.RenderMessage("TOOL", msg.Text, true)
350
+ }
351
+
352
+ // Use unified ToolRenderer
353
+ rendered := dc.ToolRenderer.RenderToolExecution(&tool)
354
+ output.Print(rendered)
355
+
356
+ return nil
357
+ }
358
+
359
+ // handleShellIntegrationWarning handles shell integration warning messages
360
+ func (h *SayHandler) handleShellIntegrationWarning(msg *types.ClineMessage, dc *DisplayContext) error {
361
+ return dc.Renderer.RenderMessage("WARNING", "Shell Integration Unavailable - Cline won't be able to view the command's output.", true)
362
+ }
363
+
364
+ // handleBrowserActionLaunch handles browser action launch messages
365
+ func (h *SayHandler) handleBrowserActionLaunch(msg *types.ClineMessage, dc *DisplayContext) error {
366
+ url := msg.Text
367
+ if url == "" {
368
+ return nil
369
+ }
370
+
371
+ return dc.Renderer.RenderMessage("BROWSER", fmt.Sprintf("Launching browser at: %s", url), true)
372
+ }
373
+
374
+ // handleBrowserAction handles browser action messages
375
+ func (h *SayHandler) handleBrowserAction(msg *types.ClineMessage, dc *DisplayContext) error {
376
+ if msg.Text == "" {
377
+ return nil
378
+ }
379
+
380
+ type BrowserActionData struct {
381
+ Action string `json:"action"`
382
+ Coordinate string `json:"coordinate,omitempty"`
383
+ Text string `json:"text,omitempty"`
384
+ }
385
+
386
+ var actionData BrowserActionData
387
+ if err := json.Unmarshal([]byte(msg.Text), &actionData); err != nil {
388
+ return dc.Renderer.RenderMessage("BROWSER", msg.Text, true)
389
+ }
390
+
391
+ // Special handling for type action
392
+ if actionData.Action == "type" && actionData.Text != "" {
393
+ actionText := fmt.Sprintf("type '%s'", actionData.Text)
394
+ return dc.Renderer.RenderMessage("BROWSER", fmt.Sprintf("Next action: %s", actionText), true)
395
+ }
396
+
397
+ // Special handling for click action
398
+ if actionData.Action == "click" && actionData.Coordinate != "" {
399
+ actionText := fmt.Sprintf("click (%s)", actionData.Coordinate)
400
+ return dc.Renderer.RenderMessage("BROWSER", fmt.Sprintf("Next action: %s", actionText), true)
401
+ }
402
+
403
+ // Generic handling for all other actions
404
+ return dc.Renderer.RenderMessage("BROWSER", fmt.Sprintf("Next action: %s", actionData.Action), true)
405
+ }
406
+
407
+ // handleBrowserActionResult handles browser action result messages
408
+ func (h *SayHandler) handleBrowserActionResult(msg *types.ClineMessage, dc *DisplayContext) error {
409
+ if msg.Text == "" {
410
+ return nil
411
+ }
412
+
413
+ type BrowserActionResult struct {
414
+ Screenshot string `json:"screenshot,omitempty"`
415
+ Logs string `json:"logs,omitempty"`
416
+ CurrentUrl string `json:"currentUrl,omitempty"`
417
+ CurrentMousePosition string `json:"currentMousePosition,omitempty"`
418
+ }
419
+
420
+ var result BrowserActionResult
421
+ if err := json.Unmarshal([]byte(msg.Text), &result); err != nil {
422
+ return dc.Renderer.RenderMessage("BROWSER", "Action completed", true)
423
+ }
424
+
425
+ // If we have logs, include them in the message
426
+ if result.Logs != "" {
427
+ return dc.Renderer.RenderMessage("BROWSER", fmt.Sprintf("Action completed with logs: '%s'", result.Logs), true)
428
+ }
429
+
430
+ // Default case
431
+ return dc.Renderer.RenderMessage("BROWSER", "Action completed", true)
432
+ }
433
+
434
+ // handleMcpServerRequestStarted handles MCP server request started messages
435
+ func (h *SayHandler) handleMcpServerRequestStarted(msg *types.ClineMessage, dc *DisplayContext) error {
436
+ return dc.Renderer.RenderMessage("MCP", "Sending request to server", true)
437
+ }
438
+
439
+ // handleMcpServerResponse handles MCP server response messages
440
+ func (h *SayHandler) handleMcpServerResponse(msg *types.ClineMessage, dc *DisplayContext) error {
441
+ return dc.Renderer.RenderMessage("MCP", fmt.Sprintf("Server response: %s", msg.Text), true)
442
+ }
443
+
444
+ // handleMcpNotification handles MCP notification messages
445
+ func (h *SayHandler) handleMcpNotification(msg *types.ClineMessage, dc *DisplayContext) error {
446
+ return dc.Renderer.RenderMessage("MCP", fmt.Sprintf("Server notification: %s", msg.Text), true)
447
+ }
448
+
449
+ // handleUseMcpServer handles MCP server usage messages
450
+ func (h *SayHandler) handleUseMcpServer(msg *types.ClineMessage, dc *DisplayContext) error {
451
+ return dc.Renderer.RenderMessage("MCP", "Server operation approved", true)
452
+ }
453
+
454
+ // handleDiffError handles diff error messages
455
+ func (h *SayHandler) handleDiffError(msg *types.ClineMessage, dc *DisplayContext) error {
456
+ if dc.SystemRenderer != nil {
457
+ return dc.SystemRenderer.RenderWarning(
458
+ "Diff Edit Failure",
459
+ "The model used search patterns that don't match anything in the file. Retrying...",
460
+ )
461
+ }
462
+ return dc.Renderer.RenderMessage("WARNING", "Diff Edit Failure - The model used an invalid diff edit format or used search patterns that don't match anything in the file.", true)
463
+ }
464
+
465
+ // handleDeletedAPIReqs handles deleted API requests messages
466
+ func (h *SayHandler) handleDeletedAPIReqs(msg *types.ClineMessage, dc *DisplayContext) error {
467
+ // Don't render - this is internal metadata (aggregated API metrics from deleted checkpoint messages)
468
+ return nil
469
+ }
470
+
471
+ // handleClineignoreError handles .clineignore error messages
472
+ func (h *SayHandler) handleClineignoreError(msg *types.ClineMessage, dc *DisplayContext) error {
473
+ if dc.SystemRenderer != nil {
474
+ return dc.SystemRenderer.RenderInfo(
475
+ "Access Denied",
476
+ fmt.Sprintf("Cline tried to access `%s` which is blocked by the .clineignore file.", msg.Text),
477
+ )
478
+ }
479
+ return dc.Renderer.RenderMessage("WARNING", fmt.Sprintf("Access Denied - Cline tried to access %s which is blocked by the .clineignore file", msg.Text), true)
480
+ }
481
+
482
+ func (h *SayHandler) handleCheckpointCreated(msg *types.ClineMessage, dc *DisplayContext, timestamp string) error {
483
+ if dc.SystemRenderer != nil {
484
+ return dc.SystemRenderer.RenderCheckpoint(timestamp, msg.Timestamp)
485
+ }
486
+ // Fallback to basic renderer if SystemRenderer not available
487
+ markdown := fmt.Sprintf("## [%s] Checkpoint created `%d`", timestamp, msg.Timestamp)
488
+ rendered := dc.Renderer.RenderMarkdown(markdown)
489
+ output.Print(rendered)
490
+ return nil
491
+ }
492
+
493
+ // handleLoadMcpDocumentation handles load MCP documentation messages
494
+ func (h *SayHandler) handleLoadMcpDocumentation(msg *types.ClineMessage, dc *DisplayContext) error {
495
+ if dc.SystemRenderer != nil {
496
+ return dc.SystemRenderer.RenderInfo("MCP", "Loading MCP documentation")
497
+ }
498
+ return dc.Renderer.RenderMessage("INFO", "Loading MCP documentation", true)
499
+ }
500
+
501
+ // handleInfo handles info messages
502
+ func (h *SayHandler) handleInfo(msg *types.ClineMessage, dc *DisplayContext) error {
503
+ return nil
504
+ }
505
+
506
+ // handleTaskProgress handles task progress messages
507
+ func (h *SayHandler) handleTaskProgress(msg *types.ClineMessage, dc *DisplayContext) error {
508
+ if msg.Text == "" {
509
+ return nil
510
+ }
511
+
512
+ markdown := fmt.Sprintf("### Progress\n\n%s", msg.Text)
513
+ rendered := dc.Renderer.RenderMarkdown(markdown)
514
+ output.Printf("\n%s\n", rendered)
515
+ return nil
516
+ }
517
+
518
+ // handleDefault handles unknown SAY message types
519
+ func (h *SayHandler) handleDefault(msg *types.ClineMessage, dc *DisplayContext) error {
520
+ return dc.Renderer.RenderMessage("SAY", msg.Text, true)
521
+ }