language-operator 0.1.61 → 0.1.62

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 (143) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/commands/persona.md +9 -0
  3. data/.claude/commands/task.md +46 -1
  4. data/.rubocop.yml +13 -0
  5. data/.rubocop_custom/use_ux_helper.rb +44 -0
  6. data/CHANGELOG.md +8 -0
  7. data/Gemfile.lock +12 -1
  8. data/Makefile +26 -7
  9. data/Makefile.common +50 -0
  10. data/bin/aictl +8 -1
  11. data/components/agent/Gemfile +1 -1
  12. data/components/agent/bin/langop-agent +7 -0
  13. data/docs/README.md +58 -0
  14. data/docs/{dsl/best-practices.md → best-practices.md} +4 -4
  15. data/docs/cli-reference.md +274 -0
  16. data/docs/{dsl/constraints.md → constraints.md} +5 -5
  17. data/docs/how-agents-work.md +156 -0
  18. data/docs/installation.md +218 -0
  19. data/docs/quickstart.md +299 -0
  20. data/docs/understanding-generated-code.md +265 -0
  21. data/docs/using-tools.md +457 -0
  22. data/docs/webhooks.md +509 -0
  23. data/examples/ux_helpers_demo.rb +296 -0
  24. data/lib/language_operator/agent/base.rb +11 -1
  25. data/lib/language_operator/agent/executor.rb +23 -6
  26. data/lib/language_operator/agent/safety/safe_executor.rb +41 -39
  27. data/lib/language_operator/agent/task_executor.rb +346 -63
  28. data/lib/language_operator/agent/web_server.rb +110 -14
  29. data/lib/language_operator/agent/webhook_authenticator.rb +39 -5
  30. data/lib/language_operator/agent.rb +88 -2
  31. data/lib/language_operator/cli/base_command.rb +17 -11
  32. data/lib/language_operator/cli/command_loader.rb +72 -0
  33. data/lib/language_operator/cli/commands/agent/base.rb +837 -0
  34. data/lib/language_operator/cli/commands/agent/code_operations.rb +102 -0
  35. data/lib/language_operator/cli/commands/agent/helpers/cluster_llm_client.rb +116 -0
  36. data/lib/language_operator/cli/commands/agent/helpers/code_parser.rb +115 -0
  37. data/lib/language_operator/cli/commands/agent/helpers/synthesis_watcher.rb +96 -0
  38. data/lib/language_operator/cli/commands/agent/learning.rb +289 -0
  39. data/lib/language_operator/cli/commands/agent/lifecycle.rb +102 -0
  40. data/lib/language_operator/cli/commands/agent/logs.rb +125 -0
  41. data/lib/language_operator/cli/commands/agent/workspace.rb +327 -0
  42. data/lib/language_operator/cli/commands/cluster.rb +129 -84
  43. data/lib/language_operator/cli/commands/install.rb +1 -1
  44. data/lib/language_operator/cli/commands/model/base.rb +215 -0
  45. data/lib/language_operator/cli/commands/model/test.rb +165 -0
  46. data/lib/language_operator/cli/commands/persona.rb +16 -34
  47. data/lib/language_operator/cli/commands/quickstart.rb +3 -2
  48. data/lib/language_operator/cli/commands/status.rb +40 -67
  49. data/lib/language_operator/cli/commands/system/base.rb +44 -0
  50. data/lib/language_operator/cli/commands/system/exec.rb +147 -0
  51. data/lib/language_operator/cli/commands/system/helpers/llm_synthesis.rb +183 -0
  52. data/lib/language_operator/cli/commands/system/helpers/pod_manager.rb +212 -0
  53. data/lib/language_operator/cli/commands/system/helpers/template_loader.rb +57 -0
  54. data/lib/language_operator/cli/commands/system/helpers/template_validator.rb +174 -0
  55. data/lib/language_operator/cli/commands/system/schema.rb +92 -0
  56. data/lib/language_operator/cli/commands/system/synthesis_template.rb +151 -0
  57. data/lib/language_operator/cli/commands/system/synthesize.rb +224 -0
  58. data/lib/language_operator/cli/commands/system/validate_template.rb +130 -0
  59. data/lib/language_operator/cli/commands/tool/base.rb +271 -0
  60. data/lib/language_operator/cli/commands/tool/install.rb +255 -0
  61. data/lib/language_operator/cli/commands/tool/search.rb +69 -0
  62. data/lib/language_operator/cli/commands/tool/test.rb +115 -0
  63. data/lib/language_operator/cli/commands/use.rb +29 -6
  64. data/lib/language_operator/cli/errors/handler.rb +20 -17
  65. data/lib/language_operator/cli/errors/suggestions.rb +3 -5
  66. data/lib/language_operator/cli/errors/thor_errors.rb +55 -0
  67. data/lib/language_operator/cli/formatters/code_formatter.rb +4 -11
  68. data/lib/language_operator/cli/formatters/log_formatter.rb +8 -15
  69. data/lib/language_operator/cli/formatters/progress_formatter.rb +6 -8
  70. data/lib/language_operator/cli/formatters/status_formatter.rb +26 -7
  71. data/lib/language_operator/cli/formatters/table_formatter.rb +47 -36
  72. data/lib/language_operator/cli/formatters/value_formatter.rb +75 -0
  73. data/lib/language_operator/cli/helpers/cluster_context.rb +5 -3
  74. data/lib/language_operator/cli/helpers/kubeconfig_validator.rb +2 -1
  75. data/lib/language_operator/cli/helpers/label_utils.rb +97 -0
  76. data/lib/language_operator/{ux/concerns/provider_helpers.rb → cli/helpers/provider_helper.rb} +10 -29
  77. data/lib/language_operator/cli/helpers/schedule_builder.rb +21 -1
  78. data/lib/language_operator/cli/helpers/user_prompts.rb +19 -11
  79. data/lib/language_operator/cli/helpers/ux_helper.rb +538 -0
  80. data/lib/language_operator/{ux/concerns/input_validation.rb → cli/helpers/validation_helper.rb} +13 -66
  81. data/lib/language_operator/cli/main.rb +50 -40
  82. data/lib/language_operator/cli/templates/tools/generic.yaml +3 -0
  83. data/lib/language_operator/cli/wizards/agent_wizard.rb +12 -20
  84. data/lib/language_operator/cli/wizards/model_wizard.rb +271 -0
  85. data/lib/language_operator/cli/wizards/quickstart_wizard.rb +8 -34
  86. data/lib/language_operator/client/base.rb +28 -0
  87. data/lib/language_operator/client/config.rb +4 -1
  88. data/lib/language_operator/client/mcp_connector.rb +1 -1
  89. data/lib/language_operator/config/cluster_config.rb +3 -2
  90. data/lib/language_operator/config.rb +38 -11
  91. data/lib/language_operator/constants/kubernetes_labels.rb +80 -0
  92. data/lib/language_operator/constants.rb +13 -0
  93. data/lib/language_operator/dsl/http.rb +127 -10
  94. data/lib/language_operator/dsl.rb +153 -6
  95. data/lib/language_operator/errors.rb +50 -0
  96. data/lib/language_operator/kubernetes/client.rb +11 -6
  97. data/lib/language_operator/kubernetes/resource_builder.rb +58 -84
  98. data/lib/language_operator/templates/schema/agent_dsl_openapi.yaml +1 -1
  99. data/lib/language_operator/templates/schema/agent_dsl_schema.json +1 -1
  100. data/lib/language_operator/type_coercion.rb +118 -34
  101. data/lib/language_operator/utils/secure_path.rb +74 -0
  102. data/lib/language_operator/utils.rb +7 -0
  103. data/lib/language_operator/validators.rb +54 -2
  104. data/lib/language_operator/version.rb +1 -1
  105. data/synth/001/Makefile +10 -2
  106. data/synth/001/agent.rb +16 -15
  107. data/synth/001/output.log +27 -10
  108. data/synth/002/Makefile +10 -2
  109. data/synth/003/Makefile +1 -1
  110. data/synth/003/README.md +205 -133
  111. data/synth/003/agent.optimized.rb +66 -0
  112. data/synth/003/agent.synthesized.rb +41 -0
  113. metadata +111 -35
  114. data/docs/dsl/agent-reference.md +0 -604
  115. data/docs/dsl/mcp-integration.md +0 -1177
  116. data/docs/dsl/webhooks.md +0 -932
  117. data/docs/dsl/workflows.md +0 -744
  118. data/lib/language_operator/cli/commands/agent.rb +0 -1712
  119. data/lib/language_operator/cli/commands/model.rb +0 -366
  120. data/lib/language_operator/cli/commands/system.rb +0 -1259
  121. data/lib/language_operator/cli/commands/tool.rb +0 -654
  122. data/lib/language_operator/cli/formatters/optimization_formatter.rb +0 -226
  123. data/lib/language_operator/cli/helpers/pastel_helper.rb +0 -24
  124. data/lib/language_operator/learning/adapters/base_adapter.rb +0 -149
  125. data/lib/language_operator/learning/adapters/jaeger_adapter.rb +0 -221
  126. data/lib/language_operator/learning/adapters/signoz_adapter.rb +0 -435
  127. data/lib/language_operator/learning/adapters/tempo_adapter.rb +0 -239
  128. data/lib/language_operator/learning/optimizer.rb +0 -319
  129. data/lib/language_operator/learning/pattern_detector.rb +0 -260
  130. data/lib/language_operator/learning/task_synthesizer.rb +0 -288
  131. data/lib/language_operator/learning/trace_analyzer.rb +0 -285
  132. data/lib/language_operator/templates/task_synthesis.tmpl +0 -98
  133. data/lib/language_operator/ux/base.rb +0 -81
  134. data/lib/language_operator/ux/concerns/README.md +0 -155
  135. data/lib/language_operator/ux/concerns/headings.rb +0 -90
  136. data/lib/language_operator/ux/create_agent.rb +0 -255
  137. data/lib/language_operator/ux/create_model.rb +0 -267
  138. data/lib/language_operator/ux/quickstart.rb +0 -594
  139. data/synth/003/agent.rb +0 -41
  140. data/synth/003/output.log +0 -68
  141. /data/docs/{architecture/agent-runtime.md → agent-internals.md} +0 -0
  142. /data/docs/{dsl/chat-endpoints.md → chat-endpoints.md} +0 -0
  143. /data/docs/{dsl/SCHEMA_VERSION.md → schema-versioning.md} +0 -0
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require_relative '../../../constants/kubernetes_labels'
5
+
6
+ module LanguageOperator
7
+ module CLI
8
+ module Commands
9
+ module Tool
10
+ # Tool testing commands
11
+ module Test
12
+ def self.included(base)
13
+ base.class_eval do
14
+ desc 'test NAME', 'Test tool connectivity and health'
15
+ option :cluster, type: :string, desc: 'Override current cluster context'
16
+ def test(tool_name)
17
+ handle_command_error('test tool') do
18
+ tool = get_resource_or_exit(LanguageOperator::Constants::RESOURCE_TOOL, tool_name)
19
+
20
+ puts "Testing tool '#{tool_name}' in cluster '#{ctx.name}'"
21
+ puts
22
+
23
+ # Check phase
24
+ phase = tool.dig('status', 'phase') || 'Unknown'
25
+ status_indicator = case phase
26
+ when 'Running' then '✓'
27
+ when 'Pending' then '⏳'
28
+ when 'Failed' then '✗'
29
+ else '?'
30
+ end
31
+
32
+ puts "Status: #{status_indicator} #{phase}"
33
+
34
+ # Check replicas
35
+ ready_replicas = tool.dig('status', 'readyReplicas') || 0
36
+ desired_replicas = tool.dig('spec', 'replicas') || 1
37
+ puts "Replicas: #{ready_replicas}/#{desired_replicas} ready"
38
+
39
+ # Check endpoint
40
+ endpoint = tool.dig('status', 'endpoint')
41
+ if endpoint
42
+ puts "Endpoint: #{endpoint}"
43
+ else
44
+ puts 'Endpoint: Not available yet'
45
+ end
46
+
47
+ # Get pod status
48
+ puts
49
+ puts 'Pod Status:'
50
+
51
+ label_selector = Constants::KubernetesLabels.tool_selector(tool_name)
52
+ pods = ctx.client.list_resources('Pod', namespace: ctx.namespace, label_selector: label_selector)
53
+
54
+ if pods.empty?
55
+ puts ' No pods found'
56
+ else
57
+ pods.each do |pod|
58
+ pod_name = pod.dig('metadata', 'name')
59
+ pod_phase = pod.dig('status', 'phase') || 'Unknown'
60
+ pod_indicator = case pod_phase
61
+ when 'Running' then '✓'
62
+ when 'Pending' then '⏳'
63
+ when 'Failed' then '✗'
64
+ else '?'
65
+ end
66
+
67
+ puts " #{pod_indicator} #{pod_name}: #{pod_phase}"
68
+
69
+ # Check container status
70
+ container_statuses = pod.dig('status', 'containerStatuses') || []
71
+ container_statuses.each do |status|
72
+ ready = status['ready'] ? '✓' : '✗'
73
+ puts " #{ready} #{status['name']}: #{status['state']&.keys&.first || 'unknown'}"
74
+ end
75
+ end
76
+ end
77
+
78
+ # Test connectivity if endpoint is available
79
+ if endpoint && phase == 'Running'
80
+ puts
81
+ puts 'Testing connectivity...'
82
+ begin
83
+ uri = URI(endpoint)
84
+ response = Net::HTTP.get_response(uri)
85
+ if response.code.to_i < 400
86
+ Formatters::ProgressFormatter.success('Connectivity test passed')
87
+ else
88
+ Formatters::ProgressFormatter.warn("HTTP #{response.code}: #{response.message}")
89
+ end
90
+ rescue StandardError => e
91
+ Formatters::ProgressFormatter.error("Connectivity test failed: #{e.message}")
92
+ end
93
+ end
94
+
95
+ # Overall health
96
+ puts
97
+ if phase == 'Running' && ready_replicas == desired_replicas
98
+ Formatters::ProgressFormatter.success("Tool '#{tool_name}' is healthy and operational")
99
+ elsif phase == 'Pending'
100
+ Formatters::ProgressFormatter.info("Tool '#{tool_name}' is starting up, please wait")
101
+ else
102
+ Formatters::ProgressFormatter.warn("Tool '#{tool_name}' has issues, check logs for details")
103
+ puts
104
+ puts 'View logs with:'
105
+ puts " kubectl logs -n #{ctx.namespace} -l #{Constants::KubernetesLabels::TOOL_LABEL}=#{tool_name}"
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -1,15 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../base_command'
4
- require 'pastel'
5
4
  require_relative '../formatters/progress_formatter'
6
5
  require_relative '../../config/cluster_config'
6
+ require_relative '../helpers/cluster_validator'
7
7
 
8
8
  module LanguageOperator
9
9
  module CLI
10
10
  module Commands
11
11
  # Switch cluster context command
12
12
  class Use < BaseCommand
13
+ include Helpers::UxHelper
14
+
13
15
  desc 'use CLUSTER', 'Switch to a different cluster context'
14
16
  def self.exit_on_failure?
15
17
  true
@@ -31,11 +33,32 @@ module LanguageOperator
31
33
 
32
34
  Formatters::ProgressFormatter.success("Switched to cluster '#{cluster_name}'")
33
35
 
34
- pastel = Pastel.new
35
- puts "\nCluster Details"
36
- puts '----------------'
37
- puts "Name: #{pastel.bold.white(cluster[:name])}"
38
- puts "Namespace: #{pastel.bold.white(cluster[:namespace])}"
36
+ # Get cluster details from Kubernetes for complete information
37
+ begin
38
+ k8s = Helpers::ClusterValidator.kubernetes_client(cluster_name)
39
+ cluster_resource = k8s.get_resource('LanguageCluster', cluster[:name], cluster[:namespace])
40
+ status = cluster_resource.dig('status', 'phase') || 'Unknown'
41
+ domain = cluster_resource.dig('spec', 'domain')
42
+
43
+ puts
44
+ format_cluster_details(
45
+ name: cluster[:name],
46
+ namespace: cluster[:namespace],
47
+ context: cluster[:context] || 'default',
48
+ domain: domain,
49
+ status: status,
50
+ created: cluster[:created]
51
+ )
52
+ rescue StandardError
53
+ # Fallback to basic display if K8s access fails
54
+ puts
55
+ format_cluster_details(
56
+ name: cluster[:name],
57
+ namespace: cluster[:namespace],
58
+ context: cluster[:context] || 'default',
59
+ status: 'Connection Error'
60
+ )
61
+ end
39
62
  end
40
63
  end
41
64
  end
@@ -1,14 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pastel'
4
3
  require_relative 'suggestions'
4
+ require_relative 'thor_errors'
5
5
  require_relative '../formatters/progress_formatter'
6
+ require_relative '../helpers/ux_helper'
6
7
 
7
8
  module LanguageOperator
8
9
  module CLI
9
10
  module Errors
10
11
  # Central error handler with context-aware suggestions
11
12
  class Handler
13
+ extend Helpers::UxHelper
14
+
12
15
  class << self
13
16
  # Handle an error with context and provide helpful suggestions
14
17
  def handle(error, context = {})
@@ -51,31 +54,33 @@ module LanguageOperator
51
54
  suggestions = Suggestions.for_error(error_type, context)
52
55
  display_suggestions(suggestions) if suggestions.any?
53
56
 
54
- # Re-raise if in debug mode, otherwise exit
57
+ # Re-raise if in debug mode, otherwise raise Thor error
55
58
  raise error if ENV['DEBUG']
56
59
 
57
- exit 1
60
+ raise NotFoundError, message
58
61
  end
59
62
 
60
63
  # Handle generic errors
61
64
  def handle_generic(error, context)
62
65
  operation = context[:operation] || 'operation'
66
+ message = "Failed to #{operation}: #{error.message}"
63
67
 
64
- Formatters::ProgressFormatter.error("Failed to #{operation}: #{error.message}")
68
+ Formatters::ProgressFormatter.error(message)
65
69
  puts
66
70
 
67
71
  # Display suggestions if provided in context
68
72
  display_suggestions(context[:suggestions]) if context[:suggestions]
69
73
 
70
- # Re-raise if in debug mode, otherwise exit
74
+ # Re-raise if in debug mode, otherwise raise Thor error
71
75
  raise error if ENV['DEBUG']
72
76
 
73
- exit 1
77
+ raise Thor::Error, message
74
78
  end
75
79
 
76
80
  # Handle specific error scenarios with custom suggestions
77
81
  def handle_no_cluster_selected
78
- Formatters::ProgressFormatter.error('No cluster selected')
82
+ message = 'No cluster selected'
83
+ Formatters::ProgressFormatter.error(message)
79
84
  puts
80
85
 
81
86
  puts 'You must connect to a cluster first:'
@@ -84,27 +89,29 @@ module LanguageOperator
84
89
  suggestions = Suggestions.for_error(:no_cluster_selected)
85
90
  suggestions.each { |line| puts line }
86
91
 
87
- exit 1
92
+ raise ValidationError, message
88
93
  end
89
94
 
90
95
  def handle_no_models_available(context = {})
91
- Formatters::ProgressFormatter.error('No models found in cluster')
96
+ message = 'No models found in cluster'
97
+ Formatters::ProgressFormatter.error(message)
92
98
  puts
93
99
 
94
100
  suggestions = Suggestions.for_error(:no_models_available, context)
95
101
  suggestions.each { |line| puts line }
96
102
 
97
- exit 1
103
+ raise ValidationError, message
98
104
  end
99
105
 
100
106
  def handle_synthesis_failed(message)
101
- Formatters::ProgressFormatter.error("Synthesis failed: #{message}")
107
+ error_message = "Synthesis failed: #{message}"
108
+ Formatters::ProgressFormatter.error(error_message)
102
109
  puts
103
110
 
104
111
  suggestions = Suggestions.for_error(:synthesis_failed)
105
112
  suggestions.each { |line| puts line }
106
113
 
107
- exit 1
114
+ raise SynthesisError, error_message
108
115
  end
109
116
 
110
117
  def handle_already_exists(context = {})
@@ -124,7 +131,7 @@ module LanguageOperator
124
131
  suggestions = Suggestions.for_error(:already_exists, context)
125
132
  display_suggestions(suggestions) if suggestions.any?
126
133
 
127
- exit 1
134
+ raise ValidationError, message
128
135
  end
129
136
 
130
137
  private
@@ -169,10 +176,6 @@ module LanguageOperator
169
176
  :resource_not_found
170
177
  end
171
178
  end
172
-
173
- def pastel
174
- @pastel ||= Pastel.new
175
- end
176
179
  end
177
180
  end
178
181
  end
@@ -1,13 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'did_you_mean'
4
- require 'pastel'
4
+ require_relative '../helpers/ux_helper'
5
5
 
6
6
  module LanguageOperator
7
7
  module CLI
8
8
  module Errors
9
9
  # Provides helpful suggestions for error recovery
10
10
  class Suggestions
11
+ extend Helpers::UxHelper
12
+
11
13
  class << self
12
14
  # Find similar resource names using fuzzy matching
13
15
  def find_similar(input_name, available_names, limit: 3)
@@ -165,10 +167,6 @@ module LanguageOperator
165
167
  resource_type.downcase
166
168
  end
167
169
  end
168
-
169
- def pastel
170
- @pastel ||= Pastel.new
171
- end
172
170
  end
173
171
  end
174
172
  end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+
5
+ module LanguageOperator
6
+ module CLI
7
+ module Errors
8
+ # Base error class that integrates properly with Thor's error handling
9
+ # while providing specific exit codes for different error types
10
+ class ThorCompatibleError < Thor::Error
11
+ attr_reader :exit_code
12
+
13
+ def initialize(message = nil, exit_code = 1)
14
+ super(message)
15
+ @exit_code = exit_code
16
+ end
17
+ end
18
+
19
+ # Resource not found error (exit code 2)
20
+ class NotFoundError < ThorCompatibleError
21
+ def initialize(message = nil)
22
+ super(message, 2)
23
+ end
24
+ end
25
+
26
+ # Validation or configuration error (exit code 3)
27
+ class ValidationError < ThorCompatibleError
28
+ def initialize(message = nil)
29
+ super(message, 3)
30
+ end
31
+ end
32
+
33
+ # Network or connectivity error (exit code 4)
34
+ class NetworkError < ThorCompatibleError
35
+ def initialize(message = nil)
36
+ super(message, 4)
37
+ end
38
+ end
39
+
40
+ # Authentication or authorization error (exit code 5)
41
+ class AuthError < ThorCompatibleError
42
+ def initialize(message = nil)
43
+ super(message, 5)
44
+ end
45
+ end
46
+
47
+ # Synthesis or code generation error (exit code 6)
48
+ class SynthesisError < ThorCompatibleError
49
+ def initialize(message = nil)
50
+ super(message, 6)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rouge'
4
- require_relative '../helpers/pastel_helper'
3
+ require_relative '../helpers/ux_helper'
5
4
 
6
5
  module LanguageOperator
7
6
  module CLI
@@ -9,7 +8,7 @@ module LanguageOperator
9
8
  # Formatter for displaying syntax-highlighted code in the terminal
10
9
  class CodeFormatter
11
10
  class << self
12
- include Helpers::PastelHelper
11
+ include Helpers::UxHelper
13
12
 
14
13
  # Display Ruby code with syntax highlighting
15
14
  #
@@ -17,10 +16,6 @@ module LanguageOperator
17
16
  # @param title [String, nil] Optional title to display above the code
18
17
  # @param max_lines [Integer, nil] Maximum number of lines to display (nil for all)
19
18
  def display_ruby_code(code_content, title: nil, max_lines: nil)
20
- # Use Rouge to highlight the code
21
- formatter = Rouge::Formatters::Terminal256.new
22
- lexer = Rouge::Lexers::Ruby.new
23
-
24
19
  # Truncate if max_lines specified
25
20
  lines = code_content.lines
26
21
  truncated = false
@@ -33,7 +28,7 @@ module LanguageOperator
33
28
  end
34
29
 
35
30
  # Highlight and print the code
36
- highlighted = formatter.format(lexer.lex(code_to_display))
31
+ highlighted = highlight_ruby_code(code_to_display)
37
32
  puts highlighted
38
33
 
39
34
  # Show truncation notice if applicable
@@ -53,9 +48,7 @@ module LanguageOperator
53
48
  puts pastel.dim(description) if description
54
49
  puts
55
50
 
56
- formatter = Rouge::Formatters::Terminal256.new
57
- lexer = Rouge::Lexers::Ruby.new
58
- highlighted = formatter.format(lexer.lex(code_content))
51
+ highlighted = highlight_ruby_code(code_content)
59
52
 
60
53
  puts highlighted
61
54
  puts
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../helpers/pastel_helper'
3
+ require_relative '../helpers/ux_helper'
4
4
  require_relative 'log_style'
5
+ require_relative 'value_formatter'
5
6
  require 'json'
6
7
  require 'time'
7
8
 
@@ -11,7 +12,7 @@ module LanguageOperator
11
12
  # Formatter for displaying agent execution logs with color and icons
12
13
  class LogFormatter
13
14
  class << self
14
- include Helpers::PastelHelper
15
+ include Helpers::UxHelper
15
16
 
16
17
  # Format a single log line from kubectl output
17
18
  #
@@ -207,27 +208,19 @@ module LanguageOperator
207
208
 
208
209
  # Format timestamp from ISO8601 format
209
210
  def format_timestamp_from_iso(timestamp_str)
210
- return '' unless timestamp_str
211
-
212
- time = Time.parse(timestamp_str)
213
- format_time(time)
214
- rescue StandardError
215
- ''
211
+ time_str = ValueFormatter.parse_and_format_time(timestamp_str)
212
+ time_str.empty? ? '' : pastel.dim(time_str)
216
213
  end
217
214
 
218
215
  # Format timestamp from text format (YYYY-MM-DD HH:MM:SS)
219
216
  def format_timestamp_from_text(timestamp_str)
220
- return '' unless timestamp_str
221
-
222
- time = Time.parse(timestamp_str)
223
- format_time(time)
224
- rescue StandardError
225
- ''
217
+ time_str = ValueFormatter.parse_and_format_time(timestamp_str)
218
+ time_str.empty? ? '' : pastel.dim(time_str)
226
219
  end
227
220
 
228
221
  # Format Time object as HH:MM:SS
229
222
  def format_time(time)
230
- pastel.dim(time.strftime('%H:%M:%S'))
223
+ pastel.dim(ValueFormatter.log_time(time))
231
224
  end
232
225
  end
233
226
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'tty-spinner'
4
- require_relative '../helpers/pastel_helper'
3
+ require_relative '../helpers/ux_helper'
5
4
  require_relative 'log_style'
6
5
 
7
6
  module LanguageOperator
@@ -10,22 +9,21 @@ module LanguageOperator
10
9
  # Beautiful progress output for CLI operations
11
10
  class ProgressFormatter
12
11
  class << self
13
- include Helpers::PastelHelper
12
+ include Helpers::UxHelper
14
13
 
15
14
  def with_spinner(message, success_msg: nil, &block)
16
- success_icon = LogStyle.styled_icon(:success, pastel)
17
- spinner = TTY::Spinner.new(":spinner #{message}...", format: :dots, success_mark: success_icon)
18
- spinner.auto_spin
15
+ spin = spinner("#{message}...")
16
+ spin.auto_spin
19
17
 
20
18
  result = block.call
21
19
 
22
20
  # Determine what to show after spinner completes
23
21
  final_status = success_msg || 'done'
24
22
 
25
- spinner.success(final_status)
23
+ spin.success(final_status)
26
24
  result
27
25
  rescue StandardError => e
28
- spinner.error(e.message)
26
+ spin.error(e.message)
29
27
  raise
30
28
  end
31
29
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../helpers/pastel_helper'
3
+ require_relative '../helpers/ux_helper'
4
4
 
5
5
  module LanguageOperator
6
6
  module CLI
@@ -9,7 +9,7 @@ module LanguageOperator
9
9
  #
10
10
  # Provides consistent colored status dots (●) for resource states
11
11
  class StatusFormatter
12
- extend Helpers::PastelHelper
12
+ extend Helpers::UxHelper
13
13
 
14
14
  # Format a status string with colored indicator
15
15
  #
@@ -17,20 +17,39 @@ module LanguageOperator
17
17
  # @return [String] Formatted status with colored dot
18
18
  def self.format(status)
19
19
  status_str = status.to_s
20
+ color = status_color(status_str)
21
+ "#{pastel.send(color, '●')} #{status_str}"
22
+ end
20
23
 
24
+ # Format just the status indicator dot (without text)
25
+ #
26
+ # @param status [String, Symbol] The status to format
27
+ # @return [String] Just the colored dot
28
+ def self.dot(status)
29
+ color = status_color(status.to_s)
30
+ pastel.send(color, '●')
31
+ end
32
+
33
+ # Determine the appropriate color for a status
34
+ #
35
+ # @param status_str [String] The status string
36
+ # @return [Symbol] Color method name for pastel
37
+ def self.status_color(status_str)
21
38
  case status_str.downcase
22
39
  when 'ready', 'running', 'active'
23
- "#{pastel.green('●')} #{status_str}"
40
+ :green
24
41
  when 'pending', 'creating', 'synthesizing'
25
- "#{pastel.yellow('●')} #{status_str}"
42
+ :yellow
26
43
  when 'failed', 'error'
27
- "#{pastel.red('●')} #{status_str}"
44
+ :red
28
45
  when 'paused', 'stopped', 'suspended'
29
- "#{pastel.dim('●')} #{status_str}"
46
+ :dim
30
47
  else
31
- "#{pastel.dim('●')} #{status_str}"
48
+ :dim
32
49
  end
33
50
  end
51
+
52
+ private_class_method :status_color
34
53
  end
35
54
  end
36
55
  end