MetaList 0.18.0__tar.gz → 0.19.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (559) hide show
  1. {metalist-0.18.0/metalist.egg-info → metalist-0.19.0}/PKG-INFO +10 -1
  2. {metalist-0.18.0 → metalist-0.19.0}/README.md +9 -0
  3. {metalist-0.18.0 → metalist-0.19.0}/app/api/note_requests.py +16 -6
  4. {metalist-0.18.0 → metalist-0.19.0}/app/api/routes/notes.py +30 -17
  5. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/skills/help-formatting.md +17 -2
  6. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/skills/help-notes.md +1 -1
  7. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/skills/help-releases.md +9 -0
  8. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/skills/help-search.md +2 -1
  9. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/skills/help-tags.md +9 -6
  10. {metalist-0.18.0 → metalist-0.19.0}/app/services/code_rendering.py +28 -2
  11. {metalist-0.18.0 → metalist-0.19.0}/app/services/markdown_rendering.py +5 -0
  12. {metalist-0.18.0 → metalist-0.19.0}/app/services/search_history.py +25 -0
  13. {metalist-0.18.0 → metalist-0.19.0}/app/services/search_index.py +25 -3
  14. metalist-0.19.0/app/services/tag_details.py +224 -0
  15. {metalist-0.18.0 → metalist-0.19.0}/app/services/tag_suggestion_reasons.py +130 -66
  16. {metalist-0.18.0 → metalist-0.19.0}/app/services/tag_suggestions.py +19 -6
  17. {metalist-0.18.0 → metalist-0.19.0}/app/services/tag_term_matching.py +57 -0
  18. {metalist-0.18.0 → metalist-0.19.0}/app/static/css/main.css +62 -0
  19. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/api-client.js +46 -10
  20. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/config.js +2 -1
  21. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/context-menu/context-menu-registry.js +8 -19
  22. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/events/context-menu-events.js +58 -39
  23. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/events/keyboard-events.js +168 -10
  24. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/events/mouse-events.js +27 -2
  25. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/paste-format-detection-service.js +127 -1
  26. metalist-0.19.0/app/static/js/modules/mode-manager/services/paste-format-guess-service.js +317 -0
  27. metalist-0.19.0/app/static/js/modules/mode-manager/services/paste-format-offer-service.js +185 -0
  28. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/tag_proposals.py +1 -64
  29. {metalist-0.18.0 → metalist-0.19.0}/app/version.py +1 -1
  30. {metalist-0.18.0 → metalist-0.19.0/metalist.egg-info}/PKG-INFO +10 -1
  31. {metalist-0.18.0 → metalist-0.19.0}/metalist.egg-info/SOURCES.txt +3 -0
  32. {metalist-0.18.0 → metalist-0.19.0}/MANIFEST.in +0 -0
  33. {metalist-0.18.0 → metalist-0.19.0}/app/__init__.py +0 -0
  34. {metalist-0.18.0 → metalist-0.19.0}/app/api/__init__.py +0 -0
  35. {metalist-0.18.0 → metalist-0.19.0}/app/api/deps.py +0 -0
  36. {metalist-0.18.0 → metalist-0.19.0}/app/api/dev.py +0 -0
  37. {metalist-0.18.0 → metalist-0.19.0}/app/api/middleware/auth.py +0 -0
  38. {metalist-0.18.0 → metalist-0.19.0}/app/api/request_auth.py +0 -0
  39. {metalist-0.18.0 → metalist-0.19.0}/app/api/routes/ai.py +0 -0
  40. {metalist-0.18.0 → metalist-0.19.0}/app/api/routes/app_updates.py +0 -0
  41. {metalist-0.18.0 → metalist-0.19.0}/app/api/routes/auth.py +0 -0
  42. {metalist-0.18.0 → metalist-0.19.0}/app/api/routes/backups.py +0 -0
  43. {metalist-0.18.0 → metalist-0.19.0}/app/api/routes/files.py +0 -0
  44. {metalist-0.18.0 → metalist-0.19.0}/app/api/routes/ontology.py +0 -0
  45. {metalist-0.18.0 → metalist-0.19.0}/app/api/routes/reminders.py +0 -0
  46. {metalist-0.18.0 → metalist-0.19.0}/app/api/routes/remote_images.py +0 -0
  47. {metalist-0.18.0 → metalist-0.19.0}/app/api/routes/test.py +0 -0
  48. {metalist-0.18.0 → metalist-0.19.0}/app/api/transactions.py +0 -0
  49. {metalist-0.18.0 → metalist-0.19.0}/app/api/upload_limits.py +0 -0
  50. {metalist-0.18.0 → metalist-0.19.0}/app/config.py +0 -0
  51. {metalist-0.18.0 → metalist-0.19.0}/app/data_directory.py +0 -0
  52. {metalist-0.18.0 → metalist-0.19.0}/app/db/__init__.py +0 -0
  53. {metalist-0.18.0 → metalist-0.19.0}/app/db/backup_settings_sql.py +0 -0
  54. {metalist-0.18.0 → metalist-0.19.0}/app/db/editable_files_migration.py +0 -0
  55. {metalist-0.18.0 → metalist-0.19.0}/app/db/engine.py +0 -0
  56. {metalist-0.18.0 → metalist-0.19.0}/app/db/file_schema.py +0 -0
  57. {metalist-0.18.0 → metalist-0.19.0}/app/db/file_session.py +0 -0
  58. {metalist-0.18.0 → metalist-0.19.0}/app/db/files_sql.py +0 -0
  59. {metalist-0.18.0 → metalist-0.19.0}/app/db/link_titles_sql.py +0 -0
  60. {metalist-0.18.0 → metalist-0.19.0}/app/db/live_recovery.py +0 -0
  61. {metalist-0.18.0 → metalist-0.19.0}/app/db/migrations.py +0 -0
  62. {metalist-0.18.0 → metalist-0.19.0}/app/db/notes_sql.py +0 -0
  63. {metalist-0.18.0 → metalist-0.19.0}/app/db/ontology_rules_sql.py +0 -0
  64. {metalist-0.18.0 → metalist-0.19.0}/app/db/reminders_sql.py +0 -0
  65. {metalist-0.18.0 → metalist-0.19.0}/app/db/retire_sounds.py +0 -0
  66. {metalist-0.18.0 → metalist-0.19.0}/app/db/schema.py +0 -0
  67. {metalist-0.18.0 → metalist-0.19.0}/app/db/search_history_sql.py +0 -0
  68. {metalist-0.18.0 → metalist-0.19.0}/app/db/session.py +0 -0
  69. {metalist-0.18.0 → metalist-0.19.0}/app/db/settings_sql.py +0 -0
  70. {metalist-0.18.0 → metalist-0.19.0}/app/db/tab_state_sql.py +0 -0
  71. {metalist-0.18.0 → metalist-0.19.0}/app/db/version.py +0 -0
  72. {metalist-0.18.0 → metalist-0.19.0}/app/encryption_audit.py +0 -0
  73. {metalist-0.18.0 → metalist-0.19.0}/app/exception_boundaries.py +0 -0
  74. {metalist-0.18.0 → metalist-0.19.0}/app/https_proxy.py +0 -0
  75. {metalist-0.18.0 → metalist-0.19.0}/app/main.py +0 -0
  76. {metalist-0.18.0 → metalist-0.19.0}/app/models/commands.py +0 -0
  77. {metalist-0.18.0 → metalist-0.19.0}/app/models/database.py +0 -0
  78. {metalist-0.18.0 → metalist-0.19.0}/app/models/entities.py +0 -0
  79. {metalist-0.18.0 → metalist-0.19.0}/app/models/enums.py +0 -0
  80. {metalist-0.18.0 → metalist-0.19.0}/app/models/linked_list.py +0 -0
  81. {metalist-0.18.0 → metalist-0.19.0}/app/models/list_operations.py +0 -0
  82. {metalist-0.18.0 → metalist-0.19.0}/app/models/list_traversal.py +0 -0
  83. {metalist-0.18.0 → metalist-0.19.0}/app/models/note_crud.py +0 -0
  84. {metalist-0.18.0 → metalist-0.19.0}/app/models/utils.py +0 -0
  85. {metalist-0.18.0 → metalist-0.19.0}/app/network_settings.py +0 -0
  86. {metalist-0.18.0 → metalist-0.19.0}/app/presentation/__init__.py +0 -0
  87. {metalist-0.18.0 → metalist-0.19.0}/app/presentation/login_page.py +0 -0
  88. {metalist-0.18.0 → metalist-0.19.0}/app/presentation/render/__init__.py +0 -0
  89. {metalist-0.18.0 → metalist-0.19.0}/app/presentation/render/note_renderer.py +0 -0
  90. {metalist-0.18.0 → metalist-0.19.0}/app/presentation/templates.py +0 -0
  91. {metalist-0.18.0 → metalist-0.19.0}/app/security/authenticated_logging.py +0 -0
  92. {metalist-0.18.0 → metalist-0.19.0}/app/security/encryption.py +0 -0
  93. {metalist-0.18.0 → metalist-0.19.0}/app/security/http_error_diagnostics.py +0 -0
  94. {metalist-0.18.0 → metalist-0.19.0}/app/security/http_headers.py +0 -0
  95. {metalist-0.18.0 → metalist-0.19.0}/app/security/note_html.py +0 -0
  96. {metalist-0.18.0 → metalist-0.19.0}/app/security/request_boundary.py +0 -0
  97. {metalist-0.18.0 → metalist-0.19.0}/app/security/request_hosts.py +0 -0
  98. {metalist-0.18.0 → metalist-0.19.0}/app/security/sensitive_cache.py +0 -0
  99. {metalist-0.18.0 → metalist-0.19.0}/app/security/sensitive_logging.py +0 -0
  100. {metalist-0.18.0 → metalist-0.19.0}/app/security/shell_execution.py +0 -0
  101. {metalist-0.18.0 → metalist-0.19.0}/app/security/validation_errors.py +0 -0
  102. {metalist-0.18.0 → metalist-0.19.0}/app/server_runtime.py +0 -0
  103. {metalist-0.18.0 → metalist-0.19.0}/app/services/__init__.py +0 -0
  104. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/__init__.py +0 -0
  105. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/action_log.py +0 -0
  106. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/agent_loop.py +0 -0
  107. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/agent_tools.py +0 -0
  108. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/citation_tokens.py +0 -0
  109. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/cloud_privacy.py +0 -0
  110. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/context.py +0 -0
  111. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/evidence_serialization.py +0 -0
  112. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/execution_errors.py +0 -0
  113. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/failure_explanations.py +0 -0
  114. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/help_catalog.py +0 -0
  115. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/history.py +0 -0
  116. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/inference.py +0 -0
  117. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/investigation.py +0 -0
  118. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/judging.py +0 -0
  119. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/menu_actions.py +0 -0
  120. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/model_policy.py +0 -0
  121. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/note_aliases.py +0 -0
  122. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/openai_cost_tracking.py +0 -0
  123. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/openai_inference.py +0 -0
  124. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/prompt_settings.py +0 -0
  125. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/prompts/__init__.py +0 -0
  126. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/prompts/agent.md +0 -0
  127. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/prompts/final-response.md +0 -0
  128. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/prompts/system.md +0 -0
  129. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/release_notes.py +0 -0
  130. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/retrieval_settings.py +0 -0
  131. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/runtime.py +0 -0
  132. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/scope.py +0 -0
  133. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/skill_settings.py +0 -0
  134. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/skills/__init__.py +0 -0
  135. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/skills/help-ai.md +0 -0
  136. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/skills/help-data.md +0 -0
  137. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/skills/help-dictation.md +0 -0
  138. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/skills/help-menus.md +0 -0
  139. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/skills/help-privacy.md +0 -0
  140. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/skills/help-references.md +0 -0
  141. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/skills/help-reminders.md +0 -0
  142. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/skills/staged-summary.md +0 -0
  143. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/skills/tag-proposals.md +0 -0
  144. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/skills/web-browsing.md +0 -0
  145. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/staged_summary.py +0 -0
  146. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/strict_structured_outputs.py +0 -0
  147. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/structured_inference.py +0 -0
  148. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/summary_batch_store.py +0 -0
  149. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/tagging.py +0 -0
  150. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/tagging_run.py +0 -0
  151. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/token_estimation.py +0 -0
  152. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/tool_calling.py +0 -0
  153. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/trace.py +0 -0
  154. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/web_actions.py +0 -0
  155. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/web_capabilities.py +0 -0
  156. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/web_evidence.py +0 -0
  157. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/web_fetch.py +0 -0
  158. {metalist-0.18.0 → metalist-0.19.0}/app/services/agent/web_settings.py +0 -0
  159. {metalist-0.18.0 → metalist-0.19.0}/app/services/ai_chat.py +0 -0
  160. {metalist-0.18.0 → metalist-0.19.0}/app/services/ai_chat_rendering.py +0 -0
  161. {metalist-0.18.0 → metalist-0.19.0}/app/services/ai_chat_stream.py +0 -0
  162. {metalist-0.18.0 → metalist-0.19.0}/app/services/app_update_worker.py +0 -0
  163. {metalist-0.18.0 → metalist-0.19.0}/app/services/app_updates.py +0 -0
  164. {metalist-0.18.0 → metalist-0.19.0}/app/services/auth.py +0 -0
  165. {metalist-0.18.0 → metalist-0.19.0}/app/services/auth_cache_state.py +0 -0
  166. {metalist-0.18.0 → metalist-0.19.0}/app/services/auth_service.py +0 -0
  167. {metalist-0.18.0 → metalist-0.19.0}/app/services/backlink_index.py +0 -0
  168. {metalist-0.18.0 → metalist-0.19.0}/app/services/backlinks.py +0 -0
  169. {metalist-0.18.0 → metalist-0.19.0}/app/services/backup_service.py +0 -0
  170. {metalist-0.18.0 → metalist-0.19.0}/app/services/backup_settings_service.py +0 -0
  171. {metalist-0.18.0 → metalist-0.19.0}/app/services/bulk_operation.py +0 -0
  172. {metalist-0.18.0 → metalist-0.19.0}/app/services/chess_rendering.py +0 -0
  173. {metalist-0.18.0 → metalist-0.19.0}/app/services/client_state_service.py +0 -0
  174. {metalist-0.18.0 → metalist-0.19.0}/app/services/content_cache.py +0 -0
  175. {metalist-0.18.0 → metalist-0.19.0}/app/services/content_formatting.py +0 -0
  176. {metalist-0.18.0 → metalist-0.19.0}/app/services/diagnostics.py +0 -0
  177. {metalist-0.18.0 → metalist-0.19.0}/app/services/dictation_cleanup.py +0 -0
  178. {metalist-0.18.0 → metalist-0.19.0}/app/services/diff_rendering.py +0 -0
  179. {metalist-0.18.0 → metalist-0.19.0}/app/services/embedded_references.py +0 -0
  180. {metalist-0.18.0 → metalist-0.19.0}/app/services/encryption.py +0 -0
  181. {metalist-0.18.0 → metalist-0.19.0}/app/services/exception_capture.py +0 -0
  182. {metalist-0.18.0 → metalist-0.19.0}/app/services/file_edit_sessions.py +0 -0
  183. {metalist-0.18.0 → metalist-0.19.0}/app/services/file_registry.py +0 -0
  184. {metalist-0.18.0 → metalist-0.19.0}/app/services/file_storage.py +0 -0
  185. {metalist-0.18.0 → metalist-0.19.0}/app/services/file_text_preview.py +0 -0
  186. {metalist-0.18.0 → metalist-0.19.0}/app/services/footnote_layout.py +0 -0
  187. {metalist-0.18.0 → metalist-0.19.0}/app/services/footnote_rendering.py +0 -0
  188. {metalist-0.18.0 → metalist-0.19.0}/app/services/hierarchy.py +0 -0
  189. {metalist-0.18.0 → metalist-0.19.0}/app/services/html_export.py +0 -0
  190. {metalist-0.18.0 → metalist-0.19.0}/app/services/html_unformatting.py +0 -0
  191. {metalist-0.18.0 → metalist-0.19.0}/app/services/hydration_state.py +0 -0
  192. {metalist-0.18.0 → metalist-0.19.0}/app/services/image_size_formatting.py +0 -0
  193. {metalist-0.18.0 → metalist-0.19.0}/app/services/inline_image_dimensions.py +0 -0
  194. {metalist-0.18.0 → metalist-0.19.0}/app/services/inline_image_occurrences.py +0 -0
  195. {metalist-0.18.0 → metalist-0.19.0}/app/services/input_errors.py +0 -0
  196. {metalist-0.18.0 → metalist-0.19.0}/app/services/integrity.py +0 -0
  197. {metalist-0.18.0 → metalist-0.19.0}/app/services/latex_rendering.py +0 -0
  198. {metalist-0.18.0 → metalist-0.19.0}/app/services/link_title_retry.py +0 -0
  199. {metalist-0.18.0 → metalist-0.19.0}/app/services/link_titles.py +0 -0
  200. {metalist-0.18.0 → metalist-0.19.0}/app/services/login_rate_limit.py +0 -0
  201. {metalist-0.18.0 → metalist-0.19.0}/app/services/maintenance_mode.py +0 -0
  202. {metalist-0.18.0 → metalist-0.19.0}/app/services/mermaid_note_rendering.py +0 -0
  203. {metalist-0.18.0 → metalist-0.19.0}/app/services/namespace_deletion_jobs.py +0 -0
  204. {metalist-0.18.0 → metalist-0.19.0}/app/services/namespace_deletion_worker.py +0 -0
  205. {metalist-0.18.0 → metalist-0.19.0}/app/services/namespace_rename_jobs.py +0 -0
  206. {metalist-0.18.0 → metalist-0.19.0}/app/services/namespace_rename_worker.py +0 -0
  207. {metalist-0.18.0 → metalist-0.19.0}/app/services/namespace_runtime_guard.py +0 -0
  208. {metalist-0.18.0 → metalist-0.19.0}/app/services/namespace_switcher.py +0 -0
  209. {metalist-0.18.0 → metalist-0.19.0}/app/services/note_fullscreen.py +0 -0
  210. {metalist-0.18.0 → metalist-0.19.0}/app/services/note_image_tags.py +0 -0
  211. {metalist-0.18.0 → metalist-0.19.0}/app/services/note_ordering.py +0 -0
  212. {metalist-0.18.0 → metalist-0.19.0}/app/services/note_store.py +0 -0
  213. {metalist-0.18.0 → metalist-0.19.0}/app/services/ontology_rules_store.py +0 -0
  214. {metalist-0.18.0 → metalist-0.19.0}/app/services/openai_credentials.py +0 -0
  215. {metalist-0.18.0 → metalist-0.19.0}/app/services/password_note_fields.py +0 -0
  216. {metalist-0.18.0 → metalist-0.19.0}/app/services/public_http.py +0 -0
  217. {metalist-0.18.0 → metalist-0.19.0}/app/services/reference_presentation.py +0 -0
  218. {metalist-0.18.0 → metalist-0.19.0}/app/services/reminders.py +0 -0
  219. {metalist-0.18.0 → metalist-0.19.0}/app/services/remote_image_proxy.py +0 -0
  220. {metalist-0.18.0 → metalist-0.19.0}/app/services/request_recovery.py +0 -0
  221. {metalist-0.18.0 → metalist-0.19.0}/app/services/resource_limits.py +0 -0
  222. {metalist-0.18.0 → metalist-0.19.0}/app/services/root_sorting.py +0 -0
  223. {metalist-0.18.0 → metalist-0.19.0}/app/services/runtime_generation.py +0 -0
  224. {metalist-0.18.0 → metalist-0.19.0}/app/services/runtime_hardening.py +0 -0
  225. {metalist-0.18.0 → metalist-0.19.0}/app/services/runtime_lock.py +0 -0
  226. {metalist-0.18.0 → metalist-0.19.0}/app/services/search_history_storage.py +0 -0
  227. {metalist-0.18.0 → metalist-0.19.0}/app/services/search_query.py +0 -0
  228. {metalist-0.18.0 → metalist-0.19.0}/app/services/search_text.py +0 -0
  229. {metalist-0.18.0 → metalist-0.19.0}/app/services/selected_text_tag.py +0 -0
  230. {metalist-0.18.0 → metalist-0.19.0}/app/services/self_update.py +0 -0
  231. {metalist-0.18.0 → metalist-0.19.0}/app/services/session_timeout_service.py +0 -0
  232. {metalist-0.18.0 → metalist-0.19.0}/app/services/shell_session_service.py +0 -0
  233. {metalist-0.18.0 → metalist-0.19.0}/app/services/snapshot.py +0 -0
  234. {metalist-0.18.0 → metalist-0.19.0}/app/services/store.py +0 -0
  235. {metalist-0.18.0 → metalist-0.19.0}/app/services/structured_note_renderers.py +0 -0
  236. {metalist-0.18.0 → metalist-0.19.0}/app/services/sync.py +0 -0
  237. {metalist-0.18.0 → metalist-0.19.0}/app/services/sync_state.py +0 -0
  238. {metalist-0.18.0 → metalist-0.19.0}/app/services/tab_state.py +0 -0
  239. {metalist-0.18.0 → metalist-0.19.0}/app/services/tag_case.py +0 -0
  240. {metalist-0.18.0 → metalist-0.19.0}/app/services/tag_ontology.py +0 -0
  241. {metalist-0.18.0 → metalist-0.19.0}/app/services/tag_rename.py +0 -0
  242. {metalist-0.18.0 → metalist-0.19.0}/app/services/test_reset.py +0 -0
  243. {metalist-0.18.0 → metalist-0.19.0}/app/services/tokens.py +0 -0
  244. {metalist-0.18.0 → metalist-0.19.0}/app/services/undo_state.py +0 -0
  245. {metalist-0.18.0 → metalist-0.19.0}/app/services/update_backups.py +0 -0
  246. {metalist-0.18.0 → metalist-0.19.0}/app/services/update_installer.py +0 -0
  247. {metalist-0.18.0 → metalist-0.19.0}/app/services/update_preflight.py +0 -0
  248. {metalist-0.18.0 → metalist-0.19.0}/app/services/view_cache.py +0 -0
  249. {metalist-0.18.0 → metalist-0.19.0}/app/services/view_diff.py +0 -0
  250. {metalist-0.18.0 → metalist-0.19.0}/app/services/view_state.py +0 -0
  251. {metalist-0.18.0 → metalist-0.19.0}/app/services/windows_process_control.py +0 -0
  252. {metalist-0.18.0 → metalist-0.19.0}/app/startup_console.py +0 -0
  253. {metalist-0.18.0 → metalist-0.19.0}/app/startup_environment.py +0 -0
  254. {metalist-0.18.0 → metalist-0.19.0}/app/startup_js_sanity.py +0 -0
  255. {metalist-0.18.0 → metalist-0.19.0}/app/startup_sanity.py +0 -0
  256. {metalist-0.18.0 → metalist-0.19.0}/app/startup_sanity_config.py +0 -0
  257. {metalist-0.18.0 → metalist-0.19.0}/app/static/config/agent-menu-actions.json +0 -0
  258. {metalist-0.18.0 → metalist-0.19.0}/app/static/config/command_palette_tags.json +0 -0
  259. {metalist-0.18.0 → metalist-0.19.0}/app/static/css/floating-notes.css +0 -0
  260. {metalist-0.18.0 → metalist-0.19.0}/app/static/css/forms.css +0 -0
  261. {metalist-0.18.0 → metalist-0.19.0}/app/static/img/favicon.ico +0 -0
  262. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/locked.js +0 -0
  263. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/main.js +0 -0
  264. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/activity-tracker.js +0 -0
  265. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/ai-chat/agent-menu-actions.js +0 -0
  266. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/ai-chat/agent-retrieval-settings.js +0 -0
  267. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/ai-chat/agent-web-settings.js +0 -0
  268. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/ai-chat/ai-agent-debug-view.js +0 -0
  269. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/ai-chat/ai-chat-api.js +0 -0
  270. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/ai-chat/ai-chat-message-placement.js +0 -0
  271. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/ai-chat/ai-chat-panel-controller.js +0 -0
  272. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/ai-chat/ai-chat-panel-service.js +0 -0
  273. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/ai-chat/ai-thinking-level-service.js +0 -0
  274. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/ai-chat/bulk-elapsed-clock.js +0 -0
  275. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/ai-chat/bulk-proposal-ui.js +0 -0
  276. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/ai-chat/bulk-scope-question.js +0 -0
  277. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/ai-chat/cloud-privacy-policy.js +0 -0
  278. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/ai-chat/confirmation-card.js +0 -0
  279. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/ai-chat/confirmation-question.js +0 -0
  280. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/ai-chat/proposal-menu.js +0 -0
  281. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/ai-chat/summary-batch-preview.js +0 -0
  282. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/api-error-diagnostics.js +0 -0
  283. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/api-failure-classification-service.js +0 -0
  284. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/app-update-service.js +0 -0
  285. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/application-state.js +0 -0
  286. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/async-result.js +0 -0
  287. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/auth.js +0 -0
  288. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/client-state-api.js +0 -0
  289. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/client-state-migration.js +0 -0
  290. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/command-palette/activation-auth-policy.js +0 -0
  291. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/command-palette/backup-command-availability.js +0 -0
  292. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/command-palette/click-activation-service.js +0 -0
  293. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/command-palette/command-palette-controller.js +0 -0
  294. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/command-palette/endpoint-registry.js +0 -0
  295. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/command-palette/note-layout-preferences.js +0 -0
  296. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/command-palette/preferences-store.js +0 -0
  297. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/command-palette/tag-config-loader.js +0 -0
  298. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/command-palette/usage-store.js +0 -0
  299. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/connectivity-monitor.js +0 -0
  300. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/context-menu/context-menu-service.js +0 -0
  301. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/context-menu/context-menu-target-service.js +0 -0
  302. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/context-menu/input-caret-service.js +0 -0
  303. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/disconnect-editing-state-service.js +0 -0
  304. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/dom-utils-fixed.js +0 -0
  305. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/dom-utils.js +0 -0
  306. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/editor-commands.js +0 -0
  307. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/editor-selection.js +0 -0
  308. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/editor-toolbar.js +0 -0
  309. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/elapsed-time.js +0 -0
  310. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/error-handler.js +0 -0
  311. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/error-overlay.js +0 -0
  312. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/excalidraw/excalidraw-actions.js +0 -0
  313. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/excalidraw/excalidraw-autosave.js +0 -0
  314. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/excalidraw/excalidraw-editor-service.js +0 -0
  315. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/excalidraw/excalidraw-editor-state.js +0 -0
  316. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/excalidraw/excalidraw-loader.js +0 -0
  317. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/excalidraw/excalidraw-preview-service.js +0 -0
  318. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/excalidraw/excalidraw-scene.js +0 -0
  319. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/expected-errors.js +0 -0
  320. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/location-flags.js +0 -0
  321. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/login-namespace-picker.js +0 -0
  322. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/maintenance.js +0 -0
  323. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/ai-agent-settings-modal.js +0 -0
  324. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/alphabetize-root-notes-modal.js +0 -0
  325. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/backup-restore-modal.js +0 -0
  326. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/backup-result-modal.js +0 -0
  327. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/backup-retention-modal.js +0 -0
  328. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/backup-settings-modal.js +0 -0
  329. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/base-modal.js +0 -0
  330. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/confirmation-modal.js +0 -0
  331. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/delete-namespace-modal.js +0 -0
  332. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/delete-namespace-validation.js +0 -0
  333. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/dictation-settings-modal.js +0 -0
  334. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/help-modal.js +0 -0
  335. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/link-title-retry-modal.js +0 -0
  336. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/namespace-loading-page.js +0 -0
  337. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/namespace-modals.js +0 -0
  338. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/namespace-ports-profile.js +0 -0
  339. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/namespace-rename-validation.js +0 -0
  340. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/note-layout-appearance-modal.js +0 -0
  341. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/ontology-modal.js +0 -0
  342. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/password-modal.js +0 -0
  343. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/prioritize-modal.js +0 -0
  344. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/random-password-modal.js +0 -0
  345. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/reminder-modal.js +0 -0
  346. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/reset-updated-at-modal.js +0 -0
  347. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/search-suggestion-statistics-modal.js +0 -0
  348. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/session-timeout-modal.js +0 -0
  349. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/tag-suggestion-settings-modal.js +0 -0
  350. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/version-info-modal.js +0 -0
  351. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/modals/visual-cues-modal.js +0 -0
  352. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/actions/content-actions.js +0 -0
  353. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/actions/history-actions.js +0 -0
  354. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/actions/note-actions.js +0 -0
  355. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/actions/search-actions.js +0 -0
  356. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/actions/selection-actions.js +0 -0
  357. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/actions/ui-actions.js +0 -0
  358. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/events/focus-events.js +0 -0
  359. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/events/inactivity-events.js +0 -0
  360. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/events/input-events.js +0 -0
  361. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/events/search-events.js +0 -0
  362. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/mode-context.js +0 -0
  363. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/mode-logger.js +0 -0
  364. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/mode-manager-controller.js +0 -0
  365. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/add-style-service.js +0 -0
  366. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/animated-scroll-service.js +0 -0
  367. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/backlinks-navigation-service.js +0 -0
  368. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/backlinks-panel-service.js +0 -0
  369. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/clipboard-shortcut-policy-service.js +0 -0
  370. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/collapse-affordance-service.js +0 -0
  371. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/collapse-editing-policy-service.js +0 -0
  372. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/command-gate-service.js +0 -0
  373. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/context-menu-target-service.js +0 -0
  374. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/deselect-selection-state-service.js +0 -0
  375. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/dictation-note-paste.js +0 -0
  376. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/dictation-paste-padding.js +0 -0
  377. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/dictation-paste-service.js +0 -0
  378. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/differential-view-service.js +0 -0
  379. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/dropped-file-preview-service.js +0 -0
  380. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/edit-session-collapse-policy-service.js +0 -0
  381. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/edit-session-collapse-service.js +0 -0
  382. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/embedded-image-service.js +0 -0
  383. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/file-drop-policy-service.js +0 -0
  384. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/file-image-preview-service.js +0 -0
  385. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/file-reference-service.js +0 -0
  386. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/filtered-refresh-selection-service.js +0 -0
  387. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/floating-note-dom.js +0 -0
  388. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/floating-note-layout.js +0 -0
  389. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/floating-note-service.js +0 -0
  390. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/footnote-navigation-service.js +0 -0
  391. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/history-selection-policy-service.js +0 -0
  392. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/history-shortcut-policy-service.js +0 -0
  393. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/html-paste-sanitizer-service.js +0 -0
  394. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/image-context-menu-action-service.js +0 -0
  395. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/image-file-insert-choice-modal-service.js +0 -0
  396. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/infinite-scroll-service.js +0 -0
  397. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/link-context-menu-action-service.js +0 -0
  398. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/link-title-prefetch-service.js +0 -0
  399. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/markdown-render-service.js +0 -0
  400. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/mermaid-render-service.js +0 -0
  401. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/note-click-target-service.js +0 -0
  402. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/note-clipboard-write-service.js +0 -0
  403. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/note-collapse-animation-service.js +0 -0
  404. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/note-context-menu-action-service.js +0 -0
  405. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/note-delete-shortcut-policy-service.js +0 -0
  406. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/note-drag-indicator-service.js +0 -0
  407. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/note-drag-service.js +0 -0
  408. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/note-fullscreen-service.js +0 -0
  409. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/note-reposition-animation-service.js +0 -0
  410. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/note-split-service.js +0 -0
  411. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/note-timestamp-hover-service.js +0 -0
  412. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/password-clipboard-service.js +0 -0
  413. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/polling-service.js +0 -0
  414. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/reference-source-navigation-service.js +0 -0
  415. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/remote-image-proxy-service.js +0 -0
  416. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/remove-formatting-service.js +0 -0
  417. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/root-date-separator-service.js +0 -0
  418. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/root-note-creation-service.js +0 -0
  419. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/root-sort-indicator-service.js +0 -0
  420. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/root-sort-service.js +0 -0
  421. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/scroll-anchor-service.js +0 -0
  422. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/scroll-restoration-service.js +0 -0
  423. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/scroll-to-top-service.js +0 -0
  424. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/search-contexts-overlay-service.js +0 -0
  425. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/search-debounce-service.js +0 -0
  426. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/search-input-service.js +0 -0
  427. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/search-interaction-service.js +0 -0
  428. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/search-redaction-reveal-service.js +0 -0
  429. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/search-suggestion-statistics-service.js +0 -0
  430. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/search-suggestion-window-labels-service.js +0 -0
  431. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/search-suggestion-windows-service.js +0 -0
  432. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/search-suggestions-service.js +0 -0
  433. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/search-syntax-service.js +0 -0
  434. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/selected-formatting-removal-service.js +0 -0
  435. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/selected-text-tag-service.js +0 -0
  436. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/shell-output-service.js +0 -0
  437. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/tab-dom-cache-service.js +0 -0
  438. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/tab-drag-service.js +0 -0
  439. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/tab-duplication-service.js +0 -0
  440. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/tab-state-service.js +0 -0
  441. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/tag-bar-service.js +0 -0
  442. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/tag-input-selection-service.js +0 -0
  443. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/tag-proposal-service.js +0 -0
  444. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/tag-suggestions-service.js +0 -0
  445. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/tag-syntax-service.js +0 -0
  446. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/todo-toggle-editing-service.js +0 -0
  447. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/untagged-view-indicator-service.js +0 -0
  448. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/view-mode-search-shortcut-service.js +0 -0
  449. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/mode-manager/services/viewport-hold-service.js +0 -0
  450. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/note-html-sanitizer.js +0 -0
  451. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/password-generator.js +0 -0
  452. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/password-operation-response.js +0 -0
  453. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/password-policy.js +0 -0
  454. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/password-strength.js +0 -0
  455. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/reminder-store.js +0 -0
  456. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/reminder-surface-service.js +0 -0
  457. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/selection-markers.js +0 -0
  458. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/session-auth.js +0 -0
  459. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/tag-token.js +0 -0
  460. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/modules/uuid.js +0 -0
  461. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/namespace-deleted.js +0 -0
  462. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/namespace-renamed.js +0 -0
  463. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/dompurify-3.4.16.LICENSE.txt +0 -0
  464. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/dompurify-3.4.16.min.js +0 -0
  465. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/excalidraw.css +0 -0
  466. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-Bold.woff2 +0 -0
  467. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-Medium.woff2 +0 -0
  468. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-Regular.woff2 +0 -0
  469. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Assistant/Assistant-SemiBold.woff2 +0 -0
  470. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Cascadia/CascadiaCode-Regular.woff2 +0 -0
  471. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-279a7b317d12eb88de06167bd672b4b4.woff2 +0 -0
  472. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-6e066e8de2ac57ea9283adb9c24d7f0c.woff2 +0 -0
  473. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-dc6a8806fa96795d7b3be5026f989a17.woff2 +0 -0
  474. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/ComicShanns/ComicShanns-Regular-fcb0fc02dcbee4c9846b3e2508668039.woff2 +0 -0
  475. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-349fac6ca4700ffec595a7150a0d1e1d.woff2 +0 -0
  476. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-3f2c5db56cc93c5a6873b1361d730c16.woff2 +0 -0
  477. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-41b173a47b57366892116a575a43e2b6.woff2 +0 -0
  478. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-623ccf21b21ef6b3a0d87738f77eb071.woff2 +0 -0
  479. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-a88b72a24fb54c9f94e3b5fdaa7481c9.woff2 +0 -0
  480. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-b9dcf9d2e50a1eaf42fc664b50a3fd0d.woff2 +0 -0
  481. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Excalifont/Excalifont-Regular-be310b9bcd4f1a43f571c46df7809174.woff2 +0 -0
  482. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYE98RXi4EwSsbg.woff2 +0 -0
  483. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Lilita/Lilita-Regular-i7dPIFZ9Zz-WBtRtedDbYEF8RXi4EwQ.woff2 +0 -0
  484. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTA3j6zbXWjgevT5.woff2 +0 -0
  485. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTQ3j6zbXWjgeg.woff2 +0 -0
  486. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTk3j6zbXWjgevT5.woff2 +0 -0
  487. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTo3j6zbXWjgevT5.woff2 +0 -0
  488. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Nunito/Nunito-Regular-XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTs3j6zbXWjgevT5.woff2 +0 -0
  489. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1-assets/fonts/Virgil/Virgil-Regular.woff2 +0 -0
  490. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1.LICENSE.txt +0 -0
  491. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/excalidraw-0.18.1.min.js +0 -0
  492. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/markdown-it-14.3.2.LICENSE.txt +0 -0
  493. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/markdown-it-14.3.2.min.js +0 -0
  494. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/mermaid-11.16.1.LICENSE.txt +0 -0
  495. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/mermaid-11.16.1.min.js +0 -0
  496. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/zxcvbn-4.4.2.LICENSE.txt +0 -0
  497. {metalist-0.18.0 → metalist-0.19.0}/app/static/js/vendor/zxcvbn-4.4.2.js +0 -0
  498. {metalist-0.18.0 → metalist-0.19.0}/app/static/note-html-policy.json +0 -0
  499. {metalist-0.18.0 → metalist-0.19.0}/app/templates/_logo_mark.html +0 -0
  500. {metalist-0.18.0 → metalist-0.19.0}/app/templates/base.html +0 -0
  501. {metalist-0.18.0 → metalist-0.19.0}/app/templates/index.html +0 -0
  502. {metalist-0.18.0 → metalist-0.19.0}/app/templates/locked.html +0 -0
  503. {metalist-0.18.0 → metalist-0.19.0}/app/templates/maintenance.html +0 -0
  504. {metalist-0.18.0 → metalist-0.19.0}/app/templates/namespace_deleted.html +0 -0
  505. {metalist-0.18.0 → metalist-0.19.0}/app/templates/namespace_renamed.html +0 -0
  506. {metalist-0.18.0 → metalist-0.19.0}/app/templates/notes_list.html +0 -0
  507. {metalist-0.18.0 → metalist-0.19.0}/app/upload_limits.py +0 -0
  508. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/__init__.py +0 -0
  509. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/add_selected_text_tag.py +0 -0
  510. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/alphabetize_root_notes.py +0 -0
  511. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/base.py +0 -0
  512. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/bulk_tag_proposals.py +0 -0
  513. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/collapse.py +0 -0
  514. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/copy_note.py +0 -0
  515. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/create_child.py +0 -0
  516. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/create_file_preview_child.py +0 -0
  517. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/create_note.py +0 -0
  518. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/create_sibling.py +0 -0
  519. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/delete_subtree.py +0 -0
  520. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/delete_tag.py +0 -0
  521. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/expand.py +0 -0
  522. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/file_edit_session.py +0 -0
  523. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/indent.py +0 -0
  524. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/lock.py +0 -0
  525. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/move.py +0 -0
  526. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/move_to_top.py +0 -0
  527. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/outdent.py +0 -0
  528. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/paste_child.py +0 -0
  529. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/paste_sibling.py +0 -0
  530. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/prefetch_link_titles.py +0 -0
  531. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/prioritize.py +0 -0
  532. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/redo.py +0 -0
  533. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/rename_tag.py +0 -0
  534. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/reset_updated_at.py +0 -0
  535. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/resize_image.py +0 -0
  536. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/run_shell.py +0 -0
  537. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/search_comment_autofill.py +0 -0
  538. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/search_context_tags.py +0 -0
  539. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/set_collapse_bulk.py +0 -0
  540. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/set_collapse_in_context.py +0 -0
  541. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/split_note.py +0 -0
  542. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/toggle_reference_mode.py +0 -0
  543. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/toggle_todo_done.py +0 -0
  544. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/undo.py +0 -0
  545. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/unformat_content.py +0 -0
  546. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/update_content.py +0 -0
  547. {metalist-0.18.0 → metalist-0.19.0}/app/usecases/view.py +0 -0
  548. {metalist-0.18.0 → metalist-0.19.0}/app/utils/__init__.py +0 -0
  549. {metalist-0.18.0 → metalist-0.19.0}/app/utils/encryption.py +0 -0
  550. {metalist-0.18.0 → metalist-0.19.0}/app/utils/text_utils.py +0 -0
  551. {metalist-0.18.0 → metalist-0.19.0}/convert-from-legacy.py +0 -0
  552. {metalist-0.18.0 → metalist-0.19.0}/main.py +0 -0
  553. {metalist-0.18.0 → metalist-0.19.0}/metalist.egg-info/dependency_links.txt +0 -0
  554. {metalist-0.18.0 → metalist-0.19.0}/metalist.egg-info/entry_points.txt +0 -0
  555. {metalist-0.18.0 → metalist-0.19.0}/metalist.egg-info/requires.txt +0 -0
  556. {metalist-0.18.0 → metalist-0.19.0}/metalist.egg-info/top_level.txt +0 -0
  557. {metalist-0.18.0 → metalist-0.19.0}/pyproject.toml +0 -0
  558. {metalist-0.18.0 → metalist-0.19.0}/scripts/generate-lan-cert.sh +0 -0
  559. {metalist-0.18.0 → metalist-0.19.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: metalist
3
- Version: 0.18.0
3
+ Version: 0.19.0
4
4
  Summary: A minimalist single-user note-taking app with SSR, fast in-memory tree operations, and efficient sync.
5
5
  Project-URL: Homepage, https://github.com/evolvingstuff/metalist
6
6
  Project-URL: Repository, https://github.com/evolvingstuff/metalist
@@ -51,6 +51,15 @@ A minimalist single-user note-taking app focused on server-side rendering (SSR),
51
51
  - Multi-tab search contexts with server-persisted scroll/search state (survives browser restarts)
52
52
  - Manual namespace backups/restores to a user-selected backup folder with retention controls
53
53
 
54
+ ## Changes in 0.19.0
55
+
56
+ - Paste formats: pasting a fenced code block that names its language tags the note `@markdown`, and `@markdown` now colours that code like `@code=<language>` (with its label). Code copied from VS Code is tagged `@code=<its language>`, and cells copied from Excel, Google Sheets or Numbers become CSV text tagged `@csv`.
57
+ - Text that only looks like a format is offered, not applied: after pasting CSV-like, Markdown-like or code-like text, a small card says "Apply as CSV" / "Apply as Markdown" / "Apply as Python" (up to three close languages for code) with "Skip". The card moves nothing and never takes the keyboard; typing on, Escape or a click elsewhere closes it. It also appears when the paste makes a new note.
58
+ - Right-click a tag already in the tag bar or the search box for **About this tag**: whether the note names it, the notes it shares with your other tags, whether a parent or a rule already gives it, its synonyms and implications, how many notes have it ("Only on this note" hints at a typo); in the search box, what it finds and what leaving it out removes. Edit Tag Relationships now comes first in the tag menu, at a fixed place under the pointer.
59
+ - Tag suggestions: a web address in a note counts only by its site's name, so a YouTube link no longer suggests `HTTPS` or `V-neuron`; one letter alone no longer names a tag with longer words. A suggestion without evidence now says only what is true (what you typed matches, which part of its name the note has) instead of "Nothing in this note points to it".
60
+ - Fixed: accepting a Grammarly suggestion while editing could undo itself and end editing, when Grammarly drew its card in an element MetaList did not recognise.
61
+ - Removed the "Make pseudo-suggestions" test item from the note menu.
62
+
54
63
  ## Changes in 0.18.0
55
64
 
56
65
  - Right-click a tag suggestion, in the tag bar or the search bar, to see why it is suggested. The menu starts with **Why suggested**: the words of the note that name the tag (or a synonym), the tags it goes with and on how many notes, notes sharing this note's tags, whether it already applies through a parent or a rule, or that nothing in the note points to it; then how often the tag is used. Search suggestions also say how often you worked with a tag lately (when that put it first), what your search so far finds, or what leaving it out removes. The reasons are MetaList's own ranking, not the AI's, and appear instantly.
@@ -12,6 +12,15 @@ A minimalist single-user note-taking app focused on server-side rendering (SSR),
12
12
  - Multi-tab search contexts with server-persisted scroll/search state (survives browser restarts)
13
13
  - Manual namespace backups/restores to a user-selected backup folder with retention controls
14
14
 
15
+ ## Changes in 0.19.0
16
+
17
+ - Paste formats: pasting a fenced code block that names its language tags the note `@markdown`, and `@markdown` now colours that code like `@code=<language>` (with its label). Code copied from VS Code is tagged `@code=<its language>`, and cells copied from Excel, Google Sheets or Numbers become CSV text tagged `@csv`.
18
+ - Text that only looks like a format is offered, not applied: after pasting CSV-like, Markdown-like or code-like text, a small card says "Apply as CSV" / "Apply as Markdown" / "Apply as Python" (up to three close languages for code) with "Skip". The card moves nothing and never takes the keyboard; typing on, Escape or a click elsewhere closes it. It also appears when the paste makes a new note.
19
+ - Right-click a tag already in the tag bar or the search box for **About this tag**: whether the note names it, the notes it shares with your other tags, whether a parent or a rule already gives it, its synonyms and implications, how many notes have it ("Only on this note" hints at a typo); in the search box, what it finds and what leaving it out removes. Edit Tag Relationships now comes first in the tag menu, at a fixed place under the pointer.
20
+ - Tag suggestions: a web address in a note counts only by its site's name, so a YouTube link no longer suggests `HTTPS` or `V-neuron`; one letter alone no longer names a tag with longer words. A suggestion without evidence now says only what is true (what you typed matches, which part of its name the note has) instead of "Nothing in this note points to it".
21
+ - Fixed: accepting a Grammarly suggestion while editing could undo itself and end editing, when Grammarly drew its card in an element MetaList did not recognise.
22
+ - Removed the "Make pseudo-suggestions" test item from the note menu.
23
+
15
24
  ## Changes in 0.18.0
16
25
 
17
26
  - Right-click a tag suggestion, in the tag bar or the search bar, to see why it is suggested. The menu starts with **Why suggested**: the words of the note that name the tag (or a synonym), the tags it goes with and on how many notes, notes sharing this note's tags, whether it already applies through a parent or a rule, or that nothing in the note points to it; then how often the tag is used. Search suggestions also say how often you worked with a tag lately (when that put it first), what your search so far finds, or what leaving it out removes. The reasons are MetaList's own ranking, not the AI's, and appear instantly.
@@ -127,6 +127,22 @@ class TagSuggestionsRequest(TypedDict):
127
127
  prefix: Text
128
128
  content_html: Content
129
129
 
130
+ @with_config(ConfigDict(strict=True))
131
+ class TagDetailsRequest(TypedDict):
132
+ note_id: Identifier
133
+ tag: Identifier
134
+ tags_text: Text
135
+ content_html: Content
136
+
137
+ @with_config(ConfigDict(strict=True))
138
+ class SearchTagDetailsRequest(TypedDict):
139
+ query: Text
140
+ tag: Identifier
141
+ start: Nonnegative
142
+ end: Nonnegative
143
+ excluded: bool
144
+ windowDays: WindowDays
145
+
130
146
  @with_config(ConfigDict(strict=True))
131
147
  class CreateNoteTopRequest(TypedDict):
132
148
  first_visible_note_id: Text | None
@@ -180,12 +196,6 @@ class AddSelectedTextTagRequest(TypedDict):
180
196
  undoContext: UndoContext
181
197
  viewport: Viewport
182
198
 
183
- @with_config(ConfigDict(strict=True))
184
- class MakePseudoTagProposalsRequest(TypedDict):
185
- clientId: Identifier
186
- undoContext: UndoContext
187
- viewport: Viewport
188
-
189
199
  @with_config(ConfigDict(strict=True))
190
200
  class AcceptTagProposalRequest(TypedDict):
191
201
  proposal: Identifier
@@ -20,6 +20,8 @@ from app.api.note_requests import (
20
20
  SearchSuggestionInteractionRequest,
21
21
  TabSearchInteractionRequest,
22
22
  TagSuggestionsRequest,
23
+ TagDetailsRequest,
24
+ SearchTagDetailsRequest,
23
25
  DictationPasteRequest,
24
26
  CreateNoteTopRequest,
25
27
  CreateSiblingRequest,
@@ -28,7 +30,6 @@ from app.api.note_requests import (
28
30
  UpdateNoteRequest,
29
31
  SaveNoteRequest,
30
32
  AddSelectedTextTagRequest,
31
- MakePseudoTagProposalsRequest,
32
33
  AcceptTagProposalRequest,
33
34
  RejectTagProposalRequest,
34
35
  SplitNoteRequest,
@@ -77,7 +78,6 @@ from app.services.link_title_retry import (
77
78
  from app.usecases.add_selected_text_tag import CmdAddSelectedTextTag
78
79
  from app.usecases.tag_proposals import (
79
80
  CmdAcceptTagProposal,
80
- CmdMakePseudoTagProposals,
81
81
  CmdRejectTagProposal,
82
82
  )
83
83
  from app.usecases.delete_subtree import CmdDeleteSubtree
@@ -138,6 +138,8 @@ from app.services.note_fullscreen import build_note_fullscreen_markup
138
138
  from app.services.link_titles import link_title_store
139
139
  from app.services.search_index import search_index
140
140
  from app.services.dictation_cleanup import clean_dictated_paste
141
+ from app.services.tag_details import describe_search_tag
142
+ from app.services.tag_details import describe_tag_bar_tag
141
143
  from app.services.tag_suggestion_reasons import search_suggestion_reasons
142
144
  from app.services.tag_suggestions import suggest_tags_with_reasons_for_note
143
145
  from app.services.client_state_service import suggests_already_applying_tags
@@ -654,6 +656,32 @@ def tag_suggestions(request: Request, payload: TagSuggestionsRequest) -> Dict[st
654
656
  }
655
657
 
656
658
 
659
+ @router.post("/notes/tag-details")
660
+ @transactional_route
661
+ def tag_details(payload: TagDetailsRequest) -> Dict[str, object]:
662
+ """About a tag in a note's tag bar, shown when it is right-clicked (docs/ui/tag-bar.md)."""
663
+ note_id = payload["note_id"]
664
+ _require_note_present(note_id, context="notes.tag-details")
665
+ lines = describe_tag_bar_tag(
666
+ note_id=note_id, tag=payload["tag"], tags_text=payload["tags_text"], content_html=payload["content_html"],
667
+ )
668
+ return {"lines": list(lines)}
669
+
670
+
671
+ @router.post("/notes/search-tag-details")
672
+ @transactional_route
673
+ def search_tag_details(request: Request, payload: SearchTagDetailsRequest) -> Dict[str, object]:
674
+ """About a tag in the search box, shown when it is right-clicked (docs/ui/controls.md)."""
675
+ window_days = tuple(payload["windowDays"])
676
+ validate_tag_activity_windows(window_days)
677
+ lines = describe_search_tag(
678
+ query=payload["query"], tag=payload["tag"], start=payload["start"], end=payload["end"],
679
+ is_excluded=payload["excluded"], window_days=window_days,
680
+ token=_require_bearer_token(request), today=current_local_date(),
681
+ )
682
+ return {"lines": list(lines)}
683
+
684
+
657
685
  @router.get("/notes/export-html")
658
686
  def export_notes_html(request: Request) -> Response:
659
687
  token = _require_bearer_token(request)
@@ -914,21 +942,6 @@ def add_selected_text_tag(request: Request, note_id: str, body: AddSelectedTextT
914
942
  return response
915
943
 
916
944
 
917
- @router.post("/notes/{note_id}/tag-proposals/pseudo")
918
- @transactional_route
919
- def make_pseudo_tag_proposals(request: Request, note_id: str, body: MakePseudoTagProposalsRequest):
920
- token = _require_bearer_token(request)
921
- viewport = _require_viewport(body)
922
- _require_note_present(note_id, context="notes.tag-proposals.pseudo")
923
- return CmdMakePseudoTagProposals(
924
- note_id=note_id,
925
- token=token,
926
- client_id=body["clientId"],
927
- undo_context=body["undoContext"],
928
- viewport=viewport,
929
- ).execute()
930
-
931
-
932
945
  def _execute_tag_proposal_mutation(*, command: QueryCommand) -> Dict[str, object]:
933
946
  return command.execute()
934
947
 
@@ -145,6 +145,7 @@ Other (non-meta) tags may also appear inside wrapper tokens (e.g. `{{foo bar}}`)
145
145
  ## Markdown meta tags
146
146
  - `@markdown`: renders the note content as Markdown in view mode on the server.
147
147
  - Scoped Markdown renders only the matching wrapped region.
148
+ - Fenced code that names a language (```` ```python ````, ```` ```js ````, any language name or alias `@code=` accepts, in any case) is coloured as `@code=<language>` colours it, with the language label above the block. A fence with no language, or one naming plain text (`text`, `output`, `console`) or a language MetaList does not know, stays plain, with no badge. Fenced `mermaid` blocks are unaffected.
148
149
  - Fenced `mermaid` blocks render as responsive SVG diagrams in the app. They use a compact layout (13 px labels and tight spacing between nodes and rows); diagrams are never capped or scaled to fit, so large ones keep all their detail. The pinned Mermaid runtime loads locally and only when a visible note contains a Mermaid fence; no diagram source is sent to a CDN or external service.
149
150
  - In a help answer, show the literal Mermaid source the user must type: open an outer `text` block with four backticks, put the triple-backtick `mermaid` block inside it, close that inner block with three backticks, and close the outer block with four backticks before returning to prose. Never use only three backticks for the outer block. A direct `mermaid` fence renders as a diagram in AI chat instead of displaying its source.
150
151
  - Do not promise support for named Mermaid diagram families that this reference does not document. Use a basic flowchart for the example and describe Mermaid support generically.
@@ -209,9 +210,23 @@ Other (non-meta) tags may also appear inside wrapper tokens (e.g. `{{foo bar}}`)
209
210
  - JSON (a complete object or array) → `@json`
210
211
  - a chess FEN position → `@chess`
211
212
  - a unified diff (with `@@` section lines, `---`/`+++` headers, or `diff --git`) → `@diff`
212
- - Mermaid starting with a diagram keyword (`graph TD`, `sequenceDiagram`, `gantt`...) → `@mermaid`; a fenced ```` ```mermaid ```` block → `@markdown`
213
+ - Mermaid starting with a diagram keyword (`graph TD`, `sequenceDiagram`, `gantt`...) → `@mermaid`
214
+ - a fenced code block naming its language (```` ```python ````, ```` ```mermaid ````), alone or with text around it → `@markdown` (the fence says it is Markdown; a bare ```` ``` ```` or an unclosed fence is not enough)
213
215
  - a pure LaTeX block (`$$...$$`, `\[...\]`, or `\begin{...}...\end{...}`) → `@LaTeX`
216
+ - code copied from VS Code (two lines or more) → `@code=<its language>`, from the language VS Code puts on the clipboard (`vscode-editor-data`): `@code=python`, `@code=bash` for shell scripts, `@markdown` for Markdown files; JSON that parses stays `@json`; plain text and unlisted languages get nothing
217
+ - cells copied from a spreadsheet (Excel, Google Sheets, Numbers: an HTML table on the clipboard) → the cells as CSV text (commas, quoting cells that hold commas, quotes or line breaks) and `@csv`
214
218
  - Into an otherwise empty note (or with all of its text selected), and when pasting creates a new note, the plain tag is added. Into a note with content, the pasted text is wrapped `((...))` and `((@json))` (etc.) is added, so the existing text is untouched.
215
- - Nothing is added for anything uncertain (prose, code, CSV, JSON-looking text that does not parse), when the note already has a renderer tag, when pasting inside an existing wrapped region, or when `((...))` is already in use in that note.
219
+ - Nothing is added at once for anything uncertain (prose, JSON-looking text that does not parse); CSV-like, Markdown-like and code-like text is offered instead (see below). Nothing is added or offered when the note already has a renderer tag, when pasting inside an existing wrapped region, or when `((...))` is already in use in that note.
216
220
  - `⌘Z` right after the paste removes the added tag together with the pasted text (one undo step, like a normal paste). `⇧⌘V` (Ctrl+Shift+V) pastes as plain text without detection.
217
221
  - Implementation: `paste-format-detection-service.js` (detection and planning, tests in `tests/unit/paste_format_detection.test.mjs`), wired in `keyboard-events.js`.
222
+
223
+ ## Paste format guesses
224
+ - 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.
225
+ - What is offered:
226
+ - 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`.
227
+ - 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.
228
+ - 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.
229
+ - 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`.
230
+ - 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.
231
+ - 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).
232
+ - `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.
@@ -172,7 +172,7 @@ On macOS, `⌘ + Y` normally opens Safari History rather than performing native
172
172
  | Right-click image in note | Adds image actions to the note context menu: `Copy Image`, `Save Image`, `Zoom Image`, `Open Image in New Tab` |
173
173
  | Right-click anywhere in a completed AI response bubble (including padding and links) | Choose `Copy Response` to place its raw Markdown on the MetaList note clipboard with `@markdown @llm`, while also writing rendered HTML and raw Markdown to the system clipboard. It can be pasted as a note but not as a reference until inserted. |
174
174
  | Right-click notes view background | Open the view menu: outside edit mode `Add Note at Top`, `Paste Note at Top` (once a note is copied), `Undo`, `Redo`; `Go to Top`, `Go to Bottom` (unless at that end), `Fully Expand All`, `Fully Collapse All`; `View ▸` (All / Untagged notes), `Sort by ▸`, `Show ▸` (Chat, Tabs, Tags in List), `Theme ▸` (System, Light, Dark), each ticking the current choice; `New Tab`, `Open/Switch Namespace…`, `Reminders…`; `Export View as HTML`; `Log Out`. Shortcuts show on the right; items that do not apply are hidden. |
175
- | Right-click tag in search input, tag bar, or their suggestion lists | Open tag context menu (Edit Tag Relationships); a suggestion's menu (tag bar or search) starts with **Why suggested**. A suggestion list, the typed letters and edit mode stay as they were. Choosing Edit Tag Relationships saves an edited note first and completes the view refresh, restoring view-only rendering such as cached URL titles. |
175
+ | Right-click tag in search input, tag bar, or their suggestion lists | Open tag context menu (Edit Tag Relationships); below it a suggestion's menu (tag bar or search) says **Why suggested**, a tag already in the tag bar or search box **About this tag**. A suggestion list, the typed letters and edit mode stay as they were. Choosing Edit Tag Relationships saves an edited note first and completes the view refresh, restoring view-only rendering such as cached URL titles. |
176
176
  | Right-click left or right lane | Open the same view menu |
177
177
  | Hover left side of search bar | Show the tab/search-context overlay |
178
178
  | Hover/click search input | Hide the tab/search-context overlay |
@@ -5,6 +5,15 @@ 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.19.0
9
+
10
+ - Paste formats: pasting a fenced code block that names its language tags the note `@markdown`, and `@markdown` now colours that code like `@code=<language>` (with its label). Code copied from VS Code is tagged `@code=<its language>`, and cells copied from Excel, Google Sheets or Numbers become CSV text tagged `@csv`.
11
+ - Text that only looks like a format is offered, not applied: after pasting CSV-like, Markdown-like or code-like text, a small card says "Apply as CSV" / "Apply as Markdown" / "Apply as Python" (up to three close languages for code) with "Skip". The card moves nothing and never takes the keyboard; typing on, Escape or a click elsewhere closes it. It also appears when the paste makes a new note.
12
+ - Right-click a tag already in the tag bar or the search box for **About this tag**: whether the note names it, the notes it shares with your other tags, whether a parent or a rule already gives it, its synonyms and implications, how many notes have it ("Only on this note" hints at a typo); in the search box, what it finds and what leaving it out removes. Edit Tag Relationships now comes first in the tag menu, at a fixed place under the pointer.
13
+ - Tag suggestions: a web address in a note counts only by its site's name, so a YouTube link no longer suggests `HTTPS` or `V-neuron`; one letter alone no longer names a tag with longer words. A suggestion without evidence now says only what is true (what you typed matches, which part of its name the note has) instead of "Nothing in this note points to it".
14
+ - Fixed: accepting a Grammarly suggestion while editing could undo itself and end editing, when Grammarly drew its card in an element MetaList did not recognise.
15
+ - Removed the "Make pseudo-suggestions" test item from the note menu.
16
+
8
17
  ## 0.18.0
9
18
 
10
19
  - Right-click a tag suggestion, in the tag bar or the search bar, to see why it is suggested. The menu starts with **Why suggested**: the words of the note that name the tag (or a synonym), the tags it goes with and on how many notes, notes sharing this note's tags, whether it already applies through a parent or a rule, or that nothing in the note points to it; then how often the tag is used. Search suggestions also say how often you worked with a tag lately (when that put it first), what your search so far finds, or what leaving it out removes. The reasons are MetaList's own ranking, not the AI's, and appear instantly.
@@ -144,8 +144,9 @@ Ontology rules also add **inferred tags** before search matching:
144
144
  - A typed prefix can match either the start of the full tag or the start of any connector-separated segment.
145
145
  - Example: `wor` suggests `workspaces` and `databricks-workspaces`.
146
146
  - Example: `orksp` suggests neither.
147
- - Right-clicking a search suggestion (Control-click on a Mac) opens its tag menu: **Why suggested**, then Edit Tag Relationships. The search and the list stay as they were; `Escape` closes only the menu. A right-click earns no activity credit.
147
+ - Right-clicking a search suggestion (Control-click on a Mac) opens its tag menu: Edit Tag Relationships, then **Why suggested** below it. The search and the list stay as they were; `Escape` closes only the menu. A right-click earns no activity credit.
148
148
  - **Why suggested** says what MetaList's ranking used (not the AI): how often you worked with the tag in a personalization window (`You've worked with it 12 times in the last 7 days`), the notes it shares with the tags already in the search, how many notes the search so far finds it on, how many notes leaving it out removes, or that a first tag is listed by use; last, how many notes searching for it finds.
149
+ - Right-clicking a tag already typed in the search box opens its menu with **About this tag** below Edit Tag Relationships: how many notes searching for it finds (or `No note has this tag`, often a typo), how many notes it shares with the other tags in the search, what leaving out a `-tag` removes, which synonyms and implying tags it also finds, and how often you worked with it recently.
149
150
  - The server returns at most `MAX_SEARCH_SUGGESTIONS` suggestions; the default is 20.
150
151
  - This affects suggestions only; actual tag search matching remains exact against effective tag terms.
151
152
 
@@ -152,7 +152,8 @@ Unclosed comments behave like unclosed wrappers:
152
152
  - Connector-heavy tags need near-complete literal coverage before they surface from content alone: after ignoring numeric-only chunks, a tag with `k` remaining connector-separated chunks requires at least `max(1, k-1)` meaningful matches, capped by its number of meaningful non-noise chunks. Thus `gpt-6-astra` behaves like `gpt-astra`: either `GPT` or `Astra` can surface it. Decimal versions such as `5.6` are ignored in the same way. `X-Y-Z` still needs two matches and cannot surface from just `X`, `Y`, or `Z`.
153
153
  - Numeric chunks remain insufficient on their own, but they count inside a contiguous near-complete connector phrase that also contains a meaningful text chunk. For example, content `5.6 sol` can promote `GPT-5.6-sol`, while content `5.6` alone does not promote `GPT-5.6`.
154
154
  - When content matches connector-separated tags, the candidate covering the longest contiguous portion of the note wins first. Fewer unmatched connector segments rank ahead of more padded tags, and prefix-aligned partials beat suffix-aligned ones when coverage otherwise ties. Examples: `A B C D` prefers `B-C-D` over `C-D`, `Z` prefers `Z` over `Y-Z`, `Y` prefers `Y-Z` over `X-Y`, and `Y Z` prefers `Y-Z` over `Z` over `X-Y-Z`.
155
- - Single-character connector segments are still ignored for lowercase noise like `a-b-test`. Uppercase one-letter segments can still count as meaningful literals for entity-like tags, but prose-like `A` and `I` are treated as noise so they do not boost unrelated suggestions.
155
+ - Single-character connector segments are still ignored for lowercase noise like `a-b-test`. Uppercase one-letter segments can still count as meaningful literals for entity-like tags, but prose-like `A` and `I` are treated as noise so they do not boost unrelated suggestions. One letter alone never names a tag that also has longer words: a stray `v` does not surface `V-neuron` or `V-Shred` (with `shred` also in the text, `V-Shred` is named). Tags made only of letters (`X-Y-Z`, `Z`) still match.
156
+ - A web address in the note's text counts only by its site's name: `https://www.youtube.com/watch?v=GYx4…` reads as `youtube`, so it can name a `YouTube` tag but not `HTTPS`, `V-neuron` or `indeed.com`. The scheme, `www`/`m`, the top-level domain (and `co.uk`-style suffixes), the path and the query are dropped; an IP address has no name. Only addresses with a scheme or a leading `www.` count as addresses: `indeed.com` written in prose still names the tag.
156
157
  - When content-hit strength ties, more structured/specific tags rank ahead of broader/common ones. Mixed-case tags, digit-bearing tags, connector-separated tags, and prefix-aligned segment matches beat looser matches; usage frequency then breaks structurally equal ties before content position, raw tag length, or alphabetical ordering.
157
158
  - Surrounding prose punctuation is ignored for content matching, so content like `(github?)` still promotes the `github` tag.
158
159
  - Possessive words also match the base tag: `Julie's birthday is today...` promotes the existing `Julie` tag. Straight and curly apostrophes are equivalent, and full tags containing apostrophes (such as `goat's-milk`) still match normally.
@@ -161,17 +162,19 @@ Unclosed comments behave like unclosed wrappers:
161
162
  - Tags declared in ontology rules remain eligible for literal-content matching and typed-prefix completion even when they have never been explicitly assigned to a note. With a blank prefix, unrelated unused ontology tags are not added as generic fallback suggestions.
162
163
  - Tags already present explicitly in the current tag bar are never suggested.
163
164
  - Tags already present only via inheritance or ontology inference are suppressed unless they match the prefix. For one-character prefixes they come right after the suggestions with evidence; for longer prefixes they appear at the bottom. The **Tag Suggestions** settings dialog has `Allow suggesting tags that already apply` (off by default): when on, tags a parent already has and tags the rules imply from them are ranked like any other tag. Tags written in the note's own bar are still never suggested.
164
- - Right-clicking a suggestion (Control-click on a Mac) opens the tag menu for it: **Why suggested**, then Edit Tag Relationships. The list, the typed letters and edit mode stay as they were; `Escape` closes only the menu.
165
- - **Why suggested** says what the ranking found, then how often the tag is used: named (or partly named) in the note's text, a synonym named in it, the rest of the tag after what was typed, on N notes together with the note's tags, named in the note as last saved, on N notes that share the note's tags, or already applying through a parent or a rule. `Nothing in this note points to it` means it is listed only because it is used often. The reasons are MetaList's own ranking, not the AI's.
165
+ - Right-clicking a suggestion (Control-click on a Mac) opens the tag menu for it: Edit Tag Relationships, then **Why suggested** below it. The list, the typed letters and edit mode stay as they were; `Escape` closes only the menu.
166
+ - **Why suggested** says what the ranking found, then how often the tag is used: named (or partly named) in the note's text, a synonym named in it, the rest of the tag after what was typed, on N notes together with the note's tags, named in the note as last saved, on N notes that share the note's tags, or already applying through a parent or a rule. `Listed by use` means the ranking found no evidence in this note, so it is listed because it is used often; `Part of its name is in this note's text` then shows the words that are there but too few to count. The reasons are MetaList's own ranking, not the AI's.
166
167
  - Suggestions appear below the tag bar when there is room; if the tag bar is near the bottom, the list flips upward but keeps the same best-on-top ordering and initial scroll position.
167
168
  - The server returns at most `MAX_TAG_SUGGESTIONS` note tag suggestions; the default is 20.
168
169
 
170
+ ## About This Tag
171
+ - Right-clicking a tag already in the tag bar opens its menu with **About this tag** below Edit Tag Relationships (facts, since it may never have been suggested): whether the note's text names it, how many other notes have it together with this note's other tags, whether a parent or a rule already gives it (writing it repeats that), its synonyms and what it implies, and how many notes have it. `Only on this note` can mean a typo or a one-off tag; `Not on any saved note yet` means it was just typed.
172
+
169
173
  ## AI Tag Proposals
170
174
 
171
175
  - Unresolved proposals are stored separately from accepted tags. They affect inheritance, ontology-aware search/autocomplete, and Untagged Notes immediately, but do not activate formatting or tag commands.
172
- - Right-clicking the actively edited note exposes **Make pseudo-suggestions**, which adds a deterministic temporary test set to that note only.
173
176
  - Direct proposals appear beneath the tag bar only while their note is edited. `+` accepts a proposal into the ordinary tag bar; `−` rejects it.
174
- - The current single-note **Make pseudo-suggestions** test action and individual proposal accept/reject controls participate in normal undo/redo; undoing an individual acceptance restores its proposal and robot count, while redo accepts it again. This does not define undo behavior for bulk operations.
177
+ - Individual proposal accept/reject controls participate in normal undo/redo; undoing an individual acceptance restores its proposal and robot count, while redo accepts it again. This does not define undo behavior for bulk operations.
175
178
  - The robot count marks unresolved proposals on visible notes. A collapsed note rolls up proposals hidden in its descendant branch; inherited and ontology-derived terms do not inflate the count.
176
179
  - Copy/paste and duplication preserve each note's direct unresolved proposals.
177
180
  - The connector characters used for content matching are configurable via `TAG_SUGGESTION_CONNECTORS` in `app/config.py`.
@@ -179,7 +182,7 @@ Unclosed comments behave like unclosed wrappers:
179
182
 
180
183
  ### Bulk proposal operations
181
184
 
182
- Chat-requested LLM generation and menu/chat bulk acceptance or rejection use a separate atomic path from the single-note pseudo-suggestion test action above. See [agent tagging](../design/agent-harness.md#tag-proposal-operations).
185
+ Chat-requested LLM generation and menu/chat bulk acceptance or rejection use a separate atomic path from the individual proposal controls above. See [agent tagging](../design/agent-harness.md#tag-proposal-operations).
183
186
 
184
187
  - Bulk operations are outside ordinary undo/redo, even when applied atomically. They create no individual or combined undo entry and expose no bulk Undo control.
185
188
  - Successful application clears the existing undo and redo stacks using the search-context boundary mechanism. Failure, cancellation, or decline preserves the stacks. A result with no changes preserves history.
@@ -24,6 +24,8 @@ CODE_LANGUAGE_RE = re.compile(r"[a-z0-9][a-z0-9+#._-]*")
24
24
  # Every name and alias Pygments knows (python, py, js, javascript, c++...).
25
25
  _KNOWN_LANGUAGES = frozenset(alias for _name, aliases, _patterns, _mimetypes in get_all_lexers() for alias in aliases)
26
26
  _FORMATTER = HtmlFormatter(nowrap=True, classprefix="tok-")
27
+ # Fence names that mean "no language": a Markdown fence naming one stays plain.
28
+ _PLAIN_FENCE_LANGUAGES = frozenset({"text", "txt", "plain", "plaintext", "output", "console", "none", "nohighlight"})
27
29
 
28
30
 
29
31
  def parse_code_tag_language(tag_name: str) -> str | None:
@@ -61,13 +63,37 @@ def render_code_meta(*, content_html: str, language: str, formatting_tags: Froze
61
63
  f'<pre class="meta-code-pre"><code class="{code_class}">{html.escape(raw_text, quote=False)}</code></pre>'
62
64
  "</div>"
63
65
  )
66
+ return _highlighted_block(raw_text=raw_text, language=language, label=language, code_class=code_class, copy_attr=copy_attr)
67
+
68
+
69
+ def is_highlighted_fence_language(language: str) -> bool:
70
+ """Whether a Markdown fence naming this language is highlighted (any case, aliases too)."""
71
+ if not isinstance(language, str):
72
+ raise TypeError("language must be a string")
73
+ folded = language.casefold()
74
+ return folded not in _PLAIN_FENCE_LANGUAGES and is_known_code_language(folded)
75
+
76
+
77
+ def render_fenced_code(*, code: str, language: str) -> str:
78
+ """A Markdown fence's code, highlighted and labelled as @code=<language> renders it."""
79
+ if not is_highlighted_fence_language(language):
80
+ raise ValueError(f"Fence language is not highlighted: {language!r}")
81
+ return _highlighted_block(
82
+ raw_text=code, language=language.casefold(), label=language, code_class="meta-code-code", copy_attr="",
83
+ )
84
+
85
+
86
+ def _highlighted_block(*, raw_text: str, language: str, label: str, code_class: str, copy_attr: str) -> str:
64
87
  highlighted = highlight(raw_text, get_lexer_by_name(language), _FORMATTER).rstrip("\n")
65
88
  return (
66
89
  f'<div class="meta-code"{copy_attr}>'
67
- f'<span class="meta-code-language">{escaped_language}</span>'
90
+ f'<span class="meta-code-language">{html.escape(label, quote=True)}</span>'
68
91
  f'<pre class="meta-code-pre"><code class="{code_class}">{highlighted}</code></pre>'
69
92
  "</div>"
70
93
  )
71
94
 
72
95
 
73
- __all__ = ["CODE_TAG_PREFIX", "is_known_code_language", "parse_code_tag_language", "render_code_meta"]
96
+ __all__ = [
97
+ "CODE_TAG_PREFIX", "is_highlighted_fence_language", "is_known_code_language", "parse_code_tag_language",
98
+ "render_code_meta", "render_fenced_code",
99
+ ]
@@ -6,6 +6,8 @@ from dataclasses import dataclass
6
6
  from typing import List
7
7
  from urllib.parse import urlsplit
8
8
 
9
+ from app.services.code_rendering import is_highlighted_fence_language
10
+ from app.services.code_rendering import render_fenced_code
9
11
  from app.services.latex_rendering import render_latex_math_to_html
10
12
 
11
13
 
@@ -127,6 +129,9 @@ class _MarkdownRenderer:
127
129
  "</pre>"
128
130
  )
129
131
 
132
+ # A language Pygments knows is coloured as @code=<language>; others stay plain.
133
+ if language != "" and is_highlighted_fence_language(language):
134
+ return render_fenced_code(code="\n".join(content_lines), language=language)
130
135
  language_attr = ""
131
136
  if language != "":
132
137
  escaped_language = html.escape(language, quote=True)
@@ -656,6 +656,31 @@ def list_recent_search_tag_selections_for_first_query(
656
656
  )
657
657
 
658
658
 
659
+ def count_recent_tag_activity(
660
+ *, tag: str, window_days: tuple[int, ...], token: str, today: date,
661
+ ) -> list[TagActivityWindowSelection]:
662
+ """The tag's activity credits in each window that has any, in window order."""
663
+ if not isinstance(tag, str) or tag == "":
664
+ raise ValueError("tag must be a non-empty string")
665
+ validate_tag_activity_windows(window_days)
666
+ counts_by_date = search_history_store.copy_daily_counts(token=token)
667
+ tag_casefold = tag.casefold()
668
+ windows: list[TagActivityWindowSelection] = []
669
+ for day_count in window_days:
670
+ earliest_day = today - timedelta(days=day_count - 1)
671
+ total = 0
672
+ for day_text, tag_counts in counts_by_date.items():
673
+ activity_day = date.fromisoformat(day_text)
674
+ if activity_day < earliest_day or activity_day > today:
675
+ continue
676
+ for tag_name, count in tag_counts.items():
677
+ if tag_name.casefold() == tag_casefold:
678
+ total += count
679
+ if total > 0:
680
+ windows.append(TagActivityWindowSelection(tag=tag, window_days=day_count, activity_count=total))
681
+ return windows
682
+
683
+
659
684
  def reset_search_history(*, token: str) -> int:
660
685
  if not isinstance(token, str) or token == "":
661
686
  raise ValueError("token must be a non-empty string")
@@ -549,23 +549,27 @@ class SearchIndex:
549
549
  if term and not term.startswith("@")
550
550
  }
551
551
 
552
- def describe_tag_cooccurrence(self, *, anchors: Iterable[str], terms: Iterable[str]) -> Dict[str, TagCooccurrence]:
552
+ def describe_tag_cooccurrence(
553
+ self, *, anchors: Iterable[str], terms: Iterable[str], excluded_note_ids: FrozenSet[str],
554
+ ) -> Dict[str, TagCooccurrence]:
553
555
  """For each term, the notes carrying it together with the most of the anchors.
554
556
 
555
557
  The same measure `suggest_tag_completions` ranks by (the most anchors one
556
558
  of the term's notes carries, and how many notes carry that many), with
557
559
  the anchors named. Terms on no note with an anchor are left out.
560
+ excluded_note_ids: notes not to count (the note a tag is already on).
558
561
  """
559
562
  anchor_casefold_set = frozenset(
560
563
  anchor.casefold() for anchor in anchors if anchor and not anchor.startswith("@")
561
564
  )
562
565
  described: Dict[str, TagCooccurrence] = {}
563
566
  with self._lock:
567
+ excluded = {self._uuid_to_id[note_id] for note_id in excluded_note_ids if note_id in self._uuid_to_id}
564
568
  for term in terms:
565
569
  term_casefold = term.casefold()
566
570
  if term_casefold not in self._tag_notes_casefold:
567
571
  continue
568
- term_notes = self._tag_notes_casefold[term_casefold]
572
+ term_notes = self._tag_notes_casefold[term_casefold] - excluded
569
573
  anchors_by_note: Dict[int, Set[str]] = {}
570
574
  for anchor_casefold in anchor_casefold_set:
571
575
  if anchor_casefold == term_casefold or anchor_casefold not in self._tag_notes_casefold:
@@ -604,7 +608,9 @@ class SearchIndex:
604
608
  posting = frozenset(self._tag_notes_casefold[term.casefold()])
605
609
  note_counts[term] = len(posting)
606
610
  matching_counts[term] = len(posting & matching_ids)
607
- cooccurrences = self.describe_tag_cooccurrence(anchors=context.anchors, terms=shown)
611
+ cooccurrences = self.describe_tag_cooccurrence(
612
+ anchors=context.anchors, terms=shown, excluded_note_ids=frozenset(),
613
+ )
608
614
  return SearchSuggestionFacts(
609
615
  partial_prefix=partial_prefix, anchors=tuple(context.anchors),
610
616
  has_completed_clause=has_completed_clause, is_exclusion=context.is_exclusion,
@@ -612,6 +618,22 @@ class SearchIndex:
612
618
  matching_counts=matching_counts, cooccurrences=cooccurrences,
613
619
  )
614
620
 
621
+ def count_tag_within_search(self, *, term: str, search: str) -> Tuple[int, int]:
622
+ """(notes the search finds, how many of them carry the tag); a blank search finds every note."""
623
+ if not isinstance(term, str) or term == "":
624
+ raise TypeError("term must be a non-empty string")
625
+ if not isinstance(search, str):
626
+ raise TypeError("search must be a string")
627
+ with self._lock:
628
+ if search.strip() == "":
629
+ found = set(self._alive)
630
+ else:
631
+ found = {self._uuid_to_id[note_id] for note_id in self.query_note_ids(search)}
632
+ posting: Set[int] = set()
633
+ if term.casefold() in self._tag_notes_casefold:
634
+ posting = self._tag_notes_casefold[term.casefold()]
635
+ return len(found), len(found & posting)
636
+
615
637
  def count_notes_with_tag(self, term: str) -> int:
616
638
  """Notes carrying the tag, as suggestions count usage (case-insensitive)."""
617
639
  if not isinstance(term, str) or term == "":