hokipoki 0.1.2 → 0.1.3

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,828 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators'
4
+ require 'rails/generators/active_record'
5
+ require 'tty-prompt'
6
+ require 'pastel'
7
+
8
+ module HiveMind
9
+ class InstallGenerator < Rails::Generators::Base
10
+ include ActiveRecord::Generators::Migration
11
+
12
+ source_root File.expand_path('templates', __dir__)
13
+
14
+ class_option :minimal, type: :boolean, default: false, desc: 'Install minimal HiveMind setup'
15
+ class_option :full, type: :boolean, default: false, desc: 'Install complete revolutionary stack'
16
+ class_option :claude, type: :boolean, default: false, desc: 'Install HiveMind + Claude integration'
17
+ class_option :parasites, type: :boolean, default: nil, desc: 'Enable parasites system'
18
+ class_option :forge, type: :boolean, default: nil, desc: 'Enable forge components'
19
+ class_option :security, type: :boolean, default: nil, desc: 'Enable security features'
20
+ class_option :skip_migrations, type: :boolean, default: false, desc: 'Skip database migrations'
21
+ class_option :skip_config, type: :boolean, default: false, desc: 'Skip configuration files'
22
+
23
+ def initialize(*args)
24
+ super
25
+ @prompt = TTY::Prompt.new
26
+ @pastel = Pastel.new
27
+ end
28
+
29
+ def security_authentication
30
+ say "\n#{@pastel.red.bold('🔒 SECURITY AUTHENTICATION REQUIRED')}"
31
+ say @pastel.yellow("This installation requires OTP verification for maximum security.")
32
+
33
+ # Show current valid OTP for this app
34
+ current_otp = generate_current_otp
35
+ say @pastel.cyan("Current OTP for #{Rails.application.class.module_parent_name}: #{@pastel.bold(current_otp)}")
36
+ say @pastel.dim("(OTP changes every 30 seconds)")
37
+
38
+ max_attempts = 3
39
+ attempts = 0
40
+
41
+ while attempts < max_attempts
42
+ otp_code = @prompt.ask("Enter the 6-digit OTP code shown above:")
43
+
44
+ if validate_otp_code(otp_code)
45
+ say @pastel.green("✅ Authentication successful!")
46
+ return true
47
+ else
48
+ attempts += 1
49
+ remaining = max_attempts - attempts
50
+ if remaining > 0
51
+ say @pastel.red("❌ Invalid OTP code. #{remaining} attempts remaining.")
52
+ # Show refreshed OTP
53
+ current_otp = generate_current_otp
54
+ say @pastel.cyan("Updated OTP: #{@pastel.bold(current_otp)}")
55
+ else
56
+ say @pastel.red("❌ Authentication failed. Installation aborted for security.")
57
+ exit(1)
58
+ end
59
+ end
60
+ end
61
+
62
+ false
63
+ end
64
+
65
+ def welcome_message
66
+ say "\n#{@pastel.cyan.bold('🚀 Welcome to HokiPoki - Revolutionary AI Intelligence Platform')}"
67
+ say @pastel.green("Transform your Rails app with vector intelligence, universal parasites, and template-as-data architecture!")
68
+ say "\n#{@pastel.yellow('Installation Options:')}"
69
+ say " #{@pastel.blue('--minimal')} : Core vector DB + smart retrieval (minimal)"
70
+ say " #{@pastel.blue('--claude')} : HiveMind + Claude integration (recommended for Claude users)"
71
+ say " #{@pastel.blue('--full')} : Everything - HiveMind + Parasites + Forge + Security (maximum power)"
72
+ say " #{@pastel.blue('Interactive')}: Choose components (recommended)\n"
73
+ end
74
+
75
+ def gather_installation_preferences
76
+ # Security authentication required before any installation
77
+ security_authentication
78
+
79
+ return setup_minimal_installation if options[:minimal]
80
+ return setup_claude_installation if options[:claude]
81
+ return setup_full_installation if options[:full]
82
+
83
+ setup_interactive_installation
84
+ end
85
+
86
+ def validate_requirements
87
+ check_ruby_version
88
+ check_rails_version
89
+ check_database_support
90
+ check_redis_availability if @config[:redis_required]
91
+ end
92
+
93
+ def create_configuration_files
94
+ return if options[:skip_config]
95
+
96
+ say "\n#{@pastel.cyan('📝 Creating configuration files...')}"
97
+
98
+ template 'initializers/hokipoki.rb.tt', 'config/initializers/hokipoki.rb'
99
+
100
+ if @config[:lm_studio_integration]
101
+ template 'initializers/lm_studio.rb.tt', 'config/initializers/lm_studio.rb'
102
+ end
103
+
104
+ create_configuration_yml
105
+ create_brain_configurations if @config[:enable_brains]
106
+ end
107
+
108
+ def setup_database_migrations
109
+ return if options[:skip_migrations]
110
+
111
+ say "\n#{@pastel.cyan('🗄️ Setting up database migrations...')}"
112
+
113
+ # Core tables
114
+ migration_template 'migrations/enable_pgvector.rb.tt', 'db/migrate/enable_pgvector.rb'
115
+ migration_template 'migrations/create_documents.rb.tt', 'db/migrate/create_documents.rb'
116
+ migration_template 'migrations/create_intelligence_templates.rb.tt', 'db/migrate/create_intelligence_templates.rb'
117
+
118
+ # Parasite tables
119
+ if @config[:enable_parasites]
120
+ migration_template 'migrations/create_custom_parasites.rb.tt', 'db/migrate/create_custom_parasites.rb'
121
+ migration_template 'migrations/create_llm_behavioral_patterns.rb.tt', 'db/migrate/create_llm_behavioral_patterns.rb'
122
+ end
123
+
124
+ # Brain management tables
125
+ if @config[:enable_brains]
126
+ migration_template 'migrations/create_brain_configurations.rb.tt', 'db/migrate/create_brain_configurations.rb'
127
+ end
128
+
129
+ # Security tables
130
+ if @config[:enable_security]
131
+ migration_template 'migrations/create_security_audit_logs.rb.tt', 'db/migrate/create_security_audit_logs.rb'
132
+ end
133
+ end
134
+
135
+ def create_application_components
136
+ say "\n#{@pastel.cyan('🏗️ Creating application components...')}"
137
+
138
+ # Create models
139
+ template 'app/models/hokipoki/document.rb.tt', 'app/models/hokipoki/document.rb'
140
+ template 'app/models/hokipoki/intelligence_template.rb.tt', 'app/models/hokipoki/intelligence_template.rb'
141
+
142
+ if @config[:enable_parasites]
143
+ template 'app/models/hokipoki/custom_parasite.rb.tt', 'app/models/hokipoki/custom_parasite.rb'
144
+ end
145
+
146
+ # Create controllers
147
+ template 'app/controllers/hokipoki/api/documents_controller.rb.tt', 'app/controllers/hokipoki/api/documents_controller.rb'
148
+ template 'app/controllers/hokipoki/api/vector_search_controller.rb.tt', 'app/controllers/hokipoki/api/vector_search_controller.rb'
149
+
150
+ if @config[:enable_parasites]
151
+ template 'app/controllers/hokipoki/api/parasites_controller.rb.tt', 'app/controllers/hokipoki/api/parasites_controller.rb'
152
+ end
153
+
154
+ # Create services
155
+ create_service_components
156
+
157
+ # Create jobs
158
+ if @config[:background_processing]
159
+ template 'app/jobs/hokipoki/document_processor_job.rb.tt', 'app/jobs/hokipoki/document_processor_job.rb'
160
+
161
+ if @config[:enable_parasites]
162
+ template 'app/jobs/hokipoki/parasite_optimization_job.rb.tt', 'app/jobs/hokipoki/parasite_optimization_job.rb'
163
+ end
164
+ end
165
+ end
166
+
167
+ def setup_routing
168
+ say "\n#{@pastel.cyan('🛣️ Setting up routes...')}"
169
+
170
+ route_content = generate_route_content
171
+ inject_into_file 'config/routes.rb', after: "Rails.application.routes.draw do\n" do
172
+ route_content
173
+ end
174
+ end
175
+
176
+ def create_cli_tools
177
+ if @config[:enable_cli_tools]
178
+ say "\n#{@pastel.cyan('🔧 Creating CLI tools...')}"
179
+
180
+ template 'bin/hive_mind_claude.tt', 'bin/hive_mind_claude'
181
+ chmod 'bin/hive_mind_claude', 0755
182
+
183
+ if @config[:enable_security]
184
+ template 'bin/hive_mind_secure.tt', 'bin/hive_mind_secure'
185
+ chmod 'bin/hive_mind_secure', 0755
186
+ end
187
+ end
188
+ end
189
+
190
+ def create_sample_data
191
+ if @config[:create_samples]
192
+ say "\n#{@pastel.cyan('📚 Creating sample data and templates...')}"
193
+
194
+ create_sample_templates
195
+ create_sample_brains if @config[:enable_brains]
196
+ create_sample_parasites if @config[:enable_parasites]
197
+ end
198
+ end
199
+
200
+ def run_post_install_tasks
201
+ say "\n#{@pastel.cyan('⚙️ Running post-installation tasks...')}"
202
+
203
+ # Run migrations
204
+ unless options[:skip_migrations]
205
+ run 'rails db:create' unless database_exists?
206
+ run 'rails db:migrate'
207
+ end
208
+
209
+ # Display HIVE_MIND banner after database setup
210
+ display_hive_mind_installation
211
+
212
+ # Install dependencies
213
+ if @config[:auto_install_dependencies]
214
+ run 'bundle install'
215
+ run 'yarn install' if @config[:frontend_assets] && File.exist?('package.json')
216
+ end
217
+
218
+ # Display component banners as they're installed
219
+ display_component_installations
220
+
221
+ # Seed initial data
222
+ if @config[:seed_initial_data]
223
+ run 'rails hokipoki:seed_templates'
224
+ run 'rails hokipoki:seed_brains' if @config[:enable_brains]
225
+ end
226
+
227
+ # Claude-specific setup
228
+ if @config[:enable_claude_integration]
229
+ setup_claude_integration
230
+ end
231
+
232
+ # Auto-activate Claude script
233
+ if @config[:auto_activate_claude_script]
234
+ run_claude_activation_script
235
+ end
236
+ end
237
+
238
+ def display_completion_message
239
+ say "\n#{@pastel.green.bold('✅ HokiPoki installation completed successfully!')}"
240
+ say "\n#{@pastel.cyan.bold('🎯 Quick Start Guide:')}"
241
+
242
+ if @config[:enable_parasites]
243
+ say " #{@pastel.yellow('Generate a parasite:')}"
244
+ say " rails g hive_mind:parasite claude_cli claude --optimize"
245
+ end
246
+
247
+ if @config[:enable_brains]
248
+ say " #{@pastel.yellow('Create a brain:')}"
249
+ say " rails g hive_mind:brain training_js --domain=javascript"
250
+ end
251
+
252
+ say " #{@pastel.yellow('Use in your code:')}"
253
+ say " facts = Hokipoki.retrieve_facts('how to implement authentication')"
254
+
255
+ if @config[:enable_parasites]
256
+ say " parasite = Hokipoki.generate_parasite(tool: 'claude_cli', model: 'claude')"
257
+ end
258
+
259
+ say "\n#{@pastel.blue.bold('📖 Documentation:')}"
260
+ say " - Configuration: config/initializers/hokipoki.rb"
261
+ say " - API Endpoints: /hokipoki/api/"
262
+ say " - Admin Dashboard: /hokipoki/admin/ (if enabled)"
263
+
264
+ if @config[:enable_security]
265
+ say "\n#{@pastel.red.bold('🔒 Security:')}"
266
+ say " - API authentication enabled"
267
+ say " - Audit logging configured"
268
+ say " - Check config/initializers/hokipoki.rb for security settings"
269
+ end
270
+
271
+ # Claude-specific completion message
272
+ if @config[:enable_claude_integration]
273
+ display_claude_completion_message
274
+ end
275
+
276
+ display_next_steps
277
+ end
278
+
279
+ private
280
+
281
+ def generate_current_otp
282
+ current_time = Time.now.to_i / 30
283
+ secret_key = "HOKIPOKI_SECURITY_#{Rails.application.class.module_parent_name}"
284
+
285
+ require 'digest'
286
+ Digest::SHA256.hexdigest("#{current_time}#{secret_key}").last(6)
287
+ end
288
+
289
+ def validate_otp_code(otp_code)
290
+ # Basic validation: 6 digits
291
+ return false unless otp_code =~ /^\d{6}$/
292
+
293
+ # For maximum security, we could integrate with actual OTP providers
294
+ # For now, we'll use a time-based validation that changes every 30 seconds
295
+ current_time = Time.now.to_i / 30
296
+ secret_key = "HOKIPOKI_SECURITY_#{Rails.application.class.module_parent_name}"
297
+
298
+ # Generate expected OTP based on time and app-specific secret
299
+ require 'digest'
300
+ expected_otp = Digest::SHA256.hexdigest("#{current_time}#{secret_key}").last(6)
301
+
302
+ # Also check previous 30-second window for clock drift tolerance
303
+ previous_time = current_time - 1
304
+ previous_otp = Digest::SHA256.hexdigest("#{previous_time}#{secret_key}").last(6)
305
+
306
+ otp_code == expected_otp || otp_code == previous_otp
307
+ end
308
+
309
+ def display_hive_mind_installation
310
+ require 'hokipoki/feedback/display_manager'
311
+
312
+ feedback = Hokipoki::Feedback::DisplayManager.instance
313
+ document_count = get_document_count
314
+ feedback.hive_mind_installed(document_count)
315
+ end
316
+
317
+ def display_component_installations
318
+ require 'hokipoki/feedback/display_manager'
319
+
320
+ feedback = Hokipoki::Feedback::DisplayManager.instance
321
+
322
+ # Display banners for enabled components
323
+ if @config[:enable_parasites]
324
+ feedback.parasite_installed
325
+ end
326
+
327
+ if @config[:enable_forge]
328
+ feedback.forge_installed
329
+ end
330
+
331
+ # Final installation complete banner
332
+ installed_components = []
333
+ installed_components << 'hive_mind'
334
+ installed_components << 'parasite' if @config[:enable_parasites]
335
+ installed_components << 'forge' if @config[:enable_forge]
336
+ installed_components << 'security' if @config[:enable_security]
337
+ installed_components << 'claude' if @config[:enable_claude_integration]
338
+
339
+ feedback.installation_complete(installed_components)
340
+ end
341
+
342
+ def get_document_count
343
+ return 0 unless File.exist?('app/models/document.rb')
344
+
345
+ begin
346
+ # Try to get document count if database is accessible
347
+ require Rails.root.join('config/environment') if defined?(Rails.root)
348
+ Document.count if defined?(Document)
349
+ rescue
350
+ 0
351
+ end
352
+ end
353
+
354
+ def setup_claude_integration
355
+ say "\n#{@pastel.cyan('🧠 Setting up Claude integration...')}"
356
+
357
+ # Generate Claude-specific parasite
358
+ say " 📝 Generating Claude parasite..."
359
+ invoke 'hive_mind:parasite', ['claude_cli', 'claude'], {
360
+ optimize: true,
361
+ behavioral_analysis: true,
362
+ auto_activate: true
363
+ }
364
+
365
+ # Create Claude auto-loader initializer
366
+ create_claude_auto_loader_initializer
367
+
368
+ # Create Claude connection status command
369
+ create_claude_status_command
370
+
371
+ say " ✓ Claude integration configured"
372
+ end
373
+
374
+ def run_claude_activation_script
375
+ say "\n#{@pastel.cyan('🚀 Running Claude activation script...')}"
376
+
377
+ script_paths = [
378
+ Rails.root.join('ACTIVATE_10X_CLAUDE.sh'),
379
+ Rails.root.join('bin', 'ACTIVATE_10X_CLAUDE.sh')
380
+ ]
381
+
382
+ script_path = script_paths.find { |path| File.exist?(path) }
383
+
384
+ if script_path
385
+ say " 🔧 Executing #{File.basename(script_path)}..."
386
+
387
+ # Make executable
388
+ File.chmod(0755, script_path)
389
+
390
+ # Run script
391
+ success = system("cd #{Rails.root} && #{script_path}")
392
+
393
+ if success
394
+ say " #{@pastel.green('✓ Activation script completed successfully')}"
395
+ else
396
+ say " #{@pastel.yellow('⚠ Activation script completed with warnings')}"
397
+ end
398
+ else
399
+ say " #{@pastel.yellow('⚠ ACTIVATE_10X_CLAUDE.sh not found')}"
400
+ say " #{@pastel.dim(' You can copy it from your existing HiveMind installation')}"
401
+ end
402
+ end
403
+
404
+ def create_claude_auto_loader_initializer
405
+ initializer_content = <<~RUBY
406
+ # Claude Auto-Loader Initializer
407
+ # Automatically detects Claude CLI and loads HiveMind integration
408
+
409
+ if defined?(Hokipoki) && Rails.env.development?
410
+ # Load Claude integration modules
411
+ require 'hokipoki/claude/auto_loader'
412
+ require 'hokipoki/claude/connection_manager'
413
+ require 'hokipoki/claude/parasite'
414
+
415
+ # Auto-detect and load Claude integration
416
+ Rails.application.config.after_initialize do
417
+ if Hokipoki::Claude::AutoLoader.claude_cli_detected?
418
+ Rails.logger.info "🔍 Claude CLI detected - Auto-loading HiveMind integration"
419
+ Hokipoki::Claude::AutoLoader.force_load!
420
+ end
421
+ end
422
+ end
423
+ RUBY
424
+
425
+ create_file 'config/initializers/claude_auto_loader.rb', initializer_content
426
+ end
427
+
428
+ def create_claude_status_command
429
+ command_content = <<~RUBY
430
+ #!/usr/bin/env ruby
431
+
432
+ # Claude HiveMind Status Command
433
+ # Usage: ./bin/claude_status
434
+
435
+ require_relative '../config/environment'
436
+
437
+ if defined?(Hokipoki::Claude::ConnectionManager)
438
+ connection_manager = Hokipoki::Claude::ConnectionManager.instance
439
+ parasite = Hokipoki::Claude::Parasite.instance
440
+
441
+ puts "\\n🧠 Claude ↔ HiveMind Status"
442
+ puts "=" * 40
443
+
444
+ connection_manager.display_connection_info
445
+ parasite.display_status
446
+
447
+ # Test vector retrieval
448
+ puts "\\n🧪 Testing vector retrieval..."
449
+ if connection_manager.test_vector_retrieval("test query")
450
+ puts "✅ All systems operational!"
451
+ else
452
+ puts "❌ Issues detected - check configuration"
453
+ end
454
+ else
455
+ puts "❌ Claude integration not installed"
456
+ puts "Run: rails g hive_mind:install --claude"
457
+ end
458
+ RUBY
459
+
460
+ create_file 'bin/claude_status', command_content
461
+ chmod 'bin/claude_status', 0755
462
+ end
463
+
464
+ def display_claude_completion_message
465
+ say "\n#{@pastel.cyan.bold('🧠 Claude Integration Ready!')}"
466
+ say "#{@pastel.green('✓ Claude parasite installed and activated')}"
467
+ say "#{@pastel.green('✓ Auto-loader configured for Claude CLI detection')}"
468
+ say "#{@pastel.green('✓ Vector database connection established')}"
469
+
470
+ if File.exist?(Rails.root.join('ACTIVATE_10X_CLAUDE.sh'))
471
+ say "#{@pastel.green('✓ ACTIVATE_10X_CLAUDE.sh executed successfully')}"
472
+ end
473
+
474
+ say "\n#{@pastel.yellow.bold('🎯 Claude Quick Commands:')}"
475
+ say "#{@pastel.dim(' Check status: ./bin/claude_status')}"
476
+ say "#{@pastel.dim(' Test retrieval: Hokipoki.retrieve_facts(\"your query\")')}"
477
+ say "#{@pastel.dim(' Force connect: Hokipoki::Claude::AutoLoader.force_load!')}"
478
+
479
+ say "\n#{@pastel.magenta('🚀 Your Claude CLI now has AI superpowers!')}"
480
+ say "#{@pastel.dim('Every query will be enhanced with project-specific context.')}"
481
+ end
482
+
483
+ def display_next_steps
484
+ say "\n#{@pastel.blue.bold('🎯 Next Steps:')}"
485
+
486
+ if @config[:enable_claude_integration]
487
+ say " 1. #{@pastel.cyan('Start Claude CLI')} - HiveMind will auto-connect"
488
+ say " 2. #{@pastel.cyan('Check status:')} ./bin/claude_status"
489
+ say " 3. #{@pastel.cyan('Test integration:')} Ask Claude any coding question"
490
+ end
491
+
492
+ def setup_minimal_installation
493
+ say @pastel.cyan("\n🎯 Setting up minimal HiveMind installation...")
494
+
495
+ @config = {
496
+ enable_parasites: false,
497
+ enable_forge: false,
498
+ enable_security: false,
499
+ enable_brains: true,
500
+ lm_studio_integration: true,
501
+ background_processing: false,
502
+ redis_required: false,
503
+ enable_cli_tools: false,
504
+ create_samples: false,
505
+ auto_install_dependencies: true,
506
+ seed_initial_data: true,
507
+ frontend_assets: false
508
+ }
509
+ end
510
+
511
+ def setup_claude_installation
512
+ say @pastel.cyan("\n🧠 Setting up HiveMind + Claude integration...")
513
+
514
+ @config = {
515
+ enable_parasites: true, # Need parasites for Claude
516
+ enable_forge: false, # Not needed for Claude basic
517
+ enable_security: true, # Security always good
518
+ enable_brains: true, # Multi-brain support
519
+ enable_claude_integration: true, # Special Claude features
520
+ lm_studio_integration: true, # For embedding generation
521
+ background_processing: false, # Not needed for basic Claude
522
+ redis_required: true, # For caching vector results
523
+ enable_cli_tools: true, # Claude CLI tools
524
+ create_samples: true, # Sample Claude parasites
525
+ auto_install_dependencies: true,
526
+ seed_initial_data: true,
527
+ frontend_assets: false, # No UI needed for Claude
528
+ enable_workshop: false, # Not needed for basic
529
+ enable_behavioral_analysis: true, # For Claude optimization
530
+ auto_activate_claude_script: true # Auto-run ACTIVATE_10X_CLAUDE.sh
531
+ }
532
+ end
533
+
534
+ def setup_full_installation
535
+ say @pastel.cyan("\n🚀 Setting up complete revolutionary stack...")
536
+
537
+ @config = {
538
+ enable_parasites: true,
539
+ enable_forge: true,
540
+ enable_security: true,
541
+ enable_brains: true,
542
+ enable_claude_integration: true,
543
+ lm_studio_integration: true,
544
+ background_processing: true,
545
+ redis_required: true,
546
+ enable_cli_tools: true,
547
+ create_samples: true,
548
+ auto_install_dependencies: true,
549
+ seed_initial_data: true,
550
+ frontend_assets: true,
551
+ enable_workshop: true,
552
+ enable_behavioral_analysis: true,
553
+ auto_activate_claude_script: true
554
+ }
555
+ end
556
+
557
+ def setup_interactive_installation
558
+ say @pastel.cyan("\n🎮 Interactive installation - Choose your components:")
559
+
560
+ @config = {}
561
+
562
+ # Core components
563
+ @config[:enable_parasites] = @prompt.yes?("Enable Universal Parasites? (94% code reduction)", default: true)
564
+ @config[:enable_forge] = @prompt.yes?("Enable Generator Forge? (heavyweight processing)", default: false)
565
+ @config[:enable_security] = @prompt.yes?("Enable enterprise security features?", default: true)
566
+ @config[:enable_brains] = @prompt.yes?("Enable multi-brain system?", default: true)
567
+
568
+ # Integration options
569
+ @config[:lm_studio_integration] = @prompt.yes?("Configure LM Studio integration?", default: true)
570
+ @config[:background_processing] = @prompt.yes?("Enable background job processing?", default: @config[:enable_forge])
571
+ @config[:redis_required] = @config[:background_processing] || @prompt.yes?("Use Redis for caching?", default: true)
572
+
573
+ # Additional features
574
+ @config[:enable_cli_tools] = @prompt.yes?("Create CLI tools (bin/hive_mind_claude)?", default: true)
575
+ @config[:create_samples] = @prompt.yes?("Create sample data and templates?", default: true)
576
+ @config[:frontend_assets] = @config[:enable_forge] && @prompt.yes?("Include frontend workshop interface?", default: false)
577
+
578
+ # Installation preferences
579
+ @config[:auto_install_dependencies] = @prompt.yes?("Auto-install dependencies (bundle install)?", default: true)
580
+ @config[:seed_initial_data] = @prompt.yes?("Seed initial templates and data?", default: true)
581
+
582
+ # Advanced features (only if forge is enabled)
583
+ if @config[:enable_forge]
584
+ @config[:enable_workshop] = @prompt.yes?("Enable LLM refinement workshop?", default: true)
585
+ @config[:enable_behavioral_analysis] = @prompt.yes?("Enable LLM behavioral analysis?", default: true)
586
+ end
587
+
588
+ display_configuration_summary
589
+ end
590
+
591
+ def display_configuration_summary
592
+ say "\n#{@pastel.yellow.bold('📋 Installation Configuration:')}"
593
+ say " #{component_status('Universal Parasites', @config[:enable_parasites])}"
594
+ say " #{component_status('Generator Forge', @config[:enable_forge])}"
595
+ say " #{component_status('Security Features', @config[:enable_security])}"
596
+ say " #{component_status('Multi-Brain System', @config[:enable_brains])}"
597
+ say " #{component_status('LM Studio Integration', @config[:lm_studio_integration])}"
598
+ say " #{component_status('Background Processing', @config[:background_processing])}"
599
+ say " #{component_status('Redis Caching', @config[:redis_required])}"
600
+ say " #{component_status('CLI Tools', @config[:enable_cli_tools])}"
601
+
602
+ unless @prompt.yes?("\nProceed with this configuration?", default: true)
603
+ say @pastel.red("Installation cancelled.")
604
+ exit 1
605
+ end
606
+ end
607
+
608
+ def component_status(name, enabled)
609
+ status = enabled ? @pastel.green('✓ Enabled') : @pastel.dim('○ Disabled')
610
+ "#{name.ljust(25)} #{status}"
611
+ end
612
+
613
+ def check_ruby_version
614
+ required_version = Gem::Version.new('3.0.0')
615
+ current_version = Gem::Version.new(RUBY_VERSION)
616
+
617
+ if current_version < required_version
618
+ say @pastel.red("❌ Ruby #{required_version} or higher required. Current: #{current_version}")
619
+ exit 1
620
+ end
621
+ end
622
+
623
+ def check_rails_version
624
+ required_version = Gem::Version.new('7.0.0')
625
+ current_version = Gem::Version.new(Rails::VERSION::STRING)
626
+
627
+ if current_version < required_version
628
+ say @pastel.red("❌ Rails #{required_version} or higher required. Current: #{current_version}")
629
+ exit 1
630
+ end
631
+ end
632
+
633
+ def check_database_support
634
+ adapter = ActiveRecord::Base.connection.adapter_name.downcase
635
+
636
+ unless adapter.include?('postgresql')
637
+ say @pastel.red("❌ PostgreSQL required for vector similarity. Current adapter: #{adapter}")
638
+ say @pastel.yellow("Please configure PostgreSQL and install the 'pg' gem.")
639
+ exit 1
640
+ end
641
+
642
+ # Check for pgvector extension
643
+ unless pgvector_available?
644
+ say @pastel.yellow("⚠️ pgvector extension not detected. It will be installed during migration.")
645
+ end
646
+ end
647
+
648
+ def check_redis_availability
649
+ return unless @config[:redis_required]
650
+
651
+ begin
652
+ require 'redis'
653
+ redis = Redis.new
654
+ redis.ping
655
+ say @pastel.green("✓ Redis connection successful")
656
+ rescue LoadError
657
+ say @pastel.yellow("⚠️ Redis gem not found. Add 'gem \"redis\"' to your Gemfile.")
658
+ rescue => e
659
+ say @pastel.yellow("⚠️ Redis connection failed: #{e.message}")
660
+ say @pastel.yellow(" Make sure Redis is running or update config/initializers/hokipoki.rb")
661
+ end
662
+ end
663
+
664
+ def pgvector_available?
665
+ ActiveRecord::Base.connection.execute("SELECT 1 FROM pg_extension WHERE extname = 'vector'").any?
666
+ rescue
667
+ false
668
+ end
669
+
670
+ def database_exists?
671
+ ActiveRecord::Base.connection
672
+ true
673
+ rescue ActiveRecord::NoDatabaseError
674
+ false
675
+ end
676
+
677
+ def create_configuration_yml
678
+ config_data = {
679
+ 'development' => generate_config_hash('development'),
680
+ 'test' => generate_config_hash('test'),
681
+ 'production' => generate_config_hash('production')
682
+ }
683
+
684
+ create_file 'config/hokipoki.yml' do
685
+ YAML.dump(config_data)
686
+ end
687
+ end
688
+
689
+ def generate_config_hash(env)
690
+ base_config = {
691
+ 'vector_dimensions' => 768,
692
+ 'token_budget_default' => 1500,
693
+ 'enable_parasites' => @config[:enable_parasites],
694
+ 'enable_forge' => @config[:enable_forge],
695
+ 'enable_behavioral_analysis' => @config[:enable_behavioral_analysis] || false,
696
+ 'enable_template_optimization' => true,
697
+ 'template_caching' => true,
698
+ 'context_compression' => true,
699
+ 'default_brain' => 'default_brain',
700
+ 'auto_brain_switching' => @config[:enable_brains]
701
+ }
702
+
703
+ case env
704
+ when 'development'
705
+ base_config.merge({
706
+ 'lm_studio_url' => 'http://localhost:1236',
707
+ 'redis_url' => 'redis://localhost:6379/0',
708
+ 'audit_logging' => false,
709
+ 'rate_limiting' => false
710
+ })
711
+ when 'test'
712
+ base_config.merge({
713
+ 'lm_studio_url' => 'http://localhost:1236',
714
+ 'redis_url' => 'redis://localhost:6379/1',
715
+ 'audit_logging' => false,
716
+ 'rate_limiting' => false,
717
+ 'template_caching' => false
718
+ })
719
+ when 'production'
720
+ base_config.merge({
721
+ 'lm_studio_url' => '<%= ENV["LM_STUDIO_URL"] %>',
722
+ 'redis_url' => '<%= ENV["REDIS_URL"] %>',
723
+ 'audit_logging' => @config[:enable_security],
724
+ 'rate_limiting' => @config[:enable_security],
725
+ 'api_authentication' => @config[:enable_security]
726
+ })
727
+ end
728
+ end
729
+
730
+ def create_brain_configurations
731
+ say " 📧 Creating brain configurations..."
732
+
733
+ directory 'config/brains', 'config/brains'
734
+ end
735
+
736
+ def create_service_components
737
+ say " 🔧 Creating service components..."
738
+
739
+ template 'app/services/hokipoki/template_versioning_service.rb.tt', 'app/services/hokipoki/template_versioning_service.rb'
740
+ template 'app/services/hokipoki/template_performance_tracker.rb.tt', 'app/services/hokipoki/template_performance_tracker.rb'
741
+
742
+ if @config[:enable_security]
743
+ template 'app/services/hokipoki/security_audit_service.rb.tt', 'app/services/hokipoki/security_audit_service.rb'
744
+ end
745
+ end
746
+
747
+ def generate_route_content
748
+ routes = []
749
+ routes << "\n # HokiPoki Routes"
750
+ routes << " mount Hokipoki::Engine => '/hokipoki'"
751
+ routes << ""
752
+ routes << " namespace :hokipoki do"
753
+ routes << " namespace :api do"
754
+ routes << " resources :documents, only: [:index, :show, :create]"
755
+ routes << " resources :vector_search, only: [:create]"
756
+
757
+ if @config[:enable_parasites]
758
+ routes << " resources :parasites, only: [:index, :show, :create, :update]"
759
+ end
760
+
761
+ routes << " end"
762
+
763
+ if @config[:enable_forge] && @config[:frontend_assets]
764
+ routes << ""
765
+ routes << " namespace :admin do"
766
+ routes << " resources :dashboard, only: [:index]"
767
+ routes << " resources :templates"
768
+ routes << " resources :workshop, only: [:index, :show]" if @config[:enable_workshop]
769
+ routes << " end"
770
+ end
771
+
772
+ routes << " end\n"
773
+
774
+ routes.join("\n")
775
+ end
776
+
777
+ def create_sample_templates
778
+ template 'samples/templates/smart_retrieval_template.yml.tt', 'db/seeds/templates/smart_retrieval_template.yml'
779
+
780
+ if @config[:enable_parasites]
781
+ template 'samples/templates/claude_parasite_template.yml.tt', 'db/seeds/templates/claude_parasite_template.yml'
782
+ end
783
+ end
784
+
785
+ def create_sample_brains
786
+ template 'samples/brains/default_brain.yml.tt', 'db/seeds/brains/default_brain.yml'
787
+ template 'samples/brains/training_brain_js.yml.tt', 'db/seeds/brains/training_brain_js.yml'
788
+ end
789
+
790
+ def create_sample_parasites
791
+ template 'samples/parasites/claude_cli_parasite.rb.tt', 'db/seeds/parasites/claude_cli_parasite.rb'
792
+ end
793
+
794
+ def display_next_steps
795
+ say "\n#{@pastel.blue.bold('🎯 Next Steps:')}"
796
+
797
+ if @config[:lm_studio_integration]
798
+ say " 1. Start LM Studio and load your preferred model"
799
+ say " 2. Update LM Studio URL in config/initializers/hokipoki.rb if needed"
800
+ end
801
+
802
+ if @config[:redis_required]
803
+ say " 3. Ensure Redis is running for background processing"
804
+ end
805
+
806
+ if @config[:enable_parasites]
807
+ say " 4. Generate your first parasite: rails g hive_mind:parasite claude_cli claude"
808
+ end
809
+
810
+ say " 5. Start your Rails server and visit /hokipoki/api for API endpoints"
811
+
812
+ if @config[:frontend_assets]
813
+ say " 6. Visit /hokipoki/admin/dashboard for the management interface"
814
+ end
815
+
816
+ say "\n#{@pastel.magenta.bold('🌟 Advanced Features:')}"
817
+ say " - Template optimization: Hokipoki::IntelligenceTemplate.optimize_all!"
818
+ say " - Parasite generation: Hokipoki.generate_parasite(tool: 'tool', model: 'model')" if @config[:enable_parasites]
819
+ say " - System status: Hokipoki.system_status"
820
+
821
+ say "\n#{@pastel.green('Happy coding with HokiPoki! 🚀')}"
822
+ end
823
+
824
+ def self.next_migration_number(dirname)
825
+ ActiveRecord::Generators::Base.next_migration_number(dirname)
826
+ end
827
+ end
828
+ end