gaggle 0.2.2

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 (71) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +167 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/config/gaggle_manifest.js +4 -0
  6. data/app/assets/stylesheets/application.css +1 -0
  7. data/app/assets/stylesheets/gaggle/tailwind.css +1740 -0
  8. data/app/controllers/gaggle/application_controller.rb +23 -0
  9. data/app/controllers/gaggle/channels/messages_controller.rb +27 -0
  10. data/app/controllers/gaggle/channels_controller.rb +84 -0
  11. data/app/controllers/gaggle/gooses/sessions_controller.rb +23 -0
  12. data/app/controllers/gaggle/gooses_controller.rb +47 -0
  13. data/app/controllers/gaggle/messages_controller.rb +7 -0
  14. data/app/controllers/gaggle/overviews_controller.rb +5 -0
  15. data/app/controllers/gaggle/sessions_controller.rb +27 -0
  16. data/app/helpers/gaggle/application_helper.rb +4 -0
  17. data/app/javascript/controllers/gaggle/application.js +9 -0
  18. data/app/javascript/controllers/gaggle/chat_field_form_controller.js +7 -0
  19. data/app/javascript/controllers/gaggle/index.js +4 -0
  20. data/app/javascript/controllers/gaggle/local_timestamp_controller.js +21 -0
  21. data/app/javascript/controllers/gaggle/text_area_auto_expand_controller.js +27 -0
  22. data/app/javascript/controllers/gaggle/transition_controller.js +102 -0
  23. data/app/javascript/gaggle/application.js +3 -0
  24. data/app/javascript/gaggle/el-transition.js +64 -0
  25. data/app/jobs/gaggle/application_job.rb +4 -0
  26. data/app/mailers/gaggle/application_mailer.rb +6 -0
  27. data/app/models/gaggle/application_record.rb +8 -0
  28. data/app/models/gaggle/channel.rb +45 -0
  29. data/app/models/gaggle/channel_goose.rb +11 -0
  30. data/app/models/gaggle/current.rb +5 -0
  31. data/app/models/gaggle/goose/personality_defaults.rb +87 -0
  32. data/app/models/gaggle/goose.rb +94 -0
  33. data/app/models/gaggle/message.rb +61 -0
  34. data/app/models/gaggle/notification.rb +47 -0
  35. data/app/models/gaggle/session.rb +138 -0
  36. data/app/views/gaggle/application/_logo.html.erb +125 -0
  37. data/app/views/gaggle/application/_mobile_header.html.erb +15 -0
  38. data/app/views/gaggle/application/_sidebar.html.erb +259 -0
  39. data/app/views/gaggle/channels/_channel.html.erb +22 -0
  40. data/app/views/gaggle/channels/_form.html.erb +70 -0
  41. data/app/views/gaggle/channels/edit.html.erb +10 -0
  42. data/app/views/gaggle/channels/gooses/index.html.erb +12 -0
  43. data/app/views/gaggle/channels/index.json.jbuilder +3 -0
  44. data/app/views/gaggle/channels/messages/new.html.erb +2 -0
  45. data/app/views/gaggle/channels/new.html.erb +8 -0
  46. data/app/views/gaggle/channels/show.html.erb +98 -0
  47. data/app/views/gaggle/channels/show.json.jbuilder +5 -0
  48. data/app/views/gaggle/channels/update.turbo_stream.erb +1 -0
  49. data/app/views/gaggle/gooses/_form.html.erb +65 -0
  50. data/app/views/gaggle/gooses/edit.html.erb +2 -0
  51. data/app/views/gaggle/gooses/index.json.jbuilder +5 -0
  52. data/app/views/gaggle/gooses/new.html.erb +2 -0
  53. data/app/views/gaggle/gooses/sessions/index.html.erb +55 -0
  54. data/app/views/gaggle/gooses/show.html.erb +41 -0
  55. data/app/views/gaggle/messages/_message.html.erb +30 -0
  56. data/app/views/gaggle/overviews/show.html.erb +17 -0
  57. data/app/views/gaggle/sessions/show.html.erb +76 -0
  58. data/app/views/layouts/gaggle/application.html.erb +19 -0
  59. data/config/importmap.rb +7 -0
  60. data/config/routes.rb +19 -0
  61. data/config/utility_classes.yml +22 -0
  62. data/db/gaggle_migrate/20250214180303_create_gaggle_tables.rb +53 -0
  63. data/db/gaggle_migrate/20250220002655_add_delivered_at_to_notification.rb +5 -0
  64. data/db/gaggle_migrate/20250220004428_create_join_table_gaggle_channel_gaggle_goose.rb +8 -0
  65. data/lib/gaggle/engine.rb +48 -0
  66. data/lib/gaggle/version.rb +3 -0
  67. data/lib/gaggle.rb +8 -0
  68. data/lib/generators/gaggle/install/install_generator.rb +7 -0
  69. data/lib/generators/gaggle/install/templates/db/gaggle_schema.rb +59 -0
  70. data/lib/generators/gaggle/update/update_generator.rb +16 -0
  71. metadata +269 -0
@@ -0,0 +1,55 @@
1
+
2
+ <div class="flex flex-col max-h-full">
3
+ <%= render "mobile_header" %>
4
+ <div class="w-full overflow-auto flex-grow">
5
+ <table class="w-full border-collapse rounded-lg overflow-hidden shadow-lg
6
+ bg-white dark:bg-gray-900 shadow-gray-200/50 dark:shadow-gray-800/20
7
+ overflow-y-auto">
8
+ <thead>
9
+ <tr class="sticky top-0 bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-gray-100">
10
+ <th class="px-6 py-3 text-left text-sm font-semibold border-b
11
+ border-gray-200 dark:border-gray-700">Session</th>
12
+ <th class="px-6 py-3 text-left text-sm font-semibold border-b
13
+ border-gray-200 dark:border-gray-700">Created At</th>
14
+ <th class="px-6 py-3 text-left text-sm font-semibold border-b
15
+ border-gray-200 dark:border-gray-700">Updated At</th>
16
+ <th class="px-6 py-3 text-left text-sm font-semibold border-b
17
+ border-gray-200 dark:border-gray-700">Running</th>
18
+ <th class="px-6 py-3 text-left text-sm font-semibold border-b
19
+ border-gray-200 dark:border-gray-700">Link</th>
20
+ </tr>
21
+ </thead>
22
+ <tbody>
23
+ <% @sessions.reverse.each_with_index do |session, index| %>
24
+ <% index = @sessions.length - index %>
25
+ <tr class="hover:bg-gray-50 dark:hover:bg-gray-800/50
26
+ transition-colors duration-150 text-gray-900 dark:text-gray-100">
27
+ <td class="px-6 py-4 border-b border-gray-200 dark:border-gray-800
28
+ text-sm">Session <%= index %></td>
29
+ <td class="px-6 py-4 border-b border-gray-200 dark:border-gray-800
30
+ text-sm">
31
+ <%= session.created_at&.strftime("%Y-%m-%d %H:%M") %>
32
+ </td>
33
+ <td class="px-6 py-4 border-b border-gray-200 dark:border-gray-800
34
+ text-sm">
35
+ <%= session.updated_at&.strftime("%Y-%m-%d %H:%M") %>
36
+ </td>
37
+ <td class="px-6 py-4 border-b border-gray-200 dark:border-gray-800
38
+ text-sm">
39
+ <span class="<%= session.running? ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400' %>">
40
+ <%= session.running? ? "Yes" : "No" %>
41
+ </span>
42
+ </td>
43
+ <td class="px-6 py-4 border-b border-gray-200 dark:border-gray-800
44
+ text-sm">
45
+ <%= link_to "View", session, class: yass(btn: :gray, add: 'w-full') %>
46
+ </td>
47
+ </tr>
48
+ <% end %>
49
+ </tbody>
50
+ </table>
51
+ </div>
52
+
53
+ <%= button_to "Start Session", goose_sessions_path(@goose),
54
+ class: yass(btn: :blue, add: 'w-full') %>
55
+ </div>
@@ -0,0 +1,41 @@
1
+ <%= render "mobile_header" %>
2
+ <div class="max-w-2xl mx-auto p-6 bg-white dark:bg-gray-900 rounded-xl shadow-lg
3
+ shadow-gray-200/50 dark:shadow-gray-800/20 transition-all duration-300">
4
+ <!-- Mimicking the form_with structure without the form -->
5
+ <div class="space-y-6">
6
+ <!-- Name (Header) Section -->
7
+ <div class="space-y-2">
8
+ <h1 class="text-3xl font-bold text-gray-900 dark:text-gray-100">
9
+ Profile: <%= @goose.name %>
10
+ </h1>
11
+ </div>
12
+
13
+ <!-- Prompt Section -->
14
+ <div class="space-y-2">
15
+ <label class="block text-sm font-medium text-gray-900 dark:text-gray-100">
16
+ Prompt
17
+ </label>
18
+ <div class="block w-full px-4 py-2.5 bg-white dark:bg-gray-800/50
19
+ border border-gray-300 dark:border-gray-700/50
20
+ rounded-lg shadow-sm text-gray-900 dark:text-gray-100
21
+ hover:border-gray-400 dark:hover:border-gray-600
22
+ transition-all duration-200">
23
+ <%= simple_format(@goose.prompt.presence) || "No additional information provided." %>
24
+ </div>
25
+ </div>
26
+
27
+ <!-- Action Buttons -->
28
+ <div>
29
+ <div class="flex space-x-4">
30
+ <%= link_to "Edit", edit_goose_path(@goose),
31
+ class: yass(btn: :blue) %>
32
+ <%= link_to "Sessions", goose_sessions_path(@goose),
33
+ class: yass(btn: :gray) %>
34
+ <% if session = @goose.sessions.running.first %>
35
+ <%= link_to "Active Session", session,
36
+ class: yass(btn: :success) if @goose.sessions.running.any? %>
37
+ <% end %>
38
+ </div>
39
+ </div>
40
+ </div>
41
+ </div>
@@ -0,0 +1,30 @@
1
+ <%# locals: (message:) %>
2
+
3
+ <div id="<%= dom_id(message) %>" class="group flex flex-col <%= message.goose_id.nil? ? 'items-end ml-auto' : 'items-start mr-auto' %> max-w-[70%]">
4
+ <% if message.goose_id.nil? %>
5
+ <span class="text-xs text-gray-500 dark:text-gray-400 mb-1 mr-1"
6
+ data-controller="local-timestamp"
7
+ data-local-timestamp-utc-value="<%= message.created_at.iso8601 %>">
8
+ <span data-local-timestamp-target="display"></span>
9
+ </span>
10
+ <div class="flex flex-col bg-blue-600 dark:bg-blue-700 rounded-lg p-3 shadow-sm">
11
+ <div class="text-white dark:text-white prose dark:prose-invert max-w-none">
12
+ <%= simple_format message.markdown_content %>
13
+ </div>
14
+ </div>
15
+ <% else %>
16
+ <div class="flex flex-col bg-white dark:bg-gray-800 rounded-lg p-3 shadow-sm">
17
+ <div class="flex items-center gap-2 mb-1">
18
+ <span class="font-semibold text-gray-900 dark:text-white"><%= message.user_name || "Human" %></span>
19
+ <span class="text-xs text-gray-500 dark:text-gray-400"
20
+ data-controller="local-timestamp"
21
+ data-local-timestamp-utc-value="<%= message.created_at.iso8601 %>">
22
+ <span data-local-timestamp-target="display"></span>
23
+ </span>
24
+ </div>
25
+ <div class="text-gray-700 dark:text-gray-300 prose dark:prose-invert max-w-none">
26
+ <%= simple_format message.markdown_content %>
27
+ </div>
28
+ </div>
29
+ <% end %>
30
+ </div>
@@ -0,0 +1,17 @@
1
+ <div class="flex flex-col items-center justify-center h-full">
2
+ <div class="bg-white rounded-lg shadow-xl p-8 text-center">
3
+ <h1 class="text-3xl font-bold text-gray-800 mb-6">Welcome to Gaggle!</h1>
4
+ <p class="text-gray-700 mb-5">
5
+ To get started, create a Goose using the left sidebar.
6
+ </p>
7
+ <p class="text-gray-700">
8
+ Once you've created a Goose, you can start and view sessions.
9
+ </p>
10
+ <div class="mt-8">
11
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 inline-block align-middle">
12
+ <path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l7.5-1.5 7.5 1.5m-15 0l7.5 1.5 7.5-1.5M4.5 12.75l7.5 3.75 7.5-3.75m-15 0l7.5-3.75 7.5 3.75" />
13
+ </svg>
14
+ <span class="ml-2 text-sm text-gray-500">Follow the Goose!</span>
15
+ </div>
16
+ </div>
17
+ </div>
@@ -0,0 +1,76 @@
1
+ <%= turbo_stream_from @session %>
2
+
3
+ <div class="flex flex-col max-h-full flex-grow bg-gray-50 dark:bg-gray-950 transition-colors duration-300">
4
+ <!-- Header Section -->
5
+ <div class="bg-white dark:bg-gray-900 shadow-md shadow-gray-200/50 dark:shadow-gray-800/20
6
+ px-6 py-4 flex items-center justify-between sticky top-0 z-20">
7
+ <%= render "mobile_header" %>
8
+ <h1 class="text-2xl font-bold text-gray-900 dark:text-gray-100">
9
+ Executable Console
10
+ </h1>
11
+ <div class="flex items-center space-x-3">
12
+ <%= link_to "Back", goose_sessions_path(@session.goose),
13
+ class: yass(btn: :gray) %>
14
+ <%= button_to "Stop Session", @session,
15
+ class: yass(btn: :danger),
16
+ method: :delete,
17
+ data: { turbo_confirm: "Are you sure you want to stop this session?" } %>
18
+ </div>
19
+ </div>
20
+
21
+ <!-- Console Output -->
22
+ <section id="console-output"
23
+ class="flex-1 bg-gray-900 dark:bg-gray-950 text-green-400 dark:text-green-300
24
+ p-6 rounded-lg mb-6 font-mono text-sm border border-gray-800 dark:border-gray-700/50
25
+ shadow-inner overflow-y-auto flex flex-col-reverse">
26
+ <pre><code id="<%= dom_id(@session, :code) %>">
27
+ <%= Strings::ANSI.sanitize(File.read(@session.log_file)) rescue "No output available..." %>
28
+ </code></pre>
29
+ </section>
30
+
31
+ <!-- Input Section -->
32
+ <div class="bg-white dark:bg-gray-900 rounded-lg p-4 shadow-md shadow-gray-200/50 dark:shadow-gray-800/20">
33
+ <% if @session.running? %>
34
+ <%= form_with model: @session,
35
+ class: "relative" do |form| %>
36
+ <div class="relative flex items-center">
37
+ <%= form.text_area :content,
38
+ rows: 1,
39
+ autofocus: true,
40
+ placeholder: "Type your message...",
41
+ class: "w-full px-4 py-2.5 pr-20 rounded-lg border border-gray-300 dark:border-gray-700/50
42
+ bg-white dark:bg-gray-800/70 text-gray-900 dark:text-gray-100
43
+ placeholder-gray-400 dark:placeholder-gray-500
44
+ focus:outline-none focus:ring-2 focus:ring-indigo-500
45
+ dark:focus:ring-indigo-400 focus:border-transparent
46
+ resize-none min-h-[2.5rem] max-h-32 transition-all duration-200
47
+ scrollbar-thin scrollbar-thumb-gray-300 dark:scrollbar-thumb-gray-600
48
+ scrollbar-track-transparent hover:border-gray-400 dark:hover:border-gray-600 resize-y",
49
+ data: {
50
+ controller: "text-area-auto-expand chat-field-form",
51
+ text_area_auto_expand_max_rows_value: 5,
52
+ action: "keydown.enter->chat-field-form#submitForm:prevent"
53
+ } %>
54
+ <%= form.label :content,
55
+ class: "absolute right-2 px-3 py-1 bg-indigo-600 hover:bg-indigo-700
56
+ dark:bg-indigo-500 dark:hover:bg-indigo-600
57
+ text-white text-sm font-medium rounded-full
58
+ focus:outline-none focus:ring-2 focus:ring-indigo-500
59
+ dark:focus:ring-indigo-400 focus:ring-offset-2
60
+ dark:focus:ring-offset-gray-900
61
+ disabled:opacity-50 disabled:cursor-not-allowed
62
+ transition-all duration-200" do %>
63
+ <% form.submit '', class: 'hidden' %>
64
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
65
+ <path stroke-linecap="round" stroke-linejoin="round" d="M6 12 3.269 3.125A59.769 59.769 0 0 1 21.485 12 59.768 59.768 0 0 1 3.27 20.875L5.999 12Zm0 0h7.5" />
66
+ </svg>
67
+ <% end %>
68
+ </div>
69
+ <% end %>
70
+ <% else %>
71
+ <div class="text-gray-600 dark:text-gray-400 text-sm italic py-2">
72
+ Session is no longer running. Please start a new session.
73
+ </div>
74
+ <% end %>
75
+ </div>
76
+ </div>
@@ -0,0 +1,19 @@
1
+ <!DOCTYPE html>
2
+ <html class="h-full bg-white dark:bg-gray-900">
3
+ <head>
4
+ <title>Gaggle</title>
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <%= csrf_meta_tags %>
7
+ <%= csp_meta_tag %>
8
+ <%= javascript_importmap_tags 'gaggle/application' %>
9
+ <%= stylesheet_link_tag "gaggle/tailwind", "data-turbo-track": "reload" %>
10
+ </head>
11
+ <body class="h-full bg-white dark:bg-gray-900 max-h-screen">
12
+ <%= turbo_stream_from 'gaggle'%>
13
+ <div class="flex h-full">
14
+ <%= render 'sidebar', channels: @channels do %>
15
+ <%= yield %>
16
+ <% end %>
17
+ </div>
18
+ </body>
19
+ </html>
@@ -0,0 +1,7 @@
1
+ pin "@hotwired/turbo-rails", to: "turbo.min.js"
2
+ pin "@hotwired/stimulus", to: "stimulus.min.js"
3
+ pin "@hotwired/stimulus-loading", to: "stimulus-loading.js"
4
+
5
+ pin_all_from File.expand_path("../app/javascript/gaggle", __dir__), under: "gaggle"
6
+ pin_all_from File.expand_path("../app/javascript/controllers/", __dir__), under: "controllers"
7
+ pin "gaggle/el-transition", to: "gaggle/el-transition.js"
data/config/routes.rb ADDED
@@ -0,0 +1,19 @@
1
+ Gaggle::Engine.routes.draw do
2
+ root to: "overviews#show"
3
+
4
+ resources :channels, mcp: true do
5
+ scope module: :channels do
6
+ resources :messages, only: [ :create ], mcp: true
7
+ end
8
+ end
9
+
10
+ resources :messages, only: [ :destroy ], mcp: true
11
+
12
+ resources :gooses, mcp: [ :index ] do
13
+ scope module: :gooses do
14
+ resources :sessions, only: [ :index, :create, :destroy ]
15
+ end
16
+ end
17
+
18
+ resources :sessions, only: [ :show, :update, :destroy ]
19
+ end
@@ -0,0 +1,22 @@
1
+ btn:
2
+ base: 'inline-flex justify-center items-center border border-transparent font-medium rounded shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2 cursor-pointer px-4 py-2 text-sm rounded-md dark:focus:ring-offset-gray-800'
3
+ xs: 'px-2.5 py-1.5 text-xs rounded'
4
+ sm: 'px-3 py-2 text-sm rounded-md'
5
+ lg: 'px-4 py-2 text-base rounded-md'
6
+ xl: 'px-6 py-3 text-base rounded-md'
7
+
8
+ blue: 'text-white bg-blue-600 hover:bg-blue-700 focus:ring-blue-500 border-transparent dark:bg-blue-500 dark:hover:bg-blue-600 dark:focus:ring-blue-400'
9
+ light: 'text-gray-700 bg-white hover:bg-gray-50 focus:ring-gray-500 border-gray-300 dark:text-gray-300 dark:bg-gray-700 dark:hover:bg-gray-600 dark:border-gray-600 dark:focus:ring-gray-400'
10
+ gray: 'text-gray-700 bg-gray-200 hover:bg-gray-300 focus:ring-gray-500 border-gray-300 dark:text-white dark:bg-gray-600 dark:hover:bg-gray-700 dark:focus:ring-offset-gray-800 disabled:hover:bg-white dark:disabled:hover:bg-gray-600'
11
+ danger: 'text-white bg-red-600 hover:bg-red-700 focus:ring-red-500 border-transparent dark:bg-red-500 dark:hover:bg-red-600 dark:focus:ring-red-400'
12
+ warning: 'text-white bg-yellow-400 hover:bg-yellow-600 focus:ring-yellow-300 border-transparent dark:bg-yellow-500 dark:hover:bg-yellow-600 dark:focus:ring-yellow-400'
13
+ success: 'text-white bg-green-600 hover:bg-green-700 focus:ring-green-500 border-transparent dark:bg-green-500 dark:hover:bg-green-600 dark:focus:ring-green-400'
14
+
15
+ primary: 'text-white bg-primary-600 hover:bg-primary-700 focus:ring-primary-500 border-transparent dark:bg-primary-500 dark:hover:bg-primary-600 dark:focus:ring-primary-400'
16
+ secondary: 'text-secondary-700 bg-white hover:bg-secondary-50 focus:ring-secondary-500 border-secondary-300 dark:text-secondary-300 dark:bg-gray-700 dark:hover:bg-gray-600 dark:border-gray-600 dark:focus:ring-secondary-400'
17
+
18
+ icon:
19
+ sm: 'ml-2 -mr-0.5 h-4 w-4'
20
+ md: 'ml-2 -mr-1 h-5 w-5'
21
+ lg: 'ml-3 -mr-1 h-5 w-5'
22
+ xl: 'ml-3 -mr-1 h-5 w-5'
@@ -0,0 +1,53 @@
1
+ class CreateGaggleTables < ActiveRecord::Migration[7.2]
2
+ def change
3
+ create_table "gaggle_gooses", force: :cascade do |t|
4
+ t.string "name", null: false
5
+ t.text "prompt"
6
+ t.datetime "created_at", null: false
7
+ t.datetime "updated_at", null: false
8
+ end
9
+
10
+ create_table "gaggle_messages", force: :cascade do |t|
11
+ t.text "content", null: false
12
+ t.integer "goose_id"
13
+ t.datetime "created_at", null: false
14
+ t.datetime "updated_at", null: false
15
+ t.string "messageable_type", null: false
16
+ t.integer "messageable_id", null: false
17
+ t.index [ "goose_id" ], name: "index_gaggle_messages_on_goose_id"
18
+ t.index [ "messageable_type", "messageable_id" ], name: "index_gaggle_messages_on_messageable"
19
+ end
20
+
21
+ create_table "gaggle_notifications", force: :cascade do |t|
22
+ t.integer "message_id"
23
+ t.integer "goose_id"
24
+ t.datetime "read_at", precision: nil
25
+ t.datetime "created_at", null: false
26
+ t.datetime "updated_at", null: false
27
+ t.string "messageable_type", null: false
28
+ t.integer "messageable_id", null: false
29
+ t.index [ "goose_id" ], name: "index_gaggle_notifications_on_goose_id"
30
+ t.index [ "message_id" ], name: "index_gaggle_notifications_on_message_id"
31
+ t.index [ "messageable_type", "messageable_id" ], name: "idx_on_messageable_type_messageable_id_e697f3e48f"
32
+ end
33
+
34
+ create_table "gaggle_sessions", force: :cascade do |t|
35
+ t.integer "goose_id", null: false
36
+ t.string "log_file"
37
+ t.datetime "created_at", null: false
38
+ t.datetime "updated_at", null: false
39
+ t.index [ "goose_id" ], name: "index_gaggle_sessions_on_goose_id"
40
+ end
41
+
42
+ create_table "gaggle_channels", force: :cascade do |t|
43
+ t.string "name", null: false
44
+ t.datetime "created_at", null: false
45
+ t.datetime "updated_at", null: false
46
+ end
47
+
48
+ add_foreign_key "gaggle_messages", "gaggle_gooses", column: "goose_id"
49
+ add_foreign_key "gaggle_notifications", "gaggle_gooses", column: "goose_id"
50
+ add_foreign_key "gaggle_notifications", "gaggle_messages", column: "message_id"
51
+ add_foreign_key "gaggle_sessions", "gaggle_gooses", column: "goose_id"
52
+ end
53
+ end
@@ -0,0 +1,5 @@
1
+ class AddDeliveredAtToNotification < ActiveRecord::Migration[7.2]
2
+ def change
3
+ add_column :gaggle_notifications, :delivered_at, :datetime
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ class CreateJoinTableGaggleChannelGaggleGoose < ActiveRecord::Migration[7.2]
2
+ def change
3
+ create_join_table :channels, :gooses, table_name: :gaggle_channels_gooses do |t|
4
+ t.index [ :channel_id, :goose_id ]
5
+ t.index [ :goose_id, :channel_id ]
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,48 @@
1
+ module Gaggle
2
+ class Engine < ::Rails::Engine
3
+ require "classy/yaml"
4
+ isolate_namespace Gaggle
5
+
6
+ config.to_prepare do
7
+ Classy::Yaml.setup do |config|
8
+ Gaggle::ApplicationController.helper(Classy::Yaml::Helpers)
9
+ config.engine_files << Engine.root.join("config/utility_classes.yml")
10
+ end
11
+ ::MCP::Rails.configure do |config|
12
+ config.register_engine(Gaggle::Engine, env_vars: [ "GOOSE_USER_ID" ])
13
+ end
14
+ end
15
+
16
+ initializer "gaggle.development_check" do
17
+ unless Rails.env.development? || Rails.env.test?
18
+ warn "Gaggle is intended for development use only. It is not loaded in #{Rails.env} environment."
19
+ end
20
+ end
21
+
22
+ initializer "gaggle.assets" do |app|
23
+ if Gem.loaded_specs.key?("sprockets-rails")
24
+ # Sprockets configuration
25
+ Rails.logger.info "Gaggle: Detected sprockets-rails, configuring for Sprockets"
26
+ app.config.assets.paths << root.join("app/assets/stylesheets")
27
+ app.config.assets.paths << root.join("app/javascript")
28
+ app.config.assets.precompile += %w[ gaggle_manifest ]
29
+ end
30
+ end
31
+
32
+ initializer "gaggle.importmap.assets", before: "importmap" do |app|
33
+ app.config.assets.paths << Engine.root.join("app", "javascript")
34
+ if defined?(Importmap::Engine)
35
+ app.config.importmap.paths << Engine.root.join("config/importmap.rb")
36
+ app.config.importmap.cache_sweepers << Engine.root.join("app/javascript")
37
+ end
38
+ end
39
+
40
+ initializer "gaggle.autoloader" do |app|
41
+ Rails.autoloaders.main.ignore(Gaggle::Engine.root.join("app/models/gaggle/session.rb"))
42
+
43
+ app.config.after_initialize do
44
+ require Gaggle::Engine.root.join("app/models/gaggle/session.rb")
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,3 @@
1
+ module Gaggle
2
+ VERSION = "0.2.2"
3
+ end
data/lib/gaggle.rb ADDED
@@ -0,0 +1,8 @@
1
+ require "gaggle/version"
2
+ require "gaggle/engine"
3
+ require "strings/ansi"
4
+ require "redcarpet"
5
+
6
+ module Gaggle
7
+ # Your code goes here...
8
+ end
@@ -0,0 +1,7 @@
1
+ class Gaggle::InstallGenerator < Rails::Generators::Base
2
+ source_root File.expand_path("templates", __dir__)
3
+
4
+ def copy_files
5
+ template "db/gaggle_schema.rb"
6
+ end
7
+ end
@@ -0,0 +1,59 @@
1
+ ActiveRecord::Schema[7.2].define(version: 1) do
2
+ create_table "gaggle_channels", force: :cascade do |t|
3
+ t.string "name", null: false
4
+ t.datetime "created_at", precision: nil, null: false
5
+ t.datetime "updated_at", precision: nil, null: false
6
+ end
7
+
8
+ create_table "gaggle_channels_gooses", id: false, force: :cascade do |t|
9
+ t.integer "channel_id", null: false
10
+ t.integer "goose_id", null: false
11
+ t.index [ "channel_id", "goose_id" ], name: "index_gaggle_channels_gooses_on_channel_id_and_goose_id"
12
+ t.index [ "goose_id", "channel_id" ], name: "index_gaggle_channels_gooses_on_goose_id_and_channel_id"
13
+ end
14
+
15
+ create_table "gaggle_gooses", force: :cascade do |t|
16
+ t.string "name", null: false
17
+ t.text "prompt"
18
+ t.datetime "created_at", precision: nil, null: false
19
+ t.datetime "updated_at", precision: nil, null: false
20
+ end
21
+
22
+ create_table "gaggle_messages", force: :cascade do |t|
23
+ t.text "content", null: false
24
+ t.integer "goose_id"
25
+ t.datetime "created_at", precision: nil, null: false
26
+ t.datetime "updated_at", precision: nil, null: false
27
+ t.string "messageable_type", null: false
28
+ t.integer "messageable_id", null: false
29
+ t.index [ "goose_id" ], name: "index_gaggle_messages_on_goose_id"
30
+ t.index [ "messageable_type", "messageable_id" ], name: "index_gaggle_messages_on_messageable"
31
+ end
32
+
33
+ create_table "gaggle_notifications", force: :cascade do |t|
34
+ t.integer "message_id"
35
+ t.integer "goose_id"
36
+ t.datetime "read_at", precision: nil
37
+ t.datetime "created_at", precision: nil, null: false
38
+ t.datetime "updated_at", precision: nil, null: false
39
+ t.string "messageable_type", null: false
40
+ t.integer "messageable_id", null: false
41
+ t.datetime "delivered_at"
42
+ t.index [ "goose_id" ], name: "index_gaggle_notifications_on_goose_id"
43
+ t.index [ "message_id" ], name: "index_gaggle_notifications_on_message_id"
44
+ t.index [ "messageable_type", "messageable_id" ], name: "idx_on_messageable_type_messageable_id_e697f3e48f"
45
+ end
46
+
47
+ create_table "gaggle_sessions", force: :cascade do |t|
48
+ t.integer "goose_id", null: false
49
+ t.string "log_file"
50
+ t.datetime "created_at", precision: nil, null: false
51
+ t.datetime "updated_at", precision: nil, null: false
52
+ t.index [ "goose_id" ], name: "index_gaggle_sessions_on_goose_id"
53
+ end
54
+
55
+ add_foreign_key "gaggle_messages", "gaggle_gooses", column: "goose_id"
56
+ add_foreign_key "gaggle_notifications", "gaggle_gooses", column: "goose_id"
57
+ add_foreign_key "gaggle_notifications", "gaggle_messages", column: "message_id"
58
+ add_foreign_key "gaggle_sessions", "gaggle_gooses", column: "goose_id"
59
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "rails/generators/active_record"
5
+
6
+ class Gaggle::UpdateGenerator < Rails::Generators::Base
7
+ include ActiveRecord::Generators::Migration
8
+
9
+ source_root File.expand_path("templates", __dir__)
10
+
11
+ def copy_files
12
+ # For reference
13
+ # migration_template "db/migrate/create_compact_channel.rb",
14
+ # "db/gaggle/create_compact_channel.rb"
15
+ end
16
+ end