htm 0.0.20 → 0.0.30

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 (154) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +60 -0
  3. data/Rakefile +104 -18
  4. data/db/migrate/00001_enable_extensions.rb +9 -5
  5. data/db/migrate/00002_create_robots.rb +18 -6
  6. data/db/migrate/00003_create_file_sources.rb +30 -17
  7. data/db/migrate/00004_create_nodes.rb +60 -48
  8. data/db/migrate/00005_create_tags.rb +24 -12
  9. data/db/migrate/00006_create_node_tags.rb +28 -13
  10. data/db/migrate/00007_create_robot_nodes.rb +40 -26
  11. data/db/schema.sql +17 -1
  12. data/db/seeds.rb +33 -33
  13. data/docs/database/naming-convention.md +244 -0
  14. data/docs/database_rake_tasks.md +31 -0
  15. data/docs/development/rake-tasks.md +80 -35
  16. data/docs/guides/mcp-server.md +70 -1
  17. data/examples/.envrc +6 -0
  18. data/examples/.gitignore +2 -0
  19. data/examples/00_create_examples_db.rb +94 -0
  20. data/examples/{basic_usage.rb → 01_basic_usage.rb} +12 -16
  21. data/examples/{custom_llm_configuration.rb → 03_custom_llm_configuration.rb} +13 -3
  22. data/examples/{file_loader_usage.rb → 04_file_loader_usage.rb} +11 -14
  23. data/examples/{timeframe_demo.rb → 05_timeframe_demo.rb} +10 -3
  24. data/examples/{example_app → 06_example_app}/app.rb +15 -15
  25. data/examples/{cli_app → 07_cli_app}/htm_cli.rb +15 -22
  26. data/examples/08_sinatra_app/Gemfile.lock +241 -0
  27. data/examples/{sinatra_app → 08_sinatra_app}/app.rb +19 -18
  28. data/examples/{mcp_client.rb → 09_mcp_client.rb} +5 -8
  29. data/examples/{telemetry → 10_telemetry}/SETUP_README.md +1 -1
  30. data/examples/{telemetry → 10_telemetry}/demo.rb +14 -10
  31. data/examples/11_robot_groups/README.md +335 -0
  32. data/examples/{robot_groups → 11_robot_groups/lib}/robot_worker.rb +17 -3
  33. data/examples/{robot_groups → 11_robot_groups}/multi_process.rb +9 -9
  34. data/examples/{robot_groups → 11_robot_groups}/same_process.rb +9 -12
  35. data/examples/{rails_app → 12_rails_app}/Gemfile +3 -0
  36. data/examples/{rails_app → 12_rails_app}/Gemfile.lock +87 -58
  37. data/examples/{rails_app → 12_rails_app}/app/controllers/dashboard_controller.rb +10 -6
  38. data/examples/{rails_app → 12_rails_app}/app/controllers/files_controller.rb +5 -5
  39. data/examples/{rails_app → 12_rails_app}/app/controllers/memories_controller.rb +11 -7
  40. data/examples/{rails_app → 12_rails_app}/app/controllers/robots_controller.rb +8 -8
  41. data/examples/12_rails_app/app/controllers/tags_controller.rb +36 -0
  42. data/examples/{rails_app → 12_rails_app}/app/views/dashboard/index.html.erb +2 -2
  43. data/examples/{rails_app → 12_rails_app}/app/views/files/new.html.erb +5 -2
  44. data/examples/{rails_app → 12_rails_app}/app/views/memories/_memory_card.html.erb +3 -3
  45. data/examples/{rails_app → 12_rails_app}/app/views/memories/deleted.html.erb +3 -3
  46. data/examples/{rails_app → 12_rails_app}/app/views/memories/edit.html.erb +3 -3
  47. data/examples/{rails_app → 12_rails_app}/app/views/memories/show.html.erb +4 -4
  48. data/examples/{rails_app → 12_rails_app}/app/views/robots/index.html.erb +2 -2
  49. data/examples/{rails_app → 12_rails_app}/app/views/robots/show.html.erb +4 -4
  50. data/examples/{rails_app → 12_rails_app}/app/views/search/index.html.erb +1 -1
  51. data/examples/{rails_app → 12_rails_app}/app/views/tags/index.html.erb +2 -2
  52. data/examples/{rails_app → 12_rails_app}/app/views/tags/show.html.erb +1 -1
  53. data/examples/12_rails_app/config/initializers/htm.rb +7 -0
  54. data/examples/12_rails_app/config/initializers/rack.rb +5 -0
  55. data/examples/README.md +230 -211
  56. data/examples/examples_helper.rb +138 -0
  57. data/lib/htm/config/builder.rb +167 -0
  58. data/lib/htm/config/database.rb +317 -0
  59. data/lib/htm/config/defaults.yml +37 -9
  60. data/lib/htm/config/section.rb +74 -0
  61. data/lib/htm/config/validator.rb +83 -0
  62. data/lib/htm/config.rb +64 -360
  63. data/lib/htm/database.rb +85 -127
  64. data/lib/htm/errors.rb +14 -0
  65. data/lib/htm/integrations/sinatra.rb +13 -44
  66. data/lib/htm/jobs/generate_embedding_job.rb +3 -4
  67. data/lib/htm/jobs/generate_propositions_job.rb +4 -5
  68. data/lib/htm/jobs/generate_tags_job.rb +16 -15
  69. data/lib/htm/loaders/defaults_loader.rb +23 -0
  70. data/lib/htm/loaders/markdown_loader.rb +17 -15
  71. data/lib/htm/loaders/xdg_config_loader.rb +9 -9
  72. data/lib/htm/long_term_memory/fulltext_search.rb +14 -14
  73. data/lib/htm/long_term_memory/hybrid_search.rb +396 -229
  74. data/lib/htm/long_term_memory/node_operations.rb +24 -23
  75. data/lib/htm/long_term_memory/relevance_scorer.rb +23 -20
  76. data/lib/htm/long_term_memory/robot_operations.rb +4 -4
  77. data/lib/htm/long_term_memory/tag_operations.rb +91 -77
  78. data/lib/htm/long_term_memory/vector_search.rb +4 -5
  79. data/lib/htm/long_term_memory.rb +13 -13
  80. data/lib/htm/mcp/cli.rb +115 -8
  81. data/lib/htm/mcp/resources.rb +4 -3
  82. data/lib/htm/mcp/server.rb +5 -4
  83. data/lib/htm/mcp/tools.rb +37 -28
  84. data/lib/htm/migration.rb +72 -0
  85. data/lib/htm/models/file_source.rb +52 -31
  86. data/lib/htm/models/node.rb +224 -108
  87. data/lib/htm/models/node_tag.rb +49 -28
  88. data/lib/htm/models/robot.rb +38 -27
  89. data/lib/htm/models/robot_node.rb +63 -35
  90. data/lib/htm/models/tag.rb +126 -123
  91. data/lib/htm/observability.rb +45 -41
  92. data/lib/htm/proposition_service.rb +76 -7
  93. data/lib/htm/railtie.rb +2 -2
  94. data/lib/htm/robot_group.rb +30 -18
  95. data/lib/htm/sequel_config.rb +215 -0
  96. data/lib/htm/sql_builder.rb +14 -16
  97. data/lib/htm/tag_service.rb +78 -0
  98. data/lib/htm/tasks.rb +3 -0
  99. data/lib/htm/version.rb +1 -1
  100. data/lib/htm/workflows/remember_workflow.rb +6 -5
  101. data/lib/htm.rb +26 -22
  102. data/lib/tasks/db.rake +0 -2
  103. data/lib/tasks/doc.rake +2 -2
  104. data/lib/tasks/files.rake +11 -18
  105. data/lib/tasks/htm.rake +190 -62
  106. data/lib/tasks/jobs.rake +179 -54
  107. data/lib/tasks/tags.rake +8 -13
  108. data/scripts/backfill_parent_tags.rb +376 -0
  109. data/scripts/normalize_plural_tags.rb +335 -0
  110. metadata +109 -80
  111. data/examples/rails_app/app/controllers/tags_controller.rb +0 -30
  112. data/examples/sinatra_app/Gemfile.lock +0 -166
  113. data/lib/htm/active_record_config.rb +0 -104
  114. /data/examples/{config_file_example → 02_config_file_example}/README.md +0 -0
  115. /data/examples/{config_file_example → 02_config_file_example}/config/htm.local.yml +0 -0
  116. /data/examples/{config_file_example → 02_config_file_example}/custom_config.yml +0 -0
  117. /data/examples/{config_file_example → 02_config_file_example}/show_config.rb +0 -0
  118. /data/examples/{example_app → 06_example_app}/Rakefile +0 -0
  119. /data/examples/{cli_app → 07_cli_app}/README.md +0 -0
  120. /data/examples/{sinatra_app → 08_sinatra_app}/Gemfile +0 -0
  121. /data/examples/{telemetry → 10_telemetry}/README.md +0 -0
  122. /data/examples/{telemetry → 10_telemetry}/grafana/dashboards/htm-metrics.json +0 -0
  123. /data/examples/{rails_app → 12_rails_app}/.gitignore +0 -0
  124. /data/examples/{rails_app → 12_rails_app}/Procfile.dev +0 -0
  125. /data/examples/{rails_app → 12_rails_app}/README.md +0 -0
  126. /data/examples/{rails_app → 12_rails_app}/Rakefile +0 -0
  127. /data/examples/{rails_app → 12_rails_app}/app/assets/stylesheets/application.css +0 -0
  128. /data/examples/{rails_app → 12_rails_app}/app/assets/stylesheets/inter-font.css +0 -0
  129. /data/examples/{rails_app → 12_rails_app}/app/controllers/application_controller.rb +0 -0
  130. /data/examples/{rails_app → 12_rails_app}/app/controllers/search_controller.rb +0 -0
  131. /data/examples/{rails_app → 12_rails_app}/app/javascript/application.js +0 -0
  132. /data/examples/{rails_app → 12_rails_app}/app/javascript/controllers/application.js +0 -0
  133. /data/examples/{rails_app → 12_rails_app}/app/javascript/controllers/index.js +0 -0
  134. /data/examples/{rails_app → 12_rails_app}/app/views/files/index.html.erb +0 -0
  135. /data/examples/{rails_app → 12_rails_app}/app/views/files/show.html.erb +0 -0
  136. /data/examples/{rails_app → 12_rails_app}/app/views/layouts/application.html.erb +0 -0
  137. /data/examples/{rails_app → 12_rails_app}/app/views/memories/index.html.erb +0 -0
  138. /data/examples/{rails_app → 12_rails_app}/app/views/memories/new.html.erb +0 -0
  139. /data/examples/{rails_app → 12_rails_app}/app/views/robots/new.html.erb +0 -0
  140. /data/examples/{rails_app → 12_rails_app}/app/views/shared/_navbar.html.erb +0 -0
  141. /data/examples/{rails_app → 12_rails_app}/app/views/shared/_stat_card.html.erb +0 -0
  142. /data/examples/{rails_app → 12_rails_app}/bin/dev +0 -0
  143. /data/examples/{rails_app → 12_rails_app}/bin/rails +0 -0
  144. /data/examples/{rails_app → 12_rails_app}/bin/rake +0 -0
  145. /data/examples/{rails_app → 12_rails_app}/config/application.rb +0 -0
  146. /data/examples/{rails_app → 12_rails_app}/config/boot.rb +0 -0
  147. /data/examples/{rails_app → 12_rails_app}/config/database.yml +0 -0
  148. /data/examples/{rails_app → 12_rails_app}/config/environment.rb +0 -0
  149. /data/examples/{rails_app → 12_rails_app}/config/importmap.rb +0 -0
  150. /data/examples/{rails_app → 12_rails_app}/config/routes.rb +0 -0
  151. /data/examples/{rails_app → 12_rails_app}/config/tailwind.config.js +0 -0
  152. /data/examples/{rails_app → 12_rails_app}/config.ru +0 -0
  153. /data/examples/{rails_app → 12_rails_app}/log/.keep +0 -0
  154. /data/examples/{rails_app → 12_rails_app}/tmp/local_secret.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  <div class="space-y-6">
2
2
  <!-- Back link -->
3
3
  <div>
4
- <%= link_to memory_path(@memory), class: 'inline-flex items-center gap-1 text-sm text-gray-400 hover:text-white transition-colors' do %>
4
+ <%= link_to memory_path(@memory.id), class: 'inline-flex items-center gap-1 text-sm text-gray-400 hover:text-white transition-colors' do %>
5
5
  <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
6
6
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
7
7
  </svg>
@@ -13,7 +13,7 @@
13
13
  <div class="rounded-lg bg-gray-800 border border-gray-700 p-6">
14
14
  <h1 class="text-xl font-bold text-white mb-6">Edit Memory</h1>
15
15
 
16
- <%= form_with url: memory_path(@memory), method: :patch, class: 'space-y-6' do %>
16
+ <%= form_with url: memory_path(@memory.id), method: :patch, class: 'space-y-6' do %>
17
17
  <div>
18
18
  <label for="content" class="block text-sm font-medium text-gray-300 mb-2">Content</label>
19
19
  <textarea
@@ -28,7 +28,7 @@
28
28
 
29
29
  <div class="flex items-center gap-4 pt-4 border-t border-gray-700">
30
30
  <%= submit_tag 'Update Memory', class: 'rounded-md bg-indigo-600 px-4 py-2 text-sm font-medium text-white hover:bg-indigo-500 cursor-pointer transition-colors' %>
31
- <%= link_to 'Cancel', memory_path(@memory), class: 'rounded-md bg-gray-700 px-4 py-2 text-sm font-medium text-white hover:bg-gray-600 transition-colors' %>
31
+ <%= link_to 'Cancel', memory_path(@memory.id), class: 'rounded-md bg-gray-700 px-4 py-2 text-sm font-medium text-white hover:bg-gray-600 transition-colors' %>
32
32
  </div>
33
33
  <% end %>
34
34
  </div>
@@ -35,26 +35,26 @@
35
35
 
36
36
  <div class="flex items-center gap-2">
37
37
  <% if @memory.deleted? %>
38
- <%= button_to restore_memory_path(@memory), method: :post, class: 'inline-flex items-center gap-2 rounded-md bg-green-600 px-3 py-2 text-sm font-medium text-white hover:bg-green-500 transition-colors' do %>
38
+ <%= button_to restore_memory_path(@memory.id), method: :post, class: 'inline-flex items-center gap-2 rounded-md bg-green-600 px-3 py-2 text-sm font-medium text-white hover:bg-green-500 transition-colors' do %>
39
39
  <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
40
40
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
41
41
  </svg>
42
42
  Restore
43
43
  <% end %>
44
- <%= button_to memory_path(@memory, permanent: true), method: :delete, class: 'inline-flex items-center gap-2 rounded-md bg-red-600 px-3 py-2 text-sm font-medium text-white hover:bg-red-500 transition-colors', data: { turbo_confirm: 'Permanently delete this memory? This cannot be undone!' } do %>
44
+ <%= button_to memory_path(@memory.id, permanent: true), method: :delete, class: 'inline-flex items-center gap-2 rounded-md bg-red-600 px-3 py-2 text-sm font-medium text-white hover:bg-red-500 transition-colors', data: { turbo_confirm: 'Permanently delete this memory? This cannot be undone!' } do %>
45
45
  <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
46
46
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
47
47
  </svg>
48
48
  Delete Forever
49
49
  <% end %>
50
50
  <% else %>
51
- <%= link_to edit_memory_path(@memory), class: 'inline-flex items-center gap-2 rounded-md bg-gray-700 px-3 py-2 text-sm font-medium text-white hover:bg-gray-600 transition-colors' do %>
51
+ <%= link_to edit_memory_path(@memory.id), class: 'inline-flex items-center gap-2 rounded-md bg-gray-700 px-3 py-2 text-sm font-medium text-white hover:bg-gray-600 transition-colors' do %>
52
52
  <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
53
53
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
54
54
  </svg>
55
55
  Edit
56
56
  <% end %>
57
- <%= button_to memory_path(@memory), method: :delete, class: 'inline-flex items-center gap-2 rounded-md bg-red-600/80 px-3 py-2 text-sm font-medium text-white hover:bg-red-600 transition-colors', data: { turbo_confirm: 'Move this memory to trash?' } do %>
57
+ <%= button_to memory_path(@memory.id), method: :delete, class: 'inline-flex items-center gap-2 rounded-md bg-red-600/80 px-3 py-2 text-sm font-medium text-white hover:bg-red-600 transition-colors', data: { turbo_confirm: 'Move this memory to trash?' } do %>
58
58
  <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
59
59
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
60
60
  </svg>
@@ -80,9 +80,9 @@
80
80
  <div class="mt-4 pt-4 border-t border-gray-700 flex items-center justify-between">
81
81
  <p class="text-sm text-gray-400"><%= robot.nodes.count %> memories</p>
82
82
  <div class="flex items-center gap-2">
83
- <%= link_to 'View', robot_path(robot), class: 'text-sm text-indigo-400 hover:text-indigo-300' %>
83
+ <%= link_to 'View', robot_path(robot.id), class: 'text-sm text-indigo-400 hover:text-indigo-300' %>
84
84
  <% unless robot.name == current_robot_name %>
85
- <%= button_to switch_robot_path(robot), method: :post, class: 'inline-flex items-center gap-1 text-sm text-green-400 hover:text-green-300 bg-transparent border-0 cursor-pointer', title: "Switch to #{robot.name} - new memories will be created under this robot" do %>
85
+ <%= button_to switch_robot_path(robot.id), method: :post, class: 'inline-flex items-center gap-1 text-sm text-green-400 hover:text-green-300 bg-transparent border-0 cursor-pointer', title: "Switch to #{robot.name} - new memories will be created under this robot" do %>
86
86
  <svg class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
87
87
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" />
88
88
  </svg>
@@ -31,7 +31,7 @@
31
31
  Active
32
32
  </span>
33
33
  <% else %>
34
- <%= button_to switch_robot_path(@robot), method: :post, class: 'inline-flex items-center gap-2 rounded-md bg-indigo-600 px-4 py-2 text-sm font-medium text-white hover:bg-indigo-500 transition-colors' do %>
34
+ <%= button_to switch_robot_path(@robot.id), method: :post, class: 'inline-flex items-center gap-2 rounded-md bg-indigo-600 px-4 py-2 text-sm font-medium text-white hover:bg-indigo-500 transition-colors' do %>
35
35
  Switch to this robot
36
36
  <% end %>
37
37
  <% end %>
@@ -45,11 +45,11 @@
45
45
  <p class="text-sm text-gray-400">Total Memories</p>
46
46
  </div>
47
47
  <div>
48
- <p class="text-2xl font-bold text-white"><%= @robot.nodes.where.not(embedding: nil).count %></p>
48
+ <p class="text-2xl font-bold text-white"><%= @robot.nodes_dataset.exclude(embedding: nil).count %></p>
49
49
  <p class="text-sm text-gray-400">With Embeddings</p>
50
50
  </div>
51
51
  <div>
52
- <p class="text-2xl font-bold text-white"><%= @robot.nodes.joins(:tags).distinct.count('tags.id') %></p>
52
+ <p class="text-2xl font-bold text-white"><%= @robot.nodes_dataset.join(:node_tags, node_id: Sequel[:nodes][:id]).distinct.select(:tag_id).count %></p>
53
53
  <p class="text-sm text-gray-400">Unique Tags</p>
54
54
  </div>
55
55
  </div>
@@ -61,7 +61,7 @@
61
61
  <% if @recent_memories.any? %>
62
62
  <div class="space-y-3">
63
63
  <% @recent_memories.each do |memory| %>
64
- <%= link_to memory_path(memory), class: 'block rounded-md bg-gray-700/50 p-3 hover:bg-gray-700 transition-colors' do %>
64
+ <%= link_to memory_path(memory.id), class: 'block rounded-md bg-gray-700/50 p-3 hover:bg-gray-700 transition-colors' do %>
65
65
  <p class="text-sm text-gray-300 line-clamp-2"><%= memory.content %></p>
66
66
  <div class="mt-2 flex items-center gap-2 text-xs text-gray-500">
67
67
  <span><%= time_ago_in_words(memory.created_at) %> ago</span>
@@ -7,7 +7,7 @@
7
7
 
8
8
  <!-- Search Form -->
9
9
  <div class="rounded-lg bg-gray-800 border border-gray-700 p-6">
10
- <%= form_with url: search_path, method: :get, class: 'space-y-4' do %>
10
+ <%= form_with url: search_path, method: :get, class: 'space-y-4', data: { turbo: false } do %>
11
11
  <div>
12
12
  <label for="query" class="block text-sm font-medium text-gray-300 mb-2">Search Query</label>
13
13
  <div class="flex gap-4">
@@ -88,7 +88,7 @@
88
88
  <% @tags.each do |tag| %>
89
89
  <tr class="hover:bg-gray-700/50 transition-colors">
90
90
  <td class="px-6 py-4 whitespace-nowrap">
91
- <%= link_to tag_path(tag), class: 'inline-flex items-center rounded-full bg-indigo-900/50 border border-indigo-500/30 px-3 py-1 text-sm text-indigo-300 hover:bg-indigo-800/50 transition-colors' do %>
91
+ <%= link_to tag_path(tag.id), class: 'inline-flex items-center rounded-full bg-indigo-900/50 border border-indigo-500/30 px-3 py-1 text-sm text-indigo-300 hover:bg-indigo-800/50 transition-colors' do %>
92
92
  <%= tag.name %>
93
93
  <% end %>
94
94
  </td>
@@ -103,7 +103,7 @@
103
103
  <%= tag.node_count %>
104
104
  </td>
105
105
  <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
106
- <%= link_to 'View', tag_path(tag), class: 'text-indigo-400 hover:text-indigo-300' %>
106
+ <%= link_to 'View', tag_path(tag.id), class: 'text-indigo-400 hover:text-indigo-300' %>
107
107
  <span class="mx-2 text-gray-600">|</span>
108
108
  <%= link_to 'Filter Memories', memories_path(tag: tag.name), class: 'text-indigo-400 hover:text-indigo-300' %>
109
109
  </td>
@@ -32,7 +32,7 @@
32
32
  </svg>
33
33
  <% end %>
34
34
  <% prefix = parts[0..i].join(':') %>
35
- <% matching_tag = HTM::Models::Tag.find_by(name: prefix) %>
35
+ <% matching_tag = HTM::Models::Tag.first(name: prefix) %>
36
36
  <% if matching_tag %>
37
37
  <%= link_to part, tag_path(matching_tag), class: "#{i == parts.length - 1 ? 'text-indigo-400' : 'text-gray-400 hover:text-white'}" %>
38
38
  <% else %>
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Override the examples_helper.rb :inline setting for the Rails app
4
+ # Use fiber-based async jobs for better responsiveness
5
+ HTM.configure do |config|
6
+ config.job.backend = :fiber
7
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Increase multipart file upload limit for directory uploads
4
+ # Default is 128 parts, increase to 4096 for large directories
5
+ Rack::Utils.multipart_part_limit = 4096