MetaList 0.3.3__tar.gz → 0.3.6__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 (323) hide show
  1. {metalist-0.3.3/metalist.egg-info → metalist-0.3.6}/PKG-INFO +5 -5
  2. {metalist-0.3.3 → metalist-0.3.6}/README.md +4 -4
  3. {metalist-0.3.3 → metalist-0.3.6}/app/api/routes/auth.py +9 -1
  4. {metalist-0.3.3 → metalist-0.3.6}/app/api/routes/backups.py +96 -31
  5. {metalist-0.3.3 → metalist-0.3.6}/app/services/namespace_deletion_worker.py +8 -0
  6. {metalist-0.3.3 → metalist-0.3.6}/app/services/namespace_switcher.py +10 -0
  7. metalist-0.3.6/app/services/windows_process_control.py +145 -0
  8. {metalist-0.3.3 → metalist-0.3.6}/app/static/css/main.css +0 -13
  9. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/auth.js +23 -3
  10. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/modals/backup-restore-modal.js +151 -83
  11. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/modals/namespace-modals.js +2 -1
  12. metalist-0.3.6/app/static/js/modules/modals/namespace-ports-profile.js +17 -0
  13. {metalist-0.3.3 → metalist-0.3.6}/app/version.py +1 -1
  14. {metalist-0.3.3 → metalist-0.3.6}/convert-from-legacy.py +91 -11
  15. {metalist-0.3.3 → metalist-0.3.6}/main.py +10 -0
  16. {metalist-0.3.3 → metalist-0.3.6/metalist.egg-info}/PKG-INFO +5 -5
  17. {metalist-0.3.3 → metalist-0.3.6}/metalist.egg-info/SOURCES.txt +2 -0
  18. {metalist-0.3.3 → metalist-0.3.6}/MANIFEST.in +0 -0
  19. {metalist-0.3.3 → metalist-0.3.6}/app/__init__.py +0 -0
  20. {metalist-0.3.3 → metalist-0.3.6}/app/api/__init__.py +0 -0
  21. {metalist-0.3.3 → metalist-0.3.6}/app/api/deps.py +0 -0
  22. {metalist-0.3.3 → metalist-0.3.6}/app/api/dev.py +0 -0
  23. {metalist-0.3.3 → metalist-0.3.6}/app/api/middleware/auth.py +0 -0
  24. {metalist-0.3.3 → metalist-0.3.6}/app/api/request_auth.py +0 -0
  25. {metalist-0.3.3 → metalist-0.3.6}/app/api/routes/files.py +0 -0
  26. {metalist-0.3.3 → metalist-0.3.6}/app/api/routes/mcp.py +0 -0
  27. {metalist-0.3.3 → metalist-0.3.6}/app/api/routes/memory.py +0 -0
  28. {metalist-0.3.3 → metalist-0.3.6}/app/api/routes/notes.py +0 -0
  29. {metalist-0.3.3 → metalist-0.3.6}/app/api/routes/ontology.py +0 -0
  30. {metalist-0.3.3 → metalist-0.3.6}/app/api/routes/reminders.py +0 -0
  31. {metalist-0.3.3 → metalist-0.3.6}/app/api/routes/sounds.py +0 -0
  32. {metalist-0.3.3 → metalist-0.3.6}/app/api/routes/test.py +0 -0
  33. {metalist-0.3.3 → metalist-0.3.6}/app/api/transactions.py +0 -0
  34. {metalist-0.3.3 → metalist-0.3.6}/app/config.py +0 -0
  35. {metalist-0.3.3 → metalist-0.3.6}/app/db/__init__.py +0 -0
  36. {metalist-0.3.3 → metalist-0.3.6}/app/db/backup_settings_sql.py +0 -0
  37. {metalist-0.3.3 → metalist-0.3.6}/app/db/engine.py +0 -0
  38. {metalist-0.3.3 → metalist-0.3.6}/app/db/file_schema.py +0 -0
  39. {metalist-0.3.3 → metalist-0.3.6}/app/db/file_session.py +0 -0
  40. {metalist-0.3.3 → metalist-0.3.6}/app/db/files_sql.py +0 -0
  41. {metalist-0.3.3 → metalist-0.3.6}/app/db/link_titles_sql.py +0 -0
  42. {metalist-0.3.3 → metalist-0.3.6}/app/db/migrations.py +0 -0
  43. {metalist-0.3.3 → metalist-0.3.6}/app/db/notes_sql.py +0 -0
  44. {metalist-0.3.3 → metalist-0.3.6}/app/db/ontology_rules_sql.py +0 -0
  45. {metalist-0.3.3 → metalist-0.3.6}/app/db/reminders_sql.py +0 -0
  46. {metalist-0.3.3 → metalist-0.3.6}/app/db/schema.py +0 -0
  47. {metalist-0.3.3 → metalist-0.3.6}/app/db/search_history_sql.py +0 -0
  48. {metalist-0.3.3 → metalist-0.3.6}/app/db/session.py +0 -0
  49. {metalist-0.3.3 → metalist-0.3.6}/app/db/settings_sql.py +0 -0
  50. {metalist-0.3.3 → metalist-0.3.6}/app/db/sounds_sql.py +0 -0
  51. {metalist-0.3.3 → metalist-0.3.6}/app/db/tab_state_sql.py +0 -0
  52. {metalist-0.3.3 → metalist-0.3.6}/app/encryption_audit.py +0 -0
  53. {metalist-0.3.3 → metalist-0.3.6}/app/main.py +0 -0
  54. {metalist-0.3.3 → metalist-0.3.6}/app/mcp/__init__.py +0 -0
  55. {metalist-0.3.3 → metalist-0.3.6}/app/mcp/__main__.py +0 -0
  56. {metalist-0.3.3 → metalist-0.3.6}/app/mcp/errors.py +0 -0
  57. {metalist-0.3.3 → metalist-0.3.6}/app/mcp/policy.py +0 -0
  58. {metalist-0.3.3 → metalist-0.3.6}/app/mcp/read_service.py +0 -0
  59. {metalist-0.3.3 → metalist-0.3.6}/app/mcp/server.py +0 -0
  60. {metalist-0.3.3 → metalist-0.3.6}/app/mcp/tools.py +0 -0
  61. {metalist-0.3.3 → metalist-0.3.6}/app/models/commands.py +0 -0
  62. {metalist-0.3.3 → metalist-0.3.6}/app/models/database.py +0 -0
  63. {metalist-0.3.3 → metalist-0.3.6}/app/models/entities.py +0 -0
  64. {metalist-0.3.3 → metalist-0.3.6}/app/models/enums.py +0 -0
  65. {metalist-0.3.3 → metalist-0.3.6}/app/models/linked_list.py +0 -0
  66. {metalist-0.3.3 → metalist-0.3.6}/app/models/list_operations.py +0 -0
  67. {metalist-0.3.3 → metalist-0.3.6}/app/models/list_traversal.py +0 -0
  68. {metalist-0.3.3 → metalist-0.3.6}/app/models/note_crud.py +0 -0
  69. {metalist-0.3.3 → metalist-0.3.6}/app/models/utils.py +0 -0
  70. {metalist-0.3.3 → metalist-0.3.6}/app/presentation/__init__.py +0 -0
  71. {metalist-0.3.3 → metalist-0.3.6}/app/presentation/render/__init__.py +0 -0
  72. {metalist-0.3.3 → metalist-0.3.6}/app/presentation/render/note_renderer.py +0 -0
  73. {metalist-0.3.3 → metalist-0.3.6}/app/presentation/templates.py +0 -0
  74. {metalist-0.3.3 → metalist-0.3.6}/app/security/encryption.py +0 -0
  75. {metalist-0.3.3 → metalist-0.3.6}/app/server_runtime.py +0 -0
  76. {metalist-0.3.3 → metalist-0.3.6}/app/services/__init__.py +0 -0
  77. {metalist-0.3.3 → metalist-0.3.6}/app/services/auth.py +0 -0
  78. {metalist-0.3.3 → metalist-0.3.6}/app/services/auth_cache_state.py +0 -0
  79. {metalist-0.3.3 → metalist-0.3.6}/app/services/auth_service.py +0 -0
  80. {metalist-0.3.3 → metalist-0.3.6}/app/services/backlinks.py +0 -0
  81. {metalist-0.3.3 → metalist-0.3.6}/app/services/backup_service.py +0 -0
  82. {metalist-0.3.3 → metalist-0.3.6}/app/services/backup_settings_service.py +0 -0
  83. {metalist-0.3.3 → metalist-0.3.6}/app/services/base_service.py +0 -0
  84. {metalist-0.3.3 → metalist-0.3.6}/app/services/client_state_service.py +0 -0
  85. {metalist-0.3.3 → metalist-0.3.6}/app/services/content_cache.py +0 -0
  86. {metalist-0.3.3 → metalist-0.3.6}/app/services/content_formatting.py +0 -0
  87. {metalist-0.3.3 → metalist-0.3.6}/app/services/date_filtering.py +0 -0
  88. {metalist-0.3.3 → metalist-0.3.6}/app/services/dependencies.py +0 -0
  89. {metalist-0.3.3 → metalist-0.3.6}/app/services/diagnostics.py +0 -0
  90. {metalist-0.3.3 → metalist-0.3.6}/app/services/embedded_references.py +0 -0
  91. {metalist-0.3.3 → metalist-0.3.6}/app/services/encryption.py +0 -0
  92. {metalist-0.3.3 → metalist-0.3.6}/app/services/exception_capture.py +0 -0
  93. {metalist-0.3.3 → metalist-0.3.6}/app/services/file_registry.py +0 -0
  94. {metalist-0.3.3 → metalist-0.3.6}/app/services/file_storage.py +0 -0
  95. {metalist-0.3.3 → metalist-0.3.6}/app/services/html_export.py +0 -0
  96. {metalist-0.3.3 → metalist-0.3.6}/app/services/html_unformatting.py +0 -0
  97. {metalist-0.3.3 → metalist-0.3.6}/app/services/hydration_state.py +0 -0
  98. {metalist-0.3.3 → metalist-0.3.6}/app/services/integrity.py +0 -0
  99. {metalist-0.3.3 → metalist-0.3.6}/app/services/latex_rendering.py +0 -0
  100. {metalist-0.3.3 → metalist-0.3.6}/app/services/link_titles.py +0 -0
  101. {metalist-0.3.3 → metalist-0.3.6}/app/services/login_rate_limit.py +0 -0
  102. {metalist-0.3.3 → metalist-0.3.6}/app/services/maintenance_mode.py +0 -0
  103. {metalist-0.3.3 → metalist-0.3.6}/app/services/markdown_rendering.py +0 -0
  104. {metalist-0.3.3 → metalist-0.3.6}/app/services/memory.py +0 -0
  105. {metalist-0.3.3 → metalist-0.3.6}/app/services/memory_service.py +0 -0
  106. {metalist-0.3.3 → metalist-0.3.6}/app/services/namespace_deletion_jobs.py +0 -0
  107. {metalist-0.3.3 → metalist-0.3.6}/app/services/note_image_tags.py +0 -0
  108. {metalist-0.3.3 → metalist-0.3.6}/app/services/note_service.py +0 -0
  109. {metalist-0.3.3 → metalist-0.3.6}/app/services/note_store.py +0 -0
  110. {metalist-0.3.3 → metalist-0.3.6}/app/services/ontology_rules_store.py +0 -0
  111. {metalist-0.3.3 → metalist-0.3.6}/app/services/query_service.py +0 -0
  112. {metalist-0.3.3 → metalist-0.3.6}/app/services/reminders.py +0 -0
  113. {metalist-0.3.3 → metalist-0.3.6}/app/services/root_sorting.py +0 -0
  114. {metalist-0.3.3 → metalist-0.3.6}/app/services/runtime_hardening.py +0 -0
  115. {metalist-0.3.3 → metalist-0.3.6}/app/services/search_history.py +0 -0
  116. {metalist-0.3.3 → metalist-0.3.6}/app/services/search_index.py +0 -0
  117. {metalist-0.3.3 → metalist-0.3.6}/app/services/search_query.py +0 -0
  118. {metalist-0.3.3 → metalist-0.3.6}/app/services/search_text.py +0 -0
  119. {metalist-0.3.3 → metalist-0.3.6}/app/services/session_timeout_service.py +0 -0
  120. {metalist-0.3.3 → metalist-0.3.6}/app/services/shell_session_service.py +0 -0
  121. {metalist-0.3.3 → metalist-0.3.6}/app/services/snapshot.py +0 -0
  122. {metalist-0.3.3 → metalist-0.3.6}/app/services/sound_storage.py +0 -0
  123. {metalist-0.3.3 → metalist-0.3.6}/app/services/store.py +0 -0
  124. {metalist-0.3.3 → metalist-0.3.6}/app/services/sync.py +0 -0
  125. {metalist-0.3.3 → metalist-0.3.6}/app/services/sync_state.py +0 -0
  126. {metalist-0.3.3 → metalist-0.3.6}/app/services/tab_state.py +0 -0
  127. {metalist-0.3.3 → metalist-0.3.6}/app/services/tag_case.py +0 -0
  128. {metalist-0.3.3 → metalist-0.3.6}/app/services/tag_ontology.py +0 -0
  129. {metalist-0.3.3 → metalist-0.3.6}/app/services/tag_rename.py +0 -0
  130. {metalist-0.3.3 → metalist-0.3.6}/app/services/tag_suggestions.py +0 -0
  131. {metalist-0.3.3 → metalist-0.3.6}/app/services/tag_term_matching.py +0 -0
  132. {metalist-0.3.3 → metalist-0.3.6}/app/services/test_reset.py +0 -0
  133. {metalist-0.3.3 → metalist-0.3.6}/app/services/tokens.py +0 -0
  134. {metalist-0.3.3 → metalist-0.3.6}/app/services/transaction_manager.py +0 -0
  135. {metalist-0.3.3 → metalist-0.3.6}/app/services/undo_service.py +0 -0
  136. {metalist-0.3.3 → metalist-0.3.6}/app/services/undo_state.py +0 -0
  137. {metalist-0.3.3 → metalist-0.3.6}/app/services/view_cache.py +0 -0
  138. {metalist-0.3.3 → metalist-0.3.6}/app/services/view_diff.py +0 -0
  139. {metalist-0.3.3 → metalist-0.3.6}/app/services/view_state.py +0 -0
  140. {metalist-0.3.3 → metalist-0.3.6}/app/startup_js_sanity.py +0 -0
  141. {metalist-0.3.3 → metalist-0.3.6}/app/startup_sanity.py +0 -0
  142. {metalist-0.3.3 → metalist-0.3.6}/app/startup_sanity_config.py +0 -0
  143. {metalist-0.3.3 → metalist-0.3.6}/app/static/config/command_palette_tags.json +0 -0
  144. {metalist-0.3.3 → metalist-0.3.6}/app/static/css/forms.css +0 -0
  145. {metalist-0.3.3 → metalist-0.3.6}/app/static/img/favicon.ico +0 -0
  146. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/locked.js +0 -0
  147. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/main.js +0 -0
  148. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/activity-tracker.js +0 -0
  149. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/api-client.js +0 -0
  150. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/async-result.js +0 -0
  151. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/client-state-api.js +0 -0
  152. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/client-state-migration.js +0 -0
  153. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/command-palette/click-activation-service.js +0 -0
  154. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/command-palette/command-palette-controller.js +0 -0
  155. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/command-palette/endpoint-registry.js +0 -0
  156. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/command-palette/preferences-store.js +0 -0
  157. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/command-palette/tag-config-loader.js +0 -0
  158. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/command-palette/usage-store.js +0 -0
  159. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/config.js +0 -0
  160. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/connectivity-monitor.js +0 -0
  161. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/context-menu/context-menu-registry.js +0 -0
  162. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/context-menu/context-menu-service.js +0 -0
  163. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/context-menu/input-caret-service.js +0 -0
  164. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/dom-utils-fixed.js +0 -0
  165. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/dom-utils.js +0 -0
  166. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/editor-commands.js +0 -0
  167. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/editor-selection.js +0 -0
  168. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/editor-toolbar.js +0 -0
  169. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/error-handler.js +0 -0
  170. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/error-overlay.js +0 -0
  171. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/location-flags.js +0 -0
  172. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/login-namespace-picker.js +0 -0
  173. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/modals/alphabetize-root-notes-modal.js +0 -0
  174. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/modals/backup-result-modal.js +0 -0
  175. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/modals/backup-retention-modal.js +0 -0
  176. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/modals/backup-settings-modal.js +0 -0
  177. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/modals/base-modal.js +0 -0
  178. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/modals/delete-namespace-modal.js +0 -0
  179. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/modals/delete-namespace-validation.js +0 -0
  180. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/modals/help-modal.js +0 -0
  181. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/modals/memory-modal.js +0 -0
  182. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/modals/namespace-loading-page.js +0 -0
  183. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/modals/ontology-modal.js +0 -0
  184. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/modals/password-modal.js +0 -0
  185. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/modals/prioritize-modal.js +0 -0
  186. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/modals/random-password-modal.js +0 -0
  187. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/modals/reminder-modal.js +0 -0
  188. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/modals/reset-updated-at-modal.js +0 -0
  189. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/modals/session-timeout-modal.js +0 -0
  190. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/modals/sound-manager-modal.js +0 -0
  191. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/modals/version-info-modal.js +0 -0
  192. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/actions/content-actions.js +0 -0
  193. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/actions/history-actions.js +0 -0
  194. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/actions/note-actions.js +0 -0
  195. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/actions/search-actions.js +0 -0
  196. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/actions/selection-actions.js +0 -0
  197. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/actions/ui-actions.js +0 -0
  198. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/events/context-menu-events.js +0 -0
  199. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/events/focus-events.js +0 -0
  200. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/events/inactivity-events.js +0 -0
  201. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/events/input-events.js +0 -0
  202. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/events/keyboard-events.js +0 -0
  203. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/events/mouse-events.js +0 -0
  204. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/events/search-events.js +0 -0
  205. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/mode-context.js +0 -0
  206. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/mode-logger.js +0 -0
  207. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/mode-manager-controller.js +0 -0
  208. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/animated-scroll-service.js +0 -0
  209. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/backlinks-panel-service.js +0 -0
  210. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/clipboard-shortcut-policy-service.js +0 -0
  211. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/collapse-affordance-service.js +0 -0
  212. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/collapse-editing-policy-service.js +0 -0
  213. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/command-gate-service.js +0 -0
  214. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/context-menu-target-service.js +0 -0
  215. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/date-filter-indicator-service.js +0 -0
  216. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/date-filter-service.js +0 -0
  217. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/differential-view-service.js +0 -0
  218. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/edit-session-collapse-policy-service.js +0 -0
  219. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/edit-session-collapse-service.js +0 -0
  220. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/embedded-image-service.js +0 -0
  221. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/file-image-preview-service.js +0 -0
  222. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/file-reference-service.js +0 -0
  223. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/filtered-refresh-selection-service.js +0 -0
  224. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/html-paste-sanitizer-service.js +0 -0
  225. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/image-context-menu-action-service.js +0 -0
  226. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/image-file-insert-choice-modal-service.js +0 -0
  227. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/infinite-scroll-service.js +0 -0
  228. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/link-context-menu-action-service.js +0 -0
  229. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/markdown-render-service.js +0 -0
  230. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/note-click-target-service.js +0 -0
  231. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/note-clipboard-write-service.js +0 -0
  232. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/note-collapse-animation-service.js +0 -0
  233. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/note-context-menu-action-service.js +0 -0
  234. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/note-drag-service.js +0 -0
  235. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/note-reposition-animation-service.js +0 -0
  236. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/note-split-service.js +0 -0
  237. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/password-clipboard-service.js +0 -0
  238. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/polling-service.js +0 -0
  239. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/rhs-panel-service.js +0 -0
  240. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/root-date-separator-service.js +0 -0
  241. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/root-sort-indicator-service.js +0 -0
  242. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/root-sort-service.js +0 -0
  243. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/scroll-anchor-service.js +0 -0
  244. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/scroll-restoration-service.js +0 -0
  245. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/scroll-to-top-service.js +0 -0
  246. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/search-contexts-overlay-service.js +0 -0
  247. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/search-debounce-service.js +0 -0
  248. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/search-input-service.js +0 -0
  249. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/search-interaction-service.js +0 -0
  250. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/search-redaction-reveal-service.js +0 -0
  251. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/search-suggestions-service.js +0 -0
  252. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/search-syntax-service.js +0 -0
  253. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/shell-output-service.js +0 -0
  254. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/tab-dom-cache-service.js +0 -0
  255. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/tab-duplication-service.js +0 -0
  256. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/tab-state-service.js +0 -0
  257. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/tag-bar-service.js +0 -0
  258. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/tag-suggestions-service.js +0 -0
  259. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/tag-syntax-service.js +0 -0
  260. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/todo-toggle-editing-service.js +0 -0
  261. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/mode-manager/services/view-mode-search-shortcut-service.js +0 -0
  262. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/password-generator.js +0 -0
  263. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/reminder-store.js +0 -0
  264. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/reminder-surface-service.js +0 -0
  265. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/selection-markers.js +0 -0
  266. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/session-auth.js +0 -0
  267. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/sound-service.js +0 -0
  268. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/tag-token.js +0 -0
  269. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/modules/uuid.js +0 -0
  270. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/namespace-deleted.js +0 -0
  271. {metalist-0.3.3 → metalist-0.3.6}/app/static/js/vendor/markdown-it.min.js +0 -0
  272. {metalist-0.3.3 → metalist-0.3.6}/app/static/video/login-startup.mp4 +0 -0
  273. {metalist-0.3.3 → metalist-0.3.6}/app/templates/base.html +0 -0
  274. {metalist-0.3.3 → metalist-0.3.6}/app/templates/index.html +0 -0
  275. {metalist-0.3.3 → metalist-0.3.6}/app/templates/locked.html +0 -0
  276. {metalist-0.3.3 → metalist-0.3.6}/app/templates/maintenance.html +0 -0
  277. {metalist-0.3.3 → metalist-0.3.6}/app/templates/namespace_deleted.html +0 -0
  278. {metalist-0.3.3 → metalist-0.3.6}/app/templates/notes_list.html +0 -0
  279. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/__init__.py +0 -0
  280. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/alphabetize_root_notes.py +0 -0
  281. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/base.py +0 -0
  282. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/collapse.py +0 -0
  283. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/copy_note.py +0 -0
  284. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/create_child.py +0 -0
  285. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/create_note.py +0 -0
  286. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/create_sibling.py +0 -0
  287. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/delete_subtree.py +0 -0
  288. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/expand.py +0 -0
  289. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/indent.py +0 -0
  290. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/lock.py +0 -0
  291. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/move.py +0 -0
  292. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/move_to_top.py +0 -0
  293. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/outdent.py +0 -0
  294. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/paste_child.py +0 -0
  295. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/paste_sibling.py +0 -0
  296. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/prioritize.py +0 -0
  297. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/record_edit_mode.py +0 -0
  298. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/redo.py +0 -0
  299. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/rename_tag.py +0 -0
  300. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/reset_updated_at.py +0 -0
  301. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/run_shell.py +0 -0
  302. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/search_comment_autofill.py +0 -0
  303. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/search_context_tags.py +0 -0
  304. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/set_collapse_bulk.py +0 -0
  305. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/set_collapse_in_context.py +0 -0
  306. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/split_note.py +0 -0
  307. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/toggle_reference_mode.py +0 -0
  308. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/toggle_todo_done.py +0 -0
  309. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/undo.py +0 -0
  310. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/unformat_content.py +0 -0
  311. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/update_content.py +0 -0
  312. {metalist-0.3.3 → metalist-0.3.6}/app/usecases/view.py +0 -0
  313. {metalist-0.3.3 → metalist-0.3.6}/app/utils/__init__.py +0 -0
  314. {metalist-0.3.3 → metalist-0.3.6}/app/utils/encryption.py +0 -0
  315. {metalist-0.3.3 → metalist-0.3.6}/app/utils/text_utils.py +0 -0
  316. {metalist-0.3.3 → metalist-0.3.6}/mcp_client.py +0 -0
  317. {metalist-0.3.3 → metalist-0.3.6}/metalist.egg-info/dependency_links.txt +0 -0
  318. {metalist-0.3.3 → metalist-0.3.6}/metalist.egg-info/entry_points.txt +0 -0
  319. {metalist-0.3.3 → metalist-0.3.6}/metalist.egg-info/requires.txt +0 -0
  320. {metalist-0.3.3 → metalist-0.3.6}/metalist.egg-info/top_level.txt +0 -0
  321. {metalist-0.3.3 → metalist-0.3.6}/pyproject.toml +0 -0
  322. {metalist-0.3.3 → metalist-0.3.6}/scripts/generate-lan-cert.sh +0 -0
  323. {metalist-0.3.3 → metalist-0.3.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: metalist
3
- Version: 0.3.3
3
+ Version: 0.3.6
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
@@ -234,9 +234,9 @@ Tool catalog and schemas:
234
234
  - `docs/mcp_tools.md`
235
235
 
236
236
  ### Legacy Import
237
- `convert-from-legacy.py` replaces the SQLite database referenced by `app.config.DATABASE_URL` and imports notes from a legacy JSON export.
237
+ `convert-from-legacy.py` replaces the SQLite database referenced by `app.config.DATABASE_URL`, clears its files/sounds sidecar, and imports notes from a legacy JSON export.
238
238
 
239
- This is destructive. It deletes the existing DB file before rebuilding it.
239
+ This is destructive. It deletes the existing notes DB and related files/sounds DB before rebuilding the namespace.
240
240
 
241
241
  Example usage:
242
242
  ```bash
@@ -263,11 +263,11 @@ This repo now packages itself under the PyPI distribution name `metalist`. Curre
263
263
 
264
264
  Recommended release path:
265
265
  1. In the existing PyPI project `metalist`, configure GitHub Trusted Publishing for `evolvingstuff/metalist` and the workflow file `.github/workflows/publish-pypi.yml`.
266
- 2. Push a tag such as `v0.3.3`.
266
+ 2. Push a tag such as `v0.3.5`.
267
267
  3. After the GitHub Actions workflow completes, users can run it with `uvx metalist`, install it persistently with `uv tool install metalist`, or install it with `pip install metalist`.
268
268
 
269
269
  If `--input` is omitted, a file picker opens (when `tkinter` is available).
270
- Notes tagged with `@implies` are converted into ontology rules and are not imported as notes.
270
+ Notes tagged with `@implies` are converted into ontology rules and are not imported as notes. Legacy rules that are invalid under the current ontology grammar are reported and skipped while valid rules continue importing.
271
271
 
272
272
  ### Run Tests
273
273
 
@@ -205,9 +205,9 @@ Tool catalog and schemas:
205
205
  - `docs/mcp_tools.md`
206
206
 
207
207
  ### Legacy Import
208
- `convert-from-legacy.py` replaces the SQLite database referenced by `app.config.DATABASE_URL` and imports notes from a legacy JSON export.
208
+ `convert-from-legacy.py` replaces the SQLite database referenced by `app.config.DATABASE_URL`, clears its files/sounds sidecar, and imports notes from a legacy JSON export.
209
209
 
210
- This is destructive. It deletes the existing DB file before rebuilding it.
210
+ This is destructive. It deletes the existing notes DB and related files/sounds DB before rebuilding the namespace.
211
211
 
212
212
  Example usage:
213
213
  ```bash
@@ -234,11 +234,11 @@ This repo now packages itself under the PyPI distribution name `metalist`. Curre
234
234
 
235
235
  Recommended release path:
236
236
  1. In the existing PyPI project `metalist`, configure GitHub Trusted Publishing for `evolvingstuff/metalist` and the workflow file `.github/workflows/publish-pypi.yml`.
237
- 2. Push a tag such as `v0.3.3`.
237
+ 2. Push a tag such as `v0.3.5`.
238
238
  3. After the GitHub Actions workflow completes, users can run it with `uvx metalist`, install it persistently with `uv tool install metalist`, or install it with `pip install metalist`.
239
239
 
240
240
  If `--input` is omitted, a file picker opens (when `tkinter` is available).
241
- Notes tagged with `@implies` are converted into ontology rules and are not imported as notes.
241
+ Notes tagged with `@implies` are converted into ontology rules and are not imported as notes. Legacy rules that are invalid under the current ontology grammar are reported and skipped while valid rules continue importing.
242
242
 
243
243
  ### Run Tests
244
244
 
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import logging
3
4
  import secrets
4
5
  import sqlite3
5
6
  from fastapi import APIRouter, Depends, Header, HTTPException, Request, Response
@@ -88,6 +89,7 @@ from app.services.client_state_service import save_command_palette_usage
88
89
 
89
90
 
90
91
  router = APIRouter(prefix="/auth", tags=["auth2"])
92
+ logger = logging.getLogger(__name__)
91
93
 
92
94
 
93
95
  class LoginRequest(BaseModel):
@@ -437,7 +439,13 @@ def _on_hydration_done(future: Future) -> None:
437
439
  return
438
440
  error = future.exception()
439
441
  if error is not None:
440
- hydration_state.fail(str(error))
442
+ error_message = f"{type(error).__name__}: {error}"
443
+ logger.error(
444
+ "Hydration worker failed: %s",
445
+ error_message,
446
+ exc_info=(type(error), error, error.__traceback__),
447
+ )
448
+ hydration_state.fail(error_message)
441
449
 
442
450
 
443
451
  def _start_hydration(*, first_load: bool, rebuild_required: bool) -> None:
@@ -35,6 +35,7 @@ from app.server_runtime import NamespaceLaunchProfile
35
35
  from app.server_runtime import _DEFAULT_HTTP_PORT
36
36
  from app.server_runtime import _DEFAULT_MCP_AGENT_WEB_PORT
37
37
  from app.server_runtime import load_all_namespace_launch_profiles
38
+ from app.server_runtime import load_namespace_launch_profile
38
39
  from app.server_runtime import resolve_namespace_directory
39
40
  from app.server_runtime import resolve_namespaced_database_path
40
41
  from app.server_runtime import resolve_namespaces_directory
@@ -125,6 +126,7 @@ class BackupRestorePreflightResponse(BaseModel):
125
126
  backup_namespace: str
126
127
  target_namespace: str
127
128
  same_namespace: bool
129
+ target_is_active: bool
128
130
  target_exists: bool
129
131
  target_requires_password: bool
130
132
  restored_profile: BackupRestoreLaunchProfileResponse | None
@@ -699,6 +701,22 @@ def _response_profile_from_backup_profile(
699
701
  )
700
702
 
701
703
 
704
+ def _required_existing_target_launch_profile(*, target_namespace: str) -> BackupLaunchProfile:
705
+ profile = load_namespace_launch_profile(namespace=target_namespace)
706
+ if profile is None:
707
+ raise RuntimeError(f"Existing target namespace has no saved launch profile: {target_namespace}")
708
+ if profile.port is None:
709
+ raise RuntimeError(f"Existing target namespace has no saved HTTP port: {target_namespace}")
710
+ if profile.mcp_port is None:
711
+ raise RuntimeError(f"Existing target namespace has no saved MCP port: {target_namespace}")
712
+ return BackupLaunchProfile(
713
+ namespace=target_namespace,
714
+ port=profile.port,
715
+ https_port=profile.https_port,
716
+ mcp_port=profile.mcp_port,
717
+ )
718
+
719
+
702
720
  def _backup_profile_from_request(
703
721
  *,
704
722
  namespace: str,
@@ -725,6 +743,27 @@ def _assert_import_profile_has_no_internal_overlap(*, profile: BackupLaunchProfi
725
743
  )
726
744
 
727
745
 
746
+ def _restore_import_to_target(
747
+ *,
748
+ backup_path: Path,
749
+ target_database_path: Path,
750
+ backup_namespace: str,
751
+ target_namespace: str,
752
+ launch_profile: BackupLaunchProfile,
753
+ ) -> None:
754
+ restore_backup_to_paths_from_namespace(
755
+ backup_path,
756
+ target_database_path,
757
+ source_namespace=backup_namespace,
758
+ )
759
+ save_namespace_launch_profile(
760
+ namespace=target_namespace,
761
+ port=launch_profile.port,
762
+ https_port=launch_profile.https_port,
763
+ mcp_port=launch_profile.mcp_port,
764
+ )
765
+
766
+
728
767
  @router.get("/settings", response_model=BackupSettingsResponse)
729
768
  def get_backup_settings(token: Annotated[str, Depends(_require_auth)]):
730
769
  settings = load_backup_settings(token=token)
@@ -878,23 +917,32 @@ def restore_backup_preflight(
878
917
  backup_path,
879
918
  expected_namespace=backup_namespace,
880
919
  )
920
+ target_exists = _restore_target_exists(target_namespace=target_namespace)
881
921
  suggested_profile = None
882
922
  port_conflicts: list[str] = []
883
923
  if target_namespace != backup_namespace:
884
- port_conflicts = _collect_import_profile_port_conflicts(
885
- target_namespace=target_namespace,
886
- launch_profile=restored_profile,
887
- )
888
- suggested_profile = _suggest_import_launch_profile(
889
- target_namespace=target_namespace,
890
- restored_profile=restored_profile,
891
- )
924
+ if target_exists:
925
+ target_profile = _required_existing_target_launch_profile(
926
+ target_namespace=target_namespace,
927
+ )
928
+ suggested_profile = _response_profile_from_backup_profile(profile=target_profile)
929
+ assert suggested_profile is not None
930
+ else:
931
+ port_conflicts = _collect_import_profile_port_conflicts(
932
+ target_namespace=target_namespace,
933
+ launch_profile=restored_profile,
934
+ )
935
+ suggested_profile = _suggest_import_launch_profile(
936
+ target_namespace=target_namespace,
937
+ restored_profile=restored_profile,
938
+ )
892
939
 
893
940
  return BackupRestorePreflightResponse(
894
941
  backup_namespace=backup_namespace,
895
942
  target_namespace=target_namespace,
896
943
  same_namespace=target_namespace == backup_namespace,
897
- target_exists=_restore_target_exists(target_namespace=target_namespace),
944
+ target_is_active=target_namespace == ACTIVE_NAMESPACE,
945
+ target_exists=target_exists,
898
946
  target_requires_password=_target_namespace_requires_password(target_namespace=target_namespace),
899
947
  restored_profile=_response_profile_from_backup_profile(profile=restored_profile),
900
948
  suggested_profile=suggested_profile,
@@ -999,27 +1047,44 @@ def import_backup(
999
1047
  if not backup_path.exists():
1000
1048
  raise HTTPException(status_code=404, detail=f"Backup not found: {folder_filename}")
1001
1049
 
1002
- launch_profile = _backup_profile_from_request(
1003
- namespace=target_namespace,
1004
- profile=payload.launch_profile,
1005
- )
1006
- _assert_import_profile_has_no_internal_overlap(profile=launch_profile)
1007
- _assert_import_profile_ports_do_not_conflict(
1008
- target_namespace=target_namespace,
1009
- launch_profile=launch_profile,
1010
- )
1050
+ if target_exists:
1051
+ launch_profile = _required_existing_target_launch_profile(
1052
+ target_namespace=target_namespace,
1053
+ )
1054
+ else:
1055
+ launch_profile = _backup_profile_from_request(
1056
+ namespace=target_namespace,
1057
+ profile=payload.launch_profile,
1058
+ )
1059
+ _assert_import_profile_has_no_internal_overlap(profile=launch_profile)
1060
+ _assert_import_profile_ports_do_not_conflict(
1061
+ target_namespace=target_namespace,
1062
+ launch_profile=launch_profile,
1063
+ )
1011
1064
 
1012
- restore_backup_to_paths_from_namespace(
1013
- backup_path,
1014
- target_database_path,
1015
- source_namespace=backup_namespace,
1016
- )
1017
- save_namespace_launch_profile(
1018
- namespace=target_namespace,
1019
- port=launch_profile.port,
1020
- https_port=launch_profile.https_port,
1021
- mcp_port=launch_profile.mcp_port,
1022
- )
1065
+ target_is_active = target_namespace == ACTIVE_NAMESPACE
1066
+ if target_is_active:
1067
+ maintenance_service.enter_maintenance("Importing backup")
1068
+ try:
1069
+ _restore_import_to_target(
1070
+ backup_path=backup_path,
1071
+ target_database_path=target_database_path,
1072
+ backup_namespace=backup_namespace,
1073
+ target_namespace=target_namespace,
1074
+ launch_profile=launch_profile,
1075
+ )
1076
+ _reset_runtime_state_after_restore()
1077
+ finally:
1078
+ maintenance_service.exit_maintenance()
1079
+ _schedule_server_restart_after_restore(delay_seconds=0.5)
1080
+ else:
1081
+ _restore_import_to_target(
1082
+ backup_path=backup_path,
1083
+ target_database_path=target_database_path,
1084
+ backup_namespace=backup_namespace,
1085
+ target_namespace=target_namespace,
1086
+ launch_profile=launch_profile,
1087
+ )
1023
1088
 
1024
1089
  return BackupRestoreResponse(
1025
1090
  backup_id=payload.backup_id,
@@ -1027,7 +1092,7 @@ def import_backup(
1027
1092
  backup_filename=payload.backup_filename,
1028
1093
  backup_namespace=backup_namespace,
1029
1094
  target_namespace=target_namespace,
1030
- active_namespace_restarted=False,
1031
- open_namespace_suggested=True,
1095
+ active_namespace_restarted=target_is_active,
1096
+ open_namespace_suggested=not target_is_active,
1032
1097
  message="Backup imported successfully",
1033
1098
  )
@@ -5,6 +5,7 @@ import os
5
5
  import shutil
6
6
  import signal
7
7
  import subprocess
8
+ import sys
8
9
  import time
9
10
  import traceback
10
11
 
@@ -14,6 +15,8 @@ from app.server_runtime import validate_namespace
14
15
  from app.services.exception_capture import CapturedExceptionContext
15
16
  from app.services.namespace_deletion_jobs import mark_namespace_deletion_job_failed
16
17
  from app.services.namespace_deletion_jobs import mark_namespace_deletion_job_succeeded
18
+ from app.services.windows_process_control import is_process_running as is_windows_process_running
19
+ from app.services.windows_process_control import stop_process as stop_windows_process
17
20
 
18
21
 
19
22
  _WAIT_POLL_INTERVAL_SECONDS = 0.25
@@ -50,6 +53,8 @@ def _is_process_running(*, pid: int) -> bool:
50
53
  raise TypeError(f"pid must be an int, got {type(pid)}")
51
54
  if pid <= 0:
52
55
  raise ValueError(f"pid must be positive, got: {pid}")
56
+ if sys.platform == "win32":
57
+ return is_windows_process_running(pid=pid)
53
58
  kill_capture = CapturedExceptionContext(ProcessLookupError, PermissionError)
54
59
  with kill_capture:
55
60
  os.kill(pid, 0)
@@ -92,6 +97,9 @@ def _send_signal_if_running(*, pid: int, signal_number: int) -> None:
92
97
 
93
98
 
94
99
  def _stop_process(*, pid: int) -> None:
100
+ if sys.platform == "win32":
101
+ stop_windows_process(pid=pid)
102
+ return
95
103
  if _wait_for_process_exit(pid=pid, timeout_seconds=_INITIAL_EXIT_GRACE_SECONDS):
96
104
  return
97
105
 
@@ -30,6 +30,9 @@ from app.server_runtime import validate_namespace
30
30
  from app.services.diagnostics import recycle_direct_append_log_file
31
31
  from app.services.exception_capture import CapturedExceptionContext
32
32
  from app.services.namespace_deletion_jobs import create_namespace_deletion_job
33
+ from app.services.windows_process_control import find_listening_pids_for_port as find_windows_listening_pids_for_port
34
+ from app.services.windows_process_control import is_process_running as is_windows_process_running
35
+ from app.services.windows_process_control import stop_process as stop_windows_process
33
36
 
34
37
 
35
38
  _PROJECT_ROOT = Path(__file__).resolve().parents[2]
@@ -1086,6 +1089,8 @@ def _is_process_running(*, pid: int) -> bool:
1086
1089
  raise TypeError(f"pid must be an int, got {type(pid)}")
1087
1090
  if pid <= 0:
1088
1091
  raise ValueError(f"pid must be positive, got: {pid}")
1092
+ if sys.platform == "win32":
1093
+ return is_windows_process_running(pid=pid)
1089
1094
  kill_capture = CapturedExceptionContext(ProcessLookupError, PermissionError)
1090
1095
  with kill_capture:
1091
1096
  os.kill(pid, 0)
@@ -1128,6 +1133,9 @@ def _send_signal_if_running(*, pid: int, signal_number: int) -> None:
1128
1133
 
1129
1134
 
1130
1135
  def _stop_process(*, pid: int) -> None:
1136
+ if sys.platform == "win32":
1137
+ stop_windows_process(pid=pid)
1138
+ return
1131
1139
  if not _is_process_running(pid=pid):
1132
1140
  return
1133
1141
 
@@ -1147,6 +1155,8 @@ def _find_listening_pids_for_port(*, port: int) -> list[int]:
1147
1155
  raise TypeError(f"port must be an int, got {type(port)}")
1148
1156
  if port <= 0 or port > 65535:
1149
1157
  raise ValueError(f"port must be between 1 and 65535, got: {port}")
1158
+ if sys.platform == "win32":
1159
+ return find_windows_listening_pids_for_port(port=port)
1150
1160
 
1151
1161
  lsof_path = shutil.which("lsof")
1152
1162
  if lsof_path is None:
@@ -0,0 +1,145 @@
1
+ from __future__ import annotations
2
+
3
+ import shutil
4
+ import subprocess
5
+ import time
6
+
7
+
8
+ _WAIT_POLL_INTERVAL_SECONDS = 0.25
9
+ _TERMINATE_GRACE_SECONDS = 5.0
10
+ _KILL_GRACE_SECONDS = 5.0
11
+
12
+
13
+ def _validate_pid(*, pid: int) -> None:
14
+ if not isinstance(pid, int):
15
+ raise TypeError(f"pid must be an int, got {type(pid)}")
16
+ if pid <= 0:
17
+ raise ValueError(f"pid must be positive, got: {pid}")
18
+
19
+
20
+ def _validate_port(*, port: int) -> None:
21
+ if not isinstance(port, int):
22
+ raise TypeError(f"port must be an int, got {type(port)}")
23
+ if port <= 0 or port > 65535:
24
+ raise ValueError(f"port must be between 1 and 65535, got: {port}")
25
+
26
+
27
+ def _resolve_powershell_path() -> str:
28
+ powershell_path = shutil.which("powershell.exe")
29
+ if powershell_path is not None:
30
+ return powershell_path
31
+ pwsh_path = shutil.which("pwsh.exe")
32
+ if pwsh_path is not None:
33
+ return pwsh_path
34
+ raise RuntimeError("PowerShell is required for MetaList process management on Windows")
35
+
36
+
37
+ def _run_powershell(*, script: str, operation: str) -> str:
38
+ if script.strip() == "":
39
+ raise ValueError("PowerShell script must not be empty")
40
+ if operation.strip() == "":
41
+ raise ValueError("PowerShell operation must not be empty")
42
+ completed = subprocess.run(
43
+ [
44
+ _resolve_powershell_path(),
45
+ "-NoLogo",
46
+ "-NoProfile",
47
+ "-NonInteractive",
48
+ "-Command",
49
+ script,
50
+ ],
51
+ capture_output=True,
52
+ check=False,
53
+ text=True,
54
+ )
55
+ if completed.returncode != 0:
56
+ raise RuntimeError(
57
+ f"PowerShell failed while {operation}: "
58
+ f"exit={completed.returncode} stderr={completed.stderr.strip()!r}"
59
+ )
60
+ return completed.stdout.strip()
61
+
62
+
63
+ def find_listening_pids_for_port(*, port: int) -> list[int]:
64
+ _validate_port(port=port)
65
+ stdout = _run_powershell(
66
+ script=(
67
+ f"@(Get-NetTCPConnection -State Listen -LocalPort {port} -ErrorAction SilentlyContinue "
68
+ "| Select-Object -ExpandProperty OwningProcess) -join [Environment]::NewLine"
69
+ ),
70
+ operation=f"checking port {port}",
71
+ )
72
+ if stdout == "":
73
+ return []
74
+
75
+ ordered_pids: list[int] = []
76
+ seen_pids: set[int] = set()
77
+ for raw_line in stdout.splitlines():
78
+ raw_pid = raw_line.strip()
79
+ if not raw_pid.isdigit():
80
+ raise RuntimeError(
81
+ f"PowerShell returned a non-numeric listener pid for port {port}: {raw_pid!r}"
82
+ )
83
+ pid = int(raw_pid)
84
+ if pid <= 0:
85
+ raise RuntimeError(f"PowerShell returned invalid listener pid for port {port}: {pid}")
86
+ if pid in seen_pids:
87
+ continue
88
+ seen_pids.add(pid)
89
+ ordered_pids.append(pid)
90
+ return ordered_pids
91
+
92
+
93
+ def is_process_running(*, pid: int) -> bool:
94
+ _validate_pid(pid=pid)
95
+ stdout = _run_powershell(
96
+ script=(
97
+ f"@(Get-Process -Id {pid} -ErrorAction SilentlyContinue "
98
+ "| Select-Object -ExpandProperty Id) -join [Environment]::NewLine"
99
+ ),
100
+ operation=f"checking process {pid}",
101
+ )
102
+ if stdout == "":
103
+ return False
104
+ if stdout != str(pid):
105
+ raise RuntimeError(f"PowerShell returned an unexpected process id for pid {pid}: {stdout!r}")
106
+ return True
107
+
108
+
109
+ def _wait_for_process_exit(*, pid: int, timeout_seconds: float) -> bool:
110
+ if not isinstance(timeout_seconds, float):
111
+ raise TypeError(f"timeout_seconds must be a float, got {type(timeout_seconds)}")
112
+ if timeout_seconds < 0.0:
113
+ raise ValueError(f"timeout_seconds must be >= 0.0, got {timeout_seconds}")
114
+
115
+ deadline = time.monotonic() + timeout_seconds
116
+ while time.monotonic() < deadline:
117
+ if not is_process_running(pid=pid):
118
+ return True
119
+ time.sleep(_WAIT_POLL_INTERVAL_SECONDS)
120
+ return not is_process_running(pid=pid)
121
+
122
+
123
+ def stop_process(*, pid: int) -> None:
124
+ _validate_pid(pid=pid)
125
+ if not is_process_running(pid=pid):
126
+ return
127
+
128
+ _run_powershell(
129
+ script=f"Stop-Process -Id {pid} -ErrorAction Stop",
130
+ operation=f"stopping process {pid}",
131
+ )
132
+ if _wait_for_process_exit(pid=pid, timeout_seconds=_TERMINATE_GRACE_SECONDS):
133
+ return
134
+ if not is_process_running(pid=pid):
135
+ return
136
+
137
+ _run_powershell(
138
+ script=f"Stop-Process -Id {pid} -Force -ErrorAction Stop",
139
+ operation=f"force-stopping process {pid}",
140
+ )
141
+ if _wait_for_process_exit(pid=pid, timeout_seconds=_KILL_GRACE_SECONDS):
142
+ return
143
+ if not is_process_running(pid=pid):
144
+ return
145
+ raise RuntimeError(f"Timed out waiting for Windows process {pid} to exit")
@@ -1472,19 +1472,6 @@ body.ontology-modal-open #ontology-modal {
1472
1472
  font-weight: 700;
1473
1473
  }
1474
1474
 
1475
- .backup-restore-port-config {
1476
- margin: 16px 0;
1477
- }
1478
-
1479
- .backup-restore-port-config h4 {
1480
- margin: 0 0 8px;
1481
- }
1482
-
1483
- .backup-restore-port-config ul {
1484
- margin: 8px 0 0;
1485
- padding-left: 22px;
1486
- }
1487
-
1488
1475
  .backup-retention-modal-content {
1489
1476
  width: min(760px, 92vw);
1490
1477
  }
@@ -533,7 +533,13 @@ export const Auth = {
533
533
  if (typeof status.error === 'string' && status.error.length > 0) {
534
534
  throw new Error(status.error);
535
535
  }
536
- throw new Error('Hydration failed');
536
+ const failedPhase = typeof status.phase === 'string' && status.phase.length > 0
537
+ ? status.phase
538
+ : 'unknown phase';
539
+ const failedMessage = typeof status.message === 'string' && status.message.length > 0
540
+ ? status.message
541
+ : 'server returned no error detail';
542
+ throw new Error(`Hydration failed during ${failedPhase}: ${failedMessage}`);
537
543
  }
538
544
  await new Promise((resolve) => setTimeout(resolve, 200));
539
545
  const pollResponse = await fetch(CONFIG.API.AUTH.HYDRATION_STATUS, { headers });
@@ -680,6 +686,7 @@ export const Auth = {
680
686
  }
681
687
 
682
688
  const responseText = await response.text();
689
+ let startupPhase = 'reading the login response';
683
690
  try {
684
691
  const data = JSON.parse(responseText);
685
692
 
@@ -691,28 +698,41 @@ export const Auth = {
691
698
  if (data.hydration_required !== true) {
692
699
  throw new Error('Login response must require the progress flow');
693
700
  }
701
+ startupPhase = 'hydrating the workspace';
694
702
  await this._runHydrationFlow();
695
703
 
696
704
  console.log('[Auth] Login successful, initializing ModeManager');
697
705
  if (window.ModeManager) {
706
+ startupPhase = 'initializing the workspace UI';
698
707
  await window.ModeManager.init({});
708
+ startupPhase = 'initializing the command palette';
699
709
  await CommandPalette.init();
710
+ startupPhase = 'finishing the startup introduction';
700
711
  await this.waitForStartupIntro();
712
+ startupPhase = 'revealing the workspace';
701
713
  this.revealMainApp();
714
+ startupPhase = 'starting reminders';
702
715
  await ReminderSurface.start();
703
716
  document.body.dataset.appReady = 'true';
704
717
  } else {
718
+ startupPhase = 'reloading the workspace';
705
719
  window.location.reload();
706
720
  }
707
721
  } catch (error) {
708
722
  document.body.classList.remove('loading');
709
723
  this._setLoginLoadingTitle('Workspace startup failed');
710
724
  const loadingMessage = this._requireElement('login-loading-message');
711
- loadingMessage.textContent = 'Your password was accepted, but the workspace could not finish opening.';
725
+ const errorMessage = error instanceof Error
726
+ ? `${error.name}: ${error.message}`
727
+ : `Non-Error thrown: ${String(error)}`;
728
+ const diagnosticMessage = `${startupPhase}: ${errorMessage}`;
729
+ loadingMessage.textContent =
730
+ `Your password was accepted, but the workspace could not finish opening. ${diagnosticMessage}`;
731
+ window.alert(`MetaList workspace startup failed:\n\n${diagnosticMessage}`);
712
732
  if (error instanceof Error) {
713
733
  throw error;
714
734
  }
715
- throw new Error('Workspace startup failed');
735
+ throw new Error(errorMessage);
716
736
  }
717
737
  document.body.classList.remove('loading');
718
738
  },