aia 0.8.2 → 0.8.4
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/.version +1 -1
- data/README.md +62 -47
- data/lib/aia/config.rb +37 -26
- data/lib/aia/directive_processor.rb +36 -17
- data/lib/aia/session.rb +14 -18
- data/lib/aia.rb +10 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8e3b68ad8d2e1a8fb2d1e8ad7f914f1660be948bd591027884fac746f22bc006
|
4
|
+
data.tar.gz: 9ca5aaadda10b6f09cc559140f2d79210e93ea9c1106a41c1309e93e8eafe670
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7a2002dbc191d05a8aa6c70f534049f049f8ed8721cacc6b93873f25a12deb256364ae324fd90971456a609ae0cb1cc899a5dc50a827175bc379a73c20614108
|
7
|
+
data.tar.gz: 3845d59a7f7a026f1cd60566cfc5eaf39658c7c49bc822e195c622d9e5799d2ebe76b52d26f2d1ece5093c22a7a811e6e19ab1985d8b13ad723260dcd329f47c
|
data/.version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.8.
|
1
|
+
0.8.4
|
data/README.md
CHANGED
@@ -34,48 +34,47 @@ AIA leverages the [prompt_manager gem](https://github.com/madbomber/prompt_manag
|
|
34
34
|
|
35
35
|
## Table of Contents
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
- [Configuration
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
- [
|
50
|
-
|
51
|
-
|
52
|
-
- [
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
- [
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
- [
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
- [License](#license)
|
37
|
+
- [Table of Contents](#table-of-contents)
|
38
|
+
- [Installation](#installation)
|
39
|
+
- [What is a Prompt ID?](#what-is-a-prompt-id)
|
40
|
+
- [Configuration Options](#configuration-options)
|
41
|
+
- [Configuration Flexibility](#configuration-flexibility)
|
42
|
+
- [Expandable Configuration](#expandable-configuration)
|
43
|
+
- [Shell Integration inside of a Prompt](#shell-integration-inside-of-a-prompt)
|
44
|
+
- [Dynamic Shell Commands](#dynamic-shell-commands)
|
45
|
+
- [Shell Command Safety](#shell-command-safety)
|
46
|
+
- [Chat Session Use](#chat-session-use)
|
47
|
+
- [*E*mbedded *R*u*B*y (ERB)](#embedded-ruby-erb)
|
48
|
+
- [Prompt Directives](#prompt-directives)
|
49
|
+
- [Parameter and Shell Substitution in Directives](#parameter-and-shell-substitution-in-directives)
|
50
|
+
- [Directive Syntax](#directive-syntax)
|
51
|
+
- [AIA Specific Directive Commands](#aia-specific-directive-commands)
|
52
|
+
- [//config](#config)
|
53
|
+
- [//include](#include)
|
54
|
+
- [//ruby](#ruby)
|
55
|
+
- [//shell](#shell)
|
56
|
+
- [//next](#next)
|
57
|
+
- [//pipeline](#pipeline)
|
58
|
+
- [Using Directives in Chat Sessions](#using-directives-in-chat-sessions)
|
59
|
+
- [Prompt Sequences](#prompt-sequences)
|
60
|
+
- [--next](#--next)
|
61
|
+
- [--pipeline](#--pipeline)
|
62
|
+
- [Best Practices ??](#best-practices-)
|
63
|
+
- [Example pipeline](#example-pipeline)
|
64
|
+
- [All About ROLES](#all-about-roles)
|
65
|
+
- [The --roles\_prefix (AIA\_ROLES\_PREFIX)](#the---roles_prefix-aia_roles_prefix)
|
66
|
+
- [The --role Option](#the---role-option)
|
67
|
+
- [Other Ways to Insert Roles into Prompts](#other-ways-to-insert-roles-into-prompts)
|
68
|
+
- [External CLI Tools Used](#external-cli-tools-used)
|
69
|
+
- [Shell Completion](#shell-completion)
|
70
|
+
- [My Most Powerful Prompt](#my-most-powerful-prompt)
|
71
|
+
- [My Configuration](#my-configuration)
|
72
|
+
- [Executable Prompts](#executable-prompts)
|
73
|
+
- [Development](#development)
|
74
|
+
- [Contributing](#contributing)
|
75
|
+
- [History of Development](#history-of-development)
|
76
|
+
- [Roadmap](#roadmap)
|
77
|
+
- [License](#license)
|
79
78
|
|
80
79
|
<!-- Tocer[finish]: Auto-generated, don't remove. -->
|
81
80
|
|
@@ -142,16 +141,32 @@ Tell me how to do something for a $(uname -s) platform that would rename all
|
|
142
141
|
of the files in the directory $MY_DIRECTORY to have a prefix of for its filename
|
143
142
|
that is [PREFIX] and a ${SUFFIX}
|
144
143
|
|
145
|
-
|
146
|
-
|
147
|
-
|
144
|
+
<!--
|
145
|
+
directives, ERB blocks and other junk can be used
|
146
|
+
anywhere in the file mixing dynamic context/instructions with
|
147
|
+
the static stuff.
|
148
|
+
-->
|
149
|
+
|
150
|
+
```markdown
|
151
|
+
# Header 1 -- not a comment
|
152
|
+
## Header 2 -- not a comment
|
153
|
+
### Header 3, etc -- not a comment
|
154
|
+
|
155
|
+
```ruby
|
156
|
+
# this is a comment; but it stays in the prompt
|
157
|
+
puts "hello world" <!-- this is also a comment; but it gets removed -->
|
158
|
+
```
|
159
|
+
Kewl!
|
160
|
+
```
|
148
161
|
|
149
162
|
__END__
|
150
163
|
|
151
|
-
|
152
|
-
the LLM.
|
164
|
+
Everything after the "__END__" line is not part of the context or instructions to
|
165
|
+
the LLM.
|
153
166
|
```
|
154
167
|
|
168
|
+
Comments in a prompt text file are just there to document the prompt. They are removed before the completed prompt is processed by the LLM. This reduces token counts; but, more importantly it helps you remember why you structured your prompt they way you did - if you remembered to document your prompt.
|
169
|
+
|
155
170
|
That is just about everything including the kitchen sink that a pre-compositional parameterized prompt file can have. It can be an executable with a she-bang line and a special system prompt name `run` as shown in the example. It has line comments that use the `#` symbol. It had end of file block comments that appear after the "__END__" line. It has directive command that begin with the double slash `//` - an homage to IBM JCL. It has shell variables in both forms. It has shell commands. It has parameters that default to a regex that uses square brackets and all uppercase characeters to define the parameter name whose value is to be given in a Q&A session before the prompt is sent to the LLM for processing.
|
156
171
|
|
157
172
|
AIA has the ability to define a workflow of prompt IDs with either the //next or //pipeline directives.
|
data/lib/aia/config.rb
CHANGED
@@ -10,15 +10,17 @@ require 'toml-rb'
|
|
10
10
|
require 'erb'
|
11
11
|
require 'optparse'
|
12
12
|
|
13
|
-
|
14
13
|
module AIA
|
15
14
|
class Config
|
16
|
-
DEFAULT_CONFIG = {
|
15
|
+
DEFAULT_CONFIG = OpenStruct.new({
|
17
16
|
aia_dir: File.join(ENV['HOME'], '.aia'),
|
18
17
|
config_file: File.join(ENV['HOME'], '.aia', 'config.yml'),
|
19
18
|
out_file: 'temp.md',
|
20
19
|
log_file: File.join(ENV['HOME'], '.prompts', '_prompts.log'),
|
21
20
|
prompts_dir: File.join(ENV['HOME'], '.prompts'),
|
21
|
+
#
|
22
|
+
prompt_extname: PromptManager::Storage::FileSystemAdapter::PROMPT_EXTENSION,
|
23
|
+
#
|
22
24
|
roles_prefix: 'roles',
|
23
25
|
roles_dir: File.join(ENV['HOME'], '.prompts', 'roles'),
|
24
26
|
role: '',
|
@@ -67,11 +69,10 @@ module AIA
|
|
67
69
|
|
68
70
|
# Ruby libraries to require for Ruby binding
|
69
71
|
require_libs: [],
|
70
|
-
}.freeze
|
71
|
-
|
72
|
+
}).freeze
|
72
73
|
|
73
74
|
def self.setup
|
74
|
-
default_config =
|
75
|
+
default_config = DEFAULT_CONFIG.dup
|
75
76
|
cli_config = cli_options
|
76
77
|
envar_config = envar_options(default_config, cli_config)
|
77
78
|
|
@@ -92,6 +93,35 @@ module AIA
|
|
92
93
|
|
93
94
|
|
94
95
|
def self.tailor_the_config(config)
|
96
|
+
remaining_args = config.remaining_args.dup
|
97
|
+
config.remaining_args = nil
|
98
|
+
|
99
|
+
# Is first remaining argument a prompt ID?
|
100
|
+
unless remaining_args.empty?
|
101
|
+
maybe_id = remaining_args.first
|
102
|
+
maybe_id_plus = File.join(config.prompts_dir, maybe_id + config.prompt_extname)
|
103
|
+
|
104
|
+
if AIA.bad_file?(maybe_id) && AIA.good_file?(maybe_id_plus)
|
105
|
+
config.prompt_id =remaining_args.shift
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
unless remaining_args.empty?
|
110
|
+
bad_files = remaining_args.reject { |filename| AIA.good_file?(filename) }
|
111
|
+
if bad_files.any?
|
112
|
+
STDERR.puts "Error: The following files do not exist: #{bad_files.join(', ')}"
|
113
|
+
exit 1
|
114
|
+
end
|
115
|
+
|
116
|
+
config.context_files = remaining_args
|
117
|
+
end
|
118
|
+
|
119
|
+
if config.prompt_id.nil? && !config.chat && !config.fuzzy
|
120
|
+
STDERR.puts "Error: A prompt ID is required unless using --chat, --fuzzy, or providing context files. Use -h or --help for help."
|
121
|
+
exit 1
|
122
|
+
end
|
123
|
+
|
124
|
+
|
95
125
|
unless config.role.empty?
|
96
126
|
unless config.roles_prefix.empty?
|
97
127
|
unless config.role.start_with?(config.roles_prefix)
|
@@ -151,7 +181,7 @@ module AIA
|
|
151
181
|
STDERR.puts "Error: A prompt ID is required unless using --chat, --fuzzy, or providing context files. Use -h or --help for help."
|
152
182
|
exit 1
|
153
183
|
end
|
154
|
-
|
184
|
+
|
155
185
|
# If we're in chat mode with context files but no prompt_id, that's valid
|
156
186
|
if config.chat && config.prompt_id.empty? && config.context_files && !config.context_files.empty?
|
157
187
|
# This is a valid use case - no action needed
|
@@ -391,32 +421,13 @@ module AIA
|
|
391
421
|
|
392
422
|
# Parse the command line arguments
|
393
423
|
begin
|
394
|
-
remaining_args = opt_parser.parse(args)
|
424
|
+
config.remaining_args = opt_parser.parse(args)
|
395
425
|
rescue OptionParser::InvalidOption => e
|
396
426
|
puts e.message
|
397
427
|
puts opt_parser
|
398
428
|
exit 1
|
399
429
|
end
|
400
430
|
|
401
|
-
# Handle remaining args
|
402
|
-
unless remaining_args.empty?
|
403
|
-
# If in chat mode and all args are existing files, treat them all as context files
|
404
|
-
if config.chat && remaining_args.all? { |arg| File.exist?(arg) }
|
405
|
-
config.context_files = remaining_args
|
406
|
-
# If first arg is empty string and we're in chat mode, treat all args as context files
|
407
|
-
elsif config.chat && remaining_args.first == ""
|
408
|
-
remaining_args.shift # Remove the empty string
|
409
|
-
config.context_files = remaining_args unless remaining_args.empty?
|
410
|
-
else
|
411
|
-
# First remaining arg is the prompt ID
|
412
|
-
config.prompt_id = remaining_args.shift
|
413
|
-
|
414
|
-
# Remaining args are context files
|
415
|
-
config.context_files = remaining_args unless remaining_args.empty?
|
416
|
-
end
|
417
|
-
end
|
418
|
-
|
419
|
-
|
420
431
|
config
|
421
432
|
end
|
422
433
|
|
@@ -63,7 +63,7 @@ module AIA
|
|
63
63
|
if EXCLUDED_METHODS.include?(method_name)
|
64
64
|
return "Error: #{method_name} is not a valid directive: #{key}"
|
65
65
|
elsif respond_to?(method_name, true)
|
66
|
-
return send(method_name, args)
|
66
|
+
return send(method_name, args, context_manager)
|
67
67
|
else
|
68
68
|
return "Error: Unknown directive '#{key}'"
|
69
69
|
end
|
@@ -125,8 +125,9 @@ module AIA
|
|
125
125
|
end
|
126
126
|
|
127
127
|
desc "Inserts the contents of a file Example: //include path/to/file"
|
128
|
-
def include(args)
|
129
|
-
|
128
|
+
def include(args, context_manager=nil)
|
129
|
+
# echo takes care of envars and tilde expansion
|
130
|
+
file_path = `echo #{args.shift}`.strip
|
130
131
|
|
131
132
|
if @included_files.include?(file_path)
|
132
133
|
""
|
@@ -143,7 +144,7 @@ module AIA
|
|
143
144
|
alias_method :import, :include
|
144
145
|
|
145
146
|
desc "Without arguments it will print a list of all config items and their values _or_ //config item (for one item's value) _or_ //config item = value (to set a value of an item)"
|
146
|
-
def config(args = [])
|
147
|
+
def config(args = [], context_manager=nil)
|
147
148
|
args = Array(args)
|
148
149
|
|
149
150
|
if args.empty?
|
@@ -171,33 +172,42 @@ module AIA
|
|
171
172
|
alias_method :cfg, :config
|
172
173
|
|
173
174
|
desc "Shortcut for //config top_p _and_ //config top_p = value"
|
174
|
-
def top_p(
|
175
|
-
send(:config, args.prepend('top_p'))
|
175
|
+
def top_p(args, context_manager=nil)
|
176
|
+
send(:config, args.prepend('top_p'), context_manager)
|
176
177
|
end
|
177
178
|
alias_method :topp, :top_p
|
178
179
|
|
180
|
+
desc "Review the current context"
|
181
|
+
def review(args, context_manager=nil)
|
182
|
+
ap context_manager.get_context
|
183
|
+
''
|
184
|
+
end
|
185
|
+
alias_method :context, :review
|
186
|
+
|
179
187
|
desc "Shortcut for //config model _and_ //config model = value"
|
180
|
-
def model(
|
181
|
-
send(:config, args.prepend('model'))
|
188
|
+
def model(args, context_manager=nil)
|
189
|
+
send(:config, args.prepend('model'), context_manager)
|
182
190
|
end
|
183
191
|
|
184
192
|
desc "Shortcut for //config temperature _and_ //config temperature = value"
|
185
|
-
def temperature(
|
186
|
-
send(:config, args.prepend('temperature'))
|
193
|
+
def temperature(args, context_manager=nil)
|
194
|
+
send(:config, args.prepend('temperature'), context_manager)
|
187
195
|
end
|
188
196
|
alias_method :temp, :temperature
|
189
197
|
|
190
198
|
desc "Clears the conversation history (aka context) same as //config clear = true"
|
191
|
-
def clear(args, context_manager)
|
199
|
+
def clear(args, context_manager=nil)
|
192
200
|
if context_manager.nil?
|
193
201
|
return "Error: Context manager not available for //clear directive."
|
194
202
|
end
|
203
|
+
|
195
204
|
context_manager.clear_context
|
196
|
-
|
205
|
+
|
206
|
+
''
|
197
207
|
end
|
198
208
|
|
199
209
|
desc "Shortcut for a one line of ruby code; result is added to the context"
|
200
|
-
def ruby(
|
210
|
+
def ruby(args, context_manager=nil)
|
201
211
|
ruby_code = args.join(' ')
|
202
212
|
|
203
213
|
begin
|
@@ -211,25 +221,34 @@ module AIA
|
|
211
221
|
end
|
212
222
|
alias_method :rb, :ruby
|
213
223
|
|
224
|
+
|
225
|
+
desc "Executes one line of shell code; result is added to the context"
|
226
|
+
def shell(args, context_manager=nil)
|
227
|
+
shell_code = args.join(' ')
|
228
|
+
|
229
|
+
`#{shell_code}`
|
230
|
+
end
|
231
|
+
alias_method :sh, :shell
|
232
|
+
|
214
233
|
desc "Use the system's say command to speak text //say some text"
|
215
|
-
def say(
|
234
|
+
def say(args, context_manager=nil)
|
216
235
|
`say #{args.join(' ')}`
|
217
236
|
""
|
218
237
|
end
|
219
238
|
|
220
239
|
desc "Inserts an instruction to keep responses short and to the point."
|
221
|
-
def terse(
|
240
|
+
def terse(args, context_manager=nil)
|
222
241
|
AIA::Session::TERSE_PROMPT
|
223
242
|
end
|
224
243
|
|
225
244
|
desc "Display the ASCII art AIA robot."
|
226
|
-
def robot(
|
245
|
+
def robot(args, context_manager=nil)
|
227
246
|
AIA::Utility.robot
|
228
247
|
""
|
229
248
|
end
|
230
249
|
|
231
250
|
desc "Generates this help content"
|
232
|
-
def help(
|
251
|
+
def help(args=nil, context_manager=nil)
|
233
252
|
puts
|
234
253
|
puts "Available Directives"
|
235
254
|
puts "===================="
|
data/lib/aia/session.rb
CHANGED
@@ -158,55 +158,55 @@ module AIA
|
|
158
158
|
@ui_presenter.display_chat_header
|
159
159
|
|
160
160
|
Reline::HISTORY.clear # Keep Reline history for user input editing, separate from chat context
|
161
|
-
|
161
|
+
|
162
162
|
# Load context files if any and not skipping
|
163
163
|
if !skip_context_files && AIA.config.context_files && !AIA.config.context_files.empty?
|
164
164
|
context_content = AIA.config.context_files.map do |file|
|
165
165
|
File.read(file) rescue "Error reading file: #{file}"
|
166
166
|
end.join("\n\n")
|
167
|
-
|
167
|
+
|
168
168
|
if !context_content.empty?
|
169
169
|
# Add context files content to context
|
170
170
|
@context_manager.add_to_context(role: 'user', content: context_content)
|
171
|
-
|
171
|
+
|
172
172
|
# Process the context
|
173
173
|
operation_type = @chat_processor.determine_operation_type(AIA.config.model)
|
174
174
|
@ui_presenter.display_thinking_animation
|
175
175
|
response = @chat_processor.process_prompt(@context_manager.get_context, operation_type)
|
176
|
-
|
176
|
+
|
177
177
|
# Add AI response to context
|
178
178
|
@context_manager.add_to_context(role: 'assistant', content: response)
|
179
|
-
|
179
|
+
|
180
180
|
# Output the response
|
181
181
|
@chat_processor.output_response(response)
|
182
182
|
@chat_processor.speak(response)
|
183
183
|
@ui_presenter.display_separator
|
184
184
|
end
|
185
185
|
end
|
186
|
-
|
186
|
+
|
187
187
|
# Check for piped input (STDIN not a TTY and has data)
|
188
188
|
if !STDIN.tty?
|
189
189
|
# Save the original STDIN
|
190
190
|
orig_stdin = STDIN.dup
|
191
|
-
|
191
|
+
|
192
192
|
# Read the piped input
|
193
193
|
piped_input = STDIN.read.strip
|
194
|
-
|
194
|
+
|
195
195
|
# Reopen STDIN to the terminal
|
196
196
|
STDIN.reopen('/dev/tty')
|
197
|
-
|
197
|
+
|
198
198
|
if !piped_input.empty?
|
199
199
|
# Add piped input to context
|
200
200
|
@context_manager.add_to_context(role: 'user', content: piped_input)
|
201
|
-
|
201
|
+
|
202
202
|
# Process the piped input
|
203
203
|
operation_type = @chat_processor.determine_operation_type(AIA.config.model)
|
204
204
|
@ui_presenter.display_thinking_animation
|
205
205
|
response = @chat_processor.process_prompt(@context_manager.get_context, operation_type)
|
206
|
-
|
206
|
+
|
207
207
|
# Add AI response to context
|
208
208
|
@context_manager.add_to_context(role: 'assistant', content: response)
|
209
|
-
|
209
|
+
|
210
210
|
# Output the response
|
211
211
|
@chat_processor.output_response(response)
|
212
212
|
@chat_processor.speak(response)
|
@@ -217,7 +217,7 @@ module AIA
|
|
217
217
|
loop do
|
218
218
|
# Get user input
|
219
219
|
prompt = @ui_presenter.ask_question
|
220
|
-
|
220
|
+
|
221
221
|
|
222
222
|
|
223
223
|
break if prompt.nil? || prompt.strip.downcase == 'exit' || prompt.strip.empty?
|
@@ -232,7 +232,7 @@ module AIA
|
|
232
232
|
directive_output = @directive_processor.process(prompt, @context_manager) # Pass context_manager
|
233
233
|
|
234
234
|
# Add check for specific directives like //clear that might modify context
|
235
|
-
if prompt.strip.start_with?('//clear'
|
235
|
+
if prompt.strip.start_with?('//clear')
|
236
236
|
# Context is likely cleared within directive_processor.process now
|
237
237
|
# or add @context_manager.clear_context here if not handled internally
|
238
238
|
@ui_presenter.display_info("Chat context cleared.")
|
@@ -256,10 +256,6 @@ module AIA
|
|
256
256
|
# Use ContextManager to get the conversation
|
257
257
|
conversation = @context_manager.get_context # System prompt handled internally
|
258
258
|
|
259
|
-
# FIXME: remove this comment once verified
|
260
|
-
# is conversation the same thing as the context for a chat session? YES
|
261
|
-
# if so need to somehow delete it when the //clear directive is entered. - Addressed above/in DirectiveProcessor
|
262
|
-
|
263
259
|
operation_type = @chat_processor.determine_operation_type(AIA.config.model)
|
264
260
|
@ui_presenter.display_thinking_animation
|
265
261
|
response = @chat_processor.process_prompt(conversation, operation_type)
|
data/lib/aia.rb
CHANGED
@@ -45,6 +45,16 @@ module AIA
|
|
45
45
|
@config.client = client
|
46
46
|
end
|
47
47
|
|
48
|
+
def self.good_file?(filename)
|
49
|
+
File.exist?(filename) &&
|
50
|
+
File.readable?(filename) &&
|
51
|
+
!File.directory?(filename)
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.bad_file?(filename)
|
55
|
+
!good_file?(filename)
|
56
|
+
end
|
57
|
+
|
48
58
|
def self.build_flags
|
49
59
|
@config.each_pair do |key, value|
|
50
60
|
if [TrueClass, FalseClass].include?(value.class)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aia
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dewayne VanHoozer
|
@@ -57,14 +57,14 @@ dependencies:
|
|
57
57
|
requirements:
|
58
58
|
- - ">="
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: 0.
|
60
|
+
version: 0.5.2
|
61
61
|
type: :runtime
|
62
62
|
prerelease: false
|
63
63
|
version_requirements: !ruby/object:Gem::Requirement
|
64
64
|
requirements:
|
65
65
|
- - ">="
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version: 0.
|
67
|
+
version: 0.5.2
|
68
68
|
- !ruby/object:Gem::Dependency
|
69
69
|
name: reline
|
70
70
|
requirement: !ruby/object:Gem::Requirement
|