appydave-tools 0.10.4 → 0.11.0

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: 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