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.
- checksums.yaml +4 -4
- data/.claude/commands/persona.md +9 -0
- data/.claude/commands/task.md +46 -1
- data/.rubocop.yml +13 -0
- data/.rubocop_custom/use_ux_helper.rb +44 -0
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +12 -1
- data/Makefile +26 -7
- data/Makefile.common +50 -0
- data/bin/aictl +8 -1
- data/components/agent/Gemfile +1 -1
- data/components/agent/bin/langop-agent +7 -0
- data/docs/README.md +58 -0
- data/docs/{dsl/best-practices.md → best-practices.md} +4 -4
- data/docs/cli-reference.md +274 -0
- data/docs/{dsl/constraints.md → constraints.md} +5 -5
- data/docs/how-agents-work.md +156 -0
- data/docs/installation.md +218 -0
- data/docs/quickstart.md +299 -0
- data/docs/understanding-generated-code.md +265 -0
- data/docs/using-tools.md +457 -0
- data/docs/webhooks.md +509 -0
- data/examples/ux_helpers_demo.rb +296 -0
- data/lib/language_operator/agent/base.rb +11 -1
- data/lib/language_operator/agent/executor.rb +23 -6
- data/lib/language_operator/agent/safety/safe_executor.rb +41 -39
- data/lib/language_operator/agent/task_executor.rb +346 -63
- data/lib/language_operator/agent/web_server.rb +110 -14
- data/lib/language_operator/agent/webhook_authenticator.rb +39 -5
- data/lib/language_operator/agent.rb +88 -2
- data/lib/language_operator/cli/base_command.rb +17 -11
- data/lib/language_operator/cli/command_loader.rb +72 -0
- data/lib/language_operator/cli/commands/agent/base.rb +837 -0
- data/lib/language_operator/cli/commands/agent/code_operations.rb +102 -0
- data/lib/language_operator/cli/commands/agent/helpers/cluster_llm_client.rb +116 -0
- data/lib/language_operator/cli/commands/agent/helpers/code_parser.rb +115 -0
- data/lib/language_operator/cli/commands/agent/helpers/synthesis_watcher.rb +96 -0
- data/lib/language_operator/cli/commands/agent/learning.rb +289 -0
- data/lib/language_operator/cli/commands/agent/lifecycle.rb +102 -0
- data/lib/language_operator/cli/commands/agent/logs.rb +125 -0
- data/lib/language_operator/cli/commands/agent/workspace.rb +327 -0
- data/lib/language_operator/cli/commands/cluster.rb +129 -84
- data/lib/language_operator/cli/commands/install.rb +1 -1
- data/lib/language_operator/cli/commands/model/base.rb +215 -0
- data/lib/language_operator/cli/commands/model/test.rb +165 -0
- data/lib/language_operator/cli/commands/persona.rb +16 -34
- data/lib/language_operator/cli/commands/quickstart.rb +3 -2
- data/lib/language_operator/cli/commands/status.rb +40 -67
- data/lib/language_operator/cli/commands/system/base.rb +44 -0
- data/lib/language_operator/cli/commands/system/exec.rb +147 -0
- data/lib/language_operator/cli/commands/system/helpers/llm_synthesis.rb +183 -0
- data/lib/language_operator/cli/commands/system/helpers/pod_manager.rb +212 -0
- data/lib/language_operator/cli/commands/system/helpers/template_loader.rb +57 -0
- data/lib/language_operator/cli/commands/system/helpers/template_validator.rb +174 -0
- data/lib/language_operator/cli/commands/system/schema.rb +92 -0
- data/lib/language_operator/cli/commands/system/synthesis_template.rb +151 -0
- data/lib/language_operator/cli/commands/system/synthesize.rb +224 -0
- data/lib/language_operator/cli/commands/system/validate_template.rb +130 -0
- data/lib/language_operator/cli/commands/tool/base.rb +271 -0
- data/lib/language_operator/cli/commands/tool/install.rb +255 -0
- data/lib/language_operator/cli/commands/tool/search.rb +69 -0
- data/lib/language_operator/cli/commands/tool/test.rb +115 -0
- data/lib/language_operator/cli/commands/use.rb +29 -6
- data/lib/language_operator/cli/errors/handler.rb +20 -17
- data/lib/language_operator/cli/errors/suggestions.rb +3 -5
- data/lib/language_operator/cli/errors/thor_errors.rb +55 -0
- data/lib/language_operator/cli/formatters/code_formatter.rb +4 -11
- data/lib/language_operator/cli/formatters/log_formatter.rb +8 -15
- data/lib/language_operator/cli/formatters/progress_formatter.rb +6 -8
- data/lib/language_operator/cli/formatters/status_formatter.rb +26 -7
- data/lib/language_operator/cli/formatters/table_formatter.rb +47 -36
- data/lib/language_operator/cli/formatters/value_formatter.rb +75 -0
- data/lib/language_operator/cli/helpers/cluster_context.rb +5 -3
- data/lib/language_operator/cli/helpers/kubeconfig_validator.rb +2 -1
- data/lib/language_operator/cli/helpers/label_utils.rb +97 -0
- data/lib/language_operator/{ux/concerns/provider_helpers.rb → cli/helpers/provider_helper.rb} +10 -29
- data/lib/language_operator/cli/helpers/schedule_builder.rb +21 -1
- data/lib/language_operator/cli/helpers/user_prompts.rb +19 -11
- data/lib/language_operator/cli/helpers/ux_helper.rb +538 -0
- data/lib/language_operator/{ux/concerns/input_validation.rb → cli/helpers/validation_helper.rb} +13 -66
- data/lib/language_operator/cli/main.rb +50 -40
- data/lib/language_operator/cli/templates/tools/generic.yaml +3 -0
- data/lib/language_operator/cli/wizards/agent_wizard.rb +12 -20
- data/lib/language_operator/cli/wizards/model_wizard.rb +271 -0
- data/lib/language_operator/cli/wizards/quickstart_wizard.rb +8 -34
- data/lib/language_operator/client/base.rb +28 -0
- data/lib/language_operator/client/config.rb +4 -1
- data/lib/language_operator/client/mcp_connector.rb +1 -1
- data/lib/language_operator/config/cluster_config.rb +3 -2
- data/lib/language_operator/config.rb +38 -11
- data/lib/language_operator/constants/kubernetes_labels.rb +80 -0
- data/lib/language_operator/constants.rb +13 -0
- data/lib/language_operator/dsl/http.rb +127 -10
- data/lib/language_operator/dsl.rb +153 -6
- data/lib/language_operator/errors.rb +50 -0
- data/lib/language_operator/kubernetes/client.rb +11 -6
- data/lib/language_operator/kubernetes/resource_builder.rb +58 -84
- data/lib/language_operator/templates/schema/agent_dsl_openapi.yaml +1 -1
- data/lib/language_operator/templates/schema/agent_dsl_schema.json +1 -1
- data/lib/language_operator/type_coercion.rb +118 -34
- data/lib/language_operator/utils/secure_path.rb +74 -0
- data/lib/language_operator/utils.rb +7 -0
- data/lib/language_operator/validators.rb +54 -2
- data/lib/language_operator/version.rb +1 -1
- data/synth/001/Makefile +10 -2
- data/synth/001/agent.rb +16 -15
- data/synth/001/output.log +27 -10
- data/synth/002/Makefile +10 -2
- data/synth/003/Makefile +1 -1
- data/synth/003/README.md +205 -133
- data/synth/003/agent.optimized.rb +66 -0
- data/synth/003/agent.synthesized.rb +41 -0
- metadata +111 -35
- data/docs/dsl/agent-reference.md +0 -604
- data/docs/dsl/mcp-integration.md +0 -1177
- data/docs/dsl/webhooks.md +0 -932
- data/docs/dsl/workflows.md +0 -744
- data/lib/language_operator/cli/commands/agent.rb +0 -1712
- data/lib/language_operator/cli/commands/model.rb +0 -366
- data/lib/language_operator/cli/commands/system.rb +0 -1259
- data/lib/language_operator/cli/commands/tool.rb +0 -654
- data/lib/language_operator/cli/formatters/optimization_formatter.rb +0 -226
- data/lib/language_operator/cli/helpers/pastel_helper.rb +0 -24
- data/lib/language_operator/learning/adapters/base_adapter.rb +0 -149
- data/lib/language_operator/learning/adapters/jaeger_adapter.rb +0 -221
- data/lib/language_operator/learning/adapters/signoz_adapter.rb +0 -435
- data/lib/language_operator/learning/adapters/tempo_adapter.rb +0 -239
- data/lib/language_operator/learning/optimizer.rb +0 -319
- data/lib/language_operator/learning/pattern_detector.rb +0 -260
- data/lib/language_operator/learning/task_synthesizer.rb +0 -288
- data/lib/language_operator/learning/trace_analyzer.rb +0 -285
- data/lib/language_operator/templates/task_synthesis.tmpl +0 -98
- data/lib/language_operator/ux/base.rb +0 -81
- data/lib/language_operator/ux/concerns/README.md +0 -155
- data/lib/language_operator/ux/concerns/headings.rb +0 -90
- data/lib/language_operator/ux/create_agent.rb +0 -255
- data/lib/language_operator/ux/create_model.rb +0 -267
- data/lib/language_operator/ux/quickstart.rb +0 -594
- data/synth/003/agent.rb +0 -41
- data/synth/003/output.log +0 -68
- /data/docs/{architecture/agent-runtime.md → agent-internals.md} +0 -0
- /data/docs/{dsl/chat-endpoints.md → chat-endpoints.md} +0 -0
- /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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
|
57
|
+
# Re-raise if in debug mode, otherwise raise Thor error
|
|
55
58
|
raise error if ENV['DEBUG']
|
|
56
59
|
|
|
57
|
-
|
|
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(
|
|
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
|
|
74
|
+
# Re-raise if in debug mode, otherwise raise Thor error
|
|
71
75
|
raise error if ENV['DEBUG']
|
|
72
76
|
|
|
73
|
-
|
|
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
|
-
|
|
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
|
-
|
|
92
|
+
raise ValidationError, message
|
|
88
93
|
end
|
|
89
94
|
|
|
90
95
|
def handle_no_models_available(context = {})
|
|
91
|
-
|
|
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
|
-
|
|
103
|
+
raise ValidationError, message
|
|
98
104
|
end
|
|
99
105
|
|
|
100
106
|
def handle_synthesis_failed(message)
|
|
101
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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::
|
|
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 =
|
|
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
|
-
|
|
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/
|
|
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::
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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::
|
|
12
|
+
include Helpers::UxHelper
|
|
14
13
|
|
|
15
14
|
def with_spinner(message, success_msg: nil, &block)
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
23
|
+
spin.success(final_status)
|
|
26
24
|
result
|
|
27
25
|
rescue StandardError => e
|
|
28
|
-
|
|
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/
|
|
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::
|
|
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
|
-
|
|
40
|
+
:green
|
|
24
41
|
when 'pending', 'creating', 'synthesizing'
|
|
25
|
-
|
|
42
|
+
:yellow
|
|
26
43
|
when 'failed', 'error'
|
|
27
|
-
|
|
44
|
+
:red
|
|
28
45
|
when 'paused', 'stopped', 'suspended'
|
|
29
|
-
|
|
46
|
+
:dim
|
|
30
47
|
else
|
|
31
|
-
|
|
48
|
+
:dim
|
|
32
49
|
end
|
|
33
50
|
end
|
|
51
|
+
|
|
52
|
+
private_class_method :status_color
|
|
34
53
|
end
|
|
35
54
|
end
|
|
36
55
|
end
|