aia 0.3.19 → 0.3.20

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 505546a036010eb8b0360f7fbfbb4c6494c311e98969c8095fa091882815aac2
4
- data.tar.gz: 6f9323e50879c3b51a5ead99c29b1b41fc377dc1957283edb13e03bb30c866db
3
+ metadata.gz: b3061141e7330122b3ec6ffd64cf967d8fb0c4f8741531337bf32bfba28ee4ea
4
+ data.tar.gz: b62080a48b5d4afefb9da0eb5bdc1deff20a8c666048a755b38f759815bea8f3
5
5
  SHA512:
6
- metadata.gz: 23926f77a010a023fd1fbbde152f83cfacd75f003bb2e060d4e2b4ca0cd7aecac6631b0520c5e3c6d56cbde31914f158f520f15bfa239a1a72bf682c5ea79032
7
- data.tar.gz: 9d76ab35f70a13a4320d9fb4ee5f3fd47e4039c95e99fc02ce858977e179d1891d44fb08cf7cfc17975e6828dbe28d01d9d778d949c371e898e847e7fa865020
6
+ metadata.gz: c2e83d7db907fe2e3c91aae7acad12bf1569071479f99ba70f3626c98640323148e83b46cda2aa2353afcad54d740116999399e8e646b7db02b4a7e42916d0fc
7
+ data.tar.gz: 3f327c042a67a574231d9e25a5ed8df83ca6d4cf28444ae92be20d241480143ce95ec4e4238aab70caecf0c9c64417d579c6e8fd3dd3e7928c64f8e56fb2196a
data/.semver CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  :major: 0
3
3
  :minor: 3
4
- :patch: 19
4
+ :patch: 20
5
5
  :special: ''
6
6
  :metadata: ''
data/CHANGELOG.md CHANGED
@@ -1,4 +1,8 @@
1
1
  ## [Unreleased]
2
+ ## [0.3.20] 2023-12-28
3
+ - added work around to issue with multiple context files going to the `mods` backend
4
+ - added shellwords gem to santize prompt text on the command line
5
+
2
6
  ## [0.3.19] 2023-12-26
3
7
  - major code refactoring.
4
8
  - supports config files \*.yml, \*.yaml and \*.toml
data/lib/aia/main.rb CHANGED
@@ -20,9 +20,10 @@ class AIA::Main
20
20
  AIA::Cli.new(args)
21
21
 
22
22
  @logger = AIA::Logging.new(AIA.config.log_file)
23
- @tools = AIA::Tools.new
23
+ AIA::Tools.load_tools
24
24
 
25
- tools.class.verify_tools
25
+ # TODO: still should verify that the tools are ion the $PATH
26
+ # tools.class.verify_tools
26
27
  end
27
28
 
28
29
 
@@ -37,14 +38,30 @@ class AIA::Main
37
38
  # prompt keyword or process the prompt. Do not
38
39
  # want invalid files to make it this far.
39
40
 
41
+ found = AIA::Tools
42
+ .search_for(
43
+ name: AIA.config.backend,
44
+ role: :backend
45
+ )
46
+
47
+ if found.empty?
48
+ abort "There are no :backend tools named #{AIA.config.backend}"
49
+ end
50
+
51
+ if found.size > 1
52
+ abort "There are #{found.size} :backend tools with the name #{AIAA.config.backend}"
53
+ end
54
+
55
+ backend_klass = found.first.klass
56
+
57
+ abort "backend not found: #{AIA.config.backend}" if backend_klass.nil?
40
58
 
41
- mods = AIA::Mods.new(
42
- extra_options: AIA.config.extra,
59
+ backend = backend_klass.new(
43
60
  text: @prompt.to_s,
44
61
  files: AIA.config.arguments # FIXME: want validated context files
45
62
  )
46
63
 
47
- result = mods.run
64
+ result = backend.run
48
65
 
49
66
  AIA.config.output_file.write result
50
67
 
@@ -4,19 +4,21 @@
4
4
 
5
5
 
6
6
  class AIA::Editor < AIA::Tools
7
+
8
+ meta(
9
+ name: 'editor',
10
+ role: :editor,
11
+ desc: "Your default system $EDITOR",
12
+ url: "unknown",
13
+ install: "should already be installed",
14
+ )
15
+
7
16
  DEFAULT_PARAMETERS = ""
8
17
 
9
18
  attr_accessor :command
10
19
 
11
20
 
12
- def initialize(file: "")
13
- super
14
-
15
- @role = :editor
16
- @description = "Your default system $EDITOR"
17
- @url = "unknown"
18
- @install = "should already be installed"
19
-
21
+ def initialize(file: "")
20
22
  @file = file
21
23
 
22
24
  discover_editor
@@ -39,7 +41,7 @@ class AIA::Editor < AIA::Tools
39
41
 
40
42
 
41
43
  def build_command
42
- @command = "#{name} #{DEFAULT_PARAMETERS} #{@file}"
44
+ @command = "#{meta.name} #{DEFAULT_PARAMETERS} #{@file}"
43
45
  end
44
46
 
45
47
 
@@ -1,29 +1,28 @@
1
1
  # lib/aia/tools/mods.rb
2
2
 
3
3
  class AIA::Mods < AIA::Tools
4
+
5
+ meta(
6
+ name: 'mods',
7
+ role: :backend,
8
+ desc: 'AI on the command-line',
9
+ url: 'https://github.com/charmbracelet/mods',
10
+ install: 'brew install mods',
11
+ )
12
+
13
+
4
14
  DEFAULT_PARAMETERS = [
5
15
  "--no-limit" # no limit on input context
6
16
  ].join(' ').freeze
7
17
 
8
- attr_accessor :command, :extra_options, :text, :files
9
-
10
- # TODO: put the prompt text to be resolved into a
11
- # temporary text file then cat that file into mods.
12
- # This will keep from polluting the CLI history with
13
- # lots of text
18
+ attr_accessor :command, :text, :files
14
19
 
15
20
 
16
21
  def initialize(
17
- extra_options: "", # everything after -- on command line
18
22
  text: "", # prompt text after keyword replacement
19
23
  files: [] # context file paths (Array of Pathname)
20
24
  )
21
- super
22
- @role = :gen_ai
23
- @description = 'AI on the command-line'
24
- @url = 'https://github.com/charmbracelet/mods'
25
-
26
- @extra_options = extra_options
25
+
27
26
  @text = text
28
27
  @files = files
29
28
 
@@ -31,46 +30,84 @@ class AIA::Mods < AIA::Tools
31
30
  end
32
31
 
33
32
 
33
+ def sanitize(input)
34
+ Shellwords.escape(input)
35
+ end
36
+
37
+
34
38
  def build_command
35
39
  parameters = DEFAULT_PARAMETERS.dup + " "
36
- parameters += "-f " if ::AIA.config.markdown?
37
- parameters += "-m #{AIA.config.model} " if ::AIA.config.model
38
- parameters += @extra_options
40
+ parameters += "-f " if AIA.config.markdown?
41
+ parameters += "-m #{AIA.config.model} " if AIA.config.model
42
+ parameters += AIA.config.extra
39
43
  @command = "mods #{parameters} "
40
- @command += %Q["#{@text}"] # TODO: consider using the pipeline
41
-
42
- @files.each {|f| @command += " < #{f}" }
44
+ @command += sanitize(@text)
45
+
46
+ # context = @files.join(' ')
47
+ #
48
+ # unless context.empty?
49
+ # if @files.size > 1
50
+ # # FIXME: This syntax breaks mods which does not know how
51
+ # # to read the temporary file descriptor created
52
+ # # by the shell
53
+ # @command += " <(cat #{context})"
54
+ # else
55
+ # @command += " < #{context}"
56
+ # end
57
+ # end
43
58
 
44
59
  @command
45
60
  end
46
61
 
47
62
 
48
63
  def run
49
- `#{command}`
64
+ case @files.size
65
+ when 0
66
+ @result = `#{build_command}`
67
+ when 1
68
+ @result = `#{build_command} < #{@files.first}`
69
+ else
70
+ create_temp_file_with_contexts
71
+ run_mods_with_temp_file
72
+ clean_up_temp_file
73
+ end
74
+
75
+ @result
50
76
  end
51
- end
52
-
53
- __END__
54
-
77
+
78
+
79
+ # Create a temporary file that concatenates all contexts,
80
+ # to be used as STDIN for the 'mods' utility
81
+ def create_temp_file_with_contexts
82
+ @temp_file = Tempfile.new('mods-context')
83
+
84
+ @files.each do |file|
85
+ content = File.read(file)
86
+ @temp_file.write(content)
87
+ @temp_file.write("\n")
88
+ end
55
89
 
56
- # Execute the command and log the results
57
- def send_prompt_to_external_command
58
- command = build_command
90
+ @temp_file.close
91
+ end
92
+
59
93
 
60
- puts command if verbose?
94
+ # Run 'mods' with the temporary file as STDIN
95
+ def run_mods_with_temp_file
96
+ command = "#{build_command} < #{@temp_file.path}"
61
97
  @result = `#{command}`
98
+ end
99
+
62
100
 
63
- if @output.nil?
64
- puts @result
65
- else
66
- @output.write @result
67
- end
68
-
69
- @result
101
+ # Clean up the temporary file after use
102
+ def clean_up_temp_file
103
+ @temp_file.unlink if @temp_file
70
104
  end
105
+ end
71
106
 
107
+ __END__
72
108
 
73
109
 
110
+
74
111
 
75
112
 
76
113
  ##########################################################
@@ -1,12 +1,17 @@
1
1
  # lib/aia/tools/sgpt.rb
2
2
 
3
3
  class AIA::Sgpt < AIA::Tools
4
+
5
+ meta(
6
+ name: 'sgpt',
7
+ role: :backend,
8
+ desc: "shell-gpt",
9
+ url: "https://github.com/TheR1D/shell_gpt",
10
+ install: "pip install shell-gpt",
11
+ )
12
+
4
13
  def initialize
5
- super
6
- @role = :backend
7
- @desc = "shell-gpt"
8
- @url = "https://github.com/TheR1D/shell_gpt"
9
- @install = "pip install shell-gpt"
14
+ # TODO: something
10
15
  end
11
16
  end
12
17
 
@@ -1,6 +1,16 @@
1
1
  # lib/aia/tools/subl.rb
2
2
 
3
3
  class AIA::Subl < AIA::Tools
4
+
5
+ meta(
6
+ name: 'subl',
7
+ role: :editor,
8
+ desc: "Sublime Text Editor",
9
+ url: "https://www.sublimetext.com/",
10
+ install: "echo 'Download from website'",
11
+ )
12
+
13
+
4
14
  DEFAULT_PARAMETERS = [
5
15
  "--new-window", # Open a new window
6
16
  "--wait", # Wait for the files to be closed before returning
@@ -10,13 +20,6 @@ class AIA::Subl < AIA::Tools
10
20
 
11
21
 
12
22
  def initialize(file: "")
13
- super
14
-
15
- @role = :editor
16
- @desc = "Sublime Text Editor"
17
- @url = "https://www.sublimetext.com/"
18
- @install = "echo 'Download from website'"
19
-
20
23
  @file = file
21
24
 
22
25
  build_command
@@ -24,7 +27,7 @@ class AIA::Subl < AIA::Tools
24
27
 
25
28
 
26
29
  def build_command
27
- @command = "#{name} #{DEFAULT_PARAMETERS} #{@file}"
30
+ @command = "#{meta.name} #{DEFAULT_PARAMETERS} #{@file}"
28
31
  end
29
32
 
30
33
 
@@ -0,0 +1,97 @@
1
+ # lib/aia/tools.rb
2
+
3
+ ```ruby
4
+ require 'hashie'
5
+
6
+ module AIA
7
+ class Tools
8
+ @subclasses = {}
9
+
10
+ class << self
11
+ attr_reader :subclasses, :metadata
12
+
13
+ def inherited(subclass)
14
+ @subclasses[subclass.name.split('::').last.downcase] = subclass
15
+ subclass.instance_variable_set(:@metadata, Jashie::Mash.new)
16
+ end
17
+
18
+ def meta
19
+ @metadata ||= Jashie::Mash.new
20
+ end
21
+
22
+ def define_metadata(&block)
23
+ meta.instance_eval(&block)
24
+ end
25
+
26
+ def search_for(name: nil, role: nil)
27
+ return subclasses[name.downcase] if name
28
+ return subclasses.values.select { |subclass| subclass.meta.role == role } if role
29
+ end
30
+ end
31
+
32
+ def self.method_missing(name, *args, &block)
33
+ @metadata.public_send(name, *args, &block)
34
+ end
35
+
36
+ def self.respond_to_missing?(method_name, include_private = false)
37
+ @metadata.respond_to?(method_name) || super
38
+ end
39
+ end
40
+ end
41
+ ```
42
+
43
+ # lib/aia/tools/mods.rb
44
+
45
+ ```ruby
46
+ require_relative 'tools'
47
+
48
+ module AIA
49
+ class Mods < Tools
50
+ DEFAULT_PARAMETERS = "--no-limit".freeze
51
+
52
+ attr_accessor :command, :extra_options, :text, :files
53
+
54
+ define_metadata do
55
+ role :backend
56
+ desc 'AI on the command-line'
57
+ url 'https://github.com/charmbracelet/mods'
58
+ end
59
+
60
+ def initialize(extra_options: "", text: "", files: [])
61
+ @extra_options = extra_options
62
+ @text = text
63
+ @files = files
64
+ build_command
65
+ end
66
+
67
+ def build_command
68
+ parameters = DEFAULT_PARAMETERS.dup + " "
69
+ parameters += "-f " if ::AIA.config.markdown?
70
+ parameters += "-m #{AIA.config.model} " if ::AIA.config.model
71
+ parameters += @extra_options
72
+ @command = "mods #{parameters}"
73
+ @command += %Q["#{@text}"]
74
+
75
+ @files.each { |f| @command += " < #{f}" }
76
+
77
+ @command
78
+ end
79
+
80
+ def run
81
+ `#{@command}`
82
+ end
83
+ end
84
+ end
85
+ ```
86
+
87
+ ```ruby
88
+ # Example usage:
89
+ # mods_class = AIA::Tools.search_for(name: 'mods')
90
+ # mods_instance = mods_class.new(text: "Hello, mods!")
91
+ # result = mods_instance.run
92
+
93
+ # backend_tools = AIA::Tools.search_for(role: :backend)
94
+ ```
95
+
96
+ Note: The `Jashie::Mash` class is assumed to behave like `Hashie::Mash` (or similar) in providing a flexible object for storing metadata. You'll need to define `Jashie::Mash` or import a library that provides a similar functionality to match this example.
97
+
data/lib/aia/tools/vim.rb CHANGED
@@ -1,6 +1,15 @@
1
1
  # lib/aia/tools/vim.rb
2
2
 
3
3
  class AIA::Vim < AIA::Tools
4
+
5
+ meta(
6
+ name: 'vim',
7
+ role: :editor,
8
+ desc: "Vi IMproved (VIM)",
9
+ url: "https://www.vim.org",
10
+ install: "brew install vim",
11
+ )
12
+
4
13
  DEFAULT_PARAMETERS = [
5
14
  " ", # no parameters
6
15
  ].join(' ')
@@ -9,13 +18,6 @@ class AIA::Vim < AIA::Tools
9
18
 
10
19
 
11
20
  def initialize(file: "")
12
- super
13
-
14
- @role = :editor
15
- @description = "Vi IMproved (VIM)"
16
- @url = "https://www.vim.org"
17
- @install = "brew install vim"
18
-
19
21
  @file = file
20
22
 
21
23
  build_command
@@ -23,7 +25,7 @@ class AIA::Vim < AIA::Tools
23
25
 
24
26
 
25
27
  def build_command
26
- @command = "#{name} #{DEFAULT_PARAMETERS} #{@file}"
28
+ @command = "#{meta.name} #{DEFAULT_PARAMETERS} #{@file}"
27
29
  end
28
30
 
29
31
 
data/lib/aia/tools.rb CHANGED
@@ -1,77 +1,50 @@
1
1
  # lib/aia/tools.rb
2
2
 
3
- class AIA::Tools
4
- @@subclasses = []
5
-
6
- def self.inherited(subclass)
7
- @@subclasses << subclass
8
- end
3
+ require 'hashie'
9
4
 
10
- attr_accessor :role, :name, :description, :url, :install
11
-
12
-
13
- def initialize(*)
14
- @role = :role
15
- @name = self.class.name.split('::').last.downcase
16
- @description = "description"
17
- @url = "URL"
18
- @install = "brew install #{name}"
19
- end
5
+ class AIA::Tools
6
+ @@catalog = []
20
7
 
8
+ class << self
9
+ def inherited(subclass)
10
+ subclass_meta = Hashie::Mash.new(klass: subclass)
11
+ subclass.instance_variable_set(:@_metadata, subclass_meta)
21
12
 
22
- def installed?
23
- path = `which #{name}`.chomp
24
- !path.empty? && File.executable?(path)
25
- end
13
+ @@catalog << subclass_meta
14
+ end
26
15
 
27
16
 
28
- def help
29
- `#{name} --help`
30
- end
31
-
17
+ def meta(metadata = nil)
18
+ return @_metadata if metadata.nil?
32
19
 
33
- def version
34
- `#{name} --version`
35
- end
20
+ @_metadata = Hashie::Mash.new(metadata)
21
+ entry = @@catalog.detect { |item| item[:klass] == self }
22
+
23
+ entry.merge!(metadata) if entry
24
+ end
36
25
 
37
26
 
38
- #########################################
39
- class << self
40
- def tools
41
- @@subclasses.map(&:name)
27
+ def get_meta
28
+ @_metadata
42
29
  end
43
30
 
44
31
 
45
- def verify_tools
46
- missing_tools = @@subclasses.map(&:new).reject(&:installed?)
47
- unless missing_tools.empty?
48
- puts format_missing_tools_response(missing_tools)
32
+ def search_for(criteria = {})
33
+ @@catalog.select do |meta|
34
+ criteria.all? { |k, v| meta[k] == v }
49
35
  end
50
36
  end
51
37
 
52
38
 
53
- def format_missing_tools_response(missing_tools)
54
- response = <<~EOS
55
-
56
- WARNING: AIA makes use of external CLI tools that are missing.
57
-
58
- Please install the following tools:
39
+ def catalog
40
+ @@catalog
41
+ end
59
42
 
60
- EOS
61
43
 
62
- missing_tools.each do |tool|
63
- response << " #{tool.name}: install from #{tool.url}\n"
44
+ def load_tools
45
+ Dir.glob(File.join(File.dirname(__FILE__), 'tools', '*.rb')).each do |file|
46
+ require file
64
47
  end
65
-
66
- response
67
48
  end
68
49
  end
69
50
  end
70
-
71
-
72
- (Pathname.new(__dir__)+"tools")
73
- .glob('*.rb')
74
- .each do |tool|
75
- require_relative "tools/#{tool.basename.to_s}"
76
- end
77
-
data/lib/aia.rb CHANGED
@@ -6,6 +6,7 @@ include DebugMe
6
6
  require 'hashie'
7
7
  require 'pathname'
8
8
  require 'readline'
9
+ require 'shellwords'
9
10
  require 'tempfile'
10
11
 
11
12
  require 'prompt_manager'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aia
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.19
4
+ version: 0.3.20
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dewayne VanHoozer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-12-26 00:00:00.000000000 Z
11
+ date: 2023-12-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hashie
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: shellwords
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: toml-rb
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -172,6 +186,7 @@ files:
172
186
  - lib/aia/tools/mods.rb
173
187
  - lib/aia/tools/sgpt.rb
174
188
  - lib/aia/tools/subl.rb
189
+ - lib/aia/tools/temp.md
175
190
  - lib/aia/tools/vim.rb
176
191
  - lib/aia/version.rb
177
192
  - lib/core_ext/string_wrap.rb