aicli 0.1.1 → 0.2.6
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/CHANGELOG.md +39 -0
- data/README.md +48 -14
- data/lib/aicli/cli.rb +2 -2
- data/lib/aicli/commands/chat.rb +91 -30
- data/lib/aicli/commands/update.rb +65 -3
- data/lib/aicli/helpers/completion.rb +138 -182
- data/lib/aicli/helpers/config.rb +103 -15
- data/lib/aicli/helpers/context.rb +94 -0
- data/lib/aicli/helpers/llm.rb +130 -0
- data/lib/aicli/prompt.rb +43 -37
- data/lib/aicli/version.rb +1 -1
- data/lib/aicli.rb +2 -0
- data/locales/en.yml +10 -0
- data/locales/it.yml +10 -0
- metadata +17 -1
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'ruby_llm'
|
|
4
|
+
|
|
5
|
+
module AiCli
|
|
6
|
+
module Helpers
|
|
7
|
+
module Llm
|
|
8
|
+
PROVIDERS = %w[openai anthropic].freeze
|
|
9
|
+
|
|
10
|
+
DEFAULT_MODELS = {
|
|
11
|
+
'openai' => 'gpt-4o-mini',
|
|
12
|
+
'anthropic' => 'claude-sonnet-4-6'
|
|
13
|
+
}.freeze
|
|
14
|
+
|
|
15
|
+
module_function
|
|
16
|
+
|
|
17
|
+
def configure!(config)
|
|
18
|
+
provider = normalize_provider(config['PROVIDER'])
|
|
19
|
+
ensure_credentials!(config, provider)
|
|
20
|
+
|
|
21
|
+
RubyLLM.configure do |c|
|
|
22
|
+
openai_key = config['OPENAI_KEY'].to_s
|
|
23
|
+
anthropic_key = config['ANTHROPIC_KEY'].to_s
|
|
24
|
+
endpoint = config['OPENAI_API_ENDPOINT'].to_s
|
|
25
|
+
|
|
26
|
+
c.openai_api_key = openai_key unless openai_key.empty?
|
|
27
|
+
c.anthropic_api_key = anthropic_key unless anthropic_key.empty?
|
|
28
|
+
|
|
29
|
+
if !endpoint.empty? && endpoint != 'https://api.openai.com/v1'
|
|
30
|
+
c.openai_api_base = endpoint.sub(%r{/+\z}, '')
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
provider
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def build_chat(config)
|
|
38
|
+
provider, model = resolve_provider_and_model(config)
|
|
39
|
+
ensure_credentials!(config, provider)
|
|
40
|
+
|
|
41
|
+
configure!(config.merge('PROVIDER' => provider, 'MODEL' => model))
|
|
42
|
+
|
|
43
|
+
opts = { model: model, provider: provider.to_sym }
|
|
44
|
+
opts[:assume_model_exists] = true unless model_known?(model, provider)
|
|
45
|
+
RubyLLM.chat(**opts)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Returns [provider, model], fixing mismatches against the RubyLLM registry.
|
|
49
|
+
def resolve_provider_and_model(config)
|
|
50
|
+
provider = normalize_provider(config['PROVIDER'])
|
|
51
|
+
model = config['MODEL'].to_s
|
|
52
|
+
model = default_model_for(provider) if model.empty?
|
|
53
|
+
|
|
54
|
+
model_provider = provider_for_model(model)
|
|
55
|
+
if model_provider && model_provider != provider
|
|
56
|
+
# Prefer the provider that actually owns the selected model.
|
|
57
|
+
provider = model_provider
|
|
58
|
+
elsif model_provider.nil? && !model_known?(model, provider)
|
|
59
|
+
# Unknown id for this provider: fall back to a safe default.
|
|
60
|
+
model = default_model_for(provider)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
[provider, model]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def provider_for_model(model_id)
|
|
67
|
+
return nil if model_id.to_s.empty?
|
|
68
|
+
|
|
69
|
+
info = RubyLLM.models.find(model_id)
|
|
70
|
+
normalize_provider(info.provider)
|
|
71
|
+
rescue StandardError
|
|
72
|
+
# Try each known provider explicitly (aliases can be provider-specific).
|
|
73
|
+
PROVIDERS.each do |provider|
|
|
74
|
+
return provider if model_known?(model_id, provider)
|
|
75
|
+
end
|
|
76
|
+
nil
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def list_chat_models(provider)
|
|
80
|
+
provider = normalize_provider(provider)
|
|
81
|
+
|
|
82
|
+
RubyLLM.models.chat_models
|
|
83
|
+
.by_provider(provider.to_sym)
|
|
84
|
+
.select { |m| text_chat_model?(m) }
|
|
85
|
+
.sort_by { |m| [m.name.to_s.downcase, m.id] }
|
|
86
|
+
.map { |m| { 'id' => m.id, 'name' => m.name.to_s } }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def default_model_for(provider)
|
|
90
|
+
DEFAULT_MODELS.fetch(normalize_provider(provider), DEFAULT_MODELS['openai'])
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def normalize_provider(provider)
|
|
94
|
+
value = provider.to_s.downcase
|
|
95
|
+
PROVIDERS.include?(value) ? value : 'openai'
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def ensure_credentials!(config, provider = nil)
|
|
99
|
+
provider = normalize_provider(provider || config['PROVIDER'])
|
|
100
|
+
|
|
101
|
+
case provider
|
|
102
|
+
when 'anthropic'
|
|
103
|
+
if config['ANTHROPIC_KEY'].to_s.empty?
|
|
104
|
+
raise KnownError,
|
|
105
|
+
"Please set your Anthropic API key via `#{Constants::COMMAND_NAME} config set ANTHROPIC_KEY=<your token>`"
|
|
106
|
+
end
|
|
107
|
+
else
|
|
108
|
+
if config['OPENAI_KEY'].to_s.empty?
|
|
109
|
+
raise KnownError,
|
|
110
|
+
"Please set your OpenAI API key via `#{Constants::COMMAND_NAME} config set OPENAI_KEY=<your token>`"
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def model_known?(model, provider)
|
|
116
|
+
RubyLLM.models.find(model, provider.to_sym)
|
|
117
|
+
true
|
|
118
|
+
rescue StandardError
|
|
119
|
+
false
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def text_chat_model?(model)
|
|
123
|
+
outputs = Array(model.modalities&.output).map(&:to_s)
|
|
124
|
+
return false unless outputs.include?('text')
|
|
125
|
+
|
|
126
|
+
!model.id.match?(/tts|transcribe|realtime|whisper|embedding|moderation|dall-e|imagen|search-preview|babbage|davinci|ada-|curie|instruct/i)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
data/lib/aicli/prompt.rb
CHANGED
|
@@ -14,14 +14,12 @@ module AiCli
|
|
|
14
14
|
init_i18n
|
|
15
15
|
|
|
16
16
|
config = Helpers::Config.get
|
|
17
|
-
key = config['OPENAI_KEY']
|
|
18
|
-
model = config['MODEL']
|
|
19
|
-
api_endpoint = config['OPENAI_API_ENDPOINT']
|
|
20
17
|
skip_explanation = silent_mode || config['SILENT_MODE']
|
|
21
18
|
|
|
22
19
|
pastel = Pastel.new
|
|
23
20
|
puts ''
|
|
24
|
-
puts
|
|
21
|
+
puts pastel.cyan(Helpers::Constants::PROJECT_NAME)
|
|
22
|
+
puts pastel.dim("#{config['PROVIDER']} / #{config['MODEL']}")
|
|
25
23
|
|
|
26
24
|
the_prompt = use_prompt.nil? || use_prompt.strip.empty? ? ask_prompt : use_prompt
|
|
27
25
|
|
|
@@ -30,9 +28,7 @@ module AiCli
|
|
|
30
28
|
|
|
31
29
|
result = Helpers::Completion.get_script_and_info(
|
|
32
30
|
prompt: the_prompt,
|
|
33
|
-
|
|
34
|
-
model: model,
|
|
35
|
-
api_endpoint: api_endpoint
|
|
31
|
+
config: config
|
|
36
32
|
)
|
|
37
33
|
|
|
38
34
|
spinner.success(Helpers::I18n.t('Your script') + ':')
|
|
@@ -40,8 +36,8 @@ module AiCli
|
|
|
40
36
|
script = result[:read_script].call(->(chunk) { print chunk })
|
|
41
37
|
puts ''
|
|
42
38
|
puts ''
|
|
43
|
-
puts pastel.dim('•')
|
|
44
39
|
|
|
40
|
+
explanation_text = ''
|
|
45
41
|
unless skip_explanation
|
|
46
42
|
spinner = TTY::Spinner.new("[:spinner] #{Helpers::I18n.t('Getting explanation...')}", format: :dots)
|
|
47
43
|
spinner.auto_spin
|
|
@@ -50,22 +46,21 @@ module AiCli
|
|
|
50
46
|
if info.nil? || info.empty?
|
|
51
47
|
explanation = Helpers::Completion.get_explanation(
|
|
52
48
|
script: script,
|
|
53
|
-
|
|
54
|
-
model: model,
|
|
55
|
-
api_endpoint: api_endpoint
|
|
49
|
+
config: config
|
|
56
50
|
)
|
|
57
51
|
spinner.success(Helpers::I18n.t('Explanation') + ':')
|
|
58
52
|
puts ''
|
|
59
|
-
explanation[:read_explanation].call(->(chunk) { print chunk })
|
|
53
|
+
explanation_text = explanation[:read_explanation].call(->(chunk) { print chunk })
|
|
60
54
|
puts ''
|
|
61
55
|
puts ''
|
|
62
|
-
puts pastel.dim('•')
|
|
63
56
|
else
|
|
57
|
+
explanation_text = info
|
|
64
58
|
spinner.success(Helpers::I18n.t('Explanation') + ':')
|
|
65
59
|
end
|
|
66
60
|
end
|
|
67
61
|
|
|
68
|
-
|
|
62
|
+
append_prompt_context(the_prompt, script, explanation_text)
|
|
63
|
+
run_or_revise_flow(script, config, silent_mode)
|
|
69
64
|
end
|
|
70
65
|
|
|
71
66
|
def init_i18n
|
|
@@ -85,14 +80,32 @@ module AiCli
|
|
|
85
80
|
end
|
|
86
81
|
|
|
87
82
|
def ask_prompt(initial = nil)
|
|
88
|
-
prompt = TTY::Prompt.new(interrupt: :
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
83
|
+
prompt = TTY::Prompt.new(interrupt: :error)
|
|
84
|
+
Helpers::Context.seed_prompt_history(prompt)
|
|
85
|
+
|
|
86
|
+
loop do
|
|
87
|
+
begin
|
|
88
|
+
return prompt.ask(Helpers::I18n.t('What would you like me to do?')) do |q|
|
|
89
|
+
q.required true
|
|
90
|
+
q.default initial || Helpers::I18n.t('Say hello')
|
|
91
|
+
q.validate(/.+/, Helpers::I18n.t('Please enter a prompt.'))
|
|
92
|
+
end
|
|
93
|
+
rescue TTY::Reader::InputInterrupt
|
|
94
|
+
print "\r\e[2K"
|
|
95
|
+
end
|
|
93
96
|
end
|
|
94
97
|
end
|
|
95
98
|
|
|
99
|
+
def append_prompt_context(user_prompt, script, explanation)
|
|
100
|
+
assistant = +"```\n#{script}\n```"
|
|
101
|
+
assistant << "\n\n#{explanation}" unless explanation.to_s.strip.empty?
|
|
102
|
+
|
|
103
|
+
messages = Helpers::Context.load_messages
|
|
104
|
+
messages << { 'role' => 'user', 'content' => user_prompt.to_s }
|
|
105
|
+
messages << { 'role' => 'assistant', 'content' => assistant }
|
|
106
|
+
Helpers::Context.save_messages(messages)
|
|
107
|
+
end
|
|
108
|
+
|
|
96
109
|
def ask_revision
|
|
97
110
|
prompt = TTY::Prompt.new(interrupt: :exit)
|
|
98
111
|
prompt.ask(Helpers::I18n.t('What would you like me to change in this script?')) do |q|
|
|
@@ -102,14 +115,13 @@ module AiCli
|
|
|
102
115
|
end
|
|
103
116
|
|
|
104
117
|
def run_script(script)
|
|
105
|
-
|
|
106
|
-
puts "└ #{Helpers::I18n.t('Running')}: #{script}"
|
|
118
|
+
puts "#{Helpers::I18n.t('Running')}: #{script}"
|
|
107
119
|
puts ''
|
|
108
120
|
system(ENV['SHELL'] || 'bash', '-c', script)
|
|
109
121
|
Helpers::ShellHistory.append(script)
|
|
110
122
|
end
|
|
111
123
|
|
|
112
|
-
def run_or_revise_flow(script,
|
|
124
|
+
def run_or_revise_flow(script, config, silent_mode)
|
|
113
125
|
prompt = TTY::Prompt.new(interrupt: :exit)
|
|
114
126
|
empty_script = script.strip.empty?
|
|
115
127
|
|
|
@@ -132,18 +144,17 @@ module AiCli
|
|
|
132
144
|
new_script = prompt.ask(Helpers::I18n.t('you can edit script here'), default: script)
|
|
133
145
|
run_script(new_script) if new_script && !new_script.empty?
|
|
134
146
|
when :revise
|
|
135
|
-
revision_flow(script,
|
|
147
|
+
revision_flow(script, config, silent_mode)
|
|
136
148
|
when :copy
|
|
137
149
|
Clipboard.copy(script)
|
|
138
|
-
puts
|
|
150
|
+
puts Helpers::I18n.t('Copied to clipboard!')
|
|
139
151
|
when :cancel
|
|
140
|
-
puts
|
|
152
|
+
puts Helpers::I18n.t('Goodbye!')
|
|
141
153
|
exit 0
|
|
142
154
|
end
|
|
143
155
|
end
|
|
144
156
|
|
|
145
|
-
def revision_flow(current_script,
|
|
146
|
-
pastel = Pastel.new
|
|
157
|
+
def revision_flow(current_script, config, silent_mode)
|
|
147
158
|
revision = ask_revision
|
|
148
159
|
|
|
149
160
|
spinner = TTY::Spinner.new("[:spinner] #{Helpers::I18n.t('Loading...')}", format: :dots)
|
|
@@ -152,9 +163,7 @@ module AiCli
|
|
|
152
163
|
result = Helpers::Completion.get_revision(
|
|
153
164
|
prompt: revision,
|
|
154
165
|
code: current_script,
|
|
155
|
-
|
|
156
|
-
model: model,
|
|
157
|
-
api_endpoint: api_endpoint
|
|
166
|
+
config: config
|
|
158
167
|
)
|
|
159
168
|
|
|
160
169
|
spinner.success(Helpers::I18n.t('Your new script') + ':')
|
|
@@ -162,7 +171,6 @@ module AiCli
|
|
|
162
171
|
script = result[:read_script].call(->(chunk) { print chunk })
|
|
163
172
|
puts ''
|
|
164
173
|
puts ''
|
|
165
|
-
puts pastel.dim('•')
|
|
166
174
|
|
|
167
175
|
unless silent_mode
|
|
168
176
|
info_spinner = TTY::Spinner.new("[:spinner] #{Helpers::I18n.t('Getting explanation...')}", format: :dots)
|
|
@@ -170,9 +178,7 @@ module AiCli
|
|
|
170
178
|
|
|
171
179
|
explanation = Helpers::Completion.get_explanation(
|
|
172
180
|
script: script,
|
|
173
|
-
|
|
174
|
-
model: model,
|
|
175
|
-
api_endpoint: api_endpoint
|
|
181
|
+
config: config
|
|
176
182
|
)
|
|
177
183
|
|
|
178
184
|
info_spinner.success(Helpers::I18n.t('Explanation') + ':')
|
|
@@ -180,13 +186,13 @@ module AiCli
|
|
|
180
186
|
explanation[:read_explanation].call(->(chunk) { print chunk })
|
|
181
187
|
puts ''
|
|
182
188
|
puts ''
|
|
183
|
-
puts pastel.dim('•')
|
|
184
189
|
end
|
|
185
190
|
|
|
186
|
-
run_or_revise_flow(script,
|
|
191
|
+
run_or_revise_flow(script, config, silent_mode)
|
|
187
192
|
end
|
|
188
193
|
|
|
189
194
|
private_class_method :init_i18n, :examples, :ask_prompt, :ask_revision,
|
|
190
|
-
:run_script, :run_or_revise_flow, :revision_flow
|
|
195
|
+
:run_script, :run_or_revise_flow, :revision_flow,
|
|
196
|
+
:append_prompt_context
|
|
191
197
|
end
|
|
192
198
|
end
|
data/lib/aicli/version.rb
CHANGED
data/lib/aicli.rb
CHANGED
|
@@ -7,8 +7,10 @@ require_relative 'aicli/helpers/i18n'
|
|
|
7
7
|
require_relative 'aicli/helpers/os_detect'
|
|
8
8
|
require_relative 'aicli/helpers/strip_regex_patterns'
|
|
9
9
|
require_relative 'aicli/helpers/shell_history'
|
|
10
|
+
require_relative 'aicli/helpers/llm'
|
|
10
11
|
require_relative 'aicli/helpers/completion'
|
|
11
12
|
require_relative 'aicli/helpers/config'
|
|
13
|
+
require_relative 'aicli/helpers/context'
|
|
12
14
|
require_relative 'aicli/prompt'
|
|
13
15
|
require_relative 'aicli/commands/chat'
|
|
14
16
|
require_relative 'aicli/commands/config'
|
data/locales/en.yml
CHANGED
|
@@ -8,14 +8,20 @@ Please set your OpenAI API key via `ai config set OPENAI_KEY=<your token>`: Plea
|
|
|
8
8
|
set your OpenAI API key via `ai config set OPENAI_KEY=<your token>`
|
|
9
9
|
Set config: Set config
|
|
10
10
|
Enter your OpenAI API key: Enter your OpenAI API key
|
|
11
|
+
Enter your Anthropic API key: Enter your Anthropic API key
|
|
11
12
|
"(not set)": "(not set)"
|
|
13
|
+
Provider: Provider
|
|
14
|
+
Pick a provider: Pick a provider
|
|
12
15
|
OpenAI Key: OpenAI Key
|
|
16
|
+
Anthropic Key: Anthropic Key
|
|
13
17
|
Please enter a key: Please enter a key
|
|
14
18
|
OpenAI API Endpoint: OpenAI API Endpoint
|
|
15
19
|
Enter your OpenAI API Endpoint: Enter your OpenAI API Endpoint
|
|
16
20
|
Silent Mode: Silent Mode
|
|
17
21
|
Enable silent mode?: Enable silent mode?
|
|
18
22
|
Model: Model
|
|
23
|
+
Pick a model.: Pick a model.
|
|
24
|
+
No models found for this provider.: No models found for this provider.
|
|
19
25
|
Enter the model you want to use: Enter the model you want to use
|
|
20
26
|
Language: Language
|
|
21
27
|
Enter the language you want to use: Enter the language you want to use
|
|
@@ -35,6 +41,7 @@ Loading...: Loading...
|
|
|
35
41
|
Getting explanation...: Getting explanation...
|
|
36
42
|
Explanation: Explanation
|
|
37
43
|
Run this script?: Run this script?
|
|
44
|
+
Run it?: Run it?
|
|
38
45
|
Revise this script?: Revise this script?
|
|
39
46
|
'Yes': 'Yes'
|
|
40
47
|
Lets go!: Lets go!
|
|
@@ -59,3 +66,6 @@ Please open a Bug report with the information above: Please open a Bug report wi
|
|
|
59
66
|
the information above
|
|
60
67
|
Prompt to run: Prompt to run
|
|
61
68
|
You: You
|
|
69
|
+
Ask for a shell command. Type exit to quit.: Ask for a shell command. Type exit to quit.
|
|
70
|
+
Restored context: Restored context
|
|
71
|
+
messages: messages
|
data/locales/it.yml
CHANGED
|
@@ -8,14 +8,20 @@ Please set your OpenAI API key via `ai config set OPENAI_KEY=<your token>`: Per
|
|
|
8
8
|
imposta la tua chiave API OpenAI tramite `ai config set OPENAI_KEY=<your token>`
|
|
9
9
|
Set config: Imposta la configurazione
|
|
10
10
|
Enter your OpenAI API key: Inserisci la tua chiave API OpenAI
|
|
11
|
+
Enter your Anthropic API key: Inserisci la tua chiave API Anthropic
|
|
11
12
|
"(not set)": "(non impostato)"
|
|
13
|
+
Provider: Provider
|
|
14
|
+
Pick a provider: Scegli un provider
|
|
12
15
|
OpenAI Key: Chiave OpenAI
|
|
16
|
+
Anthropic Key: Chiave Anthropic
|
|
13
17
|
Please enter a key: Per favore inserisci una chiave
|
|
14
18
|
OpenAI API Endpoint: Endpoint API OpenAI
|
|
15
19
|
Enter your OpenAI API Endpoint: Inserisci il tuo endpoint API OpenAI
|
|
16
20
|
Silent Mode: Modalità silenziosa
|
|
17
21
|
Enable silent mode?: Abilitare la modalità silenziosa?
|
|
18
22
|
Model: Modello
|
|
23
|
+
Pick a model.: Scegli un modello.
|
|
24
|
+
No models found for this provider.: Nessun modello trovato per questo provider.
|
|
19
25
|
Enter the model you want to use: Inserisci il modello che vuoi utilizzare
|
|
20
26
|
Language: Lingua
|
|
21
27
|
Enter the language you want to use: Inserisci la lingua che vuoi utilizzare
|
|
@@ -35,6 +41,7 @@ Loading...: Caricamento...
|
|
|
35
41
|
Getting explanation...: Ottieni spiegazione...
|
|
36
42
|
Explanation: Spiegazione
|
|
37
43
|
Run this script?: Esegui questo script?
|
|
44
|
+
Run it?: Lo eseguo?
|
|
38
45
|
Revise this script?: Rivedi questo script?
|
|
39
46
|
'Yes': Si
|
|
40
47
|
Lets go!: Vai!
|
|
@@ -58,3 +65,6 @@ Please open a Bug report with the information above: Apri un report di bug con l
|
|
|
58
65
|
informazioni sopra
|
|
59
66
|
Prompt to run: Prompt da eseguire
|
|
60
67
|
You: Tu
|
|
68
|
+
Ask for a shell command. Type exit to quit.: Chiedi un comando shell. Digita exit per uscire.
|
|
69
|
+
Restored context: Contesto ripristinato
|
|
70
|
+
messages: messaggi
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: aicli
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Antonio Molinari
|
|
@@ -37,6 +37,20 @@ dependencies:
|
|
|
37
37
|
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
39
|
version: '0.8'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: ruby_llm
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '1.16'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '1.16'
|
|
40
54
|
- !ruby/object:Gem::Dependency
|
|
41
55
|
name: thor
|
|
42
56
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -102,8 +116,10 @@ files:
|
|
|
102
116
|
- lib/aicli/helpers/completion.rb
|
|
103
117
|
- lib/aicli/helpers/config.rb
|
|
104
118
|
- lib/aicli/helpers/constants.rb
|
|
119
|
+
- lib/aicli/helpers/context.rb
|
|
105
120
|
- lib/aicli/helpers/error.rb
|
|
106
121
|
- lib/aicli/helpers/i18n.rb
|
|
122
|
+
- lib/aicli/helpers/llm.rb
|
|
107
123
|
- lib/aicli/helpers/os_detect.rb
|
|
108
124
|
- lib/aicli/helpers/shell_history.rb
|
|
109
125
|
- lib/aicli/helpers/strip_regex_patterns.rb
|