htm 0.0.18 → 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 (216) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +119 -1
  3. data/README.md +12 -0
  4. data/Rakefile +104 -18
  5. data/db/migrate/00001_enable_extensions.rb +9 -5
  6. data/db/migrate/00002_create_robots.rb +18 -6
  7. data/db/migrate/00003_create_file_sources.rb +30 -17
  8. data/db/migrate/00004_create_nodes.rb +60 -48
  9. data/db/migrate/00005_create_tags.rb +24 -12
  10. data/db/migrate/00006_create_node_tags.rb +28 -13
  11. data/db/migrate/00007_create_robot_nodes.rb +40 -26
  12. data/db/schema.sql +17 -1
  13. data/db/seeds.rb +34 -34
  14. data/docs/api/embedding-service.md +140 -110
  15. data/docs/api/yard/HTM/ActiveRecordConfig.md +6 -0
  16. data/docs/api/yard/HTM/Config.md +173 -0
  17. data/docs/api/yard/HTM/ConfigSection.md +28 -0
  18. data/docs/api/yard/HTM/Database.md +1 -1
  19. data/docs/api/yard/HTM/Railtie.md +2 -2
  20. data/docs/api/yard/HTM.md +0 -57
  21. data/docs/api/yard/index.csv +76 -61
  22. data/docs/api/yard-reference.md +2 -1
  23. data/docs/architecture/adrs/003-ollama-embeddings.md +45 -36
  24. data/docs/architecture/adrs/004-hive-mind.md +1 -1
  25. data/docs/architecture/adrs/008-robot-identification.md +1 -1
  26. data/docs/architecture/index.md +11 -9
  27. data/docs/architecture/overview.md +11 -7
  28. data/docs/assets/images/balanced-strategy-decay.svg +41 -0
  29. data/docs/assets/images/class-hierarchy.svg +1 -1
  30. data/docs/assets/images/eviction-priority.svg +43 -0
  31. data/docs/assets/images/exception-hierarchy.svg +2 -2
  32. data/docs/assets/images/hive-mind-shared-memory.svg +52 -0
  33. data/docs/assets/images/htm-architecture-overview.svg +3 -3
  34. data/docs/assets/images/htm-core-components.svg +4 -4
  35. data/docs/assets/images/htm-layered-architecture.svg +1 -1
  36. data/docs/assets/images/htm-memory-addition-flow.svg +2 -2
  37. data/docs/assets/images/htm-memory-recall-flow.svg +2 -2
  38. data/docs/assets/images/memory-topology.svg +53 -0
  39. data/docs/assets/images/two-tier-memory-architecture.svg +55 -0
  40. data/docs/database/naming-convention.md +244 -0
  41. data/docs/database_rake_tasks.md +31 -0
  42. data/docs/development/rake-tasks.md +80 -35
  43. data/docs/development/setup.md +76 -44
  44. data/docs/examples/basic-usage.md +133 -0
  45. data/docs/examples/config-files.md +170 -0
  46. data/docs/examples/file-loading.md +208 -0
  47. data/docs/examples/index.md +116 -0
  48. data/docs/examples/llm-configuration.md +168 -0
  49. data/docs/examples/mcp-client.md +172 -0
  50. data/docs/examples/rails-integration.md +173 -0
  51. data/docs/examples/robot-groups.md +210 -0
  52. data/docs/examples/sinatra-integration.md +218 -0
  53. data/docs/examples/standalone-app.md +216 -0
  54. data/docs/examples/telemetry.md +224 -0
  55. data/docs/examples/timeframes.md +143 -0
  56. data/docs/getting-started/installation.md +97 -40
  57. data/docs/getting-started/quick-start.md +28 -11
  58. data/docs/guides/configuration.md +515 -0
  59. data/docs/guides/file-loading.md +322 -0
  60. data/docs/guides/getting-started.md +40 -9
  61. data/docs/guides/index.md +3 -3
  62. data/docs/guides/mcp-server.md +100 -13
  63. data/docs/guides/propositions.md +264 -0
  64. data/docs/guides/recalling-memories.md +4 -4
  65. data/docs/guides/search-strategies.md +3 -3
  66. data/docs/guides/tags.md +318 -0
  67. data/docs/guides/telemetry.md +229 -0
  68. data/docs/index.md +8 -16
  69. data/docs/{architecture → robots}/hive-mind.md +8 -111
  70. data/docs/robots/index.md +73 -0
  71. data/docs/{guides → robots}/multi-robot.md +3 -3
  72. data/docs/{guides → robots}/robot-groups.md +8 -7
  73. data/docs/{architecture → robots}/two-tier-memory.md +13 -149
  74. data/docs/robots/why-robots.md +85 -0
  75. data/examples/.envrc +6 -0
  76. data/examples/.gitignore +2 -0
  77. data/examples/00_create_examples_db.rb +94 -0
  78. data/examples/{basic_usage.rb → 01_basic_usage.rb} +12 -16
  79. data/examples/{custom_llm_configuration.rb → 03_custom_llm_configuration.rb} +13 -3
  80. data/examples/{file_loader_usage.rb → 04_file_loader_usage.rb} +11 -14
  81. data/examples/{timeframe_demo.rb → 05_timeframe_demo.rb} +10 -3
  82. data/examples/{example_app → 06_example_app}/app.rb +15 -15
  83. data/examples/{cli_app → 07_cli_app}/htm_cli.rb +15 -22
  84. data/examples/08_sinatra_app/Gemfile.lock +241 -0
  85. data/examples/{sinatra_app → 08_sinatra_app}/app.rb +19 -18
  86. data/examples/{mcp_client.rb → 09_mcp_client.rb} +5 -8
  87. data/examples/{telemetry → 10_telemetry}/SETUP_README.md +1 -1
  88. data/examples/{telemetry → 10_telemetry}/demo.rb +14 -10
  89. data/examples/11_robot_groups/README.md +335 -0
  90. data/examples/{robot_groups → 11_robot_groups/lib}/robot_worker.rb +17 -3
  91. data/examples/{robot_groups → 11_robot_groups}/multi_process.rb +9 -9
  92. data/examples/{robot_groups → 11_robot_groups}/same_process.rb +9 -12
  93. data/examples/{rails_app → 12_rails_app}/Gemfile +3 -0
  94. data/examples/{rails_app → 12_rails_app}/Gemfile.lock +87 -58
  95. data/examples/{rails_app → 12_rails_app}/app/controllers/dashboard_controller.rb +10 -6
  96. data/examples/{rails_app → 12_rails_app}/app/controllers/files_controller.rb +5 -5
  97. data/examples/{rails_app → 12_rails_app}/app/controllers/memories_controller.rb +11 -7
  98. data/examples/{rails_app → 12_rails_app}/app/controllers/robots_controller.rb +8 -8
  99. data/examples/12_rails_app/app/controllers/tags_controller.rb +36 -0
  100. data/examples/{rails_app → 12_rails_app}/app/views/dashboard/index.html.erb +2 -2
  101. data/examples/{rails_app → 12_rails_app}/app/views/files/new.html.erb +5 -2
  102. data/examples/{rails_app → 12_rails_app}/app/views/memories/_memory_card.html.erb +3 -3
  103. data/examples/{rails_app → 12_rails_app}/app/views/memories/deleted.html.erb +3 -3
  104. data/examples/{rails_app → 12_rails_app}/app/views/memories/edit.html.erb +3 -3
  105. data/examples/{rails_app → 12_rails_app}/app/views/memories/show.html.erb +4 -4
  106. data/examples/{rails_app → 12_rails_app}/app/views/robots/index.html.erb +2 -2
  107. data/examples/{rails_app → 12_rails_app}/app/views/robots/show.html.erb +4 -4
  108. data/examples/{rails_app → 12_rails_app}/app/views/search/index.html.erb +1 -1
  109. data/examples/{rails_app → 12_rails_app}/app/views/tags/index.html.erb +2 -2
  110. data/examples/{rails_app → 12_rails_app}/app/views/tags/show.html.erb +1 -1
  111. data/examples/12_rails_app/config/initializers/htm.rb +7 -0
  112. data/examples/12_rails_app/config/initializers/rack.rb +5 -0
  113. data/examples/README.md +230 -211
  114. data/examples/examples_helper.rb +138 -0
  115. data/lib/htm/config/builder.rb +167 -0
  116. data/lib/htm/config/database.rb +317 -0
  117. data/lib/htm/config/defaults.yml +41 -13
  118. data/lib/htm/config/section.rb +74 -0
  119. data/lib/htm/config/validator.rb +83 -0
  120. data/lib/htm/config.rb +65 -361
  121. data/lib/htm/database.rb +85 -127
  122. data/lib/htm/errors.rb +14 -0
  123. data/lib/htm/integrations/sinatra.rb +13 -44
  124. data/lib/htm/job_adapter.rb +75 -1
  125. data/lib/htm/jobs/generate_embedding_job.rb +3 -4
  126. data/lib/htm/jobs/generate_propositions_job.rb +4 -5
  127. data/lib/htm/jobs/generate_tags_job.rb +16 -15
  128. data/lib/htm/loaders/defaults_loader.rb +23 -0
  129. data/lib/htm/loaders/markdown_loader.rb +17 -15
  130. data/lib/htm/loaders/xdg_config_loader.rb +9 -9
  131. data/lib/htm/long_term_memory/fulltext_search.rb +14 -14
  132. data/lib/htm/long_term_memory/hybrid_search.rb +396 -229
  133. data/lib/htm/long_term_memory/node_operations.rb +24 -23
  134. data/lib/htm/long_term_memory/relevance_scorer.rb +23 -20
  135. data/lib/htm/long_term_memory/robot_operations.rb +4 -4
  136. data/lib/htm/long_term_memory/tag_operations.rb +91 -77
  137. data/lib/htm/long_term_memory/vector_search.rb +4 -5
  138. data/lib/htm/long_term_memory.rb +13 -13
  139. data/lib/htm/mcp/cli.rb +115 -8
  140. data/lib/htm/mcp/resources.rb +4 -3
  141. data/lib/htm/mcp/server.rb +5 -4
  142. data/lib/htm/mcp/tools.rb +37 -28
  143. data/lib/htm/migration.rb +72 -0
  144. data/lib/htm/models/file_source.rb +52 -31
  145. data/lib/htm/models/node.rb +224 -108
  146. data/lib/htm/models/node_tag.rb +49 -28
  147. data/lib/htm/models/robot.rb +38 -27
  148. data/lib/htm/models/robot_node.rb +63 -35
  149. data/lib/htm/models/tag.rb +126 -123
  150. data/lib/htm/observability.rb +45 -41
  151. data/lib/htm/proposition_service.rb +76 -7
  152. data/lib/htm/railtie.rb +2 -2
  153. data/lib/htm/robot_group.rb +30 -18
  154. data/lib/htm/sequel_config.rb +215 -0
  155. data/lib/htm/sql_builder.rb +14 -16
  156. data/lib/htm/tag_service.rb +78 -0
  157. data/lib/htm/tasks.rb +3 -0
  158. data/lib/htm/version.rb +1 -1
  159. data/lib/htm/workflows/remember_workflow.rb +213 -0
  160. data/lib/htm.rb +27 -22
  161. data/lib/tasks/db.rake +0 -2
  162. data/lib/tasks/doc.rake +2 -2
  163. data/lib/tasks/files.rake +11 -18
  164. data/lib/tasks/htm.rake +190 -62
  165. data/lib/tasks/jobs.rake +179 -54
  166. data/lib/tasks/tags.rake +8 -13
  167. data/mkdocs.yml +33 -8
  168. data/scripts/backfill_parent_tags.rb +376 -0
  169. data/scripts/normalize_plural_tags.rb +335 -0
  170. metadata +168 -86
  171. data/docs/api/yard/HTM/Configuration.md +0 -240
  172. data/docs/telemetry.md +0 -391
  173. data/examples/rails_app/app/controllers/tags_controller.rb +0 -30
  174. data/examples/sinatra_app/Gemfile.lock +0 -166
  175. data/lib/htm/active_record_config.rb +0 -104
  176. /data/examples/{config_file_example → 02_config_file_example}/README.md +0 -0
  177. /data/examples/{config_file_example → 02_config_file_example}/config/htm.local.yml +0 -0
  178. /data/examples/{config_file_example → 02_config_file_example}/custom_config.yml +0 -0
  179. /data/examples/{config_file_example → 02_config_file_example}/show_config.rb +0 -0
  180. /data/examples/{example_app → 06_example_app}/Rakefile +0 -0
  181. /data/examples/{cli_app → 07_cli_app}/README.md +0 -0
  182. /data/examples/{sinatra_app → 08_sinatra_app}/Gemfile +0 -0
  183. /data/examples/{telemetry → 10_telemetry}/README.md +0 -0
  184. /data/examples/{telemetry → 10_telemetry}/grafana/dashboards/htm-metrics.json +0 -0
  185. /data/examples/{rails_app → 12_rails_app}/.gitignore +0 -0
  186. /data/examples/{rails_app → 12_rails_app}/Procfile.dev +0 -0
  187. /data/examples/{rails_app → 12_rails_app}/README.md +0 -0
  188. /data/examples/{rails_app → 12_rails_app}/Rakefile +0 -0
  189. /data/examples/{rails_app → 12_rails_app}/app/assets/stylesheets/application.css +0 -0
  190. /data/examples/{rails_app → 12_rails_app}/app/assets/stylesheets/inter-font.css +0 -0
  191. /data/examples/{rails_app → 12_rails_app}/app/controllers/application_controller.rb +0 -0
  192. /data/examples/{rails_app → 12_rails_app}/app/controllers/search_controller.rb +0 -0
  193. /data/examples/{rails_app → 12_rails_app}/app/javascript/application.js +0 -0
  194. /data/examples/{rails_app → 12_rails_app}/app/javascript/controllers/application.js +0 -0
  195. /data/examples/{rails_app → 12_rails_app}/app/javascript/controllers/index.js +0 -0
  196. /data/examples/{rails_app → 12_rails_app}/app/views/files/index.html.erb +0 -0
  197. /data/examples/{rails_app → 12_rails_app}/app/views/files/show.html.erb +0 -0
  198. /data/examples/{rails_app → 12_rails_app}/app/views/layouts/application.html.erb +0 -0
  199. /data/examples/{rails_app → 12_rails_app}/app/views/memories/index.html.erb +0 -0
  200. /data/examples/{rails_app → 12_rails_app}/app/views/memories/new.html.erb +0 -0
  201. /data/examples/{rails_app → 12_rails_app}/app/views/robots/new.html.erb +0 -0
  202. /data/examples/{rails_app → 12_rails_app}/app/views/shared/_navbar.html.erb +0 -0
  203. /data/examples/{rails_app → 12_rails_app}/app/views/shared/_stat_card.html.erb +0 -0
  204. /data/examples/{rails_app → 12_rails_app}/bin/dev +0 -0
  205. /data/examples/{rails_app → 12_rails_app}/bin/rails +0 -0
  206. /data/examples/{rails_app → 12_rails_app}/bin/rake +0 -0
  207. /data/examples/{rails_app → 12_rails_app}/config/application.rb +0 -0
  208. /data/examples/{rails_app → 12_rails_app}/config/boot.rb +0 -0
  209. /data/examples/{rails_app → 12_rails_app}/config/database.yml +0 -0
  210. /data/examples/{rails_app → 12_rails_app}/config/environment.rb +0 -0
  211. /data/examples/{rails_app → 12_rails_app}/config/importmap.rb +0 -0
  212. /data/examples/{rails_app → 12_rails_app}/config/routes.rb +0 -0
  213. /data/examples/{rails_app → 12_rails_app}/config/tailwind.config.js +0 -0
  214. /data/examples/{rails_app → 12_rails_app}/config.ru +0 -0
  215. /data/examples/{rails_app → 12_rails_app}/log/.keep +0 -0
  216. /data/examples/{rails_app → 12_rails_app}/tmp/local_secret.txt +0 -0
@@ -1,17 +1,20 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- htm (0.0.18)
5
- activerecord
4
+ htm (0.0.21)
5
+ activesupport
6
6
  anyway_config (>= 2.6)
7
+ async (~> 2.0)
7
8
  baran
8
9
  chronic
9
10
  fast-mcp
10
11
  lru_redux
11
- neighbor
12
12
  pg (>= 1.5.0)
13
13
  ruby-progressbar
14
14
  ruby_llm
15
+ sequel (>= 5.0)
16
+ sequel_pg
17
+ simple_flow
15
18
  tiktoken_ruby
16
19
 
17
20
  GEM
@@ -94,16 +97,26 @@ GEM
94
97
  public_suffix (>= 2.0.2, < 8.0)
95
98
  anyway_config (2.7.2)
96
99
  ruby-next-core (~> 1.0)
100
+ async (2.36.0)
101
+ console (~> 1.29)
102
+ fiber-annotation
103
+ io-event (~> 1.11)
104
+ metrics (~> 0.12)
105
+ traces (~> 0.18)
97
106
  baran (0.2.1)
98
107
  base64 (0.3.0)
99
108
  benchmark (0.5.0)
100
- bigdecimal (3.3.1)
109
+ bigdecimal (4.0.1)
101
110
  bindex (0.8.1)
102
111
  builder (3.3.0)
103
112
  cgi (0.5.1)
104
113
  chronic (0.10.2)
105
114
  concurrent-ruby (1.3.6)
106
115
  connection_pool (3.0.2)
116
+ console (1.34.2)
117
+ fiber-annotation
118
+ fiber-local (~> 1.1)
119
+ json
107
120
  crass (1.0.6)
108
121
  date (3.5.1)
109
122
  debug_me (1.1.3)
@@ -111,27 +124,27 @@ GEM
111
124
  dry-configurable (1.3.0)
112
125
  dry-core (~> 1.1)
113
126
  zeitwerk (~> 2.6)
114
- dry-core (1.1.0)
127
+ dry-core (1.2.0)
115
128
  concurrent-ruby (~> 1.0)
116
129
  logger
117
130
  zeitwerk (~> 2.6)
118
- dry-inflector (1.2.0)
131
+ dry-inflector (1.3.1)
119
132
  dry-initializer (3.2.0)
120
133
  dry-logic (1.6.0)
121
134
  bigdecimal
122
135
  concurrent-ruby (~> 1.0)
123
136
  dry-core (~> 1.1)
124
137
  zeitwerk (~> 2.6)
125
- dry-schema (1.14.1)
138
+ dry-schema (1.15.0)
126
139
  concurrent-ruby (~> 1.0)
127
140
  dry-configurable (~> 1.0, >= 1.0.1)
128
141
  dry-core (~> 1.1)
129
142
  dry-initializer (~> 3.2)
130
- dry-logic (~> 1.5)
143
+ dry-logic (~> 1.6)
131
144
  dry-types (~> 1.8)
132
145
  zeitwerk (~> 2.6)
133
- dry-types (1.8.3)
134
- bigdecimal (~> 3.0)
146
+ dry-types (1.9.0)
147
+ bigdecimal (>= 3.0)
135
148
  concurrent-ruby (~> 1.0)
136
149
  dry-core (~> 1.0)
137
150
  dry-inflector (~> 1.0)
@@ -144,11 +157,11 @@ GEM
144
157
  faraday-net_http (>= 2.0, < 3.5)
145
158
  json
146
159
  logger
147
- faraday-multipart (1.1.1)
160
+ faraday-multipart (1.2.0)
148
161
  multipart-post (~> 2.0)
149
162
  faraday-net_http (3.4.2)
150
163
  net-http (~> 0.5)
151
- faraday-retry (2.3.2)
164
+ faraday-retry (2.4.0)
152
165
  faraday (~> 2.0)
153
166
  fast-mcp (1.6.0)
154
167
  addressable (~> 2.8)
@@ -157,11 +170,16 @@ GEM
157
170
  json (~> 2.0)
158
171
  mime-types (~> 3.4)
159
172
  rack (>= 2.0, < 4.0)
173
+ fiber-annotation (0.2.0)
174
+ fiber-local (1.1.0)
175
+ fiber-storage
176
+ fiber-storage (1.0.1)
160
177
  globalid (1.3.0)
161
178
  activesupport (>= 6.1)
162
- i18n (1.14.7)
179
+ i18n (1.14.8)
163
180
  concurrent-ruby (~> 1.0)
164
181
  io-console (0.8.2)
182
+ io-event (1.14.2)
165
183
  irb (1.16.0)
166
184
  pp (>= 0.6.0)
167
185
  rdoc (>= 4.0.0)
@@ -179,17 +197,15 @@ GEM
179
197
  net-pop
180
198
  net-smtp
181
199
  marcel (1.1.0)
200
+ metrics (0.15.0)
182
201
  mime-types (3.7.0)
183
202
  logger
184
203
  mime-types-data (~> 3.2025, >= 3.2025.0507)
185
- mime-types-data (3.2025.0924)
204
+ mime-types-data (3.2026.0113)
186
205
  mini_mime (1.1.5)
187
- mini_portile2 (2.8.9)
188
- minitest (6.0.0)
206
+ minitest (6.0.1)
189
207
  prism (~> 1.5)
190
208
  multipart-post (2.4.1)
191
- neighbor (0.6.0)
192
- activerecord (>= 7.1)
193
209
  net-http (0.9.1)
194
210
  uri (>= 0.11.1)
195
211
  net-imap (0.6.2)
@@ -202,14 +218,15 @@ GEM
202
218
  net-smtp (0.5.1)
203
219
  net-protocol
204
220
  nio4r (2.7.5)
205
- nokogiri (1.18.10)
206
- mini_portile2 (~> 2.8.2)
221
+ nokogiri (1.19.0-arm64-darwin)
207
222
  racc (~> 1.4)
208
- pg (1.6.2)
223
+ ostruct (0.6.3)
224
+ pg (1.6.3)
225
+ pg (1.6.3-arm64-darwin)
209
226
  pp (0.6.3)
210
227
  prettyprint
211
228
  prettyprint (0.2.0)
212
- prism (1.7.0)
229
+ prism (1.8.0)
213
230
  propshaft (1.3.1)
214
231
  actionpack (>= 7.0.0)
215
232
  activesupport (>= 7.0.0)
@@ -217,7 +234,7 @@ GEM
217
234
  psych (5.3.1)
218
235
  date
219
236
  stringio
220
- public_suffix (7.0.0)
237
+ public_suffix (7.0.2)
221
238
  puma (6.6.1)
222
239
  nio4r (~> 2.0)
223
240
  racc (1.8.1)
@@ -261,18 +278,15 @@ GEM
261
278
  tsort (>= 0.2)
262
279
  zeitwerk (~> 2.6)
263
280
  rake (13.3.1)
264
- rake-compiler-dock (1.10.0)
265
- rb_sys (0.9.123)
266
- rake-compiler-dock (= 1.10.0)
267
- rdoc (7.0.1)
281
+ rdoc (7.1.0)
268
282
  erb
269
283
  psych (>= 4.0.0)
270
284
  tsort
271
285
  reline (0.6.3)
272
286
  io-console (~> 0.5)
273
- ruby-next-core (1.1.2)
287
+ ruby-next-core (1.2.0)
274
288
  ruby-progressbar (1.13.0)
275
- ruby_llm (1.9.1)
289
+ ruby_llm (1.11.0)
276
290
  base64
277
291
  event_stream_parser (~> 1)
278
292
  faraday (>= 1.10.0)
@@ -284,11 +298,17 @@ GEM
284
298
  zeitwerk (~> 2)
285
299
  ruby_llm-schema (0.2.5)
286
300
  securerandom (0.4.1)
301
+ sequel (5.100.0)
302
+ bigdecimal
303
+ sequel_pg (1.18.2)
304
+ pg (>= 0.18.0, != 1.2.0)
305
+ sequel (>= 4.38.0)
306
+ simple_flow (0.3.0)
287
307
  stringio (3.2.0)
288
- thor (1.4.0)
289
- tiktoken_ruby (0.0.14.1)
290
- rb_sys (~> 0.9)
308
+ thor (1.5.0)
309
+ tiktoken_ruby (0.0.15.1-arm64-darwin)
291
310
  timeout (0.6.0)
311
+ traces (0.18.2)
292
312
  tsort (0.2.0)
293
313
  tzinfo (2.0.6)
294
314
  concurrent-ruby (~> 1.0)
@@ -307,11 +327,11 @@ GEM
307
327
 
308
328
  PLATFORMS
309
329
  arm64-darwin-25
310
- ruby
311
330
 
312
331
  DEPENDENCIES
313
332
  debug_me
314
333
  htm!
334
+ ostruct
315
335
  pg (~> 1.5)
316
336
  propshaft
317
337
  puma (~> 6.0)
@@ -332,39 +352,45 @@ CHECKSUMS
332
352
  activesupport (7.2.3) sha256=5675c9770dac93e371412684249f9dc3c8cec104efd0624362a520ae685c7b10
333
353
  addressable (2.8.8) sha256=7c13b8f9536cf6364c03b9d417c19986019e28f7c00ac8132da4eb0fe393b057
334
354
  anyway_config (2.7.2) sha256=30f6b087c0b41afdd43fe46c81d65a16f052a8489dab453abaeb4ea67aa74bad
355
+ async (2.36.0) sha256=090623f4c65706664355c9efa6c7bfb86771a513e65cd681c51cb27747530550
335
356
  baran (0.2.1) sha256=6c19e835c6f73c70e7073fb3d3cb48d2c85606e0b1484914b4c01a3cecdd7892
336
357
  base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
337
358
  benchmark (0.5.0) sha256=465df122341aedcb81a2a24b4d3bd19b6c67c1530713fd533f3ff034e419236c
338
- bigdecimal (3.3.1) sha256=eaa01e228be54c4f9f53bf3cc34fe3d5e845c31963e7fcc5bedb05a4e7d52218
359
+ bigdecimal (4.0.1) sha256=8b07d3d065a9f921c80ceaea7c9d4ae596697295b584c296fe599dd0ad01c4a7
339
360
  bindex (0.8.1) sha256=7b1ecc9dc539ed8bccfc8cb4d2732046227b09d6f37582ff12e50a5047ceb17e
340
361
  builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f
341
362
  cgi (0.5.1) sha256=e93fcafc69b8a934fe1e6146121fa35430efa8b4a4047c4893764067036f18e9
342
363
  chronic (0.10.2) sha256=766f2fcce6ac3cc152249ed0f2b827770d3e517e2e87c5fba7ed74f4889d2dc3
343
364
  concurrent-ruby (1.3.6) sha256=6b56837e1e7e5292f9864f34b69c5a2cbc75c0cf5338f1ce9903d10fa762d5ab
344
365
  connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a
366
+ console (1.34.2) sha256=1c036abf606ccec83f9dc28f0c31710fe5936ffe7ba5d235ae2865590a482d58
345
367
  crass (1.0.6) sha256=dc516022a56e7b3b156099abc81b6d2b08ea1ed12676ac7a5657617f012bd45d
346
368
  date (3.5.1) sha256=750d06384d7b9c15d562c76291407d89e368dda4d4fff957eb94962d325a0dc0
347
369
  debug_me (1.1.3) sha256=ae8cf61993350d9b3cbe337a7f9a0f595be5b4976c10891a4e1eacc63d09f717
348
370
  drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373
349
371
  dry-configurable (1.3.0) sha256=882d862858567fc1210d2549d4c090f34370fc1bb7c5c1933de3fe792e18afa8
350
- dry-core (1.1.0) sha256=0903821a9707649a7da545a2cd88e20f3a663ab1c5288abd7f914fa7751ab195
351
- dry-inflector (1.2.0) sha256=22f5d0b50fd57074ae57e2ca17e3b300e57564c218269dcf82ff3e42d3f38f2e
372
+ dry-core (1.2.0) sha256=0cc5a7da88df397f153947eeeae42e876e999c1e30900f3c536fb173854e96a1
373
+ dry-inflector (1.3.1) sha256=7fb0c2bb04f67638f25c52e7ba39ab435d922a3a5c3cd196120f63accb682dcc
352
374
  dry-initializer (3.2.0) sha256=37d59798f912dc0a1efe14a4db4a9306989007b302dcd5f25d0a2a20c166c4e3
353
375
  dry-logic (1.6.0) sha256=da6fedbc0f90fc41f9b0cc7e6f05f5d529d1efaef6c8dcc8e0733f685745cea2
354
- dry-schema (1.14.1) sha256=2fcd7539a7099cacae6a22f6a3a2c1846fe5afeb1c841cde432c89c6cb9b9ff1
355
- dry-types (1.8.3) sha256=b5d97a45e0ed273131c0c3d5bc9f5633c2d1242e092ee47401ce7d5eab65c1bc
376
+ dry-schema (1.15.0) sha256=0f2a34adba4206bd6d46ec1b6b7691b402e198eecaff1d8349a7d48a77d82cd2
377
+ dry-types (1.9.0) sha256=7b656fe0a78d2432500ae1f29fefd6762f5a032ca7000e4f36bc111453d45d4d
356
378
  erb (6.0.1) sha256=28ecdd99c5472aebd5674d6061e3c6b0a45c049578b071e5a52c2a7f13c197e5
357
379
  erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9
358
380
  event_stream_parser (1.0.0) sha256=a2683bab70126286f8184dc88f7968ffc4028f813161fb073ec90d171f7de3c8
359
381
  faraday (2.14.0) sha256=8699cfe5d97e55268f2596f9a9d5a43736808a943714e3d9a53e6110593941cd
360
- faraday-multipart (1.1.1) sha256=77a18ff40149030fd1aef55bb4fc7a67ce46419a8a3fcd010e28c2526e8d8903
382
+ faraday-multipart (1.2.0) sha256=7d89a949693714176f612323ca13746a2ded204031a6ba528adee788694ef757
361
383
  faraday-net_http (3.4.2) sha256=f147758260d3526939bf57ecf911682f94926a3666502e24c69992765875906c
362
- faraday-retry (2.3.2) sha256=2402d2029032ebd238a2046221e67f6ef0da78c5a8ce8cd4f8b9c62e4d6451d1
384
+ faraday-retry (2.4.0) sha256=7b79c48fb7e56526faf247b12d94a680071ff40c9fda7cf1ec1549439ad11ebe
363
385
  fast-mcp (1.6.0) sha256=d68abb45d2daab9e7ae2934417460e4bf9ac87493c585dc5bb626f1afb7d12c4
386
+ fiber-annotation (0.2.0) sha256=7abfadf1d119f508867d4103bf231c0354d019cc39a5738945dec2edadaf6c03
387
+ fiber-local (1.1.0) sha256=c885f94f210fb9b05737de65d511136ea602e00c5105953748aa0f8793489f06
388
+ fiber-storage (1.0.1) sha256=f48e5b6d8b0be96dac486332b55cee82240057065dc761c1ea692b2e719240e1
364
389
  globalid (1.3.0) sha256=05c639ad6eb4594522a0b07983022f04aa7254626ab69445a0e493aa3786ff11
365
- htm (0.0.18)
366
- i18n (1.14.7) sha256=ceba573f8138ff2c0915427f1fc5bdf4aa3ab8ae88c8ce255eb3ecf0a11a5d0f
390
+ htm (0.0.21)
391
+ i18n (1.14.8) sha256=285778639134865c5e0f6269e0b818256017e8cde89993fdfcbfb64d088824a5
367
392
  io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc
393
+ io-event (1.14.2) sha256=b0a069190eafe86005c22f7464f744971b5bd82f153740d34e6ab49548d4f613
368
394
  irb (1.16.0) sha256=2abe56c9ac947cdcb2f150572904ba798c1e93c890c256f8429981a7675b0806
369
395
  json (2.18.0) sha256=b10506aee4183f5cf49e0efc48073d7b75843ce3782c68dbeb763351c08fd505
370
396
  logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
@@ -372,27 +398,28 @@ CHECKSUMS
372
398
  lru_redux (1.1.0) sha256=ee71d0ccab164c51de146c27b480a68b3631d5b4297b8ffe8eda1c72de87affb
373
399
  mail (2.9.0) sha256=6fa6673ecd71c60c2d996260f9ee3dd387d4673b8169b502134659ece6d34941
374
400
  marcel (1.1.0) sha256=fdcfcfa33cc52e93c4308d40e4090a5d4ea279e160a7f6af988260fa970e0bee
401
+ metrics (0.15.0) sha256=61ded5bac95118e995b1bc9ed4a5f19bc9814928a312a85b200abbdac9039072
375
402
  mime-types (3.7.0) sha256=dcebf61c246f08e15a4de34e386ebe8233791e868564a470c3fe77c00eed5e56
376
- mime-types-data (3.2025.0924) sha256=f276bca15e59f35767cbcf2bc10e023e9200b30bd6a572c1daf7f4cc24994728
403
+ mime-types-data (3.2026.0113) sha256=8c88fa7b1af91c87098f666b7ffbd4794799a71c05765be2c1f6df337d41b04c
377
404
  mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef
378
- mini_portile2 (2.8.9) sha256=0cd7c7f824e010c072e33f68bc02d85a00aeb6fce05bb4819c03dfd3c140c289
379
- minitest (6.0.0) sha256=4ca597fc1d735ea18d2b4b98c5fb1d5a6da4a6f35ddf32bd5fa3eded33a453be
405
+ minitest (6.0.1) sha256=7854c74f48e2e975969062833adc4013f249a4b212f5e7b9d5c040bf838d54bb
380
406
  multipart-post (2.4.1) sha256=9872d03a8e552020ca096adadbf5e3cb1cd1cdd6acd3c161136b8a5737cdb4a8
381
- neighbor (0.6.0) sha256=e2bd0bb98e1d6403892d1d0cf3683ae9429be51d6a6a14859135dc71cf9c27d3
382
407
  net-http (0.9.1) sha256=25ba0b67c63e89df626ed8fac771d0ad24ad151a858af2cc8e6a716ca4336996
383
408
  net-imap (0.6.2) sha256=08caacad486853c61676cca0c0c47df93db02abc4a8239a8b67eb0981428acc6
384
409
  net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3
385
410
  net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8
386
411
  net-smtp (0.5.1) sha256=ed96a0af63c524fceb4b29b0d352195c30d82dd916a42f03c62a3a70e5b70736
387
412
  nio4r (2.7.5) sha256=6c90168e48fb5f8e768419c93abb94ba2b892a1d0602cb06eef16d8b7df1dca1
388
- nokogiri (1.18.10) sha256=d5cc0731008aa3b3a87b361203ea3d19b2069628cb55e46ac7d84a0445e69cc1
389
- pg (1.6.2) sha256=58614afd405cc9c2c9e15bffe8432e0d6cfc58b722344ad4a47c73a85189c875
413
+ nokogiri (1.19.0-arm64-darwin) sha256=0811dfd936d5f6dd3f6d32ef790568bf29b2b7bead9ba68866847b33c9cf5810
414
+ ostruct (0.6.3) sha256=95a2ed4a4bd1d190784e666b47b2d3f078e4a9efda2fccf18f84ddc6538ed912
415
+ pg (1.6.3) sha256=1388d0563e13d2758c1089e35e973a3249e955c659592d10e5b77c468f628a99
416
+ pg (1.6.3-arm64-darwin) sha256=7240330b572e6355d7c75a7de535edb5dfcbd6295d9c7777df4d9dddfb8c0e5f
390
417
  pp (0.6.3) sha256=2951d514450b93ccfeb1df7d021cae0da16e0a7f95ee1e2273719669d0ab9df6
391
418
  prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
392
- prism (1.7.0) sha256=10062f734bf7985c8424c44fac382ac04a58124ea3d220ec3ba9fe4f2da65103
419
+ prism (1.8.0) sha256=84453a16ef5530ea62c5f03ec16b52a459575ad4e7b9c2b360fd8ce2c39c1254
393
420
  propshaft (1.3.1) sha256=9acc664ef67e819ffa3d95bd7ad4c3623ea799110c5f4dee67fa7e583e74c392
394
421
  psych (5.3.1) sha256=eb7a57cef10c9d70173ff74e739d843ac3b2c019a003de48447b2963d81b1974
395
- public_suffix (7.0.0) sha256=f7090b5beb0e56f9f10d79eed4d5fbe551b3b425da65877e075dad47a6a1b095
422
+ public_suffix (7.0.2) sha256=9114090c8e4e7135c1fd0e7acfea33afaab38101884320c65aaa0ffb8e26a857
396
423
  puma (6.6.1) sha256=b9b56e4a4ea75d1bfa6d9e1972ee2c9f43d0883f011826d914e8e37b3694ea1e
397
424
  racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
398
425
  rack (3.2.4) sha256=5d74b6f75082a643f43c1e76b419c40f0e5527fcfee1e669ac1e6b73c0ccb6f6
@@ -404,19 +431,21 @@ CHECKSUMS
404
431
  rails-html-sanitizer (1.6.2) sha256=35fce2ca8242da8775c83b6ba9c1bcaad6751d9eb73c1abaa8403475ab89a560
405
432
  railties (7.2.3) sha256=6eb010a6bfe6f223e783f739ddfcbdb5b88b1f3a87f7739f0a0685e466250422
406
433
  rake (13.3.1) sha256=8c9e89d09f66a26a01264e7e3480ec0607f0c497a861ef16063604b1b08eb19c
407
- rake-compiler-dock (1.10.0) sha256=dd62ee19df2a185a3315697e560cfa8cc9129901332152851e023fab0e94bf11
408
- rb_sys (0.9.123) sha256=c22ae84d1bca3eec0f13a45ae4ca9ba6eace93d5be270a40a9c0a9a5b92a34e5
409
- rdoc (7.0.1) sha256=7ae1540c54eb8174f6549440dd2299276eac51deaa7d80ea7db9ea5b96559f53
434
+ rdoc (7.1.0) sha256=494899df0706c178596ca6e1d50f1b7eb285a9b2aae715be5abd742734f17363
410
435
  reline (0.6.3) sha256=1198b04973565b36ec0f11542ab3f5cfeeec34823f4e54cebde90968092b1835
411
- ruby-next-core (1.1.2) sha256=1b095fe2e45929f2581b3ecdb8d92b601ce4d72c12a466057c10e23b6f0c4512
436
+ ruby-next-core (1.2.0) sha256=f6a7d00bb5186cecbb02f7f1845a0f3a2c9788d35b6ccff5c9be3f0d46799b86
412
437
  ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
413
- ruby_llm (1.9.1) sha256=f7d3c72489c70041ee73d7bfe4250a989f801fbba1fad2200904091e433ba511
438
+ ruby_llm (1.11.0) sha256=c1bc17bb02a7e805d8f62ea6ada2ecfe7782fc955e9440b53a2fdbd00e5ec9cc
414
439
  ruby_llm-schema (0.2.5) sha256=b08cd42e8de7100325e2e868672a56f1915eb23692bb808f51f214e41392104f
415
440
  securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1
441
+ sequel (5.100.0) sha256=cb0329b62287a01db68eead46759c14497a3fae01b174e2c41da108a9e9b4a12
442
+ sequel_pg (1.18.2) sha256=6bdf0f5f13e062ef0e4b1fd2ddafbe6a13d1aab579473c9627ef4e88da431953
443
+ simple_flow (0.3.0) sha256=f365506159d25625836db44d19484f7a337fdcd75aa06eae6d4d24c333ad618c
416
444
  stringio (3.2.0) sha256=c37cb2e58b4ffbd33fe5cd948c05934af997b36e0b6ca6fdf43afa234cf222e1
417
- thor (1.4.0) sha256=8763e822ccb0f1d7bee88cde131b19a65606657b847cc7b7b4b82e772bcd8a3d
418
- tiktoken_ruby (0.0.14.1) sha256=cff8ecf6e8a7b9e854027812b01e55c35f5f7719182c3589655008d0eeb51db1
445
+ thor (1.5.0) sha256=e3a9e55fe857e44859ce104a84675ab6e8cd59c650a49106a05f55f136425e73
446
+ tiktoken_ruby (0.0.15.1-arm64-darwin) sha256=942d15acdaa6de172e9c72644c8acb115f601152b81dc765957e10c526204a48
419
447
  timeout (0.6.0) sha256=6d722ad619f96ee383a0c557ec6eb8c4ecb08af3af62098a0be5057bf00de1af
448
+ traces (0.18.2) sha256=80f1649cb4daace1d7174b81f3b3b7427af0b93047759ba349960cb8f315e214
420
449
  tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f
421
450
  tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b
422
451
  uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6
@@ -427,4 +456,4 @@ CHECKSUMS
427
456
  zeitwerk (2.7.4) sha256=2bef90f356bdafe9a6c2bd32bcd804f83a4f9b8bc27f3600fff051eb3edcec8b
428
457
 
429
458
  BUNDLED WITH
430
- 4.0.2
459
+ 4.0.4
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'ostruct'
4
+
3
5
  class DashboardController < ApplicationController
4
6
  def index
5
7
  # Note: HTM::Models::Node has a default_scope that excludes deleted nodes
@@ -15,13 +17,15 @@ class DashboardController < ApplicationController
15
17
 
16
18
  @recent_memories = HTM::Models::Node.recent.limit(5)
17
19
 
18
- @top_tags = HTM::Models::Tag
19
- .joins(:nodes)
20
- .group('tags.id')
21
- .order('COUNT(nodes.id) DESC')
20
+ @top_tags = HTM.db[:tags]
21
+ .join(:node_tags, tag_id: Sequel[:tags][:id])
22
+ .group(Sequel[:tags][:id], Sequel[:tags][:name], Sequel[:tags][:created_at])
23
+ .order(Sequel.desc(Sequel.function(:count, Sequel[:node_tags][:node_id])))
22
24
  .limit(10)
23
- .select('tags.*, COUNT(nodes.id) as node_count')
25
+ .select(Sequel[:tags][:id], Sequel[:tags][:name], Sequel[:tags][:created_at])
26
+ .select_append(Sequel.function(:count, Sequel[:node_tags][:node_id]).as(:node_count))
27
+ .map { |row| OpenStruct.new(row) }
24
28
 
25
- @robots = HTM::Models::Robot.order(created_at: :desc).limit(5)
29
+ @robots = HTM::Models::Robot.order(Sequel.desc(:created_at)).limit(5)
26
30
  end
27
31
  end
@@ -2,11 +2,11 @@
2
2
 
3
3
  class FilesController < ApplicationController
4
4
  def index
5
- @file_sources = HTM::Models::FileSource.order(updated_at: :desc)
5
+ @file_sources = HTM::Models::FileSource.order(Sequel.desc(:updated_at))
6
6
  end
7
7
 
8
8
  def show
9
- @file_source = HTM::Models::FileSource.find(params[:id])
9
+ @file_source = HTM::Models::FileSource[params[:id]]
10
10
  @chunks = @file_source.chunks.order(:id)
11
11
  end
12
12
 
@@ -127,7 +127,7 @@ class FilesController < ApplicationController
127
127
  end
128
128
 
129
129
  def sync
130
- @file_source = HTM::Models::FileSource.find(params[:id])
130
+ @file_source = HTM::Models::FileSource[params[:id]]
131
131
 
132
132
  begin
133
133
  result = htm.load_file(@file_source.file_path, force: true)
@@ -140,7 +140,7 @@ class FilesController < ApplicationController
140
140
  end
141
141
 
142
142
  def destroy
143
- @file_source = HTM::Models::FileSource.find(params[:id])
143
+ @file_source = HTM::Models::FileSource[params[:id]]
144
144
 
145
145
  begin
146
146
  htm.unload_file(@file_source.file_path)
@@ -156,7 +156,7 @@ class FilesController < ApplicationController
156
156
  synced = 0
157
157
  errors = 0
158
158
 
159
- HTM::Models::FileSource.find_each do |source|
159
+ HTM::Models::FileSource.paged_each do |source|
160
160
  if source.needs_sync?
161
161
  begin
162
162
  htm.load_file(source.file_path, force: true)
@@ -5,15 +5,19 @@ class MemoriesController < ApplicationController
5
5
 
6
6
  def index
7
7
  # Default scope excludes deleted nodes, so no .active needed
8
- @memories = HTM::Models::Node.includes(:tags)
9
- .order(created_at: :desc)
8
+ @memories = HTM::Models::Node.eager(:tags)
9
+ .order(Sequel.desc(:created_at))
10
10
 
11
11
  if params[:tag].present?
12
- @memories = @memories.joins(:tags).where(tags: { name: params[:tag] })
12
+ tag_node_ids = HTM::Models::NodeTag
13
+ .join(:tags, id: :tag_id)
14
+ .where(Sequel[:tags][:name] => params[:tag])
15
+ .select_map(:node_id)
16
+ @memories = @memories.where(id: tag_node_ids) if tag_node_ids.any?
13
17
  end
14
18
 
15
19
  if params[:search].present?
16
- @memories = @memories.where('content ILIKE ?', "%#{params[:search]}%")
20
+ @memories = @memories.where(Sequel.ilike(:content, "%#{params[:search]}%"))
17
21
  end
18
22
 
19
23
  # Simple pagination without Kaminari
@@ -67,7 +71,7 @@ class MemoriesController < ApplicationController
67
71
  return
68
72
  end
69
73
 
70
- @memory.update!(content: content)
74
+ @memory.update(content: content)
71
75
  flash[:notice] = 'Memory updated successfully'
72
76
  redirect_to memory_path(@memory)
73
77
  end
@@ -91,12 +95,12 @@ class MemoriesController < ApplicationController
91
95
  end
92
96
 
93
97
  def deleted
94
- @memories = HTM::Models::Node.deleted.order(deleted_at: :desc)
98
+ @memories = HTM::Models::Node.deleted.order(Sequel.desc(:deleted_at))
95
99
  end
96
100
 
97
101
  private
98
102
 
99
103
  def set_memory
100
- @memory = HTM::Models::Node.with_deleted.find(params[:id])
104
+ @memory = HTM::Models::Node.with_deleted[params[:id].to_i]
101
105
  end
102
106
  end
@@ -2,14 +2,14 @@
2
2
 
3
3
  class RobotsController < ApplicationController
4
4
  def index
5
- @robots = HTM::Models::Robot.order(created_at: :desc)
5
+ @robots = HTM::Models::Robot.order(Sequel.desc(:created_at))
6
6
  end
7
7
 
8
8
  def show
9
- @robot = HTM::Models::Robot.find(params[:id])
9
+ @robot = HTM::Models::Robot[params[:id]]
10
10
  # Default scope already excludes deleted nodes, so no .active needed
11
- @memory_count = @robot.nodes.count
12
- @recent_memories = @robot.nodes.order(created_at: :desc).limit(10)
11
+ @memory_count = @robot.nodes_dataset.count
12
+ @recent_memories = @robot.nodes_dataset.order(Sequel.desc(:created_at)).limit(10).all
13
13
  end
14
14
 
15
15
  def new
@@ -24,19 +24,19 @@ class RobotsController < ApplicationController
24
24
  return
25
25
  end
26
26
 
27
- if HTM::Models::Robot.exists?(name: name)
27
+ if HTM::Models::Robot.where(name: name).any?
28
28
  flash[:alert] = 'A robot with that name already exists'
29
29
  redirect_to new_robot_path
30
30
  return
31
31
  end
32
32
 
33
- robot = HTM::Models::Robot.create!(name: name, metadata: {})
33
+ robot = HTM::Models::Robot.create(name: name, metadata: {})
34
34
  flash[:notice] = "Robot '#{name}' created successfully"
35
- redirect_to robot_path(robot)
35
+ redirect_to robot_path(robot.id)
36
36
  end
37
37
 
38
38
  def switch
39
- robot = HTM::Models::Robot.find(params[:id])
39
+ robot = HTM::Models::Robot[params[:id]]
40
40
  self.current_robot_name = robot.name
41
41
  flash[:notice] = "Switched to robot '#{robot.name}'"
42
42
  redirect_to root_path
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ostruct'
4
+
5
+ class TagsController < ApplicationController
6
+ def index
7
+ @view_type = params[:view] || 'list'
8
+
9
+ case @view_type
10
+ when 'tree'
11
+ @tree_string = HTM::Models::Tag.tree_string
12
+ @tree_svg = HTM::Models::Tag.tree_svg(title: 'HTM Tag Hierarchy')
13
+ when 'mermaid'
14
+ @tree_mermaid = HTM::Models::Tag.tree_mermaid
15
+ else
16
+ # Build tag list with node counts using Sequel
17
+ tags_with_counts = HTM.db[:tags]
18
+ .left_join(:node_tags, tag_id: Sequel[:tags][:id])
19
+ .group(Sequel[:tags][:id], Sequel[:tags][:name], Sequel[:tags][:created_at])
20
+ .select(Sequel[:tags][:id], Sequel[:tags][:name], Sequel[:tags][:created_at])
21
+ .select_append(Sequel.function(:count, Sequel[:node_tags][:node_id]).as(:node_count))
22
+ .order(Sequel[:tags][:name])
23
+
24
+ if params[:prefix].present?
25
+ tags_with_counts = tags_with_counts.where(Sequel.like(:name, "#{params[:prefix]}%"))
26
+ end
27
+
28
+ @tags = tags_with_counts.map { |row| OpenStruct.new(row) }
29
+ end
30
+ end
31
+
32
+ def show
33
+ @tag = HTM::Models::Tag[params[:id]]
34
+ @memories = @tag.nodes_dataset.active.eager(:tags).order(Sequel.desc(:created_at)).all
35
+ end
36
+ end
@@ -51,7 +51,7 @@
51
51
  <% if @top_tags.any? %>
52
52
  <div class="flex flex-wrap gap-2">
53
53
  <% @top_tags.each do |tag| %>
54
- <%= link_to tag_path(tag), class: 'group' do %>
54
+ <%= link_to tag_path(tag.id), class: 'group' do %>
55
55
  <span class="inline-flex items-center gap-1 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 hover:border-indigo-500/50 transition-colors">
56
56
  <%= tag.name %>
57
57
  <span class="text-xs text-indigo-400/70">(<%= tag.node_count %>)</span>
@@ -74,7 +74,7 @@
74
74
  <% if @robots.any? %>
75
75
  <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
76
76
  <% @robots.each do |robot| %>
77
- <%= link_to robot_path(robot), class: 'block rounded-md bg-gray-700/50 p-4 hover:bg-gray-700 transition-colors' do %>
77
+ <%= link_to robot_path(robot.id), class: 'block rounded-md bg-gray-700/50 p-4 hover:bg-gray-700 transition-colors' do %>
78
78
  <div class="flex items-center gap-3">
79
79
  <div class="flex-shrink-0">
80
80
  <div class="h-10 w-10 rounded-full bg-purple-900/50 flex items-center justify-center">
@@ -65,6 +65,9 @@
65
65
  <!-- Upload Directory -->
66
66
  <div class="rounded-lg bg-gray-800 border border-gray-700 p-6">
67
67
  <h2 class="text-lg font-bold text-white mb-4">Upload Directory</h2>
68
+ <div class="mb-4 rounded-md bg-yellow-900/30 border border-yellow-500/30 p-3">
69
+ <p class="text-xs text-yellow-400"><strong>Note:</strong> Browser uploads limited to ~100 files due to OS restrictions. For larger directories, use <strong>Load Directory by Path</strong> below.</p>
70
+ </div>
68
71
 
69
72
  <%= form_with url: upload_directory_files_path, method: :post, multipart: true, class: 'space-y-4', id: 'upload-dir-form', data: { turbo: false } do %>
70
73
  <div>
@@ -146,8 +149,8 @@
146
149
  </div>
147
150
 
148
151
  <!-- Load Directory by Path -->
149
- <div class="rounded-lg bg-gray-800 border border-gray-700 p-6">
150
- <h2 class="text-lg font-bold text-white mb-4">Load Directory by Path</h2>
152
+ <div class="rounded-lg bg-indigo-900/30 border border-indigo-500/30 p-6">
153
+ <h2 class="text-lg font-bold text-white mb-4">Load Directory by Path <span class="text-xs font-normal text-indigo-400">(Recommended for large directories)</span></h2>
151
154
 
152
155
  <%= form_with url: load_directory_files_path, method: :post, class: 'space-y-4' do %>
153
156
  <div>
@@ -1,7 +1,7 @@
1
1
  <div class="rounded-lg bg-gray-800 border border-gray-700 p-5 hover:border-gray-600 transition-colors">
2
2
  <div class="flex items-start justify-between gap-4">
3
3
  <div class="flex-1 min-w-0">
4
- <%= link_to memory_path(memory), class: 'block group' do %>
4
+ <%= link_to memory_path(memory.id), class: 'block group' do %>
5
5
  <p class="text-sm text-gray-300 group-hover:text-white transition-colors line-clamp-3">
6
6
  <%= memory.content %>
7
7
  </p>
@@ -36,12 +36,12 @@
36
36
  </div>
37
37
 
38
38
  <div class="flex-shrink-0 flex items-center gap-2">
39
- <%= link_to edit_memory_path(memory), class: 'rounded p-1.5 text-gray-400 hover:text-white hover:bg-gray-700 transition-colors', title: 'Edit' do %>
39
+ <%= link_to edit_memory_path(memory.id), class: 'rounded p-1.5 text-gray-400 hover:text-white hover:bg-gray-700 transition-colors', title: 'Edit' do %>
40
40
  <svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
41
41
  <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" />
42
42
  </svg>
43
43
  <% end %>
44
- <%= button_to memory_path(memory), method: :delete, class: 'rounded p-1.5 text-gray-400 hover:text-red-400 hover:bg-gray-700 transition-colors', title: 'Delete', data: { turbo_confirm: 'Move this memory to trash?' } do %>
44
+ <%= button_to memory_path(memory.id), method: :delete, class: 'rounded p-1.5 text-gray-400 hover:text-red-400 hover:bg-gray-700 transition-colors', title: 'Delete', data: { turbo_confirm: 'Move this memory to trash?' } 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>
@@ -20,7 +20,7 @@
20
20
  <div class="rounded-lg bg-gray-800 border border-red-900/50 p-5">
21
21
  <div class="flex items-start justify-between gap-4">
22
22
  <div class="flex-1 min-w-0">
23
- <%= link_to memory_path(memory), class: 'block group' do %>
23
+ <%= link_to memory_path(memory.id), class: 'block group' do %>
24
24
  <p class="text-sm text-gray-400 group-hover:text-gray-300 transition-colors line-clamp-3">
25
25
  <%= memory.content %>
26
26
  </p>
@@ -33,13 +33,13 @@
33
33
  </div>
34
34
 
35
35
  <div class="flex-shrink-0 flex items-center gap-2">
36
- <%= button_to restore_memory_path(memory), method: :post, class: 'inline-flex items-center gap-1 rounded-md bg-green-600/80 px-3 py-1.5 text-xs font-medium text-white hover:bg-green-600 transition-colors' do %>
36
+ <%= button_to restore_memory_path(memory.id), method: :post, class: 'inline-flex items-center gap-1 rounded-md bg-green-600/80 px-3 py-1.5 text-xs font-medium text-white hover:bg-green-600 transition-colors' do %>
37
37
  <svg class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
38
38
  <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" />
39
39
  </svg>
40
40
  Restore
41
41
  <% end %>
42
- <%= button_to memory_path(memory, permanent: true), method: :delete, class: 'inline-flex items-center gap-1 rounded-md bg-red-600/80 px-3 py-1.5 text-xs font-medium text-white hover:bg-red-600 transition-colors', data: { turbo_confirm: 'Permanently delete? This cannot be undone!' } do %>
42
+ <%= button_to memory_path(memory.id, permanent: true), method: :delete, class: 'inline-flex items-center gap-1 rounded-md bg-red-600/80 px-3 py-1.5 text-xs font-medium text-white hover:bg-red-600 transition-colors', data: { turbo_confirm: 'Permanently delete? This cannot be undone!' } do %>
43
43
  <svg class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
44
44
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
45
45
  </svg>