MetaList 0.23.0__tar.gz → 0.24.0__tar.gz

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 (616) hide show
  1. {metalist-0.23.0/metalist.egg-info → metalist-0.24.0}/PKG-INFO +11 -1
  2. {metalist-0.23.0 → metalist-0.24.0}/README.md +10 -0
  3. {metalist-0.23.0 → metalist-0.24.0}/app/api/note_requests.py +12 -0
  4. {metalist-0.23.0 → metalist-0.24.0}/app/api/routes/ai.py +10 -1
  5. {metalist-0.23.0 → metalist-0.24.0}/app/api/routes/notes.py +82 -0
  6. {metalist-0.23.0 → metalist-0.24.0}/app/api/routes/ontology.py +66 -13
  7. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/cloud_privacy.py +50 -2
  8. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/note_tag_suggestions.py +10 -4
  9. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/scope.py +12 -1
  10. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-formatting.md +1 -1
  11. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-menus.md +10 -1
  12. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-mouse.md +1 -0
  13. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-notes.md +3 -2
  14. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-ontology.md +34 -0
  15. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-releases.md +10 -0
  16. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-search.md +50 -0
  17. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-tags.md +18 -1
  18. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/tag-proposals.md +10 -0
  19. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/tagging.py +9 -5
  20. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/tagging_run.py +13 -9
  21. {metalist-0.23.0 → metalist-0.24.0}/app/services/content_formatting.py +7 -1
  22. {metalist-0.23.0 → metalist-0.24.0}/app/services/file_registry.py +63 -1
  23. {metalist-0.23.0 → metalist-0.24.0}/app/services/file_storage.py +23 -1
  24. {metalist-0.23.0 → metalist-0.24.0}/app/services/html_export.py +11 -5
  25. {metalist-0.23.0 → metalist-0.24.0}/app/services/note_store.py +59 -7
  26. {metalist-0.23.0 → metalist-0.24.0}/app/services/ontology_rules_store.py +7 -1
  27. metalist-0.24.0/app/services/root_date_filter.py +153 -0
  28. {metalist-0.23.0 → metalist-0.24.0}/app/services/search_index.py +330 -4
  29. {metalist-0.23.0 → metalist-0.24.0}/app/services/search_query.py +52 -0
  30. {metalist-0.23.0 → metalist-0.24.0}/app/services/search_text.py +6 -1
  31. {metalist-0.23.0 → metalist-0.24.0}/app/services/snapshot.py +92 -22
  32. {metalist-0.23.0 → metalist-0.24.0}/app/services/tab_state.py +77 -3
  33. {metalist-0.23.0 → metalist-0.24.0}/app/services/tag_ontology.py +196 -2
  34. metalist-0.24.0/app/services/tag_properties.py +472 -0
  35. {metalist-0.23.0 → metalist-0.24.0}/app/services/tag_rename.py +6 -3
  36. {metalist-0.23.0 → metalist-0.24.0}/app/static/config/agent-menu-actions.json +48 -0
  37. {metalist-0.23.0 → metalist-0.24.0}/app/static/config/command_palette_tags.json +32 -0
  38. {metalist-0.23.0 → metalist-0.24.0}/app/static/css/main.css +48 -1
  39. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/command-palette/command-palette-controller.js +114 -1
  40. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/command-palette/endpoint-registry.js +36 -0
  41. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/config.js +1 -0
  42. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/context-menu/context-menu-registry.js +93 -7
  43. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/context-menu/context-menu-service.js +10 -0
  44. metalist-0.24.0/app/static/js/modules/modals/date-range-modal.js +178 -0
  45. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/help-modal.js +1 -0
  46. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/ontology-modal.js +53 -5
  47. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/actions/ui-actions.js +2 -0
  48. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/events/context-menu-events.js +132 -10
  49. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/events/keyboard-events.js +11 -3
  50. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/events/mouse-events.js +13 -0
  51. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/events/search-events.js +7 -4
  52. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/context-menu-target-service.js +2 -1
  53. metalist-0.24.0/app/static/js/modules/mode-manager/services/date-range-filter-service.js +173 -0
  54. metalist-0.24.0/app/static/js/modules/mode-manager/services/date-range-kinds.js +20 -0
  55. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/root-sort-indicator-service.js +31 -1
  56. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-suggestions-service.js +24 -2
  57. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-syntax-service.js +87 -0
  58. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/tab-state-service.js +26 -1
  59. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/tag-suggestions-service.js +19 -3
  60. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/tag-syntax-service.js +158 -7
  61. {metalist-0.23.0 → metalist-0.24.0}/app/templates/index.html +10 -0
  62. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/alphabetize_root_notes.py +1 -0
  63. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/bulk_tag_proposals.py +10 -9
  64. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/move_to_top.py +1 -0
  65. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/reset_updated_at.py +1 -0
  66. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/search_context_tags.py +35 -1
  67. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/set_collapse_in_context.py +21 -0
  68. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/tag_proposals.py +82 -19
  69. {metalist-0.23.0 → metalist-0.24.0}/app/version.py +1 -1
  70. {metalist-0.23.0 → metalist-0.24.0/metalist.egg-info}/PKG-INFO +11 -1
  71. {metalist-0.23.0 → metalist-0.24.0}/metalist.egg-info/SOURCES.txt +5 -0
  72. {metalist-0.23.0 → metalist-0.24.0}/MANIFEST.in +0 -0
  73. {metalist-0.23.0 → metalist-0.24.0}/app/__init__.py +0 -0
  74. {metalist-0.23.0 → metalist-0.24.0}/app/api/__init__.py +0 -0
  75. {metalist-0.23.0 → metalist-0.24.0}/app/api/deps.py +0 -0
  76. {metalist-0.23.0 → metalist-0.24.0}/app/api/dev.py +0 -0
  77. {metalist-0.23.0 → metalist-0.24.0}/app/api/middleware/auth.py +0 -0
  78. {metalist-0.23.0 → metalist-0.24.0}/app/api/request_auth.py +0 -0
  79. {metalist-0.23.0 → metalist-0.24.0}/app/api/routes/app_updates.py +0 -0
  80. {metalist-0.23.0 → metalist-0.24.0}/app/api/routes/auth.py +0 -0
  81. {metalist-0.23.0 → metalist-0.24.0}/app/api/routes/backups.py +0 -0
  82. {metalist-0.23.0 → metalist-0.24.0}/app/api/routes/files.py +0 -0
  83. {metalist-0.23.0 → metalist-0.24.0}/app/api/routes/reminders.py +0 -0
  84. {metalist-0.23.0 → metalist-0.24.0}/app/api/routes/remote_images.py +0 -0
  85. {metalist-0.23.0 → metalist-0.24.0}/app/api/routes/test.py +0 -0
  86. {metalist-0.23.0 → metalist-0.24.0}/app/api/transactions.py +0 -0
  87. {metalist-0.23.0 → metalist-0.24.0}/app/api/upload_limits.py +0 -0
  88. {metalist-0.23.0 → metalist-0.24.0}/app/config.py +0 -0
  89. {metalist-0.23.0 → metalist-0.24.0}/app/contracts.py +0 -0
  90. {metalist-0.23.0 → metalist-0.24.0}/app/data_directory.py +0 -0
  91. {metalist-0.23.0 → metalist-0.24.0}/app/db/__init__.py +0 -0
  92. {metalist-0.23.0 → metalist-0.24.0}/app/db/backup_settings_sql.py +0 -0
  93. {metalist-0.23.0 → metalist-0.24.0}/app/db/content_migrations_sql.py +0 -0
  94. {metalist-0.23.0 → metalist-0.24.0}/app/db/editable_files_migration.py +0 -0
  95. {metalist-0.23.0 → metalist-0.24.0}/app/db/engine.py +0 -0
  96. {metalist-0.23.0 → metalist-0.24.0}/app/db/file_schema.py +0 -0
  97. {metalist-0.23.0 → metalist-0.24.0}/app/db/file_session.py +0 -0
  98. {metalist-0.23.0 → metalist-0.24.0}/app/db/files_sql.py +0 -0
  99. {metalist-0.23.0 → metalist-0.24.0}/app/db/link_titles_sql.py +0 -0
  100. {metalist-0.23.0 → metalist-0.24.0}/app/db/live_recovery.py +0 -0
  101. {metalist-0.23.0 → metalist-0.24.0}/app/db/migrations.py +0 -0
  102. {metalist-0.23.0 → metalist-0.24.0}/app/db/notes_sql.py +0 -0
  103. {metalist-0.23.0 → metalist-0.24.0}/app/db/ontology_rules_sql.py +0 -0
  104. {metalist-0.23.0 → metalist-0.24.0}/app/db/raw_connection.py +0 -0
  105. {metalist-0.23.0 → metalist-0.24.0}/app/db/reminders_sql.py +0 -0
  106. {metalist-0.23.0 → metalist-0.24.0}/app/db/retire_sounds.py +0 -0
  107. {metalist-0.23.0 → metalist-0.24.0}/app/db/schema.py +0 -0
  108. {metalist-0.23.0 → metalist-0.24.0}/app/db/search_history_sql.py +0 -0
  109. {metalist-0.23.0 → metalist-0.24.0}/app/db/session.py +0 -0
  110. {metalist-0.23.0 → metalist-0.24.0}/app/db/settings_sql.py +0 -0
  111. {metalist-0.23.0 → metalist-0.24.0}/app/db/tab_state_sql.py +0 -0
  112. {metalist-0.23.0 → metalist-0.24.0}/app/db/version.py +0 -0
  113. {metalist-0.23.0 → metalist-0.24.0}/app/encryption_audit.py +0 -0
  114. {metalist-0.23.0 → metalist-0.24.0}/app/exception_boundaries.py +0 -0
  115. {metalist-0.23.0 → metalist-0.24.0}/app/https_proxy.py +0 -0
  116. {metalist-0.23.0 → metalist-0.24.0}/app/launch_clock.py +0 -0
  117. {metalist-0.23.0 → metalist-0.24.0}/app/main.py +0 -0
  118. {metalist-0.23.0 → metalist-0.24.0}/app/models/database.py +0 -0
  119. {metalist-0.23.0 → metalist-0.24.0}/app/models/utils.py +0 -0
  120. {metalist-0.23.0 → metalist-0.24.0}/app/network_settings.py +0 -0
  121. {metalist-0.23.0 → metalist-0.24.0}/app/presentation/__init__.py +0 -0
  122. {metalist-0.23.0 → metalist-0.24.0}/app/presentation/login_page.py +0 -0
  123. {metalist-0.23.0 → metalist-0.24.0}/app/presentation/render/__init__.py +0 -0
  124. {metalist-0.23.0 → metalist-0.24.0}/app/presentation/render/note_renderer.py +0 -0
  125. {metalist-0.23.0 → metalist-0.24.0}/app/presentation/templates.py +0 -0
  126. {metalist-0.23.0 → metalist-0.24.0}/app/process_memory.py +0 -0
  127. {metalist-0.23.0 → metalist-0.24.0}/app/security/authenticated_logging.py +0 -0
  128. {metalist-0.23.0 → metalist-0.24.0}/app/security/crypto_sizes.py +0 -0
  129. {metalist-0.23.0 → metalist-0.24.0}/app/security/encryption.py +0 -0
  130. {metalist-0.23.0 → metalist-0.24.0}/app/security/http_error_diagnostics.py +0 -0
  131. {metalist-0.23.0 → metalist-0.24.0}/app/security/http_headers.py +0 -0
  132. {metalist-0.23.0 → metalist-0.24.0}/app/security/note_html.py +0 -0
  133. {metalist-0.23.0 → metalist-0.24.0}/app/security/rendered_html.py +0 -0
  134. {metalist-0.23.0 → metalist-0.24.0}/app/security/request_boundary.py +0 -0
  135. {metalist-0.23.0 → metalist-0.24.0}/app/security/request_hosts.py +0 -0
  136. {metalist-0.23.0 → metalist-0.24.0}/app/security/sensitive_cache.py +0 -0
  137. {metalist-0.23.0 → metalist-0.24.0}/app/security/sensitive_logging.py +0 -0
  138. {metalist-0.23.0 → metalist-0.24.0}/app/security/shell_execution.py +0 -0
  139. {metalist-0.23.0 → metalist-0.24.0}/app/security/validation_errors.py +0 -0
  140. {metalist-0.23.0 → metalist-0.24.0}/app/server_runtime.py +0 -0
  141. {metalist-0.23.0 → metalist-0.24.0}/app/services/__init__.py +0 -0
  142. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/__init__.py +0 -0
  143. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/action_log.py +0 -0
  144. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/agent_loop.py +0 -0
  145. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/agent_tools.py +0 -0
  146. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/ai_send.py +0 -0
  147. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/citation_tokens.py +0 -0
  148. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/context.py +0 -0
  149. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/evidence_serialization.py +0 -0
  150. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/execution_errors.py +0 -0
  151. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/export_title_suggestions.py +0 -0
  152. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/failure_explanations.py +0 -0
  153. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/help_catalog.py +0 -0
  154. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/history.py +0 -0
  155. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/inference.py +0 -0
  156. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/investigation.py +0 -0
  157. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/judging.py +0 -0
  158. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/menu_actions.py +0 -0
  159. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/model_policy.py +0 -0
  160. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/note_aliases.py +0 -0
  161. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/openai_cost_tracking.py +0 -0
  162. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/openai_inference.py +0 -0
  163. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/openai_models.py +0 -0
  164. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/privacy_guard.py +0 -0
  165. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/prompt_settings.py +0 -0
  166. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/prompts/__init__.py +0 -0
  167. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/prompts/agent.md +0 -0
  168. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/prompts/final-response.md +0 -0
  169. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/prompts/system.md +0 -0
  170. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/release_notes.py +0 -0
  171. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/retrieval_settings.py +0 -0
  172. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/runtime.py +0 -0
  173. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skill_settings.py +0 -0
  174. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/__init__.py +0 -0
  175. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-ai.md +0 -0
  176. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-data.md +0 -0
  177. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-dictation.md +0 -0
  178. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-privacy.md +0 -0
  179. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-references.md +0 -0
  180. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/help-reminders.md +0 -0
  181. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/staged-summary.md +0 -0
  182. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/skills/web-browsing.md +0 -0
  183. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/staged_summary.py +0 -0
  184. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/strict_structured_outputs.py +0 -0
  185. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/structured_inference.py +0 -0
  186. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/summary_batch_store.py +0 -0
  187. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/token_estimation.py +0 -0
  188. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/tool_calling.py +0 -0
  189. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/trace.py +0 -0
  190. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/web_actions.py +0 -0
  191. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/web_capabilities.py +0 -0
  192. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/web_evidence.py +0 -0
  193. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/web_fetch.py +0 -0
  194. {metalist-0.23.0 → metalist-0.24.0}/app/services/agent/web_settings.py +0 -0
  195. {metalist-0.23.0 → metalist-0.24.0}/app/services/ai_chat.py +0 -0
  196. {metalist-0.23.0 → metalist-0.24.0}/app/services/ai_chat_rendering.py +0 -0
  197. {metalist-0.23.0 → metalist-0.24.0}/app/services/ai_chat_stream.py +0 -0
  198. {metalist-0.23.0 → metalist-0.24.0}/app/services/ai_setup.py +0 -0
  199. {metalist-0.23.0 → metalist-0.24.0}/app/services/app_update_worker.py +0 -0
  200. {metalist-0.23.0 → metalist-0.24.0}/app/services/app_updates.py +0 -0
  201. {metalist-0.23.0 → metalist-0.24.0}/app/services/auth.py +0 -0
  202. {metalist-0.23.0 → metalist-0.24.0}/app/services/auth_cache_state.py +0 -0
  203. {metalist-0.23.0 → metalist-0.24.0}/app/services/auth_service.py +0 -0
  204. {metalist-0.23.0 → metalist-0.24.0}/app/services/backlink_index.py +0 -0
  205. {metalist-0.23.0 → metalist-0.24.0}/app/services/backlinks.py +0 -0
  206. {metalist-0.23.0 → metalist-0.24.0}/app/services/backup_service.py +0 -0
  207. {metalist-0.23.0 → metalist-0.24.0}/app/services/backup_settings_service.py +0 -0
  208. {metalist-0.23.0 → metalist-0.24.0}/app/services/bulk_operation.py +0 -0
  209. {metalist-0.23.0 → metalist-0.24.0}/app/services/chess_rendering.py +0 -0
  210. {metalist-0.23.0 → metalist-0.24.0}/app/services/client_state_service.py +0 -0
  211. {metalist-0.23.0 → metalist-0.24.0}/app/services/code_rendering.py +0 -0
  212. {metalist-0.23.0 → metalist-0.24.0}/app/services/content_cache.py +0 -0
  213. {metalist-0.23.0 → metalist-0.24.0}/app/services/diagnostics.py +0 -0
  214. {metalist-0.23.0 → metalist-0.24.0}/app/services/dictation_cleanup.py +0 -0
  215. {metalist-0.23.0 → metalist-0.24.0}/app/services/diff_rendering.py +0 -0
  216. {metalist-0.23.0 → metalist-0.24.0}/app/services/editing_image_sizes.py +0 -0
  217. {metalist-0.23.0 → metalist-0.24.0}/app/services/embedded_references.py +0 -0
  218. {metalist-0.23.0 → metalist-0.24.0}/app/services/encryption.py +0 -0
  219. {metalist-0.23.0 → metalist-0.24.0}/app/services/exception_capture.py +0 -0
  220. {metalist-0.23.0 → metalist-0.24.0}/app/services/file_edit_sessions.py +0 -0
  221. {metalist-0.23.0 → metalist-0.24.0}/app/services/file_text_preview.py +0 -0
  222. {metalist-0.23.0 → metalist-0.24.0}/app/services/find_text.py +0 -0
  223. {metalist-0.23.0 → metalist-0.24.0}/app/services/footnote_layout.py +0 -0
  224. {metalist-0.23.0 → metalist-0.24.0}/app/services/footnote_rendering.py +0 -0
  225. {metalist-0.23.0 → metalist-0.24.0}/app/services/hierarchy.py +0 -0
  226. {metalist-0.23.0 → metalist-0.24.0}/app/services/html_unformatting.py +0 -0
  227. {metalist-0.23.0 → metalist-0.24.0}/app/services/hydration_state.py +0 -0
  228. {metalist-0.23.0 → metalist-0.24.0}/app/services/image_size_formatting.py +0 -0
  229. {metalist-0.23.0 → metalist-0.24.0}/app/services/inline_image_dimensions.py +0 -0
  230. {metalist-0.23.0 → metalist-0.24.0}/app/services/inline_image_occurrences.py +0 -0
  231. {metalist-0.23.0 → metalist-0.24.0}/app/services/input_errors.py +0 -0
  232. {metalist-0.23.0 → metalist-0.24.0}/app/services/integrity.py +0 -0
  233. {metalist-0.23.0 → metalist-0.24.0}/app/services/latex_rendering.py +0 -0
  234. {metalist-0.23.0 → metalist-0.24.0}/app/services/link_title_retry.py +0 -0
  235. {metalist-0.23.0 → metalist-0.24.0}/app/services/link_titles.py +0 -0
  236. {metalist-0.23.0 → metalist-0.24.0}/app/services/login_rate_limit.py +0 -0
  237. {metalist-0.23.0 → metalist-0.24.0}/app/services/maintenance_mode.py +0 -0
  238. {metalist-0.23.0 → metalist-0.24.0}/app/services/markdown_rendering.py +0 -0
  239. {metalist-0.23.0 → metalist-0.24.0}/app/services/memory_breakdown.py +0 -0
  240. {metalist-0.23.0 → metalist-0.24.0}/app/services/memory_usage.py +0 -0
  241. {metalist-0.23.0 → metalist-0.24.0}/app/services/mermaid_note_rendering.py +0 -0
  242. {metalist-0.23.0 → metalist-0.24.0}/app/services/namespace_deletion_jobs.py +0 -0
  243. {metalist-0.23.0 → metalist-0.24.0}/app/services/namespace_deletion_worker.py +0 -0
  244. {metalist-0.23.0 → metalist-0.24.0}/app/services/namespace_rename_jobs.py +0 -0
  245. {metalist-0.23.0 → metalist-0.24.0}/app/services/namespace_rename_worker.py +0 -0
  246. {metalist-0.23.0 → metalist-0.24.0}/app/services/namespace_runtime_guard.py +0 -0
  247. {metalist-0.23.0 → metalist-0.24.0}/app/services/namespace_switcher.py +0 -0
  248. {metalist-0.23.0 → metalist-0.24.0}/app/services/note_fullscreen.py +0 -0
  249. {metalist-0.23.0 → metalist-0.24.0}/app/services/note_image_tags.py +0 -0
  250. {metalist-0.23.0 → metalist-0.24.0}/app/services/note_ordering.py +0 -0
  251. {metalist-0.23.0 → metalist-0.24.0}/app/services/openai_credentials.py +0 -0
  252. {metalist-0.23.0 → metalist-0.24.0}/app/services/password_note_fields.py +0 -0
  253. {metalist-0.23.0 → metalist-0.24.0}/app/services/preference_values.py +0 -0
  254. {metalist-0.23.0 → metalist-0.24.0}/app/services/public_http.py +0 -0
  255. {metalist-0.23.0 → metalist-0.24.0}/app/services/reference_presentation.py +0 -0
  256. {metalist-0.23.0 → metalist-0.24.0}/app/services/reminders.py +0 -0
  257. {metalist-0.23.0 → metalist-0.24.0}/app/services/remote_image_proxy.py +0 -0
  258. {metalist-0.23.0 → metalist-0.24.0}/app/services/request_recovery.py +0 -0
  259. {metalist-0.23.0 → metalist-0.24.0}/app/services/reset_for_tests.py +0 -0
  260. {metalist-0.23.0 → metalist-0.24.0}/app/services/resource_limits.py +0 -0
  261. {metalist-0.23.0 → metalist-0.24.0}/app/services/root_sorting.py +0 -0
  262. {metalist-0.23.0 → metalist-0.24.0}/app/services/runtime_generation.py +0 -0
  263. {metalist-0.23.0 → metalist-0.24.0}/app/services/runtime_hardening.py +0 -0
  264. {metalist-0.23.0 → metalist-0.24.0}/app/services/runtime_lock.py +0 -0
  265. {metalist-0.23.0 → metalist-0.24.0}/app/services/search_history.py +0 -0
  266. {metalist-0.23.0 → metalist-0.24.0}/app/services/search_history_storage.py +0 -0
  267. {metalist-0.23.0 → metalist-0.24.0}/app/services/selected_text_tag.py +0 -0
  268. {metalist-0.23.0 → metalist-0.24.0}/app/services/self_update.py +0 -0
  269. {metalist-0.23.0 → metalist-0.24.0}/app/services/session_timeout_service.py +0 -0
  270. {metalist-0.23.0 → metalist-0.24.0}/app/services/shared_sets.py +0 -0
  271. {metalist-0.23.0 → metalist-0.24.0}/app/services/shell_session_service.py +0 -0
  272. {metalist-0.23.0 → metalist-0.24.0}/app/services/store.py +0 -0
  273. {metalist-0.23.0 → metalist-0.24.0}/app/services/structured_note_renderers.py +0 -0
  274. {metalist-0.23.0 → metalist-0.24.0}/app/services/sync.py +0 -0
  275. {metalist-0.23.0 → metalist-0.24.0}/app/services/tag_case.py +0 -0
  276. {metalist-0.23.0 → metalist-0.24.0}/app/services/tag_details.py +0 -0
  277. {metalist-0.23.0 → metalist-0.24.0}/app/services/tag_plural_variants.py +0 -0
  278. {metalist-0.23.0 → metalist-0.24.0}/app/services/tag_suggestion_reasons.py +0 -0
  279. {metalist-0.23.0 → metalist-0.24.0}/app/services/tag_suggestions.py +0 -0
  280. {metalist-0.23.0 → metalist-0.24.0}/app/services/tag_term_matching.py +0 -0
  281. {metalist-0.23.0 → metalist-0.24.0}/app/services/tokens.py +0 -0
  282. {metalist-0.23.0 → metalist-0.24.0}/app/services/undo_state.py +0 -0
  283. {metalist-0.23.0 → metalist-0.24.0}/app/services/update_backups.py +0 -0
  284. {metalist-0.23.0 → metalist-0.24.0}/app/services/update_installer.py +0 -0
  285. {metalist-0.23.0 → metalist-0.24.0}/app/services/update_preflight.py +0 -0
  286. {metalist-0.23.0 → metalist-0.24.0}/app/services/view_cache.py +0 -0
  287. {metalist-0.23.0 → metalist-0.24.0}/app/services/view_diff.py +0 -0
  288. {metalist-0.23.0 → metalist-0.24.0}/app/services/view_state.py +0 -0
  289. {metalist-0.23.0 → metalist-0.24.0}/app/services/windows_process_control.py +0 -0
  290. {metalist-0.23.0 → metalist-0.24.0}/app/startup_console.py +0 -0
  291. {metalist-0.23.0 → metalist-0.24.0}/app/startup_environment.py +0 -0
  292. {metalist-0.23.0 → metalist-0.24.0}/app/startup_js_sanity.py +0 -0
  293. {metalist-0.23.0 → metalist-0.24.0}/app/startup_sanity.py +0 -0
  294. {metalist-0.23.0 → metalist-0.24.0}/app/startup_sanity_config.py +0 -0
  295. {metalist-0.23.0 → metalist-0.24.0}/app/startup_shockharness.py +0 -0
  296. {metalist-0.23.0 → metalist-0.24.0}/app/static/css/floating-notes.css +0 -0
  297. {metalist-0.23.0 → metalist-0.24.0}/app/static/css/forms.css +0 -0
  298. {metalist-0.23.0 → metalist-0.24.0}/app/static/img/favicon.ico +0 -0
  299. {metalist-0.23.0 → metalist-0.24.0}/app/static/img/metalist-logo-black-1024.png +0 -0
  300. {metalist-0.23.0 → metalist-0.24.0}/app/static/img/metalist-logo-black-512.png +0 -0
  301. {metalist-0.23.0 → metalist-0.24.0}/app/static/img/metalist-logo-black.svg +0 -0
  302. {metalist-0.23.0 → metalist-0.24.0}/app/static/img/metalist-logo-white-1024.png +0 -0
  303. {metalist-0.23.0 → metalist-0.24.0}/app/static/img/metalist-logo-white-512.png +0 -0
  304. {metalist-0.23.0 → metalist-0.24.0}/app/static/img/metalist-logo-white.svg +0 -0
  305. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/locked.js +0 -0
  306. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/main.js +0 -0
  307. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/activity-tracker.js +0 -0
  308. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/agent-menu-actions.js +0 -0
  309. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/agent-retrieval-settings.js +0 -0
  310. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/agent-web-settings.js +0 -0
  311. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/ai-agent-debug-view.js +0 -0
  312. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/ai-chat-api.js +0 -0
  313. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/ai-chat-message-placement.js +0 -0
  314. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/ai-chat-panel-controller.js +0 -0
  315. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/ai-chat-panel-service.js +0 -0
  316. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/ai-chat-refused-turns.js +0 -0
  317. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/ai-chat-size-limits.js +0 -0
  318. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/ai-thinking-level-service.js +0 -0
  319. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/bulk-elapsed-clock.js +0 -0
  320. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/bulk-proposal-ui.js +0 -0
  321. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/bulk-scope-question.js +0 -0
  322. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/cloud-privacy-policy.js +0 -0
  323. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/confirmation-card.js +0 -0
  324. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/confirmation-question.js +0 -0
  325. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/proposal-menu.js +0 -0
  326. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/ai-chat/summary-batch-preview.js +0 -0
  327. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/api-client.js +0 -0
  328. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/api-error-diagnostics.js +0 -0
  329. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/api-failure-classification-service.js +0 -0
  330. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/app-notice-stack.js +0 -0
  331. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/app-update-service.js +0 -0
  332. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/application-state.js +0 -0
  333. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/async-result.js +0 -0
  334. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/auth.js +0 -0
  335. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/backup-reminder-schedule.js +0 -0
  336. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/backup-reminder-service.js +0 -0
  337. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/byte-sizes.js +0 -0
  338. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/client-state-api.js +0 -0
  339. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/client-state-migration.js +0 -0
  340. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/command-palette/activation-auth-policy.js +0 -0
  341. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/command-palette/backup-command-availability.js +0 -0
  342. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/command-palette/click-activation-service.js +0 -0
  343. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/command-palette/note-layout-preferences.js +0 -0
  344. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/command-palette/preferences-store.js +0 -0
  345. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/command-palette/tag-config-loader.js +0 -0
  346. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/command-palette/usage-store.js +0 -0
  347. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/context-menu/context-menu-target-service.js +0 -0
  348. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/context-menu/input-caret-service.js +0 -0
  349. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/decimal-integer.js +0 -0
  350. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/disconnect-editing-state-service.js +0 -0
  351. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/dom-focus.js +0 -0
  352. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/dom-utils.js +0 -0
  353. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/editor-commands.js +0 -0
  354. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/editor-selection.js +0 -0
  355. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/editor-toolbar.js +0 -0
  356. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/elapsed-time.js +0 -0
  357. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/error-handler.js +0 -0
  358. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/error-overlay.js +0 -0
  359. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/excalidraw/excalidraw-actions.js +0 -0
  360. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/excalidraw/excalidraw-autosave.js +0 -0
  361. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/excalidraw/excalidraw-editor-service.js +0 -0
  362. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/excalidraw/excalidraw-editor-state.js +0 -0
  363. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/excalidraw/excalidraw-loader.js +0 -0
  364. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/excalidraw/excalidraw-preview-service.js +0 -0
  365. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/excalidraw/excalidraw-scene.js +0 -0
  366. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/expected-errors.js +0 -0
  367. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/half.js +0 -0
  368. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/html-escape.js +0 -0
  369. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/http-status.js +0 -0
  370. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/list-selection.js +0 -0
  371. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/local-date-text.js +0 -0
  372. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/location-flags.js +0 -0
  373. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/login-namespace-picker.js +0 -0
  374. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/maintenance.js +0 -0
  375. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/ai-agent-settings-modal.js +0 -0
  376. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/alphabetize-root-notes-modal.js +0 -0
  377. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/backup-restore-modal.js +0 -0
  378. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/backup-result-modal.js +0 -0
  379. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/backup-settings-modal.js +0 -0
  380. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/base-modal.js +0 -0
  381. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/confirmation-modal.js +0 -0
  382. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/delete-namespace-modal.js +0 -0
  383. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/delete-namespace-validation.js +0 -0
  384. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/dictation-settings-modal.js +0 -0
  385. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/export-options-modal.js +0 -0
  386. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/link-title-retry-modal.js +0 -0
  387. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/memory-usage-modal.js +0 -0
  388. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/namespace-loading-page.js +0 -0
  389. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/namespace-modals.js +0 -0
  390. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/namespace-ports-profile.js +0 -0
  391. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/namespace-rename-validation.js +0 -0
  392. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/note-layout-appearance-modal.js +0 -0
  393. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/password-modal.js +0 -0
  394. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/prioritize-modal.js +0 -0
  395. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/random-password-modal.js +0 -0
  396. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/reminder-modal.js +0 -0
  397. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/reset-updated-at-modal.js +0 -0
  398. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/search-suggestion-statistics-modal.js +0 -0
  399. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/session-timeout-modal.js +0 -0
  400. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/version-info-modal.js +0 -0
  401. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/modals/visual-cues-modal.js +0 -0
  402. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/actions/content-actions.js +0 -0
  403. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/actions/history-actions.js +0 -0
  404. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/actions/note-actions.js +0 -0
  405. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/actions/search-actions.js +0 -0
  406. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/actions/selection-actions.js +0 -0
  407. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/events/focus-events.js +0 -0
  408. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/events/inactivity-events.js +0 -0
  409. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/events/input-events.js +0 -0
  410. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/mode-context.js +0 -0
  411. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/mode-logger.js +0 -0
  412. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/mode-manager-controller.js +0 -0
  413. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/add-style-service.js +0 -0
  414. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/animated-scroll-service.js +0 -0
  415. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/backlinks-navigation-service.js +0 -0
  416. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/clipboard-shortcut-policy-service.js +0 -0
  417. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/collapse-affordance-service.js +0 -0
  418. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/collapse-editing-policy-service.js +0 -0
  419. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/command-gate-service.js +0 -0
  420. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/deselect-selection-state-service.js +0 -0
  421. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/dictation-note-paste.js +0 -0
  422. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/dictation-paste-padding.js +0 -0
  423. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/dictation-paste-service.js +0 -0
  424. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/differential-view-service.js +0 -0
  425. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/dropped-file-preview-service.js +0 -0
  426. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/edit-session-collapse-policy-service.js +0 -0
  427. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/edit-session-collapse-service.js +0 -0
  428. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/editing-image-size-service.js +0 -0
  429. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/embedded-image-service.js +0 -0
  430. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/export-service.js +0 -0
  431. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/export-title-service.js +0 -0
  432. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/file-drop-policy-service.js +0 -0
  433. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/file-image-preview-service.js +0 -0
  434. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/file-reference-service.js +0 -0
  435. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/filtered-refresh-selection-service.js +0 -0
  436. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/find-in-list-service.js +0 -0
  437. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/floating-note-dom.js +0 -0
  438. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/floating-note-layout.js +0 -0
  439. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/floating-note-service.js +0 -0
  440. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/footnote-navigation-service.js +0 -0
  441. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/history-selection-policy-service.js +0 -0
  442. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/history-shortcut-policy-service.js +0 -0
  443. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/html-paste-sanitizer-service.js +0 -0
  444. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/image-context-menu-action-service.js +0 -0
  445. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/image-file-insert-choice-modal-service.js +0 -0
  446. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/infinite-scroll-service.js +0 -0
  447. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/link-context-menu-action-service.js +0 -0
  448. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/link-target-service.js +0 -0
  449. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/link-title-prefetch-service.js +0 -0
  450. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/mermaid-render-service.js +0 -0
  451. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-click-target-service.js +0 -0
  452. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-clipboard-write-service.js +0 -0
  453. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-collapse-animation-service.js +0 -0
  454. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-context-menu-action-service.js +0 -0
  455. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-delete-shortcut-policy-service.js +0 -0
  456. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-drag-indicator-service.js +0 -0
  457. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-drag-service.js +0 -0
  458. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-fullscreen-service.js +0 -0
  459. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-reposition-animation-service.js +0 -0
  460. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-split-service.js +0 -0
  461. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/note-timestamp-hover-service.js +0 -0
  462. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/password-clipboard-service.js +0 -0
  463. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/paste-format-detection-service.js +0 -0
  464. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/paste-format-guess-service.js +0 -0
  465. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/paste-format-offer-service.js +0 -0
  466. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/paste-reference-here-service.js +0 -0
  467. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/polling-service.js +0 -0
  468. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/print-service.js +0 -0
  469. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/reference-source-navigation-service.js +0 -0
  470. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/reference-view-transition-service.js +0 -0
  471. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/referenced-note-removal-service.js +0 -0
  472. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/remote-image-proxy-service.js +0 -0
  473. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/remove-formatting-service.js +0 -0
  474. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/right-press-focus-service.js +0 -0
  475. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/root-date-separator-service.js +0 -0
  476. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/root-note-creation-service.js +0 -0
  477. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/root-sort-service.js +0 -0
  478. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/scroll-anchor-service.js +0 -0
  479. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/scroll-restoration-service.js +0 -0
  480. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/scroll-to-top-service.js +0 -0
  481. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-contexts-overlay-service.js +0 -0
  482. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-debounce-service.js +0 -0
  483. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-highlight-matching.js +0 -0
  484. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-highlight-service.js +0 -0
  485. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-input-chip-service.js +0 -0
  486. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-input-service.js +0 -0
  487. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-interaction-service.js +0 -0
  488. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-redaction-reveal-service.js +0 -0
  489. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-suggestion-statistics-service.js +0 -0
  490. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-suggestion-window-labels-service.js +0 -0
  491. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/search-suggestion-windows-service.js +0 -0
  492. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/selected-formatting-removal-service.js +0 -0
  493. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/selected-text-tag-service.js +0 -0
  494. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/shell-output-service.js +0 -0
  495. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/tab-dom-cache-service.js +0 -0
  496. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/tab-drag-service.js +0 -0
  497. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/tab-duplication-service.js +0 -0
  498. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/tag-bar-service.js +0 -0
  499. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/tag-input-selection-service.js +0 -0
  500. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/tag-proposal-service.js +0 -0
  501. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/todo-toggle-editing-service.js +0 -0
  502. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/untagged-view-indicator-service.js +0 -0
  503. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/view-mode-search-shortcut-service.js +0 -0
  504. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/viewport-hold-service.js +0 -0
  505. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/mode-manager/services/viewport-reference.js +0 -0
  506. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/not-found.js +0 -0
  507. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/note-html-sanitizer.js +0 -0
  508. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/password-generator.js +0 -0
  509. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/password-operation-response.js +0 -0
  510. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/password-policy.js +0 -0
  511. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/password-strength.js +0 -0
  512. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/reminder-store.js +0 -0
  513. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/reminder-surface-service.js +0 -0
  514. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/server-rendered-html.js +0 -0
  515. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/session-auth.js +0 -0
  516. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/startup-timing.js +0 -0
  517. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/tag-token.js +0 -0
  518. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/tcp-ports.js +0 -0
  519. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/time-units.js +0 -0
  520. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/url-tracking-cleaner.js +0 -0
  521. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/modules/uuid.js +0 -0
  522. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/namespace-deleted.js +0 -0
  523. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/namespace-renamed.js +0 -0
  524. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/shockharness/contracts.d.ts +0 -0
  525. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/shockharness/contracts.js +0 -0
  526. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/dompurify-3.4.17.LICENSE.txt +0 -0
  527. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/dompurify-3.4.17.min.js +0 -0
  528. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/excalidraw.css +0 -0
  529. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-Bold.woff2 +0 -0
  530. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-Medium.woff2 +0 -0
  531. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-Regular.woff2 +0 -0
  532. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-SemiBold.woff2 +0 -0
  533. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Cascadia/CascadiaCode-Regular.woff2 +0 -0
  534. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-279a7b317d12eb88de06167bd672b4b4.woff2 +0 -0
  535. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-6e066e8de2ac57ea9283adb9c24d7f0c.woff2 +0 -0
  536. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-dc6a8806fa96795d7b3be5026f989a17.woff2 +0 -0
  537. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-fcb0fc02dcbee4c9846b3e2508668039.woff2 +0 -0
  538. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-349fac6ca4700ffec595a7150a0d1e1d.woff2 +0 -0
  539. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-3f2c5db56cc93c5a6873b1361d730c16.woff2 +0 -0
  540. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-41b173a47b57366892116a575a43e2b6.woff2 +0 -0
  541. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-623ccf21b21ef6b3a0d87738f77eb071.woff2 +0 -0
  542. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-a88b72a24fb54c9f94e3b5fdaa7481c9.woff2 +0 -0
  543. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-b9dcf9d2e50a1eaf42fc664b50a3fd0d.woff2 +0 -0
  544. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-be310b9bcd4f1a43f571c46df7809174.woff2 +0 -0
  545. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYE98RXi4EwSsbg.woff2 +0 -0
  546. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYEF8RXi4EwQ.woff2 +0 -0
  547. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTA3j6zbXWjgevT5.woff2 +0 -0
  548. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTQ3j6zbXWjgeg.woff2 +0 -0
  549. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTk3j6zbXWjgevT5.woff2 +0 -0
  550. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTo3j6zbXWjgevT5.woff2 +0 -0
  551. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTs3j6zbXWjgevT5.woff2 +0 -0
  552. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Virgil/Virgil-Regular.woff2 +0 -0
  553. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1.LICENSE.txt +0 -0
  554. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/excalidraw-0.18.1.min.js +0 -0
  555. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/mermaid-11.16.1.LICENSE.txt +0 -0
  556. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/mermaid-11.16.1.min.js +0 -0
  557. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/zxcvbn-4.4.2.LICENSE.txt +0 -0
  558. {metalist-0.23.0 → metalist-0.24.0}/app/static/js/vendor/zxcvbn-4.4.2.js +0 -0
  559. {metalist-0.23.0 → metalist-0.24.0}/app/static/note-html-policy.json +0 -0
  560. {metalist-0.23.0 → metalist-0.24.0}/app/templates/_logo_mark.html +0 -0
  561. {metalist-0.23.0 → metalist-0.24.0}/app/templates/base.html +0 -0
  562. {metalist-0.23.0 → metalist-0.24.0}/app/templates/locked.html +0 -0
  563. {metalist-0.23.0 → metalist-0.24.0}/app/templates/maintenance.html +0 -0
  564. {metalist-0.23.0 → metalist-0.24.0}/app/templates/namespace_deleted.html +0 -0
  565. {metalist-0.23.0 → metalist-0.24.0}/app/templates/namespace_renamed.html +0 -0
  566. {metalist-0.23.0 → metalist-0.24.0}/app/templates/notes_list.html +0 -0
  567. {metalist-0.23.0 → metalist-0.24.0}/app/upload_limits.py +0 -0
  568. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/__init__.py +0 -0
  569. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/add_selected_text_tag.py +0 -0
  570. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/base.py +0 -0
  571. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/collapse.py +0 -0
  572. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/copy_note.py +0 -0
  573. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/create_child.py +0 -0
  574. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/create_file_preview_child.py +0 -0
  575. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/create_note.py +0 -0
  576. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/create_sibling.py +0 -0
  577. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/delete_subtree.py +0 -0
  578. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/delete_tag.py +0 -0
  579. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/expand.py +0 -0
  580. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/file_edit_session.py +0 -0
  581. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/indent.py +0 -0
  582. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/move.py +0 -0
  583. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/outdent.py +0 -0
  584. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/paste_child.py +0 -0
  585. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/paste_reference.py +0 -0
  586. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/paste_sibling.py +0 -0
  587. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/prefetch_link_titles.py +0 -0
  588. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/prioritize.py +0 -0
  589. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/redo.py +0 -0
  590. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/rename_tag.py +0 -0
  591. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/resize_image.py +0 -0
  592. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/run_shell.py +0 -0
  593. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/search_comment_autofill.py +0 -0
  594. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/set_collapse_bulk.py +0 -0
  595. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/split_note.py +0 -0
  596. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/toggle_todo_done.py +0 -0
  597. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/undo.py +0 -0
  598. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/unformat_content.py +0 -0
  599. {metalist-0.23.0 → metalist-0.24.0}/app/usecases/update_content.py +0 -0
  600. {metalist-0.23.0 → metalist-0.24.0}/app/utils/__init__.py +0 -0
  601. {metalist-0.23.0 → metalist-0.24.0}/app/utils/byte_sizes.py +0 -0
  602. {metalist-0.23.0 → metalist-0.24.0}/app/utils/encryption.py +0 -0
  603. {metalist-0.23.0 → metalist-0.24.0}/app/utils/not_found.py +0 -0
  604. {metalist-0.23.0 → metalist-0.24.0}/app/utils/sent_fields.py +0 -0
  605. {metalist-0.23.0 → metalist-0.24.0}/app/utils/tcp_ports.py +0 -0
  606. {metalist-0.23.0 → metalist-0.24.0}/app/utils/text_utils.py +0 -0
  607. {metalist-0.23.0 → metalist-0.24.0}/app/utils/time_units.py +0 -0
  608. {metalist-0.23.0 → metalist-0.24.0}/convert-from-legacy.py +0 -0
  609. {metalist-0.23.0 → metalist-0.24.0}/main.py +0 -0
  610. {metalist-0.23.0 → metalist-0.24.0}/metalist.egg-info/dependency_links.txt +0 -0
  611. {metalist-0.23.0 → metalist-0.24.0}/metalist.egg-info/entry_points.txt +0 -0
  612. {metalist-0.23.0 → metalist-0.24.0}/metalist.egg-info/requires.txt +0 -0
  613. {metalist-0.23.0 → metalist-0.24.0}/metalist.egg-info/top_level.txt +0 -0
  614. {metalist-0.23.0 → metalist-0.24.0}/pyproject.toml +0 -0
  615. {metalist-0.23.0 → metalist-0.24.0}/scripts/generate-lan-cert.sh +0 -0
  616. {metalist-0.23.0 → metalist-0.24.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: metalist
3
- Version: 0.23.0
3
+ Version: 0.24.0
4
4
  Summary: A minimalist single-user note-taking app with SSR, fast in-memory tree operations, and efficient sync.
5
5
  Project-URL: Homepage, https://metalist.app
6
6
  Project-URL: Repository, https://github.com/metalist-app/metalist
@@ -53,6 +53,16 @@ A minimalist single-user note-taking app focused on server-side rendering (SSR),
53
53
  - Multi-tab search contexts with server-persisted scroll/search state (survives browser restarts)
54
54
  - Manual namespace backups/restores to a user-selected backup folder with retention controls
55
55
 
56
+ ## Changes in 0.24.0
57
+
58
+ - **Super tags.** A tag can carry values: `jogging:miles=3:duration=30`, `drug:dosage=10mg`, `run:start=10:30pm`. Search by them with `jogging:miles>2`, `jogging:miles?` (notes missing it), `date>=2024-01`, or `jogging:miles=MAX` / `=MIN` for the largest or smallest among the notes found. Values compare as numbers (a unit is a label: `dosage>5mg` compares only mg, `dosage>5` every unit), dates, times (`10:30pm` = `22:30`) or text. A search reads values through tag rules too: with `jogging => exercise`, `exercise:miles>2` finds your runs. The tag bar and the search box suggest the property names and units you already use, and `MAX`/`MIN` after `=`. A plain `jogging` search still finds `jogging:miles=3`; children inherit the tag, never its values.
59
+ - Tag rules can test values: `jogging:miles>10 => long-run`, `task:due? => needs-date`. The tag a rule gives passes to the note's children; Edit Tag Relationships shows such a rule in the left column of the tag it gives, suggests names and units while you type one, and warns about a property no note has (a typo). Saving one re-tags only the notes it can concern.
60
+ - The AI can propose super tags with values a note states (`jogging:miles=3` for "ran 3 miles"), reusing your property names and units; accepting one adds its values to the note's tag.
61
+ - **Date range** (right-click menu, search box menu and command palette): show only notes created, or last updated, today, in the last 7 or 30 days, this year, or in a custom range. A chip in the search box names it; its `×`, a new search or leaving the tab ends it.
62
+ - File names are searchable: a quoted search (`"congratulation"`) and find (Cmd/Ctrl+F) match the names of files a note holds, and the AI sees them.
63
+ - ⌘+ / ⌘− with the pointer on a picture or diagram makes it bigger or smaller, viewing or editing.
64
+ - Right-clicking the search box past what you typed offers View, Sort by and Date range.
65
+
56
66
  ## Changes in 0.23.0
57
67
 
58
68
  - **Reference views.** Following a reference (a link, an embed's reference icon, Go to Source Note) or an AI answer's references slides the list to the left, and a gray chip takes the search box's place: **Source note** (its first line is the tooltip), **Reference** or **All references**. `←` or Escape goes back one level, `×` straight back to your search, each to the exact place you left; the list slides back to the right. With Reduce Motion it is a quick fade. The magnifier beside the chip starts a new search. Reference tabs keep their label and chip after a reload and in every window: no tab is named by a note ID any more.
@@ -12,6 +12,16 @@ A minimalist single-user note-taking app focused on server-side rendering (SSR),
12
12
  - Multi-tab search contexts with server-persisted scroll/search state (survives browser restarts)
13
13
  - Manual namespace backups/restores to a user-selected backup folder with retention controls
14
14
 
15
+ ## Changes in 0.24.0
16
+
17
+ - **Super tags.** A tag can carry values: `jogging:miles=3:duration=30`, `drug:dosage=10mg`, `run:start=10:30pm`. Search by them with `jogging:miles>2`, `jogging:miles?` (notes missing it), `date>=2024-01`, or `jogging:miles=MAX` / `=MIN` for the largest or smallest among the notes found. Values compare as numbers (a unit is a label: `dosage>5mg` compares only mg, `dosage>5` every unit), dates, times (`10:30pm` = `22:30`) or text. A search reads values through tag rules too: with `jogging => exercise`, `exercise:miles>2` finds your runs. The tag bar and the search box suggest the property names and units you already use, and `MAX`/`MIN` after `=`. A plain `jogging` search still finds `jogging:miles=3`; children inherit the tag, never its values.
18
+ - Tag rules can test values: `jogging:miles>10 => long-run`, `task:due? => needs-date`. The tag a rule gives passes to the note's children; Edit Tag Relationships shows such a rule in the left column of the tag it gives, suggests names and units while you type one, and warns about a property no note has (a typo). Saving one re-tags only the notes it can concern.
19
+ - The AI can propose super tags with values a note states (`jogging:miles=3` for "ran 3 miles"), reusing your property names and units; accepting one adds its values to the note's tag.
20
+ - **Date range** (right-click menu, search box menu and command palette): show only notes created, or last updated, today, in the last 7 or 30 days, this year, or in a custom range. A chip in the search box names it; its `×`, a new search or leaving the tab ends it.
21
+ - File names are searchable: a quoted search (`"congratulation"`) and find (Cmd/Ctrl+F) match the names of files a note holds, and the AI sees them.
22
+ - ⌘+ / ⌘− with the pointer on a picture or diagram makes it bigger or smaller, viewing or editing.
23
+ - Right-clicking the search box past what you typed offers View, Sort by and Date range.
24
+
15
25
  ## Changes in 0.23.0
16
26
 
17
27
  - **Reference views.** Following a reference (a link, an embed's reference icon, Go to Source Note) or an AI answer's references slides the list to the left, and a gray chip takes the search box's place: **Source note** (its first line is the tooltip), **Reference** or **All references**. `←` or Escape goes back one level, `×` straight back to your search, each to the exact place you left; the list slides back to the right. With Reduce Motion it is a quick fade. The magnifier beside the chip starts a new search. Reference tabs keep their label and chip after a reload and in every window: no tab is named by a note ID any more.
@@ -124,6 +124,18 @@ class UpdateTabSortModeRequest(TypedDict):
124
124
  clientId: Identifier
125
125
  undoContext: UndoContext
126
126
 
127
+ @with_config(ConfigDict(strict=True))
128
+ class UpdateTabDateFilterRequest(TypedDict):
129
+ tabId: Identifier
130
+ field: Literal["created", "updated"]
131
+ # "none" shows every date again.
132
+ rangeKind: Literal["none", "today", "last-7-days", "last-30-days", "this-year", "custom"]
133
+ # A custom range's ends (YYYY-MM-DD); "" for an open end, and for every other range.
134
+ fromDate: Text
135
+ toDate: Text
136
+ clientId: Identifier
137
+ undoContext: UndoContext
138
+
127
139
  @with_config(ConfigDict(strict=True))
128
140
  class CreateNewTabRequest(TypedDict):
129
141
  copyFromTabId: Identifier
@@ -498,6 +498,7 @@ def suggest_tags_for_note_with_ai(
498
498
  scope = resolve_view_scope_membership(
499
499
  search=payload.search,
500
500
  sort_mode=tab_state_store.get_sort_mode(tab_id=payload.tab_id),
501
+ date_filter=tab_state_store.get_date_filter(tab_id=payload.tab_id),
501
502
  is_untagged_view=payload.is_untagged_view,
502
503
  )
503
504
  if note_id not in scope.allowed_note_ids:
@@ -559,6 +560,7 @@ def _export_title_request(scope: ExportTitleScope, token: str) -> ExportTitleReq
559
560
  root_ids, allowed_note_ids = resolve_export_scope(
560
561
  search=search,
561
562
  sort_mode=tab_state_store.get_sort_mode(tab_id=scope.tab_id),
563
+ date_filter=tab_state_store.get_date_filter(tab_id=scope.tab_id),
562
564
  is_untagged_view=scope.is_untagged_view, root_note_id=note_id,
563
565
  )
564
566
  boundary = resolve_cloud_privacy_boundary(preferences=load_client_preferences(token=token), provider=scope.provider)
@@ -903,21 +905,26 @@ def stream_ai_chat(
903
905
  authoritative_sort_mode = tab_state_store.get_sort_mode(
904
906
  tab_id=payload.scope.scope_tab_id
905
907
  )
908
+ authoritative_date_filter = tab_state_store.get_date_filter(tab_id=payload.scope.scope_tab_id)
906
909
  active_search_query = authoritative_search_query
907
910
  active_sort_mode = authoritative_sort_mode
911
+ active_date_filter = authoritative_date_filter
908
912
  if payload.selected_note_id and payload.scope.active_tab_id != payload.scope.scope_tab_id:
909
913
  active_search_query = tab_state_store.get_search_query(tab_id=authoritative_active_tab_id)
910
914
  active_sort_mode = tab_state_store.get_sort_mode(tab_id=authoritative_active_tab_id)
915
+ active_date_filter = tab_state_store.get_date_filter(tab_id=authoritative_active_tab_id)
911
916
  frozen_scope = scoped_search_snapshot_factory.freeze(
912
917
  descriptor=payload.scope,
913
918
  authoritative_search_query=authoritative_search_query,
914
919
  authoritative_sort_mode=authoritative_sort_mode,
920
+ authoritative_date_filter=authoritative_date_filter,
915
921
  run_id=str(uuid4()),
916
922
  session_key=session_key,
917
923
  privacy_boundary=privacy_boundary,
918
924
  selected_note_id=payload.selected_note_id,
919
925
  authoritative_active_search_query=active_search_query,
920
926
  authoritative_active_sort_mode=active_sort_mode,
927
+ authoritative_active_date_filter=active_date_filter,
921
928
  )
922
929
  tagging_run = TaggingRun(token=token, snapshot=frozen_scope, privacy_boundary=privacy_boundary,
923
930
  preferences=preferences, sync_uuid=get_current_sync_uuid(),
@@ -1054,7 +1061,9 @@ def manage_bulk_proposals(payload: BulkManageRequest, token: Annotated[str, Depe
1054
1061
  raise HTTPException(status_code=HTTPStatus.CONFLICT, detail="Search context changed")
1055
1062
  async def execute():
1056
1063
  with bulk_operation_guard.acquire(token_service.get_session_key(token)):
1057
- note_ids = proposal_scope_ids(payload.scope)
1064
+ note_ids = proposal_scope_ids(
1065
+ payload.scope, date_filter=tab_state_store.get_date_filter(tab_id=payload.scope.scope_tab_id),
1066
+ )
1058
1067
  if payload.target == "namespace":
1059
1068
  note_ids = tuple(note_store.list_note_ids())
1060
1069
  changes, count, _ = prepare_proposal_changes(
@@ -13,6 +13,7 @@ from app.api.note_requests import (
13
13
  ViewDiffRequest,
14
14
  FindInListRequest,
15
15
  UpdateTabStateRequest,
16
+ UpdateTabDateFilterRequest,
16
17
  UpdateTabSortModeRequest,
17
18
  CreateNewTabRequest,
18
19
  DeleteTabRequest,
@@ -63,6 +64,14 @@ from app.api.note_requests import (
63
64
  )
64
65
  from app.api.transactions import serialized_read_route, transactional_route
65
66
  from app.services.sync import touch_client
67
+ from app.services.root_date_filter import DATE_RANGE_NONE
68
+ from app.services.tag_properties import PROPERTY_SUGGESTIONS_IN_SEARCH
69
+ from app.services.tag_properties import PROPERTY_SUGGESTIONS_IN_TAG_BAR
70
+ from app.services.tag_properties import PropertySuggestion
71
+ from app.services.tag_properties import has_property_syntax
72
+ from app.services.tag_properties import is_property_term
73
+ from app.services.root_date_filter import RootDateFilter
74
+ from app.services.root_date_filter import make_root_date_filter
66
75
  from app.services.snapshot import build_view_state
67
76
  from app.services.snapshot import find_in_view
68
77
  from app.services.snapshot import resolve_search_scope
@@ -262,6 +271,13 @@ def _resolve_tab_sort_mode(tab_id: object) -> str:
262
271
  return sort_mode
263
272
 
264
273
 
274
+ def _resolve_tab_date_filter(tab_id: str) -> RootDateFilter | None:
275
+ """The tab's date range filter (None: every date), as its sort order is resolved."""
276
+ if not isinstance(tab_id, str) or tab_id == "":
277
+ raise TypeError("tabId must be a non-empty string")
278
+ return tab_state_store.get_date_filter(tab_id=tab_id)
279
+
280
+
265
281
  def _block_root_reorder_when_sorted(note_id: str, *, tab_id: object, new_parent_id: object) -> None:
266
282
  sort_mode = _resolve_tab_sort_mode(tab_id)
267
283
  if not is_root_reorder_locked(sort_mode):
@@ -367,6 +383,7 @@ def view_diff(payload: ViewDiffRequest):
367
383
  find_reveal_note_id=find_reveal_note_id,
368
384
  search=normalized_search,
369
385
  sort_mode=sort_mode,
386
+ date_filter=_resolve_tab_date_filter(tab_id),
370
387
  client_known_note_ids=client_known_note_ids,
371
388
  previous_root_ids=previous_root_ids,
372
389
  visible_top_root_id=visible_top_root_id,
@@ -474,6 +491,23 @@ def update_tab_sort_mode(payload: UpdateTabSortModeRequest) -> Dict[str, object]
474
491
  return response
475
492
 
476
493
 
494
+ @router.post("/notes/tab-state/date-filter")
495
+ @transactional_route
496
+ def update_tab_date_filter(payload: UpdateTabDateFilterRequest) -> Dict[str, object]:
497
+ """Set or clear a tab's date range filter (root_date_filter.py). A range that is
498
+ not one (its start after its end, say) is answered as rejected input."""
499
+ date_filter: RootDateFilter | None = None
500
+ if payload["rangeKind"] != DATE_RANGE_NONE:
501
+ date_filter = make_root_date_filter(
502
+ field=payload["field"], range_kind=payload["rangeKind"],
503
+ from_date=payload["fromDate"], to_date=payload["toDate"],
504
+ )
505
+ response = tab_state_store.set_date_filter(tab_id=payload["tabId"], date_filter=date_filter)
506
+ if response["changed"] is True:
507
+ reset_undo_stack(payload["clientId"], payload["undoContext"])
508
+ return response
509
+
510
+
477
511
  @router.post("/notes/tab-state/new-tab")
478
512
  @transactional_route
479
513
  def create_new_tab(payload: CreateNewTabRequest) -> Dict[str, object]:
@@ -523,6 +557,15 @@ def search_suggestions(request: Request, payload: SearchSuggestionsRequest) -> D
523
557
  )
524
558
  window_days = tuple(raw_window_days)
525
559
  validate_tag_activity_windows(window_days)
560
+ # Typing a property term (exercise:mi, drug:dosage>5): its names or units.
561
+ typed_term = _typed_property_term(query)
562
+ if typed_term is not None:
563
+ return _property_suggestions_response(
564
+ search_index.suggest_property_completions(
565
+ typed=typed_term, place=PROPERTY_SUGGESTIONS_IN_SEARCH, limit=MAX_SEARCH_SUGGESTIONS,
566
+ ),
567
+ personalized=True,
568
+ )
526
569
  all_suggestions = search_index.suggest_all_tag_completions(query=query)
527
570
  suggestions = all_suggestions[:MAX_SEARCH_SUGGESTIONS]
528
571
  personalized_selections: list[TagActivityWindowSelection] = []
@@ -561,9 +604,33 @@ def search_suggestions(request: Request, payload: SearchSuggestionsRequest) -> D
561
604
  tag: list(search_suggestion_reasons(facts=facts, term=tag, recent_activity=recent_activity))
562
605
  for tag in suggestions
563
606
  },
607
+ "labels": {tag: tag for tag in suggestions},
564
608
  }
565
609
 
566
610
 
611
+ def _typed_property_term(query: str) -> str | None:
612
+ """The property term being typed at the end of a search, without its - or +."""
613
+ if query == "" or query[-1].isspace():
614
+ return None
615
+ term = query.split()[-1].lstrip("+-")
616
+ if '"' in term or "'" in term or not is_property_term(term):
617
+ return None
618
+ return term
619
+
620
+
621
+ def _property_suggestions_response(suggestions: list[PropertySuggestion], *, personalized: bool) -> Dict[str, object]:
622
+ """Property names or units as the suggestion lists take them: the full replacement,
623
+ the part the list shows (miles= for jogging:miles=) and why."""
624
+ response: Dict[str, object] = {
625
+ "suggestions": [suggestion.replacement for suggestion in suggestions],
626
+ "reasons": {suggestion.replacement: list(suggestion.reasons) for suggestion in suggestions},
627
+ "labels": {suggestion.replacement: suggestion.label for suggestion in suggestions},
628
+ }
629
+ if personalized:
630
+ response["personalizedSuggestions"] = []
631
+ return response
632
+
633
+
567
634
  @router.post("/notes/prioritize-tag-suggestions")
568
635
  @transactional_route
569
636
  def prioritize_tag_suggestions(payload: PrioritizeTagSuggestionsRequest) -> Dict[str, object]:
@@ -664,6 +731,7 @@ def find_in_list(payload: FindInListRequest) -> Dict[str, object]:
664
731
  raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="text must hold more than spaces")
665
732
  window = find_in_view(
666
733
  find_text=payload["text"], search=search, sort_mode=_resolve_tab_sort_mode(payload["tabId"]),
734
+ date_filter=_resolve_tab_date_filter(payload["tabId"]),
667
735
  is_untagged_view=payload["isUntaggedView"], from_root_index=payload["fromRootIndex"],
668
736
  direction=payload["direction"],
669
737
  )
@@ -737,6 +805,15 @@ def tag_suggestions(payload: TagSuggestionsRequest) -> Dict[str, object]:
737
805
 
738
806
  _require_note_present(note_id, context="notes.tag-suggestions")
739
807
 
808
+ # Typing after a tag's colon (jogging:mi, drug:dosage=10m): property names or units.
809
+ if has_property_syntax(prefix):
810
+ return _property_suggestions_response(
811
+ search_index.suggest_property_completions(
812
+ typed=prefix, place=PROPERTY_SUGGESTIONS_IN_TAG_BAR, limit=MAX_TAG_SUGGESTIONS,
813
+ ),
814
+ personalized=False,
815
+ )
816
+
740
817
  suggestions = suggest_tags_with_reasons_for_note(
741
818
  note_id=note_id,
742
819
  anchors=anchors,
@@ -749,6 +826,7 @@ def tag_suggestions(payload: TagSuggestionsRequest) -> Dict[str, object]:
749
826
  return {
750
827
  "suggestions": [suggestion.tag for suggestion in suggestions],
751
828
  "reasons": {suggestion.tag: list(suggestion.reasons) for suggestion in suggestions},
829
+ "labels": {suggestion.tag: suggestion.tag for suggestion in suggestions},
752
830
  }
753
831
 
754
832
 
@@ -797,6 +875,7 @@ def export_summary(request: Request) -> Dict[str, object]:
797
875
  normalized_search = None
798
876
  counts = exported_credential_counts(
799
877
  search=normalized_search, sort_mode=_resolve_tab_sort_mode(tab_id),
878
+ date_filter=_resolve_tab_date_filter(tab_id),
800
879
  is_untagged_view=is_untagged_view == "true", root_note_id=note_id,
801
880
  )
802
881
  return {
@@ -856,6 +935,7 @@ def export_notes_html(request: Request) -> Response:
856
935
  document = build_notes_export_document(
857
936
  search=normalized_search,
858
937
  sort_mode=_resolve_tab_sort_mode(tab_id),
938
+ date_filter=_resolve_tab_date_filter(tab_id),
859
939
  is_untagged_view=is_untagged_view == "true",
860
940
  theme=normalized_theme,
861
941
  token=token,
@@ -917,6 +997,7 @@ def backlinks(request: Request, note_id: str) -> Dict[str, object]:
917
997
  search=normalized_search,
918
998
  editing_note_id=None,
919
999
  sort_mode="normal",
1000
+ date_filter=None,
920
1001
  ordered_root_ids=None,
921
1002
  )
922
1003
  source_note_ids = search_scope.allowed_note_ids
@@ -1117,6 +1198,7 @@ def _robot_scope_note_ids(body: dict) -> frozenset[str]:
1117
1198
  return resolve_view_scope_membership(
1118
1199
  search=body["search"],
1119
1200
  sort_mode=_resolve_tab_sort_mode(body["tabId"]),
1201
+ date_filter=_resolve_tab_date_filter(body["tabId"]),
1120
1202
  is_untagged_view=body["isUntaggedView"],
1121
1203
  ).allowed_note_ids
1122
1204
 
@@ -21,7 +21,8 @@ from app.services.tag_term_matching import list_significant_content_match_segmen
21
21
  from app.utils.not_found import NOT_FOUND
22
22
  from app.services.note_store import store as note_store
23
23
  from app.services.sync import generate_new_uuid
24
- from app.services.tag_ontology import RegexAtom, TagAtom, TextAtom, parse_rules_text
24
+ from app.services.tag_properties import PROPERTY_SUGGESTIONS_IN_RULE, is_property_term
25
+ from app.services.tag_ontology import PropertyAtom, RegexAtom, TagAtom, TextAtom, parse_rules_text, rule_text_tests_values
25
26
  from app.services.ontology_rules_store import (
26
27
  build_direct_edge_rule_map,
27
28
  create_rule_line,
@@ -97,6 +98,10 @@ def _collect_candidate_note_ids_for_rules(rules: list) -> set[str]:
97
98
  tags: list[str] = []
98
99
  phrases: list[str] = []
99
100
  regexes: list[re.Pattern[str]] = []
101
+ # A rule testing super tag values changes notes' own tags: _refresh_note_tags
102
+ # rebuilds every note's, so it needs no candidates.
103
+ if any(isinstance(atom, PropertyAtom) for atom in rule.lhs):
104
+ continue
100
105
  for atom in rule.lhs:
101
106
  if isinstance(atom, TagAtom):
102
107
  tags.append(atom.tag)
@@ -133,6 +138,32 @@ def _collect_candidate_note_ids_for_rules(rules: list) -> set[str]:
133
138
  return candidates
134
139
 
135
140
 
141
+ def _rule_warnings(text: str) -> list[str]:
142
+ """What looks wrong in a saved rule: a super tag term no note can match, most likely
143
+ a typo (jogging:mile>10 where notes say miles)."""
144
+ warnings: list[str] = []
145
+ for rule in parse_rules_text(text=f"{text}\n", filename="ontology_rules:warnings"):
146
+ for atom in rule.lhs:
147
+ if not isinstance(atom, PropertyAtom):
148
+ continue
149
+ condition = atom.condition
150
+ if search_index.uses_property(tag=condition.tag, property_name=condition.name):
151
+ continue
152
+ warnings.append(f"No note has {condition.tag}:{condition.name} yet; check the spelling.")
153
+ return warnings
154
+
155
+
156
+ def _refresh_note_tags(candidate_note_ids: set[str], *, rule_texts: list[str]) -> None:
157
+ """After a rule changed: the candidate notes' tags. A rule testing super tag values
158
+ refreshes the notes it can concern, with their children and the notes referencing
159
+ them, since the tags it gives pass to those (NoteStore.refresh_tags_for_value_rules)."""
160
+ if any(rule_text_tests_values(text) for text in rule_texts):
161
+ note_store.refresh_tags_for_value_rules(rule_texts=[text for text in rule_texts if rule_text_tests_values(text)])
162
+ if all(rule_text_tests_values(text) for text in rule_texts):
163
+ return
164
+ note_store.rebuild_search_index_tag_terms_for_notes(candidate_note_ids)
165
+
166
+
136
167
  def _collect_candidate_note_ids_for_texts(texts: list[str], *, filename: str) -> set[str]:
137
168
  candidates: set[str] = set()
138
169
  for text in texts:
@@ -181,10 +212,10 @@ def create_rule(request: Request, payload: RuleTextRequest) -> dict:
181
212
  token = _maybe_bearer_token(request)
182
213
  rule_id, normalized = create_rule_line(text=text, token=token)
183
214
  if note_store.loaded:
184
- note_store.rebuild_search_index_tag_terms_for_notes(candidate_note_ids)
215
+ _refresh_note_tags(candidate_note_ids, rule_texts=[text])
185
216
  update_uuid = generate_new_uuid()
186
- return {"id": rule_id, "text": normalized, "updateUUID": update_uuid}
187
- return {"id": rule_id, "text": normalized}
217
+ return {"id": rule_id, "text": normalized, "updateUUID": update_uuid, "warnings": _rule_warnings(normalized)}
218
+ return {"id": rule_id, "text": normalized, "warnings": []}
188
219
 
189
220
 
190
221
  @router.put("/rules/{rule_id}")
@@ -210,18 +241,19 @@ def update_rule(request: Request, rule_id: int, payload: RuleTextRequest) -> dic
210
241
  break
211
242
  if old_text is None:
212
243
  raise RuntimeError("Expected rule text for update")
244
+ rule_texts = [old_text, text]
213
245
  candidate_note_ids = _collect_candidate_note_ids_for_texts(
214
- [old_text, text],
246
+ rule_texts,
215
247
  filename=f"ontology_rules:{rule_id}",
216
248
  )
217
249
 
218
250
  token = _maybe_bearer_token(request)
219
251
  updated_id, normalized = update_rule_line(rule_id=rule_id, text=text, token=token)
220
252
  if note_store.loaded:
221
- note_store.rebuild_search_index_tag_terms_for_notes(candidate_note_ids)
253
+ _refresh_note_tags(candidate_note_ids, rule_texts=rule_texts)
222
254
  update_uuid = generate_new_uuid()
223
- return {"id": updated_id, "text": normalized, "updateUUID": update_uuid}
224
- return {"id": updated_id, "text": normalized}
255
+ return {"id": updated_id, "text": normalized, "updateUUID": update_uuid, "warnings": _rule_warnings(normalized)}
256
+ return {"id": updated_id, "text": normalized, "warnings": []}
225
257
 
226
258
 
227
259
  @router.delete("/rules/{rule_id}")
@@ -241,14 +273,15 @@ def delete_rule(rule_id: int) -> dict:
241
273
  break
242
274
  if old_text is None:
243
275
  raise RuntimeError("Expected rule text for delete")
276
+ rule_texts = [old_text]
244
277
  candidate_note_ids = _collect_candidate_note_ids_for_texts(
245
- [old_text],
278
+ rule_texts,
246
279
  filename=f"ontology_rules:{rule_id}",
247
280
  )
248
281
 
249
282
  delete_rule_line(rule_id=rule_id)
250
283
  if note_store.loaded:
251
- note_store.rebuild_search_index_tag_terms_for_notes(candidate_note_ids)
284
+ _refresh_note_tags(candidate_note_ids, rule_texts=rule_texts)
252
285
  update_uuid = generate_new_uuid()
253
286
  return {"ok": True, "updateUUID": update_uuid}
254
287
  return {"ok": True}
@@ -306,6 +339,8 @@ def focus_view(tag: str) -> dict:
306
339
  return "text", f'"{escaped}"'
307
340
  if isinstance(atom, RegexAtom):
308
341
  return "regex", f"/{atom.pattern}/{atom.flags}"
342
+ if isinstance(atom, PropertyAtom):
343
+ return "value", atom.condition.format()
309
344
  raise TypeError(f"Unknown atom: {type(atom)}")
310
345
 
311
346
  def atom_payload(atom: object) -> dict:
@@ -316,6 +351,10 @@ def focus_view(tag: str) -> dict:
316
351
  return {"kind": kind, "text": display}
317
352
  if kind == "regex":
318
353
  return {"kind": kind, "regex": display}
354
+ if kind == "value":
355
+ # A super tag term: its tag is a chip like any tag, the rest is shown as written.
356
+ assert isinstance(atom, PropertyAtom)
357
+ return {"kind": kind, "value": display, "tag": atom.condition.tag}
319
358
  raise RuntimeError(f"Unexpected atom kind: {kind}")
320
359
 
321
360
  def format_atom_for_edit(atom: object) -> str:
@@ -327,6 +366,8 @@ def focus_view(tag: str) -> dict:
327
366
  if isinstance(atom, RegexAtom):
328
367
  escaped = atom.pattern.replace("\\", "\\\\").replace("/", "\\/")
329
368
  return f"/{escaped}/{atom.flags}"
369
+ if isinstance(atom, PropertyAtom):
370
+ return atom.condition.format()
330
371
  raise TypeError(f"Unknown atom: {type(atom)}")
331
372
 
332
373
  def record_equality_rule_ids(rules: list, rule_id: int) -> bool:
@@ -555,6 +596,18 @@ def list_tags(q: str, limit: int, focus: str, relation: str) -> dict:
555
596
  if (relation == "none") != (focus == ""):
556
597
  raise ValueError("A focus tag goes with a relation, and only with one")
557
598
 
599
+ # A super tag term in an incoming condition (jogging:mi, drug:dosage>5): its property
600
+ # names, units and values, as a rule reads them (docs/design/tag-properties.md).
601
+ if relation == "incoming" and is_property_term(q):
602
+ suggestions = search_index.suggest_property_completions(typed=q, place=PROPERTY_SUGGESTIONS_IN_RULE, limit=limit)
603
+ return {
604
+ "totalCount": len(suggestions),
605
+ "tags": [
606
+ {"tag": suggestion.replacement, "count": suggestion.note_count, "label": suggestion.label}
607
+ for suggestion in suggestions
608
+ ],
609
+ }
610
+
558
611
  ontology = get_ontology()
559
612
  # A tag only the rules name is on no note yet.
560
613
  tag_counts = {tag: 0 for tag in extract_ontology_tags(ontology)}
@@ -568,12 +621,12 @@ def list_tags(q: str, limit: int, focus: str, relation: str) -> dict:
568
621
  ordered.extend(tag for tag in group if needle == "" or _match_rank(needle=needle, tag=tag) != NOT_FOUND)
569
622
  rest = [(_match_rank(needle=needle, tag=tag), index, tag) for index, tag in enumerate(order.by_use)]
570
623
  ordered.extend(tag for rank, _index, tag in sorted(rest) if needle == "" or rank != NOT_FOUND)
571
- payload = [{"tag": tag, "count": tag_counts[tag]} for tag in ordered[:limit]]
624
+ payload = [{"tag": tag, "count": tag_counts[tag], "label": tag} for tag in ordered[:limit]]
572
625
  return {"totalCount": len(tag_counts), "tags": payload}
573
626
 
574
627
  if needle == "":
575
628
  ordered = sorted(tag_counts, key=lambda tag: (-tag_counts[tag], tag))[:limit]
576
- return {"totalCount": len(tag_counts), "tags": [{"tag": tag, "count": tag_counts[tag]} for tag in ordered]}
629
+ return {"totalCount": len(tag_counts), "tags": [{"tag": tag, "count": tag_counts[tag], "label": tag} for tag in ordered]}
577
630
 
578
631
  matches: list[tuple[int, int, str]] = []
579
632
  for tag in tag_counts:
@@ -582,5 +635,5 @@ def list_tags(q: str, limit: int, focus: str, relation: str) -> dict:
582
635
  matches.append((rank, -tag_counts[tag], tag))
583
636
  # By rank, then most used, then name.
584
637
  matches.sort()
585
- payload = [{"tag": tag, "count": tag_counts[tag]} for _rank, _negative_count, tag in matches[:limit]]
638
+ payload = [{"tag": tag, "count": tag_counts[tag], "label": tag} for _rank, _negative_count, tag in matches[:limit]]
586
639
  return {"totalCount": len(tag_counts), "tags": payload}
@@ -14,7 +14,9 @@ from app.services.search_index import search_index
14
14
  from app.services.tag_case import build_preferred_tag_case_map
15
15
  from app.services.search_query import ParsedSearchQuery, SearchClause
16
16
  from app.services.search_query import format_search_query, format_search_term, parse_search_query
17
+ from app.services.search_index import extract_ordered_tags_for_agent
17
18
  from app.services.tag_ontology import is_valid_tag_token
19
+ from app.services.tag_properties import PROPERTY_SEPARATOR, has_property_syntax, split_property_segments, tag_part_of_token
18
20
  from app.services.content_formatting import extract_note_text_for_agent
19
21
 
20
22
 
@@ -106,6 +108,37 @@ def visible_tag_counts(boundary: CloudPrivacyBoundary) -> tuple[dict[str, str],
106
108
  return display, counts
107
109
 
108
110
 
111
+ # The AI is shown at most this many properties in use (visible_super_tag_examples).
112
+ _MAX_SUPER_TAG_EXAMPLES = 40
113
+
114
+
115
+ def visible_super_tag_examples(boundary: CloudPrivacyBoundary) -> tuple[str, ...]:
116
+ """One example of each property in use on notes the AI may see, most used first
117
+ (jogging:miles=3, drug:dosage=10mg), so super tags it proposes reuse their names and
118
+ units (docs/design/tag-properties.md)."""
119
+ note_ids = tuple(note_store.list_note_ids())
120
+ hidden = cloud_privacy_evaluator.hidden_note_ids(note_ids=note_ids, boundary=boundary)
121
+ counts: Counter[tuple[str, str]] = Counter()
122
+ examples: dict[tuple[str, str], str] = {}
123
+ for note_id in note_ids:
124
+ tags = note_store.get_note(note_id).tags
125
+ if note_id in hidden or PROPERTY_SEPARATOR not in tags:
126
+ continue
127
+ for token in extract_ordered_tags_for_agent(tags):
128
+ if not has_property_syntax(token):
129
+ continue
130
+ tag = tag_part_of_token(token).split("=", 1)[0]
131
+ for segment in split_property_segments(token[len(tag_part_of_token(token)) + 1:]):
132
+ name, has_value, value = segment.partition("=")
133
+ if not has_value or value == "":
134
+ continue
135
+ key = (tag.casefold(), name.casefold())
136
+ counts[key] += 1
137
+ if key not in examples:
138
+ examples[key] = f"{tag}{PROPERTY_SEPARATOR}{name}={value}"
139
+ return tuple(examples[key] for key, _count in counts.most_common(_MAX_SUPER_TAG_EXAMPLES))
140
+
141
+
109
142
  # What the AI is shown in place of a search term it may not see.
110
143
  PRIVATE_SEARCH_TERM = "[private]"
111
144
 
@@ -135,6 +168,7 @@ def _disclosable_clause_terms(
135
168
  """The clause's terms as the AI may be shown them, and whether any was withheld."""
136
169
  required_terms = [format_search_term(tag, is_phrase=False, is_excluded=False) for tag in sorted(clause.required_tags)]
137
170
  required_terms += [format_search_term(phrase, is_phrase=True, is_excluded=False) for phrase in clause.required_text]
171
+ required_terms += [condition.format() for condition in clause.required_properties]
138
172
  shown: list[str] = []
139
173
  withheld = False
140
174
  # Every required term picks out the same notes: the ones the clause finds.
@@ -148,7 +182,9 @@ def _disclosable_clause_terms(
148
182
  for tag in sorted(clause.forbidden_tags):
149
183
  removed = SearchClause(required_tags=clause.required_tags | {tag},
150
184
  forbidden_tags=clause.forbidden_tags - {tag},
151
- required_text=clause.required_text, forbidden_text=clause.forbidden_text)
185
+ required_text=clause.required_text, forbidden_text=clause.forbidden_text,
186
+ required_properties=clause.required_properties,
187
+ forbidden_properties=clause.forbidden_properties)
152
188
  if finds_visible_note(_clause_search(removed)):
153
189
  shown.append(format_search_term(tag, is_phrase=False, is_excluded=True))
154
190
  else:
@@ -156,11 +192,23 @@ def _disclosable_clause_terms(
156
192
  for index, phrase in enumerate(clause.forbidden_text):
157
193
  removed = SearchClause(required_tags=clause.required_tags, forbidden_tags=clause.forbidden_tags,
158
194
  required_text=clause.required_text + (phrase,),
159
- forbidden_text=clause.forbidden_text[:index] + clause.forbidden_text[index + 1:])
195
+ forbidden_text=clause.forbidden_text[:index] + clause.forbidden_text[index + 1:],
196
+ required_properties=clause.required_properties,
197
+ forbidden_properties=clause.forbidden_properties)
160
198
  if finds_visible_note(_clause_search(removed)):
161
199
  shown.append(format_search_term(phrase, is_phrase=True, is_excluded=True))
162
200
  else:
163
201
  excluded_withheld = True
202
+ for index, condition in enumerate(clause.forbidden_properties):
203
+ removed = SearchClause(required_tags=clause.required_tags, forbidden_tags=clause.forbidden_tags,
204
+ required_text=clause.required_text, forbidden_text=clause.forbidden_text,
205
+ required_properties=clause.required_properties + (condition,),
206
+ forbidden_properties=clause.forbidden_properties[:index]
207
+ + clause.forbidden_properties[index + 1:])
208
+ if finds_visible_note(_clause_search(removed)):
209
+ shown.append(f"-{condition.format()}")
210
+ else:
211
+ excluded_withheld = True
164
212
  if excluded_withheld:
165
213
  shown.append(f"-{PRIVATE_SEARCH_TERM}")
166
214
  return shown, withheld or excluded_withheld
@@ -26,7 +26,7 @@ from dataclasses import dataclass
26
26
 
27
27
  from app.services.agent.cloud_privacy import CloudPrivacyBoundary
28
28
  from app.services.agent.cloud_privacy import cloud_privacy_evaluator
29
- from app.services.agent.cloud_privacy import visible_tag_counts
29
+ from app.services.agent.cloud_privacy import visible_super_tag_examples, visible_tag_counts
30
30
  from app.services.agent.inference import InferenceAdapter
31
31
  from app.services.agent.skill_settings import AgentSkill
32
32
  from app.services.agent.tagging import TagBatch
@@ -37,7 +37,8 @@ from app.services.agent.token_estimation import estimate_input_tokens
37
37
  from app.services.agent.web_settings import AgentWebSettings
38
38
  from app.services.content_formatting import extract_note_text_for_agent
39
39
  from app.services.note_store import store as note_store
40
- from app.services.search_index import extract_ordered_tags_for_search
40
+ from app.services.search_index import extract_ordered_tags_for_agent, extract_ordered_tags_for_search
41
+ from app.services.tag_properties import tag_part_of_token
41
42
  from app.services.search_index import search_index
42
43
  from app.services.tag_suggestions import suggest_tags_for_note
43
44
  from app.contracts import preserves, produces, requires
@@ -88,6 +89,8 @@ class NoteTagRequest:
88
89
  tag_skill: AgentSkill
89
90
  # The tags on notes the AI may see (cloud_privacy.visible_tag_counts).
90
91
  visible_vocabulary: dict[str, str]
92
+ # One example of each property in use there (cloud_privacy.visible_super_tag_examples).
93
+ super_tag_examples: tuple[str, ...]
91
94
 
92
95
 
93
96
  @dataclass(frozen=True, slots=True)
@@ -123,7 +126,7 @@ def _note_text(note_id: str) -> dict[str, object]:
123
126
  record = note_store.get_note(note_id)
124
127
  content, redacted = extract_note_text_for_agent(content_html=record.content, tags=record.tags)
125
128
  assert not redacted, "A note the AI may see is never password protected"
126
- return {"content_text": content, "tags": list(extract_ordered_tags_for_search(record.tags))}
129
+ return {"content_text": content, "tags": list(extract_ordered_tags_for_agent(record.tags))}
127
130
 
128
131
 
129
132
  def _note_node(note_id: str) -> dict[str, object]:
@@ -212,6 +215,7 @@ def build_note_tag_request(
212
215
  ancestors_by_batch=tuple(context for _trees, context in groups),
213
216
  vocabulary=vocabulary, rules=rules, tag_skill=tag_skill,
214
217
  visible_vocabulary=visible_tag_counts(boundary)[0],
218
+ super_tag_examples=visible_super_tag_examples(boundary),
215
219
  ), "cloud_disclosable")
216
220
 
217
221
 
@@ -226,6 +230,7 @@ def request_messages(request: NoteTagRequest, index: int, prior_batch_new_tags:
226
230
  "accepted_vocabulary": [tag for tag, _count in request.vocabulary],
227
231
  "accepted_vocabulary_note_counts": [count for _tag, count in request.vocabulary],
228
232
  "prior_batch_new_tags": list(prior_batch_new_tags),
233
+ "super_tag_properties": list(request.super_tag_examples),
229
234
  }
230
235
  messages = tag_batch_messages(
231
236
  tag_skill=request.tag_skill, vocabulary_scope=_VOCABULARY_SCOPE, focus="both", user_payload=user_payload,
@@ -240,7 +245,8 @@ def keep_new_tags_up_to_limit(*, tags: tuple[str, ...], visible_vocabulary: dict
240
245
  kept = []
241
246
  new_count = 0
242
247
  for tag in tags:
243
- if tag.casefold() not in visible_vocabulary:
248
+ # A super tag is new when its tag is (jogging:miles=3 on an existing jogging is not).
249
+ if tag_part_of_token(tag).casefold() not in visible_vocabulary:
244
250
  if new_count == MAX_NEW_TAGS:
245
251
  continue
246
252
  new_count += 1