active_canvas 0.0.1

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.
Files changed (80) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +318 -0
  4. data/Rakefile +6 -0
  5. data/app/assets/javascripts/active_canvas/editor/ai_panel.js +1607 -0
  6. data/app/assets/javascripts/active_canvas/editor/asset_manager.js +498 -0
  7. data/app/assets/javascripts/active_canvas/editor/blocks.js +1083 -0
  8. data/app/assets/javascripts/active_canvas/editor/code_panel.js +572 -0
  9. data/app/assets/javascripts/active_canvas/editor/component_toolbar.js +394 -0
  10. data/app/assets/javascripts/active_canvas/editor/panels.js +460 -0
  11. data/app/assets/javascripts/active_canvas/editor/utils.js +56 -0
  12. data/app/assets/javascripts/active_canvas/editor.js +295 -0
  13. data/app/assets/stylesheets/active_canvas/application.css +15 -0
  14. data/app/assets/stylesheets/active_canvas/editor.css +2929 -0
  15. data/app/controllers/active_canvas/admin/ai_controller.rb +181 -0
  16. data/app/controllers/active_canvas/admin/application_controller.rb +56 -0
  17. data/app/controllers/active_canvas/admin/media_controller.rb +61 -0
  18. data/app/controllers/active_canvas/admin/page_types_controller.rb +57 -0
  19. data/app/controllers/active_canvas/admin/page_versions_controller.rb +23 -0
  20. data/app/controllers/active_canvas/admin/pages_controller.rb +133 -0
  21. data/app/controllers/active_canvas/admin/partials_controller.rb +88 -0
  22. data/app/controllers/active_canvas/admin/settings_controller.rb +256 -0
  23. data/app/controllers/active_canvas/application_controller.rb +20 -0
  24. data/app/controllers/active_canvas/pages_controller.rb +18 -0
  25. data/app/controllers/concerns/active_canvas/current_user.rb +12 -0
  26. data/app/controllers/concerns/active_canvas/rate_limitable.rb +75 -0
  27. data/app/controllers/concerns/active_canvas/tailwind_compilation.rb +39 -0
  28. data/app/helpers/active_canvas/application_helper.rb +4 -0
  29. data/app/jobs/active_canvas/application_job.rb +4 -0
  30. data/app/jobs/active_canvas/compile_tailwind_job.rb +64 -0
  31. data/app/mailers/active_canvas/application_mailer.rb +6 -0
  32. data/app/models/active_canvas/ai_model.rb +136 -0
  33. data/app/models/active_canvas/application_record.rb +5 -0
  34. data/app/models/active_canvas/media.rb +141 -0
  35. data/app/models/active_canvas/page.rb +85 -0
  36. data/app/models/active_canvas/page_type.rb +22 -0
  37. data/app/models/active_canvas/page_version.rb +80 -0
  38. data/app/models/active_canvas/partial.rb +73 -0
  39. data/app/models/active_canvas/setting.rb +292 -0
  40. data/app/services/active_canvas/ai_configuration.rb +40 -0
  41. data/app/services/active_canvas/ai_models.rb +128 -0
  42. data/app/services/active_canvas/ai_service.rb +289 -0
  43. data/app/services/active_canvas/content_sanitizer.rb +112 -0
  44. data/app/services/active_canvas/tailwind_compiler.rb +156 -0
  45. data/app/views/active_canvas/admin/media/index.html.erb +401 -0
  46. data/app/views/active_canvas/admin/media/show.html.erb +297 -0
  47. data/app/views/active_canvas/admin/page_types/_form.html.erb +25 -0
  48. data/app/views/active_canvas/admin/page_types/edit.html.erb +13 -0
  49. data/app/views/active_canvas/admin/page_types/index.html.erb +29 -0
  50. data/app/views/active_canvas/admin/page_types/new.html.erb +9 -0
  51. data/app/views/active_canvas/admin/page_types/show.html.erb +18 -0
  52. data/app/views/active_canvas/admin/page_versions/show.html.erb +469 -0
  53. data/app/views/active_canvas/admin/pages/_form.html.erb +62 -0
  54. data/app/views/active_canvas/admin/pages/content.html.erb +139 -0
  55. data/app/views/active_canvas/admin/pages/edit.html.erb +335 -0
  56. data/app/views/active_canvas/admin/pages/editor.html.erb +710 -0
  57. data/app/views/active_canvas/admin/pages/index.html.erb +149 -0
  58. data/app/views/active_canvas/admin/pages/new.html.erb +19 -0
  59. data/app/views/active_canvas/admin/pages/show.html.erb +258 -0
  60. data/app/views/active_canvas/admin/pages/versions.html.erb +333 -0
  61. data/app/views/active_canvas/admin/partials/edit.html.erb +182 -0
  62. data/app/views/active_canvas/admin/partials/editor.html.erb +703 -0
  63. data/app/views/active_canvas/admin/partials/index.html.erb +131 -0
  64. data/app/views/active_canvas/admin/settings/show.html.erb +1864 -0
  65. data/app/views/active_canvas/pages/no_homepage.html.erb +45 -0
  66. data/app/views/active_canvas/pages/show.html.erb +113 -0
  67. data/app/views/layouts/active_canvas/admin/application.html.erb +960 -0
  68. data/app/views/layouts/active_canvas/admin/editor.html.erb +826 -0
  69. data/app/views/layouts/active_canvas/application.html.erb +55 -0
  70. data/config/routes.rb +48 -0
  71. data/db/migrate/20260202000001_create_active_canvas_tables.rb +113 -0
  72. data/db/migrate/20260202000002_create_active_canvas_ai_models.rb +26 -0
  73. data/lib/active_canvas/configuration.rb +232 -0
  74. data/lib/active_canvas/engine.rb +44 -0
  75. data/lib/active_canvas/version.rb +3 -0
  76. data/lib/active_canvas.rb +26 -0
  77. data/lib/generators/active_canvas/install/install_generator.rb +263 -0
  78. data/lib/generators/active_canvas/install/templates/initializer.rb.tt +163 -0
  79. data/lib/tasks/active_canvas_tasks.rake +69 -0
  80. metadata +150 -0
@@ -0,0 +1,263 @@
1
+ module ActiveCanvas
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path("templates", __dir__)
5
+
6
+ desc "Interactive setup wizard for ActiveCanvas"
7
+
8
+ def welcome
9
+ say ""
10
+ say "=" * 60, :cyan
11
+ say " Welcome to ActiveCanvas Setup Wizard", :cyan
12
+ say "=" * 60, :cyan
13
+ say ""
14
+ say "This wizard will help you set up ActiveCanvas in your Rails app."
15
+ say ""
16
+ end
17
+
18
+ def install_migrations
19
+ say "Step 1: Database Migrations", :yellow
20
+ say "-" * 40
21
+
22
+ if yes_no?("Copy ActiveCanvas migrations to your app?", default: true)
23
+ rake "active_canvas:install:migrations"
24
+ say "✓ Migrations copied", :green
25
+
26
+ if yes_no?("Run migrations now?", default: true)
27
+ rake "db:migrate"
28
+ say "✓ Migrations completed", :green
29
+ else
30
+ say "→ Remember to run: bin/rails db:migrate", :yellow
31
+ end
32
+ else
33
+ say "→ Skipped. Run later: bin/rails active_canvas:install:migrations", :yellow
34
+ end
35
+ say ""
36
+ end
37
+
38
+ def choose_css_framework
39
+ say "Step 2: CSS Framework", :yellow
40
+ say "-" * 40
41
+ say "Choose which framework to use in the editor and public pages:"
42
+ say ""
43
+ say " 1. tailwind - Tailwind CSS (recommended)"
44
+ say " 2. bootstrap - Bootstrap 5"
45
+ say " 3. none - No framework"
46
+ say ""
47
+
48
+ framework = ask("Enter choice [tailwind]:")
49
+ framework = "tailwind" if framework.blank?
50
+ framework = framework.downcase.strip
51
+
52
+ @css_framework = case framework
53
+ when "tailwind", "1" then :tailwind
54
+ when "bootstrap", "2" then :bootstrap5
55
+ when "none", "3" then :none
56
+ else :tailwind
57
+ end
58
+
59
+ if @css_framework == :tailwind
60
+ setup_tailwind
61
+ elsif @css_framework == :bootstrap5
62
+ setup_bootstrap
63
+ else
64
+ say "→ No framework selected. You can change this in Admin > Settings.", :yellow
65
+ end
66
+ say ""
67
+ end
68
+
69
+ def configure_ai_features
70
+ say "Step 3: AI Features", :yellow
71
+ say "-" * 40
72
+ say "ActiveCanvas includes AI-powered features:"
73
+ say " • Text/HTML generation from prompts"
74
+ say " • Image generation (DALL-E)"
75
+ say " • Screenshot to code conversion"
76
+ say ""
77
+ say "Supported providers:", :cyan
78
+ say " • OpenAI (GPT-4, DALL-E) - recommended"
79
+ say " • Anthropic (Claude)"
80
+ say " • OpenRouter (access to many models)"
81
+ say ""
82
+
83
+ @setup_ai = yes_no?("Configure AI API keys now?", default: true)
84
+
85
+ if @setup_ai
86
+ configure_ai_keys
87
+ else
88
+ say "→ Add API keys later in Admin > Settings > AI", :yellow
89
+ end
90
+ say ""
91
+ end
92
+
93
+ def create_initializer
94
+ say "Step 4: Configuration", :yellow
95
+ say "-" * 40
96
+
97
+ @mount_path = ask("Mount path [/canvas]:")
98
+ @mount_path = "/canvas" if @mount_path.blank?
99
+ @mount_path = "/#{@mount_path}" unless @mount_path.start_with?("/")
100
+
101
+ template "initializer.rb", "config/initializers/active_canvas.rb"
102
+ say "✓ Created config/initializers/active_canvas.rb", :green
103
+ say ""
104
+ end
105
+
106
+ def mount_engine
107
+ say "Step 5: Routes", :yellow
108
+ say "-" * 40
109
+
110
+ routes_file = "config/routes.rb"
111
+ if File.read(routes_file).include?("ActiveCanvas::Engine")
112
+ say "✓ ActiveCanvas::Engine already mounted", :green
113
+ else
114
+ route "mount ActiveCanvas::Engine => '#{@mount_path}'"
115
+ say "✓ Mounted ActiveCanvas at #{@mount_path}", :green
116
+ end
117
+ say ""
118
+ end
119
+
120
+ def sync_ai_models
121
+ if @setup_ai && yes_no?("Sync AI models now? (requires API keys in ENV)", default: false)
122
+ say ""
123
+ say "Syncing AI models...", :cyan
124
+ rake "active_canvas:sync_models"
125
+ say "✓ AI models synced", :green
126
+ end
127
+ say ""
128
+ end
129
+
130
+ def show_completion
131
+ say "=" * 60, :green
132
+ say " Setup Complete!", :green
133
+ say "=" * 60, :green
134
+ say ""
135
+ say "Next steps:", :yellow
136
+ say ""
137
+ say " 1. Start your Rails server:"
138
+ say " $ bin/rails server", :cyan
139
+ say ""
140
+ say " 2. Visit the admin panel:"
141
+ say " http://localhost:3000#{@mount_path}/admin", :cyan
142
+ say ""
143
+ say " 3. Configure authentication in:"
144
+ say " config/initializers/active_canvas.rb", :cyan
145
+ say ""
146
+
147
+ if @css_framework && @css_framework != :none
148
+ say " 4. Your CSS framework (#{@css_framework}) is configured."
149
+ say " It will be loaded automatically in the editor.", :cyan
150
+ say ""
151
+ end
152
+
153
+ unless @setup_ai
154
+ say " 5. Add AI API keys in Admin > Settings > AI", :cyan
155
+ say " Or via environment variables / Rails credentials", :cyan
156
+ say ""
157
+ end
158
+
159
+ say "Documentation: https://github.com/giovapanasiti/active_canvas"
160
+ say ""
161
+ end
162
+
163
+ private
164
+
165
+ # Helper for yes/no prompts with clear defaults
166
+ # @param question [String] The question to ask
167
+ # @param default [Boolean] The default answer (true = Y, false = N)
168
+ # @return [Boolean]
169
+ def yes_no?(question, default: true)
170
+ indicator = default ? "[Y/n]" : "[y/N]"
171
+ answer = ask("#{question} #{indicator}")
172
+
173
+ return default if answer.blank?
174
+
175
+ answer.downcase.start_with?("y")
176
+ end
177
+
178
+ def setup_tailwind
179
+ gemfile_content = File.read(Rails.root.join("Gemfile"))
180
+
181
+ if gemfile_content.include?("tailwindcss-rails")
182
+ say "✓ tailwindcss-rails gem already installed", :green
183
+ else
184
+ if yes_no?("Install tailwindcss-rails gem? (required for Tailwind)", default: true)
185
+ gem "tailwindcss-rails"
186
+ say "✓ Added tailwindcss-rails to Gemfile", :green
187
+
188
+ if yes_no?("Run bundle install now?", default: true)
189
+ run "bundle install"
190
+ say "✓ Bundle installed", :green
191
+ else
192
+ say "→ Remember to run: bundle install", :yellow
193
+ end
194
+ else
195
+ say "→ You'll need to add tailwindcss-rails gem manually", :yellow
196
+ end
197
+ end
198
+ end
199
+
200
+ def setup_bootstrap
201
+ say "✓ Bootstrap 5 will be loaded from CDN", :green
202
+ end
203
+
204
+ def configure_ai_keys
205
+ say ""
206
+ @openai_key = ask("OpenAI API key (leave blank to skip):")
207
+ @anthropic_key = ask("Anthropic API key (leave blank to skip):")
208
+ @openrouter_key = ask("OpenRouter API key (leave blank to skip):")
209
+
210
+ if @openai_key.blank? && @anthropic_key.blank? && @openrouter_key.blank?
211
+ say "→ No API keys provided. Add them later in Admin > Settings > AI", :yellow
212
+ return
213
+ end
214
+
215
+ say ""
216
+ say "How do you want to store the API keys?", :cyan
217
+ say " 1. Environment variables (recommended for production)"
218
+ say " 2. Rails credentials (encrypted)"
219
+ say ""
220
+
221
+ storage = ask("Enter choice [1]:")
222
+ storage = "1" if storage.blank?
223
+
224
+ if storage == "2"
225
+ store_keys_in_credentials
226
+ else
227
+ store_keys_in_env
228
+ end
229
+ end
230
+
231
+ def store_keys_in_env
232
+ say ""
233
+ say "Add these to your .env or environment:", :yellow
234
+ say ""
235
+ say " export OPENAI_API_KEY=\"#{@openai_key}\"" if @openai_key.present?
236
+ say " export ANTHROPIC_API_KEY=\"#{@anthropic_key}\"" if @anthropic_key.present?
237
+ say " export OPENROUTER_API_KEY=\"#{@openrouter_key}\"" if @openrouter_key.present?
238
+ say ""
239
+
240
+ # Update initializer template vars
241
+ @ai_openai_env = true if @openai_key.present?
242
+ @ai_anthropic_env = true if @anthropic_key.present?
243
+ @ai_openrouter_env = true if @openrouter_key.present?
244
+
245
+ say "✓ Remember to set these environment variables before starting the server", :green
246
+ end
247
+
248
+ def store_keys_in_credentials
249
+ say ""
250
+ say "Add these to your Rails credentials (bin/rails credentials:edit):", :yellow
251
+ say ""
252
+ say "active_canvas:"
253
+ say " openai_api_key: #{@openai_key}" if @openai_key.present?
254
+ say " anthropic_api_key: #{@anthropic_key}" if @anthropic_key.present?
255
+ say " openrouter_api_key: #{@openrouter_key}" if @openrouter_key.present?
256
+ say ""
257
+
258
+ @ai_use_credentials = true
259
+ say "✓ Remember to add these to your credentials file", :green
260
+ end
261
+ end
262
+ end
263
+ end
@@ -0,0 +1,163 @@
1
+ # ActiveCanvas Configuration
2
+ # Generated by: bin/rails generate active_canvas:install
3
+ # Documentation: https://github.com/giovapanasiti/active_canvas
4
+
5
+ ActiveCanvas.configure do |config|
6
+ # ==========================================================================
7
+ # Authentication (REQUIRED for production!)
8
+ # ==========================================================================
9
+ #
10
+ # IMPORTANT: Configure one of these options before deploying to production.
11
+ # The admin interface will be inaccessible in production until authentication
12
+ # is configured.
13
+
14
+ # --------------------------------------------------------------------------
15
+ # Option 1: Use your app's authentication method (recommended for Devise)
16
+ # --------------------------------------------------------------------------
17
+ # config.authenticate_admin = :authenticate_user!
18
+ # Or with admin check:
19
+ # config.authenticate_admin = -> {
20
+ # redirect_to main_app.login_path, alert: "Please log in" unless current_user&.admin?
21
+ # }
22
+
23
+ # --------------------------------------------------------------------------
24
+ # Option 2: Inherit from your existing admin controller
25
+ # --------------------------------------------------------------------------
26
+ # This is useful if you already have an admin area with authentication.
27
+ # ActiveCanvas admin controllers will inherit from your controller.
28
+ # config.admin_parent_controller = "Admin::ApplicationController"
29
+
30
+ # --------------------------------------------------------------------------
31
+ # Option 3: HTTP Basic Authentication
32
+ # --------------------------------------------------------------------------
33
+ # Simple password protection. Good for staging or simple setups.
34
+ # IMPORTANT: Use strong credentials and store password in credentials.yml.enc
35
+ config.authenticate_admin = :http_basic_auth
36
+ config.http_basic_user = "admin"
37
+ config.http_basic_password = ENV.fetch("ACTIVE_CANVAS_PASSWORD", "change_me_in_production!")
38
+
39
+ # --------------------------------------------------------------------------
40
+
41
+ # Public pages authentication (optional, nil = public access)
42
+ # config.authenticate_public = nil
43
+
44
+ # Method to get current user (for version tracking, AI features, etc.)
45
+ config.current_user_method = :current_user
46
+
47
+ # ==========================================================================
48
+ # CSS Framework
49
+ # ==========================================================================
50
+ <% if @css_framework && @css_framework != :none %>
51
+
52
+ # Options: :tailwind, :bootstrap5, :none
53
+ config.css_framework = :<%= @css_framework %>
54
+ <% else %>
55
+
56
+ # Options: :tailwind, :bootstrap5, :none
57
+ # config.css_framework = :tailwind
58
+ <% end %>
59
+
60
+ # ==========================================================================
61
+ # Media Uploads
62
+ # ==========================================================================
63
+
64
+ config.enable_uploads = true
65
+ config.max_upload_size = 10.megabytes
66
+ config.allowed_content_types = %w[
67
+ image/jpeg
68
+ image/png
69
+ image/gif
70
+ image/webp
71
+ image/avif
72
+ application/pdf
73
+ ]
74
+
75
+ # SVG uploads are disabled by default due to XSS risks.
76
+ # Only enable if you trust all content authors.
77
+ # config.allow_svg_uploads = false
78
+
79
+ # Active Storage service (nil = default service from storage.yml)
80
+ # config.storage_service = :amazon
81
+
82
+ # Public uploads: when false (default), uses signed URLs with expiration.
83
+ # When true, uploads are world-readable. Only enable for truly public content.
84
+ # config.public_uploads = false
85
+
86
+ # ==========================================================================
87
+ # Editor Features
88
+ # ==========================================================================
89
+
90
+ config.enable_ai_features = true # AI text/image generation
91
+ config.enable_code_editor = true # Code/HTML editing
92
+ config.enable_asset_manager = true # Media library
93
+
94
+ # Auto-save interval in seconds (0 = disabled)
95
+ config.autosave_interval = 60
96
+
97
+ # ==========================================================================
98
+ # Version History
99
+ # ==========================================================================
100
+
101
+ # Maximum versions to keep per page (0 = unlimited)
102
+ config.max_versions_per_page = 50
103
+
104
+ # ==========================================================================
105
+ # Security
106
+ # ==========================================================================
107
+
108
+ # Sanitize HTML content on save (enabled by default for security)
109
+ # Disable only if all content authors are fully trusted
110
+ # config.sanitize_content = true
111
+
112
+ # AI rate limiting (requests per minute per IP)
113
+ # config.ai_rate_limit_per_minute = 30
114
+
115
+ # AI streaming timeouts
116
+ # config.ai_stream_timeout = 5.minutes
117
+ # config.ai_stream_idle_timeout = 30.seconds
118
+ end
119
+
120
+ # ==========================================================================
121
+ # AI API Keys Configuration
122
+ # ==========================================================================
123
+ # Configure your AI provider API keys. Keys are encrypted in the database.
124
+ # You can set them here on boot, or add them via Admin > Settings > AI.
125
+
126
+ Rails.application.config.after_initialize do
127
+ # Skip if database isn't ready (migrations pending, etc.)
128
+ next unless ActiveRecord::Base.connection.table_exists?("active_canvas_settings")
129
+ <% if @ai_use_credentials %>
130
+
131
+ # Using Rails credentials
132
+ credentials = Rails.application.credentials.active_canvas || {}
133
+ ActiveCanvas::Setting.ai_openai_api_key = credentials[:openai_api_key] if credentials[:openai_api_key].present?
134
+ ActiveCanvas::Setting.ai_anthropic_api_key = credentials[:anthropic_api_key] if credentials[:anthropic_api_key].present?
135
+ ActiveCanvas::Setting.ai_openrouter_api_key = credentials[:openrouter_api_key] if credentials[:openrouter_api_key].present?
136
+ <% elsif @ai_openai_env || @ai_anthropic_env || @ai_openrouter_env %>
137
+
138
+ # Using environment variables
139
+ <% if @ai_openai_env %>
140
+ ActiveCanvas::Setting.ai_openai_api_key = ENV["OPENAI_API_KEY"] if ENV["OPENAI_API_KEY"].present?
141
+ <% end %>
142
+ <% if @ai_anthropic_env %>
143
+ ActiveCanvas::Setting.ai_anthropic_api_key = ENV["ANTHROPIC_API_KEY"] if ENV["ANTHROPIC_API_KEY"].present?
144
+ <% end %>
145
+ <% if @ai_openrouter_env %>
146
+ ActiveCanvas::Setting.ai_openrouter_api_key = ENV["OPENROUTER_API_KEY"] if ENV["OPENROUTER_API_KEY"].present?
147
+ <% end %>
148
+ <% else %>
149
+
150
+ # Uncomment and configure your preferred method:
151
+ #
152
+ # Option 1: Environment variables
153
+ # ActiveCanvas::Setting.ai_openai_api_key = ENV["OPENAI_API_KEY"] if ENV["OPENAI_API_KEY"].present?
154
+ # ActiveCanvas::Setting.ai_anthropic_api_key = ENV["ANTHROPIC_API_KEY"] if ENV["ANTHROPIC_API_KEY"].present?
155
+ # ActiveCanvas::Setting.ai_openrouter_api_key = ENV["OPENROUTER_API_KEY"] if ENV["OPENROUTER_API_KEY"].present?
156
+ #
157
+ # Option 2: Rails credentials
158
+ # credentials = Rails.application.credentials.active_canvas || {}
159
+ # ActiveCanvas::Setting.ai_openai_api_key = credentials[:openai_api_key] if credentials[:openai_api_key].present?
160
+ <% end %>
161
+ rescue ActiveRecord::NoDatabaseError, ActiveRecord::StatementInvalid
162
+ # Database not ready yet, keys will need to be set via Admin UI
163
+ end
@@ -0,0 +1,69 @@
1
+ namespace :active_canvas do
2
+ namespace :install do
3
+ desc "Copy migrations from active_canvas to application"
4
+ task :migrations do
5
+ source = ActiveCanvas::Engine.root.join("db/migrate")
6
+ destination = ActiveRecord::Tasks::DatabaseTasks.migrations_paths.first
7
+
8
+ ActiveRecord::Migration.copy(destination, { active_canvas: source })
9
+ end
10
+ end
11
+
12
+ desc "Sync AI models from configured providers (OpenAI, Anthropic, OpenRouter)"
13
+ task sync_models: :environment do
14
+ # unless ActiveCanvas::AiConfiguration.ruby_llm_available?
15
+ # puts "RubyLLM gem is not available. Add 'ruby_llm' to your Gemfile."
16
+ # exit 1
17
+ # end
18
+
19
+ unless ActiveCanvas::AiConfiguration.configured?
20
+ puts "No API keys configured."
21
+ puts "Add keys via Settings > AI or set them directly:"
22
+ puts " ActiveCanvas::Setting.ai_openai_api_key = 'sk-...'"
23
+ puts " ActiveCanvas::Setting.ai_anthropic_api_key = 'sk-ant-...'"
24
+ puts " ActiveCanvas::Setting.ai_openrouter_api_key = 'sk-or-...'"
25
+ exit 1
26
+ end
27
+
28
+ providers = ActiveCanvas::AiConfiguration.configured_providers
29
+ puts "Configured providers: #{providers.join(', ')}"
30
+ puts "Syncing models..."
31
+
32
+ count = ActiveCanvas::AiModels.refresh!
33
+ puts "Done! Synced #{count} models."
34
+
35
+ # Show breakdown by type
36
+ text_count = ActiveCanvas::AiModel.active.text_models.count
37
+ image_count = ActiveCanvas::AiModel.active.image_models.count
38
+ vision_count = ActiveCanvas::AiModel.active.vision_models.count
39
+
40
+ puts ""
41
+ puts "Breakdown:"
42
+ puts " Text models: #{text_count}"
43
+ puts " Image models: #{image_count}"
44
+ puts " Vision models: #{vision_count}"
45
+ end
46
+
47
+ desc "List synced AI models"
48
+ task list_models: :environment do
49
+ unless ActiveCanvas::AiModel.exists?
50
+ puts "No models synced yet. Run: rails active_canvas:sync_models"
51
+ exit 0
52
+ end
53
+
54
+ puts "=== Text/Chat Models ==="
55
+ ActiveCanvas::AiModel.active.text_models.order(:provider, :name).each do |m|
56
+ vision = m.supports_vision? ? " [vision]" : ""
57
+ puts " #{m.provider.ljust(12)} #{m.display_name}#{vision}"
58
+ end
59
+
60
+ puts ""
61
+ puts "=== Image Models ==="
62
+ ActiveCanvas::AiModel.active.image_models.order(:provider, :name).each do |m|
63
+ puts " #{m.provider.ljust(12)} #{m.display_name}"
64
+ end
65
+
66
+ puts ""
67
+ puts "Total: #{ActiveCanvas::AiModel.active.count} models"
68
+ end
69
+ end
metadata ADDED
@@ -0,0 +1,150 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_canvas
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Giovanni Panasiti
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2026-02-26 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rails
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 8.0.0
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: 8.0.0
26
+ - !ruby/object:Gem::Dependency
27
+ name: ruby_llm
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '1.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '1.0'
40
+ description: ActiveCanvas provides a simple CMS for creating and managing static pages
41
+ with an admin interface
42
+ email:
43
+ - giova.panasiti@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - MIT-LICENSE
49
+ - README.md
50
+ - Rakefile
51
+ - app/assets/javascripts/active_canvas/editor.js
52
+ - app/assets/javascripts/active_canvas/editor/ai_panel.js
53
+ - app/assets/javascripts/active_canvas/editor/asset_manager.js
54
+ - app/assets/javascripts/active_canvas/editor/blocks.js
55
+ - app/assets/javascripts/active_canvas/editor/code_panel.js
56
+ - app/assets/javascripts/active_canvas/editor/component_toolbar.js
57
+ - app/assets/javascripts/active_canvas/editor/panels.js
58
+ - app/assets/javascripts/active_canvas/editor/utils.js
59
+ - app/assets/stylesheets/active_canvas/application.css
60
+ - app/assets/stylesheets/active_canvas/editor.css
61
+ - app/controllers/active_canvas/admin/ai_controller.rb
62
+ - app/controllers/active_canvas/admin/application_controller.rb
63
+ - app/controllers/active_canvas/admin/media_controller.rb
64
+ - app/controllers/active_canvas/admin/page_types_controller.rb
65
+ - app/controllers/active_canvas/admin/page_versions_controller.rb
66
+ - app/controllers/active_canvas/admin/pages_controller.rb
67
+ - app/controllers/active_canvas/admin/partials_controller.rb
68
+ - app/controllers/active_canvas/admin/settings_controller.rb
69
+ - app/controllers/active_canvas/application_controller.rb
70
+ - app/controllers/active_canvas/pages_controller.rb
71
+ - app/controllers/concerns/active_canvas/current_user.rb
72
+ - app/controllers/concerns/active_canvas/rate_limitable.rb
73
+ - app/controllers/concerns/active_canvas/tailwind_compilation.rb
74
+ - app/helpers/active_canvas/application_helper.rb
75
+ - app/jobs/active_canvas/application_job.rb
76
+ - app/jobs/active_canvas/compile_tailwind_job.rb
77
+ - app/mailers/active_canvas/application_mailer.rb
78
+ - app/models/active_canvas/ai_model.rb
79
+ - app/models/active_canvas/application_record.rb
80
+ - app/models/active_canvas/media.rb
81
+ - app/models/active_canvas/page.rb
82
+ - app/models/active_canvas/page_type.rb
83
+ - app/models/active_canvas/page_version.rb
84
+ - app/models/active_canvas/partial.rb
85
+ - app/models/active_canvas/setting.rb
86
+ - app/services/active_canvas/ai_configuration.rb
87
+ - app/services/active_canvas/ai_models.rb
88
+ - app/services/active_canvas/ai_service.rb
89
+ - app/services/active_canvas/content_sanitizer.rb
90
+ - app/services/active_canvas/tailwind_compiler.rb
91
+ - app/views/active_canvas/admin/media/index.html.erb
92
+ - app/views/active_canvas/admin/media/show.html.erb
93
+ - app/views/active_canvas/admin/page_types/_form.html.erb
94
+ - app/views/active_canvas/admin/page_types/edit.html.erb
95
+ - app/views/active_canvas/admin/page_types/index.html.erb
96
+ - app/views/active_canvas/admin/page_types/new.html.erb
97
+ - app/views/active_canvas/admin/page_types/show.html.erb
98
+ - app/views/active_canvas/admin/page_versions/show.html.erb
99
+ - app/views/active_canvas/admin/pages/_form.html.erb
100
+ - app/views/active_canvas/admin/pages/content.html.erb
101
+ - app/views/active_canvas/admin/pages/edit.html.erb
102
+ - app/views/active_canvas/admin/pages/editor.html.erb
103
+ - app/views/active_canvas/admin/pages/index.html.erb
104
+ - app/views/active_canvas/admin/pages/new.html.erb
105
+ - app/views/active_canvas/admin/pages/show.html.erb
106
+ - app/views/active_canvas/admin/pages/versions.html.erb
107
+ - app/views/active_canvas/admin/partials/edit.html.erb
108
+ - app/views/active_canvas/admin/partials/editor.html.erb
109
+ - app/views/active_canvas/admin/partials/index.html.erb
110
+ - app/views/active_canvas/admin/settings/show.html.erb
111
+ - app/views/active_canvas/pages/no_homepage.html.erb
112
+ - app/views/active_canvas/pages/show.html.erb
113
+ - app/views/layouts/active_canvas/admin/application.html.erb
114
+ - app/views/layouts/active_canvas/admin/editor.html.erb
115
+ - app/views/layouts/active_canvas/application.html.erb
116
+ - config/routes.rb
117
+ - db/migrate/20260202000001_create_active_canvas_tables.rb
118
+ - db/migrate/20260202000002_create_active_canvas_ai_models.rb
119
+ - lib/active_canvas.rb
120
+ - lib/active_canvas/configuration.rb
121
+ - lib/active_canvas/engine.rb
122
+ - lib/active_canvas/version.rb
123
+ - lib/generators/active_canvas/install/install_generator.rb
124
+ - lib/generators/active_canvas/install/templates/initializer.rb.tt
125
+ - lib/tasks/active_canvas_tasks.rake
126
+ homepage: https://github.com/giovapanasiti/active_canvas
127
+ licenses:
128
+ - MIT
129
+ metadata:
130
+ homepage_uri: https://github.com/giovapanasiti/active_canvas
131
+ source_code_uri: https://github.com/giovapanasiti/active_canvas
132
+ changelog_uri: https://github.com/giovapanasiti/active_canvas/blob/master/CHANGELOG.md
133
+ rdoc_options: []
134
+ require_paths:
135
+ - lib
136
+ required_ruby_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ required_rubygems_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ requirements: []
147
+ rubygems_version: 3.6.2
148
+ specification_version: 4
149
+ summary: A mountable Rails CMS engine for managing static pages
150
+ test_files: []