MetaList 0.24.0__tar.gz → 0.24.2__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 (620) hide show
  1. {metalist-0.24.0 → metalist-0.24.2}/PKG-INFO +16 -3
  2. metalist-0.24.0/metalist.egg-info/PKG-INFO → metalist-0.24.2/README.md +13 -41
  3. {metalist-0.24.0 → metalist-0.24.2}/app/api/note_requests.py +8 -0
  4. {metalist-0.24.0 → metalist-0.24.2}/app/api/routes/ai.py +8 -0
  5. {metalist-0.24.0 → metalist-0.24.2}/app/api/routes/notes.py +27 -0
  6. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/scope.py +8 -1
  7. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/skills/help-formatting.md +8 -2
  8. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/skills/help-menus.md +6 -0
  9. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/skills/help-notes.md +1 -1
  10. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/skills/help-references.md +2 -2
  11. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/skills/help-releases.md +13 -0
  12. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/skills/help-search.md +3 -0
  13. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/tagging_run.py +5 -3
  14. {metalist-0.24.0 → metalist-0.24.2}/app/services/backlink_index.py +13 -1
  15. {metalist-0.24.0 → metalist-0.24.2}/app/services/embedded_references.py +16 -6
  16. metalist-0.24.2/app/services/file_kinds.py +46 -0
  17. {metalist-0.24.0 → metalist-0.24.2}/app/services/file_registry.py +61 -14
  18. {metalist-0.24.0 → metalist-0.24.2}/app/services/file_storage.py +19 -7
  19. {metalist-0.24.0 → metalist-0.24.2}/app/services/html_export.py +6 -6
  20. {metalist-0.24.0 → metalist-0.24.2}/app/services/note_store.py +13 -0
  21. {metalist-0.24.0 → metalist-0.24.2}/app/services/snapshot.py +78 -6
  22. {metalist-0.24.0 → metalist-0.24.2}/app/services/tab_state.py +62 -8
  23. {metalist-0.24.0 → metalist-0.24.2}/app/static/config/agent-menu-actions.json +30 -0
  24. {metalist-0.24.0 → metalist-0.24.2}/app/static/config/command_palette_tags.json +20 -0
  25. {metalist-0.24.0 → metalist-0.24.2}/app/static/css/main.css +8 -7
  26. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/command-palette/command-palette-controller.js +37 -1
  27. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/command-palette/endpoint-registry.js +16 -0
  28. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/config.js +1 -0
  29. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/context-menu/context-menu-registry.js +28 -0
  30. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/context-menu/context-menu-service.js +2 -0
  31. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/actions/ui-actions.js +2 -0
  32. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/events/context-menu-events.js +11 -2
  33. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/events/keyboard-events.js +93 -11
  34. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/events/mouse-events.js +13 -0
  35. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/clipboard-shortcut-policy-service.js +22 -1
  36. metalist-0.24.2/app/static/js/modules/mode-manager/services/file-filter-kinds.js +17 -0
  37. metalist-0.24.2/app/static/js/modules/mode-manager/services/file-filter-service.js +87 -0
  38. metalist-0.24.2/app/static/js/modules/mode-manager/services/formatted-paste-format-service.js +103 -0
  39. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/paste-format-guess-service.js +23 -11
  40. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/paste-format-offer-service.js +1 -1
  41. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/tab-state-service.js +22 -1
  42. {metalist-0.24.0 → metalist-0.24.2}/app/templates/index.html +10 -0
  43. {metalist-0.24.0 → metalist-0.24.2}/app/version.py +1 -1
  44. metalist-0.24.0/README.md → metalist-0.24.2/metalist.egg-info/PKG-INFO +54 -0
  45. {metalist-0.24.0 → metalist-0.24.2}/metalist.egg-info/SOURCES.txt +4 -0
  46. {metalist-0.24.0 → metalist-0.24.2}/metalist.egg-info/requires.txt +2 -2
  47. {metalist-0.24.0 → metalist-0.24.2}/pyproject.toml +4 -4
  48. {metalist-0.24.0 → metalist-0.24.2}/MANIFEST.in +0 -0
  49. {metalist-0.24.0 → metalist-0.24.2}/app/__init__.py +0 -0
  50. {metalist-0.24.0 → metalist-0.24.2}/app/api/__init__.py +0 -0
  51. {metalist-0.24.0 → metalist-0.24.2}/app/api/deps.py +0 -0
  52. {metalist-0.24.0 → metalist-0.24.2}/app/api/dev.py +0 -0
  53. {metalist-0.24.0 → metalist-0.24.2}/app/api/middleware/auth.py +0 -0
  54. {metalist-0.24.0 → metalist-0.24.2}/app/api/request_auth.py +0 -0
  55. {metalist-0.24.0 → metalist-0.24.2}/app/api/routes/app_updates.py +0 -0
  56. {metalist-0.24.0 → metalist-0.24.2}/app/api/routes/auth.py +0 -0
  57. {metalist-0.24.0 → metalist-0.24.2}/app/api/routes/backups.py +0 -0
  58. {metalist-0.24.0 → metalist-0.24.2}/app/api/routes/files.py +0 -0
  59. {metalist-0.24.0 → metalist-0.24.2}/app/api/routes/ontology.py +0 -0
  60. {metalist-0.24.0 → metalist-0.24.2}/app/api/routes/reminders.py +0 -0
  61. {metalist-0.24.0 → metalist-0.24.2}/app/api/routes/remote_images.py +0 -0
  62. {metalist-0.24.0 → metalist-0.24.2}/app/api/routes/test.py +0 -0
  63. {metalist-0.24.0 → metalist-0.24.2}/app/api/transactions.py +0 -0
  64. {metalist-0.24.0 → metalist-0.24.2}/app/api/upload_limits.py +0 -0
  65. {metalist-0.24.0 → metalist-0.24.2}/app/config.py +0 -0
  66. {metalist-0.24.0 → metalist-0.24.2}/app/contracts.py +0 -0
  67. {metalist-0.24.0 → metalist-0.24.2}/app/data_directory.py +0 -0
  68. {metalist-0.24.0 → metalist-0.24.2}/app/db/__init__.py +0 -0
  69. {metalist-0.24.0 → metalist-0.24.2}/app/db/backup_settings_sql.py +0 -0
  70. {metalist-0.24.0 → metalist-0.24.2}/app/db/content_migrations_sql.py +0 -0
  71. {metalist-0.24.0 → metalist-0.24.2}/app/db/editable_files_migration.py +0 -0
  72. {metalist-0.24.0 → metalist-0.24.2}/app/db/engine.py +0 -0
  73. {metalist-0.24.0 → metalist-0.24.2}/app/db/file_schema.py +0 -0
  74. {metalist-0.24.0 → metalist-0.24.2}/app/db/file_session.py +0 -0
  75. {metalist-0.24.0 → metalist-0.24.2}/app/db/files_sql.py +0 -0
  76. {metalist-0.24.0 → metalist-0.24.2}/app/db/link_titles_sql.py +0 -0
  77. {metalist-0.24.0 → metalist-0.24.2}/app/db/live_recovery.py +0 -0
  78. {metalist-0.24.0 → metalist-0.24.2}/app/db/migrations.py +0 -0
  79. {metalist-0.24.0 → metalist-0.24.2}/app/db/notes_sql.py +0 -0
  80. {metalist-0.24.0 → metalist-0.24.2}/app/db/ontology_rules_sql.py +0 -0
  81. {metalist-0.24.0 → metalist-0.24.2}/app/db/raw_connection.py +0 -0
  82. {metalist-0.24.0 → metalist-0.24.2}/app/db/reminders_sql.py +0 -0
  83. {metalist-0.24.0 → metalist-0.24.2}/app/db/retire_sounds.py +0 -0
  84. {metalist-0.24.0 → metalist-0.24.2}/app/db/schema.py +0 -0
  85. {metalist-0.24.0 → metalist-0.24.2}/app/db/search_history_sql.py +0 -0
  86. {metalist-0.24.0 → metalist-0.24.2}/app/db/session.py +0 -0
  87. {metalist-0.24.0 → metalist-0.24.2}/app/db/settings_sql.py +0 -0
  88. {metalist-0.24.0 → metalist-0.24.2}/app/db/tab_state_sql.py +0 -0
  89. {metalist-0.24.0 → metalist-0.24.2}/app/db/version.py +0 -0
  90. {metalist-0.24.0 → metalist-0.24.2}/app/encryption_audit.py +0 -0
  91. {metalist-0.24.0 → metalist-0.24.2}/app/exception_boundaries.py +0 -0
  92. {metalist-0.24.0 → metalist-0.24.2}/app/https_proxy.py +0 -0
  93. {metalist-0.24.0 → metalist-0.24.2}/app/launch_clock.py +0 -0
  94. {metalist-0.24.0 → metalist-0.24.2}/app/main.py +0 -0
  95. {metalist-0.24.0 → metalist-0.24.2}/app/models/database.py +0 -0
  96. {metalist-0.24.0 → metalist-0.24.2}/app/models/utils.py +0 -0
  97. {metalist-0.24.0 → metalist-0.24.2}/app/network_settings.py +0 -0
  98. {metalist-0.24.0 → metalist-0.24.2}/app/presentation/__init__.py +0 -0
  99. {metalist-0.24.0 → metalist-0.24.2}/app/presentation/login_page.py +0 -0
  100. {metalist-0.24.0 → metalist-0.24.2}/app/presentation/render/__init__.py +0 -0
  101. {metalist-0.24.0 → metalist-0.24.2}/app/presentation/render/note_renderer.py +0 -0
  102. {metalist-0.24.0 → metalist-0.24.2}/app/presentation/templates.py +0 -0
  103. {metalist-0.24.0 → metalist-0.24.2}/app/process_memory.py +0 -0
  104. {metalist-0.24.0 → metalist-0.24.2}/app/security/authenticated_logging.py +0 -0
  105. {metalist-0.24.0 → metalist-0.24.2}/app/security/crypto_sizes.py +0 -0
  106. {metalist-0.24.0 → metalist-0.24.2}/app/security/encryption.py +0 -0
  107. {metalist-0.24.0 → metalist-0.24.2}/app/security/http_error_diagnostics.py +0 -0
  108. {metalist-0.24.0 → metalist-0.24.2}/app/security/http_headers.py +0 -0
  109. {metalist-0.24.0 → metalist-0.24.2}/app/security/note_html.py +0 -0
  110. {metalist-0.24.0 → metalist-0.24.2}/app/security/rendered_html.py +0 -0
  111. {metalist-0.24.0 → metalist-0.24.2}/app/security/request_boundary.py +0 -0
  112. {metalist-0.24.0 → metalist-0.24.2}/app/security/request_hosts.py +0 -0
  113. {metalist-0.24.0 → metalist-0.24.2}/app/security/sensitive_cache.py +0 -0
  114. {metalist-0.24.0 → metalist-0.24.2}/app/security/sensitive_logging.py +0 -0
  115. {metalist-0.24.0 → metalist-0.24.2}/app/security/shell_execution.py +0 -0
  116. {metalist-0.24.0 → metalist-0.24.2}/app/security/validation_errors.py +0 -0
  117. {metalist-0.24.0 → metalist-0.24.2}/app/server_runtime.py +0 -0
  118. {metalist-0.24.0 → metalist-0.24.2}/app/services/__init__.py +0 -0
  119. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/__init__.py +0 -0
  120. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/action_log.py +0 -0
  121. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/agent_loop.py +0 -0
  122. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/agent_tools.py +0 -0
  123. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/ai_send.py +0 -0
  124. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/citation_tokens.py +0 -0
  125. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/cloud_privacy.py +0 -0
  126. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/context.py +0 -0
  127. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/evidence_serialization.py +0 -0
  128. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/execution_errors.py +0 -0
  129. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/export_title_suggestions.py +0 -0
  130. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/failure_explanations.py +0 -0
  131. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/help_catalog.py +0 -0
  132. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/history.py +0 -0
  133. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/inference.py +0 -0
  134. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/investigation.py +0 -0
  135. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/judging.py +0 -0
  136. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/menu_actions.py +0 -0
  137. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/model_policy.py +0 -0
  138. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/note_aliases.py +0 -0
  139. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/note_tag_suggestions.py +0 -0
  140. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/openai_cost_tracking.py +0 -0
  141. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/openai_inference.py +0 -0
  142. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/openai_models.py +0 -0
  143. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/privacy_guard.py +0 -0
  144. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/prompt_settings.py +0 -0
  145. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/prompts/__init__.py +0 -0
  146. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/prompts/agent.md +0 -0
  147. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/prompts/final-response.md +0 -0
  148. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/prompts/system.md +0 -0
  149. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/release_notes.py +0 -0
  150. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/retrieval_settings.py +0 -0
  151. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/runtime.py +0 -0
  152. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/skill_settings.py +0 -0
  153. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/skills/__init__.py +0 -0
  154. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/skills/help-ai.md +0 -0
  155. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/skills/help-data.md +0 -0
  156. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/skills/help-dictation.md +0 -0
  157. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/skills/help-mouse.md +0 -0
  158. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/skills/help-ontology.md +0 -0
  159. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/skills/help-privacy.md +0 -0
  160. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/skills/help-reminders.md +0 -0
  161. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/skills/help-tags.md +0 -0
  162. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/skills/staged-summary.md +0 -0
  163. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/skills/tag-proposals.md +0 -0
  164. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/skills/web-browsing.md +0 -0
  165. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/staged_summary.py +0 -0
  166. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/strict_structured_outputs.py +0 -0
  167. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/structured_inference.py +0 -0
  168. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/summary_batch_store.py +0 -0
  169. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/tagging.py +0 -0
  170. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/token_estimation.py +0 -0
  171. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/tool_calling.py +0 -0
  172. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/trace.py +0 -0
  173. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/web_actions.py +0 -0
  174. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/web_capabilities.py +0 -0
  175. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/web_evidence.py +0 -0
  176. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/web_fetch.py +0 -0
  177. {metalist-0.24.0 → metalist-0.24.2}/app/services/agent/web_settings.py +0 -0
  178. {metalist-0.24.0 → metalist-0.24.2}/app/services/ai_chat.py +0 -0
  179. {metalist-0.24.0 → metalist-0.24.2}/app/services/ai_chat_rendering.py +0 -0
  180. {metalist-0.24.0 → metalist-0.24.2}/app/services/ai_chat_stream.py +0 -0
  181. {metalist-0.24.0 → metalist-0.24.2}/app/services/ai_setup.py +0 -0
  182. {metalist-0.24.0 → metalist-0.24.2}/app/services/app_update_worker.py +0 -0
  183. {metalist-0.24.0 → metalist-0.24.2}/app/services/app_updates.py +0 -0
  184. {metalist-0.24.0 → metalist-0.24.2}/app/services/auth.py +0 -0
  185. {metalist-0.24.0 → metalist-0.24.2}/app/services/auth_cache_state.py +0 -0
  186. {metalist-0.24.0 → metalist-0.24.2}/app/services/auth_service.py +0 -0
  187. {metalist-0.24.0 → metalist-0.24.2}/app/services/backlinks.py +0 -0
  188. {metalist-0.24.0 → metalist-0.24.2}/app/services/backup_service.py +0 -0
  189. {metalist-0.24.0 → metalist-0.24.2}/app/services/backup_settings_service.py +0 -0
  190. {metalist-0.24.0 → metalist-0.24.2}/app/services/bulk_operation.py +0 -0
  191. {metalist-0.24.0 → metalist-0.24.2}/app/services/chess_rendering.py +0 -0
  192. {metalist-0.24.0 → metalist-0.24.2}/app/services/client_state_service.py +0 -0
  193. {metalist-0.24.0 → metalist-0.24.2}/app/services/code_rendering.py +0 -0
  194. {metalist-0.24.0 → metalist-0.24.2}/app/services/content_cache.py +0 -0
  195. {metalist-0.24.0 → metalist-0.24.2}/app/services/content_formatting.py +0 -0
  196. {metalist-0.24.0 → metalist-0.24.2}/app/services/diagnostics.py +0 -0
  197. {metalist-0.24.0 → metalist-0.24.2}/app/services/dictation_cleanup.py +0 -0
  198. {metalist-0.24.0 → metalist-0.24.2}/app/services/diff_rendering.py +0 -0
  199. {metalist-0.24.0 → metalist-0.24.2}/app/services/editing_image_sizes.py +0 -0
  200. {metalist-0.24.0 → metalist-0.24.2}/app/services/encryption.py +0 -0
  201. {metalist-0.24.0 → metalist-0.24.2}/app/services/exception_capture.py +0 -0
  202. {metalist-0.24.0 → metalist-0.24.2}/app/services/file_edit_sessions.py +0 -0
  203. {metalist-0.24.0 → metalist-0.24.2}/app/services/file_text_preview.py +0 -0
  204. {metalist-0.24.0 → metalist-0.24.2}/app/services/find_text.py +0 -0
  205. {metalist-0.24.0 → metalist-0.24.2}/app/services/footnote_layout.py +0 -0
  206. {metalist-0.24.0 → metalist-0.24.2}/app/services/footnote_rendering.py +0 -0
  207. {metalist-0.24.0 → metalist-0.24.2}/app/services/hierarchy.py +0 -0
  208. {metalist-0.24.0 → metalist-0.24.2}/app/services/html_unformatting.py +0 -0
  209. {metalist-0.24.0 → metalist-0.24.2}/app/services/hydration_state.py +0 -0
  210. {metalist-0.24.0 → metalist-0.24.2}/app/services/image_size_formatting.py +0 -0
  211. {metalist-0.24.0 → metalist-0.24.2}/app/services/inline_image_dimensions.py +0 -0
  212. {metalist-0.24.0 → metalist-0.24.2}/app/services/inline_image_occurrences.py +0 -0
  213. {metalist-0.24.0 → metalist-0.24.2}/app/services/input_errors.py +0 -0
  214. {metalist-0.24.0 → metalist-0.24.2}/app/services/integrity.py +0 -0
  215. {metalist-0.24.0 → metalist-0.24.2}/app/services/latex_rendering.py +0 -0
  216. {metalist-0.24.0 → metalist-0.24.2}/app/services/link_title_retry.py +0 -0
  217. {metalist-0.24.0 → metalist-0.24.2}/app/services/link_titles.py +0 -0
  218. {metalist-0.24.0 → metalist-0.24.2}/app/services/login_rate_limit.py +0 -0
  219. {metalist-0.24.0 → metalist-0.24.2}/app/services/maintenance_mode.py +0 -0
  220. {metalist-0.24.0 → metalist-0.24.2}/app/services/markdown_rendering.py +0 -0
  221. {metalist-0.24.0 → metalist-0.24.2}/app/services/memory_breakdown.py +0 -0
  222. {metalist-0.24.0 → metalist-0.24.2}/app/services/memory_usage.py +0 -0
  223. {metalist-0.24.0 → metalist-0.24.2}/app/services/mermaid_note_rendering.py +0 -0
  224. {metalist-0.24.0 → metalist-0.24.2}/app/services/namespace_deletion_jobs.py +0 -0
  225. {metalist-0.24.0 → metalist-0.24.2}/app/services/namespace_deletion_worker.py +0 -0
  226. {metalist-0.24.0 → metalist-0.24.2}/app/services/namespace_rename_jobs.py +0 -0
  227. {metalist-0.24.0 → metalist-0.24.2}/app/services/namespace_rename_worker.py +0 -0
  228. {metalist-0.24.0 → metalist-0.24.2}/app/services/namespace_runtime_guard.py +0 -0
  229. {metalist-0.24.0 → metalist-0.24.2}/app/services/namespace_switcher.py +0 -0
  230. {metalist-0.24.0 → metalist-0.24.2}/app/services/note_fullscreen.py +0 -0
  231. {metalist-0.24.0 → metalist-0.24.2}/app/services/note_image_tags.py +0 -0
  232. {metalist-0.24.0 → metalist-0.24.2}/app/services/note_ordering.py +0 -0
  233. {metalist-0.24.0 → metalist-0.24.2}/app/services/ontology_rules_store.py +0 -0
  234. {metalist-0.24.0 → metalist-0.24.2}/app/services/openai_credentials.py +0 -0
  235. {metalist-0.24.0 → metalist-0.24.2}/app/services/password_note_fields.py +0 -0
  236. {metalist-0.24.0 → metalist-0.24.2}/app/services/preference_values.py +0 -0
  237. {metalist-0.24.0 → metalist-0.24.2}/app/services/public_http.py +0 -0
  238. {metalist-0.24.0 → metalist-0.24.2}/app/services/reference_presentation.py +0 -0
  239. {metalist-0.24.0 → metalist-0.24.2}/app/services/reminders.py +0 -0
  240. {metalist-0.24.0 → metalist-0.24.2}/app/services/remote_image_proxy.py +0 -0
  241. {metalist-0.24.0 → metalist-0.24.2}/app/services/request_recovery.py +0 -0
  242. {metalist-0.24.0 → metalist-0.24.2}/app/services/reset_for_tests.py +0 -0
  243. {metalist-0.24.0 → metalist-0.24.2}/app/services/resource_limits.py +0 -0
  244. {metalist-0.24.0 → metalist-0.24.2}/app/services/root_date_filter.py +0 -0
  245. {metalist-0.24.0 → metalist-0.24.2}/app/services/root_sorting.py +0 -0
  246. {metalist-0.24.0 → metalist-0.24.2}/app/services/runtime_generation.py +0 -0
  247. {metalist-0.24.0 → metalist-0.24.2}/app/services/runtime_hardening.py +0 -0
  248. {metalist-0.24.0 → metalist-0.24.2}/app/services/runtime_lock.py +0 -0
  249. {metalist-0.24.0 → metalist-0.24.2}/app/services/search_history.py +0 -0
  250. {metalist-0.24.0 → metalist-0.24.2}/app/services/search_history_storage.py +0 -0
  251. {metalist-0.24.0 → metalist-0.24.2}/app/services/search_index.py +0 -0
  252. {metalist-0.24.0 → metalist-0.24.2}/app/services/search_query.py +0 -0
  253. {metalist-0.24.0 → metalist-0.24.2}/app/services/search_text.py +0 -0
  254. {metalist-0.24.0 → metalist-0.24.2}/app/services/selected_text_tag.py +0 -0
  255. {metalist-0.24.0 → metalist-0.24.2}/app/services/self_update.py +0 -0
  256. {metalist-0.24.0 → metalist-0.24.2}/app/services/session_timeout_service.py +0 -0
  257. {metalist-0.24.0 → metalist-0.24.2}/app/services/shared_sets.py +0 -0
  258. {metalist-0.24.0 → metalist-0.24.2}/app/services/shell_session_service.py +0 -0
  259. {metalist-0.24.0 → metalist-0.24.2}/app/services/store.py +0 -0
  260. {metalist-0.24.0 → metalist-0.24.2}/app/services/structured_note_renderers.py +0 -0
  261. {metalist-0.24.0 → metalist-0.24.2}/app/services/sync.py +0 -0
  262. {metalist-0.24.0 → metalist-0.24.2}/app/services/tag_case.py +0 -0
  263. {metalist-0.24.0 → metalist-0.24.2}/app/services/tag_details.py +0 -0
  264. {metalist-0.24.0 → metalist-0.24.2}/app/services/tag_ontology.py +0 -0
  265. {metalist-0.24.0 → metalist-0.24.2}/app/services/tag_plural_variants.py +0 -0
  266. {metalist-0.24.0 → metalist-0.24.2}/app/services/tag_properties.py +0 -0
  267. {metalist-0.24.0 → metalist-0.24.2}/app/services/tag_rename.py +0 -0
  268. {metalist-0.24.0 → metalist-0.24.2}/app/services/tag_suggestion_reasons.py +0 -0
  269. {metalist-0.24.0 → metalist-0.24.2}/app/services/tag_suggestions.py +0 -0
  270. {metalist-0.24.0 → metalist-0.24.2}/app/services/tag_term_matching.py +0 -0
  271. {metalist-0.24.0 → metalist-0.24.2}/app/services/tokens.py +0 -0
  272. {metalist-0.24.0 → metalist-0.24.2}/app/services/undo_state.py +0 -0
  273. {metalist-0.24.0 → metalist-0.24.2}/app/services/update_backups.py +0 -0
  274. {metalist-0.24.0 → metalist-0.24.2}/app/services/update_installer.py +0 -0
  275. {metalist-0.24.0 → metalist-0.24.2}/app/services/update_preflight.py +0 -0
  276. {metalist-0.24.0 → metalist-0.24.2}/app/services/view_cache.py +0 -0
  277. {metalist-0.24.0 → metalist-0.24.2}/app/services/view_diff.py +0 -0
  278. {metalist-0.24.0 → metalist-0.24.2}/app/services/view_state.py +0 -0
  279. {metalist-0.24.0 → metalist-0.24.2}/app/services/windows_process_control.py +0 -0
  280. {metalist-0.24.0 → metalist-0.24.2}/app/startup_console.py +0 -0
  281. {metalist-0.24.0 → metalist-0.24.2}/app/startup_environment.py +0 -0
  282. {metalist-0.24.0 → metalist-0.24.2}/app/startup_js_sanity.py +0 -0
  283. {metalist-0.24.0 → metalist-0.24.2}/app/startup_sanity.py +0 -0
  284. {metalist-0.24.0 → metalist-0.24.2}/app/startup_sanity_config.py +0 -0
  285. {metalist-0.24.0 → metalist-0.24.2}/app/startup_shockharness.py +0 -0
  286. {metalist-0.24.0 → metalist-0.24.2}/app/static/css/floating-notes.css +0 -0
  287. {metalist-0.24.0 → metalist-0.24.2}/app/static/css/forms.css +0 -0
  288. {metalist-0.24.0 → metalist-0.24.2}/app/static/img/favicon.ico +0 -0
  289. {metalist-0.24.0 → metalist-0.24.2}/app/static/img/metalist-logo-black-1024.png +0 -0
  290. {metalist-0.24.0 → metalist-0.24.2}/app/static/img/metalist-logo-black-512.png +0 -0
  291. {metalist-0.24.0 → metalist-0.24.2}/app/static/img/metalist-logo-black.svg +0 -0
  292. {metalist-0.24.0 → metalist-0.24.2}/app/static/img/metalist-logo-white-1024.png +0 -0
  293. {metalist-0.24.0 → metalist-0.24.2}/app/static/img/metalist-logo-white-512.png +0 -0
  294. {metalist-0.24.0 → metalist-0.24.2}/app/static/img/metalist-logo-white.svg +0 -0
  295. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/locked.js +0 -0
  296. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/main.js +0 -0
  297. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/activity-tracker.js +0 -0
  298. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/ai-chat/agent-menu-actions.js +0 -0
  299. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/ai-chat/agent-retrieval-settings.js +0 -0
  300. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/ai-chat/agent-web-settings.js +0 -0
  301. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/ai-chat/ai-agent-debug-view.js +0 -0
  302. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/ai-chat/ai-chat-api.js +0 -0
  303. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/ai-chat/ai-chat-message-placement.js +0 -0
  304. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/ai-chat/ai-chat-panel-controller.js +0 -0
  305. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/ai-chat/ai-chat-panel-service.js +0 -0
  306. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/ai-chat/ai-chat-refused-turns.js +0 -0
  307. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/ai-chat/ai-chat-size-limits.js +0 -0
  308. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/ai-chat/ai-thinking-level-service.js +0 -0
  309. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/ai-chat/bulk-elapsed-clock.js +0 -0
  310. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/ai-chat/bulk-proposal-ui.js +0 -0
  311. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/ai-chat/bulk-scope-question.js +0 -0
  312. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/ai-chat/cloud-privacy-policy.js +0 -0
  313. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/ai-chat/confirmation-card.js +0 -0
  314. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/ai-chat/confirmation-question.js +0 -0
  315. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/ai-chat/proposal-menu.js +0 -0
  316. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/ai-chat/summary-batch-preview.js +0 -0
  317. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/api-client.js +0 -0
  318. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/api-error-diagnostics.js +0 -0
  319. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/api-failure-classification-service.js +0 -0
  320. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/app-notice-stack.js +0 -0
  321. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/app-update-service.js +0 -0
  322. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/application-state.js +0 -0
  323. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/async-result.js +0 -0
  324. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/auth.js +0 -0
  325. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/backup-reminder-schedule.js +0 -0
  326. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/backup-reminder-service.js +0 -0
  327. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/byte-sizes.js +0 -0
  328. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/client-state-api.js +0 -0
  329. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/client-state-migration.js +0 -0
  330. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/command-palette/activation-auth-policy.js +0 -0
  331. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/command-palette/backup-command-availability.js +0 -0
  332. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/command-palette/click-activation-service.js +0 -0
  333. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/command-palette/note-layout-preferences.js +0 -0
  334. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/command-palette/preferences-store.js +0 -0
  335. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/command-palette/tag-config-loader.js +0 -0
  336. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/command-palette/usage-store.js +0 -0
  337. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/context-menu/context-menu-target-service.js +0 -0
  338. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/context-menu/input-caret-service.js +0 -0
  339. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/decimal-integer.js +0 -0
  340. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/disconnect-editing-state-service.js +0 -0
  341. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/dom-focus.js +0 -0
  342. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/dom-utils.js +0 -0
  343. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/editor-commands.js +0 -0
  344. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/editor-selection.js +0 -0
  345. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/editor-toolbar.js +0 -0
  346. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/elapsed-time.js +0 -0
  347. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/error-handler.js +0 -0
  348. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/error-overlay.js +0 -0
  349. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/excalidraw/excalidraw-actions.js +0 -0
  350. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/excalidraw/excalidraw-autosave.js +0 -0
  351. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/excalidraw/excalidraw-editor-service.js +0 -0
  352. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/excalidraw/excalidraw-editor-state.js +0 -0
  353. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/excalidraw/excalidraw-loader.js +0 -0
  354. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/excalidraw/excalidraw-preview-service.js +0 -0
  355. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/excalidraw/excalidraw-scene.js +0 -0
  356. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/expected-errors.js +0 -0
  357. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/half.js +0 -0
  358. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/html-escape.js +0 -0
  359. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/http-status.js +0 -0
  360. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/list-selection.js +0 -0
  361. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/local-date-text.js +0 -0
  362. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/location-flags.js +0 -0
  363. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/login-namespace-picker.js +0 -0
  364. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/maintenance.js +0 -0
  365. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/ai-agent-settings-modal.js +0 -0
  366. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/alphabetize-root-notes-modal.js +0 -0
  367. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/backup-restore-modal.js +0 -0
  368. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/backup-result-modal.js +0 -0
  369. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/backup-settings-modal.js +0 -0
  370. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/base-modal.js +0 -0
  371. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/confirmation-modal.js +0 -0
  372. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/date-range-modal.js +0 -0
  373. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/delete-namespace-modal.js +0 -0
  374. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/delete-namespace-validation.js +0 -0
  375. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/dictation-settings-modal.js +0 -0
  376. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/export-options-modal.js +0 -0
  377. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/help-modal.js +0 -0
  378. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/link-title-retry-modal.js +0 -0
  379. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/memory-usage-modal.js +0 -0
  380. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/namespace-loading-page.js +0 -0
  381. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/namespace-modals.js +0 -0
  382. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/namespace-ports-profile.js +0 -0
  383. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/namespace-rename-validation.js +0 -0
  384. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/note-layout-appearance-modal.js +0 -0
  385. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/ontology-modal.js +0 -0
  386. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/password-modal.js +0 -0
  387. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/prioritize-modal.js +0 -0
  388. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/random-password-modal.js +0 -0
  389. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/reminder-modal.js +0 -0
  390. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/reset-updated-at-modal.js +0 -0
  391. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/search-suggestion-statistics-modal.js +0 -0
  392. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/session-timeout-modal.js +0 -0
  393. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/version-info-modal.js +0 -0
  394. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/modals/visual-cues-modal.js +0 -0
  395. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/actions/content-actions.js +0 -0
  396. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/actions/history-actions.js +0 -0
  397. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/actions/note-actions.js +0 -0
  398. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/actions/search-actions.js +0 -0
  399. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/actions/selection-actions.js +0 -0
  400. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/events/focus-events.js +0 -0
  401. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/events/inactivity-events.js +0 -0
  402. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/events/input-events.js +0 -0
  403. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/events/search-events.js +0 -0
  404. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/mode-context.js +0 -0
  405. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/mode-logger.js +0 -0
  406. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/mode-manager-controller.js +0 -0
  407. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/add-style-service.js +0 -0
  408. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/animated-scroll-service.js +0 -0
  409. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/backlinks-navigation-service.js +0 -0
  410. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/collapse-affordance-service.js +0 -0
  411. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/collapse-editing-policy-service.js +0 -0
  412. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/command-gate-service.js +0 -0
  413. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/context-menu-target-service.js +0 -0
  414. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/date-range-filter-service.js +0 -0
  415. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/date-range-kinds.js +0 -0
  416. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/deselect-selection-state-service.js +0 -0
  417. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/dictation-note-paste.js +0 -0
  418. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/dictation-paste-padding.js +0 -0
  419. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/dictation-paste-service.js +0 -0
  420. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/differential-view-service.js +0 -0
  421. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/dropped-file-preview-service.js +0 -0
  422. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/edit-session-collapse-policy-service.js +0 -0
  423. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/edit-session-collapse-service.js +0 -0
  424. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/editing-image-size-service.js +0 -0
  425. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/embedded-image-service.js +0 -0
  426. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/export-service.js +0 -0
  427. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/export-title-service.js +0 -0
  428. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/file-drop-policy-service.js +0 -0
  429. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/file-image-preview-service.js +0 -0
  430. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/file-reference-service.js +0 -0
  431. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/filtered-refresh-selection-service.js +0 -0
  432. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/find-in-list-service.js +0 -0
  433. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/floating-note-dom.js +0 -0
  434. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/floating-note-layout.js +0 -0
  435. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/floating-note-service.js +0 -0
  436. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/footnote-navigation-service.js +0 -0
  437. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/history-selection-policy-service.js +0 -0
  438. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/history-shortcut-policy-service.js +0 -0
  439. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/html-paste-sanitizer-service.js +0 -0
  440. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/image-context-menu-action-service.js +0 -0
  441. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/image-file-insert-choice-modal-service.js +0 -0
  442. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/infinite-scroll-service.js +0 -0
  443. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/link-context-menu-action-service.js +0 -0
  444. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/link-target-service.js +0 -0
  445. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/link-title-prefetch-service.js +0 -0
  446. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/mermaid-render-service.js +0 -0
  447. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/note-click-target-service.js +0 -0
  448. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/note-clipboard-write-service.js +0 -0
  449. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/note-collapse-animation-service.js +0 -0
  450. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/note-context-menu-action-service.js +0 -0
  451. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/note-delete-shortcut-policy-service.js +0 -0
  452. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/note-drag-indicator-service.js +0 -0
  453. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/note-drag-service.js +0 -0
  454. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/note-fullscreen-service.js +0 -0
  455. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/note-reposition-animation-service.js +0 -0
  456. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/note-split-service.js +0 -0
  457. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/note-timestamp-hover-service.js +0 -0
  458. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/password-clipboard-service.js +0 -0
  459. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/paste-format-detection-service.js +0 -0
  460. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/paste-reference-here-service.js +0 -0
  461. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/polling-service.js +0 -0
  462. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/print-service.js +0 -0
  463. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/reference-source-navigation-service.js +0 -0
  464. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/reference-view-transition-service.js +0 -0
  465. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/referenced-note-removal-service.js +0 -0
  466. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/remote-image-proxy-service.js +0 -0
  467. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/remove-formatting-service.js +0 -0
  468. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/right-press-focus-service.js +0 -0
  469. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/root-date-separator-service.js +0 -0
  470. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/root-note-creation-service.js +0 -0
  471. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/root-sort-indicator-service.js +0 -0
  472. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/root-sort-service.js +0 -0
  473. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/scroll-anchor-service.js +0 -0
  474. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/scroll-restoration-service.js +0 -0
  475. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/scroll-to-top-service.js +0 -0
  476. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/search-contexts-overlay-service.js +0 -0
  477. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/search-debounce-service.js +0 -0
  478. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/search-highlight-matching.js +0 -0
  479. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/search-highlight-service.js +0 -0
  480. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/search-input-chip-service.js +0 -0
  481. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/search-input-service.js +0 -0
  482. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/search-interaction-service.js +0 -0
  483. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/search-redaction-reveal-service.js +0 -0
  484. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/search-suggestion-statistics-service.js +0 -0
  485. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/search-suggestion-window-labels-service.js +0 -0
  486. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/search-suggestion-windows-service.js +0 -0
  487. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/search-suggestions-service.js +0 -0
  488. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/search-syntax-service.js +0 -0
  489. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/selected-formatting-removal-service.js +0 -0
  490. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/selected-text-tag-service.js +0 -0
  491. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/shell-output-service.js +0 -0
  492. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/tab-dom-cache-service.js +0 -0
  493. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/tab-drag-service.js +0 -0
  494. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/tab-duplication-service.js +0 -0
  495. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/tag-bar-service.js +0 -0
  496. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/tag-input-selection-service.js +0 -0
  497. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/tag-proposal-service.js +0 -0
  498. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/tag-suggestions-service.js +0 -0
  499. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/tag-syntax-service.js +0 -0
  500. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/todo-toggle-editing-service.js +0 -0
  501. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/untagged-view-indicator-service.js +0 -0
  502. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/view-mode-search-shortcut-service.js +0 -0
  503. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/viewport-hold-service.js +0 -0
  504. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/mode-manager/services/viewport-reference.js +0 -0
  505. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/not-found.js +0 -0
  506. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/note-html-sanitizer.js +0 -0
  507. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/password-generator.js +0 -0
  508. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/password-operation-response.js +0 -0
  509. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/password-policy.js +0 -0
  510. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/password-strength.js +0 -0
  511. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/reminder-store.js +0 -0
  512. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/reminder-surface-service.js +0 -0
  513. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/server-rendered-html.js +0 -0
  514. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/session-auth.js +0 -0
  515. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/startup-timing.js +0 -0
  516. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/tag-token.js +0 -0
  517. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/tcp-ports.js +0 -0
  518. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/time-units.js +0 -0
  519. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/url-tracking-cleaner.js +0 -0
  520. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/modules/uuid.js +0 -0
  521. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/namespace-deleted.js +0 -0
  522. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/namespace-renamed.js +0 -0
  523. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/shockharness/contracts.d.ts +0 -0
  524. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/shockharness/contracts.js +0 -0
  525. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/dompurify-3.4.17.LICENSE.txt +0 -0
  526. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/dompurify-3.4.17.min.js +0 -0
  527. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/excalidraw.css +0 -0
  528. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-Bold.woff2 +0 -0
  529. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-Medium.woff2 +0 -0
  530. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-Regular.woff2 +0 -0
  531. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-SemiBold.woff2 +0 -0
  532. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Cascadia/CascadiaCode-Regular.woff2 +0 -0
  533. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-279a7b317d12eb88de06167bd672b4b4.woff2 +0 -0
  534. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-6e066e8de2ac57ea9283adb9c24d7f0c.woff2 +0 -0
  535. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-dc6a8806fa96795d7b3be5026f989a17.woff2 +0 -0
  536. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-fcb0fc02dcbee4c9846b3e2508668039.woff2 +0 -0
  537. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-349fac6ca4700ffec595a7150a0d1e1d.woff2 +0 -0
  538. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-3f2c5db56cc93c5a6873b1361d730c16.woff2 +0 -0
  539. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-41b173a47b57366892116a575a43e2b6.woff2 +0 -0
  540. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-623ccf21b21ef6b3a0d87738f77eb071.woff2 +0 -0
  541. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-a88b72a24fb54c9f94e3b5fdaa7481c9.woff2 +0 -0
  542. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-b9dcf9d2e50a1eaf42fc664b50a3fd0d.woff2 +0 -0
  543. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-be310b9bcd4f1a43f571c46df7809174.woff2 +0 -0
  544. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYE98RXi4EwSsbg.woff2 +0 -0
  545. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYEF8RXi4EwQ.woff2 +0 -0
  546. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTA3j6zbXWjgevT5.woff2 +0 -0
  547. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTQ3j6zbXWjgeg.woff2 +0 -0
  548. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTk3j6zbXWjgevT5.woff2 +0 -0
  549. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTo3j6zbXWjgevT5.woff2 +0 -0
  550. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTs3j6zbXWjgevT5.woff2 +0 -0
  551. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Virgil/Virgil-Regular.woff2 +0 -0
  552. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1.LICENSE.txt +0 -0
  553. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/excalidraw-0.18.1.min.js +0 -0
  554. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/mermaid-11.16.1.LICENSE.txt +0 -0
  555. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/mermaid-11.16.1.min.js +0 -0
  556. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/zxcvbn-4.4.2.LICENSE.txt +0 -0
  557. {metalist-0.24.0 → metalist-0.24.2}/app/static/js/vendor/zxcvbn-4.4.2.js +0 -0
  558. {metalist-0.24.0 → metalist-0.24.2}/app/static/note-html-policy.json +0 -0
  559. {metalist-0.24.0 → metalist-0.24.2}/app/templates/_logo_mark.html +0 -0
  560. {metalist-0.24.0 → metalist-0.24.2}/app/templates/base.html +0 -0
  561. {metalist-0.24.0 → metalist-0.24.2}/app/templates/locked.html +0 -0
  562. {metalist-0.24.0 → metalist-0.24.2}/app/templates/maintenance.html +0 -0
  563. {metalist-0.24.0 → metalist-0.24.2}/app/templates/namespace_deleted.html +0 -0
  564. {metalist-0.24.0 → metalist-0.24.2}/app/templates/namespace_renamed.html +0 -0
  565. {metalist-0.24.0 → metalist-0.24.2}/app/templates/notes_list.html +0 -0
  566. {metalist-0.24.0 → metalist-0.24.2}/app/upload_limits.py +0 -0
  567. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/__init__.py +0 -0
  568. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/add_selected_text_tag.py +0 -0
  569. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/alphabetize_root_notes.py +0 -0
  570. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/base.py +0 -0
  571. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/bulk_tag_proposals.py +0 -0
  572. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/collapse.py +0 -0
  573. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/copy_note.py +0 -0
  574. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/create_child.py +0 -0
  575. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/create_file_preview_child.py +0 -0
  576. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/create_note.py +0 -0
  577. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/create_sibling.py +0 -0
  578. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/delete_subtree.py +0 -0
  579. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/delete_tag.py +0 -0
  580. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/expand.py +0 -0
  581. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/file_edit_session.py +0 -0
  582. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/indent.py +0 -0
  583. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/move.py +0 -0
  584. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/move_to_top.py +0 -0
  585. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/outdent.py +0 -0
  586. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/paste_child.py +0 -0
  587. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/paste_reference.py +0 -0
  588. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/paste_sibling.py +0 -0
  589. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/prefetch_link_titles.py +0 -0
  590. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/prioritize.py +0 -0
  591. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/redo.py +0 -0
  592. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/rename_tag.py +0 -0
  593. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/reset_updated_at.py +0 -0
  594. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/resize_image.py +0 -0
  595. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/run_shell.py +0 -0
  596. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/search_comment_autofill.py +0 -0
  597. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/search_context_tags.py +0 -0
  598. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/set_collapse_bulk.py +0 -0
  599. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/set_collapse_in_context.py +0 -0
  600. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/split_note.py +0 -0
  601. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/tag_proposals.py +0 -0
  602. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/toggle_todo_done.py +0 -0
  603. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/undo.py +0 -0
  604. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/unformat_content.py +0 -0
  605. {metalist-0.24.0 → metalist-0.24.2}/app/usecases/update_content.py +0 -0
  606. {metalist-0.24.0 → metalist-0.24.2}/app/utils/__init__.py +0 -0
  607. {metalist-0.24.0 → metalist-0.24.2}/app/utils/byte_sizes.py +0 -0
  608. {metalist-0.24.0 → metalist-0.24.2}/app/utils/encryption.py +0 -0
  609. {metalist-0.24.0 → metalist-0.24.2}/app/utils/not_found.py +0 -0
  610. {metalist-0.24.0 → metalist-0.24.2}/app/utils/sent_fields.py +0 -0
  611. {metalist-0.24.0 → metalist-0.24.2}/app/utils/tcp_ports.py +0 -0
  612. {metalist-0.24.0 → metalist-0.24.2}/app/utils/text_utils.py +0 -0
  613. {metalist-0.24.0 → metalist-0.24.2}/app/utils/time_units.py +0 -0
  614. {metalist-0.24.0 → metalist-0.24.2}/convert-from-legacy.py +0 -0
  615. {metalist-0.24.0 → metalist-0.24.2}/main.py +0 -0
  616. {metalist-0.24.0 → metalist-0.24.2}/metalist.egg-info/dependency_links.txt +0 -0
  617. {metalist-0.24.0 → metalist-0.24.2}/metalist.egg-info/entry_points.txt +0 -0
  618. {metalist-0.24.0 → metalist-0.24.2}/metalist.egg-info/top_level.txt +0 -0
  619. {metalist-0.24.0 → metalist-0.24.2}/scripts/generate-lan-cert.sh +0 -0
  620. {metalist-0.24.0 → metalist-0.24.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: metalist
3
- Version: 0.24.0
3
+ Version: 0.24.2
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
@@ -15,13 +15,13 @@ Requires-Dist: httpx==0.28.1
15
15
  Requires-Dist: instructor==1.15.4
16
16
  Requires-Dist: latex2mathml==3.81.0
17
17
  Requires-Dist: loguru==0.7.3
18
- Requires-Dist: Mako==1.3.12
18
+ Requires-Dist: Mako==1.4.2
19
19
  Requires-Dist: nh3==0.3.6
20
20
  Requires-Dist: openai==2.54.0
21
21
  Requires-Dist: pillow==13.0.0
22
22
  Requires-Dist: pydantic==2.13.4
23
23
  Requires-Dist: pygments==2.20.0
24
- Requires-Dist: pypdf==6.21.1
24
+ Requires-Dist: pypdf==6.21.2
25
25
  Requires-Dist: python-dotenv==1.2.2
26
26
  Requires-Dist: python-multipart==0.0.32
27
27
  Requires-Dist: rich==14.3.4
@@ -53,6 +53,19 @@ 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.2
57
+
58
+ - ⇧⌘V pastes a copied note as a child again. Since 0.21.0, in Chrome, it put the copied note's text into the selected note instead.
59
+
60
+ ## Changes in 0.24.1
61
+
62
+ - **Security updates.** pypdf 6.21.2 fixes three ways a crafted PDF could keep MetaList busy for a long time; MetaList reads PDFs only when the AI opens one on the web (web access is off unless you turn it on). Mako 1.4.2 fixes a Windows template-path issue MetaList does not reach. Tooling used only to build and test MetaList is updated too (filelock, setuptools, zod).
63
+ - **Notes with files** (right-click menu, search box menu and command palette): show only the notes with an attached file, or with images, PDFs or Markdown files, each under the notes above it. Images also finds pictures pasted into a note. It works with a search (pick Images, then search, to find those notes with a picture); a chip in the search box names it and its `×` shows every note again. It stays with its tab.
64
+ - Pasting text that carries formatting (an answer copied from Copilot or another AI chat, a web page) is now checked too: Markdown left in it (`##` headings, `**`), CSV, code or LaTeX is offered on the small card, and Apply puts in the plain text with the tag. Headings over paragraphs and plain ``` code blocks are offered as Markdown.
65
+ - A collapsed embed of a note that only holds a link to another note now shows that note's first line in its own formatting, instead of a blank line and plain text. A link on a source's first line no longer breaks the embed.
66
+ - A note that holds only a reference stays an embed even with an invisible character beside the reference (left by ⌘B with nothing selected, or pasted).
67
+ - In a password-protected vault, PDFs and images attached before the last unlock are recognized again, for Notes with files, picture resizing and the image tag.
68
+
56
69
  ## Changes in 0.24.0
57
70
 
58
71
  - **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.
@@ -1,44 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: metalist
3
- Version: 0.24.0
4
- Summary: A minimalist single-user note-taking app with SSR, fast in-memory tree operations, and efficient sync.
5
- Project-URL: Homepage, https://metalist.app
6
- Project-URL: Repository, https://github.com/metalist-app/metalist
7
- Project-URL: Issues, https://github.com/metalist-app/metalist/issues
8
- Requires-Python: <3.15,>=3.11
9
- Description-Content-Type: text/markdown
10
- Requires-Dist: argon2-cffi==25.1.0
11
- Requires-Dist: cryptography==50.0.0
12
- Requires-Dist: fastapi==0.141.1
13
- Requires-Dist: httpcore==1.0.9
14
- Requires-Dist: httpx==0.28.1
15
- Requires-Dist: instructor==1.15.4
16
- Requires-Dist: latex2mathml==3.81.0
17
- Requires-Dist: loguru==0.7.3
18
- Requires-Dist: Mako==1.3.12
19
- Requires-Dist: nh3==0.3.6
20
- Requires-Dist: openai==2.54.0
21
- Requires-Dist: pillow==13.0.0
22
- Requires-Dist: pydantic==2.13.4
23
- Requires-Dist: pygments==2.20.0
24
- Requires-Dist: pypdf==6.21.1
25
- Requires-Dist: python-dotenv==1.2.2
26
- Requires-Dist: python-multipart==0.0.32
27
- Requires-Dist: rich==14.3.4
28
- Requires-Dist: starlette==1.3.1
29
- Requires-Dist: tqdm==4.70.0
30
- Requires-Dist: tree-sitter==0.25.2
31
- Requires-Dist: tree-sitter-javascript==0.25.0
32
- Requires-Dist: typing_extensions==4.16.0
33
- Requires-Dist: uvicorn==0.52.0
34
- Requires-Dist: zxcvbn==4.5.0
35
- Provides-Extra: dev
36
- Requires-Dist: hypothesis==6.164.0; extra == "dev"
37
- Requires-Dist: pytest==9.1.1; extra == "dev"
38
- Requires-Dist: pytest-cov==7.1.0; extra == "dev"
39
- Requires-Dist: shockharness==0.26.0; extra == "dev"
40
- Requires-Dist: mypy==2.4.0; extra == "dev"
41
-
42
1
  # MetaList
43
2
 
44
3
  A minimalist single-user note-taking app focused on server-side rendering (SSR), fast in-memory tree operations, and efficient sync/diff updates.
@@ -53,6 +12,19 @@ A minimalist single-user note-taking app focused on server-side rendering (SSR),
53
12
  - Multi-tab search contexts with server-persisted scroll/search state (survives browser restarts)
54
13
  - Manual namespace backups/restores to a user-selected backup folder with retention controls
55
14
 
15
+ ## Changes in 0.24.2
16
+
17
+ - ⇧⌘V pastes a copied note as a child again. Since 0.21.0, in Chrome, it put the copied note's text into the selected note instead.
18
+
19
+ ## Changes in 0.24.1
20
+
21
+ - **Security updates.** pypdf 6.21.2 fixes three ways a crafted PDF could keep MetaList busy for a long time; MetaList reads PDFs only when the AI opens one on the web (web access is off unless you turn it on). Mako 1.4.2 fixes a Windows template-path issue MetaList does not reach. Tooling used only to build and test MetaList is updated too (filelock, setuptools, zod).
22
+ - **Notes with files** (right-click menu, search box menu and command palette): show only the notes with an attached file, or with images, PDFs or Markdown files, each under the notes above it. Images also finds pictures pasted into a note. It works with a search (pick Images, then search, to find those notes with a picture); a chip in the search box names it and its `×` shows every note again. It stays with its tab.
23
+ - Pasting text that carries formatting (an answer copied from Copilot or another AI chat, a web page) is now checked too: Markdown left in it (`##` headings, `**`), CSV, code or LaTeX is offered on the small card, and Apply puts in the plain text with the tag. Headings over paragraphs and plain ``` code blocks are offered as Markdown.
24
+ - A collapsed embed of a note that only holds a link to another note now shows that note's first line in its own formatting, instead of a blank line and plain text. A link on a source's first line no longer breaks the embed.
25
+ - A note that holds only a reference stays an embed even with an invisible character beside the reference (left by ⌘B with nothing selected, or pasted).
26
+ - In a password-protected vault, PDFs and images attached before the last unlock are recognized again, for Notes with files, picture resizing and the image tag.
27
+
56
28
  ## Changes in 0.24.0
57
29
 
58
30
  - **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.
@@ -136,6 +136,14 @@ class UpdateTabDateFilterRequest(TypedDict):
136
136
  clientId: Identifier
137
137
  undoContext: UndoContext
138
138
 
139
+ @with_config(ConfigDict(strict=True))
140
+ class UpdateTabFileFilterRequest(TypedDict):
141
+ tabId: Identifier
142
+ # "none" shows every note again; "any" every note with an attached file.
143
+ kind: Literal["none", "any", "image", "pdf", "markdown"]
144
+ clientId: Identifier
145
+ undoContext: UndoContext
146
+
139
147
  @with_config(ConfigDict(strict=True))
140
148
  class CreateNewTabRequest(TypedDict):
141
149
  copyFromTabId: Identifier
@@ -499,6 +499,7 @@ def suggest_tags_for_note_with_ai(
499
499
  search=payload.search,
500
500
  sort_mode=tab_state_store.get_sort_mode(tab_id=payload.tab_id),
501
501
  date_filter=tab_state_store.get_date_filter(tab_id=payload.tab_id),
502
+ file_filter=tab_state_store.get_file_filter(tab_id=payload.tab_id),
502
503
  is_untagged_view=payload.is_untagged_view,
503
504
  )
504
505
  if note_id not in scope.allowed_note_ids:
@@ -561,6 +562,7 @@ def _export_title_request(scope: ExportTitleScope, token: str) -> ExportTitleReq
561
562
  search=search,
562
563
  sort_mode=tab_state_store.get_sort_mode(tab_id=scope.tab_id),
563
564
  date_filter=tab_state_store.get_date_filter(tab_id=scope.tab_id),
565
+ file_filter=tab_state_store.get_file_filter(tab_id=scope.tab_id),
564
566
  is_untagged_view=scope.is_untagged_view, root_note_id=note_id,
565
567
  )
566
568
  boundary = resolve_cloud_privacy_boundary(preferences=load_client_preferences(token=token), provider=scope.provider)
@@ -906,18 +908,22 @@ def stream_ai_chat(
906
908
  tab_id=payload.scope.scope_tab_id
907
909
  )
908
910
  authoritative_date_filter = tab_state_store.get_date_filter(tab_id=payload.scope.scope_tab_id)
911
+ authoritative_file_filter = tab_state_store.get_file_filter(tab_id=payload.scope.scope_tab_id)
909
912
  active_search_query = authoritative_search_query
910
913
  active_sort_mode = authoritative_sort_mode
911
914
  active_date_filter = authoritative_date_filter
915
+ active_file_filter = authoritative_file_filter
912
916
  if payload.selected_note_id and payload.scope.active_tab_id != payload.scope.scope_tab_id:
913
917
  active_search_query = tab_state_store.get_search_query(tab_id=authoritative_active_tab_id)
914
918
  active_sort_mode = tab_state_store.get_sort_mode(tab_id=authoritative_active_tab_id)
915
919
  active_date_filter = tab_state_store.get_date_filter(tab_id=authoritative_active_tab_id)
920
+ active_file_filter = tab_state_store.get_file_filter(tab_id=authoritative_active_tab_id)
916
921
  frozen_scope = scoped_search_snapshot_factory.freeze(
917
922
  descriptor=payload.scope,
918
923
  authoritative_search_query=authoritative_search_query,
919
924
  authoritative_sort_mode=authoritative_sort_mode,
920
925
  authoritative_date_filter=authoritative_date_filter,
926
+ authoritative_file_filter=authoritative_file_filter,
921
927
  run_id=str(uuid4()),
922
928
  session_key=session_key,
923
929
  privacy_boundary=privacy_boundary,
@@ -925,6 +931,7 @@ def stream_ai_chat(
925
931
  authoritative_active_search_query=active_search_query,
926
932
  authoritative_active_sort_mode=active_sort_mode,
927
933
  authoritative_active_date_filter=active_date_filter,
934
+ authoritative_active_file_filter=active_file_filter,
928
935
  )
929
936
  tagging_run = TaggingRun(token=token, snapshot=frozen_scope, privacy_boundary=privacy_boundary,
930
937
  preferences=preferences, sync_uuid=get_current_sync_uuid(),
@@ -1063,6 +1070,7 @@ def manage_bulk_proposals(payload: BulkManageRequest, token: Annotated[str, Depe
1063
1070
  with bulk_operation_guard.acquire(token_service.get_session_key(token)):
1064
1071
  note_ids = proposal_scope_ids(
1065
1072
  payload.scope, date_filter=tab_state_store.get_date_filter(tab_id=payload.scope.scope_tab_id),
1073
+ file_filter=tab_state_store.get_file_filter(tab_id=payload.scope.scope_tab_id),
1066
1074
  )
1067
1075
  if payload.target == "namespace":
1068
1076
  note_ids = tuple(note_store.list_note_ids())
@@ -14,6 +14,7 @@ from app.api.note_requests import (
14
14
  FindInListRequest,
15
15
  UpdateTabStateRequest,
16
16
  UpdateTabDateFilterRequest,
17
+ UpdateTabFileFilterRequest,
17
18
  UpdateTabSortModeRequest,
18
19
  CreateNewTabRequest,
19
20
  DeleteTabRequest,
@@ -64,6 +65,7 @@ from app.api.note_requests import (
64
65
  )
65
66
  from app.api.transactions import serialized_read_route, transactional_route
66
67
  from app.services.sync import touch_client
68
+ from app.services.file_kinds import FILE_FILTER_NONE
67
69
  from app.services.root_date_filter import DATE_RANGE_NONE
68
70
  from app.services.tag_properties import PROPERTY_SUGGESTIONS_IN_SEARCH
69
71
  from app.services.tag_properties import PROPERTY_SUGGESTIONS_IN_TAG_BAR
@@ -271,6 +273,13 @@ def _resolve_tab_sort_mode(tab_id: object) -> str:
271
273
  return sort_mode
272
274
 
273
275
 
276
+ def _resolve_tab_file_filter(tab_id: str) -> str | None:
277
+ """The tab's Files filter kind (None: every note)."""
278
+ if not isinstance(tab_id, str) or tab_id == "":
279
+ raise TypeError("tabId must be a non-empty string")
280
+ return tab_state_store.get_file_filter(tab_id=tab_id)
281
+
282
+
274
283
  def _resolve_tab_date_filter(tab_id: str) -> RootDateFilter | None:
275
284
  """The tab's date range filter (None: every date), as its sort order is resolved."""
276
285
  if not isinstance(tab_id, str) or tab_id == "":
@@ -384,6 +393,7 @@ def view_diff(payload: ViewDiffRequest):
384
393
  search=normalized_search,
385
394
  sort_mode=sort_mode,
386
395
  date_filter=_resolve_tab_date_filter(tab_id),
396
+ file_filter=_resolve_tab_file_filter(tab_id),
387
397
  client_known_note_ids=client_known_note_ids,
388
398
  previous_root_ids=previous_root_ids,
389
399
  visible_top_root_id=visible_top_root_id,
@@ -508,6 +518,19 @@ def update_tab_date_filter(payload: UpdateTabDateFilterRequest) -> Dict[str, obj
508
518
  return response
509
519
 
510
520
 
521
+ @router.post("/notes/tab-state/file-filter")
522
+ @transactional_route
523
+ def update_tab_file_filter(payload: UpdateTabFileFilterRequest) -> Dict[str, object]:
524
+ """Set or clear a tab's Files filter (file_kinds.py)."""
525
+ file_filter: str | None = None
526
+ if payload["kind"] != FILE_FILTER_NONE:
527
+ file_filter = payload["kind"]
528
+ response = tab_state_store.set_file_filter(tab_id=payload["tabId"], file_filter=file_filter)
529
+ if response["changed"] is True:
530
+ reset_undo_stack(payload["clientId"], payload["undoContext"])
531
+ return response
532
+
533
+
511
534
  @router.post("/notes/tab-state/new-tab")
512
535
  @transactional_route
513
536
  def create_new_tab(payload: CreateNewTabRequest) -> Dict[str, object]:
@@ -732,6 +755,7 @@ def find_in_list(payload: FindInListRequest) -> Dict[str, object]:
732
755
  window = find_in_view(
733
756
  find_text=payload["text"], search=search, sort_mode=_resolve_tab_sort_mode(payload["tabId"]),
734
757
  date_filter=_resolve_tab_date_filter(payload["tabId"]),
758
+ file_filter=_resolve_tab_file_filter(payload["tabId"]),
735
759
  is_untagged_view=payload["isUntaggedView"], from_root_index=payload["fromRootIndex"],
736
760
  direction=payload["direction"],
737
761
  )
@@ -876,6 +900,7 @@ def export_summary(request: Request) -> Dict[str, object]:
876
900
  counts = exported_credential_counts(
877
901
  search=normalized_search, sort_mode=_resolve_tab_sort_mode(tab_id),
878
902
  date_filter=_resolve_tab_date_filter(tab_id),
903
+ file_filter=_resolve_tab_file_filter(tab_id),
879
904
  is_untagged_view=is_untagged_view == "true", root_note_id=note_id,
880
905
  )
881
906
  return {
@@ -936,6 +961,7 @@ def export_notes_html(request: Request) -> Response:
936
961
  search=normalized_search,
937
962
  sort_mode=_resolve_tab_sort_mode(tab_id),
938
963
  date_filter=_resolve_tab_date_filter(tab_id),
964
+ file_filter=_resolve_tab_file_filter(tab_id),
939
965
  is_untagged_view=is_untagged_view == "true",
940
966
  theme=normalized_theme,
941
967
  token=token,
@@ -1199,6 +1225,7 @@ def _robot_scope_note_ids(body: dict) -> frozenset[str]:
1199
1225
  search=body["search"],
1200
1226
  sort_mode=_resolve_tab_sort_mode(body["tabId"]),
1201
1227
  date_filter=_resolve_tab_date_filter(body["tabId"]),
1228
+ file_filter=_resolve_tab_file_filter(body["tabId"]),
1202
1229
  is_untagged_view=body["isUntaggedView"],
1203
1230
  ).allowed_note_ids
1204
1231
 
@@ -294,6 +294,8 @@ class ScopedSearchSnapshot:
294
294
  # The tab's date range filter at Send (None: every date), for the server's own
295
295
  # searches of this view later in the run.
296
296
  date_filter: RootDateFilter | None
297
+ # The tab's Files filter at Send (None: every note), as the date range.
298
+ file_filter: str | None
297
299
  # How long freezing took, shown on the chat's first activity line.
298
300
  preparation_ms: float
299
301
  # Note text extracted on first read during the run (NoteText).
@@ -335,6 +337,7 @@ class ScopedSearchSnapshotFactory:
335
337
  authoritative_search_query: str,
336
338
  authoritative_sort_mode: str,
337
339
  authoritative_date_filter: RootDateFilter | None,
340
+ authoritative_file_filter: str | None,
338
341
  run_id: str,
339
342
  session_key: str,
340
343
  privacy_boundary: CloudPrivacyBoundary,
@@ -342,6 +345,7 @@ class ScopedSearchSnapshotFactory:
342
345
  authoritative_active_search_query: str,
343
346
  authoritative_active_sort_mode: str,
344
347
  authoritative_active_date_filter: RootDateFilter | None,
348
+ authoritative_active_file_filter: str | None,
345
349
  ) -> ScopedSearchSnapshot:
346
350
  started_at = time.perf_counter()
347
351
  text_extraction = TextExtractionMeter.start()
@@ -356,6 +360,7 @@ class ScopedSearchSnapshotFactory:
356
360
  search=descriptor.search_query,
357
361
  sort_mode=descriptor.sort_mode,
358
362
  date_filter=authoritative_date_filter,
363
+ file_filter=authoritative_file_filter,
359
364
  is_untagged_view=descriptor.scope_kind == "untagged",
360
365
  )
361
366
  selected_view = resolved
@@ -364,6 +369,7 @@ class ScopedSearchSnapshotFactory:
364
369
  search=authoritative_active_search_query,
365
370
  sort_mode=authoritative_active_sort_mode,
366
371
  date_filter=authoritative_active_date_filter,
372
+ file_filter=authoritative_active_file_filter,
367
373
  is_untagged_view=False,
368
374
  )
369
375
  selected_note = self._freeze_selected_note(selected_note_id, selected_view, privacy_boundary)
@@ -435,6 +441,7 @@ class ScopedSearchSnapshotFactory:
435
441
  note_records_at_send=self._records_at_send(tree_nodes),
436
442
  disclosable_search_query=self._disclosable_search_query(descriptor, privacy_boundary),
437
443
  date_filter=authoritative_date_filter,
444
+ file_filter=authoritative_file_filter,
438
445
  preparation_ms=(time.perf_counter() - started_at) * MS_PER_SECOND,
439
446
  text_extraction=text_extraction,
440
447
  selected_note=selected_note,
@@ -452,7 +459,7 @@ class ScopedSearchSnapshotFactory:
452
459
 
453
460
  def _finds_visible_note(self, *, search: str, sort_mode: str, boundary: CloudPrivacyBoundary) -> bool:
454
461
  resolved = self._view_scope_resolver(
455
- search=search, sort_mode=sort_mode, date_filter=None, is_untagged_view=False,
462
+ search=search, sort_mode=sort_mode, date_filter=None, file_filter=None, is_untagged_view=False,
456
463
  )
457
464
  return self._privacy_evaluator.has_visible_note(note_ids=tuple(resolved.matched_note_ids), boundary=boundary)
458
465
 
@@ -222,9 +222,15 @@ Other (non-meta) tags may also appear inside wrapper tokens (e.g. `{{foo bar}}`)
222
222
  - Text that only looks like a format is pasted as plain text, and a small card just below where the paste ended offers it: `Apply as Markdown` (or `Apply as CSV`, `Apply as Python`) and `Skip`. When several languages are close, it reads `Looks like code:` with up to three, best first (`Ruby`, `Python`), then `Skip`. A wrong guess costs nothing.
223
223
  - What is offered:
224
224
  - CSV-like: three or more lines with the same number of comma-separated cells (two or more; commas inside quotes do not count), short cells, no sentences → `@csv`.
225
- - Markdown-like: two or more different kinds of signs (`#` headings, a list of two or more items, `**bold**`, `` `code` ``, `[text](url)` links, `>` quotes, a bare ```` ``` ```` fence), or a table (`| a | b |` with its `---` line) → `@markdown`. A lone bullet list is an ordinary note and is not offered.
225
+ - Markdown-like: two or more different kinds of signs (`#` headings, a list of two or more items, `**bold**`, `` `code` ``, `[text](url)` links, `>` quotes), or two or more headings → `@markdown`. A table (`| a | b |` with its `---` line) or a bare fenced code block (```` ``` ````, opened and closed) settles it: such text is Markdown even when the code inside reads as HTML or Python. (A fence naming its language, ```` ```html ````, is tagged at once; see above.) A lone bullet list or a single heading is an ordinary note and is not offered.
226
226
  - Code: mostly code-like lines (ending in `;`, `{`, `)`, `:`..., indented code, assignments and calls, no sentences), or a strong sign of one language → `@code=<language>`, for SQL, Python, Ruby, JavaScript, TypeScript, Shell (`@code=bash`), HTML, XML, CSS, Java, C, C++, C#, Go, Rust, YAML and Dockerfile, each scored on its own signs (`SELECT ... FROM`, `def f():`, `do |x|`, `console.log`, `#!/bin/bash`...). Notes of `key: value` lines are not YAML; a sentence mentioning "select ... from" is not SQL.
227
- - Only plain-text pastes are guessed: when the clipboard carries formatted text (headings, lists, links, bold from a web page), it is pasted with its formatting as before and nothing is offered. Nothing is offered where nothing would be added (see above): Markdown into a note that is already `@markdown`, code into `@code=…`, CSV into `@csv`.
227
+ - A paste with formatting is checked too; see Formatted pastes below. Nothing is offered where nothing would be added (see above): Markdown into a note that is already `@markdown`, code into `@code=…`, CSV into `@csv`.
228
228
  - The card moves nothing and never takes the keyboard: the caret stays where the paste ended. `Skip`, `Escape` (which closes only the card, not edit mode), typing on, a click elsewhere, scrolling the page yourself, or leaving edit mode closes it without applying; when MetaList scrolls on its own (a new note settling into view) the card stays with the paste. Near the bottom of the window it opens above the paste instead; the page never scrolls to show it.
229
229
  - Pasting while no note is edited makes a new note at the top, as before; its paste is checked the same way (certain formats tagged at once, likely ones offered on the card once the new note is in place).
230
230
  - `Apply` adds the tag as a detected format is added: the plain tag into an otherwise empty note, or the paste wrapped `((...))` with `((@markdown))` into a note with other text. The note stays in edit mode and the text renders when it leaves editing. `⌘Z` right after removes the tag together with the paste, as for a format added at once.
231
+
232
+ ## Formatted pastes
233
+ - A paste whose clipboard carries formatting (bold, links, headings, code from a web page or an AI chat) goes in with its formatting, as always. Its text without the formatting is then checked as a plain paste is: Markdown left in it (`##` headings, `**`, fences, as Copilot answers often are), CSV, code, and the formats a plain paste is tagged with at once (JSON, LaTeX, a diff, Mermaid, a chess position). What is found is offered on the same card (`Apply as Markdown`, `Apply as LaTeX`), never applied at once, since applying drops the formatting.
234
+ - A fully rendered paste (real headings and bold, no Markdown signs left in its text) offers nothing. Formats the clipboard's plain text already settles (JSON, a fenced block naming its language, spreadsheet cells, VS Code code) are still tagged at once, as before.
235
+ - `Apply` replaces the formatted paste with its text and adds the tag, as for a plain paste: the clipboard's plain text when it reads as the same format (it often keeps the source, `**bold**` included), otherwise the text without formatting. `Skip`, or typing on, keeps the formatting.
236
+ - Implementation: `formatted-paste-format-service.js` (tests in `tests/unit/formatted_paste_format.test.mjs`), wired in `keyboard-events.js` (`planFormattedPasteOffer`).
@@ -56,6 +56,12 @@ Opening or dismissing the command palette does not clear undo/redo. Global actio
56
56
  - It combines with a search, Untagged notes and any sort order.
57
57
  - A gray chip inside the search input names it (`Updated · today`, `Created · Oct 1–22`, `Updated · since Oct 1`); the full wording is its tooltip and its `×` shows every date again.
58
58
  - Like a sort order it is kept per tab and ends with its `×`, a new search, or leaving the tab; a new tab starts without one; following a reference and coming back keeps it.
59
+
60
+ ## Notes With Files
61
+ - **Notes with files** (after Date range in the background, side-rail and search-box right-click menus) shows only the notes with an attached file, or a file of one kind, each with the notes above it: **All notes** (no filter), **Any file**, **Images**, **PDFs**, **Markdown files**. A note counts by a `[[file]]` link or `![[file]]` embed in its own text; **Images** also finds pictures pasted into a note. Markdown files are known by a `.md` or `.markdown` name.
62
+ - Palette actions: `Notes with files: All notes`, `Notes with files: Any file`, `Notes with files: Images`, `Notes with files: PDFs`, `Notes with files: Markdown files`.
63
+ - It combines with a search, Untagged notes, a date range and any sort order; a new search keeps it (pick Images, then type a search, to find those notes with a picture), and it stays with its tab.
64
+ - A gray chip inside the search input names it (`Files`, `Images`, `PDFs`, `Markdown files`); its `×` shows every note again.
59
65
  - A note being edited stays in view even when saving puts its date outside the range; after leaving edit mode it leaves the view.
60
66
  - Export, Print, find (⌘F) and the AI chat's view use the tab's range.
61
67
 
@@ -72,7 +72,7 @@ Sources: docs/ui/controls.md, docs/ui/find.md
72
72
  On macOS, `⌘ + Y` normally opens Safari History rather than performing native text redo. MetaList intercepts it while editing and maps it to the active editor's local redo operation; this does not call the server.
73
73
 
74
74
  - When a non-normal sort mode is active, a gray chip at the right end inside the search input names it (`A–Z`, `Created ↑`, …), with an `×` to return to normal sorting.
75
- - These dismissible chips are **view indicators**: sorted notes, a date range and Untagged notes inside the search input; reference views (Source note, Reference, All references) centered in the bar in place of the input. Entering or leaving them applies note changes immediately, without appearance/disappearance or collapse animations; only reference views slide the list.
75
+ - These dismissible chips are **view indicators**: sorted notes, a date range, a Notes with files filter and Untagged notes inside the search input; reference views (Source note, Reference, All references) centered in the bar in place of the input. Entering or leaving them applies note changes immediately, without appearance/disappearance or collapse animations; only reference views slide the list.
76
76
  - Scroll restoration preserves an exact top position without delayed anchor alignment. Resetting a view cancels pending scroll restores from its previous content.
77
77
  - When tabs are enabled, a white outline stacked-folder icon marks the black trigger region left of the search field. Its left inset matches the results count's right inset. Hovering that region or icon opens the tab/search-context overlay, which remains available while hovering over the dropdown itself. Creating a blank tab with `Enter` does not dismiss the overlay. Open search suggestions render above the tabs.
78
78
  - Left/right side lanes hide at narrower desktop widths before they can overlap the centered notes column.
@@ -14,7 +14,7 @@ Sources: docs/ui/references.md
14
14
 
15
15
  ## Status
16
16
  - One syntax for note references: `[[UUID]]`. How it shows depends on where it is:
17
- - **Embed**: a note whose only content is the reference shows the source in place (its whole note is the embed).
17
+ - **Embed**: a note whose only content is the reference shows the source in place (its whole note is the embed). Characters with no width (a zero-width space, a byte-order mark) are not content.
18
18
  - **Link**: with any other content in the note, even an extra line, the reference is a link.
19
19
  - An older `![[UUID]]` to a note reads the same as `[[UUID]]`; the `!` changes nothing. MetaList writes `[[UUID]]` (⌘R, ⇧⌘R, Paste Reference Into Note).
20
20
  - File references keep two forms: `![[UUID]]` shows the picture or diagram, `[[UUID]]` a file card.
@@ -27,7 +27,7 @@ Sources: docs/ui/references.md
27
27
  - **View mode**:
28
28
  - Note targets:
29
29
  - **Embeds.** The note holding the reference shows the source in place, tinted grey (light `#e4e7eb`; dark `#202224`), drawn exactly as the main tree draws notes: the same boxes, indent, spacing and ▾/▸ arrows. An embed inside an embed (a note in the source that is itself only a reference) is a shade deeper (`#d5dade`, then `#c6ccd2`; dark `#2a2d30`, `#35393d`).
30
- - The holder folds as its source: its ▾/▸ collapses or expands the source everywhere (the original in the tree and every other embed of it), and its own children with it. When the source is folded anywhere, the holder shows folded. Undo reverts both. A folded embed shows the source's first line as a collapsed note shows it, in the source's own formatting (a heading, a colour), still tinted and cut with … before its icon; a hidden password, footnote markers and a picture or diagram keep their compact preview.
30
+ - The holder folds as its source: its ▾/▸ collapses or expands the source everywhere (the original in the tree and every other embed of it), and its own children with it. When the source is folded anywhere, the holder shows folded. Undo reverts both. A folded embed shows the source's first line as a collapsed note shows it, in the source's own formatting (a heading, a colour), still tinted and cut with … before its icon; a source that is only a reference is followed to the note it shows, and a link on that line shows as it does in the source; a hidden password, footnote markers and a picture or diagram keep their compact preview.
31
31
  - Each note inside an embed shows the collapse saved for it, with its own ▾/▸ where it can collapse; pressing it folds that note everywhere. A note being edited is saved and left first. Full screen and floating windows show no embed arrows.
32
32
  - The holder's own children (indented under it in the tree) show after the source's children, as notes of the level around the holder (white in the main tree). They belong to the holder, not the source: the source knows nothing of them, and they cannot be moved in among the source's children.
33
33
  - An embed's reference icon, a page with an arrow coming into it (tooltip: `Go to source note`), sits at its top right and opens the source note in a temporary reference-source context.
@@ -5,6 +5,19 @@ README. Changes made after the newest listed version are not described here.
5
5
  Compare with installed_version from the help lookup to tell the user whether
6
6
  they already have a release. Version info offers updates (see the data topic).
7
7
 
8
+ ## 0.24.2
9
+
10
+ - ⇧⌘V pastes a copied note as a child again. Since 0.21.0, in Chrome, it put the copied note's text into the selected note instead.
11
+
12
+ ## 0.24.1
13
+
14
+ - **Security updates.** pypdf 6.21.2 fixes three ways a crafted PDF could keep MetaList busy for a long time; MetaList reads PDFs only when the AI opens one on the web (web access is off unless you turn it on). Mako 1.4.2 fixes a Windows template-path issue MetaList does not reach. Tooling used only to build and test MetaList is updated too (filelock, setuptools, zod).
15
+ - **Notes with files** (right-click menu, search box menu and command palette): show only the notes with an attached file, or with images, PDFs or Markdown files, each under the notes above it. Images also finds pictures pasted into a note. It works with a search (pick Images, then search, to find those notes with a picture); a chip in the search box names it and its `×` shows every note again. It stays with its tab.
16
+ - Pasting text that carries formatting (an answer copied from Copilot or another AI chat, a web page) is now checked too: Markdown left in it (`##` headings, `**`), CSV, code or LaTeX is offered on the small card, and Apply puts in the plain text with the tag. Headings over paragraphs and plain ``` code blocks are offered as Markdown.
17
+ - A collapsed embed of a note that only holds a link to another note now shows that note's first line in its own formatting, instead of a blank line and plain text. A link on a source's first line no longer breaks the embed.
18
+ - A note that holds only a reference stays an embed even with an invisible character beside the reference (left by ⌘B with nothing selected, or pasted).
19
+ - In a password-protected vault, PDFs and images attached before the last unlock are recognized again, for Notes with files, picture resizing and the image tag.
20
+
8
21
  ## 0.24.0
9
22
 
10
23
  - **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.
@@ -137,6 +137,9 @@ Ontology rules also add **inferred tags** before search matching:
137
137
  - The dismissible `Untagged notes` pill returns to the underlying tab view and restores its query in the search box. Clicking any tab or changing the search input also dismisses the temporary view.
138
138
  - Changing the search input additionally resets the active tab's sort mode to Normal before executing the search.
139
139
 
140
+ ### Notes With Files
141
+ - **Notes with files** in the right-click menus and the palette (`Notes with files: Images`, …) keeps a search to the matches whose own text links to or embeds an attached file, or a file of one kind (images, PDFs, Markdown files; Images also counts a picture pasted into the note), with the notes above them. Without a search it alone picks the notes. It is not a search term: a chip in the search box shows it, and a new search keeps it (`docs/ui/command-palette.md`, Notes With Files).
142
+
140
143
  ### Search Suggestions
141
144
  - Search-bar tag suggestions are segment-aware for connector-separated tags.
142
145
  - A suggestion must leave at least one matching note in the active `OR` clause, satisfying every completed tag, text term, and exclusion. For example, after `prediction-future`, typing `security` only suggests `computer-security` if that combination actually matches a note. Partial tag overlap alone is insufficient. Matching uses the same effective tags as search, including inheritance, references, and ontology inference. This filtering happens before personalization and the visible limit; note-tag recommendations can still propose new combinations.
@@ -97,9 +97,9 @@ def tagging_trees(snapshot):
97
97
  return tuple(payloads[root_id] for root_id in snapshot.ordered_root_ids)
98
98
 
99
99
 
100
- def proposal_scope_ids(descriptor, *, date_filter):
100
+ def proposal_scope_ids(descriptor, *, date_filter, file_filter):
101
101
  resolved = resolve_view_scope_membership(search=descriptor.search_query,
102
- sort_mode=descriptor.sort_mode, date_filter=date_filter,
102
+ sort_mode=descriptor.sort_mode, date_filter=date_filter, file_filter=file_filter,
103
103
  is_untagged_view=descriptor.scope_kind == "untagged")
104
104
  included = set(resolved.matched_note_ids)
105
105
  for note_id in tuple(included):
@@ -239,7 +239,9 @@ class TaggingRun:
239
239
  note_ids = tuple(store.list_note_ids())
240
240
  scope_label = "the whole vault"
241
241
  else:
242
- note_ids = proposal_scope_ids(self.snapshot.descriptor, date_filter=self.snapshot.date_filter)
242
+ note_ids = proposal_scope_ids(
243
+ self.snapshot.descriptor, date_filter=self.snapshot.date_filter, file_filter=self.snapshot.file_filter,
244
+ )
243
245
  scope_label = "the current view"
244
246
  changes, count, _affected = prepare_proposal_changes(note_ids, action, tag_filter, {})
245
247
  matching = "pending tag proposals"
@@ -2,22 +2,28 @@
2
2
 
3
3
  Only UUIDs and occurrence counts are retained, never note text. Targets may be
4
4
  missing (or files); retaining those edges lets a restored note regain backlinks
5
- without reparsing its referrers.
5
+ without reparsing its referrers. It also keeps which notes show a picture inline
6
+ (an <img> in their own text), for the Files filter's Images (file_kinds.py).
6
7
  """
7
8
 
8
9
  from collections import Counter
10
+ import re
9
11
 
10
12
  from app.services.embedded_references import collect_active_reference_tokens
11
13
 
14
+ _INLINE_IMAGE_RE = re.compile(r"<img\b", re.IGNORECASE)
15
+
12
16
 
13
17
  class BacklinkIndex:
14
18
  def __init__(self) -> None:
15
19
  self._outgoing: dict[str, dict[str, int]] = {}
16
20
  self._incoming: dict[str, dict[str, int]] = {}
21
+ self._inline_image_note_ids: set[str] = set()
17
22
 
18
23
  def clear(self) -> None:
19
24
  self._outgoing.clear()
20
25
  self._incoming.clear()
26
+ self._inline_image_note_ids.clear()
21
27
 
22
28
  def upsert(self, note_id: str, content: str, tags: str) -> None:
23
29
  assert isinstance(note_id, str) and note_id
@@ -26,6 +32,8 @@ class BacklinkIndex:
26
32
  if token.note_id != note_id
27
33
  ))
28
34
  self.remove(note_id)
35
+ if _INLINE_IMAGE_RE.search(content) is not None:
36
+ self._inline_image_note_ids.add(note_id)
29
37
  if not counts:
30
38
  return
31
39
  self._outgoing[note_id] = counts
@@ -35,6 +43,7 @@ class BacklinkIndex:
35
43
  self._incoming[target_id][note_id] = count
36
44
 
37
45
  def remove(self, note_id: str) -> None:
46
+ self._inline_image_note_ids.discard(note_id)
38
47
  if note_id not in self._outgoing:
39
48
  return
40
49
  for target_id in self._outgoing.pop(note_id):
@@ -52,6 +61,9 @@ class BacklinkIndex:
52
61
  return frozenset()
53
62
  return frozenset(self._outgoing[note_id])
54
63
 
64
+ def inline_image_note_ids(self) -> frozenset[str]:
65
+ return frozenset(self._inline_image_note_ids)
66
+
55
67
  def get_counts(self, note_id: str) -> dict[str, int]:
56
68
  if note_id not in self._incoming:
57
69
  return {}
@@ -396,6 +396,9 @@ _EDITOR_WRAPPER_TAG_RE = re.compile(r"</?(?:div|p|span|b|strong|i|em|u|s)\b[^>]*
396
396
  _TRAILING_BLOCK_BREAK_RE = re.compile(r"(?<=[^>\s])\s*<br\s*/?>(?=\s*</(?:div|p)>)", re.IGNORECASE)
397
397
  # Stands in for the reference while checking what else the note holds.
398
398
  _SOLE_REFERENCE_MARK = "\x00"
399
+ # Characters with no width, unseen in the editor (a zero-width space left by ⌘B
400
+ # with nothing selected, a pasted byte-order mark): they are not content.
401
+ _INVISIBLE_CHARACTERS_RE = re.compile("[\u200b-\u200d\u2060\ufeff]")
399
402
 
400
403
 
401
404
  def sole_reference_token(content_html: str) -> Optional[ReferenceToken]:
@@ -412,7 +415,7 @@ def sole_reference_token(content_html: str) -> Optional[ReferenceToken]:
412
415
  token = tokens[0]
413
416
  marked = content_html[:token.start] + _SOLE_REFERENCE_MARK + content_html[token.end:]
414
417
  unwrapped = _EDITOR_WRAPPER_TAG_RE.sub("", _TRAILING_BLOCK_BREAK_RE.sub("", marked))
415
- if html.unescape(unwrapped).strip() != _SOLE_REFERENCE_MARK:
418
+ if _INVISIBLE_CHARACTERS_RE.sub("", html.unescape(unwrapped)).strip() != _SOLE_REFERENCE_MARK:
416
419
  return None
417
420
  return token
418
421
 
@@ -748,8 +751,15 @@ def _render_collapsed_embed_body(
748
751
  redact_credentials: bool,
749
752
  ) -> str:
750
753
  """A collapsed embed: the source's first line drawn as a collapsed note draws it,
751
- in the source's own formatting (a heading, a colour), with the source icon."""
752
- record = context.get_note(reference_note_id)
754
+ in the source's own formatting (a heading, a colour), with the source icon.
755
+
756
+ A source that is only a reference is followed to the note it shows, as a
757
+ link to it reads. The line is held in a span, not a link: a link on that
758
+ line inside another link would be split apart, leaving an empty line."""
759
+ shown_note_id = resolve_held_source(
760
+ reference_note_id, has_note=context.has_note, content_of=_context_content(context),
761
+ )
762
+ record = context.get_note(shown_note_id)
753
763
  source_content = getattr(record, "content")
754
764
  source_tags = getattr(record, "tags")
755
765
  if not isinstance(source_content, str) or not isinstance(source_tags, str):
@@ -775,7 +785,7 @@ def _render_collapsed_embed_body(
775
785
  show_media=True,
776
786
  )
777
787
  preview_html = render_collapsed_note_content_with_embeds(
778
- note_id=reference_note_id,
788
+ note_id=shown_note_id,
779
789
  content_html=source_content,
780
790
  tags=source_tags,
781
791
  context=context,
@@ -786,10 +796,10 @@ def _render_collapsed_embed_body(
786
796
  return f'<span class="note-reference-link note-reference-link-static">{preview_html}</span>'
787
797
  escaped_note_id = html.escape(reference_note_id, quote=True)
788
798
  return (
789
- f'<a href="#" class="note-reference-link" data-ref-note-id="{escaped_note_id}">'
799
+ f'<span class="note-reference-link" data-ref-note-id="{escaped_note_id}">'
790
800
  '<span class="note-reference-link-icon note-reference-icon" aria-hidden="true" title="Go to source note"></span>'
791
801
  f'<span class="note-reference-link-title">{preview_html}</span>'
792
- "</a>"
802
+ "</span>"
793
803
  )
794
804
 
795
805
 
@@ -0,0 +1,46 @@
1
+ """Files filter: a tab shows only the notes that reference an attached file, or one of
2
+ a kind (an image, a PDF, a Markdown file), with the notes above them
3
+ (docs/ui/command-palette.md, Notes With Files).
4
+
5
+ A note matches by its own text: a [[file]] link or ![[file]] embed in it. Each
6
+ file's kind comes from what the file registry already holds: its thumbnail kind
7
+ and its name.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from app.services.input_errors import InputRejected
13
+
14
+ FILE_KIND_IMAGE = "image"
15
+ FILE_KIND_PDF = "pdf"
16
+ FILE_KIND_MARKDOWN = "markdown"
17
+ # Every other file: kept by the registry, offered only as part of "any".
18
+ FILE_KIND_OTHER = "other"
19
+ # The filter for every attached file, whatever its kind.
20
+ FILE_FILTER_ANY = "any"
21
+ # What a request sends to show every note again (no filter).
22
+ FILE_FILTER_NONE = "none"
23
+ FILE_FILTER_KINDS = frozenset({FILE_FILTER_ANY, FILE_KIND_IMAGE, FILE_KIND_PDF, FILE_KIND_MARKDOWN})
24
+
25
+ # A file's thumbnail kind (file_storage._derive_thumbnail_kind) already marks
26
+ # images and PDFs; Markdown files are known by their name.
27
+ _THUMBNAIL_KINDS_FILTERED = {"image": FILE_KIND_IMAGE, "pdf": FILE_KIND_PDF}
28
+ _MARKDOWN_EXTENSIONS = (".md", ".markdown")
29
+
30
+
31
+ def file_kind_of(*, thumbnail_kind: str, file_name: str) -> str:
32
+ """The kind a file is filtered by: image, pdf, markdown or other."""
33
+ if not isinstance(thumbnail_kind, str) or not isinstance(file_name, str):
34
+ raise TypeError("file_kind_of requires thumbnail_kind and file_name strings")
35
+ if thumbnail_kind in _THUMBNAIL_KINDS_FILTERED:
36
+ return _THUMBNAIL_KINDS_FILTERED[thumbnail_kind]
37
+ if file_name.strip().lower().endswith(_MARKDOWN_EXTENSIONS):
38
+ return FILE_KIND_MARKDOWN
39
+ return FILE_KIND_OTHER
40
+
41
+
42
+ def make_file_filter(kind: str) -> str:
43
+ """A validated filter kind; a request or saved tab state with another is rejected."""
44
+ if kind not in FILE_FILTER_KINDS:
45
+ raise InputRejected(f"Unknown file type to filter on: {kind!r}")
46
+ return kind