MetaList 0.7.2__tar.gz → 0.7.4__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.2 → metalist-0.7.4}/PKG-INFO +14 -1
- {metalist-0.7.2 → metalist-0.7.4}/README.md +13 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/config.py +2 -2
- {metalist-0.7.2 → metalist-0.7.4}/app/db/live_recovery.py +4 -1
- {metalist-0.7.2 → metalist-0.7.4}/app/https_proxy.py +55 -15
- {metalist-0.7.2 → metalist-0.7.4}/app/models/database.py +3 -18
- {metalist-0.7.2 → metalist-0.7.4}/app/services/app_updates.py +18 -15
- {metalist-0.7.2 → metalist-0.7.4}/app/services/self_update.py +1 -7
- metalist-0.7.4/app/services/update_installer.py +260 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/update_preflight.py +3 -2
- {metalist-0.7.2 → metalist-0.7.4}/app/startup_js_sanity.py +1 -1
- {metalist-0.7.2 → metalist-0.7.4}/app/startup_sanity.py +1 -1
- {metalist-0.7.2 → metalist-0.7.4}/app/version.py +1 -1
- {metalist-0.7.2 → metalist-0.7.4}/metalist.egg-info/PKG-INFO +14 -1
- {metalist-0.7.2 → metalist-0.7.4}/metalist.egg-info/SOURCES.txt +1 -0
- {metalist-0.7.2 → metalist-0.7.4}/MANIFEST.in +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/__init__.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/api/__init__.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/api/deps.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/api/dev.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/api/middleware/auth.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/api/note_requests.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/api/request_auth.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/api/routes/ai.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/api/routes/app_updates.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/api/routes/auth.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/api/routes/backups.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/api/routes/files.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/api/routes/notes.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/api/routes/ontology.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/api/routes/reminders.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/api/routes/remote_images.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/api/routes/test.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/api/transactions.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/api/upload_limits.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/data_directory.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/db/__init__.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/db/backup_settings_sql.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/db/engine.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/db/file_schema.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/db/file_session.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/db/files_sql.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/db/link_titles_sql.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/db/migrations.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/db/notes_sql.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/db/ontology_rules_sql.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/db/reminders_sql.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/db/retire_sounds.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/db/schema.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/db/search_history_sql.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/db/session.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/db/settings_sql.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/db/tab_state_sql.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/db/version.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/encryption_audit.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/exception_boundaries.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/main.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/models/commands.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/models/entities.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/models/enums.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/models/linked_list.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/models/list_operations.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/models/list_traversal.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/models/note_crud.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/models/utils.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/network_settings.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/presentation/__init__.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/presentation/render/__init__.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/presentation/render/note_renderer.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/presentation/templates.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/security/authenticated_logging.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/security/encryption.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/security/http_headers.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/security/note_html.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/security/request_boundary.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/security/request_hosts.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/security/sensitive_cache.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/security/sensitive_logging.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/security/shell_execution.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/security/validation_errors.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/server_runtime.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/__init__.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/__init__.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/actions.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/cloud_privacy.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/context.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/evidence_serialization.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/help_catalog.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/history.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/inference.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/investigation.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/judging.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/menu_actions.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/model_policy.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/openai_cost_tracking.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/openai_inference.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/permissions.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/prompt_settings.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/prompts/__init__.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/prompts/final-response.md +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/prompts/help-response.md +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/prompts/system.md +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/prompts/tool-result.md +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/retrieval_settings.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/runtime.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/scope.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/skill_settings.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/skills/__init__.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/skills/help-ai.md +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/skills/help-data.md +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/skills/help-formatting.md +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/skills/help-menus.md +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/skills/help-notes.md +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/skills/help-privacy.md +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/skills/help-references.md +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/skills/help-reminders.md +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/skills/help-search.md +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/skills/help-tags.md +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/skills/scoped-investigation.md +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/structured_inference.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/tagging.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/tagging_run.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/token_estimation.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/tools.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/agent/trace.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/ai_chat.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/ai_chat_rendering.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/ai_chat_stream.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/app_update_worker.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/auth.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/auth_cache_state.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/auth_service.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/backlink_index.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/backlinks.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/backup_service.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/backup_settings_service.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/bulk_operation.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/client_state_service.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/content_cache.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/content_formatting.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/diagnostics.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/embedded_references.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/encryption.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/exception_capture.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/file_registry.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/file_storage.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/footnote_layout.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/footnote_rendering.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/hierarchy.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/html_export.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/html_unformatting.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/hydration_state.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/image_size_formatting.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/inline_image_occurrences.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/input_errors.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/integrity.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/latex_rendering.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/link_titles.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/login_rate_limit.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/maintenance_mode.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/markdown_rendering.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/namespace_deletion_jobs.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/namespace_deletion_worker.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/namespace_rename_jobs.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/namespace_rename_worker.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/namespace_runtime_guard.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/namespace_switcher.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/note_fullscreen.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/note_image_tags.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/note_ordering.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/note_store.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/ontology_rules_store.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/openai_credentials.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/password_note_fields.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/reference_presentation.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/reminders.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/remote_image_proxy.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/request_recovery.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/resource_limits.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/root_sorting.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/runtime_generation.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/runtime_hardening.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/runtime_lock.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/search_history.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/search_history_storage.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/search_index.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/search_query.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/search_text.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/selected_text_tag.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/session_timeout_service.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/shell_session_service.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/snapshot.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/store.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/structured_note_renderers.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/sync.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/sync_state.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/tab_state.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/tag_case.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/tag_ontology.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/tag_rename.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/tag_suggestions.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/tag_term_matching.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/test_reset.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/tokens.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/undo_state.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/update_backups.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/view_cache.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/view_diff.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/view_state.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/services/windows_process_control.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/startup_environment.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/startup_sanity_config.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/config/agent-menu-actions.json +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/config/command_palette_tags.json +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/css/floating-notes.css +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/css/forms.css +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/css/main.css +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/img/favicon.ico +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/locked.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/main.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/activity-tracker.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/ai-chat/agent-menu-actions.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/ai-chat/agent-prompt-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/ai-chat/agent-retrieval-settings.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/ai-chat/ai-agent-debug-view.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/ai-chat/ai-chat-api.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/ai-chat/ai-chat-panel-controller.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/ai-chat/ai-chat-panel-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/ai-chat/ai-thinking-level-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/ai-chat/bulk-elapsed-clock.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/ai-chat/bulk-proposal-ui.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/ai-chat/cloud-privacy-policy.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/ai-chat/proposal-menu.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/api-client.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/api-failure-classification-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/app-update-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/application-state.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/async-result.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/auth.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/client-state-api.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/client-state-migration.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/command-palette/activation-auth-policy.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/command-palette/backup-command-availability.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/command-palette/click-activation-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/command-palette/command-palette-controller.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/command-palette/endpoint-registry.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/command-palette/note-layout-preferences.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/command-palette/preferences-store.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/command-palette/tag-config-loader.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/command-palette/usage-store.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/config.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/connectivity-monitor.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/context-menu/context-menu-registry.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/context-menu/context-menu-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/context-menu/context-menu-target-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/context-menu/input-caret-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/disconnect-editing-state-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/dom-utils-fixed.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/dom-utils.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/editor-commands.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/editor-selection.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/editor-toolbar.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/elapsed-time.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/error-handler.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/error-overlay.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/expected-errors.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/location-flags.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/login-namespace-picker.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/maintenance.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/agent-prompt-editor-modal.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/ai-agent-settings-modal.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/alphabetize-root-notes-modal.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/backup-restore-modal.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/backup-result-modal.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/backup-retention-modal.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/backup-settings-modal.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/base-modal.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/confirmation-modal.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/delete-namespace-modal.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/delete-namespace-validation.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/help-modal.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/namespace-loading-page.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/namespace-modals.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/namespace-ports-profile.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/namespace-rename-validation.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/note-layout-appearance-modal.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/ontology-modal.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/password-modal.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/prioritize-modal.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/random-password-modal.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/reminder-modal.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/reset-updated-at-modal.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/search-suggestion-statistics-modal.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/session-timeout-modal.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/modals/version-info-modal.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/actions/content-actions.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/actions/history-actions.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/actions/note-actions.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/actions/search-actions.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/actions/selection-actions.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/actions/ui-actions.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/events/context-menu-events.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/events/focus-events.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/events/inactivity-events.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/events/input-events.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/events/keyboard-events.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/events/mouse-events.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/events/search-events.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/mode-context.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/mode-logger.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/mode-manager-controller.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/add-style-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/animated-scroll-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/backlinks-navigation-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/backlinks-panel-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/clipboard-shortcut-policy-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/collapse-affordance-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/collapse-editing-policy-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/command-gate-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/context-menu-target-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/deselect-selection-state-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/differential-view-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/edit-session-collapse-policy-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/edit-session-collapse-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/embedded-image-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/file-drop-policy-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/file-image-preview-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/file-reference-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/filtered-refresh-selection-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/floating-note-dom.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/floating-note-layout.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/floating-note-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/footnote-navigation-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/history-selection-policy-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/history-shortcut-policy-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/html-paste-sanitizer-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/image-context-menu-action-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/image-file-insert-choice-modal-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/infinite-scroll-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/link-context-menu-action-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/link-title-prefetch-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/markdown-render-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/mermaid-render-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/note-click-target-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/note-clipboard-write-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/note-collapse-animation-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/note-context-menu-action-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/note-delete-shortcut-policy-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/note-drag-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/note-fullscreen-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/note-reposition-animation-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/note-split-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/note-timestamp-hover-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/password-clipboard-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/polling-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/reference-source-navigation-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/remote-image-proxy-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/remove-formatting-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/root-date-separator-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/root-sort-indicator-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/root-sort-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/scroll-anchor-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/scroll-restoration-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/scroll-to-top-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/search-contexts-overlay-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/search-debounce-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/search-input-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/search-interaction-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/search-redaction-reveal-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/search-suggestion-statistics-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/search-suggestion-window-labels-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/search-suggestion-windows-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/search-suggestions-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/search-syntax-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/selected-formatting-removal-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/selected-text-tag-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/shell-output-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/tab-dom-cache-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/tab-drag-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/tab-duplication-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/tab-state-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/tag-bar-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/tag-input-selection-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/tag-proposal-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/tag-suggestions-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/tag-syntax-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/todo-toggle-editing-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/untagged-view-indicator-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/mode-manager/services/view-mode-search-shortcut-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/note-html-sanitizer.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/password-generator.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/password-operation-response.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/password-policy.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/password-strength.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/reminder-store.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/reminder-surface-service.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/selection-markers.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/session-auth.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/tag-token.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/modules/uuid.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/namespace-deleted.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/namespace-renamed.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/vendor/dompurify-3.4.13.LICENSE.txt +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/vendor/dompurify-3.4.13.min.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/vendor/markdown-it-14.3.2.LICENSE.txt +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/vendor/markdown-it-14.3.2.min.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/vendor/mermaid-11.16.1.LICENSE.txt +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/vendor/mermaid-11.16.1.min.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/vendor/zxcvbn-4.4.2.LICENSE.txt +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/js/vendor/zxcvbn-4.4.2.js +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/note-html-policy.json +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/static/video/login-startup.mp4 +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/templates/base.html +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/templates/index.html +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/templates/locked.html +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/templates/maintenance.html +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/templates/namespace_deleted.html +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/templates/namespace_renamed.html +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/templates/notes_list.html +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/upload_limits.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/__init__.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/add_selected_text_tag.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/alphabetize_root_notes.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/base.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/bulk_tag_proposals.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/collapse.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/copy_note.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/create_child.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/create_note.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/create_sibling.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/delete_subtree.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/delete_tag.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/expand.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/indent.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/lock.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/move.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/move_to_top.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/outdent.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/paste_child.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/paste_sibling.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/prefetch_link_titles.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/prioritize.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/redo.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/rename_tag.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/reset_updated_at.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/resize_image.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/run_shell.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/search_comment_autofill.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/search_context_tags.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/set_collapse_bulk.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/set_collapse_in_context.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/split_note.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/tag_proposals.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/toggle_reference_mode.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/toggle_todo_done.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/undo.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/unformat_content.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/update_content.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/usecases/view.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/utils/__init__.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/utils/encryption.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/app/utils/text_utils.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/convert-from-legacy.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/main.py +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/metalist.egg-info/dependency_links.txt +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/metalist.egg-info/entry_points.txt +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/metalist.egg-info/requires.txt +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/metalist.egg-info/top_level.txt +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/pyproject.toml +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/scripts/generate-lan-cert.sh +0 -0
- {metalist-0.7.2 → metalist-0.7.4}/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.4
|
|
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.4
|
|
52
|
+
|
|
53
|
+
- 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.
|
|
54
|
+
- 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.
|
|
55
|
+
- 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.
|
|
56
|
+
|
|
57
|
+
## Changes in 0.7.3
|
|
58
|
+
|
|
59
|
+
- 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.
|
|
60
|
+
- Release candidates now run the complete test and installed-package matrix on Windows, macOS, and Linux across Python 3.10–3.14. Real Chrome and Firefox exercise repeated cold loads and encrypted login on every operating system; Windows also checks Edge over verified LAN HTTPS and the repair path from a published older release.
|
|
61
|
+
|
|
51
62
|
## Changes in 0.7.2
|
|
52
63
|
|
|
53
64
|
- Login, hydration, and workspace requests share one initialized browser-tab identity. Losing the `sessionStorage` copy while opening the workspace no longer causes the reported missing-tab-ID crash. The external trigger for that storage loss remains unconfirmed.
|
|
@@ -147,6 +158,8 @@ metalist update
|
|
|
147
158
|
```
|
|
148
159
|
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.
|
|
149
160
|
|
|
161
|
+
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.
|
|
162
|
+
|
|
150
163
|
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.
|
|
151
164
|
|
|
152
165
|
Only after all backups pass does the updater hand off to an external PowerShell process on Windows or `/bin/sh` on macOS/Linux so the installed environment can unlock. It delegates installation to uv, pinning the current base interpreter and the exact tested package/dependency versions, using the cache populated during preflight with network access disabled. It then launches MetaList again, and reports the installed version (for example, `MetaList updated to v0.5.0.`). This protection requires an installed version containing the backup safeguard and applies to `metalist update` and the in-app update action; direct pip/uv install commands do not run it.
|
|
@@ -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.4
|
|
16
|
+
|
|
17
|
+
- 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.
|
|
18
|
+
- 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.
|
|
19
|
+
- 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.
|
|
20
|
+
|
|
21
|
+
## Changes in 0.7.3
|
|
22
|
+
|
|
23
|
+
- 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.
|
|
24
|
+
- Release candidates now run the complete test and installed-package matrix on Windows, macOS, and Linux across Python 3.10–3.14. Real Chrome and Firefox exercise repeated cold loads and encrypted login on every operating system; Windows also checks Edge over verified LAN HTTPS and the repair path from a published older release.
|
|
25
|
+
|
|
15
26
|
## Changes in 0.7.2
|
|
16
27
|
|
|
17
28
|
- Login, hydration, and workspace requests share one initialized browser-tab identity. Losing the `sessionStorage` copy while opening the workspace no longer causes the reported missing-tab-ID crash. The external trigger for that storage loss remains unconfirmed.
|
|
@@ -111,6 +122,8 @@ metalist update
|
|
|
111
122
|
```
|
|
112
123
|
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.
|
|
113
124
|
|
|
125
|
+
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.
|
|
126
|
+
|
|
114
127
|
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.
|
|
115
128
|
|
|
116
129
|
Only after all backups pass does the updater hand off to an external PowerShell process on Windows or `/bin/sh` on macOS/Linux so the installed environment can unlock. It delegates installation to uv, pinning the current base interpreter and the exact tested package/dependency versions, using the cache populated during preflight with network access disabled. It then launches MetaList again, and reports the installed version (for example, `MetaList updated to v0.5.0.`). This protection requires an installed version containing the backup safeguard and applies to `metalist update` and the in-app update action; direct pip/uv install commands do not run it.
|
|
@@ -114,9 +114,9 @@ if TEST_MODE:
|
|
|
114
114
|
# Delete existing test.db if it exists
|
|
115
115
|
if test_database_path.exists():
|
|
116
116
|
test_database_path.unlink()
|
|
117
|
-
print("
|
|
117
|
+
print("Deleted existing test.db")
|
|
118
118
|
|
|
119
|
-
print("
|
|
119
|
+
print("Running in TEST MODE - using test.db")
|
|
120
120
|
else:
|
|
121
121
|
# Use production database
|
|
122
122
|
DEFAULT_DB_PATH = str(resolve_default_database_path())
|
|
@@ -44,7 +44,10 @@ def _sync_directory(path: Path) -> None:
|
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
def _sync_file(path: Path) -> None:
|
|
47
|
-
|
|
47
|
+
# Windows' CRT rejects fsync/_commit on a read-only descriptor with EBADF.
|
|
48
|
+
# These are live or recovery files owned by this transaction, so open them
|
|
49
|
+
# without truncation using a descriptor that every supported OS can flush.
|
|
50
|
+
with path.open('r+b') as handle:
|
|
48
51
|
os.fsync(handle.fileno())
|
|
49
52
|
|
|
50
53
|
|
|
@@ -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:
|
|
@@ -124,15 +124,8 @@ class SafeSession:
|
|
|
124
124
|
_configure_sql_logging(anchor)
|
|
125
125
|
cls._memory_anchor = anchor
|
|
126
126
|
print("\n" + "=" * 50)
|
|
127
|
-
print(
|
|
128
|
-
|
|
129
|
-
🧪 SWITCHING TO TEST MODE 🧪
|
|
130
|
-
┌──────────────────────────┐
|
|
131
|
-
│ IN-MEMORY DATABASE │
|
|
132
|
-
│ *All Data is Temporary │
|
|
133
|
-
└──────────────────────────┘
|
|
134
|
-
"""
|
|
135
|
-
)
|
|
127
|
+
print("TEST MODE: IN-MEMORY DATABASE")
|
|
128
|
+
print("All data is temporary")
|
|
136
129
|
print("=" * 50 + "\n")
|
|
137
130
|
return {"status": "ok", "message": "Using in-memory database"}
|
|
138
131
|
|
|
@@ -159,15 +152,7 @@ class SafeSession:
|
|
|
159
152
|
_configure_sql_logging(conn)
|
|
160
153
|
conn.close()
|
|
161
154
|
print("\n" + "=" * 50)
|
|
162
|
-
print(
|
|
163
|
-
"""
|
|
164
|
-
📝 RETURNING TO PRODUCTION MODE 📝
|
|
165
|
-
┌──────────────────────────┐
|
|
166
|
-
│ PROD DATABASE │
|
|
167
|
-
│ │
|
|
168
|
-
└──────────────────────────┘
|
|
169
|
-
"""
|
|
170
|
-
)
|
|
155
|
+
print("PRODUCTION MODE: FILE DATABASE")
|
|
171
156
|
print("=" * 50 + "\n")
|
|
172
157
|
return {"status": "ok", "message": "Using file database"}
|
|
173
158
|
|
|
@@ -9,6 +9,7 @@ import shutil
|
|
|
9
9
|
import subprocess
|
|
10
10
|
import sys
|
|
11
11
|
import sysconfig
|
|
12
|
+
import threading
|
|
12
13
|
from uuid import UUID, uuid4
|
|
13
14
|
|
|
14
15
|
from app.data_directory import resolve_data_directory
|
|
@@ -28,6 +29,9 @@ class AppUpdateRejected(ValueError):
|
|
|
28
29
|
"""An update cannot be started in this installation or job state."""
|
|
29
30
|
|
|
30
31
|
|
|
32
|
+
_JOB_THREAD_LOCK = threading.Lock()
|
|
33
|
+
|
|
34
|
+
|
|
31
35
|
def update_executable() -> Path:
|
|
32
36
|
receipt = Path(sys.prefix) / 'uv-receipt.toml'
|
|
33
37
|
if not receipt.is_file():
|
|
@@ -165,24 +169,23 @@ def _release_update_job_locked(job_id: str) -> None:
|
|
|
165
169
|
def _job_lock():
|
|
166
170
|
directory = jobs_directory()
|
|
167
171
|
directory.mkdir(parents=True, exist_ok=True)
|
|
168
|
-
#
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
handle.write(b'0')
|
|
173
|
-
handle.flush()
|
|
174
|
-
handle.seek(0)
|
|
175
|
-
msvcrt.locking(handle.fileno(), msvcrt.LK_LOCK, 1)
|
|
176
|
-
else:
|
|
177
|
-
fcntl.flock(handle.fileno(), fcntl.LOCK_EX)
|
|
178
|
-
try:
|
|
179
|
-
yield
|
|
180
|
-
finally:
|
|
172
|
+
# Threads share process-owned POSIX locks, so serialize them before taking
|
|
173
|
+
# the stable cross-process lock shared by all namespaces.
|
|
174
|
+
with _JOB_THREAD_LOCK:
|
|
175
|
+
with (directory / 'admission.lock').open('a+b') as handle:
|
|
181
176
|
if os.name == 'nt':
|
|
182
177
|
handle.seek(0)
|
|
183
|
-
msvcrt.locking(handle.fileno(), msvcrt.
|
|
178
|
+
msvcrt.locking(handle.fileno(), msvcrt.LK_LOCK, 1)
|
|
184
179
|
else:
|
|
185
|
-
fcntl.flock(handle.fileno(), fcntl.
|
|
180
|
+
fcntl.flock(handle.fileno(), fcntl.LOCK_EX)
|
|
181
|
+
try:
|
|
182
|
+
yield
|
|
183
|
+
finally:
|
|
184
|
+
if os.name == 'nt':
|
|
185
|
+
handle.seek(0)
|
|
186
|
+
msvcrt.locking(handle.fileno(), msvcrt.LK_UNLCK, 1)
|
|
187
|
+
else:
|
|
188
|
+
fcntl.flock(handle.fileno(), fcntl.LOCK_UN)
|
|
186
189
|
|
|
187
190
|
|
|
188
191
|
def create_update_job(target_version: str) -> dict[str, object]:
|
|
@@ -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()
|
|
@@ -16,6 +16,7 @@ from app.services.namespace_switcher import NamespaceLaunchProcess
|
|
|
16
16
|
from app.services.namespace_switcher import _stop_failed_namespace_launch
|
|
17
17
|
from app.services.namespace_switcher import _wait_for_namespace_ready
|
|
18
18
|
from app.services.windows_process_control import stop_process_tree as stop_windows_process_tree
|
|
19
|
+
from app.services.update_installer import resolve_update_installer
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
def _run_checked(command: list[str], *, environ: Mapping[str, str], directory: Path) -> str:
|
|
@@ -86,12 +87,12 @@ def _probe_candidate(*, python: str, executable: str, directory: Path,
|
|
|
86
87
|
_stop_failed_namespace_launch(process=process)
|
|
87
88
|
|
|
88
89
|
|
|
89
|
-
def prepare_update(*,
|
|
90
|
-
environ: Mapping[str, str]) -> list[str]:
|
|
90
|
+
def prepare_update(*, target_version: str, environ: Mapping[str, str]) -> list[str]:
|
|
91
91
|
# A tool environment is replaced during install: pin its external base interpreter.
|
|
92
92
|
python = str(Path(sys._base_executable).resolve())
|
|
93
93
|
if not Path(python).is_file():
|
|
94
94
|
raise RuntimeError("The current base Python interpreter is missing; MetaList was not stopped")
|
|
95
|
+
uv_executable = resolve_update_installer(platform_name=sys.platform, environ=environ)
|
|
95
96
|
print(f"Checking MetaList v{target_version} installation and startup with Python {sys.version.split()[0]}...", flush=True)
|
|
96
97
|
with TemporaryDirectory(prefix="metalist-update-check-") as temporary:
|
|
97
98
|
directory = Path(temporary)
|
|
@@ -165,7 +165,7 @@ def discover_typescript_source_paths(project_root: Path) -> list[Path]:
|
|
|
165
165
|
|
|
166
166
|
|
|
167
167
|
def _path_rel(project_root: Path, path: Path) -> str:
|
|
168
|
-
return
|
|
168
|
+
return path.relative_to(project_root).as_posix()
|
|
169
169
|
|
|
170
170
|
|
|
171
171
|
def _codeframe(lines: list[str], lineno: int, col: int, context_lines: int) -> str:
|
|
@@ -72,7 +72,7 @@ class _RouteDecorator:
|
|
|
72
72
|
|
|
73
73
|
|
|
74
74
|
def _path_rel(project_root: Path, path: Path) -> str:
|
|
75
|
-
return
|
|
75
|
+
return path.relative_to(project_root).as_posix()
|
|
76
76
|
|
|
77
77
|
|
|
78
78
|
def _suppressed(lines: list[str], lineno: int, rule_id: str) -> bool:
|