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 +4 -4
- data/CHANGELOG.md +13 -0
- data/a.json +60 -0
- data/bin/gpt_context.rb +37 -30
- data/lib/appydave/tools/gpt_context/file_collector.rb +43 -15
- data/lib/appydave/tools/gpt_context/options.rb +28 -0
- data/lib/appydave/tools/gpt_context/output_handler.rb +36 -0
- data/lib/appydave/tools/version.rb +1 -1
- data/lib/appydave/tools.rb +3 -0
- data/package-lock.json +2 -2
- data/package.json +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88fcb99717ec45c2efcd0884772e1325a7de9cdca64c58c7e54e8c91203b333d
|
4
|
+
data.tar.gz: d29c8848556ef6c8a189fb3db0b6ad546a0e112d3dc5abffadf3f8e3bbaf058b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
16
|
-
|
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
|
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
|
29
|
+
options.exclude_patterns << pattern
|
31
30
|
end
|
32
31
|
|
33
|
-
opts.on('-f', '--format FORMAT', 'Output format: content or
|
34
|
-
options
|
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
|
37
|
+
options.line_limit = limit.to_i
|
39
38
|
end
|
40
39
|
|
41
|
-
#
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
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
|
-
|
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
|
-
|
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[
|
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
|
-
|
94
|
+
output_handler = Appydave::Tools::GptContext::OutputHandler.new(content, options)
|
95
|
+
output_handler.execute
|
89
96
|
|
90
|
-
|
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
|
-
|
10
|
-
|
11
|
-
|
12
|
-
@
|
13
|
-
@
|
14
|
-
@
|
15
|
-
@
|
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
|
data/lib/appydave/tools.rb
CHANGED
@@ -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.
|
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.
|
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
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.
|
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-
|
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
|