MetaList 0.7.3__tar.gz → 0.7.5__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.
- {metalist-0.7.3 → metalist-0.7.5}/PKG-INFO +13 -2
- {metalist-0.7.3 → metalist-0.7.5}/README.md +12 -1
- {metalist-0.7.3 → metalist-0.7.5}/app/https_proxy.py +55 -15
- {metalist-0.7.3 → metalist-0.7.5}/app/main.py +13 -0
- metalist-0.7.5/app/security/http_error_diagnostics.py +19 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/self_update.py +1 -7
- metalist-0.7.5/app/services/update_installer.py +260 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/update_preflight.py +2 -5
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/api-client.js +2 -1
- metalist-0.7.5/app/static/js/modules/api-error-diagnostics.js +16 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/version.py +1 -1
- {metalist-0.7.3 → metalist-0.7.5}/metalist.egg-info/PKG-INFO +13 -2
- {metalist-0.7.3 → metalist-0.7.5}/metalist.egg-info/SOURCES.txt +2 -0
- {metalist-0.7.3 → metalist-0.7.5}/pyproject.toml +2 -0
- metalist-0.7.3/app/services/update_installer.py +0 -122
- {metalist-0.7.3 → metalist-0.7.5}/MANIFEST.in +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/__init__.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/api/__init__.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/api/deps.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/api/dev.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/api/middleware/auth.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/api/note_requests.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/api/request_auth.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/api/routes/ai.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/api/routes/app_updates.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/api/routes/auth.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/api/routes/backups.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/api/routes/files.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/api/routes/notes.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/api/routes/ontology.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/api/routes/reminders.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/api/routes/remote_images.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/api/routes/test.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/api/transactions.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/api/upload_limits.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/config.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/data_directory.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/db/__init__.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/db/backup_settings_sql.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/db/engine.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/db/file_schema.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/db/file_session.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/db/files_sql.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/db/link_titles_sql.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/db/live_recovery.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/db/migrations.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/db/notes_sql.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/db/ontology_rules_sql.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/db/reminders_sql.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/db/retire_sounds.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/db/schema.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/db/search_history_sql.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/db/session.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/db/settings_sql.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/db/tab_state_sql.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/db/version.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/encryption_audit.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/exception_boundaries.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/models/commands.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/models/database.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/models/entities.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/models/enums.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/models/linked_list.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/models/list_operations.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/models/list_traversal.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/models/note_crud.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/models/utils.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/network_settings.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/presentation/__init__.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/presentation/render/__init__.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/presentation/render/note_renderer.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/presentation/templates.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/security/authenticated_logging.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/security/encryption.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/security/http_headers.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/security/note_html.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/security/request_boundary.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/security/request_hosts.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/security/sensitive_cache.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/security/sensitive_logging.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/security/shell_execution.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/security/validation_errors.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/server_runtime.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/__init__.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/__init__.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/actions.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/cloud_privacy.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/context.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/evidence_serialization.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/help_catalog.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/history.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/inference.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/investigation.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/judging.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/menu_actions.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/model_policy.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/openai_cost_tracking.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/openai_inference.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/permissions.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/prompt_settings.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/prompts/__init__.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/prompts/final-response.md +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/prompts/help-response.md +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/prompts/system.md +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/prompts/tool-result.md +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/retrieval_settings.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/runtime.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/scope.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/skill_settings.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/skills/__init__.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/skills/help-ai.md +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/skills/help-data.md +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/skills/help-formatting.md +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/skills/help-menus.md +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/skills/help-notes.md +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/skills/help-privacy.md +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/skills/help-references.md +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/skills/help-reminders.md +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/skills/help-search.md +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/skills/help-tags.md +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/skills/scoped-investigation.md +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/structured_inference.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/tagging.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/tagging_run.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/token_estimation.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/tools.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/agent/trace.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/ai_chat.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/ai_chat_rendering.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/ai_chat_stream.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/app_update_worker.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/app_updates.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/auth.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/auth_cache_state.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/auth_service.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/backlink_index.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/backlinks.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/backup_service.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/backup_settings_service.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/bulk_operation.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/client_state_service.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/content_cache.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/content_formatting.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/diagnostics.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/embedded_references.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/encryption.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/exception_capture.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/file_registry.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/file_storage.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/footnote_layout.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/footnote_rendering.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/hierarchy.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/html_export.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/html_unformatting.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/hydration_state.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/image_size_formatting.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/inline_image_occurrences.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/input_errors.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/integrity.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/latex_rendering.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/link_titles.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/login_rate_limit.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/maintenance_mode.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/markdown_rendering.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/namespace_deletion_jobs.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/namespace_deletion_worker.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/namespace_rename_jobs.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/namespace_rename_worker.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/namespace_runtime_guard.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/namespace_switcher.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/note_fullscreen.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/note_image_tags.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/note_ordering.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/note_store.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/ontology_rules_store.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/openai_credentials.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/password_note_fields.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/reference_presentation.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/reminders.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/remote_image_proxy.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/request_recovery.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/resource_limits.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/root_sorting.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/runtime_generation.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/runtime_hardening.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/runtime_lock.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/search_history.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/search_history_storage.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/search_index.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/search_query.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/search_text.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/selected_text_tag.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/session_timeout_service.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/shell_session_service.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/snapshot.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/store.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/structured_note_renderers.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/sync.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/sync_state.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/tab_state.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/tag_case.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/tag_ontology.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/tag_rename.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/tag_suggestions.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/tag_term_matching.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/test_reset.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/tokens.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/undo_state.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/update_backups.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/view_cache.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/view_diff.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/view_state.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/services/windows_process_control.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/startup_environment.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/startup_js_sanity.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/startup_sanity.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/startup_sanity_config.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/config/agent-menu-actions.json +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/config/command_palette_tags.json +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/css/floating-notes.css +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/css/forms.css +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/css/main.css +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/img/favicon.ico +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/locked.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/main.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/activity-tracker.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/ai-chat/agent-menu-actions.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/ai-chat/agent-prompt-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/ai-chat/agent-retrieval-settings.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/ai-chat/ai-agent-debug-view.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/ai-chat/ai-chat-api.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/ai-chat/ai-chat-panel-controller.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/ai-chat/ai-chat-panel-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/ai-chat/ai-thinking-level-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/ai-chat/bulk-elapsed-clock.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/ai-chat/bulk-proposal-ui.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/ai-chat/cloud-privacy-policy.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/ai-chat/proposal-menu.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/api-failure-classification-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/app-update-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/application-state.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/async-result.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/auth.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/client-state-api.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/client-state-migration.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/command-palette/activation-auth-policy.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/command-palette/backup-command-availability.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/command-palette/click-activation-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/command-palette/command-palette-controller.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/command-palette/endpoint-registry.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/command-palette/note-layout-preferences.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/command-palette/preferences-store.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/command-palette/tag-config-loader.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/command-palette/usage-store.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/config.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/connectivity-monitor.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/context-menu/context-menu-registry.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/context-menu/context-menu-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/context-menu/context-menu-target-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/context-menu/input-caret-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/disconnect-editing-state-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/dom-utils-fixed.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/dom-utils.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/editor-commands.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/editor-selection.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/editor-toolbar.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/elapsed-time.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/error-handler.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/error-overlay.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/expected-errors.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/location-flags.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/login-namespace-picker.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/maintenance.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/agent-prompt-editor-modal.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/ai-agent-settings-modal.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/alphabetize-root-notes-modal.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/backup-restore-modal.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/backup-result-modal.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/backup-retention-modal.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/backup-settings-modal.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/base-modal.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/confirmation-modal.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/delete-namespace-modal.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/delete-namespace-validation.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/help-modal.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/namespace-loading-page.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/namespace-modals.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/namespace-ports-profile.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/namespace-rename-validation.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/note-layout-appearance-modal.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/ontology-modal.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/password-modal.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/prioritize-modal.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/random-password-modal.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/reminder-modal.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/reset-updated-at-modal.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/search-suggestion-statistics-modal.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/session-timeout-modal.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/modals/version-info-modal.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/actions/content-actions.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/actions/history-actions.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/actions/note-actions.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/actions/search-actions.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/actions/selection-actions.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/actions/ui-actions.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/events/context-menu-events.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/events/focus-events.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/events/inactivity-events.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/events/input-events.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/events/keyboard-events.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/events/mouse-events.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/events/search-events.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/mode-context.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/mode-logger.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/mode-manager-controller.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/add-style-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/animated-scroll-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/backlinks-navigation-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/backlinks-panel-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/clipboard-shortcut-policy-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/collapse-affordance-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/collapse-editing-policy-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/command-gate-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/context-menu-target-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/deselect-selection-state-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/differential-view-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/edit-session-collapse-policy-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/edit-session-collapse-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/embedded-image-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/file-drop-policy-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/file-image-preview-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/file-reference-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/filtered-refresh-selection-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/floating-note-dom.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/floating-note-layout.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/floating-note-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/footnote-navigation-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/history-selection-policy-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/history-shortcut-policy-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/html-paste-sanitizer-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/image-context-menu-action-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/image-file-insert-choice-modal-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/infinite-scroll-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/link-context-menu-action-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/link-title-prefetch-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/markdown-render-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/mermaid-render-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/note-click-target-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/note-clipboard-write-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/note-collapse-animation-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/note-context-menu-action-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/note-delete-shortcut-policy-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/note-drag-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/note-fullscreen-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/note-reposition-animation-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/note-split-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/note-timestamp-hover-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/password-clipboard-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/polling-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/reference-source-navigation-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/remote-image-proxy-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/remove-formatting-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/root-date-separator-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/root-sort-indicator-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/root-sort-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/scroll-anchor-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/scroll-restoration-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/scroll-to-top-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/search-contexts-overlay-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/search-debounce-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/search-input-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/search-interaction-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/search-redaction-reveal-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/search-suggestion-statistics-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/search-suggestion-window-labels-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/search-suggestion-windows-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/search-suggestions-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/search-syntax-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/selected-formatting-removal-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/selected-text-tag-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/shell-output-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/tab-dom-cache-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/tab-drag-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/tab-duplication-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/tab-state-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/tag-bar-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/tag-input-selection-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/tag-proposal-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/tag-suggestions-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/tag-syntax-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/todo-toggle-editing-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/untagged-view-indicator-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/mode-manager/services/view-mode-search-shortcut-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/note-html-sanitizer.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/password-generator.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/password-operation-response.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/password-policy.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/password-strength.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/reminder-store.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/reminder-surface-service.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/selection-markers.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/session-auth.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/tag-token.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/modules/uuid.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/namespace-deleted.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/namespace-renamed.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/vendor/dompurify-3.4.13.LICENSE.txt +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/vendor/dompurify-3.4.13.min.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/vendor/markdown-it-14.3.2.LICENSE.txt +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/vendor/markdown-it-14.3.2.min.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/vendor/mermaid-11.16.1.LICENSE.txt +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/vendor/mermaid-11.16.1.min.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/vendor/zxcvbn-4.4.2.LICENSE.txt +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/js/vendor/zxcvbn-4.4.2.js +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/note-html-policy.json +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/static/video/login-startup.mp4 +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/templates/base.html +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/templates/index.html +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/templates/locked.html +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/templates/maintenance.html +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/templates/namespace_deleted.html +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/templates/namespace_renamed.html +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/templates/notes_list.html +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/upload_limits.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/__init__.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/add_selected_text_tag.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/alphabetize_root_notes.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/base.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/bulk_tag_proposals.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/collapse.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/copy_note.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/create_child.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/create_note.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/create_sibling.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/delete_subtree.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/delete_tag.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/expand.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/indent.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/lock.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/move.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/move_to_top.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/outdent.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/paste_child.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/paste_sibling.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/prefetch_link_titles.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/prioritize.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/redo.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/rename_tag.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/reset_updated_at.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/resize_image.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/run_shell.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/search_comment_autofill.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/search_context_tags.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/set_collapse_bulk.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/set_collapse_in_context.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/split_note.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/tag_proposals.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/toggle_reference_mode.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/toggle_todo_done.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/undo.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/unformat_content.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/update_content.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/usecases/view.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/utils/__init__.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/utils/encryption.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/app/utils/text_utils.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/convert-from-legacy.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/main.py +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/metalist.egg-info/dependency_links.txt +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/metalist.egg-info/entry_points.txt +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/metalist.egg-info/requires.txt +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/metalist.egg-info/top_level.txt +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/scripts/generate-lan-cert.sh +0 -0
- {metalist-0.7.3 → metalist-0.7.5}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: metalist
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.5
|
|
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
|
|
@@ -48,6 +48,17 @@ A minimalist single-user note-taking app focused on server-side rendering (SSR),
|
|
|
48
48
|
- Multi-tab search contexts with server-persisted scroll/search state (survives browser restarts)
|
|
49
49
|
- Manual namespace backups/restores to a user-selected backup folder with retention controls
|
|
50
50
|
|
|
51
|
+
## Changes in 0.7.5
|
|
52
|
+
|
|
53
|
+
- Unexpected API 500 errors now show the exception class and MetaList source line in the browser, without exposing note contents, exception messages, or local filesystem paths.
|
|
54
|
+
- A local release command validates the exact cross-platform CI matrix, publishes only its tested artifacts, then verifies the public PyPI package in a clean installation.
|
|
55
|
+
|
|
56
|
+
## Changes in 0.7.4
|
|
57
|
+
|
|
58
|
+
- Updates use a private, checksum-verified uv release on Windows, macOS, and Linux. The updater does not execute a user-installed uv, and it revalidates both the cached official archive and extracted executable before each use.
|
|
59
|
+
- The HTTPS listener retries one bodyless safe request after a transient backend reset, records final transport failures server-side, and never replays a mutation or request body.
|
|
60
|
+
- Release CI builds one distribution pair, starts independent platform/Python, installed-update, browser-smoke, and browser-soak gates in parallel, and caches only hash- or lockfile-verified dependencies. Cross-platform runtime changes must pass branch CI before merge.
|
|
61
|
+
|
|
51
62
|
## Changes in 0.7.3
|
|
52
63
|
|
|
53
64
|
- Windows updates use a private verified uv release when an older installer is vulnerable to the reported PE-resource access-denied failure. A standalone repair ZIP can bootstrap installations whose existing updater cannot update itself.
|
|
@@ -152,7 +163,7 @@ metalist update
|
|
|
152
163
|
```
|
|
153
164
|
The updater checks the installed version against the latest PyPI release first. If MetaList is already current, it reports the installed version and leaves all running namespaces untouched. When an update is available, it checks installer prerequisites and uses uv to install the candidate into a disposable tool environment with the current base Python interpreter. It checks dependencies and starts a temporary namespace to verify HTTP readiness, version, and runtime assets. A failed preflight leaves the current installation and running namespaces unchanged. After preflight succeeds, it stops running namespaces, and creates and verifies a new backup of every namespace before installation can begin. Each archive includes the complete notes/settings database, the attachments database when present, and any legacy search-history database. Locked namespaces are backed up with their encrypted data and key metadata intact, without requiring a password.
|
|
154
165
|
|
|
155
|
-
|
|
166
|
+
MetaList downloads its own checksum-verified uv 0.12.17 archive for the current operating system, architecture, and Linux C library. The verified archive and extracted executable are stored in the operating system's user cache; every update verifies the archive against its pinned upstream SHA-256 and the executable against the verified archive before use. That same executable performs both preflight and final installation. MetaList does not execute or replace the user's global uv. Download, verification, platform-selection, or version failures occur before any namespace is stopped. Already-installed releases retain their own updater code; the standalone repair launcher described in [recovery](docs/security/recovery.md#windows-updater-pe-resource-failure) supplies this managed installer to an older Windows updater.
|
|
156
167
|
|
|
157
168
|
Backups are saved to `~/MetaList/namespaces/<namespace>/backups/<namespace>-<timestamp>.metalist-backup.tar.gz`; the updater prints each verified path. Existing backups remain unchanged and are not pruned. If any backup fails, the update aborts with the current installation intact; run `metalist` to restart the stopped servers after resolving the failure.
|
|
158
169
|
|
|
@@ -12,6 +12,17 @@ A minimalist single-user note-taking app focused on server-side rendering (SSR),
|
|
|
12
12
|
- Multi-tab search contexts with server-persisted scroll/search state (survives browser restarts)
|
|
13
13
|
- Manual namespace backups/restores to a user-selected backup folder with retention controls
|
|
14
14
|
|
|
15
|
+
## Changes in 0.7.5
|
|
16
|
+
|
|
17
|
+
- Unexpected API 500 errors now show the exception class and MetaList source line in the browser, without exposing note contents, exception messages, or local filesystem paths.
|
|
18
|
+
- A local release command validates the exact cross-platform CI matrix, publishes only its tested artifacts, then verifies the public PyPI package in a clean installation.
|
|
19
|
+
|
|
20
|
+
## Changes in 0.7.4
|
|
21
|
+
|
|
22
|
+
- Updates use a private, checksum-verified uv release on Windows, macOS, and Linux. The updater does not execute a user-installed uv, and it revalidates both the cached official archive and extracted executable before each use.
|
|
23
|
+
- The HTTPS listener retries one bodyless safe request after a transient backend reset, records final transport failures server-side, and never replays a mutation or request body.
|
|
24
|
+
- Release CI builds one distribution pair, starts independent platform/Python, installed-update, browser-smoke, and browser-soak gates in parallel, and caches only hash- or lockfile-verified dependencies. Cross-platform runtime changes must pass branch CI before merge.
|
|
25
|
+
|
|
15
26
|
## Changes in 0.7.3
|
|
16
27
|
|
|
17
28
|
- Windows updates use a private verified uv release when an older installer is vulnerable to the reported PE-resource access-denied failure. A standalone repair ZIP can bootstrap installations whose existing updater cannot update itself.
|
|
@@ -116,7 +127,7 @@ metalist update
|
|
|
116
127
|
```
|
|
117
128
|
The updater checks the installed version against the latest PyPI release first. If MetaList is already current, it reports the installed version and leaves all running namespaces untouched. When an update is available, it checks installer prerequisites and uses uv to install the candidate into a disposable tool environment with the current base Python interpreter. It checks dependencies and starts a temporary namespace to verify HTTP readiness, version, and runtime assets. A failed preflight leaves the current installation and running namespaces unchanged. After preflight succeeds, it stops running namespaces, and creates and verifies a new backup of every namespace before installation can begin. Each archive includes the complete notes/settings database, the attachments database when present, and any legacy search-history database. Locked namespaces are backed up with their encrypted data and key metadata intact, without requiring a password.
|
|
118
129
|
|
|
119
|
-
|
|
130
|
+
MetaList downloads its own checksum-verified uv 0.12.17 archive for the current operating system, architecture, and Linux C library. The verified archive and extracted executable are stored in the operating system's user cache; every update verifies the archive against its pinned upstream SHA-256 and the executable against the verified archive before use. That same executable performs both preflight and final installation. MetaList does not execute or replace the user's global uv. Download, verification, platform-selection, or version failures occur before any namespace is stopped. Already-installed releases retain their own updater code; the standalone repair launcher described in [recovery](docs/security/recovery.md#windows-updater-pe-resource-failure) supplies this managed installer to an older Windows updater.
|
|
120
131
|
|
|
121
132
|
Backups are saved to `~/MetaList/namespaces/<namespace>/backups/<namespace>-<timestamp>.metalist-backup.tar.gz`; the updater prints each verified path. Existing backups remain unchanged and are not pruned. If any backup fails, the update aborts with the current installation intact; run `metalist` to restart the stopped servers after resolving the failure.
|
|
122
133
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import http.client
|
|
4
4
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
|
5
|
+
import logging
|
|
5
6
|
from threading import BoundedSemaphore
|
|
6
7
|
import time
|
|
7
8
|
from app.upload_limits import MAX_UPLOAD_REQUEST_BYTES
|
|
@@ -12,6 +13,8 @@ IDLE_TIMEOUT_SECONDS = 60
|
|
|
12
13
|
MAX_REQUEST_SECONDS = 30 * 60
|
|
13
14
|
HOP_HEADERS = frozenset({'connection', 'keep-alive', 'proxy-authenticate', 'proxy-authorization',
|
|
14
15
|
'te', 'trailer', 'trailers', 'transfer-encoding', 'upgrade'})
|
|
16
|
+
RETRYABLE_METHODS = frozenset({'GET', 'HEAD', 'OPTIONS'})
|
|
17
|
+
LOGGER = logging.getLogger(__name__)
|
|
15
18
|
|
|
16
19
|
|
|
17
20
|
class BoundedProxyServer(ThreadingHTTPServer):
|
|
@@ -48,6 +51,39 @@ def make_proxy_handler(*, backend_host: str, backend_port: int, forward_headers)
|
|
|
48
51
|
class ProxyHandler(BaseHTTPRequestHandler):
|
|
49
52
|
protocol_version = 'HTTP/1.1'
|
|
50
53
|
|
|
54
|
+
def _request_upstream(self, *, headers, content_length: int, deadline: float):
|
|
55
|
+
attempts = 1
|
|
56
|
+
if self.command in RETRYABLE_METHODS and content_length == 0:
|
|
57
|
+
attempts = 2
|
|
58
|
+
for attempt in range(attempts):
|
|
59
|
+
connection = http.client.HTTPConnection(
|
|
60
|
+
backend_host, backend_port, timeout=IDLE_TIMEOUT_SECONDS,
|
|
61
|
+
)
|
|
62
|
+
# lint: allow-PY001 rationale="retry a bodyless safe request after an expected transient upstream transport failure"
|
|
63
|
+
try:
|
|
64
|
+
connection.putrequest(
|
|
65
|
+
self.command, self.path, skip_host=True, skip_accept_encoding=True,
|
|
66
|
+
)
|
|
67
|
+
for key, value in headers.items():
|
|
68
|
+
connection.putheader(key, value)
|
|
69
|
+
connection.endheaders()
|
|
70
|
+
remaining = content_length
|
|
71
|
+
while remaining:
|
|
72
|
+
if time.monotonic() >= deadline:
|
|
73
|
+
raise TimeoutError('Proxy request deadline exceeded')
|
|
74
|
+
chunk = self.rfile.read(min(CHUNK_BYTES, remaining))
|
|
75
|
+
if not chunk:
|
|
76
|
+
raise ConnectionError('Incomplete request body')
|
|
77
|
+
connection.send(chunk)
|
|
78
|
+
remaining -= len(chunk)
|
|
79
|
+
return connection, connection.getresponse()
|
|
80
|
+
# lint: allow-PY001 rationale="retry once, then re-raise the expected upstream transport failure"
|
|
81
|
+
except (OSError, http.client.HTTPException):
|
|
82
|
+
connection.close()
|
|
83
|
+
if attempt + 1 == attempts:
|
|
84
|
+
raise
|
|
85
|
+
raise AssertionError('Upstream request attempts were not exhausted')
|
|
86
|
+
|
|
51
87
|
def _proxy(self):
|
|
52
88
|
# Preserve the browser's HTTP/1.1 connection across module requests.
|
|
53
89
|
# Chunked response framing and the socket timeout bound each transfer.
|
|
@@ -78,24 +114,24 @@ def make_proxy_handler(*, backend_host: str, backend_port: int, forward_headers)
|
|
|
78
114
|
headers = forward_headers(incoming_headers=self.headers.items(), client_ip=self.client_address[0])
|
|
79
115
|
headers = {key: value for key, value in headers.items() if key.casefold() not in connection_tokens | HOP_HEADERS}
|
|
80
116
|
headers['Connection'] = 'close'
|
|
81
|
-
connection = http.client.HTTPConnection(backend_host, backend_port, timeout=IDLE_TIMEOUT_SECONDS)
|
|
82
117
|
deadline = time.monotonic() + MAX_REQUEST_SECONDS
|
|
118
|
+
# lint: allow-PY001 rationale="translate the final external upstream transport failure into a sanitized gateway response"
|
|
119
|
+
try:
|
|
120
|
+
connection, response = self._request_upstream(
|
|
121
|
+
headers=headers, content_length=remaining, deadline=deadline,
|
|
122
|
+
)
|
|
123
|
+
# lint: allow-PY001 rationale="return a sanitized gateway error after retrying an expected upstream transport failure"
|
|
124
|
+
except (OSError, http.client.HTTPException) as error:
|
|
125
|
+
self.close_connection = True
|
|
126
|
+
LOGGER.error(
|
|
127
|
+
'HTTPS proxy upstream transport failed method=%s backend=%s:%s error=%s',
|
|
128
|
+
self.command, backend_host, backend_port, type(error).__name__,
|
|
129
|
+
)
|
|
130
|
+
self.send_error(502, 'Upstream transport failed')
|
|
131
|
+
return
|
|
83
132
|
response_started = False
|
|
84
133
|
# lint: allow-PY001 rationale="close upstream on client disconnect or expected transport failure without disclosing exception details"
|
|
85
134
|
try:
|
|
86
|
-
connection.putrequest(self.command, self.path, skip_host=True, skip_accept_encoding=True)
|
|
87
|
-
for key, value in headers.items():
|
|
88
|
-
connection.putheader(key, value)
|
|
89
|
-
connection.endheaders()
|
|
90
|
-
while remaining:
|
|
91
|
-
if time.monotonic() >= deadline:
|
|
92
|
-
raise TimeoutError('Proxy request deadline exceeded')
|
|
93
|
-
chunk = self.rfile.read(min(CHUNK_BYTES, remaining))
|
|
94
|
-
if not chunk:
|
|
95
|
-
raise ConnectionError('Incomplete request body')
|
|
96
|
-
connection.send(chunk)
|
|
97
|
-
remaining -= len(chunk)
|
|
98
|
-
response = connection.getresponse()
|
|
99
135
|
self.send_response(response.status, response.reason)
|
|
100
136
|
response_tokens = {part.strip().casefold() for value in response.headers.get_all('Connection', []) for part in value.split(',')}
|
|
101
137
|
for key, value in response.getheaders():
|
|
@@ -125,9 +161,13 @@ def make_proxy_handler(*, backend_host: str, backend_port: int, forward_headers)
|
|
|
125
161
|
self.wfile.write(b'0\r\n\r\n')
|
|
126
162
|
self.wfile.flush()
|
|
127
163
|
# lint: allow-PY001 rationale="terminate a disconnected or failed external HTTP transport; emit only a sanitized upstream error"
|
|
128
|
-
except (OSError, http.client.HTTPException):
|
|
164
|
+
except (OSError, http.client.HTTPException) as error:
|
|
129
165
|
# A partial request/response cannot be reused for another request.
|
|
130
166
|
self.close_connection = True
|
|
167
|
+
LOGGER.error(
|
|
168
|
+
'HTTPS proxy response transport failed method=%s backend=%s:%s error=%s',
|
|
169
|
+
self.command, backend_host, backend_port, type(error).__name__,
|
|
170
|
+
)
|
|
131
171
|
if not response_started:
|
|
132
172
|
self.send_error(502, 'Upstream transport failed')
|
|
133
173
|
finally:
|
|
@@ -38,6 +38,7 @@ from app.services.search_history import search_history_store
|
|
|
38
38
|
from app.services.runtime_hardening import apply_runtime_hardening
|
|
39
39
|
from app.security.encryption import set_encryption_required
|
|
40
40
|
from app.security.http_headers import apply_security_headers
|
|
41
|
+
from app.security.http_error_diagnostics import describe_server_exception
|
|
41
42
|
from app.security.request_boundary import RequestBoundaryMiddleware
|
|
42
43
|
from app.security.request_boundary import resolve_allowed_request_hosts
|
|
43
44
|
from app.security.validation_errors import summarize_validation_errors
|
|
@@ -149,6 +150,18 @@ async def request_validation_error(request: Request, exc: RequestValidationError
|
|
|
149
150
|
async def handle_ontology_parse_error(request: Request, exc: OntologyParseError):
|
|
150
151
|
return JSONResponse(status_code=400, content={"detail": str(exc)})
|
|
151
152
|
|
|
153
|
+
|
|
154
|
+
@app.exception_handler(Exception)
|
|
155
|
+
async def handle_unexpected_server_error(request: Request, exc: Exception):
|
|
156
|
+
return JSONResponse(
|
|
157
|
+
status_code=500,
|
|
158
|
+
content={
|
|
159
|
+
"detail": "Internal server error",
|
|
160
|
+
"diagnostic": describe_server_exception(exc),
|
|
161
|
+
},
|
|
162
|
+
headers={"Cache-Control": "no-store, private", "X-Content-Type-Options": "nosniff"},
|
|
163
|
+
)
|
|
164
|
+
|
|
152
165
|
_startup_timing_enabled = True
|
|
153
166
|
|
|
154
167
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Small, data-free diagnostics for unexpected HTTP failures."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import traceback
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
_APP_DIRECTORY = Path(__file__).resolve().parents[1]
|
|
8
|
+
_REPOSITORY_DIRECTORY = _APP_DIRECTORY.parent
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def describe_server_exception(error: Exception) -> dict[str, str]:
|
|
12
|
+
"""Expose the exception class and last application frame, never its message."""
|
|
13
|
+
location = "external"
|
|
14
|
+
for frame in reversed(traceback.extract_tb(error.__traceback__)):
|
|
15
|
+
path = Path(frame.filename).resolve()
|
|
16
|
+
if path.is_relative_to(_APP_DIRECTORY):
|
|
17
|
+
location = f"{path.relative_to(_REPOSITORY_DIRECTORY).as_posix()}:{frame.lineno}"
|
|
18
|
+
break
|
|
19
|
+
return {"errorType": type(error).__name__, "codeLocation": location}
|
|
@@ -76,17 +76,11 @@ def schedule_self_update(
|
|
|
76
76
|
message=message,
|
|
77
77
|
)
|
|
78
78
|
|
|
79
|
-
uv_executable = shutil.which("uv")
|
|
80
|
-
if uv_executable is None:
|
|
81
|
-
raise RuntimeError("uv executable was not found on PATH; MetaList was not stopped")
|
|
82
|
-
|
|
83
79
|
if platform_name == "win32":
|
|
84
80
|
_resolve_windows_powershell()
|
|
85
81
|
elif not Path("/bin/sh").is_file():
|
|
86
82
|
raise RuntimeError("/bin/sh is required for MetaList self-update; MetaList was not stopped")
|
|
87
|
-
install_command = _prepare_update(
|
|
88
|
-
uv_executable=uv_executable, target_version=target_version, environ=environ,
|
|
89
|
-
)
|
|
83
|
+
install_command = _prepare_update(target_version=target_version, environ=environ)
|
|
90
84
|
updater_command: list[str]
|
|
91
85
|
updater_options: dict[str, object]
|
|
92
86
|
if platform_name == "win32":
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
"""Provide MetaList's checksum-pinned updater runtime on every supported OS."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from collections.abc import Mapping
|
|
5
|
+
import hashlib
|
|
6
|
+
import io
|
|
7
|
+
import os
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
import platform
|
|
10
|
+
import re
|
|
11
|
+
import shutil
|
|
12
|
+
import subprocess
|
|
13
|
+
import sys
|
|
14
|
+
import tarfile
|
|
15
|
+
from tempfile import NamedTemporaryFile
|
|
16
|
+
from urllib.request import urlopen
|
|
17
|
+
import zipfile
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# Official immutable uv 0.12.17 release archives. These values match the
|
|
21
|
+
# upstream sha256.sum asset for the same release.
|
|
22
|
+
INSTALLER_VERSION = "0.12.17"
|
|
23
|
+
INSTALLER_ARCHIVE_SHA256 = {
|
|
24
|
+
"aarch64-apple-darwin": "85f00cbdc6dd3e97eba4c31b4d014375a9fdfe8f570023b84e5102fc3456896b",
|
|
25
|
+
"aarch64-pc-windows-msvc": "3e1aa6849d77f0e00dc865e4afab5c5b32de053e21fe35bf5ad5cec3734ec976",
|
|
26
|
+
"aarch64-unknown-linux-gnu": "d636d1b678e9e7f367ecb22b46bd1cabbed234d6bc3b4d96365d2b507f72f86c",
|
|
27
|
+
"aarch64-unknown-linux-musl": "a6096da273d548cb9f277d237a01ac7344a39ef0f455c0e148e4dc9737c1596b",
|
|
28
|
+
"armv7-unknown-linux-gnueabihf": "796e101976e18a0f92d90b6f3efd289f77fbc5afd1aaa6fdedd3c84c209eabab",
|
|
29
|
+
"armv7-unknown-linux-musleabihf": "421c5f9c53d49088e705e7a64fea147082a2191178ea1d8c51d9ad758ca899f6",
|
|
30
|
+
"i686-pc-windows-msvc": "1d3653cb6eafd1e675e979d7cd8eeac1456202f8927a2216419993077a4c473f",
|
|
31
|
+
"i686-unknown-linux-gnu": "3faa79a70e2a1aa6eb3cd78eba02263f3e4b17b6be584a01429968f92ff74966",
|
|
32
|
+
"i686-unknown-linux-musl": "fc05220cfa1c6585e0e209877c228393b25a96e17cd43028b06566ac894cd078",
|
|
33
|
+
"powerpc64le-unknown-linux-gnu": "eb6dbedaaa622af32cba2388e0d2d47e34c8724d4214a129d614b96f071d8e53",
|
|
34
|
+
"riscv64gc-unknown-linux-gnu": "65b807b24357133c49d97ca9394ee7e13ca62822e1095376c809654b35f39cf2",
|
|
35
|
+
"riscv64gc-unknown-linux-musl": "87c339a735b578f285b961bebdefe0a671f3652477d1e84dc69cd1a829f45e92",
|
|
36
|
+
"s390x-unknown-linux-gnu": "d99f69f47fc5e0975d6e7a5745cf2332317015caffb3bb81e5154cc7b66fa77a",
|
|
37
|
+
"x86_64-apple-darwin": "8dcf05a8c809bb3c471d2b614788ba27a6e41298fc8c31ac84b5f4339fd468e5",
|
|
38
|
+
"x86_64-pc-windows-msvc": "a252121d5b59398fcb137c6ea448176459a44010f33f67e0072305a637119ca7",
|
|
39
|
+
"x86_64-unknown-linux-gnu": "fa82fd8dde8e8eefdecada6aa0889666556cfceb690d06e0c3bca49eb3070a63",
|
|
40
|
+
"x86_64-unknown-linux-musl": "6401c4665d8fa2a9893e087c91f585430738e3170f5398a1141483efb4a93310",
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _installer_version(executable: str, environ: Mapping[str, str]) -> tuple[int, int, int]:
|
|
45
|
+
completed = subprocess.run(
|
|
46
|
+
[executable, "--version"], env=dict(environ), capture_output=True,
|
|
47
|
+
text=True, check=True, timeout=30,
|
|
48
|
+
)
|
|
49
|
+
match = re.fullmatch(
|
|
50
|
+
r"uv (\d+)\.(\d+)\.(\d+)(?: \([^\r\n]+\))?",
|
|
51
|
+
completed.stdout.strip(),
|
|
52
|
+
)
|
|
53
|
+
if match is None:
|
|
54
|
+
raise RuntimeError("Cannot verify the uv installer version; MetaList was not stopped")
|
|
55
|
+
return tuple(int(part) for part in match.groups())
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _normalized_architecture() -> str:
|
|
59
|
+
machine = platform.machine().casefold()
|
|
60
|
+
aliases = {
|
|
61
|
+
"amd64": "x86_64", "x86_64": "x86_64",
|
|
62
|
+
"arm64": "aarch64", "aarch64": "aarch64",
|
|
63
|
+
"x86": "i686", "i386": "i686", "i686": "i686",
|
|
64
|
+
"armv7": "armv7", "armv7l": "armv7",
|
|
65
|
+
"ppc64le": "powerpc64le", "powerpc64le": "powerpc64le",
|
|
66
|
+
"riscv64": "riscv64gc", "riscv64gc": "riscv64gc",
|
|
67
|
+
"s390x": "s390x",
|
|
68
|
+
}
|
|
69
|
+
if machine not in aliases:
|
|
70
|
+
raise RuntimeError(f"Unsupported MetaList updater platform architecture: {machine}")
|
|
71
|
+
return aliases[machine]
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _linux_environment() -> str:
|
|
75
|
+
libc_name = platform.libc_ver()[0].casefold()
|
|
76
|
+
if libc_name in {"glibc", "gnu libc"}:
|
|
77
|
+
return "gnu"
|
|
78
|
+
if libc_name == "musl":
|
|
79
|
+
return "musl"
|
|
80
|
+
raise RuntimeError(f"Unsupported MetaList updater platform C library: {libc_name or 'unknown'}")
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _installer_target(platform_name: str) -> str:
|
|
84
|
+
architecture = _normalized_architecture()
|
|
85
|
+
if platform_name == "win32":
|
|
86
|
+
target = f"{architecture}-pc-windows-msvc"
|
|
87
|
+
elif platform_name == "darwin":
|
|
88
|
+
target = f"{architecture}-apple-darwin"
|
|
89
|
+
elif platform_name == "linux":
|
|
90
|
+
environment = _linux_environment()
|
|
91
|
+
if architecture == "armv7":
|
|
92
|
+
if environment == "gnu":
|
|
93
|
+
abi = "gnueabihf"
|
|
94
|
+
elif environment == "musl":
|
|
95
|
+
abi = "musleabihf"
|
|
96
|
+
else:
|
|
97
|
+
raise AssertionError(f"Unexpected Linux environment: {environment}")
|
|
98
|
+
else:
|
|
99
|
+
abi = environment
|
|
100
|
+
target = f"{architecture}-unknown-linux-{abi}"
|
|
101
|
+
else:
|
|
102
|
+
raise RuntimeError(f"Unsupported MetaList updater platform: {platform_name}")
|
|
103
|
+
if target not in INSTALLER_ARCHIVE_SHA256:
|
|
104
|
+
raise RuntimeError(f"Unsupported MetaList updater platform target: {target}")
|
|
105
|
+
return target
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _required_absolute_directory(environ: Mapping[str, str], name: str) -> Path:
|
|
109
|
+
if name not in environ:
|
|
110
|
+
raise RuntimeError(f"{name} is required for the MetaList update installer")
|
|
111
|
+
directory = Path(environ[name])
|
|
112
|
+
if not directory.is_absolute():
|
|
113
|
+
raise RuntimeError(f"{name} must be an absolute path for the MetaList update installer")
|
|
114
|
+
return directory
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _installer_cache_root(*, platform_name: str, environ: Mapping[str, str]) -> Path:
|
|
118
|
+
if platform_name == "win32":
|
|
119
|
+
return _required_absolute_directory(environ, "LOCALAPPDATA") / "MetaList" / "update-tools"
|
|
120
|
+
if platform_name == "darwin":
|
|
121
|
+
home = _required_absolute_directory(environ, "HOME")
|
|
122
|
+
return home / "Library" / "Caches" / "MetaList" / "update-tools"
|
|
123
|
+
if platform_name == "linux":
|
|
124
|
+
if "XDG_CACHE_HOME" in environ:
|
|
125
|
+
cache_home = _required_absolute_directory(environ, "XDG_CACHE_HOME")
|
|
126
|
+
else:
|
|
127
|
+
home = _required_absolute_directory(environ, "HOME")
|
|
128
|
+
cache_home = home / ".cache"
|
|
129
|
+
return cache_home / "metalist" / "update-tools"
|
|
130
|
+
raise RuntimeError(f"Unsupported MetaList updater platform: {platform_name}")
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _archive_name(*, target: str, platform_name: str) -> str:
|
|
134
|
+
if platform_name == "win32":
|
|
135
|
+
extension = "zip"
|
|
136
|
+
elif platform_name in {"darwin", "linux"}:
|
|
137
|
+
extension = "tar.gz"
|
|
138
|
+
else:
|
|
139
|
+
raise RuntimeError(f"Unsupported MetaList updater platform: {platform_name}")
|
|
140
|
+
return f"uv-{target}.{extension}"
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _download_installer_archive(asset_name: str) -> bytes:
|
|
144
|
+
url = f"https://github.com/astral-sh/uv/releases/download/{INSTALLER_VERSION}/{asset_name}"
|
|
145
|
+
with urlopen(url, timeout=120) as response:
|
|
146
|
+
return response.read()
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _extract_installer_binary(
|
|
150
|
+
*, archive_body: bytes, asset_name: str, platform_name: str, target: str,
|
|
151
|
+
) -> bytes:
|
|
152
|
+
if platform_name == "win32":
|
|
153
|
+
member_name = "uv.exe"
|
|
154
|
+
elif platform_name in {"darwin", "linux"}:
|
|
155
|
+
member_name = f"uv-{target}/uv"
|
|
156
|
+
else:
|
|
157
|
+
raise RuntimeError(f"Unsupported MetaList updater platform: {platform_name}")
|
|
158
|
+
if asset_name.endswith(".zip"):
|
|
159
|
+
with zipfile.ZipFile(io.BytesIO(archive_body)) as archive:
|
|
160
|
+
return archive.read(member_name)
|
|
161
|
+
with tarfile.open(fileobj=io.BytesIO(archive_body), mode="r:gz") as archive:
|
|
162
|
+
member = archive.extractfile(member_name)
|
|
163
|
+
if member is None:
|
|
164
|
+
raise RuntimeError("Verified update installer archive is missing the uv executable")
|
|
165
|
+
return member.read()
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _publish_bytes(*, destination: Path, body: bytes, mode: int) -> None:
|
|
169
|
+
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
170
|
+
with NamedTemporaryFile(
|
|
171
|
+
dir=destination.parent, prefix=destination.name + "-", suffix=".tmp", delete=False,
|
|
172
|
+
) as staged:
|
|
173
|
+
staged.write(body)
|
|
174
|
+
staged.flush()
|
|
175
|
+
os.fsync(staged.fileno())
|
|
176
|
+
staged_path = Path(staged.name)
|
|
177
|
+
os.chmod(staged_path, mode)
|
|
178
|
+
os.replace(staged_path, destination)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def _load_verified_archive(
|
|
182
|
+
*, archive_path: Path, expected_digest: str, asset_name: str,
|
|
183
|
+
) -> bytes:
|
|
184
|
+
if archive_path.exists():
|
|
185
|
+
archive_body = archive_path.read_bytes()
|
|
186
|
+
if hashlib.sha256(archive_body).hexdigest() != expected_digest:
|
|
187
|
+
raise RuntimeError(
|
|
188
|
+
"Cached update installer archive failed checksum verification; "
|
|
189
|
+
"MetaList was not stopped"
|
|
190
|
+
)
|
|
191
|
+
return archive_body
|
|
192
|
+
print(f"Preparing verified MetaList update installer uv {INSTALLER_VERSION}...", flush=True)
|
|
193
|
+
archive_body = _download_installer_archive(asset_name)
|
|
194
|
+
if hashlib.sha256(archive_body).hexdigest() != expected_digest:
|
|
195
|
+
raise RuntimeError(
|
|
196
|
+
"Downloaded update installer failed checksum verification; MetaList was not stopped"
|
|
197
|
+
)
|
|
198
|
+
_publish_bytes(destination=archive_path, body=archive_body, mode=0o600)
|
|
199
|
+
return archive_body
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _managed_installer(*, platform_name: str, environ: Mapping[str, str]) -> str:
|
|
203
|
+
target = _installer_target(platform_name)
|
|
204
|
+
asset_name = _archive_name(target=target, platform_name=platform_name)
|
|
205
|
+
directory = _installer_cache_root(platform_name=platform_name, environ=environ) / (
|
|
206
|
+
f"uv-{INSTALLER_VERSION}-{target}"
|
|
207
|
+
)
|
|
208
|
+
archive_path = directory / asset_name
|
|
209
|
+
archive_body = _load_verified_archive(
|
|
210
|
+
archive_path=archive_path,
|
|
211
|
+
expected_digest=INSTALLER_ARCHIVE_SHA256[target],
|
|
212
|
+
asset_name=asset_name,
|
|
213
|
+
)
|
|
214
|
+
expected_binary = _extract_installer_binary(
|
|
215
|
+
archive_body=archive_body, asset_name=asset_name,
|
|
216
|
+
platform_name=platform_name, target=target,
|
|
217
|
+
)
|
|
218
|
+
if platform_name == "win32":
|
|
219
|
+
executable = directory / "uv.exe"
|
|
220
|
+
else:
|
|
221
|
+
assert platform_name in {"darwin", "linux"}
|
|
222
|
+
executable = directory / "uv"
|
|
223
|
+
if executable.exists():
|
|
224
|
+
if executable.read_bytes() != expected_binary:
|
|
225
|
+
raise RuntimeError(
|
|
226
|
+
"Cached update installer failed checksum verification; MetaList was not stopped"
|
|
227
|
+
)
|
|
228
|
+
else:
|
|
229
|
+
_publish_bytes(destination=executable, body=expected_binary, mode=0o700)
|
|
230
|
+
if platform_name != "win32":
|
|
231
|
+
os.chmod(executable, 0o700)
|
|
232
|
+
return str(executable)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def resolve_update_installer(*, platform_name: str, environ: Mapping[str, str]) -> str:
|
|
236
|
+
executable = _managed_installer(platform_name=platform_name, environ=environ)
|
|
237
|
+
expected_version = tuple(int(part) for part in INSTALLER_VERSION.split("."))
|
|
238
|
+
if _installer_version(executable, environ) != expected_version:
|
|
239
|
+
raise RuntimeError(
|
|
240
|
+
"Verified update installer reported the wrong version; MetaList was not stopped"
|
|
241
|
+
)
|
|
242
|
+
return executable
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def repair_windows_update() -> None:
|
|
246
|
+
if sys.platform != "win32":
|
|
247
|
+
raise RuntimeError("This recovery launcher is for Windows installations")
|
|
248
|
+
metalist_executable = shutil.which("metalist")
|
|
249
|
+
if metalist_executable is None:
|
|
250
|
+
raise RuntimeError("The existing MetaList command must be available on PATH")
|
|
251
|
+
environ = dict(os.environ)
|
|
252
|
+
installer = resolve_update_installer(platform_name="win32", environ=environ)
|
|
253
|
+
# The already-installed updater discovers uv through PATH. Preserve that
|
|
254
|
+
# updater's preflight, shutdown, backup, offline install, and restart flow.
|
|
255
|
+
environ["PATH"] = str(Path(installer).parent) + os.pathsep + environ["PATH"]
|
|
256
|
+
subprocess.run([metalist_executable, "update"], env=environ, check=True)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
if __name__ == "__main__":
|
|
260
|
+
repair_windows_update()
|
|
@@ -87,15 +87,12 @@ def _probe_candidate(*, python: str, executable: str, directory: Path,
|
|
|
87
87
|
_stop_failed_namespace_launch(process=process)
|
|
88
88
|
|
|
89
89
|
|
|
90
|
-
def prepare_update(*,
|
|
91
|
-
environ: Mapping[str, str]) -> list[str]:
|
|
90
|
+
def prepare_update(*, target_version: str, environ: Mapping[str, str]) -> list[str]:
|
|
92
91
|
# A tool environment is replaced during install: pin its external base interpreter.
|
|
93
92
|
python = str(Path(sys._base_executable).resolve())
|
|
94
93
|
if not Path(python).is_file():
|
|
95
94
|
raise RuntimeError("The current base Python interpreter is missing; MetaList was not stopped")
|
|
96
|
-
uv_executable = resolve_update_installer(
|
|
97
|
-
uv_executable=uv_executable, platform_name=sys.platform, environ=environ,
|
|
98
|
-
)
|
|
95
|
+
uv_executable = resolve_update_installer(platform_name=sys.platform, environ=environ)
|
|
99
96
|
print(f"Checking MetaList v{target_version} installation and startup with Python {sys.version.split()[0]}...", flush=True)
|
|
100
97
|
with TemporaryDirectory(prefix="metalist-update-check-") as temporary:
|
|
101
98
|
directory = Path(temporary)
|
|
@@ -7,6 +7,7 @@ import { computeScrollAnchor } from './mode-manager/services/scroll-anchor-servi
|
|
|
7
7
|
import { CommandGate } from './mode-manager/services/command-gate-service.js';
|
|
8
8
|
import { buildSessionHeaders } from './session-auth.js';
|
|
9
9
|
import { sanitizeNoteHtmlForStorage } from './note-html-sanitizer.js';
|
|
10
|
+
import { describeApiFailure } from './api-error-diagnostics.js';
|
|
10
11
|
|
|
11
12
|
function buildAuthHeaders(includeContentType) {
|
|
12
13
|
return buildSessionHeaders(includeContentType);
|
|
@@ -125,7 +126,7 @@ export const NotesAPI = {
|
|
|
125
126
|
if (!response.ok) {
|
|
126
127
|
// Use centralized error handling
|
|
127
128
|
ErrorHandler.handleApiError(null, response);
|
|
128
|
-
throw new HttpRequestError(
|
|
129
|
+
throw new HttpRequestError(await describeApiFailure(response));
|
|
129
130
|
}
|
|
130
131
|
|
|
131
132
|
const data = await response.json();
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const ERROR_TYPE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
2
|
+
const CODE_LOCATION = /^(?:app(?:\/[A-Za-z_][A-Za-z0-9_]*)+\.py:\d+|external)$/;
|
|
3
|
+
|
|
4
|
+
export async function describeApiFailure(response) {
|
|
5
|
+
const base = `API call failed: ${response.status} ${response.statusText}`;
|
|
6
|
+
if (response.status < 500 || !response.headers.get('content-type')?.includes('application/json')) {
|
|
7
|
+
return base;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const body = await response.json();
|
|
11
|
+
const diagnostic = body?.diagnostic;
|
|
12
|
+
if (!ERROR_TYPE.test(diagnostic?.errorType) || !CODE_LOCATION.test(diagnostic?.codeLocation)) {
|
|
13
|
+
return base;
|
|
14
|
+
}
|
|
15
|
+
return `${base} (${diagnostic.errorType} at ${diagnostic.codeLocation})`;
|
|
16
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: metalist
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.5
|
|
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
|
|
@@ -48,6 +48,17 @@ A minimalist single-user note-taking app focused on server-side rendering (SSR),
|
|
|
48
48
|
- Multi-tab search contexts with server-persisted scroll/search state (survives browser restarts)
|
|
49
49
|
- Manual namespace backups/restores to a user-selected backup folder with retention controls
|
|
50
50
|
|
|
51
|
+
## Changes in 0.7.5
|
|
52
|
+
|
|
53
|
+
- Unexpected API 500 errors now show the exception class and MetaList source line in the browser, without exposing note contents, exception messages, or local filesystem paths.
|
|
54
|
+
- A local release command validates the exact cross-platform CI matrix, publishes only its tested artifacts, then verifies the public PyPI package in a clean installation.
|
|
55
|
+
|
|
56
|
+
## Changes in 0.7.4
|
|
57
|
+
|
|
58
|
+
- Updates use a private, checksum-verified uv release on Windows, macOS, and Linux. The updater does not execute a user-installed uv, and it revalidates both the cached official archive and extracted executable before each use.
|
|
59
|
+
- The HTTPS listener retries one bodyless safe request after a transient backend reset, records final transport failures server-side, and never replays a mutation or request body.
|
|
60
|
+
- Release CI builds one distribution pair, starts independent platform/Python, installed-update, browser-smoke, and browser-soak gates in parallel, and caches only hash- or lockfile-verified dependencies. Cross-platform runtime changes must pass branch CI before merge.
|
|
61
|
+
|
|
51
62
|
## Changes in 0.7.3
|
|
52
63
|
|
|
53
64
|
- Windows updates use a private verified uv release when an older installer is vulnerable to the reported PE-resource access-denied failure. A standalone repair ZIP can bootstrap installations whose existing updater cannot update itself.
|
|
@@ -152,7 +163,7 @@ metalist update
|
|
|
152
163
|
```
|
|
153
164
|
The updater checks the installed version against the latest PyPI release first. If MetaList is already current, it reports the installed version and leaves all running namespaces untouched. When an update is available, it checks installer prerequisites and uses uv to install the candidate into a disposable tool environment with the current base Python interpreter. It checks dependencies and starts a temporary namespace to verify HTTP readiness, version, and runtime assets. A failed preflight leaves the current installation and running namespaces unchanged. After preflight succeeds, it stops running namespaces, and creates and verifies a new backup of every namespace before installation can begin. Each archive includes the complete notes/settings database, the attachments database when present, and any legacy search-history database. Locked namespaces are backed up with their encrypted data and key metadata intact, without requiring a password.
|
|
154
165
|
|
|
155
|
-
|
|
166
|
+
MetaList downloads its own checksum-verified uv 0.12.17 archive for the current operating system, architecture, and Linux C library. The verified archive and extracted executable are stored in the operating system's user cache; every update verifies the archive against its pinned upstream SHA-256 and the executable against the verified archive before use. That same executable performs both preflight and final installation. MetaList does not execute or replace the user's global uv. Download, verification, platform-selection, or version failures occur before any namespace is stopped. Already-installed releases retain their own updater code; the standalone repair launcher described in [recovery](docs/security/recovery.md#windows-updater-pe-resource-failure) supplies this managed installer to an older Windows updater.
|
|
156
167
|
|
|
157
168
|
Backups are saved to `~/MetaList/namespaces/<namespace>/backups/<namespace>-<timestamp>.metalist-backup.tar.gz`; the updater prints each verified path. Existing backups remain unchanged and are not pruned. If any backup fails, the update aborts with the current installation intact; run `metalist` to restart the stopped servers after resolving the failure.
|
|
158
169
|
|
|
@@ -70,6 +70,7 @@ app/presentation/render/__init__.py
|
|
|
70
70
|
app/presentation/render/note_renderer.py
|
|
71
71
|
app/security/authenticated_logging.py
|
|
72
72
|
app/security/encryption.py
|
|
73
|
+
app/security/http_error_diagnostics.py
|
|
73
74
|
app/security/http_headers.py
|
|
74
75
|
app/security/note_html.py
|
|
75
76
|
app/security/request_boundary.py
|
|
@@ -224,6 +225,7 @@ app/static/js/namespace-deleted.js
|
|
|
224
225
|
app/static/js/namespace-renamed.js
|
|
225
226
|
app/static/js/modules/activity-tracker.js
|
|
226
227
|
app/static/js/modules/api-client.js
|
|
228
|
+
app/static/js/modules/api-error-diagnostics.js
|
|
227
229
|
app/static/js/modules/api-failure-classification-service.js
|
|
228
230
|
app/static/js/modules/app-update-service.js
|
|
229
231
|
app/static/js/modules/application-state.js
|