appydave-tools 0.78.0 → 0.80.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: 124ae7188a7ab1340f03990ecd808ed1434015bc04f385daa7c3bbd77731c173
4
- data.tar.gz: 72889e8c0d80d5d6513d8cfafe000a41c72af69cc4d187b48f8895f4f8a6bb48
3
+ metadata.gz: cb0b711e430f2082be55712eb0c3e630726bcc77628dc8ab144d72f27fc05bd7
4
+ data.tar.gz: 8fc9be5413601f6da5cccd649d324578df676efb842b138623998a1f6dd7b676
5
5
  SHA512:
6
- metadata.gz: 564f33a1b0383c05e65536b44b6ebcac1dc0dd8b4083476ca44172dbe8beac366e2ddfbc8488dbb6c2dd687d52aa7794d000ed8d6d17f4d8583fa7718873e476
7
- data.tar.gz: cdf9e093a0fbdaeb6fda2cdf54bedf82dbbaccda435f9e3d9f87cfb9b8fb671cd071339aefd06dd03875ef07c7676c8cd5682ba120e10cf7cb18c5b51293eb51
6
+ metadata.gz: d7527c25930ba5fb35206e6321fea074f12593a9188ed4b7d51f1f832f01f60a9929336b8670bf48bea0f68eeba0df150ecb542ea244be899334781ef432a7a1
7
+ data.tar.gz: 051f6c24d48fa6caa2ac342436a1105403d7524e871ee248996b772e0e16aafde612cd33386d4b6bba92b5f1f0c2e2f6cf61406e9f76db5a42e55d367031c642
data/CHANGELOG.md CHANGED
@@ -1,3 +1,22 @@
1
+ # [0.79.0](https://github.com/appydave/appydave-tools/compare/v0.78.0...v0.79.0) (2026-04-03)
2
+
3
+
4
+ ### Features
5
+
6
+ * add --stdin support to llm_context for piping file paths ([8890cfe](https://github.com/appydave/appydave-tools/commit/8890cfebb80cfda81b679da3e52a185bbb1c9141))
7
+
8
+ # [0.78.0](https://github.com/appydave/appydave-tools/compare/v0.77.7...v0.78.0) (2026-04-03)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * resolve rubocop block length violation in llm_context CLI ([305b65a](https://github.com/appydave/appydave-tools/commit/305b65aca92204b877ed25841a8041e9c5a08683))
14
+
15
+
16
+ ### Features
17
+
18
+ * update gpt_gatherer to llm_gatherer ([acfbf1c](https://github.com/appydave/appydave-tools/commit/acfbf1c09d40b45d2ca211d5f3921af1127f068c))
19
+
1
20
  ## [0.77.7](https://github.com/appydave/appydave-tools/compare/v0.77.6...v0.77.7) (2026-03-20)
2
21
 
3
22
 
data/bin/llm_context.rb CHANGED
@@ -80,6 +80,10 @@ def setup_options(opts, options)
80
80
  opts.on('-t', '--tokens', 'Show estimated token count after collecting context') do
81
81
  options.show_tokens = true
82
82
  end
83
+
84
+ opts.on('--stdin', 'Read file paths from stdin (one per line) instead of using patterns') do
85
+ options.stdin = true
86
+ end
83
87
  end
84
88
 
85
89
  def setup_help_sections(opts)
@@ -96,6 +100,10 @@ def setup_help_sections(opts)
96
100
  opts.separator ' temp - Write to system temp dir, copy path to clipboard'
97
101
  opts.separator ' filename - Write to specified file path'
98
102
  opts.separator ''
103
+ opts.separator 'INPUT MODES'
104
+ opts.separator ' Patterns (default): -i <glob> and -e <exclude_glob>'
105
+ opts.separator ' Stdin: --stdin (read file paths from stdin, one per line)'
106
+ opts.separator ''
99
107
  opts.separator 'EXAMPLES'
100
108
  opts.separator ' # Gather Ruby library code for AI context'
101
109
  opts.separator " llm_context -i 'lib/**/*.rb' -e 'spec/**/*' -d"
@@ -109,6 +117,9 @@ def setup_help_sections(opts)
109
117
  opts.separator ' # Write to system temp dir and copy path to clipboard'
110
118
  opts.separator " llm_context -i 'lib/**/*.rb' -o temp"
111
119
  opts.separator ''
120
+ opts.separator ' # Read file paths from stdin'
121
+ opts.separator " find lib -name '*.rb' | llm_context --stdin -o temp"
122
+ opts.separator ''
112
123
  opts.separator ' # Generate aider command'
113
124
  opts.separator " llm_context -i 'lib/**/*.rb' -f aider -p 'Add logging'"
114
125
  opts.separator ''
@@ -140,10 +151,16 @@ end
140
151
 
141
152
  parser.parse!
142
153
 
143
- if options.include_patterns.empty? && options.exclude_patterns.empty?
154
+ # Handle stdin file paths
155
+ if options.stdin
156
+ options.file_paths = $stdin.readlines.map(&:chomp).reject(&:empty?)
157
+ options.working_directory = Dir.pwd unless options.working_directory
158
+ end
159
+
160
+ if options.include_patterns.empty? && options.exclude_patterns.empty? && options.file_paths.empty?
144
161
  script_name = File.basename($PROGRAM_NAME, File.extname($PROGRAM_NAME))
145
162
 
146
- puts 'No options provided to LLM Context. Please specify patterns to include or exclude.'
163
+ puts 'No options provided to LLM Context. Please specify patterns to include or exclude, or use --stdin.'
147
164
  puts "For help, run: #{script_name} --help"
148
165
  exit
149
166
  end
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
5
+ require 'appydave/tools'
6
+
7
+ options = Appydave::Tools::BrainContextOptions.new
8
+
9
+ def setup_options(options)
10
+ OptionParser.new do |opts| # rubocop:disable Metrics/BlockLength
11
+ opts.banner = 'Usage: query_brain [options]'
12
+
13
+ opts.on('--brain NAME', 'Query brain by name, alias, or fuzzy match') do |name|
14
+ options.brain_names << name
15
+ end
16
+
17
+ opts.on('--tag TAG', 'Query brains by tag') do |tag|
18
+ options.tags << tag
19
+ end
20
+
21
+ opts.on('--category CAT', 'Query all brains in category') do |cat|
22
+ options.categories << cat
23
+ end
24
+
25
+ opts.on('--activity-min LEVEL', %w[high medium low none],
26
+ 'Filter brains by minimum activity level') do |level|
27
+ options.activity_levels << level
28
+ end
29
+
30
+ opts.on('--status STATUS', %w[active stable deprecated],
31
+ 'Filter brains by status (default: exclude deprecated)') do |status|
32
+ options.status = status
33
+ end
34
+
35
+ opts.on('--files-only', 'Exclude INDEX.md, only include content files') do
36
+ options.include_index = false
37
+ end
38
+
39
+ opts.on('-d', '--debug [MODE]', %w[none info params debug],
40
+ 'Debug output level') do |level|
41
+ options.debug_level = level || 'info'
42
+ end
43
+
44
+ opts.on('-v', '--version', 'Show version') do
45
+ puts "query_brain v#{Appydave::Tools::VERSION}"
46
+ exit 0
47
+ end
48
+
49
+ opts.on('-h', '--help', 'Show this message') do
50
+ puts opts
51
+ exit 0
52
+ end
53
+ end.parse!
54
+ end
55
+
56
+ setup_options(options)
57
+
58
+ # Query
59
+ finder = Appydave::Tools::BrainQuery.new(options)
60
+ paths = finder.find
61
+
62
+ # Output file paths, one per line
63
+ paths.each { |p| puts p }
64
+
65
+ exit 0
data/bin/query_omi.rb ADDED
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
5
+ require 'appydave/tools'
6
+
7
+ options = Appydave::Tools::BrainContextOptions.new
8
+ options.omi = true
9
+
10
+ def setup_options(options)
11
+ OptionParser.new do |opts| # rubocop:disable Metrics/BlockLength
12
+ opts.banner = 'Usage: query_omi [options]'
13
+
14
+ opts.on('--signal SIGNAL', %w[work life ambient],
15
+ 'Filter by signal') do |signal|
16
+ options.omi_signals << signal
17
+ end
18
+
19
+ opts.on('--routing ROUTING',
20
+ 'Filter by routing (brain-update, todo-item, personal, til, archive; pipe-delimited)') do |routing|
21
+ options.omi_routings.concat(routing.split('|').map(&:strip))
22
+ end
23
+
24
+ opts.on('--activity ACTIVITY',
25
+ 'Filter by activity (planning, reviewing, learning, debugging, etc.; pipe-delimited)') do |activity|
26
+ options.omi_activities.concat(activity.split('|').map(&:strip))
27
+ end
28
+
29
+ opts.on('--date-from DATE', 'Include files from date (YYYY-MM-DD)') do |date|
30
+ options.date_from = date
31
+ end
32
+
33
+ opts.on('--date-to DATE', 'Include files up to date (YYYY-MM-DD)') do |date|
34
+ options.date_to = date
35
+ end
36
+
37
+ opts.on('--enriched-only', 'Skip raw (non-enriched) transcripts') do
38
+ options.enriched_only = true
39
+ end
40
+
41
+ opts.on('--brain NAME', 'Find OMI files mentioning this brain') do |name|
42
+ options.brain_names << name
43
+ end
44
+
45
+ opts.on('-d', '--debug [MODE]', %w[none info params debug],
46
+ 'Debug output level') do |level|
47
+ options.debug_level = level || 'info'
48
+ end
49
+
50
+ opts.on('-v', '--version', 'Show version') do
51
+ puts "query_omi v#{Appydave::Tools::VERSION}"
52
+ exit 0
53
+ end
54
+
55
+ opts.on('-h', '--help', 'Show this message') do
56
+ puts opts
57
+ exit 0
58
+ end
59
+ end.parse!
60
+ end
61
+
62
+ setup_options(options)
63
+
64
+ # Query
65
+ finder = Appydave::Tools::OmiQuery.new(options)
66
+ paths = finder.find
67
+
68
+ # Output file paths, one per line
69
+ paths.each { |p| puts p }
70
+
71
+ exit 0
data/exe/query_brain ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
5
+ require 'appydave/tools'
6
+
7
+ load File.expand_path('../bin/query_brain.rb', __dir__)
data/exe/query_omi ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
5
+ require 'appydave/tools'
6
+
7
+ load File.expand_path('../bin/query_omi.rb', __dir__)
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Appydave
6
+ module Tools
7
+ # Queries brains-index.json to find brain files
8
+ class BrainQuery
9
+ def initialize(options)
10
+ @options = options
11
+ @index = nil
12
+ @alias_map = nil
13
+ end
14
+
15
+ def find
16
+ return [] unless @options.brain_query?
17
+
18
+ load_index!
19
+ paths = []
20
+
21
+ # Handle brain name queries
22
+ @options.brain_names.each do |name|
23
+ paths.concat(find_by_name(name))
24
+ end
25
+
26
+ # Handle tag queries
27
+ @options.tags.each do |tag|
28
+ paths.concat(find_by_tag(tag))
29
+ end
30
+
31
+ # Handle category queries
32
+ @options.categories.each do |category|
33
+ paths.concat(find_by_category(category))
34
+ end
35
+
36
+ # Handle activity level filters
37
+ paths.select! { |p| matches_activity_level?(p) } if @options.activity_levels.any?
38
+
39
+ # Remove duplicates and return
40
+ paths.uniq.sort
41
+ end
42
+
43
+ private
44
+
45
+ def load_index!
46
+ return if @index
47
+
48
+ index_path = @options.brains_index_path
49
+ unless File.exist?(index_path)
50
+ raise "brains-index.json not found at #{index_path}. Run: python ~/dev/ad/brains/.claude/skills/brain-librarian/scripts/build_brain_index.py build --all ~/dev/ad/brains"
51
+ end
52
+
53
+ @index = JSON.parse(File.read(index_path))
54
+ build_alias_map!
55
+ end
56
+
57
+ def build_alias_map!
58
+ @alias_map = {}
59
+ @index['alias_index']&.each { |alias_name, brain_name| @alias_map[alias_name.downcase] = brain_name }
60
+ end
61
+
62
+ def find_by_name(name)
63
+ load_index!
64
+
65
+ # Step 1: Exact match on brain key
66
+ brain_entry = find_brain_in_index(name)
67
+ return brain_entries_to_paths([brain_entry]) if brain_entry
68
+
69
+ # Step 2: Alias match
70
+ if @alias_map && @alias_map[name.downcase]
71
+ brain_name = @alias_map[name.downcase]
72
+ brain_entry = find_brain_in_index(brain_name)
73
+ return brain_entries_to_paths([brain_entry]) if brain_entry
74
+ end
75
+
76
+ # Step 3: Substring match on brain key (case-insensitive)
77
+ matches = []
78
+ @index['categories'].each_value do |category_data|
79
+ category_data['brains'].each do |brain_name, brain_data|
80
+ matches << brain_data if brain_name.downcase.include?(name.downcase)
81
+ end
82
+ end
83
+ return brain_entries_to_paths(matches) if matches.length == 1
84
+ return brain_entries_to_paths(matches) if matches.any?
85
+
86
+ # Not found
87
+ []
88
+ end
89
+
90
+ def find_by_tag(tag)
91
+ load_index!
92
+ tag = tag.downcase.gsub('_', '-')
93
+
94
+ brain_names = @index['tag_index']&.[](tag) || []
95
+ brain_entries = []
96
+
97
+ brain_names.each do |brain_name|
98
+ entry = find_brain_in_index(brain_name)
99
+ brain_entries << entry if entry
100
+ end
101
+
102
+ brain_entries_to_paths(brain_entries)
103
+ end
104
+
105
+ def find_by_category(category)
106
+ load_index!
107
+ category_data = @index['categories'][category] || @index['categories'][category.downcase]
108
+
109
+ return [] unless category_data
110
+
111
+ brain_entries = category_data['brains'].values
112
+ brain_entries_to_paths(brain_entries)
113
+ end
114
+
115
+ def find_brain_in_index(brain_name)
116
+ @index['categories'].each_value do |category_data|
117
+ return category_data['brains'][brain_name] if category_data['brains'][brain_name]
118
+ end
119
+ nil
120
+ end
121
+
122
+ def brain_entries_to_paths(brain_entries)
123
+ paths = []
124
+
125
+ brain_entries.each do |entry|
126
+ next unless entry
127
+
128
+ # Add files from files[] array
129
+ entry['files']&.each do |file|
130
+ # File entry is relative to the brain directory
131
+ brain_name = extract_brain_name(entry)
132
+ full_path = File.join(@options.brains_root, brain_name, file)
133
+ paths << full_path if File.exist?(full_path)
134
+ end
135
+
136
+ # Add INDEX.md if requested
137
+ if @options.include_index
138
+ index_path = File.join(@options.brains_root, entry['index_path'])
139
+ paths << index_path if File.exist?(index_path)
140
+ end
141
+ end
142
+
143
+ paths
144
+ end
145
+
146
+ def extract_brain_name(entry)
147
+ # index_path is like "brain-name/INDEX.md"
148
+ entry['index_path'].split('/')[0]
149
+ end
150
+
151
+ def matches_activity_level?(file_path)
152
+ # Extract brain name from path
153
+ brain_name = file_path.match(%r{#{Regexp.escape(@options.brains_root)}/([^/]+)})&.[](1)
154
+ return false unless brain_name
155
+
156
+ # Find the brain entry
157
+ entry = find_brain_in_index(brain_name)
158
+ return false unless entry
159
+
160
+ # Check if activity level matches filter
161
+ @options.activity_levels.include?(entry['activity_level'])
162
+ end
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module Appydave
6
+ module Tools
7
+ # Queries OMI transcript directory by enriched frontmatter
8
+ class OmiQuery
9
+ def initialize(options)
10
+ @options = options
11
+ end
12
+
13
+ def find
14
+ return [] unless @options.omi_query?
15
+
16
+ paths = []
17
+
18
+ Dir.glob(File.join(@options.omi_dir, '*.md')).each do |file_path|
19
+ next unless include_file?(file_path)
20
+
21
+ paths << file_path
22
+ end
23
+
24
+ paths.sort
25
+ end
26
+
27
+ private
28
+
29
+ def include_file?(file_path)
30
+ frontmatter = extract_frontmatter(file_path)
31
+ return false unless frontmatter
32
+
33
+ # If enriched-only requested, skip raw files
34
+ return false if @options.enriched_only && (!frontmatter['signal'] || !frontmatter['extraction_summary'])
35
+
36
+ # Apply filters
37
+ return false unless signal_matches?(frontmatter)
38
+ return false unless routing_matches?(frontmatter)
39
+ return false unless activity_matches?(frontmatter)
40
+ return false unless date_matches?(frontmatter)
41
+ return false unless brain_matches?(frontmatter)
42
+
43
+ true
44
+ end
45
+
46
+ def extract_frontmatter(file_path)
47
+ content = File.read(file_path, encoding: 'utf-8')
48
+ lines = content.split("\n")
49
+
50
+ return nil unless lines[0] == '---'
51
+
52
+ frontmatter = {}
53
+ i = 1
54
+ while i < lines.length
55
+ line = lines[i]
56
+ break if line == '---'
57
+
58
+ # Parse YAML-like: key: value
59
+ if line.match?(/^[a-z_]+:/)
60
+ key, value = parse_yaml_line(line)
61
+ frontmatter[key] = value
62
+ end
63
+
64
+ i += 1
65
+ end
66
+
67
+ frontmatter.empty? ? nil : frontmatter
68
+ end
69
+
70
+ def parse_yaml_line(line)
71
+ # Handle simple cases: key: value, key: [a, b, c]
72
+ match = line.match(/^([a-z_]+):\s*(.*)$/)
73
+ return [nil, nil] unless match
74
+
75
+ key = match[1]
76
+ value_str = match[2].strip
77
+
78
+ # Parse array [a, b, c]
79
+ if value_str.start_with?('[') && value_str.end_with?(']')
80
+ array_content = value_str[1..-2]
81
+ value = array_content.split(',').map { |v| v.strip.gsub(/^["']|["']$/, '') }
82
+ # Parse quoted string
83
+ elsif (value_str.start_with?('"') && value_str.end_with?('"')) ||
84
+ (value_str.start_with?("'") && value_str.end_with?("'"))
85
+ value = value_str[1..-2]
86
+ # Parse date (YYYY-MM-DD) or other values as-is
87
+ else
88
+ value = value_str
89
+ end
90
+
91
+ [key, value]
92
+ end
93
+
94
+ def signal_matches?(frontmatter)
95
+ return true if @options.omi_signals.empty?
96
+
97
+ signal = frontmatter['signal']
98
+ return false unless signal
99
+
100
+ @options.omi_signals.include?(signal)
101
+ end
102
+
103
+ def routing_matches?(frontmatter)
104
+ return true if @options.omi_routings.empty?
105
+
106
+ routing = frontmatter['routing']
107
+ return false unless routing
108
+
109
+ # routing can be pipe-delimited
110
+ routings = routing.split('|').map(&:strip)
111
+ routings.any? { |r| @options.omi_routings.include?(r) }
112
+ end
113
+
114
+ def activity_matches?(frontmatter)
115
+ return true if @options.omi_activities.empty?
116
+
117
+ activity = frontmatter['activity']
118
+ return false unless activity
119
+
120
+ # activity can be pipe-delimited
121
+ activities = activity.split('|').map(&:strip)
122
+ activities.any? { |a| @options.omi_activities.include?(a) }
123
+ end
124
+
125
+ def date_matches?(frontmatter)
126
+ extracted_at = frontmatter['extracted_at']
127
+ return true if extracted_at.nil? # No date field = include
128
+
129
+ begin
130
+ date = Date.parse(extracted_at)
131
+ rescue StandardError
132
+ return true # Can't parse = include
133
+ end
134
+
135
+ from_ok = @options.date_from.nil? || date >= Date.parse(@options.date_from)
136
+ to_ok = @options.date_to.nil? || date <= Date.parse(@options.date_to)
137
+
138
+ from_ok && to_ok
139
+ end
140
+
141
+ def brain_matches?(frontmatter)
142
+ return true if @options.brain_names.empty?
143
+
144
+ matched_brains = frontmatter['matched_brains']
145
+ return false unless matched_brains
146
+
147
+ # matched_brains is an array
148
+ matched_brains_list = matched_brains.is_a?(Array) ? matched_brains : [matched_brains]
149
+ matched_brains_list.any? { |brain| @options.brain_names.include?(brain) }
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appydave
4
+ module Tools
5
+ # Options struct for brain/OMI query tools
6
+ class BrainContextOptions
7
+ attr_accessor :brain_names, :tags, :categories, :activity_levels, :status,
8
+ :omi, :omi_signals, :omi_routings, :omi_activities,
9
+ :date_from, :date_to, :enriched_only,
10
+ :include_index, :output_targets, :formats, :line_limit,
11
+ :debug_level, :dry_run, :tokens, :base_dir, :omi_dir
12
+
13
+ def initialize
14
+ @brain_names = []
15
+ @tags = []
16
+ @categories = []
17
+ @activity_levels = []
18
+ @status = 'active' # default: exclude deprecated
19
+
20
+ @omi = false
21
+ @omi_signals = []
22
+ @omi_routings = []
23
+ @omi_activities = []
24
+ @date_from = nil
25
+ @date_to = nil
26
+ @enriched_only = false
27
+
28
+ @include_index = true
29
+ @output_targets = ['clipboard'] # default to clipboard
30
+ @formats = ['content']
31
+ @line_limit = nil
32
+ @debug_level = 'none'
33
+ @dry_run = false
34
+ @tokens = false
35
+ @base_dir = Dir.pwd
36
+
37
+ @omi_dir = File.expand_path('~/dev/raw-intake/omi')
38
+ end
39
+
40
+ def brains_root
41
+ @brains_root ||= File.expand_path('~/dev/ad/brains')
42
+ end
43
+
44
+ def brains_index_path
45
+ File.join(brains_root, 'audit', 'brains-index.json')
46
+ end
47
+
48
+ def brain_query?
49
+ brain_names.any? || tags.any? || categories.any? || activity_levels.any?
50
+ end
51
+
52
+ def omi_query?
53
+ omi
54
+ end
55
+ end
56
+ end
57
+ end
@@ -13,6 +13,7 @@ module Appydave
13
13
  @format = options.format
14
14
  @working_directory = File.expand_path(options.working_directory)
15
15
  @line_limit = options.line_limit
16
+ @file_paths = options.file_paths
16
17
  end
17
18
 
18
19
  def build
@@ -23,6 +24,22 @@ module Appydave
23
24
 
24
25
  private
25
26
 
27
+ def collect_files
28
+ if @file_paths.any?
29
+ # Use file paths directly (from stdin)
30
+ @file_paths.reject { |f| excluded?(f) || File.directory?(f) }
31
+ else
32
+ # Use glob patterns
33
+ files = []
34
+ @include_patterns.each do |pattern|
35
+ Dir.glob(pattern).each do |file_path|
36
+ files << file_path unless excluded?(file_path) || File.directory?(file_path)
37
+ end
38
+ end
39
+ files
40
+ end
41
+ end
42
+
26
43
  def build_formats
27
44
  @format.split(',').map do |fmt|
28
45
  case fmt
@@ -38,13 +55,9 @@ module Appydave
38
55
  def build_content
39
56
  concatenated_content = []
40
57
 
41
- @include_patterns.each do |pattern|
42
- Dir.glob(pattern).each do |file_path|
43
- next if excluded?(file_path) || File.directory?(file_path)
44
-
45
- content = "# file: #{file_path}\n\n#{read_file_content(file_path)}"
46
- concatenated_content << content
47
- end
58
+ collect_files.each do |file_path|
59
+ content = "# file: #{file_path}\n\n#{read_file_content(file_path)}"
60
+ concatenated_content << content
48
61
  end
49
62
 
50
63
  concatenated_content.join("\n\n")
@@ -60,13 +73,9 @@ module Appydave
60
73
  def build_tree
61
74
  tree_view = {}
62
75
 
63
- @include_patterns.each do |pattern|
64
- Dir.glob(pattern).each do |file_path|
65
- next if excluded?(file_path)
66
-
67
- path_parts = file_path.split('/')
68
- insert_into_tree(tree_view, path_parts)
69
- end
76
+ collect_files.each do |file_path|
77
+ path_parts = file_path.split('/')
78
+ insert_into_tree(tree_view, path_parts)
70
79
  end
71
80
 
72
81
  build_tree_pretty(tree_view).rstrip
@@ -96,22 +105,14 @@ module Appydave
96
105
  'content' => []
97
106
  }
98
107
 
99
- # Building tree structure in JSON
100
- @include_patterns.each do |pattern|
101
- Dir.glob(pattern).each do |file_path|
102
- next if excluded?(file_path)
108
+ collect_files.each do |file_path|
109
+ path_parts = file_path.split('/')
110
+ insert_into_tree(json_output['tree'], path_parts)
103
111
 
104
- path_parts = file_path.split('/')
105
- insert_into_tree(json_output['tree'], path_parts)
106
-
107
- # Building content structure in JSON
108
- next if excluded?(file_path) || File.directory?(file_path)
109
-
110
- json_output['content'] << {
111
- 'file' => file_path,
112
- 'content' => read_file_content(file_path)
113
- }
114
- end
112
+ json_output['content'] << {
113
+ 'file' => file_path,
114
+ 'content' => read_file_content(file_path)
115
+ }
115
116
  end
116
117
 
117
118
  JSON.pretty_generate(json_output)
@@ -120,15 +121,7 @@ module Appydave
120
121
  def build_aider
121
122
  return '' unless @options.prompt
122
123
 
123
- files = []
124
- @include_patterns.each do |pattern|
125
- Dir.glob(pattern).each do |file_path|
126
- next if excluded?(file_path) || File.directory?(file_path)
127
-
128
- files << file_path
129
- end
130
- end
131
-
124
+ files = collect_files
132
125
  "aider --message \"#{@options.prompt}\" #{files.join(' ')}"
133
126
  end
134
127
 
@@ -14,6 +14,8 @@ module Appydave
14
14
  :working_directory,
15
15
  :prompt,
16
16
  :show_tokens,
17
+ :file_paths,
18
+ :stdin,
17
19
  keyword_init: true
18
20
  ) do
19
21
  def initialize(**args)
@@ -25,6 +27,8 @@ module Appydave
25
27
  self.output_target ||= []
26
28
  self.prompt ||= nil
27
29
  self.show_tokens ||= false
30
+ self.file_paths ||= []
31
+ self.stdin ||= false
28
32
  end
29
33
  end
30
34
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Appydave
4
4
  module Tools
5
- VERSION = '0.78.0'
5
+ VERSION = '0.80.0'
6
6
  end
7
7
  end
@@ -37,6 +37,10 @@ require 'appydave/tools/llm_context/options'
37
37
  require 'appydave/tools/llm_context/file_collector'
38
38
  require 'appydave/tools/llm_context/output_handler'
39
39
 
40
+ require 'appydave/tools/brain_context/options'
41
+ require 'appydave/tools/brain_context/brain_finder'
42
+ require 'appydave/tools/brain_context/omi_finder'
43
+
40
44
  require 'appydave/tools/configuration/openai'
41
45
  require 'appydave/tools/configuration/configurable'
42
46
  require 'appydave/tools/configuration/config'
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appydave-tools",
3
- "version": "0.78.0",
3
+ "version": "0.80.0",
4
4
  "description": "AppyDave YouTube Automation Tools",
5
5
  "scripts": {
6
6
  "release": "semantic-release"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appydave-tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.78.0
4
+ version: 0.80.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Cruwys
@@ -190,6 +190,8 @@ executables:
190
190
  - jump
191
191
  - llm_context
192
192
  - prompt_tools
193
+ - query_brain
194
+ - query_omi
193
195
  - subtitle_processor
194
196
  - youtube_automation
195
197
  - youtube_manager
@@ -229,6 +231,8 @@ files:
229
231
  - bin/llm_context.rb
230
232
  - bin/move_images.rb
231
233
  - bin/prompt_tools.rb
234
+ - bin/query_brain.rb
235
+ - bin/query_omi.rb
232
236
  - bin/setup
233
237
  - bin/subtitle_manager-old.rb
234
238
  - bin/subtitle_manager.rb
@@ -338,12 +342,17 @@ files:
338
342
  - exe/jump
339
343
  - exe/llm_context
340
344
  - exe/prompt_tools
345
+ - exe/query_brain
346
+ - exe/query_omi
341
347
  - exe/subtitle_processor
342
348
  - exe/youtube_automation
343
349
  - exe/youtube_manager
344
350
  - exe/zsh_history
345
351
  - images.log
346
352
  - lib/appydave/tools.rb
353
+ - lib/appydave/tools/brain_context/brain_finder.rb
354
+ - lib/appydave/tools/brain_context/omi_finder.rb
355
+ - lib/appydave/tools/brain_context/options.rb
347
356
  - lib/appydave/tools/cli_actions/_doc.md
348
357
  - lib/appydave/tools/cli_actions/base_action.rb
349
358
  - lib/appydave/tools/cli_actions/get_video_action.rb