@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,455 @@
1
+ package display
2
+
3
+ import (
4
+ "encoding/json"
5
+ "fmt"
6
+ "strings"
7
+
8
+ "github.com/cline/cli/pkg/cli/types"
9
+ )
10
+
11
+ // ToolRenderer provides unified rendering for tool and command messages
12
+ type ToolRenderer struct {
13
+ mdRenderer *MarkdownRenderer
14
+ outputFormat string
15
+ }
16
+
17
+ // NewToolRenderer creates a new tool renderer
18
+ func NewToolRenderer(mdRenderer *MarkdownRenderer, outputFormat string) *ToolRenderer {
19
+ return &ToolRenderer{
20
+ mdRenderer: mdRenderer,
21
+ outputFormat: outputFormat,
22
+ }
23
+ }
24
+
25
+ // RenderToolApprovalRequest renders a tool approval request ("Cline wants to...")
26
+ func (tr *ToolRenderer) RenderToolApprovalRequest(tool *types.ToolMessage) string {
27
+ var output strings.Builder
28
+
29
+ // Generate header
30
+ header := tr.generateToolHeader(tool, "wants to")
31
+ rendered := tr.renderMarkdown(header)
32
+ output.WriteString(rendered)
33
+ output.WriteString("\n")
34
+
35
+ // Add content preview for relevant tools
36
+ contentPreview := tr.GenerateToolContentPreview(tool)
37
+ if contentPreview != "" {
38
+ output.WriteString("\n")
39
+ output.WriteString(contentPreview)
40
+ }
41
+
42
+ return output.String()
43
+ }
44
+
45
+ // RenderToolExecution renders a completed tool execution ("Cline is ...ing")
46
+ func (tr *ToolRenderer) RenderToolExecution(tool *types.ToolMessage) string {
47
+ var output strings.Builder
48
+
49
+ // Generate header
50
+ header := tr.generateToolHeader(tool, "is")
51
+ rendered := tr.renderMarkdown(header)
52
+ output.WriteString("\n")
53
+ output.WriteString(rendered)
54
+ output.WriteString("\n")
55
+
56
+ // Add content body for relevant tools
57
+ contentBody := tr.GenerateToolContentBody(tool)
58
+ if contentBody != "" {
59
+ output.WriteString("\n")
60
+ output.WriteString(contentBody)
61
+ output.WriteString("\n")
62
+ }
63
+
64
+ return output.String()
65
+ }
66
+
67
+ // RenderToolExecutionHeader renders just the header for streaming (no body)
68
+ func (tr *ToolRenderer) RenderToolExecutionHeader(tool *types.ToolMessage) string {
69
+ header := tr.generateToolHeader(tool, "is")
70
+ return header
71
+ }
72
+
73
+ // RenderToolApprovalHeader renders just the header for approval requests (no body)
74
+ func (tr *ToolRenderer) RenderToolApprovalHeader(tool *types.ToolMessage) string {
75
+ header := tr.generateToolHeader(tool, "wants to")
76
+ return header
77
+ }
78
+
79
+ // generateToolHeader generates the markdown header for a tool message
80
+ func (tr *ToolRenderer) generateToolHeader(tool *types.ToolMessage, verbTense string) string {
81
+ var verb string
82
+ var action string
83
+
84
+ switch tool.Tool {
85
+ case string(types.ToolTypeEditedExistingFile):
86
+ if verbTense == "wants to" {
87
+ action = "wants to edit"
88
+ } else {
89
+ action = "is editing"
90
+ }
91
+ return fmt.Sprintf("### Cline %s `%s`", action, tool.Path)
92
+
93
+ case string(types.ToolTypeNewFileCreated):
94
+ if verbTense == "wants to" {
95
+ action = "wants to write"
96
+ } else {
97
+ action = "is writing"
98
+ }
99
+ return fmt.Sprintf("### Cline %s `%s`", action, tool.Path)
100
+
101
+ case string(types.ToolTypeReadFile):
102
+ if verbTense == "wants to" {
103
+ action = "wants to read"
104
+ } else {
105
+ action = "is reading"
106
+ }
107
+ return fmt.Sprintf("### Cline %s `%s`", action, tool.Path)
108
+
109
+ case string(types.ToolTypeFileDeleted):
110
+ if verbTense == "wants to" {
111
+ action = "wants to delete"
112
+ } else {
113
+ action = "is deleting"
114
+ }
115
+ return fmt.Sprintf("### Cline %s `%s`", action, tool.Path)
116
+
117
+ case string(types.ToolTypeListFilesTopLevel):
118
+ if verbTense == "wants to" {
119
+ action = "wants to list files in"
120
+ } else {
121
+ action = "is listing files in"
122
+ }
123
+ return fmt.Sprintf("### Cline %s `%s`", action, tool.Path)
124
+
125
+ case string(types.ToolTypeListFilesRecursive):
126
+ if verbTense == "wants to" {
127
+ action = "wants to recursively list files in"
128
+ } else {
129
+ action = "is recursively listing files in"
130
+ }
131
+ return fmt.Sprintf("### Cline %s `%s`", action, tool.Path)
132
+
133
+ case string(types.ToolTypeSearchFiles):
134
+ if tool.Regex != "" && tool.Path != "" {
135
+ if verbTense == "wants to" {
136
+ action = "wants to search for"
137
+ } else {
138
+ action = "is searching for"
139
+ }
140
+ return fmt.Sprintf("### Cline %s `%s` in `%s`", action, tool.Regex, tool.Path)
141
+ } else if tool.Regex != "" {
142
+ if verbTense == "wants to" {
143
+ action = "wants to search for"
144
+ } else {
145
+ action = "is searching for"
146
+ }
147
+ return fmt.Sprintf("### Cline %s `%s`", action, tool.Regex)
148
+ } else {
149
+ if verbTense == "wants to" {
150
+ return "### Cline wants to search files"
151
+ } else {
152
+ return "### Cline is searching files"
153
+ }
154
+ }
155
+
156
+ case string(types.ToolTypeWebFetch):
157
+ if verbTense == "wants to" {
158
+ action = "wants to fetch"
159
+ } else {
160
+ action = "is fetching"
161
+ }
162
+ return fmt.Sprintf("### Cline %s `%s`", action, tool.Path)
163
+
164
+ case string(types.ToolTypeListCodeDefinitionNames):
165
+ if verbTense == "wants to" {
166
+ action = "wants to list code definitions in"
167
+ } else {
168
+ action = "is listing code definitions in"
169
+ }
170
+ return fmt.Sprintf("### Cline %s `%s`", action, tool.Path)
171
+
172
+ case string(types.ToolTypeSummarizeTask):
173
+ if verbTense == "wants to" {
174
+ return "### Cline wants to condense the conversation"
175
+ } else {
176
+ return "### Cline condensed the conversation"
177
+ }
178
+
179
+ default:
180
+ if verbTense == "wants to" {
181
+ verb = "wants to use"
182
+ } else {
183
+ verb = "is using"
184
+ }
185
+ return fmt.Sprintf("### Cline %s tool: %s", verb, tool.Tool)
186
+ }
187
+ }
188
+
189
+ // GenerateToolContentPreview generates content preview for approval requests
190
+ func (tr *ToolRenderer) GenerateToolContentPreview(tool *types.ToolMessage) string {
191
+ if tool.Content == "" {
192
+ return ""
193
+ }
194
+
195
+ switch tool.Tool {
196
+ case string(types.ToolTypeEditedExistingFile):
197
+ // Show diff for edits
198
+ diffMarkdown := fmt.Sprintf("```diff\n%s\n```", tool.Content)
199
+ return tr.renderMarkdown(diffMarkdown)
200
+
201
+ case string(types.ToolTypeNewFileCreated):
202
+ // Show content preview for new files (truncated)
203
+ preview := strings.TrimSpace(tool.Content)
204
+ if len(preview) > 500 {
205
+ preview = preview[:500] + "..."
206
+ }
207
+ previewMd := fmt.Sprintf("```\n%s\n```", preview)
208
+ return tr.renderMarkdown(previewMd)
209
+
210
+ case string(types.ToolTypeReadFile), string(types.ToolTypeWebFetch), string(types.ToolTypeFileDeleted):
211
+ // No preview for read/fetch operations
212
+ return ""
213
+
214
+ default:
215
+ // For other tools, show truncated content if available
216
+ preview := strings.TrimSpace(tool.Content)
217
+ if len(preview) > 200 {
218
+ preview = preview[:200] + "..."
219
+ }
220
+ if preview != "" {
221
+ return fmt.Sprintf("Preview: %s", preview)
222
+ }
223
+ return ""
224
+ }
225
+ }
226
+
227
+ // GenerateToolContentBody generates full content for completed executions
228
+ func (tr *ToolRenderer) GenerateToolContentBody(tool *types.ToolMessage) string {
229
+ if tool.Content == "" {
230
+ return ""
231
+ }
232
+
233
+ // Use enhanced tool result parser for supported tools
234
+ toolParser := NewToolResultParser(tr.mdRenderer)
235
+
236
+ switch tool.Tool {
237
+ case string(types.ToolTypeReadFile),
238
+ string(types.ToolTypeFileDeleted):
239
+ // readFile: show header only, no body
240
+ return ""
241
+
242
+ case string(types.ToolTypeListFilesTopLevel),
243
+ string(types.ToolTypeListFilesRecursive),
244
+ string(types.ToolTypeListCodeDefinitionNames),
245
+ string(types.ToolTypeSearchFiles),
246
+ string(types.ToolTypeWebFetch):
247
+ // Use parser for structured output
248
+ preview := toolParser.ParseToolResult(tool)
249
+ return tr.renderMarkdown(preview)
250
+
251
+ case string(types.ToolTypeEditedExistingFile):
252
+ // Show the diff
253
+ diffMarkdown := fmt.Sprintf("```diff\n%s\n```", tool.Content)
254
+ return tr.renderMarkdown(diffMarkdown)
255
+
256
+ case string(types.ToolTypeNewFileCreated):
257
+ // Show file content preview
258
+ preview := strings.TrimSpace(tool.Content)
259
+ if len(preview) > 1000 {
260
+ preview = preview[:1000] + "..."
261
+ }
262
+ contentMd := fmt.Sprintf("```\n%s\n```", preview)
263
+ return tr.renderMarkdown(contentMd)
264
+
265
+ default:
266
+ // For unknown tools, show content as-is
267
+ if len(tool.Content) > 500 {
268
+ return tool.Content[:500] + "..."
269
+ }
270
+ return tool.Content
271
+ }
272
+ }
273
+
274
+ // RenderCommandApprovalRequest renders a command approval request
275
+ func (tr *ToolRenderer) RenderCommandApprovalRequest(command string, autoApprovalConflict bool) string {
276
+ var output strings.Builder
277
+
278
+ // Clean command
279
+ command = strings.TrimSpace(command)
280
+ if strings.HasSuffix(command, "REQ_APP") {
281
+ command = strings.TrimSuffix(command, "REQ_APP")
282
+ command = strings.TrimSpace(command)
283
+ autoApprovalConflict = true
284
+ }
285
+
286
+ // Generate header
287
+ header := fmt.Sprintf("### Cline wants to run `%s`", command)
288
+ rendered := tr.renderMarkdown(header)
289
+ output.WriteString(rendered)
290
+ output.WriteString("\n")
291
+
292
+ // Show command in code block
293
+ cmdBlock := fmt.Sprintf("```shell\n%s\n```", command)
294
+ cmdRendered := tr.renderMarkdown(cmdBlock)
295
+ output.WriteString("\n")
296
+ output.WriteString(cmdRendered)
297
+
298
+ // Add warning if needed
299
+ if autoApprovalConflict {
300
+ output.WriteString("\nWARNING: The model has determined this command requires explicit approval.\n")
301
+ }
302
+
303
+ return output.String()
304
+ }
305
+
306
+ // RenderCommandExecution renders a command execution announcement
307
+ func (tr *ToolRenderer) RenderCommandExecution(command string) string {
308
+ command = strings.TrimSpace(command)
309
+ header := fmt.Sprintf("### Cline is running `%s`", command)
310
+ rendered := tr.renderMarkdown(header)
311
+ return "\n" + rendered + "\n"
312
+ }
313
+
314
+ // RenderCommandOutput renders command output
315
+ func (tr *ToolRenderer) RenderCommandOutput(output string) string {
316
+ var result strings.Builder
317
+
318
+ header := "### Terminal output"
319
+ rendered := tr.renderMarkdown(header)
320
+ result.WriteString("\n")
321
+ result.WriteString(rendered)
322
+ result.WriteString("\n\n")
323
+
324
+ // Show output in code block
325
+ outputBlock := fmt.Sprintf("```\n%s\n```", strings.TrimSpace(output))
326
+ outputRendered := tr.renderMarkdown(outputBlock)
327
+ result.WriteString(outputRendered)
328
+ result.WriteString("\n")
329
+
330
+ return result.String()
331
+ }
332
+
333
+ // RenderUserResponse renders user approval/rejection feedback
334
+ func (tr *ToolRenderer) RenderUserResponse(approved bool, feedback string) string {
335
+ var symbol, status string
336
+
337
+ if approved {
338
+ symbol = "✓"
339
+ status = "Approved"
340
+ } else {
341
+ symbol = "✗"
342
+ status = "Rejected"
343
+ }
344
+
345
+ if feedback != "" {
346
+ return fmt.Sprintf("%s %s with feedback: %s\n", symbol, status, feedback)
347
+ }
348
+ return fmt.Sprintf("%s %s\n", symbol, status)
349
+ }
350
+
351
+ // renderMarkdown renders markdown if not in plain mode and in a TTY
352
+ func (tr *ToolRenderer) renderMarkdown(markdown string) string {
353
+ // Skip markdown rendering if plain mode or not in TTY
354
+ if tr.outputFormat == "plain" || !isTTY() {
355
+ return markdown
356
+ }
357
+
358
+ if tr.mdRenderer == nil {
359
+ return markdown
360
+ }
361
+
362
+ rendered, err := tr.mdRenderer.Render(markdown)
363
+ if err != nil {
364
+ return markdown
365
+ }
366
+
367
+ return rendered
368
+ }
369
+
370
+ // GenerateAskFollowupHeader generates the header for followup questions
371
+ func (tr *ToolRenderer) GenerateAskFollowupHeader() string {
372
+ return "### Cline has a question\n"
373
+ }
374
+
375
+ // GenerateAskFollowupBody generates the body content for followup questions
376
+ func (tr *ToolRenderer) GenerateAskFollowupBody(messageText string) string {
377
+ var question string
378
+ var options []string
379
+
380
+ // Try to parse as JSON
381
+ var askData types.AskData
382
+ if err := json.Unmarshal([]byte(messageText), &askData); err == nil {
383
+ question = askData.Question
384
+ options = askData.Options
385
+ } else {
386
+ question = messageText
387
+ }
388
+
389
+ if question == "" {
390
+ return ""
391
+ }
392
+
393
+ // Build the body
394
+ var body strings.Builder
395
+
396
+ // Render the question
397
+ rendered := tr.renderMarkdown(question)
398
+ body.WriteString(rendered)
399
+
400
+ // Add options if available
401
+ if len(options) > 0 {
402
+ body.WriteString("\n\nOptions:\n")
403
+ for i, option := range options {
404
+ body.WriteString(fmt.Sprintf("%d. %s\n", i+1, option))
405
+ }
406
+ }
407
+
408
+ return body.String()
409
+ }
410
+
411
+ // GeneratePlanModeRespondHeader generates the header for plan mode responses
412
+ func (tr *ToolRenderer) GeneratePlanModeRespondHeader() string {
413
+ return "### Cline has a plan\n"
414
+ }
415
+
416
+ // GeneratePlanModeRespondBody generates the body content for plan mode responses
417
+ func (tr *ToolRenderer) GeneratePlanModeRespondBody(messageText string) string {
418
+ var response string
419
+ var options []string
420
+
421
+ // Try to parse as JSON
422
+ type PlanModeResponse struct {
423
+ Response string `json:"response"`
424
+ Options []string `json:"options,omitempty"`
425
+ }
426
+
427
+ var planData PlanModeResponse
428
+ if err := json.Unmarshal([]byte(messageText), &planData); err == nil {
429
+ response = planData.Response
430
+ options = planData.Options
431
+ } else {
432
+ response = messageText
433
+ }
434
+
435
+ if response == "" {
436
+ return ""
437
+ }
438
+
439
+ // Build the body
440
+ var body strings.Builder
441
+
442
+ // Render the response
443
+ rendered := tr.renderMarkdown(response)
444
+ body.WriteString(rendered)
445
+
446
+ // Add options if available
447
+ if len(options) > 0 {
448
+ body.WriteString("\n\nOptions:\n")
449
+ for i, option := range options {
450
+ body.WriteString(fmt.Sprintf("%d. %s\n", i+1, option))
451
+ }
452
+ }
453
+
454
+ return body.String()
455
+ }