appydave-tools 0.10.4 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40337ac9a46d2a5d2b7a645b14e572f011c84b52e958ba880be666d6dfe3413b
4
- data.tar.gz: 4e4e4bd076cae97a6cdec63dd70313f49efcbb19fb6295ffd1ef297dbbf08e42
3
+ metadata.gz: 88fcb99717ec45c2efcd0884772e1325a7de9cdca64c58c7e54e8c91203b333d
4
+ data.tar.gz: d29c8848556ef6c8a189fb3db0b6ad546a0e112d3dc5abffadf3f8e3bbaf058b
5
5
  SHA512:
6
- metadata.gz: 86448501dd1959eb0173ed98af2dead6965b56bf9cfcdc5007d335b73ecd94f8bb7e5cda9f099997285509e93f7ecff1368740fbe38c16c5e4240b1578462116
7
- data.tar.gz: 9e32acedc6fbc3b7e21123a56f068e7c91a6b6b4cc58a7315102a08b9455950f531755c5d1405b66dd52a9df60132aab08395877f771d8b096bb364aa6e83e7e
6
+ metadata.gz: a1d033506927b381145b9cd57400e4b6ced89bfee1aeee9bbcf7977b9015bfebfc3116b1d86e1e8de8a185b46180754dabb7bf24b1d4c589e6887fef1db054a8
7
+ data.tar.gz: abedf296c032a813c0e1abb2bad7eb00b4d4f32c2ee19eda9623648a8a489f6085307f4dbb9763f526d03d86714314d1f613b6c62f848a80ed2c409b64cef5f1
data/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ ## [0.10.4](https://github.com/klueless-io/appydave-tools/compare/v0.10.3...v0.10.4) (2024-10-09)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * cleanup code base before building documenation ([e473c44](https://github.com/klueless-io/appydave-tools/commit/e473c44546d8f0f5a35461fae263c348e7e2c58f))
7
+ * cleanup code base before building documenation ([38d8fb4](https://github.com/klueless-io/appydave-tools/commit/38d8fb46929e7c055308aa0b918c18a56fcd5842))
8
+ * cleanup code base before building documenation ([8dad12a](https://github.com/klueless-io/appydave-tools/commit/8dad12aadb9952f0174df45caed91c9e96070294))
9
+ * cleanup code base before building documenation ([eddfcc7](https://github.com/klueless-io/appydave-tools/commit/eddfcc78e39c93bfd4de6482690cc66cf90cc54a))
10
+ * extend prompt tools ([a628d08](https://github.com/klueless-io/appydave-tools/commit/a628d08fcdda521b7d148f0bab3261b879fca07d))
11
+ * extending bank reconciliation ([b435a20](https://github.com/klueless-io/appydave-tools/commit/b435a20237ef40a8a7d0a4f365ccd3eafdfcce1a))
12
+ * extending bank reconciliation ([b7878df](https://github.com/klueless-io/appydave-tools/commit/b7878dff0bca4ff1a3af7db19c280a8c245b6c3b))
13
+
1
14
  ## [0.10.3](https://github.com/klueless-io/appydave-tools/compare/v0.10.2...v0.10.3) (2024-06-17)
2
15
 
3
16
 
data/a.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "tree": {
3
+ "bin": {
4
+ "gpt_context.rb": {
5
+ }
6
+ },
7
+ "lib": {
8
+ "appydave": {
9
+ "tools": {
10
+ "gpt_context": {
11
+ "file_collector.rb": {
12
+ },
13
+ "options.rb": {
14
+ },
15
+ "output_handler.rb": {
16
+ }
17
+ }
18
+ }
19
+ }
20
+ },
21
+ "spec": {
22
+ "appydave": {
23
+ "tools": {
24
+ "gpt_context": {
25
+ "file_collector_spec.rb": {
26
+ },
27
+ "output_handler_spec.rb": {
28
+ }
29
+ }
30
+ }
31
+ }
32
+ }
33
+ },
34
+ "content": [
35
+ {
36
+ "file": "bin/gpt_context.rb",
37
+ "content": "#!/usr/bin/env ruby\n# frozen_string_literal: true\n\n# GPT Chats:\n# https://chatgpt.com/c/670df475-04f4-8002-a758-f5711bf433eb\n\n# Usage:\n# ./bin/gpt_context.rb -d -i 'lib/openai_101/tools/**/*.rb'\n# ./bin/gpt_context.rb -d -i 'lib/openai_101/tools/**/*' -e 'node_modules/**/*' -e 'package-lock.json' -e 'lib/openai_101/tools/prompts/*.txt'\n#\n# Get GPT Context Gatherer code\n# ./bin/gpt_context.rb -i 'bin/**/*gather*.rb' -i 'lib/openai_101/tools/**/*gather*.rb'\n$LOAD_PATH.unshift(File.expand_path('../lib', __dir__))\n\nrequire 'appydave/tools'\nrequire 'appydave/tools/gpt_context/options'\nrequire 'json'\nrequire 'optparse'\nrequire 'clipboard'\nrequire 'pathname'\n\noptions = Appydave::Tools::GptContext::Options.new(\n working_directory: nil\n)\n\nOptionParser.new do |opts|\n opts.banner = 'Usage: gather_content.rb [options]'\n\n opts.on('-i', '--include PATTERN', 'Pattern or file to include (can be used multiple times)') do |pattern|\n options.include_patterns << pattern\n end\n\n opts.on('-e', '--exclude PATTERN', 'Pattern or file to exclude (can be used multiple times)') do |pattern|\n options.exclude_patterns << pattern\n end\n\n opts.on('-f', '--format FORMAT', 'Output format: content, tree, or json, if not provided then both are used') do |format|\n options.format = format\n end\n\n opts.on('-l', '--line-limit LIMIT', 'Limit the number of lines included from each file') do |limit|\n options.line_limit = limit.to_i\n end\n\n # New option for specifying base directory\n opts.on('-b', '--base-dir DIRECTORY', 'Set the base directory to gather files from') do |directory|\n options.working_directory = directory\n end\n\n # Debug output options\n opts.on('-d', '--debug [MODE]', 'Enable debug mode [none, info, params, debug]', 'none', 'info', 'params', 'debug') do |debug|\n options.debug = debug || 'info'\n end\n\n # Output targets: clipboard or file\n opts.on('-o', '--output TARGET', 'Output target: clipboard, or a file path (can be used multiple times)') do |target|\n options.output_target << target\n end\n\n opts.on_tail('-h', '--help', 'Show this message') do\n puts opts\n puts \"\\nExamples:\"\n puts \" #{File.basename($PROGRAM_NAME)} -i 'lib/**/*.rb' -e 'lib/excluded/**/*.rb' -d\"\n puts \" #{File.basename($PROGRAM_NAME)} --include 'src/**/*.js' --exclude 'src/vendor/**/*.js'\"\n\n puts ''\n puts ' # Get GPT Context Gatherer code that is found in any folder (bin, lib & spec)'\n puts \" #{File.basename($PROGRAM_NAME)} -i '**/*gather*.rb'\"\n exit\n end\nend.parse!\n\nif options.include_patterns.empty? && options.exclude_patterns.empty? && options.format.nil?\n script_name = File.basename($PROGRAM_NAME, File.extname($PROGRAM_NAME))\n\n puts 'No options provided to GPT Context. Please specify patterns to include or exclude.'\n puts \"For help, run: #{script_name} --help\"\n exit\nend\n\nif options.output_target.empty?\n puts 'No output target provided. Will default to `clipboard`. You can set the output target using -o'\n options.output_target << 'clipboard'\nend\n\npp options if options.debug == 'params'\n\noptions.working_directory ||= Dir.pwd\n\ngatherer = Appydave::Tools::GptContext::FileCollector.new(options)\ncontent = gatherer.build\n\nif %w[info debug].include?(options.debug)\n puts '-' * 80\n puts content\n puts '-' * 80\nend\n\noutput_handler = Appydave::Tools::GptContext::OutputHandler.new(content, options)\noutput_handler.execute\n\npp options if options.debug == 'debug'\n"
38
+ },
39
+ {
40
+ "file": "lib/appydave/tools/gpt_context/file_collector.rb",
41
+ "content": "# frozen_string_literal: true\n\nmodule Appydave\n module Tools\n # Build GPT context from various sources\n module GptContext\n # Gathers file names and content based on include and exclude patterns\n class FileCollector\n def initialize(options)\n @options = options\n @include_patterns = options.include_patterns\n @exclude_patterns = options.exclude_patterns\n @format = options.format\n @working_directory = options.working_directory\n @line_limit = options.line_limit\n end\n\n def build\n FileUtils.cd(@working_directory) if @working_directory && Dir.exist?(@working_directory)\n\n formats = @format.split(',')\n result = formats.map do |fmt|\n case fmt\n when 'tree'\n build_tree\n when 'content'\n build_content\n when 'json'\n build_json\n else\n ''\n end\n end.join(\"\\n\\n\")\n\n FileUtils.cd(Dir.home) if @working_directory\n\n result\n end\n\n private\n\n def build_content\n concatenated_content = []\n\n @include_patterns.each do |pattern|\n Dir.glob(pattern).each do |file_path|\n next if excluded?(file_path) || File.directory?(file_path)\n\n content = \"# file: #{file_path}\\n\\n#{read_file_content(file_path)}\"\n concatenated_content << content\n end\n end\n\n concatenated_content.join(\"\\n\\n\")\n end\n\n def read_file_content(file_path)\n lines = File.readlines(file_path)\n return lines.first(@line_limit).join if @line_limit\n\n lines.join\n end\n\n def build_tree\n tree_view = {}\n\n @include_patterns.each do |pattern|\n Dir.glob(pattern).each do |file_path|\n next if excluded?(file_path)\n\n path_parts = file_path.split('/')\n insert_into_tree(tree_view, path_parts)\n end\n end\n\n build_tree_pretty(tree_view).rstrip\n end\n\n def insert_into_tree(tree, path_parts)\n node = tree\n path_parts.each do |part|\n node[part] ||= {}\n node = node[part]\n end\n end\n\n def build_tree_pretty(node, prefix: '', is_last: true, output: ''.dup)\n node.each_with_index do |(part, child), index|\n connector = is_last && index == node.size - 1 ? '└' : '├'\n output << \"#{prefix}#{connector}─ #{part}\\n\"\n next_prefix = is_last && index == node.size - 1 ? ' ' : '│ '\n build_tree_pretty(child, prefix: \"#{prefix}#{next_prefix}\", is_last: child.empty? || index == node.size - 1, output: output)\n end\n output\n end\n\n def build_json\n json_output = {\n 'tree' => {},\n 'content' => []\n }\n\n # Building tree structure in JSON\n @include_patterns.each do |pattern|\n Dir.glob(pattern).each do |file_path|\n next if excluded?(file_path)\n\n path_parts = file_path.split('/')\n insert_into_tree(json_output['tree'], path_parts)\n end\n end\n\n # Building content structure in JSON\n @include_patterns.each do |pattern|\n Dir.glob(pattern).each do |file_path|\n next if excluded?(file_path) || File.directory?(file_path)\n\n json_output['content'] << {\n 'file' => file_path,\n 'content' => read_file_content(file_path)\n }\n end\n end\n\n JSON.pretty_generate(json_output)\n end\n\n def excluded?(file_path)\n @exclude_patterns.any? { |pattern| File.fnmatch(pattern, file_path, File::FNM_PATHNAME | File::FNM_DOTMATCH) }\n end\n end\n end\n end\nend\n"
42
+ },
43
+ {
44
+ "file": "lib/appydave/tools/gpt_context/options.rb",
45
+ "content": "# frozen_string_literal: true\n\nmodule Appydave\n module Tools\n module GptContext\n # Struct with keyword_init: true to allow named parameters\n Options = Struct.new(\n :include_patterns,\n :exclude_patterns,\n :format,\n :line_limit,\n :debug,\n :output_target,\n :working_directory,\n keyword_init: true\n ) do\n def initialize(**args)\n super\n self.include_patterns ||= []\n self.exclude_patterns ||= []\n self.format ||= 'tree,content'\n self.debug ||= 'none'\n self.output_target ||= []\n end\n end\n end\n end\nend\n"
46
+ },
47
+ {
48
+ "file": "lib/appydave/tools/gpt_context/output_handler.rb",
49
+ "content": "# frozen_string_literal: true\n\nmodule Appydave\n module Tools\n module GptContext\n class OutputHandler\n def initialize(content, options)\n @content = content\n @output_targets = options.output_target\n @working_directory = options.working_directory\n end\n\n def execute\n @output_targets.each do |target|\n case target\n when 'clipboard'\n Clipboard.copy(@content)\n when /^.+$/\n write_to_file(target)\n end\n end\n end\n\n private\n\n attr_reader :content, :output_targets, :working_directory\n\n def write_to_file(target)\n resolved_path = Pathname.new(target).absolute? ? target : File.join(working_directory, target)\n File.write(resolved_path, content)\n end\n end\n end\n end\nend\n"
50
+ },
51
+ {
52
+ "file": "spec/appydave/tools/gpt_context/file_collector_spec.rb",
53
+ "content": "# frozen_string_literal: true\n\nRSpec.describe Appydave::Tools::GptContext::FileCollector do\n describe '#build' do\n subject { described_class.new(include_patterns: include_patterns, exclude_patterns: exclude_patterns, format: format, line_limit: line_limit) }\n\n let(:include_patterns) { ['spec/fixtures/gpt-content-gatherer/**/*.txt'] }\n let(:exclude_patterns) { ['spec/fixtures/gpt-content-gatherer/excluded/*.txt', '**/deep/**/*'] }\n let(:format) { 'content' }\n let(:line_limit) { nil }\n\n context 'when gathering content' do\n it 'concatenates content from files matching include patterns' do\n expect(subject.build).to include('File 1 content', 'File 2 content')\n end\n\n it 'excludes content from files matching exclude patterns' do\n expect(subject.build).not_to include('Excluded file content')\n expect(subject.build).not_to include('Deep 1')\n expect(subject.build).not_to include('Deep 1')\n end\n\n it 'includes file paths as headers in the gathered content' do\n expect(subject.build)\n .to include('# file: spec/fixtures/gpt-content-gatherer/included/file1.txt')\n .and include('# file: spec/fixtures/gpt-content-gatherer/included/file2.txt')\n end\n end\n\n context 'when line limit is set' do\n let(:line_limit) { 1 }\n\n it 'limits the number of lines included from each file' do\n expect(subject.build).not_to include('Line #2')\n end\n end\n end\n\n describe '#build with tree format' do\n subject { described_class.new(include_patterns: include_patterns, exclude_patterns: exclude_patterns, format: 'tree') }\n\n let(:include_patterns) { ['spec/fixtures/gpt-content-gatherer/**/*'] }\n let(:exclude_patterns) { [] }\n\n before do\n allow(Dir).to receive(:glob).and_return(\n [\n 'spec/fixtures/gpt-content-gatherer/included/file1.txt',\n 'spec/fixtures/gpt-content-gatherer/included/file2.txt',\n 'spec/fixtures/gpt-content-gatherer/included/subdir/file3.txt'\n ]\n )\n allow(File).to receive(:directory?).and_return(false)\n end\n\n it 'prints a tree view of the included files and directories with improved ASCII art' do\n expected_output = <<~TREE\n └─ spec\n └─ fixtures\n └─ gpt-content-gatherer\n └─ included\n ├─ file1.txt\n ├─ file2.txt\n └─ subdir\n └─ file3.txt\n TREE\n\n expect(subject.build.strip).to eq(expected_output.strip)\n end\n end\n\n describe '#build with both formats' do\n subject { described_class.new(include_patterns: include_patterns, exclude_patterns: exclude_patterns, format: 'tree,content') }\n\n let(:include_patterns) { ['spec/fixtures/gpt-content-gatherer/**/*'] }\n let(:exclude_patterns) { [] }\n\n before do\n allow(Dir).to receive(:glob).and_return(\n [\n 'spec/fixtures/gpt-content-gatherer/included/file1.txt',\n 'spec/fixtures/gpt-content-gatherer/included/file2.txt',\n 'spec/fixtures/gpt-content-gatherer/included/subdir/file3.txt'\n ]\n )\n allow(File).to receive(:directory?).and_return(false)\n end\n\n it 'prints both a tree view and the file contents' do\n expected_output_tree = <<~TREE\n └─ spec\n └─ fixtures\n └─ gpt-content-gatherer\n └─ included\n ├─ file1.txt\n ├─ file2.txt\n └─ subdir\n └─ file3.txt\n TREE\n\n expected_output_content = <<~CONTENT\n # file: spec/fixtures/gpt-content-gatherer/included/file1.txt\n\n File 1 content\n Line #2\n\n # file: spec/fixtures/gpt-content-gatherer/included/file2.txt\n\n File 2 content\n Line #2\n\n # file: spec/fixtures/gpt-content-gatherer/included/subdir/file3.txt\n\n File 3 content\n Line #2\n CONTENT\n\n expect(subject.build).to include(expected_output_tree.strip)\n expect(subject.build).to include(expected_output_content.strip)\n end\n end\nend\n"
54
+ },
55
+ {
56
+ "file": "spec/appydave/tools/gpt_context/output_handler_spec.rb",
57
+ "content": "# frozen_string_literal: true\n\nRSpec.describe Appydave::Tools::GptContext::OutputHandler do\n subject { described_class.new(content, options) }\n\n let(:content) { 'Sample content' }\n let(:options) { double('Options', output_target: ['clipboard'], working_directory: Dir.pwd) }\n\n describe '#execute' do\n it 'copies content to clipboard when output target is clipboard' do\n expect(Clipboard).to receive(:copy).with(content)\n subject.execute\n end\n\n context 'when output target is a file' do\n let(:options) { double('Options', output_target: ['output.txt'], working_directory: Dir.pwd) }\n\n it 'writes content to the specified file' do\n expect(File).to receive(:write).with(File.join(Dir.pwd, 'output.txt'), content)\n subject.execute\n end\n end\n\n context 'when multiple output targets are specified' do\n let(:options) { double('Options', output_target: ['clipboard', 'output.txt'], working_directory: Dir.pwd) }\n\n it 'copies content to clipboard and writes to file' do\n expect(Clipboard).to receive(:copy).with(content)\n expect(File).to receive(:write).with(File.join(Dir.pwd, 'output.txt'), content)\n subject.execute\n end\n end\n end\nend\n"
58
+ }
59
+ ]
60
+ }
data/bin/gpt_context.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
+ # GPT Chats:
5
+ # https://chatgpt.com/c/670df475-04f4-8002-a758-f5711bf433eb
6
+
4
7
  # Usage:
5
8
  # ./bin/gpt_context.rb -d -i 'lib/openai_101/tools/**/*.rb'
6
9
  # ./bin/gpt_context.rb -d -i 'lib/openai_101/tools/**/*' -e 'node_modules/**/*' -e 'package-lock.json' -e 'lib/openai_101/tools/prompts/*.txt'
@@ -11,39 +14,42 @@ $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
11
14
 
12
15
  require 'appydave/tools'
13
16
 
14
- options = {
15
- include_patterns: [],
16
- exclude_patterns: [],
17
- format: 'tree,content',
18
- line_limit: nil,
19
- debug: 'none'
20
- }
17
+ options = Appydave::Tools::GptContext::Options.new(
18
+ working_directory: nil
19
+ )
21
20
 
22
21
  OptionParser.new do |opts|
23
22
  opts.banner = 'Usage: gather_content.rb [options]'
24
23
 
25
24
  opts.on('-i', '--include PATTERN', 'Pattern or file to include (can be used multiple times)') do |pattern|
26
- options[:include_patterns] << pattern
25
+ options.include_patterns << pattern
27
26
  end
28
27
 
29
28
  opts.on('-e', '--exclude PATTERN', 'Pattern or file to exclude (can be used multiple times)') do |pattern|
30
- options[:exclude_patterns] << pattern
29
+ options.exclude_patterns << pattern
31
30
  end
32
31
 
33
- opts.on('-f', '--format FORMAT', 'Output format: content or tree, if not provided then both are used') do |format|
34
- options[:format] = format
32
+ opts.on('-f', '--format FORMAT', 'Output format: content, tree, or json, if not provided then both are used') do |format|
33
+ options.format = format
35
34
  end
36
35
 
37
36
  opts.on('-l', '--line-limit LIMIT', 'Limit the number of lines included from each file') do |limit|
38
- options[:line_limit] = limit.to_i
37
+ options.line_limit = limit.to_i
39
38
  end
40
39
 
41
- # None - No debug output
42
- # Output - Output the content to the console, this is the same as found in the clipboard
43
- # Params - Output the options that were passed to the script
44
- # Debug - Output content, options and debug information
45
- opts.on('-d', '--debug [MODE]', 'Enable debug mode [none, output, params, debug]', 'none', 'output', 'params', 'debug') do |debug|
46
- options[:debug] = debug || 'output'
40
+ # New option for specifying base directory
41
+ opts.on('-b', '--base-dir DIRECTORY', 'Set the base directory to gather files from') do |directory|
42
+ options.working_directory = directory
43
+ end
44
+
45
+ # Debug output options
46
+ opts.on('-d', '--debug [MODE]', 'Enable debug mode [none, info, params, debug]', 'none', 'info', 'params', 'debug') do |debug|
47
+ options.debug = debug || 'info'
48
+ end
49
+
50
+ # Output targets: clipboard or file
51
+ opts.on('-o', '--output TARGET', 'Output target: clipboard, or a file path (can be used multiple times)') do |target|
52
+ options.output_target << target
47
53
  end
48
54
 
49
55
  opts.on_tail('-h', '--help', 'Show this message') do
@@ -59,7 +65,7 @@ OptionParser.new do |opts|
59
65
  end
60
66
  end.parse!
61
67
 
62
- if options[:include_patterns].empty? && options[:exclude_patterns].empty? && options[:format].nil?
68
+ if options.include_patterns.empty? && options.exclude_patterns.empty? && options.format.nil?
63
69
  script_name = File.basename($PROGRAM_NAME, File.extname($PROGRAM_NAME))
64
70
 
65
71
  puts 'No options provided to GPT Context. Please specify patterns to include or exclude.'
@@ -67,24 +73,25 @@ if options[:include_patterns].empty? && options[:exclude_patterns].empty? && opt
67
73
  exit
68
74
  end
69
75
 
70
- pp options if options[:debug] == 'params'
76
+ if options.output_target.empty?
77
+ puts 'No output target provided. Will default to `clipboard`. You can set the output target using -o'
78
+ options.output_target << 'clipboard'
79
+ end
80
+
81
+ pp options if options.debug == 'params'
71
82
 
72
- gatherer = Appydave::Tools::GptContext::FileCollector.new(
73
- include_patterns: options[:include_patterns],
74
- exclude_patterns: options[:exclude_patterns],
75
- format: options[:format],
76
- line_limit: options[:line_limit],
77
- working_directory: Dir.pwd
78
- )
83
+ options.working_directory ||= Dir.pwd
79
84
 
85
+ gatherer = Appydave::Tools::GptContext::FileCollector.new(options)
80
86
  content = gatherer.build
81
87
 
82
- if %w[output debug].include?(options[:debug])
88
+ if %w[info debug].include?(options.debug)
83
89
  puts '-' * 80
84
90
  puts content
85
91
  puts '-' * 80
86
92
  end
87
93
 
88
- pp options if options[:debug] == 'debug'
94
+ output_handler = Appydave::Tools::GptContext::OutputHandler.new(content, options)
95
+ output_handler.execute
89
96
 
90
- Clipboard.copy(content)
97
+ pp options if options.debug == 'debug'
@@ -6,32 +6,33 @@ module Appydave
6
6
  module GptContext
7
7
  # Gathers file names and content based on include and exclude patterns
8
8
  class FileCollector
9
- attr_reader :include_patterns, :exclude_patterns, :format, :working_directory, :line_limit
10
-
11
- def initialize(include_patterns: [], exclude_patterns: [], format: 'tree,content', working_directory: nil, line_limit: nil)
12
- @include_patterns = include_patterns
13
- @exclude_patterns = exclude_patterns
14
- @format = format
15
- @working_directory = working_directory
16
- @line_limit = line_limit
9
+ def initialize(options)
10
+ @options = options
11
+ @include_patterns = options.include_patterns
12
+ @exclude_patterns = options.exclude_patterns
13
+ @format = options.format
14
+ @working_directory = options.working_directory
15
+ @line_limit = options.line_limit
17
16
  end
18
17
 
19
18
  def build
20
- FileUtils.cd(working_directory) if working_directory && Dir.exist?(working_directory)
19
+ FileUtils.cd(@working_directory) if @working_directory && Dir.exist?(@working_directory)
21
20
 
22
- formats = format.split(',')
21
+ formats = @format.split(',')
23
22
  result = formats.map do |fmt|
24
23
  case fmt
25
24
  when 'tree'
26
25
  build_tree
27
26
  when 'content'
28
27
  build_content
28
+ when 'json'
29
+ build_json
29
30
  else
30
31
  ''
31
32
  end
32
33
  end.join("\n\n")
33
34
 
34
- FileUtils.cd(Dir.home) if working_directory
35
+ FileUtils.cd(Dir.home) if @working_directory
35
36
 
36
37
  result
37
38
  end
@@ -41,7 +42,7 @@ module Appydave
41
42
  def build_content
42
43
  concatenated_content = []
43
44
 
44
- include_patterns.each do |pattern|
45
+ @include_patterns.each do |pattern|
45
46
  Dir.glob(pattern).each do |file_path|
46
47
  next if excluded?(file_path) || File.directory?(file_path)
47
48
 
@@ -55,7 +56,7 @@ module Appydave
55
56
 
56
57
  def read_file_content(file_path)
57
58
  lines = File.readlines(file_path)
58
- return lines.first(line_limit).join if line_limit
59
+ return lines.first(@line_limit).join if @line_limit
59
60
 
60
61
  lines.join
61
62
  end
@@ -63,7 +64,7 @@ module Appydave
63
64
  def build_tree
64
65
  tree_view = {}
65
66
 
66
- include_patterns.each do |pattern|
67
+ @include_patterns.each do |pattern|
67
68
  Dir.glob(pattern).each do |file_path|
68
69
  next if excluded?(file_path)
69
70
 
@@ -93,8 +94,35 @@ module Appydave
93
94
  output
94
95
  end
95
96
 
97
+ def build_json
98
+ json_output = {
99
+ 'tree' => {},
100
+ 'content' => []
101
+ }
102
+
103
+ # Building tree structure in JSON
104
+ @include_patterns.each do |pattern|
105
+ Dir.glob(pattern).each do |file_path|
106
+ next if excluded?(file_path)
107
+
108
+ path_parts = file_path.split('/')
109
+ insert_into_tree(json_output['tree'], path_parts)
110
+
111
+ # Building content structure in JSON
112
+ next if excluded?(file_path) || File.directory?(file_path)
113
+
114
+ json_output['content'] << {
115
+ 'file' => file_path,
116
+ 'content' => read_file_content(file_path)
117
+ }
118
+ end
119
+ end
120
+
121
+ JSON.pretty_generate(json_output)
122
+ end
123
+
96
124
  def excluded?(file_path)
97
- exclude_patterns.any? { |pattern| File.fnmatch(pattern, file_path, File::FNM_PATHNAME | File::FNM_DOTMATCH) }
125
+ @exclude_patterns.any? { |pattern| File.fnmatch(pattern, file_path, File::FNM_PATHNAME | File::FNM_DOTMATCH) }
98
126
  end
99
127
  end
100
128
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appydave
4
+ module Tools
5
+ module GptContext
6
+ # Struct with keyword_init: true to allow named parameters
7
+ Options = Struct.new(
8
+ :include_patterns,
9
+ :exclude_patterns,
10
+ :format,
11
+ :line_limit,
12
+ :debug,
13
+ :output_target,
14
+ :working_directory,
15
+ keyword_init: true
16
+ ) do
17
+ def initialize(**args)
18
+ super
19
+ self.include_patterns ||= []
20
+ self.exclude_patterns ||= []
21
+ self.format ||= 'tree,content'
22
+ self.debug ||= 'none'
23
+ self.output_target ||= []
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appydave
4
+ module Tools
5
+ module GptContext
6
+ # OutputHandler is responsible for writing the output to the desired target
7
+ class OutputHandler
8
+ def initialize(content, options)
9
+ @content = content
10
+ @output_targets = options.output_target
11
+ @working_directory = options.working_directory
12
+ end
13
+
14
+ def execute
15
+ @output_targets.each do |target|
16
+ case target
17
+ when 'clipboard'
18
+ Clipboard.copy(@content)
19
+ when /^.+$/
20
+ write_to_file(target)
21
+ end
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :content, :output_targets, :working_directory
28
+
29
+ def write_to_file(target)
30
+ resolved_path = Pathname.new(target).absolute? ? target : File.join(working_directory, target)
31
+ File.write(resolved_path, content)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Appydave
4
4
  module Tools
5
- VERSION = '0.10.4'
5
+ VERSION = '0.11.0'
6
6
  end
7
7
  end
@@ -7,6 +7,7 @@ require 'json'
7
7
  require 'open3'
8
8
  require 'openai'
9
9
  require 'optparse'
10
+ require 'pathname'
10
11
  require 'k_log'
11
12
  require 'active_model'
12
13
 
@@ -34,7 +35,9 @@ require 'appydave/tools/cli_actions/prompt_completion_action'
34
35
  require 'appydave/tools/cli_actions/get_video_action'
35
36
  require 'appydave/tools/cli_actions/update_video_action'
36
37
 
38
+ require 'appydave/tools/gpt_context/options'
37
39
  require 'appydave/tools/gpt_context/file_collector'
40
+ require 'appydave/tools/gpt_context/output_handler'
38
41
 
39
42
  require 'appydave/tools/configuration/openai'
40
43
  require 'appydave/tools/configuration/configurable'
data/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "appydave-tools",
3
- "version": "0.10.4",
3
+ "version": "0.11.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "appydave-tools",
9
- "version": "0.10.4",
9
+ "version": "0.11.0",
10
10
  "devDependencies": {
11
11
  "@klueless-js/semantic-release-rubygem": "github:klueless-js/semantic-release-rubygem",
12
12
  "@semantic-release/changelog": "^6.0.3",
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appydave-tools",
3
- "version": "0.10.4",
3
+ "version": "0.11.0",
4
4
  "description": "AppyDave YouTube Automation Tools",
5
5
  "scripts": {
6
6
  "release": "semantic-release"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appydave-tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.4
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Cruwys
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-10-09 00:00:00.000000000 Z
11
+ date: 2024-10-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -156,6 +156,7 @@ files:
156
156
  - LICENSE.txt
157
157
  - README.md
158
158
  - Rakefile
159
+ - a.json
159
160
  - bin/bank_reconciliation.rb
160
161
  - bin/configuration.rb
161
162
  - bin/console
@@ -184,6 +185,8 @@ files:
184
185
  - lib/appydave/tools/debuggable.rb
185
186
  - lib/appydave/tools/gpt_context/_doc.md
186
187
  - lib/appydave/tools/gpt_context/file_collector.rb
188
+ - lib/appydave/tools/gpt_context/options.rb
189
+ - lib/appydave/tools/gpt_context/output_handler.rb
187
190
  - lib/appydave/tools/llm/models/llm_info.rb
188
191
  - lib/appydave/tools/llm/openai_completion.rb
189
192
  - lib/appydave/tools/name_manager/_doc.md