exa-ai 0.5.0 → 0.6.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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -0
  3. data/exe/exa-ai +55 -1
  4. data/exe/exa-ai-enrichment-create +0 -10
  5. data/exe/exa-ai-import-create +253 -0
  6. data/exe/exa-ai-import-delete +92 -0
  7. data/exe/exa-ai-import-get +92 -0
  8. data/exe/exa-ai-import-list +72 -0
  9. data/exe/exa-ai-import-update +164 -0
  10. data/exe/exa-ai-monitor-create +223 -0
  11. data/exe/exa-ai-monitor-delete +101 -0
  12. data/exe/exa-ai-monitor-get +92 -0
  13. data/exe/exa-ai-monitor-list +90 -0
  14. data/exe/exa-ai-monitor-runs-get +103 -0
  15. data/exe/exa-ai-monitor-runs-list +110 -0
  16. data/exe/exa-ai-monitor-update +207 -0
  17. data/exe/exa-ai-webset-create +64 -8
  18. data/exe/exa-ai-webset-search-create +19 -6
  19. data/exe/exa-ai-webset-search-get +1 -1
  20. data/lib/exa/cli/base.rb +8 -2
  21. data/lib/exa/cli/formatters/answer_formatter.rb +2 -0
  22. data/lib/exa/cli/formatters/contents_formatter.rb +2 -0
  23. data/lib/exa/cli/formatters/context_formatter.rb +2 -0
  24. data/lib/exa/cli/formatters/enrichment_formatter.rb +58 -2
  25. data/lib/exa/cli/formatters/import_formatter.rb +153 -0
  26. data/lib/exa/cli/formatters/monitor_formatter.rb +144 -0
  27. data/lib/exa/cli/formatters/monitor_run_formatter.rb +126 -0
  28. data/lib/exa/cli/formatters/research_formatter.rb +4 -0
  29. data/lib/exa/cli/formatters/search_formatter.rb +2 -0
  30. data/lib/exa/cli/formatters/webset_formatter.rb +65 -1
  31. data/lib/exa/cli/formatters/webset_item_formatter.rb +54 -2
  32. data/lib/exa/cli/formatters/webset_search_formatter.rb +57 -0
  33. data/lib/exa/client.rb +137 -0
  34. data/lib/exa/constants/websets.rb +19 -0
  35. data/lib/exa/resources/import.rb +86 -0
  36. data/lib/exa/resources/import_collection.rb +33 -0
  37. data/lib/exa/resources/monitor.rb +48 -0
  38. data/lib/exa/resources/monitor_collection.rb +30 -0
  39. data/lib/exa/resources/monitor_run.rb +52 -0
  40. data/lib/exa/resources/monitor_run_collection.rb +30 -0
  41. data/lib/exa/services/websets/create_validator.rb +20 -3
  42. data/lib/exa/services/websets/import_create.rb +40 -0
  43. data/lib/exa/services/websets/import_delete.rb +37 -0
  44. data/lib/exa/services/websets/import_get.rb +37 -0
  45. data/lib/exa/services/websets/import_list.rb +25 -0
  46. data/lib/exa/services/websets/import_update.rb +38 -0
  47. data/lib/exa/services/websets/import_upload.rb +58 -0
  48. data/lib/exa/services/websets/monitors/create.rb +42 -0
  49. data/lib/exa/services/websets/monitors/delete.rb +32 -0
  50. data/lib/exa/services/websets/monitors/get.rb +33 -0
  51. data/lib/exa/services/websets/monitors/list.rb +27 -0
  52. data/lib/exa/services/websets/monitors/runs/get.rb +37 -0
  53. data/lib/exa/services/websets/monitors/runs/list.rb +30 -0
  54. data/lib/exa/services/websets/monitors/update.rb +33 -0
  55. data/lib/exa/version.rb +1 -1
  56. data/lib/exa.rb +24 -0
  57. metadata +51 -1
@@ -9,9 +9,11 @@ module Exa
9
9
  when "json"
10
10
  JSON.generate(enrichment.to_h)
11
11
  when "pretty"
12
- JSON.pretty_generate(enrichment.to_h)
12
+ format_as_pretty(enrichment)
13
13
  when "text"
14
14
  format_as_text(enrichment)
15
+ when "toon"
16
+ Exa::CLI::Base.encode_as_toon(enrichment.to_h)
15
17
  else
16
18
  raise ArgumentError, "Unknown output format: #{output_format}"
17
19
  end
@@ -22,14 +24,41 @@ module Exa
22
24
  when "json"
23
25
  JSON.generate(collection.to_h)
24
26
  when "pretty"
25
- JSON.pretty_generate(collection.to_h)
27
+ format_collection_as_pretty(collection)
26
28
  when "text"
27
29
  format_collection_as_text(collection)
30
+ when "toon"
31
+ Exa::CLI::Base.encode_as_toon(collection.to_h)
28
32
  else
29
33
  raise ArgumentError, "Unknown output format: #{output_format}"
30
34
  end
31
35
  end
32
36
 
37
+ def self.format_as_pretty(enrichment)
38
+ lines = []
39
+ lines << "Enrichment ID: #{enrichment.id}"
40
+ lines << "Webset ID: #{enrichment.webset_id}" if enrichment.webset_id
41
+ lines << "Status: #{enrichment.status}"
42
+ lines << "Title: #{enrichment.title}" if enrichment.title
43
+ lines << "Description: #{enrichment.description}" if enrichment.description
44
+ lines << "Format: #{enrichment.format}" if enrichment.format
45
+
46
+ if enrichment.options && !enrichment.options.empty?
47
+ lines << ""
48
+ lines << "Options (#{enrichment.options.length}):"
49
+ enrichment.options.each do |option|
50
+ lines << " • #{option['label']}" if option['label']
51
+ end
52
+ end
53
+
54
+ lines << ""
55
+ lines << "Created: #{enrichment.created_at}" if enrichment.created_at
56
+ lines << "Updated: #{enrichment.updated_at}" if enrichment.updated_at
57
+
58
+ lines.join("\n")
59
+ end
60
+ private_class_method :format_as_pretty
61
+
33
62
  def self.format_as_text(enrichment)
34
63
  lines = []
35
64
  lines << "Enrichment: #{enrichment.id}"
@@ -53,6 +82,33 @@ module Exa
53
82
  end
54
83
  private_class_method :format_as_text
55
84
 
85
+ def self.format_collection_as_pretty(collection)
86
+ lines = []
87
+ lines << "Enrichments (#{collection.data.length} items)"
88
+ lines << ""
89
+
90
+ collection.data.each_with_index do |enr, idx|
91
+ lines << "" if idx > 0 # Blank line between enrichments
92
+
93
+ lines << "Enrichment ID: #{enr['id']}"
94
+ lines << "Webset ID: #{enr['websetId']}" if enr['websetId']
95
+ lines << "Status: #{enr['status']}"
96
+ lines << "Title: #{enr['title']}" if enr['title']
97
+ lines << "Description: #{enr['description']}" if enr['description']
98
+ lines << "Format: #{enr['format']}" if enr['format']
99
+ lines << "Created: #{enr['createdAt']}" if enr['createdAt']
100
+ lines << "Updated: #{enr['updatedAt']}" if enr['updatedAt']
101
+ end
102
+
103
+ if collection.has_more
104
+ lines << ""
105
+ lines << "Next Cursor: #{collection.next_cursor}"
106
+ end
107
+
108
+ lines.join("\n")
109
+ end
110
+ private_class_method :format_collection_as_pretty
111
+
56
112
  def self.format_collection_as_text(collection)
57
113
  lines = ["Enrichments (#{collection.data.length} items):"]
58
114
  collection.data.each do |enr|
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Exa
4
+ module CLI
5
+ module Formatters
6
+ class ImportFormatter
7
+ def self.format(import, output_format)
8
+ case output_format
9
+ when "json"
10
+ JSON.generate(import.to_h)
11
+ when "pretty"
12
+ format_as_pretty(import)
13
+ when "text"
14
+ format_as_text(import)
15
+ when "toon"
16
+ Exa::CLI::Base.encode_as_toon(import.to_h)
17
+ else
18
+ raise ArgumentError, "Unknown output format: #{output_format}"
19
+ end
20
+ end
21
+
22
+ def self.format_collection(collection, output_format)
23
+ case output_format
24
+ when "json"
25
+ JSON.generate(collection.to_h)
26
+ when "pretty"
27
+ format_collection_as_pretty(collection)
28
+ when "text"
29
+ format_collection_as_text(collection)
30
+ when "toon"
31
+ Exa::CLI::Base.encode_as_toon(collection.to_h)
32
+ else
33
+ raise ArgumentError, "Unknown output format: #{output_format}"
34
+ end
35
+ end
36
+
37
+ def self.format_as_pretty(import)
38
+ lines = []
39
+ lines << "Import ID: #{import.id}"
40
+ lines << "Status: #{import.status}"
41
+ lines << "Title: #{import.title}" if import.title
42
+ lines << "Format: #{import.format}" if import.format
43
+
44
+ if import.entity
45
+ entity_type = import.entity['type'] || import.entity[:type]
46
+ lines << "Entity Type: #{entity_type}" if entity_type
47
+ end
48
+
49
+ lines << "Count: #{import.count}" if import.count
50
+
51
+ if import.failed?
52
+ lines << ""
53
+ lines << "Failure:"
54
+ lines << " Reason: #{import.failed_reason}" if import.failed_reason
55
+ lines << " Message: #{import.failed_message}" if import.failed_message
56
+ lines << " Failed At: #{import.failed_at}" if import.failed_at
57
+ end
58
+
59
+ if import.upload_url
60
+ lines << ""
61
+ lines << "Upload:"
62
+ lines << " URL: #{import.upload_url}"
63
+ lines << " Valid Until: #{import.upload_valid_until}" if import.upload_valid_until
64
+ end
65
+
66
+ lines << ""
67
+ lines << "Created: #{import.created_at}" if import.created_at
68
+ lines << "Updated: #{import.updated_at}" if import.updated_at
69
+
70
+ lines.join("\n")
71
+ end
72
+ private_class_method :format_as_pretty
73
+
74
+ def self.format_as_text(import)
75
+ lines = []
76
+ lines << "Import: #{import.id}"
77
+ lines << "Status: #{import.status}"
78
+ lines << "Title: #{import.title}" if import.title
79
+ lines << "Format: #{import.format}" if import.format
80
+
81
+ if import.entity
82
+ entity_type = import.entity['type'] || import.entity[:type]
83
+ lines << "Entity Type: #{entity_type}" if entity_type
84
+ end
85
+
86
+ lines << "Count: #{import.count}" if import.count
87
+
88
+ if import.failed?
89
+ lines << "\nFailure Details:"
90
+ lines << " Reason: #{import.failed_reason}" if import.failed_reason
91
+ lines << " Message: #{import.failed_message}" if import.failed_message
92
+ lines << " Failed At: #{import.failed_at}" if import.failed_at
93
+ end
94
+
95
+ if import.upload_url
96
+ lines << "\nUpload:"
97
+ lines << " URL: #{import.upload_url}"
98
+ lines << " Valid Until: #{import.upload_valid_until}" if import.upload_valid_until
99
+ end
100
+
101
+ lines << "\nCreated: #{import.created_at}" if import.created_at
102
+ lines << "Updated: #{import.updated_at}" if import.updated_at
103
+
104
+ lines.join("\n")
105
+ end
106
+ private_class_method :format_as_text
107
+
108
+ def self.format_collection_as_pretty(collection)
109
+ lines = []
110
+ lines << "Imports (#{collection.data.length} items)"
111
+ lines << ""
112
+
113
+ collection.data.each_with_index do |imp, idx|
114
+ lines << "" if idx > 0 # Blank line between imports
115
+
116
+ lines << "Import ID: #{imp.id}"
117
+ lines << "Status: #{imp.status}"
118
+ lines << "Title: #{imp.title}" if imp.title
119
+ lines << "Format: #{imp.format}" if imp.format
120
+ lines << "Entity Type: #{imp.entity['type']}" if imp.entity && imp.entity['type']
121
+ lines << "Count: #{imp.count}" if imp.count
122
+ lines << "Created: #{imp.created_at}" if imp.created_at
123
+ lines << "Updated: #{imp.updated_at}" if imp.updated_at
124
+
125
+ if imp.status == 'failed'
126
+ lines << "Failed Reason: #{imp.failed_reason}" if imp.failed_reason
127
+ end
128
+ end
129
+
130
+ if collection.has_more
131
+ lines << ""
132
+ lines << "Next Cursor: #{collection.next_cursor}"
133
+ end
134
+
135
+ lines.join("\n")
136
+ end
137
+ private_class_method :format_collection_as_pretty
138
+
139
+ def self.format_collection_as_text(collection)
140
+ lines = ["Imports (#{collection.data.length} items):"]
141
+ collection.data.each do |imp|
142
+ lines << "\n #{imp.id}"
143
+ lines << " Status: #{imp.status}"
144
+ lines << " Title: #{imp.title}" if imp.title
145
+ lines << " Count: #{imp.count}" if imp.count
146
+ end
147
+ lines.join("\n")
148
+ end
149
+ private_class_method :format_collection_as_text
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Exa
4
+ module CLI
5
+ module Formatters
6
+ class MonitorFormatter
7
+ def self.format(monitor, output_format)
8
+ case output_format
9
+ when "json"
10
+ JSON.generate(monitor.to_h)
11
+ when "pretty"
12
+ format_as_pretty(monitor)
13
+ when "text"
14
+ format_as_text(monitor)
15
+ when "toon"
16
+ Exa::CLI::Base.encode_as_toon(monitor.to_h)
17
+ else
18
+ raise ArgumentError, "Unknown output format: #{output_format}"
19
+ end
20
+ end
21
+
22
+ def self.format_collection(collection, output_format)
23
+ case output_format
24
+ when "json"
25
+ JSON.generate(collection.to_h)
26
+ when "pretty"
27
+ format_collection_as_pretty(collection)
28
+ when "text"
29
+ format_collection_as_text(collection)
30
+ when "toon"
31
+ Exa::CLI::Base.encode_as_toon(collection.to_h)
32
+ else
33
+ raise ArgumentError, "Unknown output format: #{output_format}"
34
+ end
35
+ end
36
+
37
+ def self.format_as_pretty(monitor)
38
+ lines = []
39
+ lines << "Monitor ID: #{monitor.id}"
40
+ lines << "Webset ID: #{monitor.webset_id}" if monitor.webset_id
41
+ lines << "Status: #{monitor.status}"
42
+
43
+ if monitor.cadence
44
+ lines << ""
45
+ lines << "Cadence:"
46
+ lines << " Cron: #{monitor.cadence['cron']}" if monitor.cadence['cron']
47
+ lines << " Timezone: #{monitor.cadence['timezone']}" if monitor.cadence['timezone']
48
+ end
49
+
50
+ if monitor.behavior
51
+ lines << ""
52
+ lines << "Behavior:"
53
+ lines << " Type: #{monitor.behavior['type']}" if monitor.behavior['type']
54
+ lines << " Query: #{monitor.behavior['query']}" if monitor.behavior['query']
55
+ lines << " Count: #{monitor.behavior['count']}" if monitor.behavior['count']
56
+ end
57
+
58
+ lines << ""
59
+ lines << "Created: #{monitor.created_at}" if monitor.created_at
60
+ lines << "Updated: #{monitor.updated_at}" if monitor.updated_at
61
+
62
+ lines.join("\n")
63
+ end
64
+ private_class_method :format_as_pretty
65
+
66
+ def self.format_as_text(monitor)
67
+ lines = []
68
+ lines << "Monitor: #{monitor.id}"
69
+ lines << "Webset: #{monitor.webset_id}" if monitor.webset_id
70
+ lines << "Status: #{monitor.status}"
71
+
72
+ if monitor.cadence
73
+ lines << "\nCadence:"
74
+ lines << " Cron: #{monitor.cadence['cron']}" if monitor.cadence['cron']
75
+ lines << " Timezone: #{monitor.cadence['timezone']}" if monitor.cadence['timezone']
76
+ end
77
+
78
+ if monitor.behavior
79
+ lines << "\nBehavior:"
80
+ lines << " Type: #{monitor.behavior['type']}" if monitor.behavior['type']
81
+ lines << " Query: #{monitor.behavior['query']}" if monitor.behavior['query']
82
+ lines << " Count: #{monitor.behavior['count']}" if monitor.behavior['count']
83
+ end
84
+
85
+ lines << "\nCreated: #{monitor.created_at}" if monitor.created_at
86
+ lines << "Updated: #{monitor.updated_at}" if monitor.updated_at
87
+
88
+ lines.join("\n")
89
+ end
90
+ private_class_method :format_as_text
91
+
92
+ def self.format_collection_as_pretty(collection)
93
+ lines = []
94
+ lines << "Monitors (#{collection.data.length} items)"
95
+ lines << ""
96
+
97
+ collection.data.each_with_index do |mon, idx|
98
+ lines << "" if idx > 0 # Blank line between monitors
99
+
100
+ lines << "Monitor ID: #{mon['id']}"
101
+ lines << "Webset ID: #{mon['websetId']}" if mon['websetId']
102
+ lines << "Status: #{mon['status']}"
103
+
104
+ if mon['cadence']
105
+ lines << "Cron: #{mon['cadence']['cron']}" if mon['cadence']['cron']
106
+ lines << "Timezone: #{mon['cadence']['timezone']}" if mon['cadence']['timezone']
107
+ end
108
+
109
+ if mon['behavior']
110
+ lines << "Query: #{mon['behavior']['query']}" if mon['behavior']['query']
111
+ end
112
+
113
+ lines << "Created: #{mon['createdAt']}" if mon['createdAt']
114
+ lines << "Updated: #{mon['updatedAt']}" if mon['updatedAt']
115
+ end
116
+
117
+ if collection.has_more
118
+ lines << ""
119
+ lines << "Next Cursor: #{collection.next_cursor}"
120
+ end
121
+
122
+ lines.join("\n")
123
+ end
124
+ private_class_method :format_collection_as_pretty
125
+
126
+ def self.format_collection_as_text(collection)
127
+ lines = ["Monitors (#{collection.data.length} items):"]
128
+ collection.data.each do |mon|
129
+ lines << "\n #{mon['id']}"
130
+ lines << " Status: #{mon['status']}"
131
+ lines << " Webset: #{mon['websetId']}" if mon['websetId']
132
+ end
133
+
134
+ if collection.has_more
135
+ lines << "\nMore available (cursor: #{collection.next_cursor})"
136
+ end
137
+
138
+ lines.join("\n")
139
+ end
140
+ private_class_method :format_collection_as_text
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Exa
4
+ module CLI
5
+ module Formatters
6
+ class MonitorRunFormatter
7
+ def self.format(monitor_run, output_format)
8
+ case output_format
9
+ when "json"
10
+ JSON.generate(monitor_run.to_h)
11
+ when "pretty"
12
+ format_as_pretty(monitor_run)
13
+ when "text"
14
+ format_as_text(monitor_run)
15
+ when "toon"
16
+ Exa::CLI::Base.encode_as_toon(monitor_run.to_h)
17
+ else
18
+ raise ArgumentError, "Unknown output format: #{output_format}"
19
+ end
20
+ end
21
+
22
+ def self.format_collection(collection, output_format)
23
+ case output_format
24
+ when "json"
25
+ JSON.generate(collection.to_h)
26
+ when "pretty"
27
+ format_collection_as_pretty(collection)
28
+ when "text"
29
+ format_collection_as_text(collection)
30
+ when "toon"
31
+ Exa::CLI::Base.encode_as_toon(collection.to_h)
32
+ else
33
+ raise ArgumentError, "Unknown output format: #{output_format}"
34
+ end
35
+ end
36
+
37
+ def self.format_as_pretty(monitor_run)
38
+ lines = []
39
+ lines << "Monitor Run ID: #{monitor_run.id}"
40
+ lines << "Monitor ID: #{monitor_run.monitor_id}" if monitor_run.monitor_id
41
+ lines << "Status: #{monitor_run.status}"
42
+
43
+ lines << ""
44
+ lines << "Created: #{monitor_run.created_at}" if monitor_run.created_at
45
+ lines << "Updated: #{monitor_run.updated_at}" if monitor_run.updated_at
46
+ lines << "Completed: #{monitor_run.completed_at}" if monitor_run.completed_at
47
+
48
+ if monitor_run.failed?
49
+ lines << ""
50
+ lines << "Failed: #{monitor_run.failed_at}" if monitor_run.failed_at
51
+ lines << "Reason: #{monitor_run.failed_reason}" if monitor_run.failed_reason
52
+ end
53
+
54
+ lines.join("\n")
55
+ end
56
+ private_class_method :format_as_pretty
57
+
58
+ def self.format_as_text(monitor_run)
59
+ lines = []
60
+ lines << "Monitor Run: #{monitor_run.id}"
61
+ lines << "Monitor: #{monitor_run.monitor_id}" if monitor_run.monitor_id
62
+ lines << "Status: #{monitor_run.status}"
63
+
64
+ lines << "\nCreated: #{monitor_run.created_at}" if monitor_run.created_at
65
+ lines << "Updated: #{monitor_run.updated_at}" if monitor_run.updated_at
66
+ lines << "Completed: #{monitor_run.completed_at}" if monitor_run.completed_at
67
+
68
+ if monitor_run.failed?
69
+ lines << "Failed: #{monitor_run.failed_at}" if monitor_run.failed_at
70
+ lines << "Reason: #{monitor_run.failed_reason}" if monitor_run.failed_reason
71
+ end
72
+
73
+ lines.join("\n")
74
+ end
75
+ private_class_method :format_as_text
76
+
77
+ def self.format_collection_as_pretty(collection)
78
+ lines = []
79
+ lines << "Monitor Runs (#{collection.data.length} items)"
80
+ lines << ""
81
+
82
+ collection.data.each_with_index do |run, idx|
83
+ lines << "" if idx > 0 # Blank line between runs
84
+
85
+ lines << "Monitor Run ID: #{run['id']}"
86
+ lines << "Monitor ID: #{run['monitorId']}" if run['monitorId']
87
+ lines << "Status: #{run['status']}"
88
+ lines << "Created: #{run['createdAt']}" if run['createdAt']
89
+ lines << "Updated: #{run['updatedAt']}" if run['updatedAt']
90
+ lines << "Completed: #{run['completedAt']}" if run['completedAt']
91
+
92
+ if run['status'] == 'failed'
93
+ lines << "Failed: #{run['failedAt']}" if run['failedAt']
94
+ lines << "Reason: #{run['failedReason']}" if run['failedReason']
95
+ end
96
+ end
97
+
98
+ if collection.has_more
99
+ lines << ""
100
+ lines << "Next Cursor: #{collection.next_cursor}"
101
+ end
102
+
103
+ lines.join("\n")
104
+ end
105
+ private_class_method :format_collection_as_pretty
106
+
107
+ def self.format_collection_as_text(collection)
108
+ lines = ["Monitor Runs (#{collection.data.length} items):"]
109
+ collection.data.each do |run|
110
+ lines << "\n #{run['id']}"
111
+ lines << " Status: #{run['status']}"
112
+ lines << " Completed: #{run['completedAt']}" if run['completedAt']
113
+ lines << " Failed: #{run['failedReason']}" if run['failedReason']
114
+ end
115
+
116
+ if collection.has_more
117
+ lines << "\nMore available (cursor: #{collection.next_cursor})"
118
+ end
119
+
120
+ lines.join("\n")
121
+ end
122
+ private_class_method :format_collection_as_text
123
+ end
124
+ end
125
+ end
126
+ end
@@ -10,6 +10,8 @@ module Exa
10
10
  format_task_pretty(task, show_events: show_events)
11
11
  when "text"
12
12
  format_task_text(task, show_events: show_events)
13
+ when "toon"
14
+ Exa::CLI::Base.encode_as_toon(task.to_h)
13
15
  else
14
16
  JSON.pretty_generate(task.to_h)
15
17
  end
@@ -23,6 +25,8 @@ module Exa
23
25
  format_list_pretty(list)
24
26
  when "text"
25
27
  format_list_text(list)
28
+ when "toon"
29
+ Exa::CLI::Base.encode_as_toon(list.to_h)
26
30
  else
27
31
  JSON.pretty_generate(list.to_h)
28
32
  end
@@ -12,6 +12,8 @@ module Exa
12
12
  format_pretty(result)
13
13
  when "text"
14
14
  format_text(result)
15
+ when "toon"
16
+ Exa::CLI::Base.encode_as_toon(result.to_h)
15
17
  else
16
18
  JSON.pretty_generate(result.to_h)
17
19
  end
@@ -12,6 +12,8 @@ module Exa
12
12
  JSON.pretty_generate(webset.to_h)
13
13
  when "text"
14
14
  format_as_text(webset)
15
+ when "toon"
16
+ Exa::CLI::Base.encode_as_toon(webset.to_h)
15
17
  else
16
18
  raise ArgumentError, "Unknown output format: #{output_format}"
17
19
  end
@@ -22,9 +24,11 @@ module Exa
22
24
  when "json"
23
25
  JSON.generate(collection.to_h)
24
26
  when "pretty"
25
- JSON.pretty_generate(collection.to_h)
27
+ format_collection_as_pretty(collection)
26
28
  when "text"
27
29
  format_collection_as_text(collection)
30
+ when "toon"
31
+ Exa::CLI::Base.encode_as_toon(collection.to_h)
28
32
  else
29
33
  raise ArgumentError, "Unknown output format: #{output_format}"
30
34
  end
@@ -62,6 +66,66 @@ module Exa
62
66
  lines.join("\n")
63
67
  end
64
68
  private_class_method :format_collection_as_text
69
+
70
+ def self.format_collection_as_pretty(collection)
71
+ lines = []
72
+
73
+ # Header with count and pagination info
74
+ header = "Websets (#{collection.data.length} items)"
75
+ header += " - Page #{collection.has_more ? '1 of many' : '1 of 1'}" if collection.data.any?
76
+ lines << header
77
+
78
+ if collection.has_more
79
+ lines << "Next Cursor: #{collection.next_cursor}"
80
+ end
81
+
82
+ lines << ""
83
+
84
+ # Format each webset
85
+ collection.data.each_with_index do |ws, idx|
86
+ lines << "" if idx > 0 # Blank line between websets
87
+
88
+ lines << "Webset ID: #{ws['id']}"
89
+ lines << "Status: #{ws['status']}"
90
+ lines << "Title: #{ws['title']}" if ws['title']
91
+ lines << "External ID: #{ws['externalId']}" if ws['externalId']
92
+ lines << "Created: #{ws['createdAt']}" if ws['createdAt']
93
+ lines << "Updated: #{ws['updatedAt']}" if ws['updatedAt']
94
+
95
+ # Searches
96
+ if ws['searches'] && !ws['searches'].empty?
97
+ lines << ""
98
+ lines << "Searches (#{ws['searches'].length}):"
99
+ ws['searches'].each do |search|
100
+ status_indicator = case search['status']
101
+ when 'completed' then '✓'
102
+ when 'running' then '→'
103
+ when 'failed' then '✗'
104
+ else '•'
105
+ end
106
+ lines << " #{status_indicator} #{search['query']} (#{search['status']})" if search['query']
107
+ end
108
+ end
109
+
110
+ # Enrichments
111
+ if ws['enrichments'] && !ws['enrichments'].empty?
112
+ lines << "Enrichments: #{ws['enrichments'].length}"
113
+ end
114
+
115
+ # Monitors
116
+ if ws['monitors'] && !ws['monitors'].empty?
117
+ lines << "Monitors: #{ws['monitors'].length}"
118
+ end
119
+
120
+ # Imports
121
+ if ws['imports'] && !ws['imports'].empty?
122
+ lines << "Imports: #{ws['imports'].length}"
123
+ end
124
+ end
125
+
126
+ lines.join("\n")
127
+ end
128
+ private_class_method :format_collection_as_pretty
65
129
  end
66
130
  end
67
131
  end