hokipoki 0.3.4 → 0.5.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.
@@ -0,0 +1,279 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators'
4
+
5
+ module Hokipoki
6
+ module Generators
7
+ # Project Scanner Generator - Scans and vectorizes project files
8
+ # Command: rails g hokipoki:scan_project
9
+ class ScanProjectGenerator < Rails::Generators::Base
10
+ source_root File.expand_path('templates', __dir__)
11
+
12
+ class_option :force_rescan, type: :boolean, default: false,
13
+ desc: 'Force rescan of all files even if already processed'
14
+
15
+ class_option :file_patterns, type: :array, default: ['**/*.rb', '**/*.js', '**/*.erb', '**/*.yml'],
16
+ desc: 'File patterns to scan'
17
+
18
+ class_option :exclude_paths, type: :array, default: ['node_modules', 'vendor', 'log', 'tmp', '.git'],
19
+ desc: 'Paths to exclude from scanning'
20
+
21
+ class_option :show_progress, type: :boolean, default: true,
22
+ desc: 'Show detailed progress during scanning'
23
+
24
+ def display_banner
25
+ say "\nšŸ” HOKIPOKI PROJECT SCANNER", :cyan
26
+ say "=" * 50, :cyan
27
+ say "Scanning project files for vector intelligence...", :white
28
+ say "This will create a vector database of your project's knowledge.", :yellow
29
+ say ""
30
+ end
31
+
32
+ def validate_environment
33
+ unless defined?(Rails)
34
+ say "āŒ Rails environment required", :red
35
+ say "Please run this generator from a Rails application directory.", :yellow
36
+ exit(1)
37
+ end
38
+
39
+ say "āœ… Rails environment detected: #{Rails.env}", :green
40
+ say "šŸ“ Project root: #{Rails.root}", :white
41
+ end
42
+
43
+ def scan_and_vectorize_project
44
+ require_hokipoki_components
45
+
46
+ # Initialize components
47
+ vector_engine = Hokipoki::VectorEngine.instance
48
+ fact_extractor = Hokipoki::AtomicFactExtractor.new
49
+
50
+ # Get project files
51
+ files_to_scan = find_project_files
52
+
53
+ if files_to_scan.empty?
54
+ say "āš ļø No files found to scan", :yellow
55
+ return
56
+ end
57
+
58
+ say "\nšŸŽÆ SCANNING STRATEGY:", :cyan
59
+ say " šŸ“‚ Files to process: #{files_to_scan.length}", :white
60
+ say " šŸ” File patterns: #{options[:file_patterns].join(', ')}", :white
61
+ say " āŒ Excluded paths: #{options[:exclude_paths].join(', ')}", :white
62
+ say ""
63
+
64
+ # Process files with visible progress
65
+ processed_files = 0
66
+ total_facts = 0
67
+ start_time = Time.current
68
+
69
+ files_to_scan.each_with_index do |file_path, index|
70
+ begin
71
+ # Show progress
72
+ if options[:show_progress]
73
+ progress_percent = ((index + 1).to_f / files_to_scan.length * 100).round(1)
74
+ say "🧠 [#{index + 1}/#{files_to_scan.length}] (#{progress_percent}%) #{relative_path(file_path)}", :cyan
75
+ end
76
+
77
+ # Check if file should be rescanned
78
+ if should_process_file?(file_path)
79
+ # Read and extract facts
80
+ content = File.read(file_path)
81
+ next if content.strip.empty?
82
+
83
+ # Extract atomic facts
84
+ facts = fact_extractor.extract_facts(
85
+ content,
86
+ source_file: file_path,
87
+ metadata: {
88
+ file_type: File.extname(file_path),
89
+ file_size: content.bytesize,
90
+ scan_session: Time.current.iso8601
91
+ }
92
+ )
93
+
94
+ # Store in vector engine
95
+ vector_id = vector_engine.store_template_vector(
96
+ content,
97
+ file_path,
98
+ {
99
+ facts_count: facts.length,
100
+ processing_time: Time.current.iso8601
101
+ }
102
+ )
103
+
104
+ processed_files += 1
105
+ total_facts += facts.length
106
+
107
+ if options[:show_progress]
108
+ say " āœ… #{facts.length} facts extracted", :green
109
+ end
110
+
111
+ else
112
+ if options[:show_progress]
113
+ say " ā­ļø Skipped (already processed)", :yellow
114
+ end
115
+ end
116
+
117
+ rescue => e
118
+ say " āŒ Error processing #{file_path}: #{e.message}", :red
119
+ next
120
+ end
121
+ end
122
+
123
+ # Display completion summary
124
+ display_completion_summary(processed_files, total_facts, start_time)
125
+
126
+ # Create or update configuration
127
+ create_hokipoki_config(processed_files, total_facts)
128
+
129
+ # Display vector engine statistics
130
+ display_vector_statistics(vector_engine)
131
+ end
132
+
133
+ def create_initializer
134
+ say "\nšŸ“ CREATING INITIALIZER:", :cyan
135
+
136
+ create_file "config/initializers/hokipoki_scanner.rb", <<~RUBY
137
+ # Hokipoki Project Scanner Configuration
138
+ # Generated by rails g hokipoki:scan_project
139
+
140
+ if Rails.env.development?
141
+ Rails.application.config.after_initialize do
142
+ # Auto-scan new files when Rails starts
143
+ if defined?(Hokipoki::VectorEngine)
144
+ Thread.new do
145
+ sleep(2) # Let Rails fully initialize
146
+
147
+ vector_engine = Hokipoki::VectorEngine.instance
148
+
149
+ # Display scanner status
150
+ stats = vector_engine.statistics
151
+ puts "\\n🧠 HOKIPOKI SCANNER STATUS:"
152
+ puts " šŸ“Š Total vectors: \#{stats[:total_vectors]}"
153
+ puts " šŸ—œļø Avg compression: \#{stats[:average_compression]}%"
154
+ puts " āœ… Success rate: \#{stats[:success_rate]}%"
155
+ puts ""
156
+
157
+ # Auto-scan if Claude is detected
158
+ if Hokipoki.claude_parasite_active?
159
+ puts "🦠 CLAUDE DETECTED: Vector intelligence ready"
160
+ puts "šŸ“” Parasite attached to project knowledge base"
161
+ puts ""
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
167
+ RUBY
168
+
169
+ say "āœ… Created config/initializers/hokipoki_scanner.rb", :green
170
+ end
171
+
172
+ def display_next_steps
173
+ say "\nšŸŽ‰ PROJECT SCAN COMPLETE!", :green
174
+ say "=" * 50, :green
175
+ say ""
176
+ say "šŸ“‹ NEXT STEPS:", :cyan
177
+ say "1. šŸ”„ Restart Rails server to load vector intelligence", :white
178
+ say "2. 🦠 Run: rails g hokipoki:attach_parasite", :white
179
+ say "3. 🧠 Start Claude Code CLI to activate parasite", :white
180
+ say "4. ✨ Enjoy 10x enhanced Claude responses!", :white
181
+ say ""
182
+ say "šŸ“Š Vector database location: ~/.hokipoki/vectors.db", :yellow
183
+ say "šŸ”§ Configuration: config/initializers/hokipoki_scanner.rb", :yellow
184
+ say ""
185
+ end
186
+
187
+ private
188
+
189
+ def require_hokipoki_components
190
+ begin
191
+ require 'hokipoki/vector_engine'
192
+ require 'hokipoki/atomic_fact_extractor'
193
+ rescue LoadError => e
194
+ say "āŒ Failed to load Hokipoki components: #{e.message}", :red
195
+ say "Make sure hokipoki gem is properly installed", :yellow
196
+ exit(1)
197
+ end
198
+ end
199
+
200
+ def find_project_files
201
+ files = []
202
+
203
+ options[:file_patterns].each do |pattern|
204
+ pattern_files = Dir.glob(File.join(Rails.root, pattern))
205
+ files.concat(pattern_files)
206
+ end
207
+
208
+ # Filter out excluded paths
209
+ filtered_files = files.reject do |file|
210
+ options[:exclude_paths].any? { |excluded| file.include?(excluded) }
211
+ end
212
+
213
+ # Remove duplicates and ensure files exist
214
+ filtered_files.uniq.select { |file| File.file?(file) }
215
+ end
216
+
217
+ def should_process_file?(file_path)
218
+ # Always process if force_rescan is true
219
+ return true if options[:force_rescan]
220
+
221
+ # Check if file has been modified since last scan
222
+ # For now, always process (could add timestamp checking later)
223
+ true
224
+ end
225
+
226
+ def relative_path(file_path)
227
+ file_path.gsub(Rails.root.to_s + '/', '')
228
+ end
229
+
230
+ def display_completion_summary(processed_files, total_facts, start_time)
231
+ duration = Time.current - start_time
232
+
233
+ say "\nšŸ“Š SCAN RESULTS:", :cyan
234
+ say "=" * 30, :cyan
235
+ say "ā±ļø Total time: #{duration.round(2)} seconds", :white
236
+ say "šŸ“ Files processed: #{processed_files}", :white
237
+ say "šŸ”¬ Facts extracted: #{total_facts}", :white
238
+ say "šŸ“ˆ Avg facts per file: #{total_facts > 0 ? (total_facts.to_f / processed_files).round(1) : 0}", :white
239
+ say "⚔ Processing rate: #{(processed_files.to_f / duration).round(1)} files/sec", :white
240
+ say ""
241
+ end
242
+
243
+ def create_hokipoki_config(processed_files, total_facts)
244
+ config_dir = File.expand_path('~/.hokipoki')
245
+ FileUtils.mkdir_p(config_dir) unless Dir.exist?(config_dir)
246
+
247
+ config_file = File.join(config_dir, 'project_config.yml')
248
+ config_data = {
249
+ project_name: Rails.application.class.module_parent_name,
250
+ project_path: Rails.root.to_s,
251
+ last_scan: Time.current.iso8601,
252
+ files_processed: processed_files,
253
+ facts_extracted: total_facts,
254
+ scan_options: {
255
+ file_patterns: options[:file_patterns],
256
+ exclude_paths: options[:exclude_paths]
257
+ }
258
+ }
259
+
260
+ File.write(config_file, config_data.to_yaml)
261
+ say "šŸ“ Updated project config: #{config_file}", :green
262
+ end
263
+
264
+ def display_vector_statistics(vector_engine)
265
+ stats = vector_engine.statistics
266
+
267
+ say "\n🧠 VECTOR ENGINE STATISTICS:", :cyan
268
+ say "=" * 35, :cyan
269
+ say "šŸ“Š Total vectors: #{stats[:total_vectors]}", :white
270
+ say "āœ… Success rate: #{stats[:success_rate]}%", :white
271
+ say "šŸ—œļø Avg compression: #{stats[:average_compression]}%", :white
272
+ say "šŸ’¾ Cache size: #{stats[:cache_size]} entries", :white
273
+ say "🧠 Learning patterns: #{stats[:learning_patterns]}", :white
274
+ say "šŸ’æ Database size: #{(stats[:database_size] / 1024.0).round(2)} KB", :white
275
+ say ""
276
+ end
277
+ end
278
+ end
279
+ end