MetaList 0.3.7__tar.gz → 0.3.9__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 (329) hide show
  1. {metalist-0.3.7/metalist.egg-info → metalist-0.3.9}/PKG-INFO +10 -4
  2. {metalist-0.3.7 → metalist-0.3.9}/README.md +9 -3
  3. {metalist-0.3.7 → metalist-0.3.9}/app/services/namespace_switcher.py +111 -3
  4. metalist-0.3.9/app/services/self_update.py +167 -0
  5. {metalist-0.3.7 → metalist-0.3.9}/app/version.py +1 -1
  6. {metalist-0.3.7 → metalist-0.3.9}/main.py +17 -4
  7. {metalist-0.3.7 → metalist-0.3.9/metalist.egg-info}/PKG-INFO +10 -4
  8. {metalist-0.3.7 → metalist-0.3.9}/metalist.egg-info/SOURCES.txt +1 -0
  9. {metalist-0.3.7 → metalist-0.3.9}/MANIFEST.in +0 -0
  10. {metalist-0.3.7 → metalist-0.3.9}/app/__init__.py +0 -0
  11. {metalist-0.3.7 → metalist-0.3.9}/app/api/__init__.py +0 -0
  12. {metalist-0.3.7 → metalist-0.3.9}/app/api/deps.py +0 -0
  13. {metalist-0.3.7 → metalist-0.3.9}/app/api/dev.py +0 -0
  14. {metalist-0.3.7 → metalist-0.3.9}/app/api/middleware/auth.py +0 -0
  15. {metalist-0.3.7 → metalist-0.3.9}/app/api/request_auth.py +0 -0
  16. {metalist-0.3.7 → metalist-0.3.9}/app/api/routes/auth.py +0 -0
  17. {metalist-0.3.7 → metalist-0.3.9}/app/api/routes/backups.py +0 -0
  18. {metalist-0.3.7 → metalist-0.3.9}/app/api/routes/files.py +0 -0
  19. {metalist-0.3.7 → metalist-0.3.9}/app/api/routes/mcp.py +0 -0
  20. {metalist-0.3.7 → metalist-0.3.9}/app/api/routes/memory.py +0 -0
  21. {metalist-0.3.7 → metalist-0.3.9}/app/api/routes/notes.py +0 -0
  22. {metalist-0.3.7 → metalist-0.3.9}/app/api/routes/ontology.py +0 -0
  23. {metalist-0.3.7 → metalist-0.3.9}/app/api/routes/reminders.py +0 -0
  24. {metalist-0.3.7 → metalist-0.3.9}/app/api/routes/sounds.py +0 -0
  25. {metalist-0.3.7 → metalist-0.3.9}/app/api/routes/test.py +0 -0
  26. {metalist-0.3.7 → metalist-0.3.9}/app/api/transactions.py +0 -0
  27. {metalist-0.3.7 → metalist-0.3.9}/app/config.py +0 -0
  28. {metalist-0.3.7 → metalist-0.3.9}/app/db/__init__.py +0 -0
  29. {metalist-0.3.7 → metalist-0.3.9}/app/db/backup_settings_sql.py +0 -0
  30. {metalist-0.3.7 → metalist-0.3.9}/app/db/engine.py +0 -0
  31. {metalist-0.3.7 → metalist-0.3.9}/app/db/file_schema.py +0 -0
  32. {metalist-0.3.7 → metalist-0.3.9}/app/db/file_session.py +0 -0
  33. {metalist-0.3.7 → metalist-0.3.9}/app/db/files_sql.py +0 -0
  34. {metalist-0.3.7 → metalist-0.3.9}/app/db/link_titles_sql.py +0 -0
  35. {metalist-0.3.7 → metalist-0.3.9}/app/db/migrations.py +0 -0
  36. {metalist-0.3.7 → metalist-0.3.9}/app/db/notes_sql.py +0 -0
  37. {metalist-0.3.7 → metalist-0.3.9}/app/db/ontology_rules_sql.py +0 -0
  38. {metalist-0.3.7 → metalist-0.3.9}/app/db/reminders_sql.py +0 -0
  39. {metalist-0.3.7 → metalist-0.3.9}/app/db/schema.py +0 -0
  40. {metalist-0.3.7 → metalist-0.3.9}/app/db/search_history_sql.py +0 -0
  41. {metalist-0.3.7 → metalist-0.3.9}/app/db/session.py +0 -0
  42. {metalist-0.3.7 → metalist-0.3.9}/app/db/settings_sql.py +0 -0
  43. {metalist-0.3.7 → metalist-0.3.9}/app/db/sounds_sql.py +0 -0
  44. {metalist-0.3.7 → metalist-0.3.9}/app/db/tab_state_sql.py +0 -0
  45. {metalist-0.3.7 → metalist-0.3.9}/app/encryption_audit.py +0 -0
  46. {metalist-0.3.7 → metalist-0.3.9}/app/main.py +0 -0
  47. {metalist-0.3.7 → metalist-0.3.9}/app/mcp/__init__.py +0 -0
  48. {metalist-0.3.7 → metalist-0.3.9}/app/mcp/__main__.py +0 -0
  49. {metalist-0.3.7 → metalist-0.3.9}/app/mcp/errors.py +0 -0
  50. {metalist-0.3.7 → metalist-0.3.9}/app/mcp/policy.py +0 -0
  51. {metalist-0.3.7 → metalist-0.3.9}/app/mcp/read_service.py +0 -0
  52. {metalist-0.3.7 → metalist-0.3.9}/app/mcp/server.py +0 -0
  53. {metalist-0.3.7 → metalist-0.3.9}/app/mcp/tools.py +0 -0
  54. {metalist-0.3.7 → metalist-0.3.9}/app/models/commands.py +0 -0
  55. {metalist-0.3.7 → metalist-0.3.9}/app/models/database.py +0 -0
  56. {metalist-0.3.7 → metalist-0.3.9}/app/models/entities.py +0 -0
  57. {metalist-0.3.7 → metalist-0.3.9}/app/models/enums.py +0 -0
  58. {metalist-0.3.7 → metalist-0.3.9}/app/models/linked_list.py +0 -0
  59. {metalist-0.3.7 → metalist-0.3.9}/app/models/list_operations.py +0 -0
  60. {metalist-0.3.7 → metalist-0.3.9}/app/models/list_traversal.py +0 -0
  61. {metalist-0.3.7 → metalist-0.3.9}/app/models/note_crud.py +0 -0
  62. {metalist-0.3.7 → metalist-0.3.9}/app/models/utils.py +0 -0
  63. {metalist-0.3.7 → metalist-0.3.9}/app/presentation/__init__.py +0 -0
  64. {metalist-0.3.7 → metalist-0.3.9}/app/presentation/render/__init__.py +0 -0
  65. {metalist-0.3.7 → metalist-0.3.9}/app/presentation/render/note_renderer.py +0 -0
  66. {metalist-0.3.7 → metalist-0.3.9}/app/presentation/templates.py +0 -0
  67. {metalist-0.3.7 → metalist-0.3.9}/app/security/encryption.py +0 -0
  68. {metalist-0.3.7 → metalist-0.3.9}/app/server_runtime.py +0 -0
  69. {metalist-0.3.7 → metalist-0.3.9}/app/services/__init__.py +0 -0
  70. {metalist-0.3.7 → metalist-0.3.9}/app/services/auth.py +0 -0
  71. {metalist-0.3.7 → metalist-0.3.9}/app/services/auth_cache_state.py +0 -0
  72. {metalist-0.3.7 → metalist-0.3.9}/app/services/auth_service.py +0 -0
  73. {metalist-0.3.7 → metalist-0.3.9}/app/services/backlinks.py +0 -0
  74. {metalist-0.3.7 → metalist-0.3.9}/app/services/backup_service.py +0 -0
  75. {metalist-0.3.7 → metalist-0.3.9}/app/services/backup_settings_service.py +0 -0
  76. {metalist-0.3.7 → metalist-0.3.9}/app/services/base_service.py +0 -0
  77. {metalist-0.3.7 → metalist-0.3.9}/app/services/client_state_service.py +0 -0
  78. {metalist-0.3.7 → metalist-0.3.9}/app/services/content_cache.py +0 -0
  79. {metalist-0.3.7 → metalist-0.3.9}/app/services/content_formatting.py +0 -0
  80. {metalist-0.3.7 → metalist-0.3.9}/app/services/date_filtering.py +0 -0
  81. {metalist-0.3.7 → metalist-0.3.9}/app/services/dependencies.py +0 -0
  82. {metalist-0.3.7 → metalist-0.3.9}/app/services/diagnostics.py +0 -0
  83. {metalist-0.3.7 → metalist-0.3.9}/app/services/embedded_references.py +0 -0
  84. {metalist-0.3.7 → metalist-0.3.9}/app/services/encryption.py +0 -0
  85. {metalist-0.3.7 → metalist-0.3.9}/app/services/exception_capture.py +0 -0
  86. {metalist-0.3.7 → metalist-0.3.9}/app/services/file_registry.py +0 -0
  87. {metalist-0.3.7 → metalist-0.3.9}/app/services/file_storage.py +0 -0
  88. {metalist-0.3.7 → metalist-0.3.9}/app/services/html_export.py +0 -0
  89. {metalist-0.3.7 → metalist-0.3.9}/app/services/html_unformatting.py +0 -0
  90. {metalist-0.3.7 → metalist-0.3.9}/app/services/hydration_state.py +0 -0
  91. {metalist-0.3.7 → metalist-0.3.9}/app/services/integrity.py +0 -0
  92. {metalist-0.3.7 → metalist-0.3.9}/app/services/latex_rendering.py +0 -0
  93. {metalist-0.3.7 → metalist-0.3.9}/app/services/link_titles.py +0 -0
  94. {metalist-0.3.7 → metalist-0.3.9}/app/services/login_rate_limit.py +0 -0
  95. {metalist-0.3.7 → metalist-0.3.9}/app/services/maintenance_mode.py +0 -0
  96. {metalist-0.3.7 → metalist-0.3.9}/app/services/markdown_rendering.py +0 -0
  97. {metalist-0.3.7 → metalist-0.3.9}/app/services/memory.py +0 -0
  98. {metalist-0.3.7 → metalist-0.3.9}/app/services/memory_service.py +0 -0
  99. {metalist-0.3.7 → metalist-0.3.9}/app/services/namespace_deletion_jobs.py +0 -0
  100. {metalist-0.3.7 → metalist-0.3.9}/app/services/namespace_deletion_worker.py +0 -0
  101. {metalist-0.3.7 → metalist-0.3.9}/app/services/namespace_rename_jobs.py +0 -0
  102. {metalist-0.3.7 → metalist-0.3.9}/app/services/namespace_rename_worker.py +0 -0
  103. {metalist-0.3.7 → metalist-0.3.9}/app/services/note_image_tags.py +0 -0
  104. {metalist-0.3.7 → metalist-0.3.9}/app/services/note_service.py +0 -0
  105. {metalist-0.3.7 → metalist-0.3.9}/app/services/note_store.py +0 -0
  106. {metalist-0.3.7 → metalist-0.3.9}/app/services/ontology_rules_store.py +0 -0
  107. {metalist-0.3.7 → metalist-0.3.9}/app/services/query_service.py +0 -0
  108. {metalist-0.3.7 → metalist-0.3.9}/app/services/reminders.py +0 -0
  109. {metalist-0.3.7 → metalist-0.3.9}/app/services/root_sorting.py +0 -0
  110. {metalist-0.3.7 → metalist-0.3.9}/app/services/runtime_hardening.py +0 -0
  111. {metalist-0.3.7 → metalist-0.3.9}/app/services/search_history.py +0 -0
  112. {metalist-0.3.7 → metalist-0.3.9}/app/services/search_index.py +0 -0
  113. {metalist-0.3.7 → metalist-0.3.9}/app/services/search_query.py +0 -0
  114. {metalist-0.3.7 → metalist-0.3.9}/app/services/search_text.py +0 -0
  115. {metalist-0.3.7 → metalist-0.3.9}/app/services/session_timeout_service.py +0 -0
  116. {metalist-0.3.7 → metalist-0.3.9}/app/services/shell_session_service.py +0 -0
  117. {metalist-0.3.7 → metalist-0.3.9}/app/services/snapshot.py +0 -0
  118. {metalist-0.3.7 → metalist-0.3.9}/app/services/sound_storage.py +0 -0
  119. {metalist-0.3.7 → metalist-0.3.9}/app/services/store.py +0 -0
  120. {metalist-0.3.7 → metalist-0.3.9}/app/services/sync.py +0 -0
  121. {metalist-0.3.7 → metalist-0.3.9}/app/services/sync_state.py +0 -0
  122. {metalist-0.3.7 → metalist-0.3.9}/app/services/tab_state.py +0 -0
  123. {metalist-0.3.7 → metalist-0.3.9}/app/services/tag_case.py +0 -0
  124. {metalist-0.3.7 → metalist-0.3.9}/app/services/tag_ontology.py +0 -0
  125. {metalist-0.3.7 → metalist-0.3.9}/app/services/tag_rename.py +0 -0
  126. {metalist-0.3.7 → metalist-0.3.9}/app/services/tag_suggestions.py +0 -0
  127. {metalist-0.3.7 → metalist-0.3.9}/app/services/tag_term_matching.py +0 -0
  128. {metalist-0.3.7 → metalist-0.3.9}/app/services/test_reset.py +0 -0
  129. {metalist-0.3.7 → metalist-0.3.9}/app/services/tokens.py +0 -0
  130. {metalist-0.3.7 → metalist-0.3.9}/app/services/transaction_manager.py +0 -0
  131. {metalist-0.3.7 → metalist-0.3.9}/app/services/undo_service.py +0 -0
  132. {metalist-0.3.7 → metalist-0.3.9}/app/services/undo_state.py +0 -0
  133. {metalist-0.3.7 → metalist-0.3.9}/app/services/view_cache.py +0 -0
  134. {metalist-0.3.7 → metalist-0.3.9}/app/services/view_diff.py +0 -0
  135. {metalist-0.3.7 → metalist-0.3.9}/app/services/view_state.py +0 -0
  136. {metalist-0.3.7 → metalist-0.3.9}/app/services/windows_process_control.py +0 -0
  137. {metalist-0.3.7 → metalist-0.3.9}/app/startup_js_sanity.py +0 -0
  138. {metalist-0.3.7 → metalist-0.3.9}/app/startup_sanity.py +0 -0
  139. {metalist-0.3.7 → metalist-0.3.9}/app/startup_sanity_config.py +0 -0
  140. {metalist-0.3.7 → metalist-0.3.9}/app/static/config/command_palette_tags.json +0 -0
  141. {metalist-0.3.7 → metalist-0.3.9}/app/static/css/forms.css +0 -0
  142. {metalist-0.3.7 → metalist-0.3.9}/app/static/css/main.css +0 -0
  143. {metalist-0.3.7 → metalist-0.3.9}/app/static/img/favicon.ico +0 -0
  144. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/locked.js +0 -0
  145. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/main.js +0 -0
  146. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/activity-tracker.js +0 -0
  147. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/api-client.js +0 -0
  148. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/async-result.js +0 -0
  149. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/auth.js +0 -0
  150. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/client-state-api.js +0 -0
  151. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/client-state-migration.js +0 -0
  152. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/command-palette/click-activation-service.js +0 -0
  153. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/command-palette/command-palette-controller.js +0 -0
  154. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/command-palette/endpoint-registry.js +0 -0
  155. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/command-palette/preferences-store.js +0 -0
  156. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/command-palette/tag-config-loader.js +0 -0
  157. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/command-palette/usage-store.js +0 -0
  158. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/config.js +0 -0
  159. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/connectivity-monitor.js +0 -0
  160. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/context-menu/context-menu-registry.js +0 -0
  161. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/context-menu/context-menu-service.js +0 -0
  162. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/context-menu/input-caret-service.js +0 -0
  163. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/dom-utils-fixed.js +0 -0
  164. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/dom-utils.js +0 -0
  165. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/editor-commands.js +0 -0
  166. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/editor-selection.js +0 -0
  167. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/editor-toolbar.js +0 -0
  168. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/error-handler.js +0 -0
  169. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/error-overlay.js +0 -0
  170. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/location-flags.js +0 -0
  171. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/login-namespace-picker.js +0 -0
  172. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/alphabetize-root-notes-modal.js +0 -0
  173. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/backup-restore-modal.js +0 -0
  174. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/backup-result-modal.js +0 -0
  175. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/backup-retention-modal.js +0 -0
  176. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/backup-settings-modal.js +0 -0
  177. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/base-modal.js +0 -0
  178. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/delete-namespace-modal.js +0 -0
  179. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/delete-namespace-validation.js +0 -0
  180. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/help-modal.js +0 -0
  181. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/memory-modal.js +0 -0
  182. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/namespace-loading-page.js +0 -0
  183. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/namespace-modals.js +0 -0
  184. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/namespace-ports-profile.js +0 -0
  185. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/namespace-rename-validation.js +0 -0
  186. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/ontology-modal.js +0 -0
  187. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/password-modal.js +0 -0
  188. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/prioritize-modal.js +0 -0
  189. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/random-password-modal.js +0 -0
  190. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/reminder-modal.js +0 -0
  191. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/reset-updated-at-modal.js +0 -0
  192. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/session-timeout-modal.js +0 -0
  193. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/sound-manager-modal.js +0 -0
  194. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/modals/version-info-modal.js +0 -0
  195. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/actions/content-actions.js +0 -0
  196. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/actions/history-actions.js +0 -0
  197. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/actions/note-actions.js +0 -0
  198. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/actions/search-actions.js +0 -0
  199. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/actions/selection-actions.js +0 -0
  200. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/actions/ui-actions.js +0 -0
  201. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/events/context-menu-events.js +0 -0
  202. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/events/focus-events.js +0 -0
  203. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/events/inactivity-events.js +0 -0
  204. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/events/input-events.js +0 -0
  205. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/events/keyboard-events.js +0 -0
  206. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/events/mouse-events.js +0 -0
  207. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/events/search-events.js +0 -0
  208. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/mode-context.js +0 -0
  209. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/mode-logger.js +0 -0
  210. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/mode-manager-controller.js +0 -0
  211. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/animated-scroll-service.js +0 -0
  212. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/backlinks-panel-service.js +0 -0
  213. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/clipboard-shortcut-policy-service.js +0 -0
  214. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/collapse-affordance-service.js +0 -0
  215. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/collapse-editing-policy-service.js +0 -0
  216. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/command-gate-service.js +0 -0
  217. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/context-menu-target-service.js +0 -0
  218. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/date-filter-indicator-service.js +0 -0
  219. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/date-filter-service.js +0 -0
  220. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/differential-view-service.js +0 -0
  221. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/edit-session-collapse-policy-service.js +0 -0
  222. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/edit-session-collapse-service.js +0 -0
  223. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/embedded-image-service.js +0 -0
  224. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/file-image-preview-service.js +0 -0
  225. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/file-reference-service.js +0 -0
  226. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/filtered-refresh-selection-service.js +0 -0
  227. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/html-paste-sanitizer-service.js +0 -0
  228. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/image-context-menu-action-service.js +0 -0
  229. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/image-file-insert-choice-modal-service.js +0 -0
  230. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/infinite-scroll-service.js +0 -0
  231. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/link-context-menu-action-service.js +0 -0
  232. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/markdown-render-service.js +0 -0
  233. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/note-click-target-service.js +0 -0
  234. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/note-clipboard-write-service.js +0 -0
  235. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/note-collapse-animation-service.js +0 -0
  236. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/note-context-menu-action-service.js +0 -0
  237. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/note-drag-service.js +0 -0
  238. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/note-reposition-animation-service.js +0 -0
  239. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/note-split-service.js +0 -0
  240. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/password-clipboard-service.js +0 -0
  241. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/polling-service.js +0 -0
  242. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/rhs-panel-service.js +0 -0
  243. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/root-date-separator-service.js +0 -0
  244. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/root-sort-indicator-service.js +0 -0
  245. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/root-sort-service.js +0 -0
  246. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/scroll-anchor-service.js +0 -0
  247. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/scroll-restoration-service.js +0 -0
  248. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/scroll-to-top-service.js +0 -0
  249. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/search-contexts-overlay-service.js +0 -0
  250. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/search-debounce-service.js +0 -0
  251. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/search-input-service.js +0 -0
  252. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/search-interaction-service.js +0 -0
  253. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/search-redaction-reveal-service.js +0 -0
  254. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/search-suggestions-service.js +0 -0
  255. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/search-syntax-service.js +0 -0
  256. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/shell-output-service.js +0 -0
  257. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/tab-dom-cache-service.js +0 -0
  258. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/tab-duplication-service.js +0 -0
  259. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/tab-state-service.js +0 -0
  260. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/tag-bar-service.js +0 -0
  261. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/tag-suggestions-service.js +0 -0
  262. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/tag-syntax-service.js +0 -0
  263. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/todo-toggle-editing-service.js +0 -0
  264. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/mode-manager/services/view-mode-search-shortcut-service.js +0 -0
  265. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/password-generator.js +0 -0
  266. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/reminder-store.js +0 -0
  267. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/reminder-surface-service.js +0 -0
  268. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/selection-markers.js +0 -0
  269. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/session-auth.js +0 -0
  270. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/sound-service.js +0 -0
  271. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/tag-token.js +0 -0
  272. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/modules/uuid.js +0 -0
  273. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/namespace-deleted.js +0 -0
  274. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/namespace-renamed.js +0 -0
  275. {metalist-0.3.7 → metalist-0.3.9}/app/static/js/vendor/markdown-it.min.js +0 -0
  276. {metalist-0.3.7 → metalist-0.3.9}/app/static/video/login-startup.mp4 +0 -0
  277. {metalist-0.3.7 → metalist-0.3.9}/app/templates/base.html +0 -0
  278. {metalist-0.3.7 → metalist-0.3.9}/app/templates/index.html +0 -0
  279. {metalist-0.3.7 → metalist-0.3.9}/app/templates/locked.html +0 -0
  280. {metalist-0.3.7 → metalist-0.3.9}/app/templates/maintenance.html +0 -0
  281. {metalist-0.3.7 → metalist-0.3.9}/app/templates/namespace_deleted.html +0 -0
  282. {metalist-0.3.7 → metalist-0.3.9}/app/templates/namespace_renamed.html +0 -0
  283. {metalist-0.3.7 → metalist-0.3.9}/app/templates/notes_list.html +0 -0
  284. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/__init__.py +0 -0
  285. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/alphabetize_root_notes.py +0 -0
  286. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/base.py +0 -0
  287. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/collapse.py +0 -0
  288. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/copy_note.py +0 -0
  289. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/create_child.py +0 -0
  290. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/create_note.py +0 -0
  291. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/create_sibling.py +0 -0
  292. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/delete_subtree.py +0 -0
  293. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/expand.py +0 -0
  294. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/indent.py +0 -0
  295. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/lock.py +0 -0
  296. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/move.py +0 -0
  297. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/move_to_top.py +0 -0
  298. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/outdent.py +0 -0
  299. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/paste_child.py +0 -0
  300. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/paste_sibling.py +0 -0
  301. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/prioritize.py +0 -0
  302. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/record_edit_mode.py +0 -0
  303. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/redo.py +0 -0
  304. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/rename_tag.py +0 -0
  305. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/reset_updated_at.py +0 -0
  306. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/run_shell.py +0 -0
  307. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/search_comment_autofill.py +0 -0
  308. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/search_context_tags.py +0 -0
  309. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/set_collapse_bulk.py +0 -0
  310. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/set_collapse_in_context.py +0 -0
  311. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/split_note.py +0 -0
  312. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/toggle_reference_mode.py +0 -0
  313. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/toggle_todo_done.py +0 -0
  314. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/undo.py +0 -0
  315. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/unformat_content.py +0 -0
  316. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/update_content.py +0 -0
  317. {metalist-0.3.7 → metalist-0.3.9}/app/usecases/view.py +0 -0
  318. {metalist-0.3.7 → metalist-0.3.9}/app/utils/__init__.py +0 -0
  319. {metalist-0.3.7 → metalist-0.3.9}/app/utils/encryption.py +0 -0
  320. {metalist-0.3.7 → metalist-0.3.9}/app/utils/text_utils.py +0 -0
  321. {metalist-0.3.7 → metalist-0.3.9}/convert-from-legacy.py +0 -0
  322. {metalist-0.3.7 → metalist-0.3.9}/mcp_client.py +0 -0
  323. {metalist-0.3.7 → metalist-0.3.9}/metalist.egg-info/dependency_links.txt +0 -0
  324. {metalist-0.3.7 → metalist-0.3.9}/metalist.egg-info/entry_points.txt +0 -0
  325. {metalist-0.3.7 → metalist-0.3.9}/metalist.egg-info/requires.txt +0 -0
  326. {metalist-0.3.7 → metalist-0.3.9}/metalist.egg-info/top_level.txt +0 -0
  327. {metalist-0.3.7 → metalist-0.3.9}/pyproject.toml +0 -0
  328. {metalist-0.3.7 → metalist-0.3.9}/scripts/generate-lan-cert.sh +0 -0
  329. {metalist-0.3.7 → metalist-0.3.9}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: metalist
3
- Version: 0.3.7
3
+ Version: 0.3.9
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
@@ -76,6 +76,12 @@ uv tool install metalist
76
76
  metalist
77
77
  ```
78
78
 
79
+ After the first installation, update and restart MetaList with one cross-platform command:
80
+ ```bash
81
+ metalist update
82
+ ```
83
+ The updater stops running namespaces, hands off to an external PowerShell process on Windows or `/bin/sh` on macOS/Linux so the installed environment can unlock, runs the forced cache-refreshed uv update, and launches MetaList again.
84
+
79
85
  For pip, users can run `pip install metalist`. For a non-editable local install from this checkout, use `uv pip install .` or `pip install .` instead of the editable command below.
80
86
 
81
87
  ```bash
@@ -87,11 +93,11 @@ npm install
87
93
  ```
88
94
 
89
95
  ### Run
90
- The installed entrypoint starts Uvicorn with the FastAPI app:
96
+ The installed entrypoint starts or restarts every known namespace, prints their URLs, and exits:
91
97
  ```bash
92
98
  metalist
93
99
  ```
94
- For source-checkout compatibility, `python main.py` still works. Plain `python main.py` is now an orchestration command: it restarts already-running namespaces from the current checkout, launches stopped namespaces, prints their URLs, and exits. Use `python main.py --namespace work` or `python main.py work` when you want one foreground namespace process.
100
+ For source-checkout compatibility, `python main.py` performs the same orchestration. Use `metalist work`, `python main.py --namespace work`, or `python main.py work` when you want one foreground namespace process.
95
101
 
96
102
  `metalist` and explicit single-namespace source runs bind HTTP on `0.0.0.0:8000` by default, matching the old MetaList LAN-friendly behavior.
97
103
  On first startup, MetaList also auto-generates a self-signed TLS pair at `~/MetaList/certs/metalist-cert.pem` and `~/MetaList/certs/metalist-key.pem`, then enables HTTPS on `0.0.0.0:8443`. If you already have real PEM files, point `METALIST_TLS_CERT` and `METALIST_TLS_KEY` at them instead. Set `METALIST_AUTO_GENERATE_TLS=0` only if you explicitly want HTTP-only startup.
@@ -104,7 +110,7 @@ Database selection:
104
110
  - Launch precedence is: explicit CLI flags > env vars > saved namespace profile; if a namespace has no saved profile, launch it once with explicit ports or configure ports from the UI
105
111
  - Backups stay beside the namespace data under `~/MetaList/namespaces/work/backups/` and use one archive per snapshot with filenames like `work-<timestamp>.metalist-backup.tar.gz`
106
112
  - The Backup Settings modal targets one user-selected backup folder and can include multiple namespaces in a single run
107
- - Restoring `work` into `work` is the normal overwrite path; importing a backup under a different namespace name requires a new target namespace and rejects saved launch-port conflicts.
113
+ - Restoring `work` into `work` is the normal overwrite path; importing a backup under a different namespace name can create a new target namespace with automatically selected conflict-free ports.
108
114
 
109
115
  Useful env flags:
110
116
  - `CRASH_SERVER_ON_FAIL=1` (default): fail-fast on validation errors
@@ -47,6 +47,12 @@ uv tool install metalist
47
47
  metalist
48
48
  ```
49
49
 
50
+ After the first installation, update and restart MetaList with one cross-platform command:
51
+ ```bash
52
+ metalist update
53
+ ```
54
+ The updater stops running namespaces, hands off to an external PowerShell process on Windows or `/bin/sh` on macOS/Linux so the installed environment can unlock, runs the forced cache-refreshed uv update, and launches MetaList again.
55
+
50
56
  For pip, users can run `pip install metalist`. For a non-editable local install from this checkout, use `uv pip install .` or `pip install .` instead of the editable command below.
51
57
 
52
58
  ```bash
@@ -58,11 +64,11 @@ npm install
58
64
  ```
59
65
 
60
66
  ### Run
61
- The installed entrypoint starts Uvicorn with the FastAPI app:
67
+ The installed entrypoint starts or restarts every known namespace, prints their URLs, and exits:
62
68
  ```bash
63
69
  metalist
64
70
  ```
65
- For source-checkout compatibility, `python main.py` still works. Plain `python main.py` is now an orchestration command: it restarts already-running namespaces from the current checkout, launches stopped namespaces, prints their URLs, and exits. Use `python main.py --namespace work` or `python main.py work` when you want one foreground namespace process.
71
+ For source-checkout compatibility, `python main.py` performs the same orchestration. Use `metalist work`, `python main.py --namespace work`, or `python main.py work` when you want one foreground namespace process.
66
72
 
67
73
  `metalist` and explicit single-namespace source runs bind HTTP on `0.0.0.0:8000` by default, matching the old MetaList LAN-friendly behavior.
68
74
  On first startup, MetaList also auto-generates a self-signed TLS pair at `~/MetaList/certs/metalist-cert.pem` and `~/MetaList/certs/metalist-key.pem`, then enables HTTPS on `0.0.0.0:8443`. If you already have real PEM files, point `METALIST_TLS_CERT` and `METALIST_TLS_KEY` at them instead. Set `METALIST_AUTO_GENERATE_TLS=0` only if you explicitly want HTTP-only startup.
@@ -75,7 +81,7 @@ Database selection:
75
81
  - Launch precedence is: explicit CLI flags > env vars > saved namespace profile; if a namespace has no saved profile, launch it once with explicit ports or configure ports from the UI
76
82
  - Backups stay beside the namespace data under `~/MetaList/namespaces/work/backups/` and use one archive per snapshot with filenames like `work-<timestamp>.metalist-backup.tar.gz`
77
83
  - The Backup Settings modal targets one user-selected backup folder and can include multiple namespaces in a single run
78
- - Restoring `work` into `work` is the normal overwrite path; importing a backup under a different namespace name requires a new target namespace and rejects saved launch-port conflicts.
84
+ - Restoring `work` into `work` is the normal overwrite path; importing a backup under a different namespace name can create a new target namespace with automatically selected conflict-free ports.
79
85
 
80
86
  Useful env flags:
81
87
  - `CRASH_SERVER_ON_FAIL=1` (default): fail-fast on validation errors
@@ -334,10 +334,33 @@ def open_or_launch_all_namespaces(
334
334
  if not isinstance(raw_namespaces, list):
335
335
  raise RuntimeError("Namespace catalog missing namespaces")
336
336
 
337
+ profiles = _resolve_conflict_free_profiles_for_all_namespaces(
338
+ raw_namespaces=raw_namespaces,
339
+ )
340
+ saved_profiles = _load_saved_profiles_by_namespace()
341
+ for profile in profiles:
342
+ saved_profile = saved_profiles.get(profile.namespace)
343
+ if saved_profile is None:
344
+ raise RuntimeError(f"Namespace {profile.namespace} launch profile disappeared")
345
+ if saved_profile == profile:
346
+ continue
347
+ save_namespace_launch_profile(
348
+ namespace=profile.namespace,
349
+ port=profile.port,
350
+ https_port=profile.https_port,
351
+ mcp_port=profile.mcp_port,
352
+ )
353
+ print(
354
+ f"[startup] WARNING: adjusted namespace {profile.namespace} ports to resolve "
355
+ f"a saved conflict: HTTP {saved_profile.port} -> {profile.port}, "
356
+ f"HTTPS {saved_profile.https_port} -> {profile.https_port}, "
357
+ f"MCP {saved_profile.mcp_port} -> {profile.mcp_port}.",
358
+ file=sys.stderr,
359
+ flush=True,
360
+ )
361
+
337
362
  results: list[NamespaceOpenResult] = []
338
- for entry in raw_namespaces:
339
- _assert_catalog_entry_has_launch_profile(entry=entry)
340
- profile = _catalog_default_profile(entry=entry)
363
+ for profile in profiles:
341
364
  result = open_or_launch_namespace(
342
365
  environ=environ,
343
366
  current_namespace=None,
@@ -365,6 +388,91 @@ def open_or_launch_all_namespaces(
365
388
  return results
366
389
 
367
390
 
391
+ def stop_all_namespace_processes_for_update() -> int:
392
+ profiles = _load_saved_profiles_by_namespace()
393
+ reserved_ports: set[int] = set()
394
+ for profile in profiles.values():
395
+ for _, port in _profile_service_ports(profile=profile):
396
+ reserved_ports.add(port)
397
+
398
+ listener_pids: set[int] = set()
399
+ for port in sorted(reserved_ports):
400
+ listener_pids.update(_find_listening_pids_for_port(port=port))
401
+ current_pid = os.getpid()
402
+ listener_pids.discard(current_pid)
403
+ for pid in sorted(listener_pids):
404
+ _stop_process(pid=pid)
405
+ return len(listener_pids)
406
+
407
+
408
+ def _resolve_conflict_free_profiles_for_all_namespaces(
409
+ *,
410
+ raw_namespaces: Sequence[object],
411
+ ) -> list[NamespaceLaunchProfile]:
412
+ occupied_ports: set[int] = set()
413
+ profiles: list[NamespaceLaunchProfile] = []
414
+ for entry in raw_namespaces:
415
+ _assert_catalog_entry_has_launch_profile(entry=entry)
416
+ saved_profile = _catalog_default_profile(entry=entry)
417
+ profile = _repair_profile_port_conflicts(
418
+ profile=saved_profile,
419
+ occupied_ports=occupied_ports,
420
+ )
421
+ profiles.append(profile)
422
+ for _, port in _profile_service_ports(profile=profile):
423
+ occupied_ports.add(port)
424
+ return profiles
425
+
426
+
427
+ def _repair_profile_port_conflicts(
428
+ *,
429
+ profile: NamespaceLaunchProfile,
430
+ occupied_ports: set[int],
431
+ ) -> NamespaceLaunchProfile:
432
+ working_ports = set(occupied_ports)
433
+ http_port = _keep_or_replace_port(
434
+ preferred_port=profile.port,
435
+ replacement_start=server_runtime._DEFAULT_HTTP_PORT,
436
+ occupied_ports=working_ports,
437
+ )
438
+ working_ports.add(http_port)
439
+
440
+ https_port = profile.https_port
441
+ if https_port is not None:
442
+ https_port = _keep_or_replace_port(
443
+ preferred_port=https_port,
444
+ replacement_start=server_runtime._DEFAULT_HTTPS_PORT,
445
+ occupied_ports=working_ports,
446
+ )
447
+ working_ports.add(https_port)
448
+
449
+ mcp_port = _keep_or_replace_port(
450
+ preferred_port=profile.mcp_port,
451
+ replacement_start=server_runtime._DEFAULT_MCP_AGENT_WEB_PORT,
452
+ occupied_ports=working_ports,
453
+ )
454
+ return NamespaceLaunchProfile(
455
+ namespace=profile.namespace,
456
+ port=http_port,
457
+ https_port=https_port,
458
+ mcp_port=mcp_port,
459
+ )
460
+
461
+
462
+ def _keep_or_replace_port(
463
+ *,
464
+ preferred_port: int,
465
+ replacement_start: int,
466
+ occupied_ports: set[int],
467
+ ) -> int:
468
+ if preferred_port not in occupied_ports:
469
+ return preferred_port
470
+ return _next_free_port(
471
+ start_port=replacement_start,
472
+ occupied_ports=occupied_ports,
473
+ )
474
+
475
+
368
476
  def save_namespace_port_profiles(
369
477
  *,
370
478
  environ: Mapping[str, str],
@@ -0,0 +1,167 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping
4
+ from dataclasses import dataclass
5
+ import os
6
+ from pathlib import Path
7
+ import shlex
8
+ import shutil
9
+ import subprocess
10
+
11
+ from app.services.namespace_switcher import stop_all_namespace_processes_for_update
12
+
13
+
14
+ _WINDOWS_CREATE_NEW_CONSOLE = 0x00000010
15
+
16
+
17
+ @dataclass(frozen=True)
18
+ class SelfUpdateScheduleResult:
19
+ stopped_process_count: int
20
+ platform_name: str
21
+ message: str
22
+
23
+
24
+ def schedule_self_update(
25
+ *,
26
+ metalist_executable: str,
27
+ current_pid: int,
28
+ platform_name: str,
29
+ environ: Mapping[str, str],
30
+ ) -> SelfUpdateScheduleResult:
31
+ _validate_schedule_inputs(
32
+ metalist_executable=metalist_executable,
33
+ current_pid=current_pid,
34
+ platform_name=platform_name,
35
+ )
36
+ uv_executable = shutil.which("uv")
37
+ if uv_executable is None:
38
+ raise RuntimeError("uv executable was not found on PATH; MetaList was not stopped")
39
+
40
+ updater_command: list[str]
41
+ updater_options: dict[str, object]
42
+ if platform_name == "win32":
43
+ powershell_executable = _resolve_windows_powershell()
44
+ updater_command = _build_windows_updater_command(
45
+ powershell_executable=powershell_executable,
46
+ uv_executable=uv_executable,
47
+ metalist_executable=metalist_executable,
48
+ current_pid=current_pid,
49
+ )
50
+ updater_options = {
51
+ "creationflags": _WINDOWS_CREATE_NEW_CONSOLE,
52
+ "cwd": str(Path.home()),
53
+ "env": dict(environ),
54
+ }
55
+ else:
56
+ shell_path = Path("/bin/sh")
57
+ if not shell_path.is_file():
58
+ raise RuntimeError("/bin/sh is required for MetaList self-update; MetaList was not stopped")
59
+ updater_command = _build_posix_updater_command(
60
+ shell_executable=str(shell_path),
61
+ uv_executable=uv_executable,
62
+ metalist_executable=metalist_executable,
63
+ current_pid=current_pid,
64
+ )
65
+ updater_options = {
66
+ "start_new_session": True,
67
+ "cwd": str(Path.home()),
68
+ "env": dict(environ),
69
+ }
70
+
71
+ stopped_process_count = stop_all_namespace_processes_for_update()
72
+ subprocess.Popen(updater_command, **updater_options)
73
+ return SelfUpdateScheduleResult(
74
+ stopped_process_count=stopped_process_count,
75
+ platform_name=platform_name,
76
+ message=(
77
+ f"Stopped {stopped_process_count} MetaList process(es). "
78
+ "The updater will install the latest release and restart MetaList."
79
+ ),
80
+ )
81
+
82
+
83
+ def _validate_schedule_inputs(
84
+ *,
85
+ metalist_executable: str,
86
+ current_pid: int,
87
+ platform_name: str,
88
+ ) -> None:
89
+ if not isinstance(metalist_executable, str) or metalist_executable.strip() == "":
90
+ raise ValueError("metalist_executable must be a non-empty string")
91
+ if not isinstance(current_pid, int) or current_pid <= 0:
92
+ raise ValueError("current_pid must be a positive integer")
93
+ if platform_name not in {"darwin", "linux", "win32"}:
94
+ raise RuntimeError(f"MetaList self-update does not support platform: {platform_name}")
95
+
96
+
97
+ def _resolve_windows_powershell() -> str:
98
+ powershell_executable = shutil.which("powershell.exe")
99
+ if powershell_executable is not None:
100
+ return powershell_executable
101
+ pwsh_executable = shutil.which("pwsh.exe")
102
+ if pwsh_executable is not None:
103
+ return pwsh_executable
104
+ raise RuntimeError("PowerShell is required for MetaList self-update; MetaList was not stopped")
105
+
106
+
107
+ def _quote_powershell_literal(value: str) -> str:
108
+ return "'" + value.replace("'", "''") + "'"
109
+
110
+
111
+ def _build_windows_updater_command(
112
+ *,
113
+ powershell_executable: str,
114
+ uv_executable: str,
115
+ metalist_executable: str,
116
+ current_pid: int,
117
+ ) -> list[str]:
118
+ quoted_uv = _quote_powershell_literal(uv_executable)
119
+ quoted_metalist = _quote_powershell_literal(metalist_executable)
120
+ script = (
121
+ f"while (Get-Process -Id {current_pid} -ErrorAction SilentlyContinue) "
122
+ "{ Start-Sleep -Milliseconds 100 }; "
123
+ f"& {quoted_uv} tool install --force --reinstall --refresh metalist; "
124
+ "if ($LASTEXITCODE -ne 0) { "
125
+ "Write-Host 'MetaList update failed. Review the uv output above.' -ForegroundColor Red; "
126
+ "Start-Sleep -Seconds 10; exit $LASTEXITCODE }; "
127
+ f"& {quoted_metalist}; "
128
+ "if ($LASTEXITCODE -ne 0) { "
129
+ "Write-Host 'MetaList updated, but restart failed.' -ForegroundColor Red; "
130
+ "Start-Sleep -Seconds 10; exit $LASTEXITCODE }; "
131
+ "Write-Host 'MetaList update complete.' -ForegroundColor Green; "
132
+ "Start-Sleep -Seconds 3"
133
+ )
134
+ return [
135
+ powershell_executable,
136
+ "-NoLogo",
137
+ "-NoProfile",
138
+ "-NonInteractive",
139
+ "-Command",
140
+ script,
141
+ ]
142
+
143
+
144
+ def _build_posix_updater_command(
145
+ *,
146
+ shell_executable: str,
147
+ uv_executable: str,
148
+ metalist_executable: str,
149
+ current_pid: int,
150
+ ) -> list[str]:
151
+ uv_command = shlex.join(
152
+ [uv_executable, "tool", "install", "--force", "--reinstall", "--refresh", "metalist"]
153
+ )
154
+ metalist_command = shlex.join([metalist_executable])
155
+ script = (
156
+ f"while kill -0 {current_pid} 2>/dev/null; do sleep 0.1; done\n"
157
+ f"if ! {uv_command}; then\n"
158
+ " echo 'MetaList update failed. Review the uv output above.' >&2\n"
159
+ " exit 1\n"
160
+ "fi\n"
161
+ f"if ! {metalist_command}; then\n"
162
+ " echo 'MetaList updated, but restart failed.' >&2\n"
163
+ " exit 1\n"
164
+ "fi\n"
165
+ "echo 'MetaList update complete.'\n"
166
+ )
167
+ return [shell_executable, "-c", script]
@@ -1,3 +1,3 @@
1
1
  """Single authoritative MetaList application version."""
2
2
 
3
- __version__ = "0.3.7"
3
+ __version__ = "0.3.9"
@@ -34,6 +34,7 @@ from app.services.exception_capture import CapturedExceptionContext
34
34
  from app.services.namespace_switcher import build_namespace_catalog
35
35
  from app.services.namespace_switcher import NamespaceOpenResult
36
36
  from app.services.namespace_switcher import open_or_launch_all_namespaces
37
+ from app.services.self_update import schedule_self_update
37
38
  from app.services.windows_process_control import find_listening_pids_for_port as find_windows_listening_pids_for_port
38
39
  from app.services.windows_process_control import is_process_running as is_windows_process_running
39
40
  from app.services.windows_process_control import stop_process as stop_windows_process
@@ -155,8 +156,6 @@ def _should_bootstrap_all_namespaces_without_cli_parse(
155
156
  ) -> bool:
156
157
  if len(argv) != 0:
157
158
  return False
158
- if not _is_source_main_entrypoint():
159
- return False
160
159
  if "TEST_MODE" in original_environ and original_environ["TEST_MODE"] == "1":
161
160
  return False
162
161
  return not any(name in original_environ for name in _EXPLICIT_NAMESPACE_LAUNCH_ENV_NAMES)
@@ -777,8 +776,22 @@ def main(argv: list[str]) -> None:
777
776
 
778
777
 
779
778
  def cli() -> None:
780
- _bootstrap_default_namespace_if_empty(environ=os.environ)
781
- main([])
779
+ argv = sys.argv[1:]
780
+ if len(argv) != 0 and argv[0] == "update":
781
+ if argv != ["update"]:
782
+ raise RuntimeError("Usage: metalist update")
783
+ metalist_executable = _resolve_current_entrypoint()
784
+ if metalist_executable is None:
785
+ raise RuntimeError("Could not resolve the installed MetaList executable")
786
+ result = schedule_self_update(
787
+ metalist_executable=metalist_executable,
788
+ current_pid=os.getpid(),
789
+ platform_name=sys.platform,
790
+ environ=os.environ,
791
+ )
792
+ print(result.message)
793
+ return
794
+ main(argv)
782
795
 
783
796
 
784
797
  def run_namespace_server(argv: list[str]) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: metalist
3
- Version: 0.3.7
3
+ Version: 0.3.9
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
@@ -76,6 +76,12 @@ uv tool install metalist
76
76
  metalist
77
77
  ```
78
78
 
79
+ After the first installation, update and restart MetaList with one cross-platform command:
80
+ ```bash
81
+ metalist update
82
+ ```
83
+ The updater stops running namespaces, hands off to an external PowerShell process on Windows or `/bin/sh` on macOS/Linux so the installed environment can unlock, runs the forced cache-refreshed uv update, and launches MetaList again.
84
+
79
85
  For pip, users can run `pip install metalist`. For a non-editable local install from this checkout, use `uv pip install .` or `pip install .` instead of the editable command below.
80
86
 
81
87
  ```bash
@@ -87,11 +93,11 @@ npm install
87
93
  ```
88
94
 
89
95
  ### Run
90
- The installed entrypoint starts Uvicorn with the FastAPI app:
96
+ The installed entrypoint starts or restarts every known namespace, prints their URLs, and exits:
91
97
  ```bash
92
98
  metalist
93
99
  ```
94
- For source-checkout compatibility, `python main.py` still works. Plain `python main.py` is now an orchestration command: it restarts already-running namespaces from the current checkout, launches stopped namespaces, prints their URLs, and exits. Use `python main.py --namespace work` or `python main.py work` when you want one foreground namespace process.
100
+ For source-checkout compatibility, `python main.py` performs the same orchestration. Use `metalist work`, `python main.py --namespace work`, or `python main.py work` when you want one foreground namespace process.
95
101
 
96
102
  `metalist` and explicit single-namespace source runs bind HTTP on `0.0.0.0:8000` by default, matching the old MetaList LAN-friendly behavior.
97
103
  On first startup, MetaList also auto-generates a self-signed TLS pair at `~/MetaList/certs/metalist-cert.pem` and `~/MetaList/certs/metalist-key.pem`, then enables HTTPS on `0.0.0.0:8443`. If you already have real PEM files, point `METALIST_TLS_CERT` and `METALIST_TLS_KEY` at them instead. Set `METALIST_AUTO_GENERATE_TLS=0` only if you explicitly want HTTP-only startup.
@@ -104,7 +110,7 @@ Database selection:
104
110
  - Launch precedence is: explicit CLI flags > env vars > saved namespace profile; if a namespace has no saved profile, launch it once with explicit ports or configure ports from the UI
105
111
  - Backups stay beside the namespace data under `~/MetaList/namespaces/work/backups/` and use one archive per snapshot with filenames like `work-<timestamp>.metalist-backup.tar.gz`
106
112
  - The Backup Settings modal targets one user-selected backup folder and can include multiple namespaces in a single run
107
- - Restoring `work` into `work` is the normal overwrite path; importing a backup under a different namespace name requires a new target namespace and rejects saved launch-port conflicts.
113
+ - Restoring `work` into `work` is the normal overwrite path; importing a backup under a different namespace name can create a new target namespace with automatically selected conflict-free ports.
108
114
 
109
115
  Useful env flags:
110
116
  - `CRASH_SERVER_ON_FAIL=1` (default): fail-fast on validation errors
@@ -114,6 +114,7 @@ app/services/search_history.py
114
114
  app/services/search_index.py
115
115
  app/services/search_query.py
116
116
  app/services/search_text.py
117
+ app/services/self_update.py
117
118
  app/services/session_timeout_service.py
118
119
  app/services/shell_session_service.py
119
120
  app/services/snapshot.py
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes